Hooking Non-Virtual Functions, Part 4

As a wrap-up to this article, I’ll show a very hacky variable-arguments version that, while untested, should work. The trouble with varargs is that we simply don’t know how many bytes were passed, and format routines simply rely on the number of ‘%’ characters to get parameters. This means the safest way, rather than to format things ourselves, is to hack the stack frame.

vararg_gate_open:
  ;push the old return value
  push dword [esp]
.stack_save
  ;call our 'stack save' function
  db 0e8h, 000h, 000h, 000h, 000h
  ;Note that the stack will now be at the first parameter
  sub esp, 8
;This is an E8 call, we'll replace the last four bytes with the address later
.call
  db 0e8h, 000h, 000h, 000h, 000h
;Now we have called the function with the original stack and returned
;Unfortunately, we've destroyed the return eip.  Restore it.
.stack_restore
  db 0e8h, 000h, 000h, 000h, 000h
  mov [esp], eax
  ret

What happened here? We’re taking the stack and realigning it, directly using it to call the handler without pushing any arguments. This is because we can’t copy, as we don’t know the byte size. However, calling it overwrites the old return eip on the stack, so we’ve saved it with two unimplemented functions. We can’t save the values on our own stack because, quite simply, we don’t have one — using the caller’s stack has destroyed our chance at having one, because the callee could corrupt our own. We could have used something callee-saved like edi, but we can’t save it ourselves. You can implement these two functions with a simple heap or data stack implementation.

Lastly, in case you were wondering how to write in an E8 call dynamically, you must use relative eips. Here is an example:

make_gate:
  ;..code..
  push myfunc.end-myfunc.start
  call malloc
  mov edi, eax
  mov esi, myfunc
  mov ecx, myfunc.end-myfunc.start
  ;Copy the 'stock' gate into our buffer
  rep movsb
  ;Move the pointer to the offset of the 4 bytes after E8
  add eax, myfunc.call - myfunc.start + 1
  mov edi, eax
  ;edi will be what eip is DURING the call
  add edi, 4
  ;the function we will be calling will now be in esi
  ;[ebp+8] is just an example of where you might be storing it
  mov esi, [ebp+8] 
  ;make the address relative to the eip
  sub esi, edi
  ;store the relative address into the call
  mov [eax], esi

myfunc:
.start
  ;...code...
  .call
  db 0e8h, 000h, 000h, 000h, 000h
  ;...code...
.end

Leave a Reply

You must be logged in to post a comment.