nonzero, CF will be set to one. It appears that some compilers like to use this
additional functionality provided by NEGas a clever way to check whether an
operand contains a zero or nonzero value. Let’s quickly go over each step in
this sequence:
■■ Use NEGto check whether the source operand is zero or nonzero. The
result is stored in CF.
■■ Use SBBto transfer the result from CF back to a usable register. Of
course, because of the nature of SBB, a nonzero value in CF will become
–1 rather than 1. Whether that’s a problem or not depends on the nature
of the high-level language. Some languages use 1 to denote True, while
others use –1.
■■ Because the code in the sample came from a C/C++ compiler, which
uses 1 to denote True, an additional NEGis required, except that this
time NEGis actually employed for reversing the operand’s sign. If the
operand is –1, it will become 1. If it’s zero it will of course remain zero.
The following is a pseudocode that will help clarify the steps described
previously:
EAX = EAX & 0x00001000;
if (EAX)
CF = 1;
else
CF = 0;
EAX = EAX – (EAX + CF);
EAX = -EAX;
Essentially, what this sequence does is check for a particular bit in EAX
(0x00001000), and returns 1 if it is set or zero if it isn’t. It is quite elegant in
the sense that it is purely arithmetic—there are no conditional branch instruc-
tions involved. Let’s quickly translate this sequence back into a high-level C
representation:
if (LocalVariable & 0x00001000)
return TRUE;
else
return FALSE;
That’s much more readable, isn’t it? Still, as reversers we’re often forced to
work with such less readable, unattractive code sequences as the one just dis-
sected. Knowing and understanding these types of low-level tricks is very
helpful because they are very frequently used in compiler-generated code.
Let’s take a look at another, slightly more involved, example of how high-
level logical constructs can be implemented using pure arithmetic:
Deciphering Code Structures 511
21_574817 appa.qxd 3/16/05 8:54 PM Page 511