What we want to do in Chapter II is a "levelskipper". Remember the fix Address for the game's score from Chapter I ? If not, read chapter I first, then come back. It was 412f74, right. And if you played the game a bit, you probably know that for each level to succeed you have to get a specific score. Your current score must be compared somewhere to the score you have to reach for each level. And what does the game have to do to get your current score? It must read the score (at 412F74). So what we have to do is to set a breakpoint on this address once again, but this time with the "R" parameter (Softice will then break if the game Reads the value stored inside 412F74). Press CTRL-D to get into Softice. You must be sure that "Loogie" is the active process. A rude way would be trying to "catch" the process by pressing CTRL-D until you finally got it. The better way is typing "addr loogie" and "map32 loogie" to get a list of the game's objects and its virtual addresses:
:map32 loogie LOOGIE .text 0001 017F:00401000 0000DB9F CODE RO LOOGIE .rdata 0002 0187:0040F000 00000340 IDATA RO LOOGIE .data 0003 0187:00410000 00004714 IDATA RW LOOGIE .idata 0004 0187:00415000 00000EA4 IDATA RW LOOGIE .rsrc 0005 0187:00416000 00026BB4 IDATA RO LOOGIE .reloc 0006 0187:0043D000 000017EE IDATA RO
As our address 412F74 resides in .data section, we will use 0187 as selector. So you simply type:
bpmd 187:412f74 r
Softice will then break here:
Break due to BPMD #0187:00412F74 R DR3 MSR LastBranchFromIp=00401C1B MSR LastBranchToIp=00401C3A 017F:00401C37 5E POP ESI 017F:00401C38 5B POP EBX 017F:00401C39 C3 RET 017F:00401C3A 833D8C45410000 CMP DWORD PTR [0041458C],00 017F:00401C41 7530 JNZ 00401C73 017F:00401C43 A1742F4100 MOV EAX,[00412F74] <- Copy scorepoints to eax 017F:00401C48 3905A82F4100 CMP [00412FA8],EAX <- and compare it with the value stored inside 412FA8 017F:00401C4E 7723 JA 00401C73 017F:00401C50 C7056045410002000000MOV DWORD PTR [00414560],00000002 017F:00401C5A FF05B02F4100 INC DWORD PTR [00412FB0] 017F:00401C60 E8DBF4FFFF CALL 00401140 017F:00401C65 E826F8FFFF CALL 00401490 017F:00401C6A B801000000 MOV EAX,00000001 017F:00401C6F 5F POP EDI 017F:00401C70 5E POP ESI 017F:00401C71 5B POP EBX 017F:00401C72 C3 RET 017F:00401C73 8B4C2410 MOV ECX,[ESP+10] 017F:00401C77 81F9007F0000 CMP ECX,00007F00
Have a look at 401C43, where Softice broke in. Our score will be "copied" to eax and then -at 401C48- compared with the dword inside 412FA8. So let's see what is stored inside 412FA8. Type ? *412FA8 and Softice will show you the value 412FA8 is pointing to.
:? *412fa8 00000014 0000000020 ""
14 hexadecimal equals 20 decimal. Twenty, XX, 20 hmmm.. sounds familiar. That
is the score we have to reach for level one. Great! Now all we have to do is
to extend our little trainer engine with a function, which copies some memory
from one place to another (from 412FA8 to 412F74 - as 412FA8 contains the score
to reach and 412F74 holds our current score) and we'll set up a new hotkey for
that (don't forget to update the dialog-file). It could look like this:
And here is our new function, which will copy a dword from one virtual address to another.
Engine_Mov Proc lpWndCap: DWORD, lpSrcAddress: DWORD, lpDstAddress: DWORD, lpBuffer: DWORD
lpWndCap is a pointer to a string containing the window's caption (e.g.: WndCap db 'Beavis & Butt-head Hock-a-Loogie',0). lpSrcAddress is a pointer to the address holding a value that will be copied to lpDstAddress. lpDstAddress is a pointer to the address where the value from lpSrcAddress will be copied to. lpBuffer is a pointer to a variable that we will use for temporary storage of the value to be copied.
Here the updated routine to fetch the F11 key:
invoke GetAsyncKeyState,VK_F11 ;Has F11 been pressed? .IF eax==TRUE ;Yes? Great! Then ... ;copy value invoke Engine_Mov,addr WndCap, LevelAddr, ScoreAddr, addr ScoreBuf .endif
chapter2 sources - sources and binaries