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