add a few more changes and improvements

This commit is contained in:
physics-sp
2021-08-01 18:40:21 -03:00
parent 5480a9e4b0
commit 2820acf36b
8 changed files with 354 additions and 289 deletions
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
+2 -2
View File
@@ -13,11 +13,11 @@ typedef struct _DARKMODULE {
PBYTE pbDllData;
DWORD dwDllDataLen;
LPWSTR LocalDLLName;
PWCHAR CrackedDLLName;
PWCHAR CrackedDLLName;
ULONG_PTR ModuleBase;
} DARKMODULE, *PDARKMODULE;
DARKMODULE DarkLoadLibrary(
PDARKMODULE DarkLoadLibrary(
DWORD dwFlags,
LPCWSTR lpwBuffer,
LPVOID lpFileBuffer,
+1 -1
View File
@@ -6,7 +6,7 @@
#define RVA(type, base_addr, rva) (type)((ULONG_PTR) base_addr + rva)
typedef BOOL(WINAPI * DLLMAIN)(HINSTANCE, DWORD, LPVOID);
typedef NTSTATUS(WINAPI *LDRGETPROCADDRESS)(HMODULE, PANSI_STRING, WORD, PVOID*);
typedef HMODULE(WINAPI* LOADLIBRARYA)(LPCSTR);
BOOL IsValidPE(PBYTE pbData);
BOOL MapSections(PDARKMODULE pdModule);
+9 -2
View File
@@ -8,12 +8,15 @@
string.MaximumLength = string.Length; \
string.Buffer = buffer
typedef NTSTATUS(WINAPI* LDRGETPROCADDRESS)(HMODULE, PANSI_STRING, WORD, PVOID*);
typedef VOID(WINAPI* RTLRBINSERTNODEEX)(_In_ PRTL_RB_TREE Tree, _In_opt_ PRTL_BALANCED_NODE Parent, _In_ BOOLEAN Right, _Out_ PRTL_BALANCED_NODE Node);
#ifdef _WIN64
#define PEB_OFFSET 0x60
#define READ_MEMLOC __readgsqword
#else
#define PEB_OFFSET 0x30
#define READ_MEMLOC __readfsdword
#define READ_MEMLOC __readfsdword
#endif
#pragma once
@@ -27,8 +30,12 @@
#define LDR_HASH_TABLE_ENTRIES 32
NTSYSAPI NTSTATUS NTAPI RtlHashUnicodeString(__in PCUNICODE_STRING String, __in BOOLEAN CaseInSensitive, __in ULONG HashAlgorithm, __out PULONG HashValue);
NTSYSAPI VOID NTAPI RtlRbInsertNodeEx(_In_ PRTL_RB_TREE Tree, _In_opt_ PRTL_BALANCED_NODE Parent, _In_ BOOLEAN Right, _Out_ PRTL_BALANCED_NODE Node);
HMODULE IsModulePresent(LPCWSTR lpwName);
HMODULE IsModulePresentA(char* Name);
BOOL LinkModuleToPEB(PDARKMODULE pdModule);
FARPROC GetFunctionAddress(HMODULE hModule, char* ProcName);
BOOL LocalLdrGetProcedureAddress(HMODULE hLibrary, PANSI_STRING ProcName, WORD Ordinal, PVOID* FunctionAddress);
BOOL LocalLdrGetProcedureAddress(HMODULE hLibrary, PANSI_STRING ProcName, WORD Ordinal, PVOID* FunctionAddress);
BOOL _LocalLdrGetProcedureAddress(HMODULE hLibrary, PANSI_STRING ProcName, WORD Ordinal, PVOID* FunctionAddress);
+268 -257
View File
@@ -1,258 +1,269 @@
#include "darkloadlibrary.h"
BOOL ParseFileName(
PDARKMODULE pdModule,
LPWSTR lpwFileName
)
{
if (lpwFileName == NULL)
{
pdModule->ErrorMsg = L"Invalid filename";
return FALSE;
}
pdModule->LocalDLLName = lpwFileName;
HANDLE hHeap = GetProcessHeap();
if (!hHeap)
{
pdModule->ErrorMsg = L"Failed to find valid heap";
return FALSE;
}
pdModule->CrackedDLLName = (PWCHAR)HeapAlloc(
hHeap,
HEAP_ZERO_MEMORY,
MAX_PATH * 2
);
PWCHAR lpwExt = (PWCHAR)HeapAlloc(
hHeap,
HEAP_ZERO_MEMORY,
MAX_PATH
);
PWCHAR lpwFilename = (PWCHAR)HeapAlloc(
hHeap,
HEAP_ZERO_MEMORY,
MAX_PATH
);
if (!pdModule->CrackedDLLName || !lpwExt || !lpwFilename)
{
pdModule->ErrorMsg = L"Failed to allocate memory";
return FALSE;
}
_wsplitpath(
lpwFileName,
NULL,
NULL,
lpwFilename,
lpwExt
);
if (lpwFilename == NULL || lpwExt == NULL)
{
pdModule->ErrorMsg = L"Failed to crack filename";
return FALSE;
}
PCHAR lpCpy = wcscpy(
pdModule->CrackedDLLName,
lpwFilename
);
PCHAR lpCat = wcscat(
pdModule->CrackedDLLName,
lpwExt
);
if (!lpCpy || !lpCat)
{
pdModule->ErrorMsg = L"Failed to format cracked path";
return FALSE;
}
return TRUE;
}
BOOL ReadFileToBuffer(
PDARKMODULE pdModule
)
{
HANDLE hFile = CreateFileW(
pdModule->LocalDLLName,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL
);
if (hFile == INVALID_HANDLE_VALUE)
{
pdModule->ErrorMsg = L"Failed to open local DLL file";
return FALSE;
}
DWORD dwSize = GetFileSize(
hFile,
NULL
);
if (dwSize == INVALID_FILE_SIZE)
{
pdModule->ErrorMsg = L"Failed to get DLL file size";
return FALSE;
}
pdModule->pbDllData = VirtualAlloc(
NULL,
dwSize,
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE
);
if (pdModule->pbDllData == NULL)
{
pdModule->ErrorMsg = L"Failed to allocate memory for DLL data";
return FALSE;
}
if (!ReadFile(
hFile,
pdModule->pbDllData,
dwSize,
&pdModule->dwDllDataLen,
NULL))
{
pdModule->ErrorMsg = L"Failed to read data from DLL file";
return FALSE;
}
if (!CloseHandle(hFile))
{
pdModule->ErrorMsg = L"Failed to close handle on DLL file";
return FALSE;
}
return TRUE;
}
DARKMODULE DarkLoadLibrary(
DWORD dwFlags,
LPCWSTR lpwBuffer,
LPVOID lpFileBuffer,
DWORD dwLen,
LPCWSTR lpwName
)
{
DARKMODULE dModule;
dModule.bSuccess = FALSE;
// get the DLL data into memory, whatever the format it's in
switch (dwFlags)
{
case LOAD_LOCAL_FILE:
if (!ParseFileName(&dModule, lpwBuffer) || !ReadFileToBuffer(&dModule))
{
goto Cleanup;
}
break;
case LOAD_MEMORY:
dModule.dwDllDataLen = dwLen;
dModule.pbDllData = lpFileBuffer;
/*
This is probably a hack for the greater scheme but lol
*/
dModule.CrackedDLLName = lpwName;
dModule.LocalDLLName = lpwName;
break;
case NO_LINK:
dModule.ErrorMsg = L"Not implemented yet, sorry";
goto Cleanup;
break;
default:
break;
}
// is there a module with the same name already loaded
if (lpwName == NULL)
{
lpwName = dModule.CrackedDLLName;
}
HMODULE hModule = IsModulePresent(
lpwName
);
if (hModule != NULL)
{
dModule.ModuleBase = hModule;
dModule.bSuccess = TRUE;
goto Cleanup;
}
// make sure the PE we are about to load is valid
if (!IsValidPE(dModule.pbDllData))
{
dModule.ErrorMsg = L"Data is an invalid PE";
goto Cleanup;
}
// map the sections into memory
if (!MapSections(&dModule))
{
dModule.ErrorMsg = L"Failed to map sections";
goto Cleanup;
}
// handle the import tables
if (!ResolveImports(&dModule))
{
dModule.ErrorMsg = L"Failed to resolve imports";
goto Cleanup;
}
// link the module to the PEB
if (!LinkModuleToPEB(&dModule))
{
dModule.ErrorMsg = L"Failed to link module to PEB";
goto Cleanup;
}
// trigger tls callbacks, set permissions and call the entry point
if (!BeginExecution(&dModule))
{
dModule.ErrorMsg = L"Failed to execute";
goto Cleanup;
}
dModule.bSuccess = TRUE;
goto Cleanup;
Cleanup:
return dModule;
}
BOOL ConcealLibrary(
PDARKMODULE pdModule,
BOOL bConceal
)
{
// TODO: reimplement this function, so it is better
pdModule->ErrorMsg = L"Not implemented yet, sorry";
return FALSE;
#include "darkloadlibrary.h"
#include "ldrutils.h"
BOOL ParseFileName(
PDARKMODULE pdModule,
LPWSTR lpwFileName
)
{
if (lpwFileName == NULL)
{
pdModule->ErrorMsg = L"Invalid filename";
return FALSE;
}
pdModule->LocalDLLName = lpwFileName;
HANDLE hHeap = GetProcessHeap();
if (!hHeap)
{
pdModule->ErrorMsg = L"Failed to find valid heap";
return FALSE;
}
pdModule->CrackedDLLName = (PWCHAR)HeapAlloc(
hHeap,
HEAP_ZERO_MEMORY,
MAX_PATH * 2
);
PWCHAR lpwExt = (PWCHAR)HeapAlloc(
hHeap,
HEAP_ZERO_MEMORY,
MAX_PATH
);
PWCHAR lpwFilename = (PWCHAR)HeapAlloc(
hHeap,
HEAP_ZERO_MEMORY,
MAX_PATH
);
if (!pdModule->CrackedDLLName || !lpwExt || !lpwFilename)
{
pdModule->ErrorMsg = L"Failed to allocate memory";
return FALSE;
}
_wsplitpath(
lpwFileName,
NULL,
NULL,
lpwFilename,
lpwExt
);
if (lpwFilename == NULL || lpwExt == NULL)
{
pdModule->ErrorMsg = L"Failed to crack filename";
return FALSE;
}
PCHAR lpCpy = (PCHAR)wcscpy(
pdModule->CrackedDLLName,
lpwFilename
);
PCHAR lpCat = (PCHAR)wcscat(
pdModule->CrackedDLLName,
lpwExt
);
if (!lpCpy || !lpCat)
{
pdModule->ErrorMsg = L"Failed to format cracked path";
return FALSE;
}
return TRUE;
}
BOOL ReadFileToBuffer(
PDARKMODULE pdModule
)
{
HANDLE hFile = CreateFileW(
pdModule->LocalDLLName,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL
);
if (hFile == INVALID_HANDLE_VALUE)
{
pdModule->ErrorMsg = L"Failed to open local DLL file";
return FALSE;
}
DWORD dwSize = GetFileSize(
hFile,
NULL
);
if (dwSize == INVALID_FILE_SIZE)
{
pdModule->ErrorMsg = L"Failed to get DLL file size";
return FALSE;
}
pdModule->pbDllData = VirtualAlloc(
NULL,
dwSize,
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE
);
if (pdModule->pbDllData == NULL)
{
pdModule->ErrorMsg = L"Failed to allocate memory for DLL data";
return FALSE;
}
if (!ReadFile(
hFile,
pdModule->pbDllData,
dwSize,
&pdModule->dwDllDataLen,
NULL))
{
pdModule->ErrorMsg = L"Failed to read data from DLL file";
return FALSE;
}
if (!CloseHandle(hFile))
{
pdModule->ErrorMsg = L"Failed to close handle on DLL file";
return FALSE;
}
return TRUE;
}
PDARKMODULE DarkLoadLibrary(
DWORD dwFlags,
LPCWSTR lpwBuffer,
LPVOID lpFileBuffer,
DWORD dwLen,
LPCWSTR lpwName
)
{
PDARKMODULE dModule = (DARKMODULE*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DARKMODULE));
dModule->bSuccess = FALSE;
// get the DLL data into memory, whatever the format it's in
switch (dwFlags)
{
case LOAD_LOCAL_FILE:
if (!ParseFileName(dModule, lpwBuffer) || !ReadFileToBuffer(dModule))
{
goto Cleanup;
}
break;
case LOAD_MEMORY:
dModule->dwDllDataLen = dwLen;
dModule->pbDllData = lpFileBuffer;
/*
This is probably a hack for the greater scheme but lol
*/
dModule->CrackedDLLName = lpwName;
dModule->LocalDLLName = lpwName;
break;
case NO_LINK:
dModule->ErrorMsg = L"Not implemented yet, sorry";
goto Cleanup;
break;
default:
break;
}
// is there a module with the same name already loaded
if (lpwName == NULL)
{
lpwName = dModule->CrackedDLLName;
}
HMODULE hModule = IsModulePresent(
lpwName
);
if (hModule != NULL)
{
dModule->ModuleBase = (ULONG_PTR)hModule;
dModule->bSuccess = TRUE;
goto Cleanup;
}
// make sure the PE we are about to load is valid
if (!IsValidPE(dModule->pbDllData))
{
dModule->ErrorMsg = (wchar_t*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 500);
wcscat(dModule->ErrorMsg, L"Data is an invalid PE: ");
wcscat(dModule->ErrorMsg, lpwName);
goto Cleanup;
}
// map the sections into memory
if (!MapSections(dModule))
{
dModule->ErrorMsg = (wchar_t*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 500);
wcscat(dModule->ErrorMsg, L"Failed to map sections: ");
wcscat(dModule->ErrorMsg, lpwName);
goto Cleanup;
}
// handle the import tables
if (!ResolveImports(dModule))
{
dModule->ErrorMsg = (wchar_t*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 500);
wcscat(dModule->ErrorMsg, L"Failed to resolve imports: ");
wcscat(dModule->ErrorMsg, lpwName);
goto Cleanup;
}
// link the module to the PEB
if (!LinkModuleToPEB(dModule))
{
dModule->ErrorMsg = (wchar_t*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 500);
wcscat(dModule->ErrorMsg, L"Failed to link module to PEB: ");
wcscat(dModule->ErrorMsg, lpwName);
goto Cleanup;
}
// trigger tls callbacks, set permissions and call the entry point
if (!BeginExecution(dModule))
{
dModule->ErrorMsg = (wchar_t*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 500);
wcscat(dModule->ErrorMsg, L"Failed to execute: ");
wcscat(dModule->ErrorMsg, lpwName);
goto Cleanup;
}
dModule->bSuccess = TRUE;
goto Cleanup;
Cleanup:
return dModule;
}
BOOL ConcealLibrary(
PDARKMODULE pdModule,
BOOL bConceal
)
{
// TODO: reimplement this function, so it is better
pdModule->ErrorMsg = L"Not implemented yet, sorry";
return FALSE;
}
+37 -13
View File
@@ -44,7 +44,7 @@ BOOL MapSections(
SIZE_T RegionSize = pNtHeaders->OptionalHeader.SizeOfImage;
NTSTATUS status = NtAllocateVirtualMemory(
(HANDLE)-1,
&pdModule->ModuleBase,
(PVOID)&pdModule->ModuleBase,
0,
&RegionSize,
MEM_RESERVE | MEM_COMMIT,
@@ -52,11 +52,11 @@ BOOL MapSections(
);
if (!NT_SUCCESS(status) || pdModule->ModuleBase != pNtHeaders->OptionalHeader.ImageBase)
{
pdModule->ModuleBase = NULL;
pdModule->ModuleBase = 0;
RegionSize = pNtHeaders->OptionalHeader.SizeOfImage;
status = NtAllocateVirtualMemory(
(HANDLE)-1,
&pdModule->ModuleBase,
(PVOID)&pdModule->ModuleBase,
0,
&RegionSize,
MEM_RESERVE | MEM_COMMIT,
@@ -91,7 +91,7 @@ BOOL MapSections(
}
#endif
// copy across the headers
for (INT i = 0; i < pNtHeaders->OptionalHeader.SizeOfHeaders; i++)
for (DWORD i = 0; i < pNtHeaders->OptionalHeader.SizeOfHeaders; i++)
{
((PBYTE)pdModule->ModuleBase)[i] = ((PBYTE)pdModule->pbDllData)[i];
}
@@ -99,9 +99,9 @@ BOOL MapSections(
// copy across the sections
pSectionHeader = IMAGE_FIRST_SECTION(pNtHeaders);
for (INT i = 0; i < pNtHeaders->FileHeader.NumberOfSections; i++, pSectionHeader++)
for (DWORD i = 0; i < pNtHeaders->FileHeader.NumberOfSections; i++, pSectionHeader++)
{
for (INT j = 0; j < pSectionHeader->SizeOfRawData; j++)
for (DWORD j = 0; j < pSectionHeader->SizeOfRawData; j++)
{
((PBYTE)(pdModule->ModuleBase + pSectionHeader->VirtualAddress))[j] = ((PBYTE)(pdModule->pbDllData + pSectionHeader->PointerToRawData))[j];
}
@@ -150,6 +150,7 @@ BOOL MapSections(
} while (pRelocation->VirtualAddress);
}
pNtHeaders->OptionalHeader.ImageBase = pdModule->ModuleBase; // set the prefered base to the real base
return TRUE;
}
@@ -166,6 +167,11 @@ BOOL ResolveImports(
PIMAGE_THUNK_DATA pFirstThunk, pOrigFirstThunk;
BOOL ok;
LOADLIBRARYA pLoadLibraryA = (LOADLIBRARYA)GetFunctionAddress(
IsModulePresentA("Kernel32.dll"),
"LoadLibraryA"
);
STRING aString = { 0 };
pNtHeaders = RVA(
@@ -202,9 +208,15 @@ BOOL ResolveImports(
{
// use LoadLibraryA for the time being.
// make this recursive in the future.
HMODULE hLibrary = LoadLibraryA(
(LPSTR)(pdModule->ModuleBase + pImportDesc->Name)
HMODULE hLibrary = IsModulePresentA(
(char*)(pdModule->ModuleBase + pImportDesc->Name)
);
if (hLibrary == NULL)
{
hLibrary = pLoadLibraryA(
(LPSTR)(pdModule->ModuleBase + pImportDesc->Name)
);
}
pFirstThunk = RVA(
PIMAGE_THUNK_DATA,
@@ -271,7 +283,15 @@ BOOL ResolveImports(
{
// use LoadLibraryA for the time being.
// make this recursive in the future.
HMODULE hLibrary = LoadLibraryA((LPSTR)(pdModule->ModuleBase + pDelayDesc->DllNameRVA));
HMODULE hLibrary = IsModulePresentA(
(char*)(pdModule->ModuleBase + pDelayDesc->DllNameRVA)
);
if (hLibrary == NULL)
{
hLibrary = pLoadLibraryA(
(LPSTR)(pdModule->ModuleBase + pDelayDesc->DllNameRVA)
);
}
pFirstThunk = RVA(
PIMAGE_THUNK_DATA,
@@ -337,7 +357,7 @@ BOOL BeginExecution(
PIMAGE_DATA_DIRECTORY pDataDir;
PIMAGE_TLS_CALLBACK* ppCallback;
PIMAGE_SECTION_HEADER pSectionHeader;
PIMAGE_RUNTIME_FUNCTION_ENTRY pFuncEntry;
//PIMAGE_RUNTIME_FUNCTION_ENTRY pFuncEntry;
DLLMAIN DllMain = NULL;
@@ -372,7 +392,7 @@ BOOL BeginExecution(
dwProtect |= PAGE_NOCACHE;
}
#if _M_X64
PVOID BaseAddress = pdModule->ModuleBase + pSectionHeader->VirtualAddress;
PVOID BaseAddress = (PVOID)(pdModule->ModuleBase + pSectionHeader->VirtualAddress);
SIZE_T RegionSize = pSectionHeader->SizeOfRawData;
NTSTATUS status = NtProtectVirtualMemory(
(HANDLE)-1,
@@ -438,6 +458,10 @@ BOOL BeginExecution(
// }
// #endif
// some DLLs don't have an entry point
if (pNtHeaders->OptionalHeader.AddressOfEntryPoint == 0)
return TRUE;
// call the image entry point
DllMain = RVA(
DLLMAIN,
@@ -445,11 +469,11 @@ BOOL BeginExecution(
pNtHeaders->OptionalHeader.AddressOfEntryPoint
);
DllMain(
BOOL ok = DllMain(
(HINSTANCE)pdModule->ModuleBase,
DLL_PROCESS_ATTACH,
(LPVOID)NULL
);
return TRUE;
return ok;
}
+8 -5
View File
@@ -8,7 +8,7 @@ typedef DWORD (WINAPI * _ThisIsAFunction) (LPCWSTR);
VOID main()
{
DARKMODULE DarkModule = DarkLoadLibrary(
PDARKMODULE DarkModule = DarkLoadLibrary(
LOAD_LOCAL_FILE,
L"TestDLL.dll",
NULL,
@@ -16,16 +16,19 @@ VOID main()
NULL
);
if (!DarkModule.bSuccess)
if (!DarkModule->bSuccess)
{
printf("load failed: %S\n", DarkModule.ErrorMsg);
printf("load failed: %S\n", DarkModule->ErrorMsg);
HeapFree(GetProcessHeap(), 0, DarkModule->ErrorMsg);
HeapFree(GetProcessHeap(), 0, DarkModule);
return;
}
_ThisIsAFunction ThisIsAFunction = GetFunctionAddress(
DarkModule.ModuleBase,
_ThisIsAFunction ThisIsAFunction = (_ThisIsAFunction)GetFunctionAddress(
(HMODULE)DarkModule->ModuleBase,
"CallThisFunction"
);
HeapFree(GetProcessHeap(), 0, DarkModule);
if (!ThisIsAFunction)
{
+28 -8
View File
@@ -173,10 +173,13 @@ BOOL AddBaseAddressEntry(
{
pLdrNode->DdagNode->LoadCount++;
}
} while (TRUE);
RtlRbInsertNodeEx(pModBaseAddrIndex, &pLdrNode->BaseAddressIndexNode, bRight, &pLdrEntry->BaseAddressIndexNode);
RTLRBINSERTNODEEX pRtlRbInsertNodeEx = (RTLRBINSERTNODEEX)GetFunctionAddress(
IsModulePresent(L"ntdll.dll"),
"RtlRbInsertNodeEx"
);
pRtlRbInsertNodeEx(pModBaseAddrIndex, &pLdrNode->BaseAddressIndexNode, bRight, &pLdrEntry->BaseAddressIndexNode);
return TRUE;
}
@@ -427,11 +430,28 @@ BOOL LocalLdrGetProcedureAddress(
if (ok)
return TRUE;
if (ProcName != NULL)
printf("LocalLdrGetProcedureAddress: unable to resolve address of function: %s\n", ProcName->Buffer);
else
printf("LocalLdrGetProcedureAddress: unable to resolve address of function ordinal: %d\n", Ordinal);
return FALSE;
//printf("Using fallback LdrGetProcedureAddress for resolving an unknown function address\n");
*FunctionAddress = NULL;
LDRGETPROCADDRESS pLdrGetProcedureAddress = NULL;
STRING funcname_s = { 0 };
FILL_STRING(
funcname_s,
"LdrGetProcedureAddress"
);
_LocalLdrGetProcedureAddress(
IsModulePresent(L"ntdll.dll"),
&funcname_s,
0,
(PVOID*)&pLdrGetProcedureAddress
);
pLdrGetProcedureAddress(
hLibrary,
ProcName,
Ordinal,
FunctionAddress
);
return *FunctionAddress != NULL;
}
BOOL _LocalLdrGetProcedureAddress(
@@ -681,7 +701,7 @@ BOOL LinkModuleToPEB(
(PVOID)pdModule->ModuleBase
);
// an the rest
// and the rest
pLdrEntry->ImageDll = TRUE;
pLdrEntry->LoadNotificationsSent = TRUE; // lol
pLdrEntry->EntryProcessed = TRUE;