From 42441677ed483f24ed65dc86673d2a3ffccbdc5e Mon Sep 17 00:00:00 2001 From: OJ Date: Thu, 21 May 2020 16:40:03 +1000 Subject: [PATCH 1/4] Make things play nice with cross compiling --- dll/src/ReflectiveLoader.c | 19 ++++++++----------- inject/src/GetProcAddressR.c | 2 +- inject/src/LoadLibraryR.c | 5 ++--- 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/dll/src/ReflectiveLoader.c b/dll/src/ReflectiveLoader.c index 4e5c95c..0af2f47 100755 --- a/dll/src/ReflectiveLoader.c +++ b/dll/src/ReflectiveLoader.c @@ -30,14 +30,17 @@ // Our loader will set this to a pseudo correct HINSTANCE/HMODULE value HINSTANCE hAppInstance = NULL; //===============================================================================================// -#ifndef __MINGW32__ +#ifdef __MINGW32__ +#define WIN_GET_CALLER() __builtin_extract_return_addr(__builtin_return_address(0)) +#else #pragma intrinsic(_ReturnAddress) +#define WIN_GET_CALLER() _ReturnAddress() #endif // This function can not be inlined by the compiler or we will not get the address we expect. Ideally // this code will be compiled with the /O2 and /Ob1 switches. Bonus points if we could take advantage of // RIP relative addressing in this instance but I dont believe we can do so with the compiler intrinsics // available (and no inline asm available under x64). -__declspec(noinline) ULONG_PTR caller( VOID ) { return (ULONG_PTR)_ReturnAddress(); } +__declspec(noinline) ULONG_PTR caller( VOID ) { return (ULONG_PTR)WIN_GET_CALLER(); } //===============================================================================================// #ifdef ENABLE_OUTPUTDEBUGSTRING @@ -53,17 +56,11 @@ __declspec(noinline) ULONG_PTR caller( VOID ) { return (ULONG_PTR)_ReturnAddress // otherwise it is assumed you are calling the ReflectiveLoader via a stub. -#ifdef RDIDLL_NOEXPORT -#define RDIDLLEXPORT -#else -#define RDIDLLEXPORT DLLEXPORT -#endif - // This is our position independent reflective DLL loader/injector #ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR -RDIDLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( LPVOID lpParameter ) +DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( LPVOID lpParameter ) #else -RDIDLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( VOID ) +DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( VOID ) #endif { // the functions we need @@ -133,7 +130,7 @@ RDIDLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( VOID ) #else #ifdef WIN_ARM uiBaseAddress = *(DWORD *)( (BYTE *)_MoveFromCoprocessor( 15, 0, 13, 0, 2 ) + 0x30 ); -#else _WIN32 +#else // _WIN32 uiBaseAddress = __readfsdword( 0x30 ); #endif #endif diff --git a/inject/src/GetProcAddressR.c b/inject/src/GetProcAddressR.c index 8718caa..5074d7a 100644 --- a/inject/src/GetProcAddressR.c +++ b/inject/src/GetProcAddressR.c @@ -78,7 +78,7 @@ FARPROC WINAPI GetProcAddressR( HANDLE hModule, LPCSTR lpProcName ) // import by ordinal... // use the import ordinal (- export ordinal base) as an index into the array of addresses - uiAddressArray += ( ( IMAGE_ORDINAL( (DWORD)lpProcName ) - pExportDirectory->Base ) * sizeof(DWORD) ); + uiAddressArray += ( ( IMAGE_ORDINAL( (DWORD)(DWORD_PTR)lpProcName ) - pExportDirectory->Base ) * sizeof(DWORD) ); // resolve the address for this imported function fpResult = (FARPROC)( uiLibraryAddress + DEREF_32(uiAddressArray) ); diff --git a/inject/src/LoadLibraryR.c b/inject/src/LoadLibraryR.c index c2472ea..c7ef1da 100644 --- a/inject/src/LoadLibraryR.c +++ b/inject/src/LoadLibraryR.c @@ -92,7 +92,6 @@ DWORD GetReflectiveLoaderOffset(VOID* lpReflectiveDllBuffer, LPCSTR cpReflective is64 = FALSE; // 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 { @@ -124,7 +123,7 @@ DWORD GetReflectiveLoaderOffset(VOID* lpReflectiveDllBuffer, LPCSTR cpReflective // import by ordinal... // use the import ordinal (- export ordinal base) as an index into the array of addresses - uiAddressArray += ((IMAGE_ORDINAL((DWORD)cpReflectiveLoaderName) - ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->Base) * sizeof(DWORD)); + uiAddressArray += ((IMAGE_ORDINAL((DWORD)(DWORD_PTR)cpReflectiveLoaderName) - ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->Base) * sizeof(DWORD)); // resolve the address for this imported function return Rva2Offset(DEREF_32(uiAddressArray), uiBaseAddress, is64); @@ -253,7 +252,7 @@ HANDLE WINAPI LoadRemoteLibraryR( HANDLE hProcess, LPVOID lpBuffer, DWORD dwLeng lpReflectiveLoader = (LPTHREAD_START_ROUTINE)( (ULONG_PTR)lpRemoteLibraryBuffer + dwReflectiveLoaderOffset ); // create a remote thread in the host process to call the ReflectiveLoader! - hThread = CreateRemoteThread( hProcess, NULL, 1024*1024, lpReflectiveLoader, lpParameter, (DWORD)NULL, &dwThreadId ); + hThread = CreateRemoteThread( hProcess, NULL, 1024*1024, lpReflectiveLoader, lpParameter, (DWORD_PTR)NULL, &dwThreadId ); } while( 0 ); From 7968058d8bf223527f5767f442f161a33101998c Mon Sep 17 00:00:00 2001 From: OJ Date: Fri, 22 May 2020 12:00:13 +1000 Subject: [PATCH 2/4] Handle force exclusion of exports --- dll/src/ReflectiveLoader.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/dll/src/ReflectiveLoader.c b/dll/src/ReflectiveLoader.c index 0af2f47..6d35d60 100755 --- a/dll/src/ReflectiveLoader.c +++ b/dll/src/ReflectiveLoader.c @@ -56,11 +56,17 @@ __declspec(noinline) ULONG_PTR caller( VOID ) { return (ULONG_PTR)WIN_GET_CALLER // otherwise it is assumed you are calling the ReflectiveLoader via a stub. +#ifdef RDIDLL_NOEXPORT +#define RDIDLLEXPORT +#else +#define RDIDLLEXPORT DLLEXPORT +#endif + // This is our position independent reflective DLL loader/injector #ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR -DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( LPVOID lpParameter ) +RDIDLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( LPVOID lpParameter ) #else -DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( VOID ) +RDIDLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( VOID ) #endif { // the functions we need From d0549dfaeb90923168cd916c0d5d27c1936b4ea5 Mon Sep 17 00:00:00 2001 From: OJ Date: Tue, 26 May 2020 15:18:46 +1000 Subject: [PATCH 3/4] Tidy up and handle messed import thunk tables --- dll/src/ReflectiveLoader.c | 49 ++++++++++++-------------------------- dll/src/ReflectiveLoader.h | 34 ++++++++++---------------- 2 files changed, 28 insertions(+), 55 deletions(-) diff --git a/dll/src/ReflectiveLoader.c b/dll/src/ReflectiveLoader.c index 6d35d60..a255739 100755 --- a/dll/src/ReflectiveLoader.c +++ b/dll/src/ReflectiveLoader.c @@ -43,19 +43,12 @@ HINSTANCE hAppInstance = NULL; __declspec(noinline) ULONG_PTR caller( VOID ) { return (ULONG_PTR)WIN_GET_CALLER(); } //===============================================================================================// -#ifdef ENABLE_OUTPUTDEBUGSTRING -#define OUTPUTDBG(str) pOutputDebug((LPCSTR)str) -#else /* ENABLE_OUTPUTDEBUGSTRING */ -#define OUTPUTDBG(str) do{}while(0) -#endif - // Note 1: If you want to have your own DllMain, define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN, // otherwise the DllMain at the end of this file will be used. // Note 2: If you are injecting the DLL via LoadRemoteLibraryR, define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR, // otherwise it is assumed you are calling the ReflectiveLoader via a stub. - #ifdef RDIDLL_NOEXPORT #define RDIDLLEXPORT #else @@ -77,9 +70,6 @@ RDIDLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( VOID ) #ifdef ENABLE_STOPPAGING VIRTUALLOCK pVirtualLock = NULL; #endif -#ifdef ENABLE_OUTPUTDEBUGSTRING - OUTPUTDEBUG pOutputDebug = NULL; -#endif USHORT usCounter; @@ -194,9 +184,6 @@ RDIDLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( VOID ) #ifdef ENABLE_STOPPAGING usCounter++; #endif -#ifdef ENABLE_OUTPUTDEBUGSTRING - usCounter++; -#endif // loop while we still have imports to find while( usCounter > 0 ) @@ -210,9 +197,6 @@ RDIDLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( VOID ) || dwHashValue == VIRTUALALLOC_HASH #ifdef ENABLE_STOPPAGING || dwHashValue == VIRTUALLOCK_HASH -#endif -#ifdef ENABLE_OUTPUTDEBUGSTRING - || dwHashValue == OUTPUTDEBUG_HASH #endif ) { @@ -233,10 +217,6 @@ RDIDLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( VOID ) else if( dwHashValue == VIRTUALLOCK_HASH ) pVirtualLock = (VIRTUALLOCK)( uiBaseAddress + DEREF_32( uiAddressArray ) ); #endif -#ifdef ENABLE_OUTPUTDEBUGSTRING - else if( dwHashValue == OUTPUTDEBUG_HASH ) - pOutputDebug = (OUTPUTDEBUG)( uiBaseAddress + DEREF_32( uiAddressArray ) ); -#endif // decrement our counter usCounter--; @@ -310,9 +290,6 @@ RDIDLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( VOID ) && pVirtualLock #endif && pNtFlushInstructionCache -#ifdef ENABLE_OUTPUTDEBUGSTRING - && pOutputDebug -#endif ) break; @@ -360,6 +337,7 @@ RDIDLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( VOID ) // copy the section over uiValueD = ((PIMAGE_SECTION_HEADER)uiValueA)->SizeOfRawData; + while( uiValueD-- ) *(BYTE *)uiValueB++ = *(BYTE *)uiValueC++; @@ -379,17 +357,11 @@ RDIDLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( VOID ) // iterate through all imports until a null RVA is found (Characteristics is mis-named) while( ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Characteristics ) { - OUTPUTDBG("Loading library: "); - OUTPUTDBG((LPCSTR)(uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name)); - OUTPUTDBG("\n"); - // use LoadLibraryA to load the imported module into memory uiLibraryAddress = (ULONG_PTR)pLoadLibraryA( (LPCSTR)( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name ) ); if ( !uiLibraryAddress ) { - OUTPUTDBG("Loading library FAILED\n"); - uiValueC += sizeof( IMAGE_IMPORT_DESCRIPTOR ); continue; } @@ -403,6 +375,20 @@ RDIDLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( VOID ) // itterate through all imported functions, importing by ordinal if no name present while( DEREF(uiValueA) ) { + // Some compilers/libs like to do silly things like fail to have a terminator at the + // end of the import descriptor thunks that result in import descriptor tables + // running over into those that belong to other libraries. As a result, we end up + // in a situation where resolution of functions in Library 2 are done against + // Library 1. All those calls to GetProcAddress result in NULL, which splats the + // thunk and results in all the IAT entries for that library being set to zero. + // This is what happened with the custom winsta.lib in kiwi when compiling with + // mingw on Linux. INORITE! So here we instead check to make sure that we don't + // bleed into the thunks that belong to the next library. We do this by seeing if + // there is a next lib, and then making sure we don't go past the FirstThunk RVA + uiValueE = uiValueC + sizeof( IMAGE_IMPORT_DESCRIPTOR ); + if( ((PIMAGE_IMPORT_DESCRIPTOR)(uiValueE))->Characteristics && uiValueA >= uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)(uiValueE))->FirstThunk ) + break; + // sanity check uiValueD as some compilers only import by FirstThunk if( uiValueD && ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal & IMAGE_ORDINAL_FLAG ) { @@ -429,10 +415,6 @@ RDIDLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( VOID ) // get the VA of this functions import by name struct uiValueB = ( uiBaseAddress + DEREF(uiValueA) ); - OUTPUTDBG("Resolving function: "); - OUTPUTDBG(((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name); - OUTPUTDBG("\n"); - // use GetProcAddress and patch in the address for this imported function DEREF(uiValueA) = (ULONG_PTR)pGetProcAddress( (HMODULE)uiLibraryAddress, (LPCSTR)((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name ); } @@ -537,7 +519,6 @@ RDIDLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( VOID ) // uiValueA = the VA of our newly loaded DLL/EXE's entry point uiValueA = ( uiBaseAddress + ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.AddressOfEntryPoint ); - OUTPUTDBG("Flushing the instruction cache"); // We must flush the instruction cache to avoid stale code being used which was updated by our relocation processing. pNtFlushInstructionCache( (HANDLE)-1, NULL, 0 ); diff --git a/dll/src/ReflectiveLoader.h b/dll/src/ReflectiveLoader.h index 3940518..c9b1943 100644 --- a/dll/src/ReflectiveLoader.h +++ b/dll/src/ReflectiveLoader.h @@ -35,37 +35,29 @@ #include "ReflectiveDLLInjection.h" -// Enable this define to turn on OutputDebugString support -//#define ENABLE_OUTPUTDEBUGSTRING 1 - // Enable this define to turn on locking of memory to prevent paging -#define ENABLE_STOPPAGING 1 +#define ENABLE_STOPPAGING #define EXITFUNC_SEH 0xEA320EFE #define EXITFUNC_THREAD 0x0A2A1DE0 #define EXITFUNC_PROCESS 0x56A2B5F0 -typedef HMODULE (WINAPI * LOADLIBRARYA)( LPCSTR ); -typedef FARPROC (WINAPI * GETPROCADDRESS)( HMODULE, LPCSTR ); -typedef LPVOID (WINAPI * VIRTUALALLOC)( LPVOID, SIZE_T, DWORD, DWORD ); -typedef DWORD (NTAPI * NTFLUSHINSTRUCTIONCACHE)( HANDLE, PVOID, ULONG ); +typedef HMODULE(WINAPI*LOADLIBRARYA)(LPCSTR); +typedef FARPROC(WINAPI*GETPROCADDRESS)(HMODULE,LPCSTR); +typedef LPVOID(WINAPI*VIRTUALALLOC)(LPVOID,SIZE_T,DWORD,DWORD); +typedef DWORD(NTAPI*NTFLUSHINSTRUCTIONCACHE)(HANDLE,PVOID,ULONG); -#define KERNEL32DLL_HASH 0x6A4ABC5B -#define NTDLLDLL_HASH 0x3CFA685D +#define KERNEL32DLL_HASH 0x6A4ABC5B +#define NTDLLDLL_HASH 0x3CFA685D -#define LOADLIBRARYA_HASH 0xEC0E4E8E -#define GETPROCADDRESS_HASH 0x7C0DFCAA -#define VIRTUALALLOC_HASH 0x91AFCA54 -#define NTFLUSHINSTRUCTIONCACHE_HASH 0x534C0AB8 +#define LOADLIBRARYA_HASH 0xEC0E4E8E +#define GETPROCADDRESS_HASH 0x7C0DFCAA +#define VIRTUALALLOC_HASH 0x91AFCA54 +#define NTFLUSHINSTRUCTIONCACHE_HASH 0x534C0AB8 #ifdef ENABLE_STOPPAGING -typedef LPVOID (WINAPI * VIRTUALLOCK)( LPVOID, SIZE_T ); -#define VIRTUALLOCK_HASH 0x0EF632F2 -#endif - -#ifdef ENABLE_OUTPUTDEBUGSTRING -typedef LPVOID (WINAPI * OUTPUTDEBUG)( LPCSTR ); -#define OUTPUTDEBUG_HASH 0x470D22BC +typedef LPVOID(WINAPI*VIRTUALLOCK)(LPVOID,SIZE_T); +#define VIRTUALLOCK_HASH 0x0EF632F2 #endif #define IMAGE_REL_BASED_ARM_MOV32A 5 From a7f0656082ee3786dc17fd99fa249c9dec6937e5 Mon Sep 17 00:00:00 2001 From: OJ Date: Mon, 6 Jul 2020 07:39:40 +1000 Subject: [PATCH 4/4] Remove code that detects overlapping import tables So what's interesting about this is that not only does this now seem to be causing issues with the Windows Meterpreter built on Windows with VS, but it appears to no longer be an issue on the mingw builds! I am so confused. --- dll/src/ReflectiveLoader.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/dll/src/ReflectiveLoader.c b/dll/src/ReflectiveLoader.c index a255739..b5b5692 100755 --- a/dll/src/ReflectiveLoader.c +++ b/dll/src/ReflectiveLoader.c @@ -375,20 +375,6 @@ RDIDLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( VOID ) // itterate through all imported functions, importing by ordinal if no name present while( DEREF(uiValueA) ) { - // Some compilers/libs like to do silly things like fail to have a terminator at the - // end of the import descriptor thunks that result in import descriptor tables - // running over into those that belong to other libraries. As a result, we end up - // in a situation where resolution of functions in Library 2 are done against - // Library 1. All those calls to GetProcAddress result in NULL, which splats the - // thunk and results in all the IAT entries for that library being set to zero. - // This is what happened with the custom winsta.lib in kiwi when compiling with - // mingw on Linux. INORITE! So here we instead check to make sure that we don't - // bleed into the thunks that belong to the next library. We do this by seeing if - // there is a next lib, and then making sure we don't go past the FirstThunk RVA - uiValueE = uiValueC + sizeof( IMAGE_IMPORT_DESCRIPTOR ); - if( ((PIMAGE_IMPORT_DESCRIPTOR)(uiValueE))->Characteristics && uiValueA >= uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)(uiValueE))->FirstThunk ) - break; - // sanity check uiValueD as some compilers only import by FirstThunk if( uiValueD && ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal & IMAGE_ORDINAL_FLAG ) {