Você está na página 1de 15

SOFTICE INTERNALS

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.

I] HOW SOFTICE WORKS


I.1 DOS startup
I.2 Protected mode setup
I.3 Interrupts
I.4 Breakpoints

II] UNDOCUMENTED COMMANDS AND INTERFACES


II.1 Undocumented commands
II.2 Internal variables
II.3 Ver interface
II.4 Dot commands
II.5 INT41h interface
II.6 INT3 - FGJM interface
II.7 INT3 - BCHK interface

I] HOW SOFTICE WORKS


=====================

I.1 DOS startup


----------------
Winice.exe is a MZ/LE file, it therefore contains parts of code to be
executed in real mode (DOS) and parts to be executed in protected mode (VxD).
When executed from DOS (on command line, or from autoexec.bat), winice.exe
performs the following steps :

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 :

/? display help text about these switches


/load filename load symbol informations from file
/sym number amount of symbol table memory in decimal K
/hst number amount of aditional display memory in decimal K
/tra number amount of backtrace history memory in decimal K
some more undocumented switches are supported :

/x break on SoftICE startup


/m monochrome video
/nmi [on|off] trap Non-Maskable Interrupt
/nol [on|off] no capslock/numlock programming
/vdd use virtual display device
/kbd [on|off] patch keyboard driver [caps/numlock]
/pen [on|off] enable pentium support
/com[123] use COM port 1-3 for serial debugging
/exp filename load exports from file name
/l filename load symbol information from file name
/l% filename load symbol information from file name
/load filename load symbol information from file name
/load% filename load symbol information from file name
/loadx filename load symbol information from file name
/loadx% filename load symbol information from file name
/load32 filename load symbol information from file name
/load32% filename load symbol information from file name

6. hook the following vectors in the IVT :

2Fh - Microsoft Windows


SoftICE handles service 1605h (Windows Init Broadcast) and returns
its own ES:BX values for startup infos structure pointer (chained
to the previous structure). Previous vector is chained.

68h - Real Mode Debugger services


SoftICE handles the following services (previous vector is chained):
43h: D386_Identify, SoftICE returns AX=0F386h.
44h: D386_Prepare_PMode, SoftICE returns a pointer to its protected
mode initialisation callback function (PMINIT). This function
implements services PMINIT_INIT_IDT, PMINIT_INIT_PAGING,
PMINIT_INIT_SPARE_PTE and PMINIT_GET_SIZE_PHYS.
5080h and 5081h: D386_Load_Segment (device driver code/data segment).
9000h: SoftICE specific (SIWVID).

23h - Ctrl-C handler


This keyboard sequence can be used to cancel SoftICE loading ; when
called SoftICE restores INT 2Fh and INT 68h original handlers, then
INT 0Bh or INT 0Ch original handler (the COM ports interrupt,
depending on what has been previously hooked according to the /COM
command line value). Then SoftICE calls XMS driver services 0Dh and
0Ah and exits. Previous vector is ignored.

7. open video driver (default SIWVID.386) and read parameters.


8. read and parse WINICE.DAT (max size is 16K).
9. read and parse WINICE.BRK (breakpoint history, see 18). This file
can contain at most 32 breakpoints, each one described in plaintext
(e.g. "BPX GetProcAddress").
10. read WINICE.VID for video configuration.
11. check for a VGA driver and get ROM Font pointer 8x14 character,
8x16 VGA or 8x8 double dot (see the FONT internal variable).
12. get DOS version and pointer to DOS List of Lists.
13. check that it can find WIN.COM.
14. open KRNL386.EXE, USER.EXE, GDI.EXE, WIN386.EXE, DOS386.EXE.
15. allocate extended memory through XMS driver for symbols, backtrace,
exports and history and display the corresponding informations.
16. if required, display more infos and "Press any key to continue".
17. load and execute WIN.COM

Here Windows is loading and takes control...

25. If BootGUI=0 in msdos.sys, SoftICE DOS part takes control back


when Windows is shut down. Then, it saves a new WINICE.BRK, free
allocated memory, restores hooked interrupts 2Fh, 68h, 0Bh/0Ch
and exits to DOS.

I.2 Protected mode setup


-------------------------
Unlike other debuggers, SoftICE is active before any process starts
or before any (non-system) static driver is loaded, and this unique
feature requires a quite complex protected mode setup. Since usual
WIN.COM is executed at step 17, SoftICE can only get control back
through hooks (INT2Fh and INT68h in the IVT) and OS callbacks (PMINIT).
So at step 17 we are still in real mode, WINICE.EXE executes WIN.COM :

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) :

- PMINIT_INIT_IDT: here SoftICE completes its code for BPINTs and


hooks IDT vectors 1,2,3,6,0Bh,0Ch,0Dh,0Eh,41h.

- PMINIT_GET_SIZE_PHYS: here SoftICE ignores the service (returns


debugger address = debugger size = 0) to force VMM to call the
two following ones :

- PMINIT_INIT_PAGING: there happens most of SoftICE initialization,


which includes PICs setup, TSC calibration, WINICE.DAT parsing
(options, macros), video setup, printer setup, keyboard patching,
symbols loading, etc. When this service is completed, SoftICE is
active and can be used.

- PMINIT_INIT_SPARE_PTE: SoftICE maps the complete physical memory


(as indicated in WINICE.DAT) into linear address space.

Since SoftICE is registered as driver, winice.exe will receive all


VxD system messages (SoftICE only handles SYS_CRITICAL_INIT, DEVICE_INIT,
INIT_COMPLETE, SYS_CRITICAL_EXIT, W32_DEVICEIOCONTROL, SET_DEVICE_FOCUS,
DESTROY_VM). During Windows startup (when static VxDs are loaded),
SoftICE will receive the three following messages :
22. SYS_CRITICAL_INIT, where SoftICE
- calls Win386_Alive service (INT22h/AX=0) to check that WIN386
is loaded.
- gets system VMM version and according to the value, enable (or not)
some commands (DEVICE,DRIVER,FOBJ,IRP,OBJDIR).
- gets machine infos (MSDOS version numbers, processor type, etc).
- hooks PM faults 06, 0Ch, 0Dh, 0Eh
VMM faults 06, 0Dh, 0Eh
V86 faults 06, 0Ch, 0Dh, 0Eh
- hooks the following VMM services (replacing previous ones):
Out_Debug_String, In_Debug_Chr, Out_Debug_Chr, Get_Profile_Hex_Int
and if VMM version is at least 400h, Trace_Out_Service and
Debug_Printf_Service.
- hooks port 84h, redirects it to a retn, and completely disable
Windows handling of this port.
- hooks the following VMM services (chained to previous ones):
Enable_Local_Trapping, Disable_Local_Trapping, Enable_Global_Trapping,
Disable_Global_Trapping.
- installs its Task Switch Callback function (called at each task switch).
- hooks the following VMM services (chained to previous ones):
_AllocateThreadDataSlot, _FreeThreadDataSlot.
- hooks the folowing VMM services (chained to previous ones):
_ContextDestroy, _Debug_Flags_Service.
- completes the SIWDEBUG DDB and adds it to the device list.
- hooks VXDLDR _PELDR_AddExportTable (chained to previous one).
- creates 3 new descriptors in GDT, one to access SoftICE's own code,
one for INT 41h hooking and one to access first Meg of memory.

23. DEVICE_INIT, where SoftICE


- calls services 0 and 1 of SIWVID.
- sets the hot key.
- installs its page fault handler.

24. INIT_COMPLETE, where SoftICE just clears the carry flag.

At this point SoftICE setup is complete and Windows continues loading


freely.

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.

Setting a new breakpoint in SoftICE is performed in two steps. First, when


the user types his command, a new breakpoint structure is filled in the
breakpoint table, but the actual resources (PTE, DRx, ...) are still not
used. Then, when the user restarts the application (with G,P,T or HERE),
the 'per type' arrays are parsed, the resources corresponding to all
active breakpoints are allocated, and the application is resumed.

Now there's one major drawback in SoftICE's breakpoint implementation :


SoftICE breakpoints are context sensitive in the lower 2GB, but quite
strangely context checking is performed independantly of the OS. Indeed,
whenever a breakpoint occurs, the current context is compared to the
context where it has been set (this original context is saved in the
breakpoint structure), and if they match SoftICE pops up. Unfortunately,
this weird method cause both feature limitations and processing overhead,
which could have been avoided by using the OS' own context mechanism.
For instance, it would have been possible to set 4 BPMs per task by
modifying DRx values in the task's _CONTEXT structure, since the OS
itself would have taken care of keeping the correct DRx values with the
correct threads. In the current implementation, SoftICE only supports
4 BPMs for the complete system.

I.4.a BPX

BPX is SoftICE's basic breakpoint on execution : when the breakpoint is


active, the byte at target address is exchanged with CCh, the special
INT3 opcode. When the INT3 is executed, SoftICE's INT 3 handler is called,
and the original byte is restored. When exiting SoftICE, the CCh byte is
set back in place and the breakpoint can trigger again. It should be noted
that the single byte INT3 opcode is slightly different from the two bytes
'INT 3' opcode, because it offers special features which guarantee more
robust breakpoint triggering (see intel manuals).

There's a problem with SoftICE's BPX implementation : sometimes after


a debugging session, one will find in his executable file some CCh bytes
where he previously had set BPXs. This apparently comes from the OS virtual
memory system, which at some point decided to page out to disk a piece
of memory where a BPX had been set, and therefore has written back to
the file this CCh byte (this is an old problem, which however has never
been fixed by NuMega).

I.4.b BPM

BPM is used to set a breakpoint on memory access or code execution, based


on debug registers. The breakpoint type is stored in the breakpoint
structure, and is translated into the R/Wn fields of DR7 :
code execution = 00
data write only = 01
data read/write = 11
data read only = 11 (read and write sorted in the handler)

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

BPR is SoftICE's breakpoint on memory range, which can detect read


and write accesses to a (hardcoded) maximum range of 400000h bytes.
This is done by marking the corresponding page (or pages, up to 1024)
as non present : when an access to a non present 4k page is made, a
page fault occur, SoftICE's page fault handler is called and checks
if the faulting address is in the required range.

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).

This breakpoint requires a little implementation subtlety : since a


page fault occur before the faulting instruction is executed, SoftICE
must in some way deactivate the BPR, let the instruction execute, and
reactivate the BPR (so that the breakpoint can be triggered again).
This is done in the page fault handler by marking the page as present,
then setting setting the single-step flag (T) of the current thread ;
when the instruction has been executed an INT 1 is triggered, SoftICE's
INT 1 handler clears the trap flag and mark the page not present again.

A BPR has some other hardcoded limitations, it cannot be set on memory


pages used by :
- SoftICE (check is performed using SoftICE's specific descriptor in GDT).
- current GDT.
- saved IDT (2FFh bytes range).
- saved LDT.
- page directories (and not tables, as said in the doc).

Note also that SoftICE's page fault handler is post-chained to original


VMM's one, which explains the nice 'virtual breakpoint' feature (you can
set BPRs on pages not yet present in memory).

I.4.d BPIO

This is a breakpoint on IO port access, and uses two methods :

- 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.

- Debug registers (with '-h' option, Win9x/NT, Pentium+ processors)


can catch accesses from Ring3 and Ring0, but not in V86 mode.

In both cases, the exception (GPF for IO Bitmap, Debug exception


for DRx) is triggered whichever condition has been defined (R, RW or W).
Then, SoftICE disassembles the IO opcode and checks if it matches
the breakpoint R/W condition.

I.4.e BPINT

This breakpoint allows triggering on interrupt event. Whenever a BPINT


is asked on an interrupt vector which is not already owned by SoftICE,
the debugger patches the corresponding IDT descriptor, and makes the
new handler address point to this code :

push <INT_number>
jmp <BPINTHandler>

All BPINT breakpoints finally end in the same handler, where


informations are checked and reported. For interrupts that are already
owned by SoftICE, the IDT descriptor is not modified and the BPINT
condition is checked in the current handler. In both cases, SoftICE
will pop up in the first instruction that is not part of its own
code (usually in VMM handler).

BPINT command parsing allows only interrupts up to 5Fh because Windows


use only IDT interrupts up to 5Fh (upper interrupts are dispatched
through GPF to PMode or RealMode handlers). Therefore you cannot use
BPINT to set a breakpoint on, for instance, INT68h real mode interrupt,
you should instead use a BPX style breakpoint, e.g. "BPX *($0:(68*4))"
II] UNDOCUMENTED COMMANDS AND INTERFACES
==========================================
Please keep in mind that the following chapter describes the features
found in SoftICE 3.23, some have been removed (and some other added) in
later versions, and so none is guaranteed to work on your system.

II.1 Built-in commands


-----------------------
Most of SoftICE's built-in commands are described in SoftICE's users
guide, but there are still a few more which give interesting system
variables (type '?<command>' to test them).

- 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.

- UTCB/UPDB: return pointers to the current Thread Control Block/


Process DataBase.

- VMMTID: returns VMM thread ID (always 1).

- CONTEXT: returns handle (ie pointer) to the current _CONTEXT structure.

- 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 :

- GENINT BCW: for BoundsChecker activation.

II.2 Internal Variables


------------------------
SoftICE uses several internal variables to retain settings informations.
These variables may be changed dynamically using the "set variable parameter"
command, current settings can be viewed by typing "set variable" with no
parameter. These variables are :

ALTSCR [on|off] :moves display to a second, monochrome monitor.


CASESENSITIVE [on|off] :make global/local symbol names case-sensitive.
CODE [on|off] :display hexadecimal bytecodes.
EXCLUDE [on|off] :enable/disable range address checking.
FAULTS [on|off] :trap General Protection and Page Faults.
I1HERE [on|off] :make any embedded INT1 invoke SoftICE.
I3HERE [on|off] :make any embedded INT3 invoke SoftICE.
LOWERCASE [on|off] :display code in lowercase.
MOUSE [on|off 1|2|3] :turn mouse on/off, set movement speed
from 1 (slow) to 3 (fast).
PAUSE [on|off] : pause after each screenful of info in the
Command Window.
REFERENCE [on|off] : toggle memory display of referenced operands
(top right corner).
SYMBOLS [on|off] : use symbol information.
TABS [on|off 1|2|3|4|5|6|7|8] : set tabstops every 1-8 characters.
THREADP [on|off] : enable/disable thread-specific stepping.
VERBOSE [on|off] : display diagnostic messages.
Some variables can also be set in winice.dat without using the "init" line :

NOPIC2=[on|off] : disable/enable second PIC handling.


NOLEDS=[on|off] : disable/enable capslock and numlock programming.
NOPAGE=[on|off] : disable/enable mapping of non-present pages.
NOCONTEXT=[on|off] : enable/disable context sensitivity for breakpoints.
MACROS=number : maxmimum number of macros.
NMI=[on|off] : trap Non-Maskable Interrupt.
VERBOSE=[on|off] : enable/disable diagnostic messages.
KBD=[on|off] : patch/do not patch keyboard driver.
LOWERCASE=[on|off] : enable/disable lowercase assembly.
MOUSE=[on|off] : enable/disable mouse support.
THREADP=[on|off] : enable/disable thread-specific stepping.
EXCLUDE=range : exclude physical memory range for SoftICE.
SIWVIDRANGE=[on|off]: exclude SoftICE video physical memory range.
TRA=size : trace buffer size.
HST=size : command history buffer size.
LOAD=filename : load symbols from file.
LOAD%=filename : " " " "
LOADX=filename : " " " "
LOADX%=filename : " " " "
LOAD32=filename : " " " "
LOAD32%=filename : " " " "
PHYSMB=size : amount of system RAM.
PHONE=number : phone number for serial debugging.
COM1=[on|off] : enable COM1 for serial debugging.
DINIT=string : DIAL initialiaztion string for serial debugging.
ANSWER=string : ANSWER initialization string for serial debugging.
EXP=filename : load exports.
VDD=[on|off] : use Virtual Display Device.
DDRAW=[on|off] : enable/disable direct video monitor access.
DRAWSIZE=size : video memory size in K.
MONITOR=value : defines number of display driver to use.
WDMEXPORTS=[on|off] : get exports loaded by PELDR driver.
NAME=string : your name (returned by VER command).
COMPANY=string : your company (returned by VER command)
SERIAL=string : your serial number (returned by VER command)
DISPLAY=[VIPE|S3|MACH32|MACH86|0|VD] : video display type.
SRC= : no longer supported
FAULTS=[on|off] : trap GPFs and PFs.
SYM=size : mem alloc for symbols.
LBRECORD=[on|off] : enable/disable last-branch message collection.

II.3 VER interface


--------------------
According to Numega's documentations, the 'ver' command just display
SoftICE version number ; actually, it does much more :

: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 :

dot : display infos about registered dot commands.


sio : greetings from the SoftICE team ; for some unknown reason,
Numega people allow users to call this only once.
lin (offset) : dump memory at the first address in the current data window
+ offset (very handy to navigate through a linked list).
asm <vxdname> : disassemble a vxd.
int : enable/disable INT41h handling.
tes : does nothing.

II.4 Dot commands


------------------
There are 3 types of dot commands, none of them is SoftICE specific,
yet they are so useful that I decided to include them in this document.

- VxD debug interface : when issuing a ".VxDname" command into


SoftICE, a Debug_Query message is sent to the corresponding VxD.
If this VxD handles this message, it can send back informations
to the debugger, or even start an interactive session. Here are
some sample Win95 VxD dot commands, and what they are useful for
(interactive commands are marked with a (I)) :

.vmm Virtual Machine Manager, plenty of system informations (I).


.vdmad Virtual DMA Device, DMA channels.
.vxdldr VxD Loader, informations about loaded VxDs.
.vtd Virtual Timer Device, gives VTD functions addresses.
.vpicd Virtual PIC Device, IRQs and IRQ handlers (I)
.dosmgr DOS virtual machine infos (I)
.vmpoll Virtual Machine Polling device.
.vtdapi Virtual Timer Device API.

- Registered commands : a VxD can also register a dot command to


the kernel debugger, by using Microsoft kernel debugger interface.
This interface is based on INT 41h, whose handler is owned by the
debugger : to register its dot command, a VxD simply issue an
INT 41h/AX=70h and gives to the debugger the addresses of the
command's code and helptext (see INT 41h chapter). By default,
only the '.m' command is available, which gives you full control
on memory management (try '.m?' to see the options). '.?' displays
a list of registered dot commands.

- WIN386 commands : these are kernel built-in commands


..? Display a list of kernel built in commands
.ds Display protected mode stack with labels
.r [#] Display the registers of the current thread (or thread #)
.vm [#] Display the complete VM status of the current VM (or #)
.vc [#] Display the current VM's (or #) control block
.vr [#] Display the registers of the current VM (or #)
.vs [#] Display the current VM's (or #) virtual stack
.vl Display list of all valid VM handles
.vh [b|w|d] [#] Display as Byte/Word/Dword the VMM linked list,
given a list handle.

Note that all these commands are available in standard Windows retail
versions, but debug versions provide more dot commands.

II.5 INT 41h Interface


------------------------
This interrupt is defined as Microsoft Kernel debugger interface.
SoftICE supports the following services :

AX=00h -- Display character on debug terminal


entry : AL = character to display

AX=01h -- Read character from debug terminal


returns: AL = readed char

AX=02h -- Displays a string on debug terminal


entry: DS:ESI pointer to null terminated string to display

AX=0Fh -- Find closest symbol


find the symbol nearest to the address in CX:EBX and
display the result in the format symbol name <+offset>
the offset is only included if needed, and no CR&LF
is displayed.

AX=12h -- Displays a string on debug terminal (called by 16 bit code)


entry: DS:SI pointer to null terminated string to display

AX=40h -- Run debugee until specified CS:IP is reached


entry : CX = desired CS BX = desires IP

AX=4Fh -- Check if a protected mode debugger is installed


return: AX = F386h, if true

AX=50h -- Define a segment value for the debugger's symbol handling


entry: SI type (0: code selector, 1: data selector,
80h: code segment, 81h: data segment)
BX segment #
CX actual segment/selector
DX data instance
ES:(E)DI pointer to module name

AX=52h -- Free segment (16 bits)


notify the debugger that a segment has been freed
entry: BX segment value

AX=5Ah -- Indicate Kernel Vars


Used by the Windows kernel to tell the
debugger the location of kernel variables
used in the heap dump commands.
entry: BX = version number of this data (03a0h)
DX:CX points to:
WORD hGlobalHeap ****
WORD pGlobalHeap ****
WORD hExeHead ****
WORD hExeSweep
WORD topPDB
WORD headPDB
WORD topsizePDB
WORD headTDB ****
WORD curTDB ****
WORD loadTDB
WORD LockTDB
WORD SelTableLen ****
DWORD SelTableStart ****

(starred fields are used by the


heap dump commands).

AX=5Dh -- Get system informations


DS:SI = pointer to an array of offsets:
BX = windows version
CX = number of words in array
WORD1 = fDebugUser (1 = DEBUG, 0 = RETAIL)
WORD2 = 16 bit offset to hHmenuSel
WORD3 = 16 bit offset to hHwndSel
WORD4 = 16 bit offset to pclsList
WORD5 = 16 bit offset to pdceFirst
WORD6 = 16 bit offset to hwndDesktop
This array MUST BE COPIED it goes away when we return
from this service.

AX=64h -- DLL Loaded


entry: CX:BX = DLL entry point CS:IP
SI = module handle

AX=65h -- Module Removed


entry: ES = module handle

AX=66h -- Print Debug message (SoftICE specific)


entry: CL = error message to display
Message is always : "WINICE: LogError ERR_" followed by a
mnemonic of the faulting function.
returns: nothing

AX=70h -- Register dot command (32 bit code )


entry: BL = dot command to register
ESI = linear address of the handler routine
EDI = linear address of the help text
returns: AX = 0 if successful, AX != 0 if registration failed

AX=71h -- Register dot command (called by 16 bit code )


entry: BL = dot command to register
CX:SI = linear address of the handler routine
DX:DI = linear address of the help text
returns: AX = 0 if successful, AX != 0 if registration failed

AX=72h -- Unregister dot command (unregister dot commands registered by


both 70h & 71h)
entry: BL = dot command to de-register

AX=73h -- Debug printf (C like printf function >> output on debugger


terminal ), 32 bits.
entry: DS:ESI = address of format string
DS:EDI = address of first parameter passed (all parameters
are DWORD's )
returns: EAX = nr. of characters printed on debug terminal

AX=74h -- Debug printf (C like printf function >> output on debugger


terminal), 16 bits.
entry: DS:SI = address of format string
ES:DI = address of the start of the word or dword arguments
returns: AX = nr of chars outputed

AX=75h -- Get Register Set


entry: DS:ESI = address of a SaveRegs_Struc type structure

AX=76h -- Set Alternate Register Set


entry: CX = thread ID (0 for current thread)
DS:ESI = address of a SaveRegs_Struc type structure

AX=77h -- Get Command Line Chararacter


entry: BL = 0 -> get char, text pointer not incremented, leading
space not ignored
= 1 -> get char, increment text pointer, leading blank
is skipped
= 2 -? get char, text pointer not incremented, leading
blank is skipped
returns: AL = command line character retrieved
AH = 0 if EOL encountered, !0 if more characters await
parsing

AX=78h -- Evaluate Expression


entry: DS:ESI expression to evaluate
returns: AX: -> 0, returns a data value
-> !0 returns a linear address
CX = TID
EBX = evaluated value

AX=79h -- Verify Memory


entry: ECX = length of memory region
DS:ESI = starting address of memory to verify
returns: AX: -> 0 OK
-> !0 memory range is invalid

AX=7Ah -- Directs debugger to dump current registers

AX=7Bh -- Directs debugger to perform a stack dump


entry: BX: -> 01h - verbose stack dump
-> 02h - 16 bit stack dump
-> 04h - 32 bit stack dump

(services 7Ch, 7Dh and 7Eh are not supported)

AX=7Fh -- Check the debugger wants control on the fault.


entry: BX = fault number
CX = fault type mask
DEBUG_FAULT_TYPE_V86
DEBUG_FAULT_TYPE_PM
DEBUG_FAULT_TYPE_RING0
DEBUG_FAULT_TYPE_FIRST
DEBUG_FAULT_TYPE_LAST
returns: AX = 0, handle fault normally
AX != 0, handled by debugger

AX=80h -- Set Break


This service allows an error break or ctrl-c handler to be
set. The old value that is returned must be save and set
back to remove the break handler.
entry: DS:ESI = pointer to BreakStruc with the CS:EIP
and SS:ESP values to be used when a error
break or ctrl-c happens. The old value is
copied into this buffer.
returns: AX = 0, no error
AX != 0, error on BreakStruc address

(services 81h and 82h are not supported)

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.

entry: EBX = linear address of call back routine, zero to uninstall


ECX = linear address of the end of the call back routine
EDX = EIP to use for for faults in call back routine
returns: none

Callback:
entry: EAX = linear base of SS
EBX = linear address of SS:EBP
DS, ES = flat ds
SS = NOT flat ds !

returns: EAX = FALSE, no thunk


TRUE, is a thunk
CX:ESI = new SS:EBP
DX:EDI = new CS:EIP

(services 85h to 8Ah are not supported)

AX=0150h -- Define a 32-bit segment for Windows 32


entry: SI = type (0: code selector, 1: data selector)
DX:EBX points to a D386_Device_Params STRUC
with all the necessaries in it

AX=0152h -- Free segment (32 bits)


notify the debugger that a segment has been freed
entry: BX segment number
DX:EDI pointer to module name

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

II.6 INT3 - FGJM interface


----------------------------
To use this interface, one should issue an INT03 with SI = 'FG',
DI = 'JM' and AH = service number. About 30 different functions
are implemented, more details to come later.

II.7 INT03 - BCHK Interface


-----------------------------
This interface provides 32 services, to use it issue and INT 03 with
EBP = 'BCHK' and AL = service number (00h-1Fh). Here is a short
overview of what these services are about, I may detail them later :

AL=00h - Get interface version


AL=08h - Reset debug register
AL=09h - Set debug register
AL=0Ah - Modify debug register
AL=0Bh - Disable debug register
AL=0Ch - Get DR6
AL=0Dh - Desactivate DRx breakpoint condition
AL=0Eh - Execute a SoftICE command
AL=0Fh - Notify Boundschecker activation
AL=10h - Notify BoundsChecker desactivation
AL=15h - Set BPM breakpoint
AL=16h - Clear breakpoint (BC)
AL=17h - Enable/Disable breakpoint (BE/BD)
AL=1Ch - Table command

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.

- Iceman and mammon_, for having published SoftICE informations


in the past, some of which I have reused in this document.

- Most of these informations were obtained by working with IDAPro,


the excellent disassembler from Datarescue.

EOF

Você também pode gostar