Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
667 lines (563 sloc) 25.1 KB
// Copyright (c) 2015, Dan Staples
//===============================================================================================//
// Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted
// provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice, this list of
// conditions and the following disclaimer in the documentation and/or other materials provided
// with the distribution.
//
// * Neither the name of Harmony Security nor the names of its contributors may be used to
// endorse or promote products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//===============================================================================================//
#include "LoadLibraryR.h"
#include <stdio.h>
#include <malloc.h>
//===============================================================================================//
enum {
PROC_WIN_UNKNOWN,
PROC_WIN_X86,
PROC_WIN_X64
};
/**
Copyright (c) 2006-2013, Rapid7 Inc
Redistribution and use in source and binary forms, with or without modification, are
permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of
conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of
conditions and the following disclaimer in the documentation and/or other materials
provided with the distribution.
* Neither the name of Rapid7 nor the names of its contributors may be used to endorse or
promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
typedef BOOL (WINAPI * ISWOW64PROCESS)( HANDLE hProcess, PBOOL Wow64Process );
typedef void (WINAPI * GETNATIVESYSTEMINFO)( LPSYSTEM_INFO lpSystemInfo );
// Definitions used for running native x64 code from a wow64 process (see executex64.asm)
typedef BOOL (WINAPI * X64FUNCTION)(DWORD dwParameter);
typedef DWORD(WINAPI * EXECUTEX64)(X64FUNCTION pFunction, DWORD dwParameter);
// The context used for injection via migrate_via_remotethread_wow64
typedef struct _WOW64CONTEXT
{
union
{
HANDLE hProcess;
BYTE bPadding2[8];
} h;
union
{
LPVOID lpStartAddress;
BYTE bPadding1[8];
} s;
union
{
LPVOID lpParameter;
BYTE bPadding2[8];
} p;
union
{
HANDLE hThread;
BYTE bPadding2[8];
} t;
} WOW64CONTEXT, *LPWOW64CONTEXT;
// see '/msf3/external/source/shellcode/x86/migrate/executex64.asm'
static BYTE migrate_executex64[] = "\x55\x89\xE5\x56\x57\x8B\x75\x08\x8B\x4D\x0C\xE8\x00\x00\x00\x00"
"\x58\x83\xC0\x25\x83\xEC\x08\x89\xE2\xC7\x42\x04\x33\x00\x00\x00"
"\x89\x02\xE8\x09\x00\x00\x00\x83\xC4\x14\x5F\x5E\x5D\xC2\x08\x00"
"\x8B\x3C\x24\xFF\x2A\x48\x31\xC0\x57\xFF\xD6\x5F\x50\xC7\x44\x24"
"\x04\x23\x00\x00\x00\x89\x3C\x24\xFF\x2C\x24";
// see '/msf3/external/source/shellcode/x64/migrate/remotethread.asm'
static BYTE migrate_wownativex[] = "\xFC\x48\x89\xCE\x48\x89\xE7\x48\x83\xE4\xF0\xE8\xC8\x00\x00\x00"
"\x41\x51\x41\x50\x52\x51\x56\x48\x31\xD2\x65\x48\x8B\x52\x60\x48"
"\x8B\x52\x18\x48\x8B\x52\x20\x48\x8B\x72\x50\x48\x0F\xB7\x4A\x4A"
"\x4D\x31\xC9\x48\x31\xC0\xAC\x3C\x61\x7C\x02\x2C\x20\x41\xC1\xC9"
"\x0D\x41\x01\xC1\xE2\xED\x52\x41\x51\x48\x8B\x52\x20\x8B\x42\x3C"
"\x48\x01\xD0\x66\x81\x78\x18\x0B\x02\x75\x72\x8B\x80\x88\x00\x00"
"\x00\x48\x85\xC0\x74\x67\x48\x01\xD0\x50\x8B\x48\x18\x44\x8B\x40"
"\x20\x49\x01\xD0\xE3\x56\x48\xFF\xC9\x41\x8B\x34\x88\x48\x01\xD6"
"\x4D\x31\xC9\x48\x31\xC0\xAC\x41\xC1\xC9\x0D\x41\x01\xC1\x38\xE0"
"\x75\xF1\x4C\x03\x4C\x24\x08\x45\x39\xD1\x75\xD8\x58\x44\x8B\x40"
"\x24\x49\x01\xD0\x66\x41\x8B\x0C\x48\x44\x8B\x40\x1C\x49\x01\xD0"
"\x41\x8B\x04\x88\x48\x01\xD0\x41\x58\x41\x58\x5E\x59\x5A\x41\x58"
"\x41\x59\x41\x5A\x48\x83\xEC\x20\x41\x52\xFF\xE0\x58\x41\x59\x5A"
"\x48\x8B\x12\xE9\x4F\xFF\xFF\xFF\x5D\x4D\x31\xC9\x41\x51\x48\x8D"
"\x46\x18\x50\xFF\x76\x10\xFF\x76\x08\x41\x51\x41\x51\x49\xB8\x01"
"\x00\x00\x00\x00\x00\x00\x00\x48\x31\xD2\x48\x8B\x0E\x41\xBA\xC8"
"\x38\xA4\x40\xFF\xD5\x48\x85\xC0\x74\x0C\x48\xB8\x00\x00\x00\x00"
"\x00\x00\x00\x00\xEB\x0A\x48\xB8\x01\x00\x00\x00\x00\x00\x00\x00"
"\x48\x83\xC4\x50\x48\x89\xFC\xC3";
DWORD Rva2Offset( DWORD dwRva, UINT_PTR uiBaseAddress )
{
WORD wIndex = 0;
WORD wNumberOfSections = 0;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)(uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew);
if (pNtHeaders->OptionalHeader.Magic == 0x010B) // PE32
{
PIMAGE_NT_HEADERS32 pNtHeaders32 = (PIMAGE_NT_HEADERS32)pNtHeaders;
pSectionHeader = (PIMAGE_SECTION_HEADER)((UINT_PTR)(&pNtHeaders32->OptionalHeader) + pNtHeaders32->FileHeader.SizeOfOptionalHeader);
wNumberOfSections = pNtHeaders32->FileHeader.NumberOfSections;
}
else if (pNtHeaders->OptionalHeader.Magic == 0x020B) // PE64
{
PIMAGE_NT_HEADERS64 pNtHeaders64 = (PIMAGE_NT_HEADERS64)pNtHeaders;
pSectionHeader = (PIMAGE_SECTION_HEADER)((UINT_PTR)(&pNtHeaders64->OptionalHeader) + pNtHeaders64->FileHeader.SizeOfOptionalHeader);
wNumberOfSections = pNtHeaders64->FileHeader.NumberOfSections;
}
else
{
return 0;
}
if( dwRva < pSectionHeader[0].PointerToRawData )
return dwRva;
for (wIndex = 0; wIndex < wNumberOfSections; wIndex++)
{
if( dwRva >= pSectionHeader[wIndex].VirtualAddress && dwRva < (pSectionHeader[wIndex].VirtualAddress + pSectionHeader[wIndex].SizeOfRawData) )
return ( dwRva - pSectionHeader[wIndex].VirtualAddress + pSectionHeader[wIndex].PointerToRawData );
}
return 0;
}
//===============================================================================================//
DWORD GetReflectiveLoaderOffset( VOID * lpReflectiveDllBuffer )
{
UINT_PTR uiBaseAddress = 0;
UINT_PTR uiExportDir = 0;
UINT_PTR uiNameArray = 0;
UINT_PTR uiAddressArray = 0;
UINT_PTR uiNameOrdinals = 0;
DWORD dwCounter = 0;
uiBaseAddress = (UINT_PTR)lpReflectiveDllBuffer;
// get the File Offset of the modules NT Header
uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew;
if( ((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.Magic == 0x010B ) // PE32
{
// uiNameArray = the address of the modules export directory entry
uiNameArray = (UINT_PTR)&((PIMAGE_NT_HEADERS32)uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
}
else if( ((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.Magic == 0x020B ) // PE64
{
// uiNameArray = the address of the modules export directory entry
uiNameArray = (UINT_PTR)&((PIMAGE_NT_HEADERS64)uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
}
else
{
return 0;
}
// get the File Offset of the export directory
uiExportDir = uiBaseAddress + Rva2Offset( ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress, uiBaseAddress );
// get the File Offset for the array of name pointers
uiNameArray = uiBaseAddress + Rva2Offset( ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNames, uiBaseAddress );
// get the File Offset for the array of addresses
uiAddressArray = uiBaseAddress + Rva2Offset( ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions, uiBaseAddress );
// get the File Offset for the array of name ordinals
uiNameOrdinals = uiBaseAddress + Rva2Offset( ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNameOrdinals, uiBaseAddress );
// get a counter for the number of exported functions...
dwCounter = ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->NumberOfNames;
// loop through all the exported functions to find the ReflectiveLoader
while( dwCounter-- )
{
char * cpExportedFunctionName = (char *)(uiBaseAddress + Rva2Offset( DEREF_32( uiNameArray ), uiBaseAddress ));
if( strstr( cpExportedFunctionName, "ReflectiveLoader" ) != NULL )
{
// get the File Offset for the array of addresses
uiAddressArray = uiBaseAddress + Rva2Offset( ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions, uiBaseAddress );
// use the functions name ordinal as an index into the array of name pointers
uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) );
// return the File Offset to the ReflectiveLoader() functions code...
return Rva2Offset( DEREF_32( uiAddressArray ), uiBaseAddress );
}
// get the next exported function name
uiNameArray += sizeof(DWORD);
// get the next exported function name ordinal
uiNameOrdinals += sizeof(WORD);
}
return 0;
}
//===============================================================================================//
// Loads a DLL image from memory via its exported ReflectiveLoader function
HMODULE WINAPI LoadLibraryR( LPVOID lpBuffer, DWORD dwLength )
{
HMODULE hResult = NULL;
DWORD dwReflectiveLoaderOffset = 0;
DWORD dwOldProtect1 = 0;
DWORD dwOldProtect2 = 0;
REFLECTIVELOADER pReflectiveLoader = NULL;
DLLMAIN pDllMain = NULL;
if( lpBuffer == NULL || dwLength == 0 )
return NULL;
__try
{
// check if the library has a ReflectiveLoader...
dwReflectiveLoaderOffset = GetReflectiveLoaderOffset( lpBuffer );
if( dwReflectiveLoaderOffset != 0 )
{
pReflectiveLoader = (REFLECTIVELOADER)((UINT_PTR)lpBuffer + dwReflectiveLoaderOffset);
// we must VirtualProtect the buffer to RWX so we can execute the ReflectiveLoader...
// this assumes lpBuffer is the base address of the region of pages and dwLength the size of the region
if( VirtualProtect( lpBuffer, dwLength, PAGE_EXECUTE_READWRITE, &dwOldProtect1 ) )
{
// call the librarys ReflectiveLoader...
pDllMain = (DLLMAIN)pReflectiveLoader();
if( pDllMain != NULL )
{
// call the loaded librarys DllMain to get its HMODULE
if( !pDllMain( NULL, DLL_QUERY_HMODULE, &hResult ) )
hResult = NULL;
}
// revert to the previous protection flags...
VirtualProtect( lpBuffer, dwLength, dwOldProtect1, &dwOldProtect2 );
}
}
}
__except( EXCEPTION_EXECUTE_HANDLER )
{
hResult = NULL;
}
return hResult;
}
//===============================================================================================//
/*
* see 'meterpreter/source/common/arch/win/i386/base_inject.c'
* Attempt to gain code execution in a native x64 process from a wow64 process by transitioning out of the wow64 (x86)
* enviroment into a native x64 enviroment and accessing the native win64 API's.
* Note: On Windows 2003 the injection will work but in the target x64 process issues occur with new
* threads (kernel32!CreateThread will return ERROR_NOT_ENOUGH_MEMORY). Because of this we filter out
* Windows 2003 from this method of injection, however the APC injection method will work on 2003.
*/
DWORD inject_via_remotethread_wow64(HANDLE hProcess, LPVOID lpStartAddress, LPVOID lpParameter, HANDLE * pThread)
{
DWORD dwResult = ERROR_SUCCESS;
EXECUTEX64 pExecuteX64 = NULL;
X64FUNCTION pX64function = NULL;
WOW64CONTEXT * ctx = NULL;
OSVERSIONINFO os = { 0 };
do
{
os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if (!GetVersionEx(&os))
BREAK_WITH_ERROR("[INJECT] inject_via_remotethread_wow64: GetVersionEx failed")
// filter out Windows 2003
if (os.dwMajorVersion == 5 && os.dwMinorVersion == 2)
{
SetLastError(ERROR_ACCESS_DENIED);
BREAK_WITH_ERROR("[INJECT] inject_via_remotethread_wow64: Windows 2003 not supported.")
}
// alloc a RWX buffer in this process for the EXECUTEX64 function
pExecuteX64 = (EXECUTEX64)VirtualAlloc(NULL, sizeof(migrate_executex64), MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (!pExecuteX64)
BREAK_WITH_ERROR("[INJECT] inject_via_remotethread_wow64: VirtualAlloc pExecuteX64 failed")
// alloc a RWX buffer in this process for the X64FUNCTION function (and its context)
pX64function = (X64FUNCTION)VirtualAlloc(NULL, sizeof(migrate_wownativex) + sizeof(WOW64CONTEXT), MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (!pX64function)
BREAK_WITH_ERROR("[INJECT] inject_via_remotethread_wow64: VirtualAlloc pX64function failed")
// copy over the wow64->x64 stub
memcpy(pExecuteX64, &migrate_executex64, sizeof(migrate_executex64));
// copy over the native x64 function
memcpy(pX64function, &migrate_wownativex, sizeof(migrate_wownativex));
// set the context
ctx = (WOW64CONTEXT *)((BYTE *)pX64function + sizeof(migrate_wownativex));
ctx->h.hProcess = hProcess;
ctx->s.lpStartAddress = lpStartAddress;
ctx->p.lpParameter = lpParameter;
ctx->t.hThread = NULL;
printf("[INJECT] inject_via_remotethread_wow64: pExecuteX64=0x%08p, pX64function=0x%08p, ctx=0x%08p", pExecuteX64, pX64function, ctx);
// Transition this wow64 process into native x64 and call pX64function( ctx )
// The native function will use the native Win64 API's to create a remote thread in the target process.
if (!pExecuteX64(pX64function, (DWORD)ctx))
{
SetLastError(ERROR_ACCESS_DENIED);
BREAK_WITH_ERROR("[INJECT] inject_via_remotethread_wow64: pExecuteX64( pX64function, ctx ) failed")
}
if (!ctx->t.hThread)
{
SetLastError(ERROR_INVALID_HANDLE);
BREAK_WITH_ERROR("[INJECT] inject_via_remotethread_wow64: ctx->t.hThread is NULL")
}
// Success! grab the new thread handle from of the context
*pThread = ctx->t.hThread;
printf("[INJECT] inject_via_remotethread_wow64: Success, hThread=0x%08p", ctx->t.hThread);
} while (0);
if (pExecuteX64)
VirtualFree(pExecuteX64, 0, MEM_RELEASE);
if (pX64function)
VirtualFree(pX64function, 0, MEM_RELEASE);
return dwResult;
}
//===============================================================================================//
static DWORD CreateBootstrap(
LPBYTE lpBuffer,
DWORD nBufferLen,
DWORD dwTargetArch,
ULONG_PTR uiParameter,
ULONG_PTR uiLibraryAddress,
DWORD dwFunctionHash,
ULONG_PTR uiUserdataAddr,
DWORD nUserdataLen,
ULONG_PTR uiReflectiveLoaderAddr)
{
DWORD i = 0;
if (nBufferLen < 64)
return 0;
#if defined(WIN_X86)
DWORD dwCurrentArch = PROC_WIN_X86;
#elif defined(WIN_X64)
DWORD dwCurrentArch = PROC_WIN_X64;
#else
#error Unsupported architecture
#endif
/*
Shellcode pseudo-code:
ReflectiveLoader(lpParameter, lpLibraryAddress, dwFunctionHash, lpUserData, nUserdataLen);
*/
// debugging (will cause infinite loop; step over in debugger)
//lpBuffer[i++] = 0xEB;
//lpBuffer[i++] = 0xFE;
if (dwTargetArch == PROC_WIN_X86) {
// push <size of userdata>
lpBuffer[i++] = 0x68; // PUSH (word/dword)
MoveMemory(lpBuffer + i, &nUserdataLen, sizeof(DWORD));
i += sizeof(DWORD);
// push <address of userdata>
lpBuffer[i++] = 0x68; // PUSH (word/dword)
MoveMemory(lpBuffer + i, &uiUserdataAddr, sizeof(DWORD));
i += sizeof(DWORD);
// push <hash of function>
lpBuffer[i++] = 0x68; // PUSH (word/dword)
MoveMemory(lpBuffer + i, &dwFunctionHash, sizeof(DWORD));
i += sizeof(DWORD);
// push <address of image base>
lpBuffer[i++] = 0x68; // PUSH (word/dword)
MoveMemory(lpBuffer + i, &uiLibraryAddress, sizeof(DWORD));
i += sizeof(DWORD);
// push <lpParameter>
lpBuffer[i++] = 0x68; // PUSH (word/dword)
MoveMemory(lpBuffer + i, &uiParameter, sizeof(DWORD));
i += sizeof(DWORD);
// mov eax, <address of reflective loader>
lpBuffer[i++] = 0xB8; // MOV EAX (word/dword)
MoveMemory(lpBuffer + i, &uiReflectiveLoaderAddr, sizeof(DWORD));
i += sizeof(DWORD);
// call eax
lpBuffer[i++] = 0xFF; // CALL
lpBuffer[i++] = 0xD0; // EAX
}
else if (dwTargetArch == PROC_WIN_X64) {
if (dwCurrentArch == PROC_WIN_X86) {
// mov rcx, <lpParameter>
MoveMemory(lpBuffer + i, "\x48\xc7\xc1", 3);
i += 3;
MoveMemory(lpBuffer + i, &uiParameter, sizeof(uiParameter));
i += sizeof(uiParameter);
// mov rdx, <address of image base>
MoveMemory(lpBuffer + i, "\x48\xc7\xc2", 3);
i += 3;
MoveMemory(lpBuffer + i, &uiLibraryAddress, sizeof(uiLibraryAddress));
i += sizeof(uiLibraryAddress);
// mov r8d, <hash of function>
MoveMemory(lpBuffer + i, "\x41\xb8", 2);
i += 2;
MoveMemory(lpBuffer + i, &dwFunctionHash, sizeof(dwFunctionHash));
i += sizeof(dwFunctionHash);
// mov r9, <address of userdata>
MoveMemory(lpBuffer + i, "\x49\xc7\xc1", 3);
i += 3;
MoveMemory(lpBuffer + i, &uiUserdataAddr, sizeof(uiUserdataAddr));
i += sizeof(uiUserdataAddr);
// push <size of userdata>
lpBuffer[i++] = 0x68; // PUSH (word/dword)
MoveMemory(lpBuffer + i, &nUserdataLen, sizeof(nUserdataLen));
i += sizeof(nUserdataLen);
// sub rsp, 20
MoveMemory(lpBuffer + i, "\x48\x83\xec\x20", 4);
i += 4;
// move rax, <address of reflective loader>
MoveMemory(lpBuffer + i, "\x48\xc7\xc0", 3);
i += 3;
MoveMemory(lpBuffer + i, &uiReflectiveLoaderAddr, sizeof(uiReflectiveLoaderAddr));
i += sizeof(uiReflectiveLoaderAddr);
}
else {
// mov rcx, <lpParameter>
MoveMemory(lpBuffer + i, "\x48\xb9", 2);
i += 2;
MoveMemory(lpBuffer + i, &uiParameter, sizeof(uiParameter));
i += sizeof(uiParameter);
// mov rdx, <address of image base>
MoveMemory(lpBuffer + i, "\x48\xba", 2);
i += 2;
MoveMemory(lpBuffer + i, &uiLibraryAddress, sizeof(uiLibraryAddress));
i += sizeof(uiLibraryAddress);
// mov r8d, <hash of function>
MoveMemory(lpBuffer + i, "\x41\xb8", 2);
i += 2;
MoveMemory(lpBuffer + i, &dwFunctionHash, sizeof(dwFunctionHash));
i += sizeof(dwFunctionHash);
// mov r9, <address of userdata>
MoveMemory(lpBuffer + i, "\x49\xb9", 2);
i += 2;
MoveMemory(lpBuffer + i, &uiUserdataAddr, sizeof(uiUserdataAddr));
i += sizeof(uiUserdataAddr);
// push <size of userdata>
lpBuffer[i++] = 0x68; // PUSH (word/dword)
MoveMemory(lpBuffer + i, &nUserdataLen, sizeof(nUserdataLen));
i += sizeof(nUserdataLen);
// sub rsp, 20
MoveMemory(lpBuffer + i, "\x48\x83\xec\x20", 4);
i += 4;
// move rax, <address of reflective loader>
MoveMemory(lpBuffer + i, "\x48\xb8", 2);
i += 2;
MoveMemory(lpBuffer + i, &uiReflectiveLoaderAddr, sizeof(uiReflectiveLoaderAddr));
i += sizeof(uiReflectiveLoaderAddr);
}
// call rax
lpBuffer[i++] = 0xFF; // CALL
lpBuffer[i++] = 0xD0; // RAX
}
return i;
}
//===============================================================================================//
// Loads a PE image from memory into the address space of a host process via the image's exported ReflectiveLoader function
// Note: The hProcess handle must have these access rights: PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION |
// PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ
// Note: If you are passing in an lpParameter value, if it is a pointer, remember it is for a different address space.
HANDLE WINAPI LoadRemoteLibraryR(
HANDLE hProcess,
LPVOID lpBuffer,
DWORD dwLength,
LPVOID lpParameter,
DWORD dwFunctionHash,
LPVOID lpUserdata,
DWORD nUserdataLen )
{
HANDLE hThread = NULL;
DWORD dwThreadId = 0;
DWORD dwTargetArch = PROC_WIN_X86; // default, in case IsWow64Process not present
DWORD dwDllArch = PROC_WIN_UNKNOWN;
#if defined(WIN_X86)
DWORD dwCurrentArch = PROC_WIN_X86;
#elif defined(WIN_X64)
DWORD dwCurrentArch = PROC_WIN_X64;
#else
#error Unsupported architecture
#endif
__try
{
do
{
if (!hProcess || !lpBuffer || !dwLength)
break;
// get architecture of target process
HANDLE hKernel = LoadLibraryA("kernel32.dll");
if (!hKernel)
break;
ISWOW64PROCESS pIsWow64Process = (ISWOW64PROCESS)GetProcAddress(hKernel, "IsWow64Process");
FreeLibrary(hKernel);
if (pIsWow64Process) {
BOOL bIsWow64;
if (!pIsWow64Process(hProcess, &bIsWow64))
break;
if (bIsWow64)
dwTargetArch = PROC_WIN_X86;
else {
SYSTEM_INFO SystemInfo = { 0 };
GetNativeSystemInfo(&SystemInfo);
if (SystemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
dwTargetArch = PROC_WIN_X64;
else if (SystemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
dwTargetArch = PROC_WIN_X86;
else
break;
}
}
// get architecture of DLL we're injecting
PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)(((UINT_PTR)lpBuffer) + ((PIMAGE_DOS_HEADER)lpBuffer)->e_lfanew);
if (pNtHeader->OptionalHeader.Magic == 0x010B) // PE32
dwDllArch = PROC_WIN_X86;
else if (pNtHeader->OptionalHeader.Magic == 0x020B) // PE64
dwDllArch = PROC_WIN_X64;
// DLL and target process must be same architecture
if (dwDllArch != dwTargetArch)
BREAK_WITH_ERROR("DLL and target process must be same architecture");
// check if the library has a ReflectiveLoader...
DWORD dwReflectiveLoaderOffset = GetReflectiveLoaderOffset(lpBuffer);
if (!dwReflectiveLoaderOffset)
BREAK_WITH_ERROR("Could not get reflective loader offset");
DWORD nBufferSize = dwLength
+ nUserdataLen
+ 64; // shellcode buffer
// alloc memory (RWX) in the host process for the image...
LPVOID lpRemoteLibraryBuffer = VirtualAllocEx(hProcess, NULL, nBufferSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (!lpRemoteLibraryBuffer)
break;
printf("Allocated memory address in remote process: 0x%p\n", lpRemoteLibraryBuffer);
// write the image into the host process...
if (!WriteProcessMemory(hProcess, lpRemoteLibraryBuffer, lpBuffer, dwLength, NULL))
break;
ULONG_PTR uiReflectiveLoaderAddr = (ULONG_PTR)lpRemoteLibraryBuffer + dwReflectiveLoaderOffset;
// write our userdata blob into the host process
ULONG_PTR userdataAddr = (ULONG_PTR)lpRemoteLibraryBuffer + dwLength;
if (!WriteProcessMemory(hProcess, (LPVOID)userdataAddr, lpUserdata, nUserdataLen, NULL))
break;
ULONG_PTR uiShellcodeAddr = userdataAddr + nUserdataLen;
BYTE bootstrap[64] = { 0 };
DWORD bootstrapLen = CreateBootstrap(
bootstrap,
64,
dwTargetArch,
(ULONG_PTR)lpParameter,
(ULONG_PTR)lpRemoteLibraryBuffer,
dwFunctionHash,
userdataAddr,
nUserdataLen,
uiReflectiveLoaderAddr);
if (bootstrapLen <= 0)
break;
// finally, write our shellcode into the host process
if (!WriteProcessMemory(hProcess, (LPVOID)uiShellcodeAddr, bootstrap, bootstrapLen, NULL))
break;
printf("Wrote shellcode to 0x%x\n", uiShellcodeAddr);
// Make sure our changes are written right away
FlushInstructionCache(hProcess, lpRemoteLibraryBuffer, nBufferSize);
// create a remote thread in the host process to call the ReflectiveLoader!
if (dwCurrentArch == PROC_WIN_X86 && dwTargetArch == PROC_WIN_X64) {
inject_via_remotethread_wow64(hProcess, (LPVOID)uiShellcodeAddr, lpParameter, &hThread);
ResumeThread(hThread);
}
else {
hThread = CreateRemoteThread(hProcess, NULL, 1024 * 1024, (LPTHREAD_START_ROUTINE)uiShellcodeAddr, lpParameter, (DWORD)NULL, &dwThreadId);
}
} while( 0 );
}
__except( EXCEPTION_EXECUTE_HANDLER )
{
hThread = NULL;
}
return hThread;
}
//===============================================================================================//