Hm. Well, Cheat Engine stopped working for me properly (it no longer lets me use hardware breakpoints, so I can't log instructions that read or write anymore like you can. Thus, your nifty tutorial doesn't work for me).
To combat this, I used IDA Pro, which CAN still log reads and writes. However, it is VERY clunky, and the option to not log instructions that it has already logged isn't working, effectively ruining the trace window.
So instead, I switched Project 64, the emulator I was hacking on (I just hate Nemu, guys), to use an interpreter core for the game I was hacking. The interpreter core only uses two instructions for reading and writing per data type (e.g. L/SW, L/SH, L/SB), so even though the trace window in IDA Pro was overflowed with repeat logs, there were only two I needed.
After logging them, I detached IDA Pro because it was making PJ 64 run at 1/3 speed (that, and IDA Pro and Cheat Engine are programs that can't run at the same time). I opened back up cheat engine and used the information I had gathered to make the hack seen in the attachment to this post. As you can see, that nop in the debugger is only broken on when a read of a specified address occurs, and the value at PJ 64's 0x4d5280 will hold the MIPS PC of the exact instruction that caused that read.
I could even modify it to log PCs instead of breaking on them (Edit: I have now done this
), to gather the information faster and mess around with those PCs using gameshark codes since I can no longer alter recompiled x86 to test for immediate results (Wrong! As of now I have a way to immediate test results without using gameshark codes, and boy is it awesome!). The interpreter core is slower, yes, but this lap top is more powerful than the computer I originally developed this hacking method on, and I believe it will prove rather effective.
Edit: This hack works even better. It lets you do what the previous hack does...if you use it to record all the PCs that access an address, you can plug those PCs into an address, and figure out if that PC is the one you're looking for.
Edit, again: This version also logs PCs for you. If the area at AllocatedMem+0x50 and beyond is filled with x86 nops (bytes of 0x90), the hack will automatically log all PCs that access the data at the pointer you specify.
org 42a885
jmp AllocatedMem
org AllocatedMem
xor ecx, pointer
jne EIP+0x37 ;make jne into jmp to disable function; this should be a jmp by default because until the game is running Project 64 will act screwy and think it is in an infinite loop. This might be due to me using the stack instead of making my own.
push eax
mov eax, EIP+0x47
mov ecx, [004d5280]
inc eax
inc eax
inc eax
inc eax
cmp ecx, [eax]
je EIP+0xC
cmp [eax], 90909090
jne EIP-0xE
mov [eax], ecx
pop eax
cmp ecx, [EIP+0x29]
je EIP+9
mov ecx, value if false
jmp EIP+0x12
mov ecx, value if true ;Break here to get reg status of correct PC
jmp EIP+0xB
xor ecx, pointer
mov ecx, [ecx+eax] ;Replaced instruction
mov [edx], ecx ;Replaced instruction
jmp 0042a88a
Edit: More info for you bastards:
429ea8 - universal 1 byte read instruction
42a8a8 - universal 1 byte write instruction
429f18 - universal 2 byte read instruction
42a918 - universal 2 byte write instruction
42a885 - universal 4 byte read instruction
42b8d5 - universal 4 byte write instruction