diff --git a/DarkLoadLibrary/include/ldrutils.h b/DarkLoadLibrary/include/ldrutils.h index d909a63..57835f2 100644 --- a/DarkLoadLibrary/include/ldrutils.h +++ b/DarkLoadLibrary/include/ldrutils.h @@ -5,11 +5,6 @@ #define RVA(type, base_addr, rva) (type)((ULONG_PTR) base_addr + rva) -#define FILL_STRING(string, buffer) \ - string.Length = (USHORT)strlen(buffer); \ - string.MaximumLength = string.Length; \ - string.Buffer = buffer - typedef BOOL(WINAPI * DLLMAIN)(HINSTANCE, DWORD, LPVOID); typedef NTSTATUS(WINAPI *LDRGETPROCADDRESS)(HMODULE, PANSI_STRING, WORD, PVOID*); diff --git a/DarkLoadLibrary/include/pebutils.h b/DarkLoadLibrary/include/pebutils.h index f6ad4d6..2db780b 100644 --- a/DarkLoadLibrary/include/pebutils.h +++ b/DarkLoadLibrary/include/pebutils.h @@ -3,6 +3,11 @@ #include "pebstructs.h" #include "darkloadlibrary.h" +#define FILL_STRING(string, buffer) \ + string.Length = (USHORT)strlen(buffer); \ + string.MaximumLength = string.Length; \ + string.Buffer = buffer + #ifdef _WIN32 #define PEB_OFFSET 0x30 #define READ_MEMLOC __readfsdword @@ -25,4 +30,6 @@ #define LDR_HASH_TABLE_ENTRIES 32 HMODULE IsModulePresent(LPCWSTR lpwName); -BOOL LinkModuleToPEB(PDARKMODULE pdModule); \ No newline at end of file +BOOL LinkModuleToPEB(PDARKMODULE pdModule); +FARPROC GetFunctionAddress(HMODULE hModule, LPCSTR lpProcName); +BOOL LocalLdrGetProcedureAddress(HMODULE hLibrary, PANSI_STRING ProcName, WORD Ordinal, PVOID* FunctionAddress); \ No newline at end of file diff --git a/DarkLoadLibrary/src/ldrutils.c b/DarkLoadLibrary/src/ldrutils.c index fc0e4c0..aef9de6 100644 --- a/DarkLoadLibrary/src/ldrutils.c +++ b/DarkLoadLibrary/src/ldrutils.c @@ -164,9 +164,9 @@ BOOL ResolveImports( PIMAGE_IMPORT_DESCRIPTOR pImportDesc; PIMAGE_DELAYLOAD_DESCRIPTOR pDelayDesc; PIMAGE_THUNK_DATA pFirstThunk, pOrigFirstThunk; + BOOL ok; STRING aString = { 0 }; - LDRGETPROCADDRESS pLdrGetProcAddress = NULL; pNtHeaders = RVA( PIMAGE_NT_HEADERS, @@ -176,16 +176,6 @@ BOOL ResolveImports( pDataDir = &pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; - pLdrGetProcAddress = (LDRGETPROCADDRESS)GetProcAddress( - IsModulePresent(L"ntdll.dll"), - "LdrGetProcedureAddress" - ); - - if (!pLdrGetProcAddress) - { - return FALSE; - } - // handle the import table if (pDataDir->Size) { @@ -232,12 +222,14 @@ BOOL ResolveImports( { if (IMAGE_SNAP_BY_ORDINAL(pOrigFirstThunk->u1.Ordinal)) { - pLdrGetProcAddress( + ok = LocalLdrGetProcedureAddress( hLibrary, NULL, (WORD)pOrigFirstThunk->u1.Ordinal, (PVOID*)&(pFirstThunk->u1.Function) ); + if (!ok) + return FALSE; } else { @@ -251,13 +243,14 @@ BOOL ResolveImports( aString, pImportByName->Name ); - - pLdrGetProcAddress( + ok = LocalLdrGetProcedureAddress( hLibrary, &aString, 0, (PVOID*)&(pFirstThunk->u1.Function) ); + if (!ok) + return FALSE; } } } @@ -296,12 +289,14 @@ BOOL ResolveImports( { if (IMAGE_SNAP_BY_ORDINAL(pOrigFirstThunk->u1.Ordinal)) { - pLdrGetProcAddress( + ok = LocalLdrGetProcedureAddress( hLibrary, NULL, (WORD)pOrigFirstThunk->u1.Ordinal, (PVOID*)&(pFirstThunk->u1.Function) ); + if (!ok) + return FALSE; } else { @@ -316,12 +311,14 @@ BOOL ResolveImports( pImportByName->Name ); - pLdrGetProcAddress( + ok = LocalLdrGetProcedureAddress( hLibrary, &aString, 0, (PVOID*)&(pFirstThunk->u1.Function) ); + if (!ok) + return FALSE; } } } diff --git a/DarkLoadLibrary/src/main.c b/DarkLoadLibrary/src/main.c index a53f7e8..33d9ba5 100644 --- a/DarkLoadLibrary/src/main.c +++ b/DarkLoadLibrary/src/main.c @@ -1,6 +1,7 @@ #include #include +#include "pebutils.h" #include "darkloadlibrary.h" typedef DWORD (WINAPI * _ThisIsAFunction) (LPCWSTR); @@ -21,7 +22,7 @@ VOID main() return; } - _ThisIsAFunction ThisIsAFunction = GetProcAddress( + _ThisIsAFunction ThisIsAFunction = GetFunctionAddress( DarkModule.ModuleBase, "CallThisFunction" ); diff --git a/DarkLoadLibrary/src/pebutils.c b/DarkLoadLibrary/src/pebutils.c index 489f49c..7d14d33 100644 --- a/DarkLoadLibrary/src/pebutils.c +++ b/DarkLoadLibrary/src/pebutils.c @@ -336,6 +336,217 @@ HMODULE IsModulePresent( return (HMODULE)NULL; } +FARPROC GetFunctionAddress( + HMODULE hModule, + LPCSTR lpProcName +) +{ + STRING aString = { 0 }; + FILL_STRING( + aString, + lpProcName + ); + + PVOID FunctionAddress = NULL; + BOOL ok = LocalLdrGetProcedureAddress( + hModule, + &aString, + 0, + &FunctionAddress + ); + if (!ok) + return NULL; + return FunctionAddress; +} + +BOOL LocalLdrGetProcedureAddress( + HMODULE hLibrary, + PANSI_STRING ProcName, + WORD Ordinal, + PVOID* FunctionAddress +) +{ + PIMAGE_NT_HEADERS pNtHeaders; + PIMAGE_DATA_DIRECTORY pDataDir; + PIMAGE_EXPORT_DIRECTORY pExpDir; + PIMAGE_SECTION_HEADER pSecHeader; + + if (hLibrary == NULL) + return FALSE; + + if (ProcName == NULL && Ordinal == 0) + return FALSE; + + // choose only one + if (ProcName != NULL && Ordinal != 0) + return FALSE; + + pNtHeaders = RVA( + PIMAGE_NT_HEADERS, + hLibrary, + ((PIMAGE_DOS_HEADER)hLibrary)->e_lfanew + ); + + if (pNtHeaders->Signature != IMAGE_NT_SIGNATURE) + return FALSE; + + // find the address range for the .text section + PVOID startTextSection = NULL; + PVOID endTextSection = NULL; + for (int i = 0; i < pNtHeaders->FileHeader.NumberOfSections; i++) + { + pSecHeader = RVA( + PIMAGE_SECTION_HEADER, + &pNtHeaders->OptionalHeader, + pNtHeaders->FileHeader.SizeOfOptionalHeader + i * IMAGE_SIZEOF_SECTION_HEADER + ); + if (strncmp(".text", pSecHeader->Name, 6) == 0) + { + startTextSection = RVA( + PVOID, + hLibrary, + pSecHeader->VirtualAddress + ); + endTextSection = RVA( + PVOID, + startTextSection, + pSecHeader->SizeOfRawData + ); + break; + } + } + if (startTextSection == NULL || endTextSection == NULL) + return FALSE; + + pDataDir = &pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; + if (pDataDir->Size) + { + pExpDir = RVA( + PIMAGE_EXPORT_DIRECTORY, + hLibrary, + pDataDir->VirtualAddress + ); + + int numberOfEntries = ProcName != NULL ? pExpDir->NumberOfNames : pExpDir->NumberOfFunctions; + // iterate over all the exports + for (int i = 0; i < numberOfEntries; i++) + { + BOOL found = FALSE; + ULONG32 FunctionOrdinal; + if (ProcName != NULL) + { + // searching by name + ULONG32* pRVA = RVA( + ULONG32*, + hLibrary, + pExpDir->AddressOfNames + i * 4 + ); + LPCSTR functionName = RVA( + LPCSTR, + hLibrary, + *pRVA + ); + if (strlen(functionName) != ProcName->Length) + continue; + if (strncmp(functionName, ProcName->Buffer, ProcName->Length) == 0) + { + // found it + found = TRUE; + short* pRVA2 = RVA( + short*, + hLibrary, + pExpDir->AddressOfNameOrdinals + i * 2 + ); + FunctionOrdinal = pExpDir->Base + *pRVA2; + } + } + else + { + // searching by ordinal + short* pRVA2 = RVA( + short*, + hLibrary, + pExpDir->AddressOfNameOrdinals + i * 2 + ); + FunctionOrdinal = pExpDir->Base + *pRVA2; + if (FunctionOrdinal == Ordinal) + { + // found it + found = TRUE; + } + } + if (found) + { + ULONG32* pFunctionRVA = RVA( + ULONG32*, + hLibrary, + pExpDir->AddressOfFunctions + 4 * (FunctionOrdinal - pExpDir->Base) + ); + PVOID FunctionPtr = RVA( + PVOID, + hLibrary, + *pFunctionRVA + ); + + if (FunctionPtr < startTextSection || FunctionPtr > endTextSection) + { + // this is not a pointer to a function, but a reference to another library with the real address + size_t full_length = strlen((char*)FunctionPtr); + int lib_length = 0; + for (int j = 0; j < full_length; j++) + { + if (((char*)FunctionPtr)[j] == '.') + { + lib_length = j; + break; + } + } + if (lib_length == 0) + return FALSE; + size_t func_length = full_length - lib_length - 1; + char* libname = HeapAlloc( + GetProcessHeap(), + HEAP_ZERO_MEMORY, + 2 * (lib_length + 5) + ); + if (!libname) + return FALSE; + + for (int j = 0; j < lib_length; j++) + { + libname[j * 2 + 0] = ((char*)FunctionPtr)[j]; + libname[j * 2 + 1] = 0; + } + libname[lib_length * 2 + 0] = '.'; libname[lib_length * 2 + 1] = 0; + libname[lib_length * 2 + 2] = 'd'; libname[lib_length * 2 + 3] = 0; + libname[lib_length * 2 + 4] = 'l'; libname[lib_length * 2 + 5] = 0; + libname[lib_length * 2 + 6] = 'l'; libname[lib_length * 2 + 7] = 0; + libname[lib_length * 2 + 8] = 0; libname[lib_length * 2 + 9] = 0; + char* funcname = (char*)FunctionPtr + lib_length + 1; + STRING funcname_s = { 0 }; + FILL_STRING( + funcname_s, + funcname + ); + // call ourselves recursively + BOOL result = LocalLdrGetProcedureAddress( + IsModulePresent((LPCWSTR)libname), + &funcname_s, + 0, + &FunctionPtr + ); + HeapFree(GetProcessHeap(), 0, libname); libname = NULL; + if (!result) + return FALSE; + } + *FunctionAddress = FunctionPtr; + return TRUE; + } + } + } + return FALSE; +} + BOOL LinkModuleToPEB( PDARKMODULE pdModule )