TimeLOCK 3.1 (JaZZ)
The problem with TimeLOCK 3+ is that it rips out some code of the app, patching it at
runtime if all the lights are green! Needless to say that this crap encrypts the missing
bytes, so u won't find this 'ready_to_patch' in a dummy DLL or so ... Marigold had
come to the conclusion that the missing snippet had to be copied
(but he didn't explain how) then patched directly onto the exe. So I understood
'copied by hand'. What was in his case acceptable, because the snippet wasn't that long
('only' 0x16E bytes), is here impossible: as you'll see, an improvement of TL31INJ.dll
(among others?) is that the 'Bag of bytes' (how silly) is growing. For this NetscanTools
3.1 it ranks 0x716 (= 1814) bytes. My aim is to explain how to let bloated TimeLOCK do
its dirty work, and then gently stop it for saving the code to a file. So let's start
the cracking. A few lines from the dissasembled file of the example NSTSTD.EXE will
quickly explain it:
//******************** Program Entry Point ********
:004FA000 FF74240C push [esp+0C]
:004FA004 FF74240C push [esp+0C]
:004FA008 FF74240C push [esp+0C]
:004FA00C 68D879A084 push 84A079D8
:004FA011 68C1FED07D push 7DD0FEC1
:004FA016 68A29C5D1E push 1E5D9CA2
:004FA01B FF15D4A24F00 call dword ptr [004FA2D4] ---> this is the infamous call
:004FA021 68FFFFFFFF push FFFFFFFF
:004FA026 FFD0 call eax ---> when returning eax
contains the correct adress,
which is the targets 'real'
entry point
:004FA028 C20C00 ret 000C ---> yes, thats all!
As one can easily experiment, bypassing 4FA01B leads to nothing, even with the correct eax,
because this is precisely where TimeLOCK will patch. I didn't want to delve into the 'heavy'
TimeLOCK encryption, CRC checking (it checks its integrity, as the target's one),
all that boring stuff ... Seems that it'd be easy to let it do the job :-)
1) You have a working trial version, then jump over the 50 next lines
2) Like me, you 'burnt' it on the first trial day by pushing the date 1 month ahead, just
to see what happens, when restoring back the clock. (No, it's expired for good :=)
So up to work with TL31INJ.DLL. We have at first to bypass the dialogbox with the 'try'
button grayed for ever. With SoftICE we find it easily:
:100081FF 6A00 push 00000000
:10008201 A164A30310 mov eax, dword ptr [1003A364]
:10008206 6840830010 push 10008340
:1000820B 6A00 push 00000000
* Possible StringData Ref from Data Obj ->"TL_DLG_MAIN"
|
:1000820D 687CF60310 push 1003F67C
:10008212 50 push eax
* Ref To: USER32.DialogBoxParamA, Ord:008Eh
--> when ret.,eax=1 if pressed 'try first'
:10008213 FF1530960410 Call dword ptr [10049630]
:10008219 8BF8 mov edi, eax
So we bpx 10008213 (care with relocation, on my pc it was 508213 ...) When
SoftICE pops, F10, press cancel, then r eax=1 to simulate the 'try_it' push.
Useful tip
Don't try to patch at 10008213 to gain time. As you can see, this is an absolute adress,
the loader will PATCH after you, in case of relocation (this is highly probable), causing
a highly probable cras h... Doing this right you have to patch the relocation table. More
on this at the end.
Unfortunately, this is not enough, as marigold noticed with the previous version. Now we
are stuck in a routine beginning at 1002B020:
* Referenced by a CALL at Addresses: (a hundred of these follow)
|
:1002B020 83EC20 sub esp, 00000020
:1002B023 B908000000 mov ecx, 00000008
:1002B028 56 push esi
:1002B029 57 push edi
:1002B02A BE28730310 mov esi, 10037328
:1002B02F 8D7C2408 lea edi, dword ptr [esp+08]
:1002B033 F3 repz
:1002B034 A5 movsd
:1002B035 8B44242C mov eax, dword ptr [esp+2C]
:1002B039 8B4C2430 mov ecx, dword ptr [esp+30]
:1002B03D 8D54241C lea edx, dword ptr [esp+1C]
:1002B041 89442420 mov dword ptr [esp+20], eax
:1002B045 8B442418 mov eax, dword ptr [esp+18]
:1002B049 52 push edx
:1002B04A 8B54240C mov edx, dword ptr [esp+0C]
:1002B04E 50 push eax
:1002B04F 894C242C mov dword ptr [esp+2C], ecx
:1002B053 8B4C2414 mov ecx, dword ptr [esp+14]
:1002B057 51 push ecx
:1002B058 52 push edx
* Reference To: KERNEL32.RaiseException, Ord:01C9h
:1002B059 FF15F4950410 Call dword ptr [100495F4]
--> I'm afraid we won't go back from here :-)
:1002B05F 5F pop edi
:1002B060 5E pop esi
:1002B061 83C420 add esp, 00000020
:1002B064 C20800 ret 0008
To get out of this trap, just bpx 1002B020, restart the whole thing and when it pops
assemble a: ret 0008 (remember a 'hard' patch won't work coz of the CRC check ...
here causing a page fault ... How mighty they are at Previewsoft)!
Now whoever you are, expired or not, the app is working, (although weak cracked !).
By pressing F12 one or two times you should be brought back in 4FA021 (look above)
just before the damned CALL EAX. As you can see, EAX is now 43D680 and this
location contains no longer bogus code... We restart then the whole process with a
bpm 43D680, just to see how & where the big patch is aplied. We land here:
* Reference To: KERNEL32.ReadProcessMemory, Ord:01D8h
|
:10015C23 FF158C940410 Call dword ptr [1004948C]
:10015C29 85C0 test eax, eax
:10015C2B 740B je 10015C38
..... ; some code here
:10015C6A 50 push eax
:10015C6B 8D8D48FFFFFF lea ecx, dword ptr [ebp+FFFFFF48]
:10015C71 E84A140000 call 100170C0
* Referenced by a Jump at Address:10015C5C(C)
|
:15C76 8D45D8 lea eax, dword ptr [ebp-28]
:15C79 50 push eax
:15C7A 8B8548FFFFFF mov eax, dword ptr [ebp+FFFFFF48]
; this is the length = 0x716
:15C80 50 push eax
:15C81 8B854CFFFFFF mov eax, dword ptr [ebp+FFFFFF4C]
; where to fetch the patch
:15C87 50 push eax
:15C88 8B4DD4 mov ecx, dword ptr [ebp-2C]
--> where to apply (=43D680)
:15C8B 51 push ecx
:15C8C 56 push esi
* Reference To: KERNEL32.WriteProcessMemory, Ord:0283h
|
:10015C8D FF1588940410 Call dword ptr [10049488]
--> go ahead, patch it!
:10015C93 85C0 test eax, eax
Now we have all the elements to kick this TimeLOCK crap out for good: press F12 to get
up to 4FA021. It's quite clear: we want to save 716h bytes from 43D680 to a file. How
proceed? Well let's assemble a small program using win32 API that'll make it for us!
As it seems, the code over 4FA028 is bogus. So We'll work here.
>A 4FA040
Then type the following instructions (I rely on win32 help & include files for the
pushes with CreateFileA and WriteFile):
push 0 ; bogus but necessary
push dword ptr 80 ; file_attributes_normal (don't forget dword ptr or it will push a
'signed' FFFFFF80 ... I spent 2 hours on this bug!)
push 02 ; create_always
push 0 ; null (security field)
push 0 ; file is not shared
push 40000000 ; file is write only
push 004FA200 ; the adress of the name of the file
call KERNEL32!CreateFileA
push eax ; eax=handle. We push it for later closehandle
push 0 ; a dummy one
push 004FA100 ; where to store the number of bytes written
db 68 16 07 00 00 ; this is: push dword ptr 0716, I didn't manage a 'real dword' push!
push 43D680 ; we save from here
push eax ; the handle
call KERNEL32!WriteFile
call KERNEL32!CloseHandle
; the handle is still on the top of the stack
push ff
jmp 43D680 ; bye bye!
Well, just type
>EB 4FA200
And enter the full pathname of the file where the data will be stored, for example
'C:\bigpatch',0 and now .... g=4FA040. I hope your HD hasn't gone formatting, mine
is OK :-)
|
TimeLOCK 3.13 - 3.15 (Marigold)
I overlooked this version when it first appeared, so I'll give some detail here.
New features are:
The whole code section is encrypted.
.idata section is encrypted.
Checksum of the protection DLL image in memory is calculated (Actually, I'm not sure
that this feature was not present in previous versions. At least, it made no problem).
*I use word 'checksum' here and below in a sense 'hash function'
Unwrapping is not so simple as with the previous version in addition to the above-described
procedure, which generally remains untouched, we need to restore .idata section
Restoration of information from .idata section is similar to that that would be used
later in VBox and is described elsewhere.
Differences are as follows: 1) Encrypted information is stored in .idata section itself;
2) The first field of 26-byte record for an imported object always contains the module
name index in the name array (-1 with meaning 'previous' is never used).
Let's consider how the necessary information could be collected in the case of
TL315INJ.DLL. Differences with TL313INJ.DLL are minimal.
:1001830D 8BB52CFEFFFF mov esi, dword ptr [ebp-1D4]
:10018313 8B9D30FEFFFF mov ebx, dword ptr [ebp-1D0]
:10018319 85F6 test esi, esi
:1001831B 742E je 1001834B
Here [ebp-1D4] contains a length and [ebp-1D0] a pointer to an array of zero terminated
strings and names of imported modules and functions and the name array. Dump this array
into a file.
Next, we need a description for each imported function. This description is a 26(1A)-byte
long record. Records are decrypted one at time to bind an imported function. Binding is
being made in a loop 1839A ... 18525.
:1001839A 813DCC9D0410F8000000 cmp dword ptr [10049DCC], 000000F8
:100183A4 7523 jne 100183C9
:100183A6 85FF test edi, edi
:100183A8 8D8564FAFFFF lea eax, dword ptr [ebp+FFFFFA64]
:100183AE 50 push eax
:100183AF 750C jne 100183BD
:100183B1 E82A7A0000 call 1001FDE0 ; Decryption of the
:100183B6 83C404 add esp, 00000004 ; first record
:100183B9 8BD8 mov ebx, eax
:100183BB EB14 jmp 100183D1
* Referenced by a Jump at Address:100183AF(C)
|
:100183BD E82E7B0000 call 1001FEF0 ; Decryption of
:100183C2 83C404 add esp, 00000004 ; all following records
:100183C5 8BD8 mov ebx, eax
:100183C7 EB08 jmp 100183D1
; Now ebx contains a pointer to the record for the current imported function
. . .
:10018503 8B4316 mov eax, dword ptr [ebx+16]
:10018506 0305F04E0410 add eax, dword ptr [10044EF0]
:1001850C 8BC8 mov ecx, eax
:1001850E 8B8560FFFFFF mov eax, dword ptr [ebp-A0]
:10018514 8901 mov dword ptr [ecx], eax ; Address of function
:10018516 83C71A add edi, 0000001A ; is recorded to Import
:10018519 FF45CC inc [ebp-34] ; Address Table
:1001851C 8B4DCC mov ecx, dword ptr [ebp-34]
:1001851F 398D64FFFFFF cmp dword ptr [ebp-9C], ecx
:10018525 0F8F6FFEFFFF jg 1001839A
One needs to patch code inside this loop to save all records into a mapped file created with
SoftDump. As this loop includes error-handling code, which never works, one has plenty of
space for this patch. I intentionally give no code for this patch as the next step is
rebuilding of .idata section and requires of cracker higher programming skills than
this simple task.
One important note about image checksum. The creators of this protection certainly follow
our 14 Commandments: the checksum is never checked against its 'right' value. Instead it
is incorporated into a decryption key, so if one makes soft-patching (file checksum is
another problem) at inappropriate moment, the decryption of the name array goes wrong
and system crashes.
Now you should take into account that setting a bpx actually means the changing of a byte
on this address to CC, though SoftICE doesn't show it. (Of course, it is applicable to
all versions with code checksum checking).
Thus, to get to the code snippets above, you should not set breakpoints there.
Here is a call to the function that calculates checksum:
:100159DF 8D851CFEFFFF lea eax, dword ptr [ebp+FFFFFE1C]
:100159E5 50 push eax ; Buffer for checksum
:100159E6 8D85B4FDFFFF lea eax, dword ptr [ebp+FFFFFDB4]
:100159EC 50 push eax
:100159ED 8D85BCFDFFFF lea eax, dword ptr [ebp+FFFFFDBC]
:100159F3 50 push eax
:100159F4 8D85C4FDFFFF lea eax, dword ptr [ebp+FFFFFDC4]
:100159FA 50 push eax
:100159FB 81F7494C0000 xor edi, 00004C49 ; "LI" < Weijun Li
:10015A01 57 push edi
:10015A02 81F64A570000 xor esi, 0000574A ; "WJ" < initials
:10015A08 0335EC4E0410 add esi, dword ptr [10044EEC]
:10015A0E 56 push esi
:10015A0F E8ECA50000 call 10020000
:10015A14 83C418 add esp, 00000018
So, you should step all the way through code or you may set bpx 10015A0F, clear it at
arrival and set necessary breakpoints after return from this function.
|
|