C3/Src/CebuLoader/UnexportedWinApi.cpp

246 lines
7.8 KiB
C++

#include "stdafx.h"
#include "UnexportedWinApi.h"
#include <algorithm>
#include <string>
using namespace std::string_literals;
// Based on Blackbone https://github.com/DarthTon/Blackbone
namespace MWR::Loader::UnexportedWinApi
{
namespace
{
std::pair<std::string, size_t> GetLdrpHandleTlsOffsetData()
{
#if defined _M_X64
if (IsWindows10RS3OrGreater())
{
auto offset = 0x43;
if (IsWindows10RS6OrGreater())
offset = 0x46;
else if (IsWindows10RS4OrGreater())
offset = 0x44;
return { "\x74\x33\x44\x8d\x43\x09"s, offset };
}
else if (IsWindows10RS2OrGreater())
return { "\x74\x33\x44\x8d\x43\x09"s, 0x43 };
else if (IsWindows8Point1OrGreater())
return { "\x44\x8d\x43\x09\x4c\x8d\x4c\x24\x38"s, 0x43 };
else if (IsWindows8OrGreater())
return { "\x48\x8b\x79\x30\x45\x8d\x66\x01"s, 0x49 };
else if (IsWindows7OrGreater())
{
const bool update1 = WinVer().revision > 24059;
return { "\x41\xb8\x09\x00\x00\x00\x48\x8d\x44\x24\x38"s, update1 ? 0x23 : 0x27 };
}
else
QuietAbort();
#elif defined _M_IX86
if (IsWindows10RS3OrGreater())
{
auto pattern = "\x8b\xc1\x8d\x4d\xbc\x51";
if (IsWindows10RS5OrGreater())
pattern = "\x33\xf6\x85\xc0\x79\x03";
else if (IsWindows10RS4OrGreater())
pattern = "\x8b\xc1\x8d\x4d\xac\x51";
auto offset = 0x18;
if (IsWindows10RS6OrGreater())
offset = 0x2E;
else if (IsWindows10RS5OrGreater())
offset = 0x2C;
return { pattern, offset };
}
else if (IsWindows10RS2OrGreater())
return { "\x8b\xc1\x8d\x4d\xbc\x51"s, 0x18 };
else if (IsWindows8Point1OrGreater())
return { "\x50\x6a\x09\x6a\x01\x8b\xc1"s, 0x1B };
else if (IsWindows8OrGreater())
return { "\x8b\x45\x08\x89\x45\xa0"s, 0xC };
else if (IsWindows7OrGreater())
return { "\x74\x20\x8d\x45\xd4\x50\x6a\x09"s, 0x14 };
else
QuietAbort();
#else
# error Unsupported architecture
#endif
}
#if defined _M_IX86
std::pair<std::string, size_t> GetRtlInsertInvertedFunctionTableOffset()
{
if (IsWindows10RS3OrGreater())
return { "\x53\x56\x57\x8d\x45\xf8\x8b\xfa"s, 0x8 };
else if (IsWindows10RS2OrGreater())
return { "\x8d\x45\xf0\x89\x55\xf8\x50\x8d\x55\xf4"s, 0xB };
else if (IsWindows8Point1OrGreater())
return { "\x53\x56\x57\x8b\xda\x8b\xf9\x50"s, 0xB };
else if (IsWindows8OrGreater())
return { "\x8b\xff\x55\x8b\xec\x51\x51\x53\x57\x8b\x7d\x08\x8d"s, 0 };
else if (IsWindows7OrGreater())
return { "\x8b\xff\x55\x8b\xec\x56\x68"s, 0 };
else
QuietAbort();
}
std::pair<std::string, size_t> GetLdrpInvertedFunctionTableOffset()
{
// AFAIK only Win7 requires passing LdrpInvertedFunctionTable pointer to RtlInsertInvertedFunctionTable
if (IsWindows8OrGreater())
QuietAbort();
else if (IsWindows7OrGreater())
return { "\x89\x5D\xE0\x38", -0x1B };
else
QuietAbort();
}
#endif
struct UNICODE_STR
{
USHORT Length;
USHORT MaximumLength;
PWSTR pBuffer;
};
struct LDR_DATA_TABLE_ENTRY
{
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STR FullDllName;
UNICODE_STR BaseDllName;
ULONG Flags;
SHORT LoadCount;
SHORT TlsIndex;
LIST_ENTRY HashTableEntry;
ULONG TimeDateStamp;
};
#if defined _M_X64
typedef DWORD(* LdrpHandleTlsData_t)(LDR_DATA_TABLE_ENTRY*);
#elif defined _M_IX86
typedef DWORD(__thiscall* LdrpHandleTlsDataWin8Point1OrGreater)(LDR_DATA_TABLE_ENTRY*);
typedef DWORD(__stdcall* LdprHandleTlsDataWin7OrGreater)(LDR_DATA_TABLE_ENTRY*);
typedef void(__fastcall* RtlInsertInvertedFunctionTableWin8Point1OrGreater)(void* baseAddr, DWORD sizeOfImage);
typedef void(__stdcall* RtlInsertInvertedFunctionTableWin8OrGreater)(void* baseAddr, DWORD sizeOfImage);
typedef void(__stdcall* RtlInsertInvertedFunctionTableWin7OrGreater)(void* ldrpInvertedFunctionTable, void* baseAddr, DWORD sizeOfImage);
#else
#error Unsupported architecture
#endif
void* Find(void* begin, void* end, std::pair<std::string, size_t> const& offsetData)
{
auto match = std::search((char*)begin, (char*)end, offsetData.first.begin(), offsetData.first.end());
if (match == end)
QuietAbort();
return (void*)(match - offsetData.second);
}
template<typename T, typename V, typename U>
T Rva2Va(V base, U rva)
{
return reinterpret_cast<T>((ULONG_PTR)base + rva);
}
std::pair<void*, void*> GetSectionRange(void* dllBase, std::string const& section)
{
auto dosHeaders = reinterpret_cast<PIMAGE_DOS_HEADER>(dllBase);
auto ntHeaders = Rva2Va<PIMAGE_NT_HEADERS>(dllBase, dosHeaders->e_lfanew);
auto sectionHeader = IMAGE_FIRST_SECTION(ntHeaders);
for (int i = 0; i < ntHeaders->FileHeader.NumberOfSections; i++, sectionHeader++)
{
char currentSection[9];
memcpy(currentSection, sectionHeader->Name, 8);
currentSection[8] = 0; // ensure null-termination
if (_stricmp(section.c_str(), currentSection) == 0)
{
auto sectionVa = Rva2Va<char*>(dllBase, sectionHeader->VirtualAddress);
return { sectionVa, sectionVa + sectionHeader->Misc.VirtualSize };
}
}
return {};
}
void* FindInSection(std::wstring const& dll, std::string const& section, std::pair<std::string, size_t> const& offsetData)
{
auto dllBase = GetModuleHandleW(dll.c_str());
auto [begin, end] = GetSectionRange(dllBase, section);
return Find(begin, end, offsetData);
}
void* FindSymbol(std::wstring const& dll, std::pair<std::string, size_t> const& offsetData)
{
auto dllBase = GetModuleHandleW(dll.c_str());
auto dllSize = GetSizeOfImage((UINT_PTR)dllBase);
return Find(dllBase, dllBase + dllSize, offsetData);
}
void* FindNtDllSymbol(std::pair<std::string, size_t> const& offsetData)
{
return FindInSection(L"ntdll.dll", ".text", offsetData);
}
#if defined _M_IX86
void* g_RtlInsertInvertedFunctionTable = nullptr;
void* GetRtlInsertInvertedFunctionTable()
{
if (!g_RtlInsertInvertedFunctionTable)
g_RtlInsertInvertedFunctionTable = FindNtDllSymbol(GetRtlInsertInvertedFunctionTableOffset());
return g_RtlInsertInvertedFunctionTable;
}
void* g_LdrpInvertedFunctionTable = nullptr;
void* GetLdrpInvetedFunctionTable()
{
if (!g_LdrpInvertedFunctionTable)
g_LdrpInvertedFunctionTable = *(void**)FindNtDllSymbol(GetLdrpInvertedFunctionTableOffset());
return g_LdrpInvertedFunctionTable;
}
#endif // defined _M_IX86
void* g_LdrpHandleTlsData = nullptr;
void* GetLdrpHandleTlsData()
{
if (!g_LdrpHandleTlsData)
g_LdrpHandleTlsData = FindNtDllSymbol(GetLdrpHandleTlsOffsetData());
return g_LdrpHandleTlsData;
}
} // namespace
DWORD LdrpHandleTlsData(void* baseAddress)
{
auto ldrpHandleTlsData = GetLdrpHandleTlsData();
LDR_DATA_TABLE_ENTRY ldrDataTableEntry{};
ldrDataTableEntry.DllBase = baseAddress;
#if defined _M_X64
return ((LdrpHandleTlsData_t)ldrpHandleTlsData)(&ldrDataTableEntry);
#elif defined _M_IX86
if (IsWindows8Point1OrGreater())
return ((LdrpHandleTlsDataWin8Point1OrGreater)ldrpHandleTlsData)(&ldrDataTableEntry);
else
return ((LdprHandleTlsDataWin7OrGreater)ldrpHandleTlsData)(&ldrDataTableEntry);
#else
#error Unsupported architecture
#endif
}
#if defined _M_IX86
void RtlInsertInvertedFunctionTable(void* baseAddress, DWORD sizeOfImage)
{
auto rtlInsertInvertedFunctionTable = GetRtlInsertInvertedFunctionTable();
if (IsWindows8Point1OrGreater())
((RtlInsertInvertedFunctionTableWin8Point1OrGreater)rtlInsertInvertedFunctionTable)(baseAddress, sizeOfImage);
else if (IsWindows8OrGreater())
((RtlInsertInvertedFunctionTableWin8OrGreater)rtlInsertInvertedFunctionTable)(baseAddress, sizeOfImage);
else
((RtlInsertInvertedFunctionTableWin7OrGreater)rtlInsertInvertedFunctionTable)(GetLdrpInvetedFunctionTable(), baseAddress, sizeOfImage);
}
#endif // defined _M_IX86
} // namespace MWR::Loader