Kayaker
February 19th, 2002, 23:54
Hi
Thanks for the info analyst ;-) I've since found out this is indeed an old largely undocumented form of the INT1 Single Step Trace Exception known as ICEBP. (Largely undocumented by Intel at least, but a search for 'ICEBP' yields a lot of info, i.e. h*tp://x86.ddj.com/secrets/opcodes/icebp.htm)
I *think* I see what's going on here, but anyone please clarify if I'm wrong, I'm still absorbing CPU architecture and Intel docs to get a better understanding. Normally if you are single step tracing (or using the SI backtrace feature), Softice clears the trace (T) flag in the EFLAGS register, so that the regular INT01 handler is not called. If this trace bit is clear, the instructions are executed without interruption.
So when this errant undocumented INT1 is stepped over (traced), it continues into the "bad boy" code. However, if you weren't single step tracing (and the Trace flag was set), then the SEH (the "good boy" code) that was previously set up would be called and you would continue on unmolested.
I'm still a little confused in how Softice behaves versus "other" debuggers in terms of this trace flag. According to http://www.woodmann.net/fravia/civetta.htm one way to detect SI is:
-----------------------------------------------------------------
4. by using the TRAP flag, one can use the single stepping feature to
call a protection routine (e.g. a decryptor). The problem is, that
during single stepping SOFT-ICE clears the TRAP flag for the V86 task
and will neither execute nor step into the INT01 handler of the
V86 task. Many schemes use this trick.
-----------------------------------------------------------------
OK, so this is where I got that the Trace (Trap) flag is cleared during single step tracing, and this is what this undocumented INT1 trick is taking advantage of. However, according to Art of Assembly Language Ch.6 (or the Intel docs):
----------------------------------------------------------------
The trace flag enables or disables the 80x86 trace mode. Debuggers (such as CodeView)
use this bit to enable or disable the single step/trace operation. When set, the CPU interrupts
each instruction and passes control to the debugger software, allowing the debugger
to single step through the application. If the trace bit is clear, then the 80x86 executes
instructions without the interruption.
----------------------------------------------------------------
In this case it seems to indicate that when the Trace flag is *set*, control is passed to the debugger "allowing the debugger to single step through the application". It just seems to indicate that there is an inherent difference in how Softice operates versus "other" debuggers, unless I'm misinterpreting all this.
Nothing I can't live with of course, it's just a question that came to my mind while trying to understand exactly what's going on. In any case you can certainly *see* the effect of this trick. If you set a bpm breakpoint on the address of the exception handler (good boy routine), which as Zairon said was at 40342E, Softice will break on it if you just execute the program. However if you try tracing over that INT1 (Trace flag cleared?) or use a Backtrace (based on BPR), then it won't break and you'll end up continuing on into the bad boy code.
The output from our Backtrace disassembler actually shows this bad boy sequence (pretty much as you see it in the Softice window anyway), but the difference is that the disassembler (based on the NASM disassembler) records the F1 opcode properly as an INT1, but Softice itself (as you'd see with SHOW) records the backtrace disassembly of 0xF1 as INVALID. Seems Numega never added support for some undocumented opcodes...
Code:
SEH:
23 401876 68875D9749 PUSH DWORD 49975D87
24 40187B 812C2459295749 SUB DWORD [ESP], 49572959
25 401882 643303 XOR EAX, [FS:EBX]
26 401885 50 PUSH EAX
27 401886 648923 MOV [FS:EBX], ESP
; handler routine now at 40342E (49975D87 - 49572959)
...
UNDOCUMENTED OPCODE + BAD BOY ROUTINE:
33 4018BE F1 INT1
34 4018BF 58 POP EAX
35 4018C0 680D620858 PUSH DWORD 5808620D
36 4018C5 810424C7B637A8 ADD DWORD [ESP], A837B6C7
37 4018CC 83C404 ADD ESP, BYTE +4
38 4018CF FF6424FC JMP NEAR [ESP-4]
39 4018D4 648903 MOV [FS:EBX], EAX
3A 4018D7 68382669F2 PUSH DWORD F2692638
3B 4018DC 810424B3F2D60D ADD DWORD [ESP], DD6F2B3
3C 4018E3 83C404 ADD ESP, BYTE +4
3D 4018E6 FF6424FC JMP NEAR [ESP-4]
3E 4018EB 83C404 ADD ESP, BYTE +4
3F 4018EE 83C404 ADD ESP, BYTE +4
40 4018F1 FF6424FC JMP NEAR [ESP-4]
; to Kernel ExitThread
Anyway, thanks again for the interesting tip
Regards,
Kayaker