Reversing : The Hacker's Guide to Reverse Engineering

(ff) #1
00401D3E XORPS XMM0,XMM0
00401D41 MOV EBP,DS:[<&MSVCR71.printf>]
00401D47 PUSH EAX
00401D48 PUSH cryptex.00403308 ; ASCII “Extracting “%.35s” - “
00401D4D MOVSS SS:[ESP+24],XMM0
00401D53 FSTP DWORD PTR SS:[ESP+34]
00401D57 CALL EBP

This sequence looks unusual because it contains quite a few instructions
that you haven’t encountered before. What are those instructions? A quick trip
to the Intel IA-32 Instruction Set Reference document [Intel2], [Intel3] reveals
that most of these instructions are floating-point arithmetic instructions. The
sequence starts with an FILDinstruction that simply loads a regular 32-bit
integer from [ESP+2C](which is where the file’s total cluster count is stored),
converts it into an 80-bit double extended-precision floating-point number
and stores it in a special floating-point stack. The floating-point is a set of float-
ing-point registers that store the values that are currently in use by the proces-
sor. It can be seen as a simple group of registers where the CPU manages their
allocation.
The next floating-point instruction is an FADD, which is only executed if
[ESP+2C]is a negative number. This FADDadds an immediate floating-point
number stored at 00403BA0to the value currently stored at the top of the
floating-point stack. Notice that unlike the FILDinstruction, which loads an
integer into the floating-point stack, this FADDuses a floating-point number in
memory, so simply dumping the value at 00403BA0as a 32-bit number shows
its value as 4F800000. This is irrelevant since you must view this number is a
32-bit floating-point number, which is what FADDexpects as an operand.
When you instruct OllyDbg to treat this data as a 32-bit floating-point number,
you come up with 4.294967e+09.
This number might seem like pure nonsense, but its not. A trained eye
immediately recognizes that it is conspicuously similar to the value of 2^32 :
4,294,967,296. It is in fact not similar, but identical to 2^32. The idea here is quite
simple. Apparently FILDalways treats the integers as signed, but the original
program declared an unsigned integer that was to be converted into a floating-
point form. To force the CPU to always treat these values as signed the com-
piler generated code that adds 2^32 to the variable if it has its most significant bit
set. This would convert the signed negative number in the floating-point stack
to the correct positive value that it should have been assigned in the first place.
After correcting the loaded number, Cryptex uses the FDIVRinstruction to
divide a constant from 00403B98by the number from the top of the floating-
point stack. This time the number is a 64-bit floating-point number (according
to the Intel documentation), so you can ask OllyDbg to dump data starting at
00403B98as 64-bit floating point. Olly displays 100.0000000000000, which
means that Cryptex is dividing 100.0 by the total number of clusters.


Deciphering File Formats 237
Free download pdf