Cheat Engine Forum Index Cheat Engine
The Official Site of Cheat Engine
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 


gettickcount() crashed game [Closed]

 
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine
View previous topic :: View next topic  
Author Message
paul44
Expert Cheater
Reputation: 2

Joined: 20 Jul 2017
Posts: 152

PostPosted: Mon May 16, 2022 10:47 am    Post subject: gettickcount() crashed game [Closed] Reply with quote

script: [ https://imgur.com/a/PheM6d0 ]

I'm trying to skip execution of setting a flag until a certain time has expired.
Did some research, and closest example I could find is this one: [ https://www.cheatengine.org/forum/viewtopic.php?p=5745885&sid=6a1b08fa34c6de252438e01f7f0a908a ]

I've also tried pushing all registers and flags, but result remains the same. As far as I can see, the logic seems to be ok... unless one needs to follow the "structure" exactly as #ParkourPenguin has set out in his example ?!


ps: in the mean time, I've used the Timer in my table - which runs every 3 secs - to do the job (works a charm ~ 2nd pic, which is not related to aforementioned script !). But I'd like to understand what i'm doing_wrong/missing here...?
To clarify: since I have no idea when the next "tick" will be, i skip one timer_cycle (which practically means that the actual skip_time will be between 3~6 secs)
In that respect: is there some property/method - related to CreateTimer() - that would allow one to actually 'build' a timerinterval, and thus skip at a precise time_interval ?


Last edited by paul44 on Fri May 20, 2022 1:01 am; edited 1 time in total
Back to top
View user's profile Send private message
ParkourPenguin
I post too much
Reputation: 138

Joined: 06 Jul 2014
Posts: 4275

PostPosted: Mon May 16, 2022 11:48 am    Post subject: Reply with quote

My script in that post was for 32-bit code. 64-bit code is different. In particular, the stack must be aligned to 16 bytes and have memory allocated on the stack to serve as a shadow store for the four register parameters (total 32 bytes).
https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170

example:
Code:
globalalloc(foo,4096)
createthread(foo)

foo:
  sub rsp,28
  call GetTickCount
  mov [foo+800],eax
  add rsp,28
  ret
Note that the stack at the injection point may already be aligned- you'll have to check.
_________________
I don't know where I'm going, but I'll figure it out when I get there.
Back to top
View user's profile Send private message
paul44
Expert Cheater
Reputation: 2

Joined: 20 Jul 2017
Posts: 152

PostPosted: Tue May 17, 2022 12:59 pm    Post subject: some details: Reply with quote

took out some time to document this for myself: [ https://www.dropbox.com/s/02bnum5248g576z/CE_GetTickCount.rar?dl=0 ] (1st image shows the new opcode)

Some considerations:
1. CE performs a far jump here (correct me if i'm wrong), which implies the use of 14+2 bytes ?! (xxx0080064 - xxx0080054 = 0x10)
It seems the return_address is incorrect (only adding 6 bytes - short jump - instead of 16) ?!
2. Conceptual: 'Retrieves the number of milliseconds that have elapsed since the system was started, up to 49.7 days' (and then rebuilds from 0 again...)
WhatIf:
- in a "worst" scenario, our 'initTime' receives this '49.7 minus a few ticks'-day value
- within our anticipated time_interval, eax restarts from 0 again
- performing the substraction at that moment results in a negative value
- iow: the interval_value will never be reached; and our code would/could loop indefinitely ?!
(unless my logic has a "loophole" ofc Cool)

Req: ^ do you happen to have an example of 'un-aligned' stack ? How would one identify such case ?

ps: based on debugging, i actually could remove the "stack_increase" altogether (~ rcx caused the crash actually - did try while pushing all registers, but must have missed something then)
ps2: i consider this topic as closed, but will wait another week in case somebody adds some more related info...
Back to top
View user's profile Send private message
ParkourPenguin
I post too much
Reputation: 138

Joined: 06 Jul 2014
Posts: 4275

PostPosted: Tue May 17, 2022 7:51 pm    Post subject: Reply with quote

paul44 wrote:
Code:
...
sub rsp,28
push rcx
...
This is wrong. You're backing up rcx in the scratch space the call to GetTickCount is using. It could be overwritten.
Either push rcx first and then make space, or make enough space for both at once and write rcx into the stack afterwards.
Code:
...
// allocating space
push rcx
sub rsp,28
...
// cleaning up
add rsp,28
pop rcx
...
Make sure to preserve alignment.
paul44 wrote:
1. CE performs a far jump here (correct me if i'm wrong)
CE uses a 5-byte jump. I don't see anything significant that would indicate otherwise.
You should be allocating memory near `TimerAlert` and not `$process`, but it would still probably work fine.
paul44 wrote:
- performing the substraction at that moment results in a negative value
That's not how modular arithmetic works.
Example C code:
Code:
#include <stdint.h>
#include <stdio.h>

int main(int, char**) {
    uint32_t u_t1 = 0xFFFFFFFF;
    uint32_t u_t2 = 0;
    uint32_t u_elapsed = u_t2 - u_t1;

    int32_t i_t1 = 2147483647;
    int32_t i_t2 = -2147483648;
    int32_t i_elapsed = i_t2 - i_t1;

    printf("unsigned elapsed: %d\n  signed elapsed: %d\n", u_elapsed, i_elapsed);

    return 0;
}

/* Output:
 * unsigned elapsed: 1
 *   signed elapsed: 1
 */
Where it goes wrong is if the elapsed time could exceed 49.7 days, after which it will circle back around and start from 0 again.
This is assuming you're treating the output type as unsigned (e.g. ja / jb) instead of signed (e.g. jg / jl). It's safe to treat it as unsigned only if GetTickCount is monotonic- i.e. the value returned by a call to GetTickCount will never be strictly greater than that of a subsequent call to GetTickCount in the immediate future.
If you don't want to worry about that, treat it as a signed type. The consequence is that the range of valid values will be reduced by half (i.e. starts wrapping after 24.86 days).
paul44 wrote:
Req: ^ do you happen to have an example of 'un-aligned' stack ? How would one identify such case ?
In the second image (precall), you see RSP is 914ED9DA10: notice the last digit is 0. This means the address is divisible by 16 and therefore has a 16-byte alignment. (this is before the `sub rsp,28` instruction executed)
If RSP ended in 8, it would not be aligned to 16 bytes. This should only happen in the prologue or epilogue (and maybe leaf functions).

_________________
I don't know where I'm going, but I'll figure it out when I get there.
Back to top
View user's profile Send private message
paul44
Expert Cheater
Reputation: 2

Joined: 20 Jul 2017
Posts: 152

PostPosted: Thu May 19, 2022 11:28 am    Post subject: jump far & return address Reply with quote

^first and foremost: thx for even taken out the time to explain this in such detail. Some of the terms are new to me, but i dig most of it (apart from the MS doc... is that even English ?). will do some additional testing coming weekend to see how that would behave...

that said: i would like to come back on the return address: [ https://imgur.com/a/CG77bSY ]
I still think this is incorrect, perhaps because of me using $process instead of TimerAlert
(although i think this will make no difference ~ CE seems to take care of that part just fine here).

ps: i only recently "picked up" the jump_far/14-byte_jmp concept and did some research on it in the process. I can not recall seeing this happening, but will recheck that again to be sure...
Back to top
View user's profile Send private message
ParkourPenguin
I post too much
Reputation: 138

Joined: 06 Jul 2014
Posts: 4275

PostPosted: Thu May 19, 2022 11:38 am    Post subject: Reply with quote

If you look at the real instructions that `call` pseudoinstruction is composed of, you'll see it works fine- the first 6 bytes are a call, the next two bytes `EB 08` jumps forward 8 bytes, and the next 8 bytes are the address being called. The return address (7FF7A5E9005A) is the address of that jmp instruction (this is correct).
_________________
I don't know where I'm going, but I'll figure it out when I get there.
Back to top
View user's profile Send private message
paul44
Expert Cheater
Reputation: 2

Joined: 20 Jul 2017
Posts: 152

PostPosted: Fri May 20, 2022 1:00 am    Post subject: and closing... Reply with quote

Got it; did not see/grasp that the first time.

What confused me here, was - while debugging and returning - you'll get visually "some garbage opcode" presented; but steps-wise everything runs fine. i finally dig it. thx !
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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


Powered by phpBB © 2001, 2005 phpBB Group

CE Wiki   IRC (#CEF)   Twitter
Third party websites