Jumping off of Igor's suggestion of a trace, have you tried a break and trace via Cheat Engine yet? If not, consider the following:
- Whether via byte array (requiring an AOB scan first; make sure you select read/write memory), module+offset, or symbol name (if applicable), find your way to the
crc32 edi, qword ptr [rsi+rax*8] instruction in Cheat Engine's disassembler (the top half of the Memory Viewer).
- Right-click on the instruction and choose
Break and trace instructions.
- In the subsequent window, check
Save stack snapshots and
Step over instead of single step, then click
- Once the Tracer window populates with your trace, right-click within it and choose
- Scroll to the farthest branch of the tree, of which the top-most instruction should be your
crc32 edi, qword ptr [rsi+rax*8] instruction.
- Click the
Stack button and keep the window that opens (Stack View), beside the Tracer window.
Now work your way down the list of recorded instructions (which will take you back up through callers with each branch). You can watch the registers on the right-hand side, as well as the stack via the Stack View window. You can double-click on any instruction in the Tracer to take you to that instruction in the disassembler, where you can then read up through sub-routines from callers.
If there isn't enough branching for you, then run the trace again and change the initial number of instructions traced from 1000 to whatever you'd like. Also, if you find your way into a caller's sub-routine and there are other calls from within it that you'd like to drill down into, simply run another break/trace at some point before the call, then do not select (or de-select, if it's already selected)
Step over instead of single step.
Finally as another tip, in the Memory Viewer, if you run
Tools -> Dissect Code, you can then select the base module and any other dependencies to run a bunch of automated tasks on, like finding all referenced strings and functions, and finding all xrefs to all routines!
The xrefs one is great for being able to head to the prologue of any given function (right-click on any instruction and choose
Select current function, then scroll to the top) and quickly see how many callers there are (of which you can double-click any of to go to them).
This allows you to quickly see if a function is shared, thus potentially acting as a pivot point to either patch with a
ret (or however you'd prefer to patch), or allowing you to choose which specific call instructions to that particular function you'd like to individually patch.