Start softice, run the symbol loader, load thebat.exe and wait until the
nag-screen is displayed. Don't close the nag-window. Switch to softice and
do a breakpoint on the closing of the window:
BPX destroywindow
Let softice run and press either the OK or Exit button of our nag-screen.
Softice will pop-up, disable the breakpoint (type BC *) and start a search
for the text that is displayed through the nag-window:
s 0 l 90000000 'This program is'
Softice will find a few locations somewhere in memory, but the one we need
is located in the TheBat!UPX0-part. Softice should find the text at the
address 6936C9. Now, set a memory access breakpoint at this address:
BPMB 6936C9
Let softice go, exit The Bat! and restart it right away (use the symbol
loader menu Module/Load). Softice will now stop at the first memory access
at our address. Ignore the first one - it's done by the UPX-unpacker, which
is decompressing our program. Press F5 to ignore this stop. Softice will
break once more at this position:
xxx:004016A3 F3A5 REPZ MOVSD
From now on, press F12 until the nag-screen appears (takes 19 keypresses).
Again, click OK or Exit and softice will break one last time at this position:
001B:0054803B 84C0 TEST AL,AL
which is part of this routine:
1 001B:00548029 8BD8 MOV EBX,EAX
2 001B:0054802B 803D0C275F0000 CMP BYTE PTR [005F270C],00
3 001B:00548032 751E JNZ 00548052 (NO JUMP)
4 001B:00548034 8BC3 MOV EAX,EBX
5 001B:00548036 E87575F9FF CALL 004DF5B0
6 001B:0054803B 84C0 TEST AL,AL
7 001B:0054803D 7413 JZ 00548052 (JUMP)
The CALL in line 5 is the window-popup. The TEST AL,AL in line 6 determines
whether we've presses OK or Exit. It will take the jump in line 7 if we've
pressed the OK-button. See line 3 ?
This one also jumps to the place where we would go when pressing OK. But in our
case the jump of line 3 did not seem to work. Let's display the byte at the position
accessed by line 2 (005F270C) - it contains a 0. If it would have been a 1, the jump
in line 3 would have worked, jumping over the nag-popup-call.
Disable all breakpoints (BC *) and set a breakpoint on memory access at address
005F270c and let softice run, exit The Bat (ignore all breaks by softice) and start
The Bat! once more. Softice will break 3 times because of the decompressor, ignore
them (F5) and the fourth stop will be at a line similiar to our line 2 from above:
1 001B:005433A0 803D0C275F0000 CMP BYTE PTR [005F270C],00
2 001B:005433A7 741D JZ 005433C6 (JUMP)
This is the first time The Bat! checks this byte and the 0 isn't what we like to see
there - so let's change line 1 using the "a" command of softice to:
MOV BYTE PTR [005F270C],01
Now the byte is a 1 and every other check coming later will find this 1 and work
like if this has ever been so. If you execute the line and disable all breakpoints
The Bat! will never show any nag-screen anymore. Cool eh? :)
Where does the real program start?
How do we find a free part in thebat.exe, which is part of the decompression
routine and NOT part of the (compressed) data?
Open thebat.exe in your favourite hex-editor and search for the code of the
jump from above (E93867F3FF) - you'll find it at position 24007 (decimal).
Hmm... doesn't look like there's free space, does it? Scroll to the beginning
of the file... hmmm... some strange ascii-art, right? Hmmm.... jump to the
beginning of thebat.exe - there it is:
UPX 0.60 Copyright (C) 1996-1999 Laszlo Molnar & Markus Oberhumer
Why not use the copyright of UPX as space for our patch-routine? Okay, let's
do it. All we need now is the position of this copyright-text in memory. I'll
use the 'L' of 'Laszlo' as my first byte of the patch-routine. Use softice to
locate this copyright-text in memory and write down the address (which is
00400296 in the case of the 'L').
We need 2 lines of code to patch the code at address 005433A0 which looks
like this:
1 001B:005433A0 803D0C275F0000 CMP BYTE PTR [005F270C],00
2 001B:005433A7 741D JZ 005433C6
but should look like this:
1 001B:005433A0 C6050C275F0001 MOV BYTE PTR [005F270C],01
2 001B:005433A7 741D JZ 005433C6
The 2 lines that do the patch plus the jump to the real program are these:
1 00400296 C705A0335400C6050C27 MOV DWORD PTR [005433A0],270C05C6
2 004002A0 C705A43354005F000174 MOV DWORD PTR [005433A4],7401005F
3 004002AA E955361E00 JMP 005E3904
Are we done? Not yet! We've got to redirect the jump from the decompressor
so it runs through our 3 new lines. Simply change the jump at 006AD1C7 to this one:
006AD1C7 E9CA30D5FF JMP 00400296
Congratulations! You've just patched The Bat! - I hope this little tutorial helps
to understand how to patch compressed programes. Even if they crash w32dasm. :)
Have fun!
varroa, 5/5/99
een this is. It's clearly not a messagebox nor a dialog box. That makes it a resource ie a bitmap. You can try to bpx on messageboxA or dialogbox and softice will not break. So let's try a bpx on loadbitmapA. Softice will break inside LoadbitmapA so step out of it (F11) and look at the stack. There's only two PSP references and they are both at the bottom (since they were the last adresses pushed on the "Call stack").
PSP!.text+0029F15 at 0137:0042AF15
PSP!.text+5546 at 0137:406546
Lets look what that code looks like:
U 42af15
:0042AF10 E83BB5FDFF call 00406450
:0042AF15 83C404 add esp, 00000004
Put a breakpoint on 0137:0042AF10. Notice that there is no nag until you execute this call at 42AF10. So that means that we have found the nag caller. Now what. Lets nop the bastard out. Five nop's instead of call 00406450.
Sad but true, you can see the screen for a second and then it exits. Leaving us to our desktop. Hmmn What now? We need to find what went wrong (no kidding) to do that we trace the code until we find something useful. It's now time for you to experience the fat overbloated MFC42.DLL. Nop the call out and continue tracing.
From 42AF10:
You'll return to 5F4018C6 in MFC42.dll
After tracing that for some time you'll get to Kernel!_FREQASM. Keep on and you'll get to Kernel, user and FINALLY back to PSP at adress 4363XX. In this procedure there is some calls that sets up PSP's screen. At 4364CD there is a call to "updatewindow". You better place a breakpoint on 4364CD or any nearby adress so you don't have to trace on next time. Anyway executing Updatewindow and you'll see PSP's screen.
Here is the path we take:
:004364CD FF1560324C00 Call dword ptr [004C3260]
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0043648E(C)
|
:004364D3 8B4DE8 mov ecx, dword ptr [ebp-18]
:004364D6 E8754AFFFF call 0042AF50
:004364DB 85C0 test eax, eax
:004364DD 7576 jne 00436555 we have eax=0
:004364DF C645FC00 mov [ebp-04], 00
:004364E3 E83B020000 call 00436723
:004364E8 E99AFAFFFF jmp 00435F87 therefore we jump here
We have 0 in eax and therefore we will jump at :004364E8 to 435F87 and we will then end up at :
:00435F87 C745FCFFFFFFFF mov [ebp-04], FFFFFFFF
:00435F8E E8AA070000 call 0043673D
:00435F93 33C0 xor eax, eax
:00435F95 8B4DF4 mov ecx, dword ptr [ebp-0C]
:00435F98 5F pop edi
:00435F99 64890D00000000 mov dword ptr fs:[00000000], ecx
:00435FA0 5E pop esi
:00435FA1 5B pop ebx
:00435FA2 8BE5 mov esp, ebp
:00435FA4 5D pop ebp
:00435FA5 C3 ret
The ret will take us to a nasty place in MFC42.dll
:5F407EAB 85C0 test eax, eax
:5F407EAD 7415 je 5F407EC4
:5F407EAF 8B06 mov eax, dword ptr [esi]
:5F407EB1 8BCE mov ecx, esi
:5F407EB3 FF505C call [eax+5C]
:5F407EB6 8BF8 mov edi, eax
:5F407EB8 E81D990000 call 5F4117DA
:5F407EBD 8BC7 mov eax, edi
:5F407EBF 5F pop edi
:5F407EC0 5E pop esi
:5F407EC1 C21000 ret 0010
AND WE'LL CONTINUE
:5F407EC4 8B4E20 mov ecx, dword ptr [esi+20]
:5F407EC7 85C9 test ecx, ecx
:5F407EC9 0F8575440100 jne 5F41C344 Here we jump
:5F41C344 8B01 mov eax, dword ptr [ecx]
:5F41C346 FF5060 call [eax+60]
:5F41C349 E981BBFEFF jmp 5F407ECF
:5F407ECF 8B06 mov eax, dword ptr [esi]
:5F407ED1 8BCE mov ecx, esi
:5F407ED3 FF5070 call [eax+70] killer!!!!
:5F407ED6 EBDE jmp 5F407EB6
The call to [eax+70] kills the window, how rude of them to exit before we even had the chance to draw a single pixel.
You, dear reader have of course already spotted the jump that needs to be changed and you may be wondering why I included all this MFC code. However there's a reason why I'm showing you all this code of MFC42.dll and that's because there is a good chance that you'll miss the *important* code among the overbloated MFC dlls. And if you do so you'll end up patching the MFC42 code instead of your targets call.
Where where where is the important code, well if you change al from 0 to 1 at
:004364DB 85C0 test eax, eax
The whole bazar will start. But as I said before should you miss this spot you'll end up changing:
:5F407EAB 85C0 test eax, eax
:5F407EAD 7415 je 5F407EC4
Inside MFC42.dll wich IS NOT a good idea, since other programs may use this particular function.
This will be the last essay on selfexpainary cracks. I want to move on to more complex cracks. What I mean by that is that only protections that donot use the common API calls will be written down and that goes for any contributor too. I'm well aware of the prideness one feel when one has succeed in cracking by oneself for the first time, but there's too many essay's on the web explaining the same sort of protections. What I wont to cover is:
- Nagscreens that do not use the standard Messagebox(a), dialogbox or messagebeep
- Serial protections that do not use: GetDlgItemText(A), GetwindowtextA or any similiar API function
- ANTIDEBUGGING protections: This is VERY Important
- Turning demo version into full versions: This will be written down this summer
- Programs that don't have their "nag text" inside w32dasm (like PSP has)
- Encryptions schemes of nagtexts.
- And so on
They don't have to be tough or hard to crack, the important thing is that they offer some new schemes like this PSP essay who deals with a nagscreen that is a bitmaps.