TimeLock 3.03 Cracking
I love Marigold's cool humour:
TimeLock has to call WriteProcessMemory to decrypt the code; any other way will demand sophistication incompatible with such a mediocre background.
"A useful essay for everyone who feels that we study protection routines to avoid them, not to follow"
I wrote about TimeLock version 2 elsewhere. One more example here: BoundsChecker 5.02
for Visual C++. An unlock-key approach to it has been described by Shadow. Now let's see if
we could "just smash this cockroach." Look at these two code snippets from BC.EXE
.0000AD12: 8BCB mov ecx,ebx .0000AD14: FF75A4 push d,[ebp][-005C] .0000AD17: FF758C push d,[ebp][-0074] .0000AD1A: FF75BC push d,[ebp][-0044] .0000AD1D: 6828B74200 push 00042B728 .0000AD22: 6820B74200 push 00042B720 .0000AD27: FF1590E24200 call ?IsValidCopy@UIShell@NmShell@@QA ; in .0000AD2D: 85C0 test eax,eax ; BCShell.dll .0000AD2F: 7518 jmps .00000AD49 .0000AD31: C7466C00000000 mov d,[esi][0006C],000000000 .0000AD38: C745FCFFFFFFFF mov d,[ebp][-0004],0FFFFFFFF .0000AD3F: E853000000 call .00000AD97 .0000AD44: E949FFFFFF jmp .00000AC92 .0000AD49: 8BCF mov ecx,edi .0000AD4B: E81067FFFF call .000001460
After:.0000AD12: 8BCB mov ecx,ebx .0000AD14: FF75A4 push d,[ebp][-005C] .0000AD17: FF758C push d,[ebp][-0074] .0000AD1A: FF75BC push d,[ebp][-0044] .0000AD1D: 6828B74200 push 00042B728 .0000AD22: 6820B74200 push 00042B720 .0000AD27: 83C414 add esp,014 ; Correcting the stack .0000AD2A: EB1D jmps .00000AD49 .0000AD2C: 0085C0EB18C7 add [ebp][0C718EBC0],al .0000AD32: 46 inc esi .0000AD33: 6C insb .0000AD34: 0000 add [eax],al .0000AD36: 0000 add [eax],al .0000AD38: C745FCFFFFFFFF mov d,[ebp][-0004],0FFFFFFFF .0000AD3F: E853000000 call .00000AD97 .0000AD44: E949FFFFFF jmp .00000AC92 .0000AD49: 8BCF mov ecx,edi .0000AD4B: E81067FFFF call .000001460
Red lines show patching, blue lines - unreachable part of code. tl32v20.dll has still to be
present after that but is never called. Sniffing the way through the dead listing took half an
hour or so. Not a key generator, of course, but it works...
One of problems with TimeLock 2 is that the actual implementation of protection depends on
application programmers, and nice people among them always tend to spare crackers' effort.
This has been amended in a new version. TimeLock version 3+ employs the so-called
"wrapping" technique. At first, an application is built without any protection and then is
"wrapped" around with TimeLock. For details let's go directly to our target: Ulead
GifAnimator 2.0. I found it through TuCows and forgot exact download URL. Executable
Ga_main.exe is initially 538949 bytes long and is protected with TimeLock ver. 3.03
(tl303inj.dll). (Both these points will be different in the end ;)
hiew566 | Any hexeditor with block write capability
TimeLock 3.03 is a "fresh start" of old protection
...Wdasm disassembler output looks strange: no imported modules, while even exe-file viewers
show quite a list. For now, let's make a notice of this fact. The executable has an additional
section besides the standard ones - PREVIEW (- they are so vain at Preview Soft.) - and a
program entry point is within it:
//******************** Program Entry Point ********
:00486000 FF74240C push [esp+0C]
:00486004 FF74240C push [esp+0C]
:00486008 FF74240C push [esp+0C]
:0048600C 680036C526 push 26C53600
:00486011 68A96DC9E0 push E0C96DA9
:00486016 68EA643A40 push 403A64EA
:0048601B FF15C4634800 call [004863C4]; tl303inj!PleaseTraceIntoMe_MrCracker
:00486021 68FFFFFFFF push FFFFFFFF
:00486026 FFD0 call eax
:00486028 C20C00 ret 000C
So, the first point of wrapping: TimeLock checks our credentials before passing the control to
the application and independently of it. And after mildest brain effort we may guess that it
returns application entry point, if check is successful. (Address of Kernel32!ExitProcess, if
not.) Let's learn more about wrapping and try to look for the original entry point in the listing.
A program usually has a sequence of calls to specific APIs at entry (e.g. GetStartupInfo).
Wdasm is of no help to us as it failed to recognize any imported functions, but neither is IDA.
IDA shows imported functions alright, and GetStartupInfo is among them, but it is never
called! An obvious guess, that part of the code is encrypted, may be confirmed at Preview
Software Web-site - they call it Bag Of Bytes, BOB. So it looks like we have no choice but
to take invitation of the function name. (Imagine, it is honest, not a bit of provocation in it!) In
my case there was also another, quite compelling, reason: God knows why, trial period
expired even before the downloading date. So, after the first launch, I had no opportunity to
try nor even to buy!
A journey (with SoftIce) into TimeLock proceeds without much adventure. In a due time one
arrives at this code snippet:
(ImageBase will be different because of collisions between many DLLs)
:10008D04 push 100353D8
:10008D09 push eax
:10008D0A Call USER32!DialogBoxParamA
:10008D10 mov edi, eax
:10008D12 mov esi, dword ptr [10034AEC]
So, bpx 10008D10 and back to the reality to face a familiar nag screen (with "Try first"
button grayed). After pushing "Cancel" one lands at the breakpoint. Value in eax is 2 (button
number) and should be changed to 1 ("Try first"). Now on we go... till message box "Trial
period expired" tells us that the disabled button is not the only obstacle in our way. Well, in
the second round one should make one more stop:
:1000C0BC call 10011190 ;dec eax manually to avoid equallity
:1000C0C1 cmp eax, dword ptr [ebp-24]
:1000C0C4 jne 1000C0E6
Ooooph... Trial period continues now.
TimeLock has to call WriteProcessMemory to decrypt the code; any other way will demand
sophistication incompatible with such a mediocre background. So, the next stop:
:1000C4FF lea eax, dword ptr [ebp-18]
:1000C502 push eax
:1000C503 mov eax, dword ptr [ebp+FFFFFF24]
:1000C509 push eax ; number of bytes to write
:1000C50A mov eax, dword ptr [ebp+FFFFFF28]
:1000C510 push eax ; address of buffer
:1000C511 mov ecx, dword ptr [ebp-28]
:1000C514 push ecx ;address to start writing to
:1000C515 mov eax, dword ptr [ebp-3C]
:1000C518 push eax ; handle to process
:1000C519 Call KERNEL32!WriteProcessMemory
:1000C51F test eax, eax
Peeking into stack provides us with all vital information: address to write code to - xx6AB60;
length of code block written - 0x16E; and, consequently, the code itself. This should be copied
for future patching, of course. At this point one may thank for the invitation and leave for
Ga_main.exe. . . to test all our guesses on the essence of "wrapping". They proved to be
The first stage of cracking is quite straightforward: replace 0x16E bytes of code starting from
6AB60 with the snippet we copy and change the EntryPoint field from 86000 to 6AB60.
Now we have a good working application, but it still has an ugly wart of PREVIEW section
with tl303inj.dll clinging to it. Once we have understood the wrapping trick, why not to try
complete unwrapping? It is simple:
1 Reduce NumberOfSection to 6
2 Clean off PREVIEW section header
3 Cut off the section itself (the last 1349 bytes of Ga_main.exe), using any suitable utility
4 (optionally) Reduce ImageSize from 0x87000 to 0x86000
All? Be careful!!! This simpleton Wdasm has alerted us on queer behavior of .idata section.
(More sophisticated disassembler IDA didn't pay attention to such a nuisance.) One more
inspection of headers reveals the cause: Import Directory Virtual Address field contains
0x861D0 - address is in PREVIEW section. Not obvious feature of wrapping trick! It is not
difficult to find the real directory and change the field to the right value 0x79000. Directory
Length has a correct value already - 0x1F4. The final version of header is shown below with
changed fields marked with red color:
. . .00000240: 2E 72 65 6C-6F 63 00 00-3C 82 00 00-00 D0 07 00 .reloc <Â -_
Ga_main.exe is now 537600 bytes long and appears before our eyes in its untouched, virgin
state. (And you thought that only Aphrodite had this feature, don't you?)
You may remove from your HD all the TimeLock crap: tl303inj.dll, GA_MAIN.lic,
ws244869.ocx (in system directory) and, possibly, something else.
We must admit that the new version is definitely better than previous: Application may be fully
restored to its original form unlike trial builts, which protected with tl32v20.dll (especially with