7C924DC0 PUSH EBP
7C924DC1 MOV EBP,ESP
7C924DC3 PUSH EDI
7C924DC4 MOV EDI,DWORD PTR [EBP+8]
7C924DC7 LEA EAX,DWORD PTR [EBP+8]
7C924DCA PUSH EAX
7C924DCB PUSH DWORD PTR [EBP+C]
7C924DCE CALL ntdll.7C92147B
7C924DD3 PUSH EAX
7C924DD4 PUSH DWORD PTR [EBP+8]
7C924DD7 PUSH DWORD PTR [EBP+14]
7C924DDA PUSH DWORD PTR [EBP+10]
7C924DDD PUSH DWORD PTR [EBP+C]
7C924DE0 PUSH EDI
7C924DE1 CALL ntdll.7C924DF0
7C924DE6 POP EDI
7C924DE7 POP EBP
7C924DE8 RET 10
Listing 5.5 A disassembly of RtlInsertElementGenericTable, produced using OllyDbg.
We’ve already discussed the first two instructions—they create the stack
frame. The instruction that follows pushes EDIonto the stack. Generally speak-
ing, there are three common scenarios where the PUSHinstruction is used in a
function:
■■ When saving the value of a register that is about to be used as a local
variable by the function. The value is then typically popped out of the
stack near the end of the function. This is easy to detect because the
value must be popped into the same register.
■■ When pushing a parameter onto the stack before making a function call.
■■ When copying a value, a PUSHinstruction is sometimes immediately
followed by a POPthat loads that value into some other register. This
is a fairly unusual sequence, but some compilers generate it from time
to time.
In the function we must try and figure out whether EDIis being pushed as
the last parameter of ntdll.7C92147B, which is called right afterward, or if
it is a register whose value is being saved. Because you can see that EDIis
overwritten with a new value immediately after the PUSH, and you can also
see that it’s popped back from the stack at the very end of the function, you
know that the compiler is just saving the value of EDIin order to be able to use
that register as a local variable within the function.
Beyond the Documentation 169