 |
Cheat Engine The Official Site of Cheat Engine
|
| View previous topic :: View next topic |
| Author |
Message |
OtisInf Cheater
Reputation: 0
Joined: 22 Sep 2015 Posts: 25 Location: The Netherlands
|
Posted: Fri Apr 01, 2016 12:06 pm Post subject: Thread problem: it never exits :) |
|
|
Hi,
I'm busy working on an AOB based timestop CT for Assassin's Creed Syndicate. This means I can't overwrite any code in the ACS.exe process, as that will make the process crash. I have to set two bytes at two different locations. These locations are known, I have the index-based addresses, these are:
| Code: |
[ENABLE]
[ACS.exe+70C2A08]+2F8:
db 01
[[ACS.exe+7151690]+98]+8A8:
db 01
[DISABLE]
[ACS.exe+70C2A08]+2F8:
db 0
[[ACS.exe+7151690]+98]+8A8:
db 0
|
But this is rigid, and I want to scan for these offsets with AOBscan and set them with a thread.
My code is below. This sets the first flag (on [ACS.exe+70C2A08]+2F8), but the problem is with the disable: the thread apparently never exists. pStopFlag is set to 0 when I disable the cheat with the key, so [disable] is called, but pThreadEnded is always 0. Also the flag set by the cheat stays '1'.
The general idea is that the [Enable] starts a thread, the thread sets the flags (currently 1 is implemented), and busy waits with a thread sleep in a loop till a byte is set to 1 (pStopFlag). If that's the case, the 2 flags (currently 1 is implemented) have to be set to 0 again, so that's the code after the sleep loop. I don't know any other way to do that, than this, and IMHO this should work OK. I have two pointers in the CT for debug, pStopFlag and pThreadEnded, and when I enable, both will flip to 0, when I disable, only pStopFlag flips to 1, pThreadEnded stays 0. The flag of the cheat also stays 1. When I move the code for setting pThreadEnded above the loop, its value is set, so the debug pointers and the actual set code works fine. Conclusion: the thread never ends!
It's a 64bit game, hence the calculation of the offset
What do I do wrong?
Thanks in advance!
// Enable script, which performs the AOB scan
| Code: |
[ENABLE]
aobscanmodule(MenuSystemEnable_AOB, ACS.exe, 40534883EC??488BD9E8????????488B0D????????4885C974??E8????????488B0D????????)
label(MenuSystemEnable)
registersymbol(MenuSystemEnable)
MenuSystemEnable_AOB:
MenuSystemEnable:
[DISABLE]
unregistersymbol(MenuSystemEnable)
|
The actual cheat script, which is a child of the above code in the CT:
| Code: |
[ENABLE]
globalalloc(timestop, 128)
createthread(timestop)
label(positive)
label(calculateRealAddress)
label(pMenuSystemData)
label(waitForDisable)
label(pStopFlag)
label(pThreadEnded)
registersymbol(calculateRealAddress)
registersymbol(pMenuSystemData)
registersymbol(waitForDisable)
registersymbol(pStopFlag)
registersymbol(pThreadEnded)
timestop:
push rsi
push rdi
push eax
push rbx
mov rsi,MenuSystemEnable+0
mov rax,11 // offset in AOB block for DWord to read
mov rbx,pMenuSystemData
call calculateRealAddress
// switch on menu camera system
mov byte ptr [rdi+2F8],01
//push rdi
waitForDisable:
push #500
call sleep
cmp byte [pStopFlag],01
jne waitForDisable
// reset flags to 0
lea rdi,[pMenuSystemData]
// pop rdi
mov byte ptr [rdi+2F8],0
mov rbx,pThreadEnded
mov byte ptr [rbx],1
pop rbx
pop eax
pop rdi
pop rsi
ret
//[[ACS.exe+7151690]+98]+8A8:
//db 01
pMenuSystemData:
dq 0
pStopFlag:
db 0
pThreadEnded:
db 0
// in:
// - rsi: Source of AOB scanned block
// - eax: offset in AOB block for dword to read
// - rbx: address of label to write the calculated pointer to. Used in disable.
//
// out:
// - rdi: address of start of block to index into.
calculateRealAddress:
push ecx
xor rdi,rdi
add rsi,eax // rsi now points to DWord to read
cmp dword [rsi],80000000 // test if the most significant bit is set
jb short positive
mov rdi,ffffffff00000000 // it's set so sign extend
positive:
mov ecx,[rsi] // this will clear the upper bits of rcx leaving the unsigned value at [rsi+eax] in rcx
add rdi,ecx
add rsi,edi
add rsi,4 // offset to dword already added to rsi. add 4 as we read a dword, this is now the offset after the Dword in the AOB scanned block
mov [rbx],rsi
mov rdi,[rsi]
pop ecx
ret
[DISABLE]
pStopFlag:
db 1
unregistersymbol(calculateRealAddress)
unregistersymbol(pMenuSystemData)
unregistersymbol(waitForDisable)
unregistersymbol(pStopFlag)
unregistersymbol(pThreadEnded)
//[ACS.exe+70C2A08]+2F8:
//db 0
//[[ACS.exe+7151690]+98]+8A8:
//db 0
|
|
|
| Back to top |
|
 |
++METHOS I post too much
Reputation: 92
Joined: 29 Oct 2010 Posts: 4197
|
Posted: Fri Apr 01, 2016 3:33 pm Post subject: |
|
|
Just curious, so I took a look at this game. I managed to get the script working for a while, but the game eventually crashed. I don't know if that was due to the protection, because of the injection points that I used, or maybe just a bug in the game itself. I only tested it once before deleting the game. Anyway, this was done with the latest version of SE plugin and CE 6.5.
| Description: |
|
 Download |
| Filename: |
ACS.CT |
| Filesize: |
4 KB |
| Downloaded: |
457 Time(s) |
|
|
| Back to top |
|
 |
OtisInf Cheater
Reputation: 0
Joined: 22 Sep 2015 Posts: 25 Location: The Netherlands
|
Posted: Fri Apr 01, 2016 4:18 pm Post subject: |
|
|
whoa that looks totally different to my code
I think the crashes are caused by a race condition between the engine's threads: I think the 2 bytes set are mutexes to make systems start / stop actions, as they control different threads (if you debug the calls to the different flags) and switching the 8A8 indexed one to 1 switches off the camera completely, switching 2F8 to 1 enables the camera system (as the UI/menu uses it) on, so what is needed is achieved: complete standstill with a moving camera . But likely some other subsystem runs off the tracks as multithreading is hard, and Ubisoft's PC programmers didn't anticipate this scenario I think. (aka: another flag has likely to be set somewhere, but which one is unclear)
I was thinking about first doing the 8A8 indexed one and then the 2F8 one, as doing it the other way around is less ideal (as the game crashed on me a couple of times indeed that way too). But I see you did it the other way around so it's not that. :/
Anyway, I appreciate your help on this! Do you mind if I ask a couple of questions regarding this?
Do you know what it could be that makes the thread I create not exit? Your code, is that usable to obtain the actual addresses? I see you use stealthedit, which I haven't seen before, is there documentation on that somewhere? Any url is fine
Thanks again
Tomorrow I'll try to use a keyhandler as a threadloop (similar to what sunbeam used in his ACS table), which is even more overhead to set just 1 byte haha but at least it will let me enable/disable it without problems.
|
|
| Back to top |
|
 |
++METHOS I post too much
Reputation: 92
Joined: 29 Oct 2010 Posts: 4197
|
|
| Back to top |
|
 |
OtisInf Cheater
Reputation: 0
Joined: 22 Sep 2015 Posts: 25 Location: The Netherlands
|
Posted: Sat Apr 02, 2016 1:38 am Post subject: |
|
|
I did, but didn't find a solution, as my problem isn't to kill a thread but to make it end properly: it now hangs on the sleep it seems. But I went back to the first thread, and realized what was wrong -> I used the 32bit way of calling sleep (by pushing the # of milliseconds onto the stack), while I should have been using the 64bit way of calling sleep, which is using rcx instead of the stack. I didn't realize calling sleep had two different usages.
So that's solved
| Quote: |
| OtisInf wrote: | | Your code, is that usable to obtain the actual addresses? | -Yes.
|
Neat! Will keep this in mind!
| Quote: |
| OtisInf wrote: | | I see you use stealthedit, which I haven't seen before, is there documentation on that somewhere? | -There are a few topics that discuss this here on CEF, but not many. The release thread is in the beta testing sub-forum. If you're not part of that group, you can download it here:
http://cheatengine.org/temp/stealthedit2.4.zip |
Ah thanks for the heads up. Nice CE gets stealth edits so a complex thread setup is no longer needed
Thanks for the help!
|
|
| Back to top |
|
 |
++METHOS I post too much
Reputation: 92
Joined: 29 Oct 2010 Posts: 4197
|
Posted: Sat Apr 02, 2016 9:35 am Post subject: |
|
|
| OtisInf wrote: | | I didn't realize calling sleep had two different usages. | -Ah...yes. To be honest, I didn't even look at your script. Sorry.
| OtisInf wrote: | | so a complex thread setup is no longer needed | -I wouldn't necessarily say that...only because SE may not work effectively on all targets. However, in cases that it does, you can inject and manipulate to your heart's content.
|
|
| Back to top |
|
 |
OtisInf Cheater
Reputation: 0
Joined: 22 Sep 2015 Posts: 25 Location: The Netherlands
|
Posted: Sat Apr 02, 2016 10:41 am Post subject: |
|
|
| ++METHOS wrote: | | OtisInf wrote: | | I didn't realize calling sleep had two different usages. | -Ah...yes. To be honest, I didn't even look at your script. Sorry.
|
No worries, I figured it out.
| Quote: |
| OtisInf wrote: | | so a complex thread setup is no longer needed | -I wouldn't necessarily say that...only because SE may not work effectively on all targets. However, in cases that it does, you can inject and manipulate to your heart's content.  |
that would be great indeed.
I wrote the script now with AOB scans, a thread which neatly exists, all constants are scanned from the code, so should be future proof See: http://forum.cheatengine.org/viewtopic.php?t=588771
Cheers!
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum You cannot attach files in this forum You can download files in this forum
|
|