■■ You know that RtlGetElementGenericTableis returning the value
of one of these pointers to the caller, but not before it is incremented by
- Note that 12 also happens to be the total size of those three pointers.
■■ You have established that RtlGetElementGenericTabletakes two
parameters and that the first is the table data structure pointer and the
second is an index into the table. You can safely assume that it returns
the element through the return value.
All of this leads to one conclusion. RtlGetElementGenericTable is
returning a pointer to an element, and adding 12 simply skips the element’s
header and gets directly to the element’s data. It seems very likely that this
header is another three-pointer data structure just like that in offset +4 in the
root data structure. Furthermore, it would make sense that each of those point-
ers point to other items with three-pointer headers, just like this one. One other
thing you have learned here is that offset +10 is the index of the cached
element—the same element pointed to by the third pointer, at offset +c. The
difference is that +c is a pointer to memory, and offset +10 is an index into the
table, which is equivalent to an element number.
To me, this is the thrill of reversing—one by one gathering pieces of evi-
dence and bringing them together to form partial explanations that slowly
evolve into a full understanding of the code. In this particular case, we’ve made
progress in what is undoubtedly the most important piece of the puzzle: the
generic table data structure.
Logic and Structure
There is one key element that’s been quietly overlooked in all of this: What is
the structure of this function? Sure, you can treat all of those conditional and
unconditional jumps as a bunch of gotoinstructions and still get away with
understanding the flow of relatively simple code. On the other hand, what
happens when there are too many of these jumps to the point where it gets
hard to keep track of all of them? You need to start thinking the code’s logic
and structure, and the natural place to start is by trying to logically place all of
these conditional and unconditional jumps. Remember, the assembly language
code you’re reversing was generated by a compiler, and the original code was
probably written in C. In all likelihood all of this logic originated in neatly
organized if-elsestatements. How do you reconstruct this layout?
Let’s start with the first interesting conditional jump in Listing 5.2—the JE
that goes to ntdll.7C962554(I’m ignoring the first two conditions that jump
to ntdll.7C962559because we’ve already discussed those). How would
you conditionally skip over so much code in a high-level language? Simple,
the condition tested in the assembly language code is the opposite of what was
Beyond the Documentation 159