The target: BreakThrough What this is: An arcanoid-clone game What we're going to do: Find a way to cheat in the game (Hehe..) What we need to anaylze it: W32Dasm, some knowledge of win32 API What we need to patch it: Borland resource workshop, HIEW 6+ Start up this game, and look at it. To the right you see that you have six balls left to play with. Since I'm not very good at arcanoid, I want to have some more. ;-) Make a copy of the main .exe-file and disassemble it. Look in the string-references for "Balls left:". You'll see that the string is a resource, with the ID 00027. Since the string is a resource, we could tell that when the program needs to use it, it has to call LoadStringA, and that's useful to know. If you search for it in the disassembly, you'll find that W32Dasm finds it at many different locations, but only one is followed by a call to LoadStringA, and that's the real one. Take a look futher down. We see a reference to the string " %u ". Now I'm really convinced, and I think that everybody who knows the syntax for the formatspecifiers for sprintf in C is too. And what do we see right after that? Yep, a call to wsprintfA. We've come right! ;-) The syntax for wsprintfA is: wsprintfA( DestinationBuffer, FormatSpecifier, ... ) "..." is the arguments that should be formatted according to the FormatSpecifier and be placed as a string in DestinationBuffer. So what does this program pass to wsprintfA? 1. movsx eax,si 2. push eax 3. lea ecx, dword ptr [ebp+0ffffff00] 4. push 414110 ; This is the formatspecifier, " %u " 5. push ecx 6. call wsprintfA Okey.. We'll find the most interesting thing on the top. In this case, ecx is set to point to DestinationBuffer at line 3, and is pushed as the first argument on line 5. The formatspecifier is pushed as the second argument at line 4. But the things we want to know, is where it gets the number of balls left. At line 2 eax is pushed as argument #3 (...), so at that point eax holds the number of balls left. At line 1, eax gets its value from si, and if we look a couple of rows up, we see that si gets its value from a fixed memoryaddress with this code: mov si, word ptr [00416700] Bingo! From this we could tell that the address 416700 holds the number of balls left. From this point, we have many different ways to patch this code, let's say that we found the location where it set the value to 6 and then patched it to give us 1000 balls to play with. Or we could find the location where it decreases the value when you loose a ball and nop it out. But if we don't always want to be cheaters then? Wouldn't it be nice to have a button to push every time you want to have more balls? I definitely think so.. Let's open this program in Resource Workshop. You'll see that it has a couple of dialogboxes, most of them for the leveleditor, but the last one is the About-box. Open that one in edit-mode and simply add a button, set the text of it to "Cheat" and make sure to note the Control ID of it. Save the whole project, start the game and open up the about-box. Hehe, there's our nice button, but nothing happens when it's clicked. Let's fix that! Remeber from Resource Workshop that the dialog ID of the about-box was 114? Anyways, it is. 114 is equal to 72 in hex, and that's what we need to find the message-procedure of the about-box. Back to W32Dasm, and click the Dlg-ref button. The second last in the box is "Dialog: DialogID_072", and that's the one we're looking for. Doubleclick it to find that it is displayed with DialogBoxParamA. This is what win32.hlp says about that API: int DialogBoxParam( HINSTANCE hInstance, // handle to application instance LPCTSTR lpTemplateName, // identifies dialog box template HWND hWndParent, // handle to owner window DLGPROC lpDialogFunc, // pointer to dialog box procedure LPARAM dwInitParam // initialization value ); So the fourth argument of this API is the offset of the message procedure. Look in your disassembly, and see that the fourth argument in this one is 40192E. This is the first point we should patch this program at, but not yet. Let's think of what we could do in this situation. We've got a button in the dialog, the offset of the message procedure and we've got the location where the message procedure of the dialog is set. What if we included some of our own code into the .exe, which would check if the messages sent to the dialogbox is WM_COMMANDs from our button, and if it is, we do some cool things, if it's not, we just pass the message to the original procedure? Sounds like a good idea to me! ;-) Now, we've got another problem. Where are we going to put our code? What would Win95.CIH do in this situation? Yes! It would fill up one of the gaps that is present in almost every PE-executable and then just make a slight change in the header of the file to make sure that enough memory is allocated when the game is loaded. Let's do the same! Open the .exe in HIEW and go to disassembly mode. Press F8 to get info from the header and press F6 to get the object-table. We'll see that the biggest object is .text, and that the PhysSize of it is 11E00 bytes, but the VirtSize is only 11C8C bytes. That means that the object has 372 unused bytes at the end of it, and that should be more than enough for our code! To find out where the used code ends, just add the VirtSize with the RVA and the imagebase (11C8C + 1000 + 400000 = 412C8C). This will be the offset of our code, and therefore, we could now do our first patch. We change the fourth argument to DialogBoxParamA from 40192E to 412C8C, and now we've redirected the messages to the spot where we're going to put our code. The next step is to write the code at 412C8C, but first we need to list what we're going to do. 1 Check if the message is WM_COMMAND, if not go to 5 2 Check if the control that sent the message was our button, if not go to 5 3 Put the amount of balls we want in [00416700] 4 Update the window that displays the amount of balls left 5 Jump to the original message procedure This is how we will do it: 412C8C: 817C240811010000 cmp d,[esp][00008],000000111 ; WM_COMMAND = 111h 412C94: 7522 jne .000412CB8 412C96: 66817C240C2004 cmp w,[esp][0000C],0041F ; The ID for the button is 1055 = 41Fh 412C9D: 7519 jne .000412CB8 412C9F: 66C70500674100FF7F mov w,[000416700],02710 ; This will give us 10000 balls 412CA8: 6A00 push 000 412CAA: 6A00 push 000 412CAC: A1F85D4100 mov eax,[000415DF8] ; [000415DF8] = The HWND of the statuswindow 412CB1: 50 push eax 412CB2: FF159C154200 call InvalidateRect ; Update it 412CB8: E971ECFEFF jmp .00040192E ; Jump to the original message procedure Now there's only one thing left, to update the header. The last byte after our code is at 412CBD. To get new VirtSize, subtract it by the imagebase and then by the RVA of the object (412CBD - 400000 - 1000 = 11CBD). Switch to hex-mode in HIEW and go to the beginning of the file. proceed a bit and you'll see the .text-label. The VirtSize is specified 8 bytes after the label begins, and should look like this: 8C 1C 01 00, since the old VirtSize was 11C8C. Change it to: BD 1C 01 00, and you should be ready to go! Exit HIEW and start up the game. It should give you six balls to play with. Open the about-box and press the Cheat-button, and you should have 10000 balls to play with! Chafe / The Exterminators