Log in

View Full Version : debugs debugger's int handler


dion
August 27th, 2002, 03:23
lately i'm facing problem with debugging TRW2000 with softice. i want to trace the int1 or int3 process from TRW. first, i try bpx in the int_handler from TRW... but no luck, softice wont popup. then i try to use BPR and softice hang up then i use bpm, but my computer reboot instantly >( then... i try to BPM not in TRW, but in a loaded program [ie notepad] and BPM at an address just right before BPX from TRW, still... cant reach the int1/3 routine

me... wondering, how debugger author debug his int_handler? if anyone know how this thing done, please help me...

just another question: when TRW loaded, the idt for int1 and int3 was replaced for a moment. how the replace process achieved? do the previous one was 'chained' or not?

thanks

Kayaker
August 27th, 2002, 06:56
Hi dion,

I took a quick look at TRW in memory and noticed both the int01 and int03 routines use VxDCall 'Get_Cur_Thread_Handle' very early, so why not set a Softice breakpoint on that instead? Type 'VCALL <partial-name>' in Softice, and you can get the spelling right before setting the bp.

Breaking on a system API should be more reliable than setting a straight bpm in an ISR in vxd code in what is likely a locked code segment, it's possible that Softice might not break on this. You could try SuperBPM.

TRW looks to use a regular IDT hooking routine, using the SIDT command to load the IDTR Register and store the IDT base address and limit from the IDTR register. Check the Intel docs and search this board for previous threads on how to the hook the IDT.

The previous int handlers may be chained to if TRW doesn't want to handle the interrupt, but for INT 1 and INT 3 I would think TRW would not want to pass control to Softice, or Icedump, or Frogsice, or the default Windows handler, or whatever the old interrupt handler was when the IDT was hooked.

Cheers,
Kayaker

dion
August 27th, 2002, 11:30
wee... thanks Kayaker

hope it'll work like u said, i'm gonna trying now.

[yAtEs]
August 27th, 2002, 12:04
you may find this handy for debugging softice its self

-----------------------------
http://www.woodmann.net/protools/files/debuggers/iceclimber.zip

IceClimber by trapflag. 28.VI.2001.
IceClimber 1.0 (3K).

This vxd enables you to set bpxes inside SoftICE's code itself, so you will be able to trace it more comfortably
-----------------------------

regards,
yates.

Kayaker
August 27th, 2002, 19:30
Interesting you mention that [yAtEs]. I was going to bring up the Iceclimber trick as well, then realized Dion probably wasn't trying to break into Softice code itself. But it is an interesting trick by itself. It's actually an easy patch in Softice you can keep permanent without using the Iceclimber vxd all the time. Basically its the code below in winice.exe:


:C003AD24 cmp eax, ds: off_0_C000BC95 ; starting address of WINICE
:C003AD2A jb short loc_0_C003AD34 ; patch to bypass error
:C003AD2C cmp eax, ds: off_0_C00F1EBC ; ending address of WINICE
:C003AD32 jbe short loc_0_C003AD36 ; if bpm set in winice code
:C003AD34 clc
:C003AD35 retn
:C003AD36 push esi
:C003AD37 mov esi, offset aBreakpointsNotAllowedWithinSoftice ; "Breakpoints not allowed within SoftICE"
:C003AD3C call sub_0_C001DE15

If your breakpoint address is set within winice code then you get the error message and the bpm never breaks. Dion, you should check if TRW may do something similar.


Tracing in Softice code is actually a lot of fun and probably the best way to learn how a real debugger works <that others try to imitate ;> It's also a good way to try to improve Softice. If you look at winice long enough you might discover that virtually *every* function in SI can be accessed and traced through disassembly or code through 1 function - the BCHK Boundschecker "Backdoor" interface.

There's enough information here for an essay, which I was thinking of writing one day ;-) , but it's basically related to the SI commands you can execute through your own code using the old:

mov ebp, 4243484Bh ; 'BCHK'
mov al, 0Eh ; Execute a SoftICE command
mov edi, offset SICommand ; ascii of command, i.e. 'SICommand db "HBOOT", 0'
INT 3

Softice intercepts the INT 3 and checks if the command is a valid one it wants to use. There are only 38 of them allowed, most of them just basic information commands, hboot is really the only "active" command allowed. It's interesting how the check is made. The ascii command used is identified, and a single byte bitmask value is retrieved from a table, this is then checked with the BT command against a long bitmask string. The bitmask string is hardcoded into winice and can be found by searching for the dwords immediately after "BCHKWPV.table r".

Here's the start of the BT section where it's decided where to branch to, to process whatever command has been sent via the BCHK interface OR typed into the SI window :

====================================
C00813FD BT DS: DWORD_C0081B07, EDX ; check byte against bitmask
C0081404 jb short loc_C0081412
C0081406 mov esi, offset aInvalidCommand ; "Invalid command"
C008140B call sub_C00818F5
C0081410 jmp short loc_C008141B

C0081412 push ebp
C0081413 call ds: off_C0022DC7[edx*4] ; jumps to *every* Softice command

The value of EDX is important here, it is the single byte bitmask value for the SI command you selected. This value is used as an offset to a jump table, which itself jumps to each and every Softice code routine that you might want to explore in winice.exe. The bitmask (edx) value for every function can be found in a table beginning at hex offset 00054288 in winice.exe. Hmmm, I guess I have to give an example here..

----------------------------------------------------------
Let's say you wanted to explore in code the I1HERE command, which enables whether Softice will break on an INT 1. Searching in winice.exe you'll find the ascii / bitmask table:
000543FF 49 31 48 45 52 45 00 51 I1HERE.Q

The "0051" is the bitmask value for this particular command. Plugging this value into EDX you can trace directly to the code associated with it:

I1HERE == 51h == EDX

C0081413 call ds: off_C0022DC7[edx*4]

(C0022DC7 [edx*4] == C0022DC7 + (51h*4) == C0022F0B)

:C0022F0B dd offset sub_0_C002926F
which leads to
:C002926F mov esi, offset dword_0_C002142F
:C0029274 call sub_0_C001F612
:C0029279 jb short loc_0_C0029288
:C002927B call sub_0_C0026808
:C0029280 jb short loc_0_C00292A1
:C0029282 mov ds: byte_0_C003509D, al

And the last line is the I1HERE ON/OFF flag. If al=0 I1HERE is OFF, al=1 I1HERE is ON.
------------------------------------------------

I found this so handy I made a module I use when writing vxd code to automatically set the flag to I1HERE ON, so I can use "INT 01" in code to debug it.

Well, I guess that's the snippet for the day

Regards,
Kayaker

JMI
August 28th, 2002, 02:10
Kayaker:

Looks like you got caught in the "oops, I forgot to turn off smilies" Great stuff as usual.

Regards.

Kayaker
August 28th, 2002, 03:00
Doh!

Thanks JMI. Fixed. Now the only smilies are the real ones

Cheers,
Kayaker

dion
August 28th, 2002, 11:21
Quote:
If your breakpoint address is set within winice code then you get the error message and the bpm never breaks. Dion, you should check if TRW may do something similar.


i had trying to BPX/BPM at vxdcall and no respon from SI. also, i had trying to make it with TRW itfself, but no luck too, ie i dont see CCh in bpx location from SI screen. actually, i think i'm agree with what Hwoarang said in another thread that i should use BPR instead BPX. its just bcoz the int3 was has been replaced by TRW, so SI wont break in any way. but if it true, strange... TRW not respond to it.

i thought that maybe debugger cant put a bp when itself using int3 as a door to break in, bcoz it'll cause a forever loop [if we can do int in ISR] or it'll trigger something bad that always make my computer to reboot. then i thought its not softice which dont want anybody to be able to trace within [especially ISR area], but bcoz its not safe to do so from debugger itself. mmm... maybe u can verify this, Kayaker.

Quote:
virtually *every* function in SI can be accessed and traced through disassembly or code through 1 function - the BCHK Boundschecker "Backdoor" interface


i've heard this for long time, but now i'm really curious... how *exactly* si put this BCHK, when it is set? cant be before CCh, can it?

btw, nice snippets... more complete than mine

[yAtEs]
August 28th, 2002, 12:49
core blimey Kayaker, you know how talk dont ya ;-)
wish i knew someone like you in rl to talk rce for hours
with heh,

Kayaker
August 29th, 2002, 03:01
Heheh, Yates, I would quite enjoy a brain picking RL conversation over a pint with you. Your vxd tuts were very useful ;-) I have had the pleasure of speaking real life with one fellow reverser, and while enjoyable it feels really weird at first saying some of these reversing terms out loud Far cry from the black screen of Softice.

You're right Dion that you can't trace or set breakpoints in Softice if TRW has control of the INT 1 and INT 3, I wasn't really thinking when I suggested breaking on the system api, essentially the same thing. However, you might be able to play with it manually and use one against the other. This is just an idea and may not work.

OK, Softice uses INT 1 for single step tracing, INT 3 for breakpoints. Your problem is that you want to break into the TRW interrupt handlers for these same INTs to trace the code in action. But of course the Softice functions for tracing and breaking are now gone. Therefore in theory, if you could "turn off" the TRW INT 01 you could write in an "INT 1" in code in the *INT 03* handler routine for TRW as a way of breaking. Just as you would normally do with I1HERE ON.

Also, if you could "turn off" the TRW INT 03 handler you could also write in an "INT 3" in code in the *INT 01* handler routine of TRW with I3HERE ON. This make sense?

To do this you can manipulate the IDT table after TRW has loaded, replacing the TRW INT 1 or INT 3 routines with the original Softice handler addresses. You may know this but, Ctrl-D into Softice and get the IDTBase address by typing "IDT" in SI. Display this address in WORD format. Each entry in the IDT is composed of 2 Dwords specifying the segment and offset of the current interrupt handler, followed by the next entry. Here's an example from my notes:

; Each entry in the IDT takes up 2 dwords and is laid out in a 'table' format:
; 016F:80003008 1390 0028 EE00 C000
; ( screendump of my IDT entry for INT 5 gate at 0028:C0001390 )

; 1390h are bits 31...16 of the address
; 0028h is the Target Segment Selector
; EE00h is a bunch of flags we don't care about
; C000h are bits 15...0 of the address

; The entry for each interrupt can be found at
; [Base address of IDT + Interrupt number * 8 bytes]
; So for this example for INT 5, the offset is 5*8=40

After TRW hooks the interrupts, you can change them back to the default Softice handlers when you want. I often do this when a nasty crackme (or my own code crashes, lol) doesn't unhook the IDT after exiting. Prevents a lot of system hangs doing this...


Now, if you had hex patched TRW with an INT 1 (01CDh) at the very beginning of the INT 03 handler routine, then removed the TRW INT 01 handler address from the IDT table and replaced it with the original Softice one, IN THEORY the Softice INT 1 should break (I1HERE ON) inside your TRW INT 03 handler when it is triggered. All fine and good up to this point.

Since single step tracing is now enabled in Softice, you should be able to trace as usual right? Well, actually no, because you've frupped up the TRW code and can't replace the bytes since the "INT 1" will have been stepped over. So what you can do is...

-------------

Depending on how determined you are, there is another way you could do this without having to patch anything into TRW I think. You know VxDCall Get_Cur_Thread_Handle is called very early in both your TRW interrupt routines. You can hook the calls with VMMCall Hook_Device_Service and you get your very own interrupt procedure to play in.

Load TRW and get it set up, manually replace the original Softice INT 1 handler. Then you start your Hook app which will trigger when TRW uses the Get_Cur_Thread_Handle call. In the HookProc interrupt routine you set an INT 1 at the start of your code. Softice should break and you're in tracing mode. You can now call other vxd services as well and possibly discover the CONTEXT structure of TRW at the time of its interrupt or whatever else you might want.

You end the HookProc with
jmp [OldServiceAddress] ; Chain to previous hook

Now the trick is getting back to TRW code from your HookProc. If you have single step tracing enabled in Softice you should be able to trace it back to the original code (and discover a lot of system code while doing it). You could only do this in one interrupt routine though, the other you'd have to do something like setting breakpoints instead of tracing.

Somewhere on this board I've posted a working SystemHook1.zip example of how to set a system hook using VMMCall Hook_Device_Service. You just change the service you want to hook. In this case it would be Get_Cur_Thread_Handle. Get_Cur_Thread_Handle returns the handle in EDI and uses Flags, you can set up a stack frame at the start of your HookProc to access the stack, maybe find the return address in TRW...

There is one caveat to this, and that is that you've got a hook procedure operating within an interrupt. I'm not sure if this could cause some unexpected reentrancy problems. It likely would actually, but you could deal with that in code since you're only doing this for debugging purposes.

If you just want to see the TRW code run you might be able to fake it by copying the handler routines into your own code and see how they operate. Rip out the handler routines from the TRW vxd if you can and stick them into your own innocuous hooked interrupt, like INT 6 or something. It might crash or hang but you can at least see how Get_Cur_Thread_Handle and the other code operates. Not sure exactly what you're trying to do.

Hope this helps,
Kayaker

dion
August 29th, 2002, 10:42
lotsa thanks for ur nice and bunch reply, Kayaker it takes several hours headache reading these stuff [just kidding ].

but, i get it already now, by changing a byte in TRW ISR... it generates a GPF/fault [i dont remember what fault, maybe coz by locked page?] and popup the softice screen right in TRW ISR code. what i'm want to do was tracking TRW ISR stack frame, bcoz i remember that i've read somewhere that TRW has a bug in handling segment from one of fs/gs/??.

Quote:
There is one caveat to this, and that is that you've got a hook procedure operating within an interrupt. I'm not sure if this could cause some unexpected reentrancy problems.


i dont know if i'm wrong, but have u ever wonder how debugger msg loop would looks like, Kayaker? i just get info from disasm, that shows that this msg loop was reside in these ISR. so lotsa thing like call vmm services and the other vxd call was executed in this loop. that somehow wierd and i felt that i'm missing something important here, but i dont know what is that. mmm... if u know about this msg loop [for debugger in general], could u give just a little pseudocode? i already post this matter in another forum, but like always... gets no answer

Quote:
Somewhere on this board I've posted a working SystemHook1.zip example of how to set a system hook using VMMCall Hook_Device_Service


mmm... lately i'm wondering how to do that in TRW plugin, and yeah! i could compile it successfully but not test it yet, just compile. and related problem with this Hook_Device_Service is... is there any reverse function for GetVxDServiceOrdinal() macro? besides, looks like TRW [and softice too maybe] was listing this VCALL ordinal from hardcoded string... how terrible! just thinking what would happen if theres 'version conflict' of vxd service stuff here?

regards