Introduction. The breeze was gentle, but a storm was coming. -Unknown
This
protection scheme may appear difficult to understand and reverse
but,
while advanced in some aspects, is very well suited to the
newby/intermediate
reverser. There are new concepts here. You will become
familiar
with the Portable Executable (PE) file format. (See Section VII below for
additional resources and for related materials). While this task may seem
daunting you will find it is simple to understand, interesting and very
powerful knowledge. You should also be reasonably familiar with SoftICE
and Hacker's View (Hiew). Although, I have several hex editors, Hiew is
such an extraordinary tool it is the only one I really use. All file changes
will be explained from the Hiew perspective. Finally, I use Windows 95
and, therefore, cannot speak for other operating systems.
The
target file is one of three primary executables each similarly
protected
in the file zm98eval.zip (1,639,565 bytes). Download it at
http://www.mijenix.com.
I selected the Wizard file (zmwiz.exe) because of its small size. The Wizard
helps the user either prepare or decompress zip
archives.
Tools:
SoftICE
W32dasm
Hiew
SoftDump
for Windows 95 (sdump95.exe)
Dumppe.exe
hexadecimal
calculator (for example, bcalc1.zip is excellent)
Tools
can be located through a simple FTP
Search or at your preferred
Reverse
Engineering tool page.
The
point of this paper is to instruct and to educate, nothing more. If you
wish
to use the target for any purpose other than Reverse Engineering, or
you
keep it beyond its evaluation period, register it.
I. And the earth was without form and void. -Genesis
Disassemble
the file with W32dasm and save the output. The program is
protected
with a 30-day cinderella time-out. You will find, though, that after the
30 days has passed a 10-day grace period is granted.
Set your system calendar ahead 31 days and run the program to reveal the grace period dialog box. Take note of relevant strings. Set the system calendar ahead 15 more days to reveal the expiration notification box, again taking note of important strings. As usual, the dialog box will act as a portal to the protection scheme.
Set
a BPX DialogBoxParamA in SoftICE. Run zmwiz.exe to activate the breakpoint
and <F12> back to the target. We will start simply: trace backward from
the call and look for a conditional jump that, if taken, would avoid the
call. You will not find it--<F12> out of this routine. Again, trace
backward from this call.
Note
the conditional jump (jz):
:0040A743 F644241802 test [esp+18], 02 :0040A748 7428 jz 0040A772 :0040A74A 800514C44000FB add byte ptr [0040C414], FB :0040A751 E84AFBFFFF call 0040A2A0 **Leads to Nag Dialog :0040A756 C60515C4400007 mov byte ptr [0040C415], 07BPX :0040A748 and rerun the program. You will find that the program does not break. Using the SoftICE loader rerun zmwiz. This will cause the file to break at its entry point. Step <F10> to the call at :0040449A. Trace <F8> into the call and step until you reach the call at :00401C3E. Entering the call places you at :00403B50. Dump the address :0040A748 to the data window and note that no data is present. (This is why SoftICE did not recognize the BPX). Continue stepping while watching the data window.
:00403D19 50 push eax :00403D1A 51 push ecx :00403D1B 55 push ebp :00403D1C 8B6C2420 mov ebp, dword ptr [esp+20] :00403D20 55 push ebp :00403D21 FF15F0124100 Call KERNEL32.WriteProcessMemoryAfter executing the above call the data window suddenly has code.
The absence of code leads us to believe that the program must be writing its own code once it is executed. Obviously, patching is not possible. But we have not wasted our time. Push these notes aside, we will return to them later.
What
roles do the Windows API functions WriteProcessMemory and its cohort
ReadProcessMemory
play in the protection scheme?
II. "It's a friend of mine--a Cheshire Cat," said Alice: "allow me to introduce it." -Carroll
The
WriteProcessMemory function writes memory in a specified process. The
entire
area to be written to must be accessible, or the operation fails.
BOOL WriteProcessMemory( 1. HANDLE hProcess, // handle of process whose memory is written 2. LPVOID lpBaseAddress, // address to start writing to 3. LPVOID lpBuffer, // address of buffer to write data to 4. DWORD cbWrite, // number of bytes write 5. LPDWORD lpNumberofBytesWritten// actual number of bytes written );The terms "process", and "image" refer to a program once it has loaded to RAM and become active. Its code is located at a "virtual" address. This is in contrast to the disk file which is referred to as "raw" or "executable" data.
Its data is located at an "offset". Note that there are 5 parameters for the WriteProcessMemory function (only 4 are used by zmwiz). Of these, we are most interested in 3: the base address to which data is written (param #2), the buffer supplying data to be written into the base address (param #3), and the number of bytes written to this address (param #4).
BPX
WriteProcessMemory in SoftICE and run zmwiz. <F12> back to zmwiz, <F10>
once to load the code to SoftICE. Clear this BPX and set a new BPX at :00403D19
and rerun the program. Take note of the bytes-written value at eax, the
buffer at ecx, and the base address at ebp. These are important and should
be written down. The values are 1D14, CC1D9C (for me) and 409000, respectively.
Your buffer addresses may differ from those listed here.
(Optional:
BoundsChecker may also be used to examine API function parameters if you
have this useful tool).
It
is appropriate, at this point, to examine the parameter requirements of
ReadProcessMemory:
The
ReadProcessMemory function reads memory in a specified process.
The
entire area to be read must be accessible, or the operation fails.
BOOL ReadProcessMemory( 1. HANDLE hProcess, // handle of process whose memory is read 2. LPCVOID lpBaseAddress, // address to start reading to 3. LPVOID lpBuffer, // address of buffer to place read data 4. DWORD cbRead, // number of bytes read 5. LPDWORD lpNumberofBytesRead // address of number of bytes read );Now, BPX ReadProcessMemory and run the target. The function is called four
:00403C8F 8B442424 mov eax, dword ptr [esp+24] :00403C93 8B0D28F04000 mov ecx, dword ptr [0040F028] :00403C99 50 push eax :00403C9A 51 push ecx :00403C9B 55 push ebp :00403C9C 53 push ebx :00403C9D FFD6 call esi ; **This is ReadProcessMemory :00403C9F A128F04000 mov eax, dword ptr [0040F028]Clear the BPX ReadProcessMemory (but not the one you set earlier at
It
is from here that the decrypted code is finally copied to :00409000
by
WriteProcessMemory. We will say no more about the mechanics of the
decryption,
however the reader is encouraged to examine this interesting
code.
The
reading and writing functions start at :00409000. Dump this address
to
the data window, leave SoftICE, run zmwiz and note, as the program
breaks,
the data changes as the code is read then written to the window.
Encrypted:
.00409000:AF DE 00 00-92 0F 00 00-BE 00 0F 00-12 03 24 15 ¯Þ ¾$ .00409010: 36 27 38 39-6A 7B 4C 9D-6E 1F 09 06-01 13 34 E5 6'89j{Ln4å .00409020: F6 96 F7 17-13 25 89 30-30 7B 4C C9-3E 18 BD 40 ö÷%00{LÉ> ½@ .00409030: AB 0F 09 F3-4B F6 96 0E-03 10 A7 FC-23 65 47 FA « óKö§ü#eGú .00409040: B0 B0 BA 72-25 4C 12 95-B1 9B ED 81-7D 5D 0D CC °°ºr%L±í}] Ì Decrypted: .00409000: 8B 44 24 08-81 EC 98 00-00 00 83 E8-02 56 0F 84 D$ ìè V .00409010: FC 00 00 00-2D 0E 01 00-00 0F 84 8F-00 00 00 48 ü - H .00409020: 0F 85 EA 00-00 00 8B 84-24 A8 00 00-00 66 3D 01 ê $¨f= .00409030: 00 75 1A 8B-84 24 A0 00-00 00 50 FF-15 54 14 41 u $ Pÿ T A .00409040: 00 33 C0 5E-81 C4 98 00-00 00 C2 10-00 66 3D 02 3À^Ä Âf=III. I will study and prepare and someday my chance will come. -Lincoln
Let's
continue studying our target. Using dumppe.exe dump the target's PE
header
information to a text file. You can use the following batch file to
facilitate
this: dumppe.exe %1 > c:\windows\desktop\dumppe.txt. Place this
batch
file in the same directory as dumppe.exe, then place a shortcut to it
in
your "send to" directory. Now, just select the file to dump, right click,
and select the bat shortcut. Look on your desktop for the PE dump.
Open
the file in notepad. There is a lot of information here but we are only
concerned with a small portion of it. Find the area titled "Section Table".
There
are six sections with names like .text, .etext and so on.
Section Table ------------- 01 .text Virtual Address 00001000 Virtual Size 00007FB0 Raw Data Offset 00000400 Raw Data Size 00008000 Relocation Offset 00000000 Relocation Count 0000 Line Number Offset 00000000 Line Number Count 0000 Characteristics 60000020 Code Execuatble Readable 02 .etext Virtual Address 00009000 Virtual Size 00001D00 Raw Data Offset 00008400 Raw Data Size 00001E00 Relocation Offset 00000000 Relocation Count 0000 Line Number Offset 00000000 Line Number Count 0000 Characteristics 60000020 Code Execuatble Readable . . . 06 .rsrc Virtual Address 00012000 Virtual Size 00001EC0 Raw Data Offset 0000E400 Raw Data Size 00002000 Relocation Offset 00000000 Relocation Count 0000 Line Number Offset 00000000 Line Number Count 0000 Characteristics 40000040 Initialized Data ReadableThe .text and .etext sections contain code while the others are data sections.
The addresses given are relative to the image base (listed earlier) which is 400000. This is simply the preferred address at which code begins to load. In the .text section the relative virtual address (RVA) is 00001000 (all values are in hexadecimal notation) while the actual address is 400000+1000=401000. Look at the RVA in the .etext section and convert it to the actual address. We got 409000. Note also the virtual size of 1D00 bytes. Do these values look familiar? They are the read and write process parameters. (Although, Write- ProcessMemory writes 1D14, the extra 14 bytes can be ignored for our purposes).
So, to complete our studies, let's summarize. The protection scheme is:
1. encrypted code starting at address :00409000. 2. 1D00 bytes in length. 3. stored at the .etext section. 4. decrypted and written back to :00409000.It's time to reverse our target.
IV. Cry 'Havoc' and let slip the dogs of War. -Shakespeare
As we are unable to patch encrypted code we must decrypt it and write it to a binary file. In this format it can be appended to .text, thereby, providing smooth, uninterrupted code and overwriting the encrypted .etext section. But, first we must relocate the .etext section and redirect the ReadProcessMemory function so as to continue reading encrypted code. The program checks the validity of its protection and will crash if this code is not present.
The best place to relocate .etext is at the end of the program following the .rsrc section. This section starts at RVA 00012000 and is 1EC0 bytes long. The .etext can go after 12000+1EC0=13EC0 RVA. However, this address must be rounded up to the next multiple of the required section alignment (1000). The new RVA for .etext would, therefore, be 00014000. We will actually be copying to the disk file at the raw offset E400+2000=10400. As this offset falls on the required file alignment (200) a rounding adjustment, such as made with the RVA above, is not needed.
Open zmwiz in Hiew and press <ctrl end> to go to the bottom of the file. Note the last byte is at offset 000103FF, and virtual address (VA).00413FFF. You may toggle between offset and VA with <alt F1> (<alt G> on earlier versions of Hiew). The pattern of repetitive zeros preceding this address is used as padding to the file boundary. Padding is used between each of the other sections, as well, to allow subsequent sections to align themselves at the boundary. It would be well to remember that padding is empty space available for any short routines you might wish to write in future projects, and is accessible via the jump command.
It
is good practice to always backup the target before making file changes.
Now
GOTO .00409000 and select the .etext block. To do this place the cursor
at
.00409000, press <shift *> , and <down arrow>. The selected bytes
appear
high-lighted.
Continue selecting until you reach .0040A070 (offset 9470). The rest of
.etext is padding in which we have no interest. Turn off block select with
the <shift *> combination. Select PutBlk <F2> and enter Path\zmwiz.exe
for file name, 10400 as the offset, and table "AS IS". You will not see
the appended bytes until you reload the target, as Hiew writes directly
to the file and not to the image. The actual number of bytes copied is
about 1070. This includes some padding which is acceptable.
We
must now tell the loader where the new .etext section is located. To do
this
requires a header change. In Hiew, perform an ASCII search <F7> for
".etext"
(without quotes).
00000190: 00 00 00 00-00 00 00 00-00 00 00 00-20 00 00 60 000001A0: 2E 65 74 65-78 74 00 00-00 1D 00 00-00 90 00 00 .etext 000001B0: 00 1E 00 00-00 84 00 00-00 00 00 00-00 00 00 00The original RVA was 9000; this value is at 1AD in low-byte, high-byte format.
00000190: 00 00 00 00-00 00 00 00-00 00 00 00-20 00 00 60 000001A0: 2E 65 74 65-78 74 00 00-00 12 00 00-00 40 01 00 .etext 000001B0: 00 12 00 00-00 04 01 00-00 00 00 00-00 00 00 00
The raw data size decreases from 1E00 because we did not copy the padding, but was raised over the 1070 actually copied to 1200 which is the size of the session's data rounded up to the next multiple of File Alignment.
At
this point, you may wish to recheck the ReadProcessMemory parameters in
SoftICE
to be sure that they have been reset. The target should run to the nag
screen without crashing.
We
are now ready to overwrite our original .etext with decrypted code. To
do this we need to run sdump95.exe and SoftICE and allow them to read the
decrypted
sequence and write it to a binary file.
Set
a BPX in SoftICE for WriteProcessMemory and leave SoftICE. Copy sdump95
to
your target's directory and enter a dos window here. Enter the following:
sdump95.exe zmwiz.bin 1D00 <enter>. Sdump95 will respond with:
Mapping address: 0x82531000 Go into SoftICE and do your thing! Hit return when you are ready for the file to be written to disk.Your address may differ from the example. Run the target; at the breakpoint
If
all seems well, while still in Hiew, select the .bin file with <shift
*>, <ctrl end>, then <shift *>. Select PutBlk <F2> and enter Path\zmwiz.exe
for
file name, 8400 as the offset, and table "AS IS".
We
must look at how we have changed the .text section. Its location has
not
changed, but its virtual and raw data sizes have increased. They can be
calculated
by subtracting the VA and raw data offset for .text from the VA
and
offset of the next section .rdata. (Remember, .etext now follows .rsrc).
We
got B000-1000=A000 for the new virtual size, and A200-400=9E00 for the
new raw size. Search for ".text" in Hiew and make changes as shown below.
00000160: 00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00 00000170: 00 00 00 00-00 00 00 00-2E 74 65 78-74 00 00 00 .text 00000180: 00 A0 00 00-00 10 00 00-00 9E 00 00-00 04 00 00The final header change will be made to the image size which is currently
00000080: 50 45 00 00-4C 01 06 00-CA C5 48 35-00 00 00 00 PE 00000090: 00 00 00 00-E0 00 0F 01-0B 01 05 02-00 9E 00 00 <clip> 000000D0: 00 60 01 00-00 04 00 00-00 00 00 00-02 00 00 00V. A correct answer is like an affectionate kiss. -Goethe
Check
your work--run zmwiz. It should run to the expiration nag without
crashing.
If this is the case you may continue with some optional changes that may
speed the program up slightly, but are not imperative to its reversal.
Replace the call to the decryption routine: :00403CF0 E80BFEFFFF call 00403B00; with :00403CF0 EB08 jmp 00403CF5 And, jump over the call to WriteProcessMemory: :00403D21 FF15F0124100 Call dword ptr [004112F0]; with :00403D17 EB0E jmp 00403D27It should be obvious why these routines are now useless to the program, as
VI. It ain't over till the fat lady sings. -Cook
Return to your reversing notes from section I above. Now, use Hiew to change the conditional jump (jz) at :0040A748 to an unconditional jump (jmp). Similar reversals must be performed at the following addresses:
:0040A7B0 :0040A831 :0040A488VII. If I have seen farther than other men, it is because I stood on the shoulders of giants. -Newton
Resources
abound on the Web; for further information refer to the following
documents:
PE File Information:
http://www.microsoft.com/win32dev/base/pefile.htm
http://www.geocities.com/SiliconValley/Lakes/5008/pefile.html
Related Tutorials:
http://www.phase-one.com.au/fravia/uvessa_2.htm
http://www.phase-one.com.au/fravia/natz_mp2.htm
http://www.phase-one.com.au/fravia/stone1.htm
http://www.phase-one.com.au/fravia/timelock.htm
Return |