Purpose : This is the second lesson in using self modifying code, a bit more difficult than the first essay.
Approach : This program is a demo, with an annoying 10 second nag/splash
screen when you start it up, and one when you
exit the program. We will be removing these.
Tools : SoftICE, W32Dasm, Hiew & Procdump.
So lets start up the program to get a good idea on what we're up against. Might as well grab a beer while you are waiting on the splash screen to die, cause it takes forever. Ok, as we run through the program we notice that there are no feature restrictions or nags while running the program, this is good. So now we go and exit the program and ack, another nag asking us if we'd like to register or press OK to exit.
The first thing we are gonna do is kill that annoying splash screen.
So lets start this program up in softice's symbol loader and start doing
some tracing to see if we can find where that nag is created. As you are
tracing, you will come upon a call at 4E546E and as you step over the call,
you will be kicked out of softice for about a second, and you will see
the creation of the nag. This is where we want to go, so we set a breakpoint
on that call by typing:
When softice breaks on that location, you should follow the call with F8 and start your tracing again with F10. You don't have to trace for long before you step over the right call at 44CA93. So Ctrl+D out of softice and exit the program and start it again with the symbol loader. make sure you clear all your breakpoints by typing:
Now you can set your new breakpoint at 44CA93 by typing:
Now load the program and press F11 so it will break on that call. When it breaks, follow that call with F8. As soon as you follow that call you will come upon these lines of code:
:004498D0 53 push ebx
:004498D1 56 push esi
:004498D2 8BDA mov ebx, edx
:004498D4 8BF0 mov esi, eax
:004498D6 F686C002000001 test byte ptr [esi+000002C0], 01
:004498DD 7417 je 004498F6
:004498DF 84DB test bl, bl
:004498E1 7409 je 004498EC
:004498E3 808EC002000002 or byte ptr [esi+000002C0], 02
:004498EA EB23 jmp 0044990F
Hmmm very interesting, the je at 4498DD has the zero flag set, so
it will jump to the code where the nag is created. So, lets invert the
zero flag by typing:
r fl z
Now start tracing with F10 and we pass the je at 4498E1 without jumping, and we hit the jmp at 4498EA and we press F10 one more time and we see a ret at address 449911. YES! so we Ctrl+D out of softice and the prog loads without the delay of the first nag/splash screen. Now we know exactly where we need to patch to kill the first Nag. But we can't simply use a direct patch because this piece of code is used by the program many times, so it will mess up. We need some self modifying code.
Now probably the hardest part of cracking this program comes into
effect. Finding a spot to add our self modifying code. So lets do a text
ADD [EAX], AL
Whose opcodes are 0000. We are gonna need a fairly large amount of usless code like this to add our code. It isn't long before we find what we're looking for at around the address 406EE5. This is where we will add our code. The first thing we need to do is make the program jump to this location back at the je we want to change. So we go back to address 4498DD and right down the opcodes for the next couple of lines. 741784DB7409808E will be sufficent enough for our purposes. So lets change the je at 4498DD to a jmp 406EE5. The opcodes for this jump are:
Also, to keep things neat, we should put a nop at the next byte so at 4498E2 we should add a nop. Now we need to add our self modifying code. First we need to have the program replace the bytes we just changed, back to its original state. we can do this with a
mov dword ptr [4498DD], 0DB841774 <--- remember to list the bytes
in reverse ;)
The opcodes for this line are:
But we aren't done yet. That is only about half of the code we replaced, so we need to add another line:
mov dword ptr [4498E1], 08E800974
The opcodes for this line are:
Now we just need the program to jump back into its normal routine. There really is several places we could jump to, but I'm gonna go ahead and choose jmp 44990F (read the pasted code above) The opcodes for this jump are:
Now we have our first nag screen patched, so lets run the program
and see how it works. Crap we forgot to change the Code section's characteristics
to allow both reading and writting. So lets load the program up in procdump's
pe editor and change its characteristics from:
60000020 to C0000040
Lets run the program now, No longer is there a long delay in the program loading up, even though the nag still flashes for less than a second, the program is loading instantly. GREAT!!! the first nag is dead. But, for some reason, it will only run once (at least on the two puters i've patched it on) After that when we try and run the program nothing happens? It just doestn't load up at all. Could this be a checksum of some kind? I could spend an hour speculating on this, but I won't, I'll just tell you how to fix it. Load the program in the symbol loader and start tracing with F10 untill you come across a jne at adress 4E5445. If your memory is good enough, you'd remember that this jump was never executed before, but if your memory is poor, like mine. You should notice that the jne is wanting to jump to a piece of code far below where the program's nag was created and below where the program itself loaded up. All we need to do is nop that jne out and the program will load up like normal everytime. Now we need to focus our attention on the second nag, which I'm sorry to say, is going to be a bit more difficult.
So far in this essay and in the last, all that I've explained is how to use self modifying code for nags at the begining of the program. But if the nag is at the end of the program, and as with the other nags, the program uses the same code to create/destroy that nag as it does with every single other dialog in the program? The solution isn't too difficult, we just need to put a comparison of some kind in our added code to make sure we patch the right dialog.
The first thing we need to do, is figure out where in the program
that the last nag is being created. This isn't too hard of a task. Run
the program, then after it loads up, Ctrl+D into softice and type:
Now Ctrl+D out of softice and hit exit on the program. You'll be poped back into softice inside user32.dll, we don't wanna be here so we press F11 to break again. This time we break in the programs code at address 44C69B. Lets trace a little bit by pressing F10. After a little while we come across a je at adress 44CC91. Lets invert the zero flag to see what happens. WOAH! the program exited without you having to click ok on the nag. This is what needs to be patched. But as with the code above, if we patch it, it'll mess up the rest of the program. So lets load the program again, and again set a breakpoint on showwindow. Once again exit the program. Once we break on our programs code. Make note of the value in the register EBX. The value is 4D1D14. This is VERY important for when we add our self modifying code, basically what we will be doing is at the jmp you just broke on, we'll change it to jump to a piece of worthless code (where we'll add our new code) then we'll add a cmp ebx, 4D1D14 and a jne back to the normal routine of the code. We will have this there in case the program is using that particular piece of code for other dialog's. If they are the same, and the program doesn't jump, then it will go into its patching routines and that, theoretically should kill the nag. Probably the hardest part now is figuring out where to add our new code. I'll save you the time and hassle of searching by telling you to add it at address 47600B. Now we need to make the program jump to that location while the nag is being created. Remember when we broke on showwindow? we landed right on a jmp. This is a perfect place to put our jump. Just be sure to write down the memory address it was originally jumping to, which is 44C7A5. Now change that jmp to a jmp 47600B. The opcodes for that jmp are:
Now we need to add our new code starting at 47600B. Remember I said we are going to need to put a comparison in to make sure we patch at the right time. And that the comparison was:
cmp ebx, 4D1D14
So we add that line at address 47600B. The opcodes for that line are:
Now we need the program to jump if they are not equal. Ane we want it to jump back into its normal routine. So we'll add a jne 44C7A5 at address 476011. The opcodes for this jne are:
That will make the program return to its normal routine, without any patching, if it is not exiting. But if it is exiting, we want it to patch itself. Remember the je that we inverted at 44CC91? Well we need that to be patched so it never jumps we can do that by simply changing the 740F to a 7400. But remember, directly patching will mess it up, so we need to add self modifying code to patch it for us. So right under that jne that we just added, we need to add this line:
mov byte ptr [44CC92], 000
The opcodes for this line are:
Now the program will patch itself when it gets to that line. Now we want the program to jump back to its normal routine. So we add a jmp 44C7A5. The opcodes for this jump are:
YES!!! The program is now fully cracked and ready to be fully evaluated.
Greets (so many friends, please don't get mad if I left you out) :-
AB4DS, Torn@do, Kwai_Lo, Killer_3k, Crackz, N0-B0dy, Azir, Darkie, Data_, Bud-, all the guys in #cracking4newbies, #shock, and #hlm2k.
Essay by Kathras. 11/26/99.