|4 May 1998||by Marigold||
|Courtesy of Reverser's page of reverse engineering |
|Well, once more a commercial protection
scheme bytes the dust, which is good. Marigold's work, here, and his 'reconstructive surgery' of
an encryption/packing protection scheme is in my opinion a very important
addition to our practical and theoretical knowledges: he'll show you exactly HOW the development
of timelock has been implemented, and how to understand (and defeat) this relatively new breed of
protection schemes. For advanced crackers and protectors only, no beginners. Enjoy!
|There is a crack, a crack in everything That's how the light gets in|
|Rating||( )Beginner ( )Intermediate (x)Advanced ( )Expert||NO beginners|
When I first heard about Vbox, I've thought that it is just another version of TimeLock.
To my surprise this turned out to be a rather tough protection scheme. Eventually I cracked it, but this essay is not a ready-made cracking solution -- rather an account on my explorations inside Vbox. You will see why. I rated this essay as "advanced" just
to avoid explaining trivia; it is messy enough in its present form.
Knowledge of PE-file structure at decent level is presumed.
Written by Marigold
I explained earlier my views on cracking: not satisfy but rather avoid protection's checks or, best of all, get rid of protection altogether. "Wrapping", "injection" and similar techniques provide a good opportunity for that. Cracking in this case usually
involves dumping of decrypted/unpacked code to a file. That's why I instantly appreciated SoftDump by Quine. A very handy thing, which every cracker must have in his toolbox! JaZZ in his essay devised a
smart trick, but SoftDump makes possible defeating TimeLock 3.xx in just three moves: 1. In SoftIce step over the call to tl*inj.dll function and write down (by hand) eax - real Entry Point; 2. With SoftDump save in a file a big enough chunk of the code (
never seen longer than 0x1E00, but one can save any length) starting from this point; 3. Patch this chunk into the .exe file and make all usual alterations in the header. As you can see, this procedure does not rely on any brain activity - only finger
movements. With Vbox one has to employ similar methods, but some brain would be necessary. Another necessary thing - one has to have a sufficiently long trial period. Never mind. As with all Previewsoft products, anyone who knows how to use Regmon and
Filemon can easily find (and remove) the "secret" markings, which should (as they hope) prevent re-installation.
We'll open Vbox for Doiley.exe. PreviewSoft distributes it as a demo of their protection. Thanx. As an app itself is almost of no importance for Vbox operation, it is a target as good as any other. In other words, procedure of V(irtual) box opening is indep
endent of its contents.
SoftDump by Quine
TimeLock by PreviewSoft has long and glorious history (of its cracking). Vbox is "a new beginning" of a kind. It's different
from its predecessors almost to the loss of the ancestorial resemblance.
First I describe the general structure of Vbox protection. Vbox is applied to the ready application, which has no own protection. Protected program is .exe file with the same name as the original but very different structure.
Apart from the usual .reloc and .rsrc, it has purely virtual PREVIEW section and WeijunLi section which contains several lines of code and packed data. Protection itself consists of three dll's: vboxp40, vboxb40 and vboxt40; only the first of them is "normal",
the other two - packed in almost the same way as the target. When protected target runs, it, first of all, calls vboxp40.PreviewExecGate_By_WeijunLi function, which unpacks the image (section by section) of the original executable into PREVIEW section.
It also unpacks a small additional section containing a call to the only exported function of vboxb40.dll (upon loading this and the other packed dll invoke the same vboxp40.PreviewExecGate_By_WeijunLi to be unpacked and properly loaded),
which makes a call to vboxt40.PreviewParadise_WJ. (Certainly, they at PreviewSoft switched from cracker intimidation to self-advertisement. Yeah, Weijun Li well deserved it: he managed to perform "a big leap" from mediocrity of TL to one of the toughest
(commercial) protections (for Win32) I've ever seen.)
At first glance, cracking seemed to be quite easy: just wait until Vbox made a sound part of its work, i.e. unpacking and decrypting the original program, save the image with SoftDump (each section separately), glue sections together and attach a self-made
PE-header. It prove to be correct except for one little point - as Vbox actually make the work of loader by itself, it must process .idata section: load modules, GetProcAddresses, etc. And here the real show began. Information on imported objects is preproc
essed and stored in a separate file in strongly encrypted form. Only when one passed all checks, information is being processed and Import Address Table of .idata section is filled with addresses. So, the original contents of .idata section are never restor
ed, and the initial plan of attack needs to be amended.
Here is the code in the protected target:
.0462000: FF74240C push d,[esp][0000C]
.0462004: FF74240C push d,[esp][0000C]
.0462008: FF74240C push d,[esp][0000C]
.046200C: 68017E098D push 08D097E01; XOR mask XOR 4 = 2BE; | Sum of these values makes
.0462011: 689E5C4F8D push 08D4F5C9E; XOR mask XOR 3 = 462026| an address of packed data
.0462016: 68417C098D push 08D097C41
.046201B: 68BB7C098D push 08D097CBB; xor-mask
.0462020: FF1550214600 call  ; PreviewExecGate_By_WeijunLi
.0462026: 68FFFFFFFF push 0FFFFFFFF
.046202B: FFD0 call eax
.046202D: C20C00 retn 0000C
Function called at 462020 unpacks sections of the original target (part of code remains encrypted) plus one small additional section. On return, eax contains 461000 -- address in this section.
0461000 PUSH DWORD PTR [ESP+0C]
0461004 PUSH DWORD PTR [ESP+0C]
0461008 PUSH DWORD PTR [ESP+0C]
046100C PUSH DD67AAA0
0461011 PUSH B55D2599
0461016 PUSH 7578DDBA
046101B PUSH 4D081FE4
0461020 CALL  ;tboxb40.ExpFn#1
0461026 PUSH FFFFFFFF
046102B CALL EAX
0137:0046102D RET 000C
Function called at 461020 finishes the work of a loader for the original program. It decrypts the code and binds imported functions. Return value - eax - contains Entry Point of the original program (or of ExitProcess). At this point it's convenient to save
sections to files.
To save image one needs to know sections' sizes and RVAs. This information may be found in a packed section header. This is the beginning of packed data in Doiley.exe:
.000622E0: xx xx xx xx-00 10 06 00-68 C1 02 00-35 91 01 00
.000622F0: 01 00 00 00-00 10 00 00-11 46 0F 4E-09 46 0F 4E
.00062300: 59 0D 58 04-00 DC 75 00-14 D7 0E 4E-54 87 0D 4E
.00062310: 2A F0 85 1F-7E FB 44 6D-E9 44 CC AC-AB 13 25 95
i.e. RVA= 2E000, PhysSize = 8168, and so on. Valid sections are preceded by non-zero DWORD; otherwise it is data used for internal purposes. Alternatively, one can obtain all this information by setting a breakpoint at 5001AFD -- call to routine that unpacks
and writes sections -- and tracing into it.
Meaning is as follows:
General information on packed data
622E4: 00100600 ; 61000h - Size of Image
622E8: 68C10200 ; total length of packed data
622EC: 35910100 ; ((this-1)/4)*4 +10h = offset to the next section
622F0: 01000000 ; 1 - marker
622F4: 00010000 ; section RVA
622F8: 11460F4E : (XORed) = 18 - marker
622FC: 09460F4E : xor-mask
62300: 590D5804 : (XORed) = "PKWJ" -signature (again Weijun Li!)
62304: 00DC7500 : ?
62308: 14D70E4E : (XORed) = 1911D - packed length
6230C: 54870D4E : (XORed) = 2C15D - physical size
Beginning of the next section is
.0007B430: 2B 22 00 00-01 00 00 00-00 E0 02 00-A6 1C AC 3D
.0007B440: BE 1C AC 3D-EE 57 FB 77-00 DC 75 00-AD 3E AC 3D
.0007B450: D6 9D AC 3D-18 F1 84 A2-E1 DA 34 9D-BC 0F E0 00
.0007B460: C4 42 90 05-68 0A 8E 89-02 40 09 0D-20 01 11 00
Note: I use term "Physical Size" for value, which rather is Virtual Size. Of course, Physical Size is this value rounded to integer of File Alignment (usu. 200h). But Virtual Size may drastically differ from this value, as you'll see below.
Dumping of a section into a file is made with Sice command
m section_VA L PhysSize AddressOfMappedFile
Length of file you create with SoftDump must be integer in File Alignment units.
If you collected information on sections from their headers you wouldn't fail to notice that packed length for one of them is very small. No wonder -- section is filled with zeros. Unmistakably, this is .idata.
Now we have to dig up information needed for reconstruction of this section, and for this purpose to look deeper into Vbox, namely into vboxt40.PreviewParadise_WJ, which is called at 60012F1.
At 700731A we have a call to routine, which creates MainDialog (all that "Try", "Quit", etc) and returns in eax pressed button number, but we do not stop here for I hope you managed to "prolong" you trial period. Somewhat further a code fragment goes that
writes into .text decrypted bytes (1E00h). No need to stop, we dumped this section in decrypted form already. A real interest for us is the following code snippet:
07007860 PUSH 0705EC38
07007865 MOV EAX,[0705A0BC]
0700786A ADD EAX,44
0700786D PUSH EAX
0700786E LEA EAX,[EBP-0108]
07007874 PUSH EAX
07007875 LEA EAX,[EBP-00C0]
0700787B PUSH EAX
0700787C MOV EAX,[EBP+18]
0700787F PUSH EAX
07007880 CALL 07007F40
07007885 ADD ESP,20
In [EBP-108] we have a byte length of and in [EBP-104] a pointer to an array of zero-terminated strings, which are names of all imported modules and functions for the original program. Let's dump this array into a file. In [EBP-C0] we again have length of
and in [EBP-BC] a pointer to an array of 26-byte records with information on each imported function. The problem is that now this information is encrypted. To retrieve it we dive somewhat deeper -- into routine at 7007F40.
This routine makes important part of work of a custom loader, which Vbox really is. It GetHandle or, if necessary, LoadLibrary for each imported module and then GetProcAddresses, filling with them Import Address Table of .idata section. Final writing of
proc address is being made here:
0700817E MOV ECX,[EDI+16]
07008181 MOV EAX,[EBP+08]
07008184 INC DWORD PTR [EBP-1C]
07008187 MOV [EAX+ECX],EBX ; here
0700818A MOV EDX,[EBP-1C]
0700818D CMP [EBP-24],EDX
07008190 JG 07007FE5
But now let's look at this code snippet:
07007FE5 CMP DWORD PTR [EBP-1C],00
07007FE9 MOV EAX,[EBP+24]
07007FEC PUSH EAX
07007FED JNZ 07007FF6
07007FEF CALL 07023E00
07007FF4 JMP 07007FFB
07007FF6 CALL 07023F10
07007FFB ADD ESP,04
07007FFE MOV EDI,EAX
Here the routine decrypts a record describing an imported function and places a pointer to this record into edi. But we are in PreviewParadise, not in the real one. Records are decrypted one at time, contents of the previous destroyed in the process. So, to
avoid saving them one by one manually, we need some automation. As one can easily see, processing is made in a loop 7007FE5..7008190. So, we first step to the beginning of the loop and insert, starting from 7007F90 (we'll never need again the original code
here), a small procedure:
000000: 56 push esi
000001: 57 push edi
000002: 51 push ecx
000003: 8BF7 mov esi,edi
000005: 81C7xxxxxxxx add edi,xxxxxxxxx
00000B: B91A000000 mov ecx,00000001A
000010: F2A4 repne movsb
000012: 59 pop ecx
000013: 5F pop edi
000014: 5E pop esi
000015: C3 retn
xxxxxxxx stands for the difference between the address of the mapped file and the value of edi at start of the cycle (a pointer to the first record). And we'll call this procedure instead of writing to .idata section:
0700817E INC DWORD PTR [EBP-1C]
07008181 MOV EAX, 7007F90
07008186 CALL EAX
0700818A MOV EDX,[EBP-1C]
0700818D CMP [EBP-24],EDX
07008190 JG 07007FE5
Now we'll push F12 till we are at 461026. Here we must replace value in eax with address of ExitProcess (BFF8AECD in my case) to prevent crash. Clumsy, of course, but makes its job.
With this operation we finished all Softicing (and Softdumping) and may start "reconstructive surgery" with limbs we collected.
26-byte record has the following structure:
Offset Length Meaning
0 4 Zero-based number of string in array with the name of a module
this function belong to.
-1 means "use previous".
4 8 Reserved? (all zeros)
C 4 Entry from Import Lookup Table. Contains an address of
Hint/Name string for a function in the original .idata
Section or *(if 31-bit set) its ordinal number in module.
10 4 Number of string in array with the name of the function.
14 2 Hint
16 4 An address of the Import Address Table entry for the function.
(A field where a proc address is placed to by the loader
* - function is identified by its ordinal number
As one can see, the name array and the record array provide all the information for re-buildidng of .idata section. I made this with a simple program written in C. Note, that I mean REBUILDING and not RESTORING of the original .idata, which proved to be
(I am tired, aren't you?)
As I said before, now we'll glue all sections together and make up a header. Here we need some guesswork - we don't know names (and meanings) of the sections, without which we can't set proper value for section flags and make some other things. In typical
case, it's not difficult to make correct guesses. All other information we have ready at hand.
In our case, final list of sections will look like that:
Number Name VirtSize RVA PhysSize Offset Flag
1 .text 0002C15D 00001000 0002C200 00000400 60000020
2 .rdata 00008168 0002E000 00008200 0002C600 40000040
3 .data 00007000 00037000 00003000 00034800 C0000040
4 .idata 000028DE 0003E000 00002A00 00037800 C0000040
5 .rsrc 0001AE2C 00041000 0001B000 0003A200 40000040
6 .reloc 000047C4 0005C000 00004800 00055200 42000040
As you can see, PhysSize is calculated as described above, VirtSize may coincide with a value from packed section header, but in case of .data it closer to RVAs difference.
Note: Doiley.exe, which we have reconstructed, is quite different in its build from the corresponding freeware available on the Net.
1. Find packed data in a protected target. Collect information on all sections.
2. Create with SoftDump a file to receive the section image. Go to SoftIce, step to a point where the section image is unpacked (decrypted) and dump it.
Repeat dumping for all sections, except for .idata.
3. Save the name array and the record array. (Find out their sizes beforehand.)
4. Reconstruct .idata section.
5. Glue all together, attach a header and try your luck by starting this contraption.
As I stated already, I like to remove protection from the target to the maximum possible extent -- to the restoration of total virginity. But when you have put together a totally dismembered body, it is not a proper word.
I apologize for the
cursory style of this essay. It would be simply impossible to describe all details (and how I arrived at them). This protection is considerably tougher than its nearest predecessor - TimeLock 3.1. Hope, I didn't miss any really important landmark.
About protection itself. I reiterate my very high opinion of Vbox. Idea about protection based on imported data is a real gem.
Anybody knows about other Vboxed applications? Any other comments?
I wont even bother explaining you that you should BUY this target program if you intend to use it for a longer period than the allowed one. Should you want to STEAL this software instead, you don't need to crack its prot
ection scheme at all: you'll find it on most Warez sites, complete and already regged, farewell.
You are deep inside reverser's page of reverse engineering, choose your way out:
Back to advanced cracking
homepagelinks search_forms+ORCstudents' essaysacademy database
toolsanonymity academy cocktailsantismut CGI-scriptsmail_reverser
Is reverse engineering legal?