Certain features in 64-bit code can provide additional clues to malware functionality that are not available in 32-bit code. These features are conventional and generally apply only to compiler-generated code.
For example, it is typically easier in 64-bit code to differentiate between pointers and data values. The most common size for storing integers is 32 bits, although that is not a requirement. Still, even when simply storing an index value that iterates from 1 to 100, most programmers will choose a 32-bit integer for storage.
Table 21-1 shows the 32-bit and 64-bit versions of the same function call.
In the 32-bit assembly shown on the left, there are two parameters to the function sub_411186. We have no information about the types or purposes of the
parameters, other than that they are both 32 bits.
In the 64-bit assembly shown on the right, we also see two parameters, but now we have
additional information. The first mov instruction at ❶ moves the value into RDX, which tells us that this is a 64-bit
value—probably a pointer. The second parameter is being moved into ECX, which tells us that it
is a 32-bit value, because ECX is the 32-bit version of the RCX register. This can’t be a
pointer, because pointers are 64 bits. We still don’t know whether this parameter is an
integer, handle, or something else, but when you’re starting to understand a function, these
little clues can be crucial to determining what a function does.