Log in

View Full Version : Differences in 32-bit exception handling on 32- and 64-bit host OS


omega_red
April 29th, 2007, 06:46
I shall be known as "Dances-with-Exceptions" after I finish the code I'm writing..

Anyway. I don't know if this has been written about (if it was, I'd appreciate pointers , at least I didn't find anything about the subject. The whole topic started after I discovered that my code (32bit) was running fine on 32bit OS, but crashed on 64bit OS. Took me about half a day to figure this out.

There is a subtle yet very important difference in 'RaiseException'-type APIs between 32-bit OS and 64bit OS running 32-bit code in WOW. Namely, RaiseException and RtlRaiseException on 64bit capture much less data from CONTEXT of calling thread than their 32bit counterparts. It's especially important if you want to play with debug registers (what I was doing) - you can't modify DRs in exception handler called by RaiseException on 64bit OS, since debug registers are not captured in the context. The only way is causing 'native' exception by means of int3, ud2, access violation etc. On 32-bit OS, 'native' exceptions work exactly as Raise Exception - both capture full context of faulting thread.

POC code attached (fasm format).

omega_red
April 29th, 2007, 08:44
Dancing with exceptions, part two: Differences in BPX handling

Scenario: in SEH, we enable hardware execution breakpoints on DR0 and DR1 on increasing addresses. Then, after BP0 hits, we disable it and continue. BP1 then hits.

Result: On 32bit windows, at the moment of BP1 (second breakpoint, first one is disabled) bit 0 of DR6 (debug status register), is not cleared (which would indicate that BP0 was the reason of exception - confusing but that's correct behavior per Intel's manual, CPU should never clear these bits). On 64bit OS, bit 0 of DR6 IS cleared - I don't know if it's OS or my old Athlon

32-bit:
Code:
Address: 00401016, DR0: 00401016, DR1: 00401017, DR6: ffff0ff1, DR7: 00000505
Address: 00401017, DR0: 00401016, DR1: 00401017, DR6: ffff0ff3, DR7: 00000504


64-bit:
Code:
Address: 00401016, DR0: 00401016, DR1: 00401017, DR6: ffff0ff1, DR7: 00000105
Address: 00401017, DR0: 00401016, DR1: 00401017, DR6: ffff0ff2, DR7: 00000104


POC attached

Btw, both samples were tested on: xp 32bit, xp 64bit, 2k3 64bit. I'd be glad to see how this works on 2k/vista

dELTA
April 30th, 2007, 01:54
Very interesting! Thanks for your high-quality contributions as usual omega_red!

evlncrn8
April 30th, 2007, 05:54
also probably worth mentioning the exception handler 'data' isn't at FS:[0] in 64 bit, its in GS:[0]... and its 8 bytes (obviously)

omega_red
April 30th, 2007, 07:50
Quote:
[Originally Posted by evlncrn8;65282]also probably worth mentioning the exception handler 'data' isn't at FS:[0] in 64 bit, its in GS:[0]... and its 8 bytes (obviously)


Yeah, but my ramblings are about 32-bit code running on 32- and 64-bit OS respectively

evlncrn8
April 30th, 2007, 09:28
aah oops heh

OHPen
May 3rd, 2007, 13:43
omega_red: seems that your sec poc, the dr6 thinggy fail for my system.
Im working on a 32 bit system, but the fourth messagebox tells me that we are dealing with 64 bit what is not correct.
I have an Intel Duo Core E4300 with WinXP + SP2 + All patches, 32 bit...

regards,

OHPen

omega_red
May 10th, 2007, 08:08
I've performed some number of tests in various environments. Seems that life is not as simple as we'd like to
OS version as "Vista 32/64" means: "32-bit Vista on vmware (64-bit host OS - xp 64)". "2k 32" is just plain 32-bit w2k on 32bit cpu.
dr6 column states if dr6 status bits are auto-cleared by OS's exception dispatcher (my post#2).
context is about RaiseException behavior: wheter it captures full or partial context.

Code:
os dr6 context
----------------------------
2k 32 clear full
xp 32 clear full
xp 32/32 preserve full
xp 64 clear partial
2k3 32 clear partial
2k3 32/64 preserve partial
vista 32 clear partial
vista 32/64 preserve full
vista 64/64 clear partial


Some conclusions:
vmware seems to change dr6-behavior of 32-bit OS-es "normal" dr6 behavior is to clear status bits 2k3 32bit is abnormal regarding to context capturing need more testing (other vms?)

dELTA
May 10th, 2007, 08:33
Cool, a new top secret 0-day leet VMware detection vector!

evaluator
November 29th, 2007, 01:45
ok, i'm here )

(i yet not look in attachments)

nothing should be strange: all is about RF flag!
PROCESSOR put RF-flag after some EXEPTIONS, so YOU need remove it from
SEH.EFLAGS.

okey, dokey!?

evaluator
November 29th, 2007, 01:54
as about DR6 bits;
if programm is interested in this DR6-bits, it MUST itself clear them after each exception..
not believe in CPU behavior, every other class CPU may have different behavior

evaluator
November 29th, 2007, 02:16
i'm about RF flag, because in BLOGS was written about NOT-breacking DRx after UD2 instruction, but here is not written;

also:
SEH.proc is NOT STDCALL; needs simple RET;

XER
November 27th, 2008, 15:39
Thanks. Very helpful stuff.