ACDSee v3.0 trial build 1209
[Reversing essay]

Subject: Cracking
Target: ACDSee v3.0 trial build 1209
URL: http://www.acdsystems.com
Author: BlackB
Date: 2000-03-05
Tools used: SoftICE, Regmon, RegView, HIEW, Procdump
Difficulty (scale 1-5): 3

Before starting!
This essay is for knowledge purposes only!!
Software developers spend much time in making their programs. They live from the money we give them!
Please buy good software!!
I. Introduction
Hi! Again an essay. This time on ACDSee. Note that in this essay some more advanced cracking techniques are used. Profound knowledge of cracking and working with HIEW is inevitable. If you are a real newbie I suggest you first read the other essays published on this site! If you feel like doing this.....go ahead and enjoy. Again, this essay is intended for more advanced crackers!! It implies that you have a profound cracking knowledge!
II. About the protection
30-day trial/ nagscreen/ ASpacked/ anti-w32dasm
III. Cracking it

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!

IV. In the end

I worked a lot on this essay! Really, a lot!! I hope you enjoyed it and most important that you learned something!!
Thx goto Lazarus coz' he gave me some advice on assembly.
I'm done......yea!

Greets

BlackB

Endnote:
Essay written by The Blackbird © 1999-2000
This essay can be freely distributed/ published/ printed etc... as long as no modifications are made.