Maximize
Bookmark

VX Heavens

Library Collection Sources Engines Constructors Simulators Utilities Links Antivirus Forum

Subtle SEH

roy g biv
June 2009

[Back to index] [Comments (0)]

What is it?

Everyone knows about Structured Exception Handling these days. First demonstrated in the Cabanas virus in 1998 by jqwerty, now many viruses and other applications use it for obfuscating code and anti-debugging tricks. It usually looks something like this:

	call	set_seh
	;handler code would go here
set_seh:
	push	dword ptr fs:[0]
	mov	dword ptr fs:[0], esp
	;code to produce exception would go here
 

So now if we see such a code sequence we know to expect an anti-debugging trick is coming soon. Probably some emulators have recogniser code for this thing and trigger some heuristics, too. So I tried to think of a way to register a Structured Exception Handler without obvious write to fs:0. Here are some of those ways. First way gets base of fs from TIB.

	mov	eax, dword ptr fs:[tibSelf]
	call	set_seh
	;handler code would go here
set_seh:
	push	dword ptr ds:[eax]
	mov	dword ptr ds:[eax], esp
	int	3			;cause exception
 

Second way gets base of fs from descriptor table.

	lea	eax, dword ptr [esp - 2]
	push	eax
	push	fs
	push	-2			;GetCurrentThread()
	call	GetThreadSelectorEntry
	pop	eax			;bits 00-23 of base
	bswap	eax
	mov	al, byte ptr [esp + 1]	;bits 24-31 of base
	bswap	eax
	call	set_seh
	;handler code would go here
set_seh:
	push	dword ptr ds:[eax]
	mov	dword ptr ds:[eax], esp
	int	3			;cause exception
 

Third way gets base of fs from descriptor table, using hard-coded fs value, so there is no fs reference.

	call	skip_k32
	db	"kernel32", 0
skip_k32:
	call	GetModuleHandleA
	call	skip_iswow
	db	"IsWow64Process", 0
skip_iswow:
	push	eax
	call	GetProcAddress
	xchg	ecx, eax
	jecxz	not_xp			;XP and later only
	push	eax
	push	esp
	push	-1
	call	ecx
	pop	ecx
not_xp:
	lea	eax, dword ptr [esp - 2]
	push	eax
	push	3bh			;all 32-bit Windows
	jecxz	not_v64
	pop	eax
	push	53h			;Vista64
not_v64:
	push	-2			;GetCurrentThread()
	call	GetThreadSelectorEntry
	pop	eax
	bswap	eax
	mov	al, byte ptr [esp + 1]
	bswap	eax
	call	set_seh
	;handler code would go here
set_seh:
	push	dword ptr ds:[eax]
	mov	dword ptr ds:[eax], esp
	int	3			;cause exception
 

but all of these ways have obvious push and mov using esp. There are some other ways, too, such as NtSetLdtEntries(), but I was told that it does not work on 64-bit Windows. Anyway, altering fs or gs introduces race condition against thread switch. When switch occurs, fs and gs values are restored to their proper values. Then I found another way. This way writes to fs using ss:esp. The code must be in writable memory because it is also used for stack. Altering ss has no race condition because only an exception (including debugger single-step, heh!) will change the value back.

	push	8		;replaced by "previous SEH"
	pop	eax		;replaced by "previous SEH"
	call	delta		;instruction must end on dword-aligned offset
				;replaced by handler address
ife DEP				;you must define this variable 0 or 1
	push	-1		;set "previous SEH"
				;if hardware DEP is not enabled by Windows for process, then stack chain is checked
				;all entries must be on stack, and finish with -1 entry
else
	push	eax		;set "previous SEH", just saves one byte, no other effect
				;if hardware DEP is enabled by Windows for process, then stack chain is not checked
				;Windows assumes that data execution will cause exception
endif
	mov	ecx, fs		;push would require extra dword before previous SEH
	mov	ss, ecx		;emulator killer, and anti-single-step, too ;)
	xchg	esp, eax	;fs:8
	call	set_seh		;change stack limit so our code looks like stack
set_seh:
	push	eax		;set new SEH
				;cannot appear after actual handler, otherwise handler looks like is on stack
				;can restore ss here if you want to delay exception
	mov	esp, ebp	;esp must be valid on except. Windows will restore ss for us
				;cannot use leave to pop from stack because current ss limit is too small
				;to delay exception, add jmp here to somewhere else
delta:
	pop	esp		;cause exception on second pass
	call	esp		;set handler address
	;handler code would go here
 

No obvious memory writes.

Greets to friendly people (A-Z):

Active - Benny - izee - Malum - Obleak - Prototype - Ratter - Ronin - RT Fishel - sars - SPTH - The Gingerbread Man - Ultras - uNdErX - Vallez - Vecna - VirusBuster - Whitehead

rgb/defjam jun 2009
iam_rgb@hotmail.com
Donate
friends
deenesitfrplruua
x