Documentos de Académico
Documentos de Profesional
Documentos de Cultura
revision 2, 02/01
by +Spath(spath@iname.com)
INTRODUCTION
This document contains various informations about SoftICE, NuMega's system
debugger for Microsoft operating systems ; unless specified, these informations
refer to Windows 95/98/ME SoftICE versions, not the NT/2K ones. My goal here
is both to explain how this debugger works and to document some of its hidden
features. The ideal target audience is made of advanced SoftICE users and/or
curious system coders, thus I will assume you have a good knowledge of x86
processors and Microsoft operating systems. Contributions and corrections
are welcome, interesting questions will be considered (but no video/mouse
complaint, please!), silly requests will be ignored.
1. change video mode to mode 3 (80x25, text mode, 16 colors) and display
SoftICE intro message (SoftICE version, OS, ...)
2. test if Windows is already running in enhanced mode, and quit if so.
3. test if an XMS driver is installed, and quit if not. If installed,
SoftICE stores the XMS driver entry point.
4. test if CPU is 386+ by trying to write higher part of eflags, quit if not.
5. parse command line ; documented switches are :
18. To get informations about the real mode situation, Windows issues
an Init Broadcast call ; this service (INT2Fh/1605h) is hooked by
SoftICE (see step 6), which returns its own Startup Infos structure,
where it declares itself as a DOS device driver.
19. Since SoftICE is now registered as a DOS device driver, Windows will
allocate new selectors for it and call INT68h/5080h and 5081h for
symbolic debugging support. When SoftICE detects that these calls
are used for itself, it will use the selector values to calculate
the linear address of the start of its protected mode code (which
actually is its PMINIT function).
20. Just before switching to protected mode, Windows will issue a
D386_Prepare_PMode call, where SoftICE returns the previously
calculated PMINIT address.
21. Windows switched to protected mode. During its initialisation, VMM
calls the PMINIT routines. Here are the ones SoftICE will react on
(in that order) :
I.3 Interrupts
---------------
Once SoftICE is loaded, Windows and its applications are running freely
and SoftICE only reacts on specific events. To do so, it has hooked 16
interrupt vectors in the system IDT (including 5 IRQs, relocated by
Windows in range 50h-5Fh):
01h : debug exception, used for BPM, BPX, BPIO, T command (and many more).
02h : NMI interrupt.
03h : breakpoint exception, used for BPX.
06h : invalid opcode exception, for logging purposes only.
09h : coprocessor segment overrun.
0Bh : segment not present.
0Ch : stack segment fault.
0Dh : general protection fault, used for BPIO.
0Eh : page fault, used for BPR.
0Fh : no operation.
41h : Microsoft Kernel Debug Interface, interface with SoftICE.
51h : IRQ1: keyboard.
53h : IRQ3: COM2.
54h : IRQ4: COM1.
57h : IRQ7: LPT1.
5Ch : IRQ12: mouse.
The 'IDT' command does not reveal this, but instead shows these interrupt
descriptors pointing to their original locations (usually VMM). This is
because SoftICE saved the original IDT before setting its hooks, and when
the user types the command, it reloads IDTR to use the saved IDT, executes
a "real" 'IDT' command, and restores IDTR to the system IDT. Thanks to
this nice implementation, one can quite easily patch his winice.exe to
always see the real IDT.
I.4 Breakpoints
----------------
SoftICE can handle 256 general breakpoints at a time (breakpoints using
debug registers are however still limited to 4). Each breakpoint
definition is stored in a 183h bytes large structure (which makes a
100k large static array). Each time a new breakpoint is set, SoftICE
performs a test on this breakpoint table to check that memory has
not been altered : if this is the case, a "Breakpoint Table Corrupted"
message is displayed.
On top of this, breakpoints numbers are also stored in 'per type' arrays
(BPX,BPM,BPR,..) which are used to speed up breakpoint recognition,
deactivation and reactivation. For instance when a INT3 occur, SoftICE
get the breakpoints numbers from the BPX array, then for each number it
directly fetches all the informations concerning this breakpoint in
the global breakpoint array.
I.4.a BPX
I.4.b BPM
A BPM for data access can be set on byte, word or dword ; when setting
such breakpoint, SoftICE checks for correct address alignment, according
to the chosen size (which actually is not necessary, since the processor
performs automatic alignment). Following debug registers' behaviour,
the breakpoint is triggered if any of the bytes accessed is in the
range defined for the breakpoint.
A BPM on execution can be set on any piece of code with any size (as
long as alignment is correct). However, you should be very careful here
because of the lack of command line checking : to have a chance to be
triggered, the breakpoint must always be set on the address of the
first byte of the instruction, and must also have a byte size. Any
other address/size combination, even accepted by SoftICE command line
parser, will never trigger.
I.4.c BPR
It should be noted that since the non-present bit of the PTE is used,
this can detect accesses from any privilege level, yet SoftICE will
only trigger for accesses from ring3. This means that for some reason
SoftICE page fault handler filters accesses from ring0 (and therefore
limits this breakpoint's capabilities).
I.4.d BPIO
- TSS' IO Port bitmap (on Win9x only, 386+ processors) can only
catch accesses from Ring3 in pmode, and all accesses from V86 mode.
This is the default method on Win9x versions.
I.4.e BPINT
push <INT_number>
jmp <BPINTHandler>
- UTID/UPID: these are the Win9x counterparts of NT's TID (thread ID)
and PID (process ID), which are very useful for setting
conditional breakpoints.
- K32XOR: the famous "Obsfucator" value, which when xored with the values
returned from GetCurrentProcessID() and GetCurrentThreadID()
give the addresses of the actual corresponding structures.
A special command :
:ver?
query [address [count]] Display PageQuery information
mutex Display mutex list
pager Display pager list
exception Display VxD exception handler list
vmsg [msg-number] Display VxD control messages
vxd [address] Display VxD location list or VxD name
phys <address> Display phys address for NP linear address
addr Display Winice module32/context structures
export Display Winice export32 structures
sym Display Winice symbol table structure
break <break-number> Display Winice breakpoint structure
context [context-handle] Change address context in symbol table
debug Toggle Winice verbose display
In SoftICE 3.0/3.01 'ver ice' display a hello message from SoftICE team.
Actually, there are 6 more commands, not described in the ver help ;
note that each ver commands is identified with only its first 3
letters, therefore I can only guess their full name :
Note that all these commands are available in standard Windows retail
versions, but debug versions provide more dot commands.
AX=83h -- Trap Fault : allows ring 3 code to send a fault to the debugger
entry: BX = fault number
CX = faulting CS
EDX = faulting EIP
ESI = fault error code
EDI = faulting flags
returns: CX = replacement CS
EDX = replacement EIP
AX=84h -- Set stack trace callback : sets the "k" command callback filter
used to back trace thru thunks.
Callback:
entry: EAX = linear base of SS
EBX = linear address of SS:EBP
DS, ES = flat ds
SS = NOT flat ds !
AX=0F003h -- ForceGO
enter the debugger and perform the equivalent
of a 'G' command to force a stop at the
specified CS:EIP
entry: CX = desired CS
EBX = desired EIP
DISCLAIMER
This document is distributed in the hope that it will be useful
but without _any_ warranty. You can copy and distribute verbatim
copies of this document, but changing it is not allowed. In no
event will the author be liable for any damage resulting from
the (mis)use of these informations.
GREETINGS
- First of all, I want to thank The Owl for having shared with
me his incredible knowledge of SoftICE. Both his IDB and our
interactive discussions have been an invaluable help for
me while writing this document.
EOF