|
Okay, this 's gonna be a long and not so easy essay and I'll try it to
explain as good as possible. First of all I'll give a little summary on
how I'm going to approach this program:
- The program is packed with ASPack, so we have to manually unpack it.
- We can't use w32dasm to find the protection so we have to use SoftICE
for it
- As the .exe becomes too big after unpacking I'll show you a method
on how to patch it without unpacking
Install the program and run it. You'll notice that you can't enter a
serial, i.e. you can't register it. That's, of course, why it is called
a trial version. When trying to disassemble, w32dasm locks....hmmm.
If we take a look in a hexeditor, we can see (quite in the beginning)
a .aspack section! That tells us that the program is packed. So let's
manually unpack. But!!! Wait! Before you start I'll tell you how to do
it ;-) Load the packed program in the SoftICE symbol loader (so it breaks
directly after the program is loaded), start tracing through the code
until you see a 'ret' instruction and until you see what the new entry
point is (I'll explain this later). Then put the program in an infinite
loop, quit SoftICE and dump the whole process with Procdump. Then fix
the PE-header, that means: change the original entry point into the entry
point you've found at the end of the unpacking routine.
If you're confused, and don't understand this all: don't worry, I'll explain
it in some more detail!
Okay, let's do it: fire SoftICE symbol loader. Click on the "Open
map" icon and double click ACDSee.exe, then click on "Load"........what!!??.......SoftICE
doesn't break! Don't panic, it are probably the section that have characteristics
C00000020. Those characteristics have certain meanings on if the section
should be read-only, writeable, etc... . (and I strongly recommend you
read Volatillity's unpacking tutorial, also published on this site, first
before continuing). Anyway, to make ACDSee break, we'll need to change
the characteristics of the .text section to C00000040. How do we do that?
Startup Procdump, click on "PE-editor", load "ACDSee.exe",
click on "Sections". Right click on the .text section, click
on "Edit section", change C00000020 into C00000040. Click ok
and exit procdump.
Now restart ACDSee from within the symbol loader. It breaks! Now we have
to trace through the unpacking code until we find the 'ret' instruction.
Note that we'll have to set some breakpoints and leave SoftICE until it
breaks again to fasten the tracing. Otherwise it would take hours and
hours before the tracing would end. Again, if you don't understand: first
read Volatility's essay on manually unpacking!
Okay, when you traced to the 'ret' instruction you should see this:
Start partial code
0137:005554B4 OR EBX,EBX
0137:005554B6 MOV [EBP+00442E5C],EAX
0137:005554BC POPAD
0137:005554BD JNZ 005554C7 <- Always jumps
0137:005554BF MOV EAX,00000001
0137:005554C4 RET 000C
0137:005554C7 PUSH 004A33BF <- This is where the real program starts
0137:005554CC RET
End partial code
If you look at the EAX register after the POPAD, you'll see 00555001.
That's our new entry point. Note it. When you're on the 'RET' instruction....stop
tracing! It's now that we have to dump the program. Now, if we quit
SoftICE, ACDSee will continue running and we won't be able to dump it
anymore....so let's change some code in that way, if we quit SoftICE the
program loops forever. How do we do that? Type (do not type the (enter)
thingies, just wants to say that you have to press enter after typing
a certain instruction!):
a eip (enter)
jmp 5554CC (enter) (enter)
Now press ctrl-d. Startup Procdump, scroll down in the application list.
You should see ACDSee somewhere at the end of the list. Rightclick on
it and click Dump full. Save it as ACDunp.exe Then do a PE-edit on ACDunp.exe
to change the old entry-point to the new one....but hey.....it's already
00555001....hah......well, then we don't have to change anything :-) Hmmm,
now, don't forget that ACDSee.exe is still looping around....let's undo
that first: press ctrl-d, sice pops again and you'll see that we're still
at the exact location from where whe quit sice. Now type:
a eip (enter)
ret (enter) (enter)
Press ctrl-d, ACDSee starts running, close it and now run ACDunp.exe.
If you did everything fine, it should run just like the original packed
ACDSee.exe Notice that its size is much bigger than the original .exe!
I tried to disassemble the unpacked .exe but it didn't work. So, let's
use SoftICE to crack the whole stuff. First thing to do now is to disable
the trial limit. I searched quite some time to find the locations where
the comparisons are made, but I did find them. I won't tell you the other
hundred methods I used that didn't work, but the right method straight
away: Set a breakpoint on GetSystemTime, load ACDSee, SoftICE breaks.
Press F12, five times to get to the comparisons. You should see
this:
Start partial code
:0137:00433A85 CMP EAX,-04 [<- Error checking]
:0137:00433A88 JNZ 00433AB4 [<-Jump
if no errors]
..........
:0137:00433AB4 CMP EAX,-05[<- Expired?]
:0137:00433AB7 JNZ 00433ACC [<- If expired, don't jump...in this case
let it jump]
.........
[Trace through the code somewhat further until....]
:0137:004045AD ADD ESP,04
:0137:004045B0 TEST EAX,EAX [<- Expired?]
:0137:004045B2 JNZ 004045C6 [<- If expired, don't jump]
End partial code
To patch the program you'll have to change the JNZ 00433ACC and JNZ 004045C6
to JMP 00433ACC and JMP 004045C6. Therefore you have to know the real
offset. So fireup HIEW, load ACDunp.exe, press F4, press F3. Scroll down
until the offset changes in 401000. Press F3 and you'll see that the 401000
changed into the real offset: 600. To get the real offset for offset 00433AB7
let's do some math: 433AB7-401000+600=330B7.
So the real offset is 330B7. Press F5 (=goto code location), enter 330B7
and there we are :-) Change the JNZ into a JMP, do the same for the other
JNZ.
Voilà, the time trial is patched!
Now, did you notice that if you run ACDSee for the first time on a new
day it displays a reminder that it's the trial version? And if you run
it a second time(or more)on the same day it won't display it anymore?
Well, at least I noticed. So I fired up Regview to check if there was
a key like "remind". ACDSee's keys are located at HKLM\SOFTWARE\ACD
Systems\ACDSee\. Let's take a look......... .Aha! What do we see
there: EvalRemind! Yups, and the value stands for the day of the month.
It works like this: ACDSee stores when you last used the program. Imagine
you used it at 1-01-2000. The value stored in EvalRemind will be '01'.
You go to sleep, wake up, and use it again. It's now 2-01-2000. ACDSee
compares the stored value '01' with todays date '02'......as it's not
equal it will jump to the "showreminder" window.
Okay now, let's think.....think very deeply. We could set a breakpoint
on RegQueryValueExa, but that would be a waste of time as this procedure
is called about a thousand times, and we would NEVER find out where EvalRemind
is read. But what did I say before? Everytime you use ACDSee it stores
the day in the EvalRemind key......so it probably uses RegSetValueExa
to store it. Let's give it a try: load ACDunp.exe in the symbol loader,
load it, set a breakpoint on RegSetValueExa. You can notice that this
API is called five times! One of these five stores the day in the
EvalRemind key. How do we find out? With Regmon. Fireup regmon, set filters
to exclude following processes: iexplore;explorer;regmon. Then run ACDunp.exe
and let everything load. When you don't see any registery action anymore,
freeze it so Regmon won't log any registery actions anymore. Goto the
beginning of the huge list (about 4500 registery actions, get the idea
why windows is so slow?) and search for "setvalue". You'll also
find it five times......and look........the fifth is our EvilRemind
key!!
Load ACDunp.exe again, set the breakpoint on RegSetValueExa, when SoftICE
pops the fifth time, press F12 twice to exit the procedure and
you'll land here:
:0137:00407BF2 CALL 00498670
:0137:00407BF9 JNZ 00407C12 <- You land here
If this conditional jump jumps, it won't display the reminder screen.
You can find out by: tracing through the call and trying to understand
the code (which I did), or you can set a breakpoint on the jump, change
the system clock and re-run ACDunp.exe and look what it does then.(it
will not jump). Patch this JNZ to JMP too. The job is done!
Done? Yea well, the filesize is damn big now. Can't we just patch the
packed file? Yes we can!
Let's think again.....t-h-i-n-k! We can't patch the prog before it is
unpacked, because when still packed the instructions we gotta patch aren't
there yet. No problem, we know the end of the unpacking routine (see beginning
of this essay). Then we gotta find some empty space in the ACDSee.exe
to insert our assembly patch code. You can do that by loading ACDSee.exe
into hiew and to scroll and scroll and scroll until you find code of which
you think it is not used (like lots of 00000000 hex values). Now be careful,
because some of these 'empty' spaces are used to store unpacked data in
it. Anyway, I used offset 00556C25 to insert
our patching code (the real offset is 88025). How do we work?
At the end of the unpacking routine we jump to 00556c25
(=place where we inserted our patch code)
The patch code is executed, let it jump back to the end of the unpacking
routine.
The code we insert looks like this:
PUSH 4A33BF //We 'll have to NOP out this
instruction at the end of the unpacking routine, so we'll insert it here.
PUSH EAX //Save the EAX register
MOV AL, 0EB //Move the hex code for JMP (=EB) into AL
MOV [00433AB7], AL //Patch the JNZ 's to JMP
MOV [004045B2], AL
MOV [00407BF9], AL
POP EAX //Restore the original value of EAX
JMP 005554CC //Jump back to the end
of the unpacking routine (we'll jump to the 'RET' instruction)
Okay, if this is the first time you're doing this method of cracking I
can imagine this is pretty hard, so follow my steps:
Load ACDSee.exe in HIEW
Press F4, then F3
Press F5 and enter "868BD" (=goto the JNZ at the end of unpacking
code, you can see this at the beginning of this essay)
Press F3(=edit)
Press F2(=insert assembly code)
Enter "JMP 88025" (=jump to our inserted code, note that you
have to use the real offset)
Enter "NOP"
Enter "NOP"
Press escape, press F9(=save changes)
Press F5 and enter "88025"
Press F3, then F2 and insert the assembly code I typed above (our assembly
patch code in blue)
Note *again* that you have to type "JMP 868CC" for the JMP 005554CC
as you have to use the real offsets!
Press escape, press F9(=save)
To make things even more clear here's a summary on how this cracking approach
works:
|
[end of unpacker code]
jmp inserted_code
back: ret
......(other code)......
inserted_code:
PUSH 4A33BF
PUSH EAX
MOV AL, 0EB
MOV [00433AB7], AL
MOV [004045B2], AL
MOV [00407BF9], AL
POP EAX
JMP back
|
Pfiew! That's it man! Run the program and if you did everything as I
told you it should run fine: it won't expire and it won't display the
remind screen anymore! Another target cracked.
Btw, if you should see any mistakes don't hesitate to mail me!
|