From c8808cc71b77d86f9a6e61a36b7e0b9bde4795a4 Mon Sep 17 00:00:00 2001 From: userexistserror Date: Wed, 28 Oct 2020 14:49:01 -0700 Subject: [PATCH] added support for calling an export by ordinal. see TestExe.cpp for usage. updated to VS2019 toolset --- Extract/Extract.vcxproj | 10 +++++----- Loader/Loader.vcxproj | 10 +++++----- Loader/ReflectiveLoader.cpp | 21 +++++++++++++++++++- Loader/ReflectiveLoader.h | 4 ++++ TestDll/TestDll.vcxproj | 17 ++++++++++++----- TestDll/TestDll.vcxproj.filters | 5 +++++ TestDll/dllmain.cpp | 10 ++++++++++ TestDll/exports.def | 4 ++++ TestExe/TestExe.cpp | 34 ++++++++++++++++++++++++++++++++- TestExe/TestExe.vcxproj | 14 +++++++++----- 10 files changed, 107 insertions(+), 22 deletions(-) create mode 100644 TestDll/exports.def diff --git a/Extract/Extract.vcxproj b/Extract/Extract.vcxproj index a2d3df0..dc5805e 100644 --- a/Extract/Extract.vcxproj +++ b/Extract/Extract.vcxproj @@ -23,34 +23,34 @@ {5FAFD59C-F4C9-4769-B5B0-588081871DF9} Win32Proj Extract - 8.1 + 10.0 Application true - v141 Unicode + v142 Application false - v141 true Unicode + v142 Application true - v141 Unicode + v142 Application false - v141 true Unicode + v142 diff --git a/Loader/Loader.vcxproj b/Loader/Loader.vcxproj index 0fcbbfb..9aad61a 100644 --- a/Loader/Loader.vcxproj +++ b/Loader/Loader.vcxproj @@ -29,34 +29,34 @@ {CAD8730E-B27E-4347-BF50-8742E94DB707} Win32Proj Loader - 8.1 + 10.0 Application true - v141 Unicode + v142 Application false - v141 true Unicode + v142 Application true - v141 Unicode + v142 Application false - v141 true Unicode + v142 diff --git a/Loader/ReflectiveLoader.cpp b/Loader/ReflectiveLoader.cpp index c9a2f51..42898af 100644 --- a/Loader/ReflectiveLoader.cpp +++ b/Loader/ReflectiveLoader.cpp @@ -380,7 +380,7 @@ extern "C" ULONG_PTR WINAPI ReflectiveLoader( VOID ) // uiValueA = VA of the IAT (via first thunk not origionalfirstthunk) uiValueA = ( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->FirstThunk ); - // itterate through all imported functions, importing by ordinal if no name present + // iterate through all imported functions, importing by ordinal if no name present while( DEREF(uiValueA) ) { // sanity check uiValueD as some compilers only import by FirstThunk @@ -524,6 +524,25 @@ extern "C" ULONG_PTR WINAPI ReflectiveLoader( VOID ) // if we are injecting an DLL via a stub we call DllMain with no parameter ((DLLMAIN)uiValueA)( (HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, NULL ); + // STEP 7: call export by ordinal +#ifdef ENABLE_EXPORT_INVOKE + const volatile DWORD ordinalToInvoke = ORDINAL_PLACEHOLDER; + if (ordinalToInvoke > 0) { + uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; + uiNameArray = (ULONG_PTR) & ((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; + uiExportDir = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress); + uiAddressArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions); + + if (ordinalToInvoke <= ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->NumberOfFunctions) { + uiValueB = uiAddressArray + ((ordinalToInvoke - 1) * sizeof(DWORD)); + if (DEREF_32(uiValueB)) { // make sure ordinal is valid + uiValueC = uiBaseAddress + DEREF_32(uiValueB); + ((FARPROC)uiValueC)(); + } + } + } +#endif + // STEP 8: return our new entry point address so whatever called us can call DllMain() if needed. return uiValueA; } diff --git a/Loader/ReflectiveLoader.h b/Loader/ReflectiveLoader.h index a8cefe0..6deafb2 100644 --- a/Loader/ReflectiveLoader.h +++ b/Loader/ReflectiveLoader.h @@ -31,6 +31,10 @@ #include #include +// placeholder. replace in generated shellcode with ordinal to invoke +#define ORDINAL_PLACEHOLDER 0xabcdefff // value should be an invalid ordinal (> 65535) +#define ENABLE_EXPORT_INVOKE 1 // define to enable calling an export by ordinal after calling the entrypoint + ////#include "ReflectiveDLLInjection.h" #define DLL_QUERY_HMODULE 6 diff --git a/TestDll/TestDll.vcxproj b/TestDll/TestDll.vcxproj index 7d5a3d7..2da0d14 100644 --- a/TestDll/TestDll.vcxproj +++ b/TestDll/TestDll.vcxproj @@ -23,34 +23,34 @@ {6863D770-09C5-4F46-8BC3-63E933694815} Win32Proj TestDll - 8.1 + 10.0 DynamicLibrary true - v141 Unicode + v142 DynamicLibrary false - v141 true Unicode + v142 DynamicLibrary true - v141 Unicode + v142 DynamicLibrary false - v141 true Unicode + v142 @@ -106,6 +106,7 @@ true true true + exports.def copy /b "$(SolutionDir)loader.$(PlatformTarget).bin"+"$(SolutionDir)$(PlatformTarget)\$(Configuration)\$(TargetName).dll" "$(SolutionDir)$(TargetName)\$(TargetName).$(PlatformTarget).$(Configuration).bin" @@ -123,6 +124,7 @@ Windows true + exports.def copy /b "$(SolutionDir)loader.$(PlatformTarget).bin"+"$(SolutionDir)$(PlatformTarget)\$(Configuration)\$(TargetName).dll" "$(SolutionDir)$(TargetName)\$(TargetName).$(PlatformTarget).$(Configuration).bin" @@ -140,6 +142,7 @@ Windows true + exports.def copy /b "$(SolutionDir)loader.$(PlatformTarget).bin"+"$(SolutionDir)$(PlatformTarget)\$(Configuration)\$(TargetName).dll" "$(SolutionDir)$(TargetName)\$(TargetName).$(PlatformTarget).$(Configuration).bin" @@ -161,6 +164,7 @@ true true true + exports.def copy /b "$(SolutionDir)loader.$(PlatformTarget).bin"+"$(SolutionDir)$(PlatformTarget)\$(Configuration)\$(TargetName).dll" "$(SolutionDir)$(TargetName)\$(TargetName).$(PlatformTarget).$(Configuration).bin" @@ -169,6 +173,9 @@ + + + diff --git a/TestDll/TestDll.vcxproj.filters b/TestDll/TestDll.vcxproj.filters index fd6c32e..0fdaa21 100644 --- a/TestDll/TestDll.vcxproj.filters +++ b/TestDll/TestDll.vcxproj.filters @@ -19,4 +19,9 @@ Source Files + + + Source Files + + \ No newline at end of file diff --git a/TestDll/dllmain.cpp b/TestDll/dllmain.cpp index 917a89a..aefb5fd 100644 --- a/TestDll/dllmain.cpp +++ b/TestDll/dllmain.cpp @@ -1,6 +1,16 @@ #define WIN32_LEAN_AND_MEAN #include +VOID ExportOne() +{ + MessageBoxA(0, "Export @1", "", 0); +} + +VOID ExportThree() +{ + MessageBoxA(0, "Export @3", "", 0); +} + BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved diff --git a/TestDll/exports.def b/TestDll/exports.def new file mode 100644 index 0000000..76f5f8b --- /dev/null +++ b/TestDll/exports.def @@ -0,0 +1,4 @@ +LIBRARY +EXPORTS +ExportOne @1 +ExportThree @3 diff --git a/TestExe/TestExe.cpp b/TestExe/TestExe.cpp index 7e7dc44..d4ac4f8 100644 --- a/TestExe/TestExe.cpp +++ b/TestExe/TestExe.cpp @@ -1,6 +1,9 @@ #define WIN32_LEAN_AND_MEAN #include #include +#include + +#include "ReflectiveLoader.h" /* Execute shellcode from file. @@ -8,10 +11,28 @@ Execute shellcode from file. BOOL ReadFileData(WCHAR *filename, BYTE **buff, DWORD *size); +int SetOrdinal(BYTE* code, DWORD codeSize, DWORD ordinal) +{ + if (ordinal <= 0 || ordinal > 65535) { + wprintf(L"Invalid ordinal. Must be [1, 65535]"); + return 0; + } + for (DWORD i = 0; i < codeSize - 3; i++) { + if (*(DWORD*)(code + i) == ORDINAL_PLACEHOLDER) { + wprintf(L"Found ordinal placeholder at offset 0x%lx", i); + DWORD* dwCodePtr = (DWORD*)(code + i); + *dwCodePtr = ordinal; + return 1; + } + } + wprintf(L"Failed to find ordinal placeholder: 0x%lx", ORDINAL_PLACEHOLDER); + return 0; +} + int wmain(int argc, WCHAR *argv[]) { if (argc < 2) { - wprintf(L"usage: TestExe.exe \n"); + wprintf(L"usage: TestExe.exe [ORDINAL]\n"); return 1; } @@ -21,6 +42,17 @@ int wmain(int argc, WCHAR *argv[]) wprintf(L"Failed to read file: %s\n", argv[1]); return 1; } + if (argc == 3) { + WCHAR* endPtr = argv[2]; + DWORD ordinal = wcstoul(argv[2], &endPtr, 10); + if (endPtr[0] != L'\0') { + wprintf(L"Failed to parse ordinal from input: %s", argv[2]); + return 1; + } + if (!SetOrdinal(code, codeSize, ordinal)) { + return 1; + } + } BYTE *rwx = (BYTE*)VirtualAlloc(0, codeSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (rwx == NULL) { wprintf(L"Failed to allocate shellcode buffer\n"); diff --git a/TestExe/TestExe.vcxproj b/TestExe/TestExe.vcxproj index c637b60..d7b4e81 100644 --- a/TestExe/TestExe.vcxproj +++ b/TestExe/TestExe.vcxproj @@ -23,34 +23,34 @@ {33879533-960C-4377-B2A1-1D8847BD037B} Win32Proj TestExe - 8.1 + 10.0 Application true - v141 Unicode + v142 Application false - v141 true Unicode + v142 Application true - v141 Unicode + v142 Application false - v141 true Unicode + v142 @@ -100,6 +100,7 @@ true NDEBUG;_CONSOLE;%(PreprocessorDefinitions) false + $(SolutionDir)Loader;%(AdditionalIncludeDirectories) Console @@ -116,6 +117,7 @@ true WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) false + $(SolutionDir)Loader;%(AdditionalIncludeDirectories) Console @@ -130,6 +132,7 @@ true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) false + $(SolutionDir)Loader;%(AdditionalIncludeDirectories) Console @@ -146,6 +149,7 @@ true WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) false + $(SolutionDir)Loader;%(AdditionalIncludeDirectories) Console