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 


Freezing when browsing specific memory regions in a game

 
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine
View previous topic :: View next topic  
Author Message
predprey
Master Cheater
Reputation: 24

Joined: 08 Oct 2015
Posts: 486

PostPosted: Fri Oct 19, 2018 2:54 pm    Post subject: Freezing when browsing specific memory regions in a game Reply with quote

So I was hacking Resonance of Fate/End of Eternity 4K on PC and I encountered this issue which never happened before. There are some specific memory addresses that when shown in the memory browser causes my CPU usage to spike to ~15% for the CE process. CE starts becoming sluggish and even becomes unresponsive when sub-windows open such as a Goto Address prompt. It does not hang completely but pressing buttons to close the sub-window yields no response and so CE becomes stuck because of the modal mode of the prompt.

I tried installing CE6.6 and this issue still persists. It's probably not a bug though but I am curious as to what could be causing this? Is it because the game accesses the memory region too heavily, and thus slows CE from accessing the same region causing a lockup?

UPDATE: So there is this other issue with Tri-Ace games on PC such as Star Ocean and this game where trying to scan for values on a new scan result in "Scan error:thread 7:Access violation". Using CE Kernel "Query memory region routines" solves both this problem and the above one. But not sure if it's a bug with the game or CE? Limiting scan range also solves it though.

UPDATE2: It seems compiling a non-multithreaded build of CE solves the error.
Back to top
View user's profile Send private message
predprey
Master Cheater
Reputation: 24

Joined: 08 Oct 2015
Posts: 486

PostPosted: Sun Oct 21, 2018 2:27 am    Post subject: Reply with quote

It seems the problem is related to memscan.pas, TScanController.firstScan, at line 6139:
Code:
      if i=(threadcount-1) then
      begin
        //if it's the last thread, just give it what's left
        scanners[i].stopaddress:=stopaddress;
        scanners[i]._stopregion:=memregionpos-1;

        //define maxregionsize , go from current till end (since it'll scan everything that's left)
        while j<memregionpos do
        begin
          if scanners[i].maxregionsize<memregion[j].MemorySize then
            scanners[i].maxregionsize:=memregion[j].MemorySize;

          inc(j);
        end;
      end

Both described problems do not present themselves in a non-multithreaded build. The code above is how CE distributes the last portion of a scanning range to its last scanner thread.

What happens in Resonance of Fate is the j counter reaches the end of memregionpos even before the last scanner thread has been initialized. E.g. memregionpos = 300, on the last loop for the last scanner thread, j will have been 299 (the else branch decreases j back down after its loop). memregion[299].MemorySize has a size of only 0x2000 bytes. However, somehow or other further down the code in TScanner.FirstScan, one of the actualread size exceeds this buffer size of 0x2000. The size value is passed along to TScanner.FirstScanMem which then loops past 0x2000 and the respective checkRoutine call tries to query the unallocated memory space, causing a segmentation fault and the Access Violation message.

Copying in some code from the else branch to the code above solves the scanning problem:
Code:
      if i=(threadcount-1) then
      begin
        //if it's the last thread, just give it what's left
        scanners[i].stopaddress:=stopaddress;
        scanners[i]._stopregion:=memregionpos-1;
       
        currentblocksize:=0;
        inc(currentblocksize,memregion[j].MemorySize-offsetincurrentregion);
        scanners[i].maxregionsize:=currentblocksize;

        //define maxregionsize , go from current till end (since it'll scan everything that's left)
        while j<memregionpos do
        begin
          if scanners[i].maxregionsize<memregion[j].MemorySize then
            scanners[i].maxregionsize:=memregion[j].MemorySize;

          inc(j);
        end;
       
        if scanners[i].maxregionsize>buffersize then
          scanners[i].maxregionsize:=buffersize;
      end


This code does not solve the high CPU spike though, I'm assuming a similar problem somewhere else where the memory browser tries to query out of bounds memory and the errors causes some delays between threads resulting in the spike.

Anyway, regarding the j counter for iterating through memregion, is it normal behavior for it to reach the end even before all threads have been initialized? My code above solves the segmentation fault by allocating more memory for the buffer using the same method as the else branch. However, I'm not sure if the bug is the original code above, the strange j counter behavior, or the later parts in TScanner.firstscan having a large actualread size even though the last thread is only assigned the last 0x2000 bytes memRegion.

P.S. The latest source on GitHub cannot be compiled by default because it's missing a debugstructurelist.pas.

EDIT: On second thought, it is cleaner to move line 6157, 6158 and 6161 to before the last thread conditional branch.
Code:
    for i:=0 to threadcount-1 do
    begin
      OutputDebugString(format('Creating scanner %d',[i]));
      scanners[i]:=tscanner.Create(true, OwningMemScan.ScanresultFolder);
      scanners[i].scannernr:=i;
      scanners[i].OwningScanController:=self;


      scanners[i]._startregion:=j;
      scanners[i].startaddress:=memRegion[j].BaseAddress+offsetincurrentregion;

      //scanners[i].maxregionsize:=0; //Original Code, no longer needed
      currentblocksize:=0; //Moved Code
      inc(currentblocksize,memregion[j].MemorySize-offsetincurrentregion); //Moved Code
      scanners[i].maxregionsize:=currentblocksize; //Moved Code

      if i=(threadcount-1) then
      begin
        //if it's the last thread, just give it what's left
        scanners[i].stopaddress:=stopaddress;
        scanners[i]._stopregion:=memregionpos-1;

        //define maxregionsize , go from current till end (since it'll scan everything that's left)
        while j<memregionpos do
        begin
          if scanners[i].maxregionsize<memregion[j].MemorySize then
            scanners[i].maxregionsize:=memregion[j].MemorySize;

          inc(j);
        end;
      end
      else
      begin
        //not the last thread
        inc(j);

        while (currentblocksize<blocksize) and (j<memregionpos) do
        begin
          if scanOption<>soUnknownValue then //not a unknown initial value scan, so it doesn't need overlap
          begin
            if scanners[i].maxregionsize<memregion[j].MemorySize then
              scanners[i].maxregionsize:=memregion[j].MemorySize;
          end;

          inc(currentblocksize,memregion[j].MemorySize);
          inc(j);
        end;


Last edited by predprey on Sun Oct 21, 2018 2:16 pm; edited 1 time in total
Back to top
View user's profile Send private message
Dark Byte
Site Admin
Reputation: 470

Joined: 09 May 2003
Posts: 25785
Location: The netherlands

PostPosted: Sun Oct 21, 2018 7:03 am    Post subject: Reply with quote

thanks i'll check it out.
_________________
Do not ask me about online cheats. I don't know any and wont help finding them.

Like my help? Join me on Patreon so i can keep helping
Back to top
View user's profile Send private message MSN Messenger
predprey
Master Cheater
Reputation: 24

Joined: 08 Oct 2015
Posts: 486

PostPosted: Sun Oct 21, 2018 2:06 pm    Post subject: Reply with quote

Update on the high CPU use issue: to reproduce the issue for Resonance of Fate, browse to this line in the disassembler
Code:
Resonance of Fate.exe+8B0D85 - 48 8B 05 A475F700     - mov rax,["Resonance of Fate.exe"+1828330]

1. Once this line appears in the panel, CPU usage spikes.
2. There are other lines like this.
3. Issue does not appear in non-multithreaded builds or when kernel query routine is used.
4. Displaying the associated machine code in hex view does not trigger CPU usage spike.
Back to top
View user's profile Send private message
Dark Byte
Site Admin
Reputation: 470

Joined: 09 May 2003
Posts: 25785
Location: The netherlands

PostPosted: Sun Oct 21, 2018 2:24 pm    Post subject: Reply with quote

hmm, the disassembler nor anything related there is affected by the cpucount var so not sure that is actually related

are the symbols still being loaded ? (blank, so not 100% or less)

_________________
Do not ask me about online cheats. I don't know any and wont help finding them.

Like my help? Join me on Patreon so i can keep helping
Back to top
View user's profile Send private message MSN Messenger
predprey
Master Cheater
Reputation: 24

Joined: 08 Oct 2015
Posts: 486

PostPosted: Sun Oct 21, 2018 6:03 pm    Post subject: Reply with quote

yea, couldn't find anything related to threads in both the disassembler and hexview sources. but the problem not showing up in a nomt build suggests it has to do with the number of threads. i think i will recompile a nomt build again to confirm i didn't mistake it.
Back to top
View user's profile Send private message
predprey
Master Cheater
Reputation: 24

Joined: 08 Oct 2015
Posts: 486

PostPosted: Tue Oct 23, 2018 12:45 am    Post subject: Reply with quote

predprey wrote:
yea, couldn't find anything related to threads in both the disassembler and hexview sources. but the problem not showing up in a nomt build suggests it has to do with the number of threads. i think i will recompile a nomt build again to confirm i didn't mistake it.


sorry, it seems i had mistaken it. compiled a new debug 64-bit nomt build and high cpu usage is still present when that offending line is in the disassembler.

to reproduce the issue, open disassembler to that address and enter a battle. cpu usage only spikes during battle. but the line isnt run nor accessed by the game, yet cpu usage spikes. so i decided to nop the code, and cpu usage drops back down to 0-1%. i then switched the ["Resonance of Fate.exe"+1828330] with rax and cpu usage remains at 0-1%. so it's something to do with the routines for autoguessing the value of the memory location, a separate issue from the scan access violation error.

i'm thinking this might be normal behavior when using the winapi version for virtualqueryex? i tried finding what is accessing the location at "Resonance of Fate.exe"+1828330 and there were at least 80 instructions accessing it around 10 times per second, some even 50 times. i'm guessing the windows version gets bogged down by the system scheduler and gets lower priority than the main game? while the kernel version can bypass all these and read directly from the memory so its faster?
Back to top
View user's profile Send private message
Dark Byte
Site Admin
Reputation: 470

Joined: 09 May 2003
Posts: 25785
Location: The netherlands

PostPosted: Thu Oct 25, 2018 5:48 pm    Post subject: Reply with quote

I've applied your patch. Though I don't really see a cause for an error (the j indexer is as it should from what I see)
_________________
Do not ask me about online cheats. I don't know any and wont help finding them.

Like my help? Join me on Patreon so i can keep helping
Back to top
View user's profile Send private message MSN Messenger
predprey
Master Cheater
Reputation: 24

Joined: 08 Oct 2015
Posts: 486

PostPosted: Thu Oct 25, 2018 7:22 pm    Post subject: Reply with quote

Dark Byte wrote:
I've applied your patch. Though I don't really see a cause for an error (the j indexer is as it should from what I see)


just compiled a new release build with the latest source. scans successfully. i concur with you, without knowing the root cause i feel the patch is more of a bandaid now, though it does not hurt performance much either.

i don't fully understand how the j indexer works. is the j indexer supposed to reach its last index before the last thread's iteration? and is it possible that the currentblocksize is larger than the last memRegion size for the last thread.
Back to top
View user's profile Send private message
Dark Byte
Site Admin
Reputation: 470

Joined: 09 May 2003
Posts: 25785
Location: The netherlands

PostPosted: Fri Oct 26, 2018 12:34 am    Post subject: Reply with quote

the array goes from 0 to memoryregionpos-1

but if anything goes wrong it likely goes wrong in TScanner.firstNextscan

also don't rule out windows itself. Do you use windows 10 ? It may have had a patch that affected ReadProcessMemory which is why it works now

_________________
Do not ask me about online cheats. I don't know any and wont help finding them.

Like my help? Join me on Patreon so i can keep helping
Back to top
View user's profile Send private message MSN Messenger
predprey
Master Cheater
Reputation: 24

Joined: 08 Oct 2015
Posts: 486

PostPosted: Fri Oct 26, 2018 5:46 pm    Post subject: Reply with quote

Dark Byte wrote:
the array goes from 0 to memoryregionpos-1

but if anything goes wrong it likely goes wrong in TScanner.firstNextscan

also don't rule out windows itself. Do you use windows 10 ? It may have had a patch that affected ReadProcessMemory which is why it works now


yea i'm using windows 10, but i did also move the currentblocksize code back to its original position in the latest source to make sure that it was not the other commits patching up the issue.

is firstNextscan what executes when pressing next scan? because the issue already occurs on a first scan.

i know the array goes from 0 to memregionpos-1, what i meant is what is the entire block of code doing? is it assigning the memory size based on the workload given to each scanner thread and if so is the workload divided evenly between all threads, or allocated sequentially moving on to the next thread when the thread has been allocated enough memregions whose total size exceeds blocksize.
Back to top
View user's profile Send private message
Dark Byte
Site Admin
Reputation: 470

Joined: 09 May 2003
Posts: 25785
Location: The netherlands

PostPosted: Sat Oct 27, 2018 2:02 am    Post subject: Reply with quote

firstNextScan is what gets called on a first scan that isn't an unknown initial value scan or as next scan on a unknown initial value scan (it works on memoryregions) nextnextscan is the one that gets called when there is an addresslist

it divides the total memory by the number of scanners and then distributes it along them in blocks (because there can be a million 4kb regions and one 2GB region)

_________________
Do not ask me about online cheats. I don't know any and wont help finding them.

Like my help? Join me on Patreon so i can keep helping
Back to top
View user's profile Send private message MSN Messenger
predprey
Master Cheater
Reputation: 24

Joined: 08 Oct 2015
Posts: 486

PostPosted: Sat Oct 27, 2018 9:29 am    Post subject: Reply with quote

ok thanks, when i have the time i will try and debug the issue again. knowing how it divides the memory will help me identify abnormal behavior this time.
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