2. Process Hollowing
#processhollowing#golang #maldev #malwaredevelopment
Process Hollowing is commonly performed by creating a process in a suspended state then unmapping/hollowing its memory, which can then be replaced with malicious code.
The Windows APIs required to perform this technique are the following:
Create suspended process
Starting a process can be achieved by calling the CreateProcess API.
BOOL CreateProcessA(
[in, optional] LPCSTR lpApplicationName,
[in, out, optional] LPSTR lpCommandLine,
[in, optional] LPSECURITY_ATTRIBUTES lpProcessAttributes,
[in, optional] LPSECURITY_ATTRIBUTES lpThreadAttributes,
[in] BOOL bInheritHandles,
[in] DWORD dwCreationFlags,
[in, optional] LPVOID lpEnvironment,
[in, optional] LPCSTR lpCurrentDirectory,
[in] LPSTARTUPINFOA lpStartupInfo,
[out] LPPROCESS_INFORMATION lpProcessInformation
);The most important parameter is the dwCreationFlags should be set to CREATE_SUSPENDED (0x04)


Identify Image Base address
To get the base address of the image we need to perform the following:
Call NtQueryInformationProcess -> This will return the ProcessInfromation Struct. This struct includes the PEB Address
The base address is stored at offset PEB address + 0x10
We then read the contents of the address at memory PEB+0x10 using ReadProcessMemory.
Let's break that down
Calling NTQueryInfromationProcess
ProcessHandle: This can be obtained from the ProcessInformation returned from the CreateProcess API
ProcessInformationClass: We will set that to ProcessBasicInformation (0x00)
ProcessInfromation: A pointer to the PROCESS_BASIC_INFORMATION structure
ProcessInformationLength: Length of the sturcture
ReturnLength: A pointer to a variable in which the function returns the size of the requested information
The windows package definition of PROCESS_BASIC_STRUCTURE didn't work well in this case so we go ahead and define our own struct.
We now have the address containing the image base address. Since we cannot read it directly we need to use ReadProcessMemory winapi. This API allows us to read the memory of a remote process.
hProcess: This can be obtained from the ProcessInformation returned from the CreateProcess API
lpBaseAddress: Target address, we will use the imageBaseAddress from the previous step.
lpBuffer: We will define a byte slice for the to store the bytes of the remote memory
nSize: Here we will read 8-bytes in the case of a 64-bit process. size(uintptr)
lpNumberOfBytesRead: Returns the size of bytes read in a variable
A quick look in process hacker shows that the base address of the target Process is indeed the one returned by our code.

Identify the Entry Point
MS-DOS Stub: At location 0x3c, the stub has the file offset to the PE signature.
From the offset found at 0x3c we then calculate the size of the different components of PE.
Signature (Image Only): 4-bytes (PE00)
COFF File Header (Object and Image): (2+2+4+4+4+2+2) 20-bytes
Optional Header Standard Fields (Image Only): Offsett to entry point 16-bytes
Offset of AddressOfEntryPoint from the PE-Header address = 4 + 20 + 16 = 40 decimal (0x28)
Let's break that down with some code:
Find PE Signature Address
Let's read the contents of the headers from memory using ReadProcessMemory.
Having a look at PE-Bear we can confirm that the PE Signature Offset is 0x78 is correct.

We now add the 0x28 offset to 0x78 to get the entry point of the executable
Once again we confirm with PE-Bear

Overwrite code with our shellcode
Similar to process injection we now use WriteProcessMemory winapi to write our shellcode to the target region. The benefit is that we don't have to create a new thread but we just overwrite the contents in memory and resume the suspended thread.
WriteProcessMemory winapi will be used to write shellcode to the remote memory
hProcess: This can be obtained from the ProcessInformation returned from the CreateProcess API
lpBaseAddress: entrypointAddress identified in the previous step
lpBuffer: A pointer to the beginning of our shellcode byte array
nSize: Size of our shellcode
lpNumberOfBytesWritten: Ouputs the number of bytes written to the destination address
Resume Execution
To resume execution we only have to resume the suspended thread. The ResumeThread API will be used to achive that.
We simply pass the handle returned by the CreateProcess API.

Complete Code
Last updated
Was this helpful?