If you look at RtlInsertElementGenericTableagain (in Listing 5.5), it
seems that the value of the first parameter passed to that function (which is
probably the address of the root TABLEdata structure) is loaded into EDI
before the function from Listing 5.6 is called. This implies that the compiler is
simply using EDIin order to directly pass that pointer into RtlLocateNode
GenericTable, but the question is which calling convention passes parame-
ters through EDI? The answer is that no standard calling convention does that,
but the compiler has chosen to do this anyway. This indicates that the compiler
controls all points of entry into this function.
Generally speaking, when a function is defined within an object file, the
compiler has no way of knowing what its scope is going to be. It might be
exported by the linker and called by other modules, or it might be internal to
the executable but called from other object files. In any case, the compiler must
honor the specified calling convention in order to ensure compatibility with
those unknown callers. The only exception to this rule occurs when a function
is explicitly defined as local to the current object file using the statickey-
word. This informs the compiler that only functions within the current source
file may call the function, which allows the compiler to give such static func-
tions nonstandard interfaces that might be more efficient.
In this particular case, the compiler is taking advantage of the statickey-
word by avoiding stack usage as much as possible and simply passing some of
the parameters through registers. This is possible because the compiler is tak-
ing advantage of having full control of register allocation in both the caller and
the callee.
Judging by the number of bytes passed on the stack (8 from looking at the
RETinstruction), and by the fact that EDIis being used without ever being ini-
tialized, we can safely assume that this function takes three parameters. Their
order is unknown to us because of that register, but judging from the previous
functions we can safely assume that the root data structure is always passed as
the first parameter. As I said, RtlInsertElementGenericTableloads EDI
with the value of the first parameter passed on to it, so we pretty much know
that EDIcontains our root data structure.
Let’s now proceed to examine the first lines of the actual body of this function.
7C921481 MOV ESI,DWORD PTR [EDI]
7C921483 TEST ESI,ESI
7C921485 JE ntdll.7C924E8C
In this snippet, you can quickly see that EDIis being treated as a pointer to
something, which supports the assumption about its being the table data struc-
ture. In this case, the first member (offset +0) is being tested for zero (remem-
ber that you’re reversing the conditions), and the function jumps to ntdll
.7C924E8Cif that condition is satisfied.
172 Chapter 5