1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
|
; TRAPOUT2.ASM v2.0 by ARK (ark@lhq.com, root@ark.dyn.ml.org) 11-28-97
; Traps IN and OUT instructions in INT 10h and displays DX and AX/AL values.
;
; In the header "T DX/I AX/L", T is the Type of instruction (I=IN, O=OUT),
; DX/I is the value of DX or the Immediate value if port<256, and AX/L
; is the value of AX or AL depending on if an 8 or 16 bit value is listed.
; AX/L is meaningless for IN's since it is the value if AX/L *before* the
; call to IN.
;
; This is very useful to find information about how your video card works.
; I wrote this to get register dumps for my Trident TVGA9440AGi card so
; that I could use it under Linux.
;
; NOTE: Pipe the output or you won't see anything!
; (ex: TRAP-OUT 4F02 0101 > 640x480.256)
;
; New in v2.0:
; * Traces into INT 10 calls that are called from inside INT 10!
; * Allows AX and BX values to be specified!
; * Command line accepts trailing spaces now.
; x Code to trap INT's also! (T column='N', DX/I=INT ##, AX/L=AX value)
; (Its commented out - but you can recompile with it if you want)
;
; How to assemble with Borland:
; tasm /ml /zd ncr.asm (case sensitive, line number debug info only)
; tlink /x /t ncr.obj (no map, make com file)
;
.model tiny ; Tiny memory model, all segments point to the same 64K
.286 ; This code will run on a 286... actually, it
.code ; Everything is in the code segment(cs) will probably
.startup ; Startup run on anything
jmp Start ; Go to beginning of progam
realINT1 dd 52411A3Eh ; Address of original INT 01h routine offset
realINT10 dd 3C1B214Bh ; Memory for [es:bx] of the real INT 10h
; (defaults are '>-ARK!-<' just for looks in the .COM)
; strings
no_command_line db 'Use: TRAPOUT2 [AX] [BX]',13,10
db ' Traces all IN/OUT calls inside INT 10h',13,10,36
tracing db 'Tracing INT 10h with AX:',36
bx_msg db ' BX:',36
header db 13,10,'T DX/I AX/L',13,10,36
INT1 proc ; Interrupt Service Routine for Single Step Debugging
push ax ; save registers
push dx
push es
push di
push bp
mov bp,sp ; set bp to the stack
push word ptr cs:[bp+12] ; put the real cs
pop es ; into es
push word ptr cs:[bp+10] ; put the real ip
pop di ; into di
mov al,byte ptr es:[di] ; set al to the next instruction that will
; be executed after this INT 01 is done.
; This code will trap INT's also...
; cmp al,0CDh ; If al is not CD (INT) keep going
; jne not_int ; If it is, display some stuff...
;; This will skip doing the INT's...
;; add word ptr cs:[bp+10],2 ; Add 2 to the real ip, to skip the INT
; mov dl,4Eh ; Display an N
; mov ah,02h ; The immediate value/DX is the INT ##
; int 21h ; that is called. AX is the value before
; mov dl,20h ; Display a space
; mov ah,02h ;
; int 21h ; Display the immediate value which is
; jmp is_imm ; reallly the interrupt number called.
not_int:
and al,0F4h ; If al is E4-E7 or EC-EF (all IN/OUT's)
cmp al,0E4h ; Then we display our stuff
jne not_io ; Otherwise, do nothing
; note: 1 more byte of code after this
; jmp will make it out of range...
mov al,byte ptr es:[di] ; Set al to next instruction
test al,02h ; If bit 1 is set then we have an OUT
jz is_in ; If bit 1 is 0, we have an IN
mov dl,4Fh ; Display an O
mov ah,02h
int 21h
jmp dx_or_imd
is_in: ; Display an I
mov dl,49h
mov ah,02h
int 21h
dx_or_imd: ; Display a space
mov dl,20h
mov ah,02h
int 21h
mov al,byte ptr es:[di] ; Set al to next instruction
test al,08h ; If bit 3 is set then we are using DX
jz is_imm ; If bit 3 is 0, we are using an immediate
mov ax,[bp+6] ; restore dx to ax
call ShowHex ; Display dx
call ShowHex
call ShowHex
call ShowHex
jmp ax_or_al
is_imm:
mov dl,20h ; Display 2 spaces
mov ah,02h
int 21h
mov dl,20h
mov ah,02h
int 21h
mov ah,byte ptr es:[di+1] ; Set ah to byte after the next instruction
call ShowHex ; Display the immediate value
call ShowHex
ax_or_al:
mov dl,2Ch ; Display a comma
mov ah,02h
int 21h
mov al,byte ptr es:[di] ; Set al to next instruction
test al,01h ; If bit 0 is set then we are using AX
jz is_al ; If bit 0 is 0, we are using AL
mov ax,[bp+8] ; Restore ax
call ShowHex ; Display ax
call ShowHex
call ShowHex
call ShowHex
jmp print_next_line
is_al:
mov ah,[bp+8] ; Restore al to ah
call ShowHex ; Display al
call ShowHex
print_next_line:
mov dl,0Dh ; print a newline
mov ah,02h
int 21h
mov dl,0Ah
mov ah,02h
int 21h
not_io:
pop bp ; restore registers
pop di
pop es
pop dx
pop ax
iret ; end interrupt
INT1 endp
; INT 10h that fakes the real INT 10 and sets the trap flag.
INT10 proc ; Interrupt Service Routine for Tracing INT 10h
push ax ; Save AX
pushf ; Put flags on the stack
pop ax ; Then into AX
or ax,0100h ; Set the trap flag
push ax ; Trap Flag calls INT 01h between every instruction
popf ; Stuff new flags back into the flags register
pop ax ; Restore AX
cli ; Fake INT call: clear interrupt flag, skip clearing
pushf ; trap flag, push flags, call to location.
call cs:[realINT10] ; This call to INT 10h is be trapped for
; IN/OUT/INT Normal INT calls would clear
; the trap flag and then INT 01h would never
; be called.
iret ; end interrupt
INT10 endp
; function that prints the highest 4 bits of ax as text {0-9,A-F} to stdout
; ax will be shifted left 4 bits on return.
ShowHex proc
push ax ; save registers
push dx
shr ax,0Ch ; move the highest 4 bits to the lowest 4
and al,0Fh ; limit to lowest 4 bits
or al,30h ; change range to 30h-3Fh {0-9:;<=>?}
cmp al,39h ; if it is 30h-39h
jbe is_0_thru_9 ; then its already set
add al,07h ; otherwise change :;<=>? to A-F
is_0_thru_9:
mov dl,al
mov ah,02h
int 21h
pop dx ; restore dx
pop ax ; restore ax
shl ax,4 ; set up ax for next call
ret ; return
ShowHex endp
Start: ; Program begins here
mov si,0080h ; CS:0080h is the command line
cmp byte ptr [si],10 ; I want it to be at least 10 bytes long
jae process_command_line ; if not, abort
mov dx,offset no_command_line ; ds is preset
mov ah,09h ; Dos function 09h
int 21h ; Display no command line string
ret ; Exit program
process_command_line:
inc si ; move si to start of actual string
mov ax,[si+1] ; copy first 2 chrs to ax, skipping the space
mov bx,[si+3] ; copy 2nd two characters to bx
sub al,30h ; subtract 30h so chrs 0-9 have value 0-9
cmp al,09h ; if its 0-9, its ok.
jbe al_is_ok ; if its not, its probably A-F or a-f
sub al,07h ; so subtract 7 more
and al,0Fh ; and limit to 0-F
al_is_ok:
sub ah,30h ; do the same to ah
cmp ah,09h
jbe ah_is_ok
sub ah,07h
and ah,0Fh
ah_is_ok:
sub bl,30h ; do the same to bl
cmp bl,09h
jbe bl_is_ok
sub bl,07h
and bl,0Fh
bl_is_ok:
sub bh,30h ; do the same to bh
cmp bh,09h
jbe bh_is_ok
sub bh,07h
and bh,0Fh
bh_is_ok:
shl al,04h ; Combine the values so that AL-AH-BL-BH
or ah,al ; Goes into --AH- --AL-
mov al,bl ; <----AX--->
shl al,04h
or al,bh
mov word ptr [si],ax ; store the value over the string
mov ax,[si+6] ; copy 3rd 2 chrs to ax, skip the 2nd space
mov bx,[si+8] ; copy 4th two characters to bx
sub al,30h ; subtract 30h so chrs 0-9 have value 0-9
cmp al,09h ; if its 0-9, its ok.
jbe al_is_ok2 ; if its not, its probably A-F or a-f
sub al,07h ; so subtract 7 more
and al,0Fh ; and limit to 0-F
al_is_ok2:
sub ah,30h ; do the same to ah
cmp ah,09h
jbe ah_is_ok2
sub ah,07h
and ah,0Fh
ah_is_ok2:
sub bl,30h ; do the same to bl
cmp bl,09h
jbe bl_is_ok2
sub bl,07h
and bl,0Fh
bl_is_ok2:
sub bh,30h ; do the same to bh
cmp bh,09h
jbe bh_is_ok2
sub bh,07h
and bh,0Fh
bh_is_ok2:
shl al,04h ; Combine the values so that AL-AH-BL-BH
or ah,al ; Goes into --AH- --AL-
mov al,bl ; <----AX--->
shl al,04h
or al,bh
mov word ptr [si+2],ax ; store the value over the string
; Now [si] contains the real values of AX and BX
mov dx,offset tracing ; ds is preset
mov ah,09h ; Dos function 09h
int 21h ; Display tracing string
mov ax,word ptr [si] ; Restore ax
call ShowHex ; Display command line
call ShowHex ; ax value back to user
call ShowHex ; by placing it in ax
call ShowHex ; and calling ShowHex
mov dx,offset bx_msg ; ds is preset
mov ah,09h ; Dos function 09h
int 21h ; Display bx message
mov ax,word ptr [si+2] ; Restore bx into ax
call ShowHex ; Display command line
call ShowHex ; bx value back to user
call ShowHex ; by placing it in ax
call ShowHex ; and calling ShowHex
mov dx,offset header ; ds is preset
mov ah,09h ; Dos function 09h
int 21h ; Display header to output
mov ax,3501h ; Dos function 35h, Get vector of INT 01h
int 21h ; Store it in es:bx
mov word ptr [realINT1],bx ; Store address of original INT 01h
mov word ptr [realINT1+2],es ; into realINT1
mov ax,3510h ; Dos function 35h, Get vector of INT 10h
int 21h ; Store it in es:bx
mov word ptr [realINT10],bx ; Store address of original INT 10h
mov word ptr [realINT10+2],es ; into realINT10 so we can fake an INT
mov ax,2501h ; Dos function 25h, Store DS:DX to INT 01h
mov dx,offset INT1 ; ds is preset, dx is the handler's offset
int 21h ; Set new Single Step handler
mov ax,2510h ; Dos function 25h, Store DS:DX to INT 10h
mov dx,offset INT10 ; ds is preset, dx is the handler's offset
int 21h ; Set new Video Interrupt
mov ax,word ptr [si] ; We will use the command line ax/bx
mov bx,word ptr [si+2] ; values for the fake int call
int 10h ; Call my int 10 which fakes the
; real int 10 and traps it.
mov ax,2501h ; Dos function 25h, Store DS:DX to INT 01h
mov dx,word ptr [realINT1] ; ds/dx are in realINT1
push ds ; Save old ds
push word ptr [realINT1+2] ; Put segment on stack
pop ds ; Set ds to the segment
int 21h ; Reset old Single Step handler
pop ds ; Restore old ds
mov ax,2510h ; Dos function 25h, Store DS:DX to INT 10h
mov dx,word ptr [realINT10] ; ds/dx are in realINT10
push ds ; Save old ds
push word ptr [realINT10+2] ; Put segment on stack
pop ds ; Set ds to the segment
int 21h ; Reset old Video Interrupt
pop ds ; Restore old ds
mov ax,0003h ; Set ax to 3
int 10h ; Set 80x25 Text mode
ret ; End of program
end ; End of file
|