Skip to content

Commit

Permalink
Added exception handling for x64
Browse files Browse the repository at this point in the history
Updated GetProcAddressR for clarity
Added /EHa to the testdll with a divide by 0 for testing
  • Loading branch information
Nick Landers committed Nov 21, 2019
1 parent 564933f commit 1c40230
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 133 deletions.
2 changes: 1 addition & 1 deletion DotNet/Program.cs

Large diffs are not rendered by default.

86 changes: 24 additions & 62 deletions FunctionTest/FunctionTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,78 +14,40 @@
#define DEREF_16( name )*(WORD *)(name)
#define DEREF_8( name )*(BYTE *)(name)

FARPROC GetProcAddressR(UINT_PTR uiLibraryAddress, LPCSTR lpProcName)
{
FARPROC fpResult = NULL;
#define RVA(type, base, rva) (type)((ULONG_PTR) base + rva)

if (uiLibraryAddress == NULL)
FARPROC GetProcAddressR(HMODULE hModule, LPCSTR lpProcName)
{
if (hModule == NULL || lpProcName == NULL)
return NULL;

UINT_PTR uiAddressArray = 0;
UINT_PTR uiNameArray = 0;
UINT_PTR uiNameOrdinals = 0;
PIMAGE_NT_HEADERS pNtHeaders = NULL;
PIMAGE_DATA_DIRECTORY pDataDirectory = NULL;
PIMAGE_EXPORT_DIRECTORY pExportDirectory = NULL;

// get the VA of the modules NT Header
pNtHeaders = (PIMAGE_NT_HEADERS)(uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew);

pDataDirectory = (PIMAGE_DATA_DIRECTORY)&pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];

// get the VA of the export directory
pExportDirectory = (PIMAGE_EXPORT_DIRECTORY)(uiLibraryAddress + pDataDirectory->VirtualAddress);
PIMAGE_NT_HEADERS ntHeaders = RVA(PIMAGE_NT_HEADERS, hModule, ((PIMAGE_DOS_HEADER)hModule)->e_lfanew);
PIMAGE_DATA_DIRECTORY dataDir = &ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
if (!dataDir->Size)
return NULL;

// get the VA for the array of addresses
uiAddressArray = (uiLibraryAddress + pExportDirectory->AddressOfFunctions);
PIMAGE_EXPORT_DIRECTORY exportDir = RVA(PIMAGE_EXPORT_DIRECTORY, hModule, dataDir->VirtualAddress);
if (!exportDir->NumberOfNames || !exportDir->NumberOfFunctions)
return NULL;

// get the VA for the array of name pointers
uiNameArray = (uiLibraryAddress + pExportDirectory->AddressOfNames);
PDWORD expName = RVA(PDWORD, hModule, exportDir->AddressOfNames);
PWORD expOrdinal = RVA(PWORD, hModule, exportDir->AddressOfNameOrdinals);
LPCSTR expNameStr;

// get the VA for the array of name ordinals
uiNameOrdinals = (uiLibraryAddress + pExportDirectory->AddressOfNameOrdinals);
for (DWORD i = 0; i < exportDir->NumberOfNames; i++, expName++, expOrdinal++) {

// test if we are importing by name or by ordinal...
if (((DWORD)lpProcName & 0xFFFF0000) == 0x00000000)
{
// import by ordinal...
expNameStr = RVA(LPCSTR, hModule, *expName);

// use the import ordinal (- export ordinal base) as an index into the array of addresses
uiAddressArray += ((IMAGE_ORDINAL((DWORD)lpProcName) - pExportDirectory->Base) * sizeof(DWORD));
if (!expNameStr)
break;

// resolve the address for this imported function
fpResult = (FARPROC)(uiLibraryAddress + DEREF_32(uiAddressArray));
}
else
{
// import by name...
DWORD dwCounter = pExportDirectory->NumberOfNames;
while (dwCounter--)
{
char* cpExportedFunctionName = (char*)(uiLibraryAddress + DEREF_32(uiNameArray));

// test if we have a match...
if (strcmp(cpExportedFunctionName, lpProcName) == 0)
{
// use the functions name ordinal as an index into the array of name pointers
uiAddressArray += (DEREF_16(uiNameOrdinals) * sizeof(DWORD));

// calculate the virtual address for the function
fpResult = (FARPROC)(uiLibraryAddress + DEREF_32(uiAddressArray));

// finish...
break;
}

// get the next exported function name
uiNameArray += sizeof(DWORD);

// get the next exported function name ordinal
uiNameOrdinals += sizeof(WORD);
if (!_stricmp(lpProcName, expNameStr)) {
DWORD funcRva = *RVA(PDWORD, hModule, exportDir->AddressOfFunctions + (*expOrdinal * 4));
return RVA(FARPROC, hModule, funcRva);
}
}

return fpResult;
return NULL;
}


Expand Down Expand Up @@ -146,9 +108,9 @@ int main()

LoadDLL(
(ULONG_PTR)buffer,
HashFunctionName("SayHello"),
HashFunctionName("SayGoodbye"),
NULL, 0,
SRDI_CLEARHEADER | SRDI_CLEARMEMORY | SRDI_OBFUSCATEIMPORTS | (3 << 16)
SRDI_CLEARHEADER | SRDI_CLEARMEMORY // | SRDI_OBFUSCATEIMPORTS | (3 << 16)
);

return 0;
Expand Down
91 changes: 28 additions & 63 deletions Native/Loader.cpp

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion PowerShell/ConvertTo-Shellcode.ps1

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Python/ShellcodeRDI.py

Large diffs are not rendered by default.

29 changes: 24 additions & 5 deletions ShellcodeRDI/ShellcodeRDI.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#define LOCALFREE_HASH 0xea61fcb1
#define VIRTUALFREE_HASH 0x300f2f0b
#define SLEEP_HASH 0xe035f044
#define RTLADDFUNCTIONTABLE_HASH 0x45b82eba

#define HASH_KEY 13

Expand All @@ -60,7 +61,7 @@ typedef int (WINAPI * MESSAGEBOXA)(HWND, LPSTR, LPSTR, UINT);
typedef BOOL(WINAPI * VIRTUALFREE)(LPVOID, SIZE_T, DWORD);
typedef BOOL(WINAPI * LOCALFREE)(LPVOID);
typedef VOID(WINAPI* SLEEP)(DWORD);

typedef BOOLEAN(WINAPI* RTLADDFUNCTIONTABLE)(PVOID, DWORD, DWORD64);

#define RVA(type, base, rva) (type)((ULONG_PTR) base + rva)

Expand Down Expand Up @@ -93,6 +94,7 @@ ULONG_PTR LoadDLL(PBYTE dllData, DWORD dwFunctionHash, LPVOID lpUserData, DWORD
VIRTUALFREE pVirtualFree = NULL;
LOCALFREE pLocalFree = NULL;
SLEEP pSleep = NULL;
RTLADDFUNCTIONTABLE pRtlAddFunctionTable = NULL;
/// MESSAGEBOXA pMessageBoxA = NULL;

// PE data
Expand All @@ -108,6 +110,7 @@ ULONG_PTR LoadDLL(PBYTE dllData, DWORD dwFunctionHash, LPVOID lpUserData, DWORD
PIMAGE_BASE_RELOCATION relocation;
PIMAGE_RELOC relocList;
PIMAGE_EXPORT_DIRECTORY exportDir;
PIMAGE_RUNTIME_FUNCTION_ENTRY rfEntry;
PDWORD expName;
PWORD expOrdinal;
LPCSTR expNameStr;
Expand Down Expand Up @@ -158,10 +161,12 @@ ULONG_PTR LoadDLL(PBYTE dllData, DWORD dwFunctionHash, LPVOID lpUserData, DWORD
pNtFlushInstructionCache = (NTFLUSHINSTRUCTIONCACHE)GetProcAddressWithHash(NTFLUSHINSTRUCTIONCACHE_HASH);
pGetNativeSystemInfo = (GETNATIVESYSTEMINFO)GetProcAddressWithHash(GETNATIVESYSTEMINFO_HASH);
pSleep = (SLEEP)GetProcAddressWithHash(SLEEP_HASH);
pRtlAddFunctionTable = (RTLADDFUNCTIONTABLE)GetProcAddressWithHash(RTLADDFUNCTIONTABLE_HASH);

/// pMessageBoxA = (MESSAGEBOXA)GetProcAddressWithHash(MESSAGEBOXA_HASH);

if (!pLoadLibraryA || !pGetProcAddress || !pVirtualAlloc || !pVirtualProtect ||
!pNtFlushInstructionCache || !pGetNativeSystemInfo || !pSleep) {
!pNtFlushInstructionCache || !pGetNativeSystemInfo || !pSleep || !pRtlAddFunctionTable) {
return 0;
}

Expand Down Expand Up @@ -416,7 +421,7 @@ ULONG_PTR LoadDLL(PBYTE dllData, DWORD dwFunctionHash, LPVOID lpUserData, DWORD
pNtFlushInstructionCache((HANDLE)-1, NULL, 0);

///
// STEP 8: execute TLS callbacks
// STEP 8: Execute TLS callbacks
///

dataDir = &ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS];
Expand All @@ -432,14 +437,28 @@ ULONG_PTR LoadDLL(PBYTE dllData, DWORD dwFunctionHash, LPVOID lpUserData, DWORD
}

///
// STEP 9: call our images entry point
// STEP 9: Register exception handlers (x64 only)
///

#ifdef _WIN64
dataDir = &ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION];

if (dataDir->Size)
{
rfEntry = RVA(PIMAGE_RUNTIME_FUNCTION_ENTRY, baseAddress, dataDir->VirtualAddress);
pRtlAddFunctionTable(rfEntry, (dataDir->Size / sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY)) - 1, baseAddress);
}
#endif

///
// STEP 10: call our images entry point
///

dllMain = RVA(DLLMAIN, baseAddress, ntHeaders->OptionalHeader.AddressOfEntryPoint);
dllMain((HINSTANCE)baseAddress, DLL_PROCESS_ATTACH, (LPVOID)1);

///
// STEP 10: call our exported function
// STEP 11: call our exported function
///

if (dwFunctionHash) {
Expand Down
4 changes: 4 additions & 0 deletions TestDLL/TestDLL.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;TESTDLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<ExceptionHandling>Async</ExceptionHandling>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
Expand All @@ -106,6 +107,7 @@
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;TESTDLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<ExceptionHandling>Async</ExceptionHandling>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
Expand All @@ -125,6 +127,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;TESTDLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<ExceptionHandling>Async</ExceptionHandling>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
Expand All @@ -146,6 +149,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;TESTDLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<ExceptionHandling>Async</ExceptionHandling>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
Expand Down
9 changes: 9 additions & 0 deletions TestDLL/dllmain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,16 @@ BOOL APIENTRY DllMain( HMODULE hModule,
//extern "C" to prevent C++ name mangling
extern "C" __declspec(dllexport) BOOL SayGoodbye(LPVOID lpUserdata, DWORD nUserdataLen)
{
try {
int i = 0, j = 1;
j /= i; // This will throw a SE (divide by zero).
}
catch (...) {
MessageBoxA(NULL, "C++ Exception Thrown!", "Caught it", 0);
}

MessageBoxA(NULL, "I'm Leaving!", "Goodbye", 0);

return TRUE;
}

Expand Down

0 comments on commit 1c40230

Please sign in to comment.