Add fake dnsapi.dll

This commit is contained in:
nastys
2019-07-30 23:40:17 +02:00
parent f53ddd1c7e
commit 30bc900afa
10 changed files with 1943 additions and 2 deletions
+32
View File
@@ -13,32 +13,64 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Launcher", "source\plugins\
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Render", "source\plugins\Render\Render.vcxproj", "{89F87459-768F-4638-9267-0F90CD74452D}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fakedll", "source\fakedll\fakedll.vcxproj", "{B49C6ABE-931C-4F91-9A94-21A41A305FEE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{CA479467-D518-46A2-AC86-3098ADA99FE5}.Debug|x64.ActiveCfg = Debug|x64
{CA479467-D518-46A2-AC86-3098ADA99FE5}.Debug|x64.Build.0 = Debug|x64
{CA479467-D518-46A2-AC86-3098ADA99FE5}.Debug|x86.ActiveCfg = Debug|Win32
{CA479467-D518-46A2-AC86-3098ADA99FE5}.Debug|x86.Build.0 = Debug|Win32
{CA479467-D518-46A2-AC86-3098ADA99FE5}.Release|x64.ActiveCfg = Release|x64
{CA479467-D518-46A2-AC86-3098ADA99FE5}.Release|x64.Build.0 = Release|x64
{CA479467-D518-46A2-AC86-3098ADA99FE5}.Release|x86.ActiveCfg = Release|Win32
{CA479467-D518-46A2-AC86-3098ADA99FE5}.Release|x86.Build.0 = Release|Win32
{2B5533BB-04A1-424F-9BCA-1CA963B46B7F}.Debug|x64.ActiveCfg = Debug|x64
{2B5533BB-04A1-424F-9BCA-1CA963B46B7F}.Debug|x64.Build.0 = Debug|x64
{2B5533BB-04A1-424F-9BCA-1CA963B46B7F}.Debug|x86.ActiveCfg = Debug|Win32
{2B5533BB-04A1-424F-9BCA-1CA963B46B7F}.Debug|x86.Build.0 = Debug|Win32
{2B5533BB-04A1-424F-9BCA-1CA963B46B7F}.Release|x64.ActiveCfg = Release|x64
{2B5533BB-04A1-424F-9BCA-1CA963B46B7F}.Release|x64.Build.0 = Release|x64
{2B5533BB-04A1-424F-9BCA-1CA963B46B7F}.Release|x86.ActiveCfg = Release|Win32
{2B5533BB-04A1-424F-9BCA-1CA963B46B7F}.Release|x86.Build.0 = Release|Win32
{3FD6ACA9-E613-4FD6-BDA2-55A91C2CF65C}.Debug|x64.ActiveCfg = Debug|x64
{3FD6ACA9-E613-4FD6-BDA2-55A91C2CF65C}.Debug|x64.Build.0 = Debug|x64
{3FD6ACA9-E613-4FD6-BDA2-55A91C2CF65C}.Debug|x86.ActiveCfg = Debug|Win32
{3FD6ACA9-E613-4FD6-BDA2-55A91C2CF65C}.Debug|x86.Build.0 = Debug|Win32
{3FD6ACA9-E613-4FD6-BDA2-55A91C2CF65C}.Release|x64.ActiveCfg = Release|x64
{3FD6ACA9-E613-4FD6-BDA2-55A91C2CF65C}.Release|x64.Build.0 = Release|x64
{3FD6ACA9-E613-4FD6-BDA2-55A91C2CF65C}.Release|x86.ActiveCfg = Release|Win32
{3FD6ACA9-E613-4FD6-BDA2-55A91C2CF65C}.Release|x86.Build.0 = Release|Win32
{60D5E9F4-335F-402B-9A07-D78674DFFC9B}.Debug|x64.ActiveCfg = Debug|x64
{60D5E9F4-335F-402B-9A07-D78674DFFC9B}.Debug|x64.Build.0 = Debug|x64
{60D5E9F4-335F-402B-9A07-D78674DFFC9B}.Debug|x86.ActiveCfg = Debug|Win32
{60D5E9F4-335F-402B-9A07-D78674DFFC9B}.Debug|x86.Build.0 = Debug|Win32
{60D5E9F4-335F-402B-9A07-D78674DFFC9B}.Release|x64.ActiveCfg = Release|x64
{60D5E9F4-335F-402B-9A07-D78674DFFC9B}.Release|x64.Build.0 = Release|x64
{60D5E9F4-335F-402B-9A07-D78674DFFC9B}.Release|x86.ActiveCfg = Release|Win32
{60D5E9F4-335F-402B-9A07-D78674DFFC9B}.Release|x86.Build.0 = Release|Win32
{89F87459-768F-4638-9267-0F90CD74452D}.Debug|x64.ActiveCfg = Debug|x64
{89F87459-768F-4638-9267-0F90CD74452D}.Debug|x64.Build.0 = Debug|x64
{89F87459-768F-4638-9267-0F90CD74452D}.Debug|x86.ActiveCfg = Debug|Win32
{89F87459-768F-4638-9267-0F90CD74452D}.Debug|x86.Build.0 = Debug|Win32
{89F87459-768F-4638-9267-0F90CD74452D}.Release|x64.ActiveCfg = Release|x64
{89F87459-768F-4638-9267-0F90CD74452D}.Release|x64.Build.0 = Release|x64
{89F87459-768F-4638-9267-0F90CD74452D}.Release|x86.ActiveCfg = Release|Win32
{89F87459-768F-4638-9267-0F90CD74452D}.Release|x86.Build.0 = Release|Win32
{B49C6ABE-931C-4F91-9A94-21A41A305FEE}.Debug|x64.ActiveCfg = Debug|x64
{B49C6ABE-931C-4F91-9A94-21A41A305FEE}.Debug|x64.Build.0 = Debug|x64
{B49C6ABE-931C-4F91-9A94-21A41A305FEE}.Debug|x86.ActiveCfg = Debug|Win32
{B49C6ABE-931C-4F91-9A94-21A41A305FEE}.Debug|x86.Build.0 = Debug|Win32
{B49C6ABE-931C-4F91-9A94-21A41A305FEE}.Release|x64.ActiveCfg = Release|x64
{B49C6ABE-931C-4F91-9A94-21A41A305FEE}.Release|x64.Build.0 = Release|x64
{B49C6ABE-931C-4F91-9A94-21A41A305FEE}.Release|x86.ActiveCfg = Release|Win32
{B49C6ABE-931C-4F91-9A94-21A41A305FEE}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
+186
View File
@@ -0,0 +1,186 @@
#pragma once
#include <vector>
#include <algorithm>
#include <cassert>
#include <string>
#include <tuple>
std::wstring GetModuleFileNameW(HMODULE hModule)
{
static constexpr auto INITIAL_BUFFER_SIZE = MAX_PATH;
static constexpr auto MAX_ITERATIONS = 7;
std::wstring ret;
auto bufferSize = INITIAL_BUFFER_SIZE;
for (size_t iterations = 0; iterations < MAX_ITERATIONS; ++iterations)
{
ret.resize(bufferSize);
auto charsReturned = GetModuleFileNameW(hModule, &ret[0], bufferSize);
if (charsReturned < ret.length())
{
ret.resize(charsReturned);
return ret;
}
else
{
bufferSize *= 2;
}
}
return L"";
}
auto starts_with = [](const std::wstring& big_str, const std::wstring& small_str) -> auto
{
return big_str.compare(0, small_str.length(), small_str) == 0;
};
// Stores a list of loaded modules with their names, WITHOUT extension
class ModuleList
{
public:
enum class SearchLocation
{
All,
LocalOnly,
SystemOnly,
};
// Initializes module list
// Needs to be called before any calls to Get or GetAll
void Enumerate(SearchLocation location = SearchLocation::All)
{
constexpr size_t INITIAL_SIZE = sizeof(HMODULE) * 256;
HMODULE* modules = static_cast<HMODULE*>(malloc(INITIAL_SIZE));
if (modules != nullptr)
{
typedef BOOL(WINAPI * Func)(HANDLE hProcess, HMODULE * lphModule, DWORD cb, LPDWORD lpcbNeeded);
HMODULE hLib = LoadLibrary(TEXT("kernel32"));
assert(hLib != nullptr); // If this fails then everything is probably broken anyway
Func pEnumProcessModules = reinterpret_cast<Func>(GetProcAddress(hLib, "K32EnumProcessModules"));
if (pEnumProcessModules == nullptr)
{
// Try psapi
FreeLibrary(hLib);
hLib = LoadLibrary(TEXT("psapi"));
if (hLib != nullptr)
{
pEnumProcessModules = reinterpret_cast<Func>(GetProcAddress(hLib, "EnumProcessModules"));
}
}
if (pEnumProcessModules != nullptr)
{
const HANDLE currentProcess = GetCurrentProcess();
DWORD cbNeeded = 0;
if (pEnumProcessModules(currentProcess, modules, INITIAL_SIZE, &cbNeeded) != 0)
{
if (cbNeeded > INITIAL_SIZE)
{
HMODULE* newModules = static_cast<HMODULE*>(realloc(modules, cbNeeded));
if (newModules != nullptr)
{
modules = newModules;
if (pEnumProcessModules(currentProcess, modules, cbNeeded, &cbNeeded) != 0)
{
EnumerateInternal(modules, location, cbNeeded / sizeof(HMODULE));
}
}
}
else
{
EnumerateInternal(modules, location, cbNeeded / sizeof(HMODULE));
}
}
}
if (hLib != nullptr)
{
FreeLibrary(hLib);
}
free(modules);
}
}
// Recreates module list
void ReEnumerate(SearchLocation location = SearchLocation::All)
{
Clear();
Enumerate(location);
}
// Clears module list
void Clear()
{
m_moduleList.clear();
}
// Gets handle of a loaded module with given name, NULL otherwise
HMODULE Get(const wchar_t* moduleName) const
{
// If vector is empty then we're trying to call it without calling Enumerate first
assert(m_moduleList.size() != 0);
auto it = std::find_if(m_moduleList.begin(), m_moduleList.end(), [&](const auto& e) {
return _wcsicmp(moduleName, std::get<1>(e).c_str()) == 0;
});
return it != m_moduleList.end() ? std::get<0>(*it) : nullptr;
}
// Gets handles to all loaded modules with given name
std::vector<HMODULE> GetAll(const wchar_t* moduleName) const
{
// If vector is empty then we're trying to call it without calling Enumerate first
assert(m_moduleList.size() != 0);
std::vector<HMODULE> results;
for (auto& e : m_moduleList)
{
if (_wcsicmp(moduleName, std::get<1>(e).c_str()) == 0)
{
results.push_back(std::get<0>(e));
}
}
return results;
}
private:
void EnumerateInternal(HMODULE* modules, SearchLocation location, size_t numModules)
{
const auto exeModulePath = GetModuleFileNameW(NULL).substr(0, GetModuleFileNameW(NULL).find_last_of(L"/\\"));
m_moduleList.reserve(numModules);
for (size_t i = 0; i < numModules; i++)
{
// Obtain module name, with resizing if necessary
auto moduleName = GetModuleFileNameW(*modules);
if (!moduleName.empty())
{
const wchar_t* nameBegin = wcsrchr(moduleName.c_str(), '\\') + 1;
const wchar_t* dotPos = wcsrchr(nameBegin, '.');
bool isLocal = starts_with(std::wstring(moduleName), exeModulePath);
if ((isLocal && location != SearchLocation::SystemOnly) || (!isLocal && location != SearchLocation::LocalOnly))
{
if (dotPos != nullptr)
{
m_moduleList.emplace_back(*modules, std::wstring(nameBegin, dotPos), isLocal);
}
else
{
m_moduleList.emplace_back(*modules, nameBegin, isLocal);
}
}
}
modules++;
}
}
public: std::vector< std::tuple<HMODULE, std::wstring, bool> > m_moduleList;
};
+721
View File
@@ -0,0 +1,721 @@
#include "framework.h"
#include "exception.hpp"
HMODULE hm;
std::vector<std::wstring> iniPaths;
bool iequals(std::wstring_view s1, std::wstring_view s2)
{
std::wstring str1(std::move(s1));
std::wstring str2(std::move(s2));
std::transform(str1.begin(), str1.end(), str1.begin(), [](wchar_t c) { return ::towlower(c); });
std::transform(str2.begin(), str2.end(), str2.begin(), [](wchar_t c) { return ::towlower(c); });
return (str1 == str2);
}
std::wstring to_wstring(std::string_view cstr)
{
std::string str(std::move(cstr));
auto charsReturned = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
std::wstring wstrTo(charsReturned, 0);
MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], charsReturned);
return wstrTo;
}
std::wstring SHGetKnownFolderPath(REFKNOWNFOLDERID rfid, DWORD dwFlags, HANDLE hToken)
{
std::wstring r;
WCHAR* szSystemPath = nullptr;
if (SUCCEEDED(SHGetKnownFolderPath(rfid, dwFlags, hToken, &szSystemPath)))
{
r = szSystemPath;
}
CoTaskMemFree(szSystemPath);
return r;
};
HMODULE LoadLibraryW(const std::wstring& lpLibFileName)
{
return LoadLibraryW(lpLibFileName.c_str());
}
std::wstring GetCurrentDirectoryW()
{
static constexpr auto INITIAL_BUFFER_SIZE = MAX_PATH;
static constexpr auto MAX_ITERATIONS = 7;
std::wstring ret;
auto bufferSize = INITIAL_BUFFER_SIZE;
for (size_t iterations = 0; iterations < MAX_ITERATIONS; ++iterations)
{
ret.resize(bufferSize);
auto charsReturned = GetCurrentDirectoryW(bufferSize, &ret[0]);
if (charsReturned < ret.length())
{
ret.resize(charsReturned);
return ret;
}
else
{
bufferSize *= 2;
}
}
return L"";
}
UINT GetPrivateProfileIntW(LPCWSTR lpAppName, LPCWSTR lpKeyName, INT nDefault, const std::vector<std::wstring>& fileNames)
{
for (const auto& file : fileNames)
{
nDefault = GetPrivateProfileIntW(lpAppName, lpKeyName, nDefault, file.c_str());
}
return nDefault;
}
std::wstring GetSelfName()
{
const std::wstring moduleFileName = GetModuleFileNameW(hm);
return moduleFileName.substr(moduleFileName.find_last_of(L"/\\") + 1);
}
template<typename T, typename... Args>
void GetSections(T&& h, Args... args)
{
const std::set< std::string_view, std::less<> > s = { args... };
size_t dwLoadOffset = (size_t)GetModuleHandle(NULL);
BYTE* pImageBase = reinterpret_cast<BYTE*>(dwLoadOffset);
PIMAGE_DOS_HEADER pDosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(dwLoadOffset);
PIMAGE_NT_HEADERS pNtHeader = reinterpret_cast<PIMAGE_NT_HEADERS>(pImageBase + pDosHeader->e_lfanew);
PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNtHeader);
for (int iSection = 0; iSection < pNtHeader->FileHeader.NumberOfSections; ++iSection, ++pSection)
{
auto pszSectionName = reinterpret_cast<const char*>(pSection->Name);
if (s.find(pszSectionName) != s.end())
{
DWORD dwPhysSize = (pSection->Misc.VirtualSize + 4095) & ~4095;
std::forward<T>(h)(pSection, dwLoadOffset, dwPhysSize);
}
}
}
enum Kernel32ExportsNames
{
eGetStartupInfoA,
eGetStartupInfoW,
eGetModuleHandleA,
eGetModuleHandleW,
eGetProcAddress,
eGetShortPathNameA,
eFindNextFileA,
eFindNextFileW,
eLoadLibraryA,
eLoadLibraryW,
eFreeLibrary,
eCreateEventA,
eCreateEventW,
eGetSystemInfo,
eInterlockedCompareExchange,
eSleep,
Kernel32ExportsNamesCount
};
enum Kernel32ExportsData
{
IATPtr,
ProcAddress,
Kernel32ExportsDataCount
};
size_t Kernel32Data[Kernel32ExportsNamesCount][Kernel32ExportsDataCount];
static LONG OriginalLibraryLoaded = 0;
void LoadOriginalLibrary()
{
if (_InterlockedCompareExchange(&OriginalLibraryLoaded, 1, 0) != 0) return;
auto szSelfName = GetSelfName();
auto szSystemPath = SHGetKnownFolderPath(FOLDERID_System, 0, nullptr) + L'\\' + szSelfName;
auto szLocalPath = GetModuleFileNameW(hm); szLocalPath = szLocalPath.substr(0, szLocalPath.find_last_of(L"/\\") + 1);
if (iequals(szSelfName, L"dnsapi.dll")) {
dnsapi.LoadOriginalLibrary(LoadLibraryW(szSystemPath));
}
}
void FindFiles(WIN32_FIND_DATAW* fd)
{
auto dir = GetCurrentDirectoryW();
HANDLE dvaFile = FindFirstFileW(L"*.dva", fd);
if (dvaFile != INVALID_HANDLE_VALUE)
{
do {
if (!(fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
auto pos = wcslen(fd->cFileName);
if (fd->cFileName[pos - 4] == '.' &&
(fd->cFileName[pos - 3] == 'd' || fd->cFileName[pos - 3] == 'D') &&
(fd->cFileName[pos - 2] == 'v' || fd->cFileName[pos - 2] == 'V') &&
(fd->cFileName[pos - 1] == 'a' || fd->cFileName[pos - 1] == 'A'))
{
auto path = dir + L'\\' + fd->cFileName;
if (GetModuleHandle(path.c_str()) == NULL)
{
auto h = LoadLibraryW(path);
SetCurrentDirectoryW(dir.c_str()); //in case dva switched it
if (h == NULL)
{
auto e = GetLastError();
if (e != ERROR_DLL_INIT_FAILED) // in case dllmain returns false
{
std::wstring msg = L"Unable to load " + std::wstring(fd->cFileName) + L". Error: " + std::to_wstring(e);
MessageBoxW(0, msg.c_str(), L"PD Loader", MB_ICONERROR);
}
}
else
{
auto procedure = (void(*)())GetProcAddress(h, "InitializeDVA");
if (procedure != NULL)
{
procedure();
}
}
}
}
}
} while (FindNextFileW(dvaFile, fd));
FindClose(dvaFile);
}
}
void LoadPlugins()
{
auto oldDir = GetCurrentDirectoryW(); // store the current directory
auto szSelfPath = GetModuleFileNameW(hm).substr(0, GetModuleFileNameW(hm).find_last_of(L"/\\") + 1);
SetCurrentDirectoryW(szSelfPath.c_str());
auto nWantsToLoadPlugins = GetPrivateProfileIntW(L"global", L"enable", TRUE, iniPaths);
if (nWantsToLoadPlugins)
{
WIN32_FIND_DATAW fd;
SetCurrentDirectoryW(szSelfPath.c_str());
if (SetCurrentDirectoryW(L"plugins\\"))
FindFiles(&fd);
}
SetCurrentDirectoryW(oldDir.c_str()); // Reset the current directory
}
void InjectCode(void* address, const std::vector<uint8_t> data)
{
const size_t byteCount = data.size() * sizeof(uint8_t);
DWORD oldProtect;
VirtualProtect(address, byteCount, PAGE_EXECUTE_READWRITE, &oldProtect);
memcpy(address, data.data(), byteCount);
VirtualProtect(address, byteCount, oldProtect, nullptr);
}
static LONG LoadedPluginsYet = 0;
void LoadEverything()
{
if (_InterlockedCompareExchange(&LoadedPluginsYet, 1, 0) != 0) return;
LoadOriginalLibrary();
//LoadPlugins();
InjectCode((void*)0x00000001409FF730, { 0x53, 0x65, 0x65, 0x20, 0x52, 0x45, 0x41, 0x44, 0x4D, 0x45, 0x2E, 0x74, 0x78, 0x74, 0x2E, 0x00, 0x00 });
}
static LONG RestoredOnce = 0;
void LoadPluginsAndRestoreIAT(uintptr_t retaddr)
{
bool calledFromBind = false;
//steam drm check
GetSections([&](PIMAGE_SECTION_HEADER pSection, size_t dwLoadOffset, DWORD dwPhysSize) {
auto dwStart = static_cast<uintptr_t>(dwLoadOffset + pSection->VirtualAddress);
auto dwEnd = dwStart + dwPhysSize;
if (retaddr >= dwStart && retaddr <= dwEnd)
calledFromBind = true;
}, ".bind");
if (calledFromBind) return;
if (_InterlockedCompareExchange(&RestoredOnce, 1, 0) != 0) return;
LoadEverything();
for (size_t i = 0; i < Kernel32ExportsNamesCount; i++)
{
if (Kernel32Data[i][IATPtr] && Kernel32Data[i][ProcAddress])
{
auto ptr = (size_t*)Kernel32Data[i][IATPtr];
DWORD dwProtect[2];
VirtualProtect(ptr, sizeof(size_t), PAGE_EXECUTE_READWRITE, &dwProtect[0]);
*ptr = Kernel32Data[i][ProcAddress];
VirtualProtect(ptr, sizeof(size_t), dwProtect[0], &dwProtect[1]);
}
}
}
void WINAPI CustomGetStartupInfoA(LPSTARTUPINFOA lpStartupInfo)
{
LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress());
return GetStartupInfoA(lpStartupInfo);
}
void WINAPI CustomGetStartupInfoW(LPSTARTUPINFOW lpStartupInfo)
{
LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress());
return GetStartupInfoW(lpStartupInfo);
}
HMODULE WINAPI CustomGetModuleHandleA(LPCSTR lpModuleName)
{
LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress());
return GetModuleHandleA(lpModuleName);
}
HMODULE WINAPI CustomGetModuleHandleW(LPCWSTR lpModuleName)
{
LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress());
return GetModuleHandleW(lpModuleName);
}
FARPROC WINAPI CustomGetProcAddress(HMODULE hModule, LPCSTR lpProcName)
{
LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress());
return GetProcAddress(hModule, lpProcName);
}
DWORD WINAPI CustomGetShortPathNameA(LPCSTR lpszLongPath, LPSTR lpszShortPath, DWORD cchBuffer)
{
LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress());
return GetShortPathNameA(lpszLongPath, lpszShortPath, cchBuffer);
}
BOOL WINAPI CustomFindNextFileA(HANDLE hFindFile, LPWIN32_FIND_DATAA lpFindFileData)
{
LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress());
return FindNextFileA(hFindFile, lpFindFileData);
}
BOOL WINAPI CustomFindNextFileW(HANDLE hFindFile, LPWIN32_FIND_DATAW lpFindFileData)
{
LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress());
return FindNextFileW(hFindFile, lpFindFileData);
}
HMODULE WINAPI CustomLoadLibraryA(LPCSTR lpLibFileName)
{
LoadOriginalLibrary();
return LoadLibraryA(lpLibFileName);
}
HMODULE WINAPI CustomLoadLibraryW(LPCWSTR lpLibFileName)
{
LoadOriginalLibrary();
return LoadLibraryW(lpLibFileName);
}
BOOL WINAPI CustomFreeLibrary(HMODULE hLibModule)
{
if (hLibModule != hm)
return FreeLibrary(hLibModule);
else
return !NULL;
}
HANDLE WINAPI CustomCreateEventA(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCSTR lpName)
{
LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress());
return CreateEventA(lpEventAttributes, bManualReset, bInitialState, lpName);
}
HANDLE WINAPI CustomCreateEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCWSTR lpName)
{
LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress());
return CreateEventW(lpEventAttributes, bManualReset, bInitialState, lpName);
}
void WINAPI CustomGetSystemInfo(LPSYSTEM_INFO lpSystemInfo)
{
LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress());
return GetSystemInfo(lpSystemInfo);
}
LONG WINAPI CustomInterlockedCompareExchange(LONG volatile* Destination, LONG ExChange, LONG Comperand)
{
LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress());
return _InterlockedCompareExchange(Destination, ExChange, Comperand);
}
void WINAPI CustomSleep(DWORD dwMilliseconds)
{
LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress());
return Sleep(dwMilliseconds);
}
bool HookKernel32IAT(HMODULE mod, bool exe)
{
auto hExecutableInstance = (size_t)mod;
IMAGE_NT_HEADERS* ntHeader = (IMAGE_NT_HEADERS*)(hExecutableInstance + ((IMAGE_DOS_HEADER*)hExecutableInstance)->e_lfanew);
IMAGE_IMPORT_DESCRIPTOR* pImports = (IMAGE_IMPORT_DESCRIPTOR*)(hExecutableInstance + ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
size_t nNumImports = ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size / sizeof(IMAGE_IMPORT_DESCRIPTOR) - 1;
if (exe)
{
Kernel32Data[eGetStartupInfoA][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "GetStartupInfoA");
Kernel32Data[eGetStartupInfoW][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "GetStartupInfoW");
Kernel32Data[eGetModuleHandleA][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "GetModuleHandleA");
Kernel32Data[eGetModuleHandleW][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "GetModuleHandleW");
Kernel32Data[eGetProcAddress][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "GetProcAddress");
Kernel32Data[eGetShortPathNameA][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "GetShortPathNameA");
Kernel32Data[eFindNextFileA][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "FindNextFileA");
Kernel32Data[eFindNextFileW][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "FindNextFileW");
Kernel32Data[eLoadLibraryA][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "LoadLibraryA");
Kernel32Data[eLoadLibraryW][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "LoadLibraryW");
Kernel32Data[eFreeLibrary][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "FreeLibrary");
Kernel32Data[eCreateEventA][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "CreateEventA");
Kernel32Data[eCreateEventW][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "CreateEventW");
Kernel32Data[eGetSystemInfo][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "GetSystemInfo");
Kernel32Data[eInterlockedCompareExchange][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "InterlockedCompareExchange");
Kernel32Data[eSleep][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "Sleep");
}
uint32_t matchedImports = 0;
auto PatchIAT = [&](size_t start, size_t end, size_t exe_end)
{
for (size_t i = 0; i < nNumImports; i++)
{
if (hExecutableInstance + (pImports + i)->FirstThunk > start && !(end && hExecutableInstance + (pImports + i)->FirstThunk > end))
end = hExecutableInstance + (pImports + i)->FirstThunk;
}
if (!end) { end = start + 0x100; }
if (end > exe_end) //for very broken exes
{
start = hExecutableInstance;
end = exe_end;
}
for (auto i = start; i < end; i += sizeof(size_t))
{
DWORD dwProtect[2];
VirtualProtect((size_t*)i, sizeof(size_t), PAGE_EXECUTE_READWRITE, &dwProtect[0]);
auto ptr = *(size_t*)i;
if (!ptr)
continue;
if (ptr == Kernel32Data[eGetStartupInfoA][ProcAddress])
{
if (exe) Kernel32Data[eGetStartupInfoA][IATPtr] = i;
*(size_t*)i = (size_t)CustomGetStartupInfoA;
matchedImports++;
}
else if (ptr == Kernel32Data[eGetStartupInfoW][ProcAddress])
{
if (exe) Kernel32Data[eGetStartupInfoW][IATPtr] = i;
*(size_t*)i = (size_t)CustomGetStartupInfoW;
matchedImports++;
}
else if (ptr == Kernel32Data[eGetModuleHandleA][ProcAddress])
{
if (exe) Kernel32Data[eGetModuleHandleA][IATPtr] = i;
*(size_t*)i = (size_t)CustomGetModuleHandleA;
matchedImports++;
}
else if (ptr == Kernel32Data[eGetModuleHandleW][ProcAddress])
{
if (exe) Kernel32Data[eGetModuleHandleW][IATPtr] = i;
*(size_t*)i = (size_t)CustomGetModuleHandleW;
matchedImports++;
}
else if (ptr == Kernel32Data[eGetProcAddress][ProcAddress])
{
if (exe) Kernel32Data[eGetProcAddress][IATPtr] = i;
*(size_t*)i = (size_t)CustomGetProcAddress;
matchedImports++;
}
else if (ptr == Kernel32Data[eGetShortPathNameA][ProcAddress])
{
if (exe) Kernel32Data[eGetShortPathNameA][IATPtr] = i;
*(size_t*)i = (size_t)CustomGetShortPathNameA;
matchedImports++;
}
else if (ptr == Kernel32Data[eFindNextFileA][ProcAddress])
{
if (exe) Kernel32Data[eFindNextFileA][IATPtr] = i;
*(size_t*)i = (size_t)CustomFindNextFileA;
matchedImports++;
}
else if (ptr == Kernel32Data[eFindNextFileW][ProcAddress])
{
if (exe) Kernel32Data[eFindNextFileW][IATPtr] = i;
*(size_t*)i = (size_t)CustomFindNextFileW;
matchedImports++;
}
else if (ptr == Kernel32Data[eLoadLibraryA][ProcAddress])
{
if (exe) Kernel32Data[eLoadLibraryA][IATPtr] = i;
*(size_t*)i = (size_t)CustomLoadLibraryA;
matchedImports++;
}
else if (ptr == Kernel32Data[eLoadLibraryW][ProcAddress])
{
if (exe) Kernel32Data[eLoadLibraryW][IATPtr] = i;
*(size_t*)i = (size_t)CustomLoadLibraryW;
matchedImports++;
}
else if (ptr == Kernel32Data[eFreeLibrary][ProcAddress])
{
if (exe) Kernel32Data[eFreeLibrary][IATPtr] = i;
*(size_t*)i = (size_t)CustomFreeLibrary;
matchedImports++;
}
else if (ptr == Kernel32Data[eCreateEventA][ProcAddress])
{
if (exe) Kernel32Data[eCreateEventA][IATPtr] = i;
*(size_t*)i = (size_t)CustomCreateEventA;
matchedImports++;
}
else if (ptr == Kernel32Data[eCreateEventW][ProcAddress])
{
if (exe) Kernel32Data[eCreateEventW][IATPtr] = i;
*(size_t*)i = (size_t)CustomCreateEventW;
matchedImports++;
}
else if (ptr == Kernel32Data[eGetSystemInfo][ProcAddress])
{
if (exe) Kernel32Data[eGetSystemInfo][IATPtr] = i;
*(size_t*)i = (size_t)CustomGetSystemInfo;
matchedImports++;
}
else if (ptr == Kernel32Data[eInterlockedCompareExchange][ProcAddress])
{
if (exe) Kernel32Data[eInterlockedCompareExchange][IATPtr] = i;
*(size_t*)i = (size_t)CustomInterlockedCompareExchange;
matchedImports++;
}
else if (ptr == Kernel32Data[eSleep][ProcAddress])
{
if (exe) Kernel32Data[eSleep][IATPtr] = i;
*(size_t*)i = (size_t)CustomSleep;
matchedImports++;
}
VirtualProtect((size_t*)i, sizeof(size_t), dwProtect[0], &dwProtect[1]);
}
};
static auto getSection = [](const PIMAGE_NT_HEADERS nt_headers, unsigned section) -> PIMAGE_SECTION_HEADER
{
return reinterpret_cast<PIMAGE_SECTION_HEADER>(
(UCHAR*)nt_headers->OptionalHeader.DataDirectory +
nt_headers->OptionalHeader.NumberOfRvaAndSizes * sizeof(IMAGE_DATA_DIRECTORY) +
section * sizeof(IMAGE_SECTION_HEADER));
};
static auto getSectionEnd = [](IMAGE_NT_HEADERS* ntHeader, size_t inst) -> auto
{
auto sec = getSection(ntHeader, ntHeader->FileHeader.NumberOfSections - 1);
auto secSize = max(sec->SizeOfRawData, sec->Misc.VirtualSize);
auto end = inst + max(sec->PointerToRawData, sec->VirtualAddress) + secSize;
return end;
};
auto hExecutableInstance_end = getSectionEnd(ntHeader, hExecutableInstance);
// Find kernel32.dll
for (size_t i = 0; i < nNumImports; i++)
{
if ((size_t)(hExecutableInstance + (pImports + i)->Name) < hExecutableInstance_end)
{
if (!_stricmp((const char*)(hExecutableInstance + (pImports + i)->Name), "KERNEL32.DLL"))
PatchIAT(hExecutableInstance + (pImports + i)->FirstThunk, 0, hExecutableInstance_end);
}
}
// Fixing ordinals
auto szSelfName = GetSelfName();
static auto PatchOrdinals = [&szSelfName](size_t hInstance)
{
IMAGE_NT_HEADERS* ntHeader = (IMAGE_NT_HEADERS*)(hInstance + ((IMAGE_DOS_HEADER*)hInstance)->e_lfanew);
IMAGE_IMPORT_DESCRIPTOR* pImports = (IMAGE_IMPORT_DESCRIPTOR*)(hInstance + ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
size_t nNumImports = ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size / sizeof(IMAGE_IMPORT_DESCRIPTOR) - 1;
for (size_t i = 0; i < nNumImports; i++)
{
if ((size_t)(hInstance + (pImports + i)->Name) < getSectionEnd(ntHeader, (size_t)hInstance))
{
if (iequals(szSelfName, (to_wstring((const char*)(hInstance + (pImports + i)->Name)))))
{
PIMAGE_THUNK_DATA thunk = (PIMAGE_THUNK_DATA)(hInstance + (pImports + i)->OriginalFirstThunk);
size_t j = 0;
while (thunk->u1.Function)
{
if (thunk->u1.Ordinal & IMAGE_ORDINAL_FLAG)
{
PIMAGE_IMPORT_BY_NAME import = (PIMAGE_IMPORT_BY_NAME)(hInstance + thunk->u1.AddressOfData);
void** p = (void**)(hInstance + (pImports + i)->FirstThunk);
}
++thunk;
}
}
}
}
};
ModuleList dlls;
dlls.Enumerate(ModuleList::SearchLocation::LocalOnly);
for (auto& e : dlls.m_moduleList)
{
PatchOrdinals((size_t)std::get<HMODULE>(e));
}
return matchedImports > 0;
}
LONG WINAPI CustomUnhandledExceptionFilter(LPEXCEPTION_POINTERS ExceptionInfo)
{
// step 1: write minidump
wchar_t modulename[MAX_PATH];
wchar_t filename[MAX_PATH];
wchar_t timestamp[128];
__time64_t time;
struct tm ltime;
HANDLE hFile;
HWND hWnd;
wchar_t* modulenameptr = NULL;
if (GetModuleFileNameW(GetModuleHandle(NULL), modulename, _countof(modulename)) != 0)
{
modulenameptr = wcsrchr(modulename, '\\');
*modulenameptr = L'\0';
modulenameptr += 1;
}
else
{
*modulenameptr = L'err.err';
}
_time64(&time);
_localtime64_s(&ltime, &time);
wcsftime(timestamp, _countof(timestamp), L"%Y%m%d%H%M%S", &ltime);
swprintf_s(filename, L"%s\\%s\\%s.%s.dmp", modulename, L"logs", modulenameptr, timestamp);
hFile = CreateFileW(filename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
MINIDUMP_EXCEPTION_INFORMATION ex;
memset(&ex, 0, sizeof(ex));
ex.ThreadId = GetCurrentThreadId();
ex.ExceptionPointers = ExceptionInfo;
ex.ClientPointers = TRUE;
if (FAILED(MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpWithDataSegs, &ex, NULL, NULL)))
{
}
CloseHandle(hFile);
}
// step 2: write log
// Logs exception into buffer and writes to file
swprintf_s(filename, L"%s\\%s\\%s.%s.log", modulename, L"logs", modulenameptr, timestamp);
hFile = CreateFileW(filename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
auto Log = [ExceptionInfo, hFile](char* buffer, size_t size, bool reg, bool stack, bool trace)
{
if (LogException(buffer, size, (LPEXCEPTION_POINTERS)ExceptionInfo, reg, stack, trace))
{
DWORD NumberOfBytesWritten = 0;
WriteFile(hFile, buffer, strlen(buffer), &NumberOfBytesWritten, NULL);
}
};
// Try to make a very descriptive exception, for that we need to malloc a huge buffer...
if (auto buffer = (char*)malloc(max_logsize_ever))
{
Log(buffer, max_logsize_ever, true, true, true);
free(buffer);
}
else
{
// Use a static buffer, no need for any allocation
static const auto size = max_logsize_basic + max_logsize_regs + max_logsize_stackdump;
static char static_buf[size];
static_assert(size <= max_static_buffer, "Static buffer is too big");
Log(buffer = static_buf, sizeof(static_buf), true, true, false);
}
CloseHandle(hFile);
}
// step 3: exit the application
ShowCursor(TRUE);
hWnd = FindWindowW(0, L"");
SetForegroundWindow(hWnd);
return EXCEPTION_CONTINUE_SEARCH;
}
void Init()
{
std::wstring modulePath = GetModuleFileNameW(hm);
std::wstring moduleName = modulePath.substr(modulePath.find_last_of(L"/\\") + 1);
moduleName.resize(moduleName.find_last_of(L'.'));
modulePath.resize(modulePath.find_last_of(L"/\\") + 1);
iniPaths.emplace_back(modulePath + moduleName + L".ini");
iniPaths.emplace_back(modulePath + L"plugins\\config.ini");
std::wstring m = GetModuleFileNameW(NULL);
m = m.substr(0, m.find_last_of(L"/\\") + 1) + L"logs";
auto FolderExists = [](LPCWSTR szPath) -> BOOL
{
DWORD dwAttrib = GetFileAttributes(szPath);
return (dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
};
if (FolderExists(m.c_str()))
{
SetUnhandledExceptionFilter(CustomUnhandledExceptionFilter);
// Now stub out CustomUnhandledExceptionFilter so NO ONE ELSE can set it!
uint32_t ret = 0x909090C3; //ret
DWORD protect[2];
VirtualProtect(&SetUnhandledExceptionFilter, sizeof(ret), PAGE_EXECUTE_READWRITE, &protect[0]);
memcpy(&SetUnhandledExceptionFilter, &ret, sizeof(ret));
VirtualProtect(&SetUnhandledExceptionFilter, sizeof(ret), protect[0], &protect[1]);
}
LoadEverything();
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID /*lpReserved*/)
{
if (reason == DLL_PROCESS_ATTACH)
{
hm = hModule;
Init();
}
return TRUE;
}
+678
View File
@@ -0,0 +1,678 @@
#pragma once
/*
* Unhandled Exception Tracer
* by LINK/2012 <dma_2012@hotmail.com>
*
* This source code is offered for use in the public domain. You may
* use, modify or distribute it freely.
*
* This code is distributed in the hope that it will be useful but
* WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
* DISCLAIMED. This includes but is not limited to warranties of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
#include <cassert>
#include <DbgHelp.h>
#pragma comment(lib, "Dbghelp.lib")
/*
* Special Note:
* Try not to allocate any memory in this file!
* Allocation after a exception may not be a good idea...
*/
#define LODWORD(_qw) ((DWORD)(_qw))
#define HIDWORD(_qw) ((DWORD)(((_qw) >> 32) & 0xffffffff))
// General constants
static const int sizeof_word = sizeof(void*); // Size of a CPU word (4 bytes on x86)
static const int max_chars_per_print = MAX_PATH + 256; // Max characters per Print() call
static const int symbol_max = 256; // Max size of a symbol (func symbol, var symbol, etc)
static const int max_static_buffer = 4096; // Max static buffer for logging
// Stackdump constants
static const int stackdump_max_words = 60; // max number of CPU words that the stackdump should dump
static const int stackdump_words_per_line = 6; // max CPU words in a single line
static const int stackdump_line_count = (stackdump_max_words / stackdump_words_per_line) + 1;
// Backtrace constants
static const int max_backtrace_ever = 100;
static const int max_backtrace = 20;
// Maximum log size constants
static const int max_logsize_basic = (MAX_PATH + 200); // module path + other text
static const int max_logsize_regs = 32 + (4 * 4 * 28); // info + (regsPerLine * numLines * charsPerReg)
static const int max_logsize_stackdump = 32 + 80 + (stackdump_line_count * 32) + (10 * stackdump_words_per_line * stackdump_line_count);
static const int max_logsize_backtrace = 32 + max_backtrace_ever * (MAX_PATH + symbol_max + 90);
static const int max_logsize_ever = 32 + max_logsize_basic + max_logsize_regs + max_logsize_stackdump + max_logsize_backtrace;
// Internal
class ExceptionTracer;
class StackTrace;
static HMODULE GetModuleFromAddress(LPVOID address);
static const char* GetExceptionCodeString(unsigned int code);
static const char* FindModuleName(HMODULE module, char* output, DWORD size);
static int LogException(char* buffer, size_t max, LPEXCEPTION_POINTERS pException, bool bLogRegisters, bool bLogStack, bool bLogBacktrace);
static LPTOP_LEVEL_EXCEPTION_FILTER PrevFilter = nullptr;
static void(*ExceptionCallback)(const char* buffer) = nullptr;
// Exportable
int InstallExceptionCatcher(void(*OnException)(const char* log));
/*
* ExceptionTrace
* This class is responssible for tracing all possible informations about an LPEXCEPTION_POINTER
*/
class ExceptionTracer
{
public:
ExceptionTracer(char* buffer, size_t max, LPEXCEPTION_POINTERS pException);
void PrintUnhandledException();
void PrintRegisters();
void PrintStackdump();
void PrintBacktrace();
void EnterScope();
void LeaveScope();
void Print(const char* fmt, ...);
void NewLine() { Print("\n%s", spc); }
protected:
EXCEPTION_POINTERS& exception;
EXCEPTION_RECORD& record;
CONTEXT& context;
HMODULE module;
char* buffer; // Logging buffer
size_t len; // Logged length
size_t max; // Maximum we can log in that buffer
char spc[(10 * 4) + 1]; // Scope/spacing buffer, 4 spaces per scope, max 10 scopes
size_t nspc; // Number spaces used up there
};
/*
* StackTracer
* Responssible for backtracing an stack from a context
*/
class StackTracer
{
public:
struct Trace
{
// The following values may be null (any)
HMODULE module; // The module the func related to this frame is located
void* pc; // Program counter at func related to this frame (EIP)
void* ret; // Return address for the frame
void* frame; // The frame address (EBP)
void* stack; // The stack pointer at the frame (ESP)
};
StackTracer(const CONTEXT& context);
Trace* Walk();
private:
Trace trace;
DWORD old_options;
CONTEXT context;
STACKFRAME64 frame;
};
/*
* TheUnhandledExceptionFilter
* Logs an unhandled exception
*/
static LONG CALLBACK TheUnhandledExceptionFilter(LPEXCEPTION_POINTERS pException)
{
// Logs exception into buffer and calls the callback
auto Log = [pException](char* buffer, size_t size, bool reg, bool stack, bool trace)
{
if (LogException(buffer, size, (LPEXCEPTION_POINTERS)pException, reg, stack, trace))
ExceptionCallback(buffer);
};
// Try to make a very descriptive exception, for that we need to malloc a huge buffer...
if (auto buffer = (char*)malloc(max_logsize_ever))
{
Log(buffer, max_logsize_ever, true, true, true);
free(buffer);
}
else
{
// Use a static buffer, no need for any allocation
static const auto size = max_logsize_basic + max_logsize_regs + max_logsize_stackdump;
static char static_buf[size];
static_assert(size <= max_static_buffer, "Static buffer is too big");
Log(buffer = static_buf, sizeof(static_buf), true, true, false);
}
// Continue exception propagation
return (PrevFilter ? PrevFilter(pException) : EXCEPTION_CONTINUE_SEARCH); // I'm not really sure about this return
}
/*
* InstallExceptionCatcher
* Installs a exception handler to call the specified callback when it happens with human readalbe information.
*/
int InstallExceptionCatcher(void(*cb)(const char* log))
{
PrevFilter = SetUnhandledExceptionFilter(TheUnhandledExceptionFilter);
ExceptionCallback = cb;
return 1;
}
/*
* LogException
* Takes an LPEXCEPTION_POINTERS and transforms in a string that is put in the logging steam
*/
static int LogException(char* buffer, size_t max, LPEXCEPTION_POINTERS pException, bool bLogRegisters, bool bLogStack, bool bLogBacktrace)
{
ExceptionTracer trace(buffer, max, pException);
trace.PrintUnhandledException();
trace.EnterScope();
if (bLogRegisters) trace.PrintRegisters();
if (bLogStack) trace.PrintStackdump();
if (bLogBacktrace) trace.PrintBacktrace();
trace.LeaveScope();
return 1;
}
/*
* ExceptionTracer
* Contructs a exception trace object, responssible for tracing informations about an exception
*/
ExceptionTracer::ExceptionTracer(char* buffer, size_t max, LPEXCEPTION_POINTERS pException) :
buffer(buffer), exception(*pException), record(*pException->ExceptionRecord), context(*pException->ContextRecord)
{
this->buffer = buffer;
this->buffer[this->len = 0] = 0;
this->spc[this->nspc = 0] = 0;
this->max = max;
// Acquiere common information that we'll access
this->module = GetModuleFromAddress(record.ExceptionAddress);
}
/*
* Print
* Prints some formated text into the logging buffer
*/
void ExceptionTracer::Print(const char* fmt, ...)
{
va_list va;
va_start(va, fmt);
if ((this->max - this->len) > max_chars_per_print)
this->len += vsprintf(&this->buffer[len], fmt, va);
va_end(va);
}
/*
* EnterScope
* Enters a new scope in the logging buffer (scope is related to indentation)
* This also prints a new line
*/
void ExceptionTracer::EnterScope()
{
nspc += 4;
spc[nspc - 4] = ' ';
spc[nspc - 3] = ' ';
spc[nspc - 2] = ' ';
spc[nspc - 1] = ' ';
spc[nspc - 0] = 0;
NewLine();
}
/*
* LeaveScope
* Leaves the scope
*/
void ExceptionTracer::LeaveScope()
{
assert(nspc > 0);
nspc -= 4;
spc[nspc] = 0;
NewLine();
}
/*
* PrintUnhandledException
* Prints the well known "Unhandled exception at ..." into the logging buffer
*/
void ExceptionTracer::PrintUnhandledException()
{
char module_name[MAX_PATH];
auto dwExceptionCode = record.ExceptionCode;
uintptr_t address = (uintptr_t)record.ExceptionAddress;
// Find out our module name for logging
if (!this->module || !GetModuleFileNameA(this->module, module_name, sizeof(module_name)))
strcpy(module_name, "unknown");
// Log the exception in a similar format similar to debuggers format
Print("Unhandled exception at 0x%p in %s", address, FindModuleName(module, module_name, sizeof(module_name)));
if (module) Print(" (+0x%x)", address - (uintptr_t)(module));
Print(": 0x%X: %s", dwExceptionCode, GetExceptionCodeString(dwExceptionCode));
// If exception is IN_PAGE_ERROR or ACCESS_VIOLATION, we have additional information such as an address
if (dwExceptionCode == EXCEPTION_IN_PAGE_ERROR || dwExceptionCode == EXCEPTION_ACCESS_VIOLATION)
{
auto rw = (DWORD)record.ExceptionInformation[0]; // read or write?
auto addr = (ULONG_PTR)record.ExceptionInformation[1]; // which address?
Print(" %s 0x%p",
rw == 0 ? "reading location" : rw == 1 ? "writing location" : rw == 8 ? "DEP at" : "",
addr);
// IN_PAGE_ERROR have another information...
if (dwExceptionCode == EXCEPTION_IN_PAGE_ERROR)
{
NewLine();
Print("Underlying NTSTATUS code that resulted in the exception is 0x%p",
record.ExceptionInformation[2]);
}
}
Print(".");
}
/*
* PrintRegisters
* Prints the content of the assembly registers into the logging buffer
*/
void ExceptionTracer::PrintRegisters()
{
int regs_in_line = 0; // Amount of registers currently printed on this line
// Prints a register, followed by spaces
auto PrintRegister = [this, &regs_in_line](const char* reg_name, size_t reg_value, const char* spaces)
{
Print("%s: 0x%p%s", reg_name, reg_value, spaces);
if (++regs_in_line >= 4) { this->NewLine(); regs_in_line = 0; }
};
auto PrintFloatRegister = [this, &regs_in_line](const char* reg_name, int reg_num, uint32_t reg_value1, uint32_t reg_value2, uint32_t reg_value3, uint32_t reg_value4)
{
Print("%s%02d: 0x%08X 0x%08X 0x%08X 0x%08X [ %f %f %f %f ]", reg_name, reg_num, reg_value1, reg_value2, reg_value3, reg_value4,
*(float*)& reg_value1, *(float*)& reg_value2, *(float*)& reg_value3, *(float*)& reg_value4);
if (++regs_in_line >= 1) { this->NewLine(); regs_in_line = 0; }
};
// Prints a general purposes register
auto PrintIntRegister = [PrintRegister](const char* reg_name, size_t reg_value)
{
PrintRegister(reg_name, reg_value, " ");
};
// Prints a segment register
auto PrintSegRegister = [PrintRegister](const char* reg_name, size_t reg_value)
{
PrintRegister(reg_name, reg_value, " ");
};
Print("Register dump:");
EnterScope();
{
// Print main general purposes registers
if (context.ContextFlags & CONTEXT_INTEGER)
{
#if !_M_X64
PrintIntRegister("EAX", context.Eax);
PrintIntRegister("EBX", context.Ebx);
PrintIntRegister("ECX", context.Ecx);
PrintIntRegister("EDX", context.Edx);
PrintIntRegister("EDI", context.Edi);
PrintIntRegister("ESI", context.Esi);
#else
PrintIntRegister("RAX", context.Rax);
PrintIntRegister("RCX", context.Rcx);
PrintIntRegister("RDX", context.Rdx);
PrintIntRegister("RBX", context.Rbx);
PrintIntRegister("RBP", context.Rbp);
PrintIntRegister("RSI", context.Rsi);
PrintIntRegister("RDI", context.Rdi);
PrintIntRegister("R08", context.R8);
PrintIntRegister("R09", context.R9);
PrintIntRegister("R10", context.R10);
PrintIntRegister("R11", context.R11);
PrintIntRegister("R12", context.R12);
PrintIntRegister("R13", context.R13);
PrintIntRegister("R14", context.R14);
PrintIntRegister("R15", context.R15);
#endif
}
// Print control registers
if (context.ContextFlags & CONTEXT_CONTROL)
{
#if !_M_X64
PrintIntRegister("EBP", context.Ebp);
PrintIntRegister("EIP", context.Eip);
PrintIntRegister("ESP", context.Esp);
PrintIntRegister("EFL", context.EFlags);
this->NewLine(); this->NewLine(); regs_in_line = 0;
PrintSegRegister("CS", context.SegCs);
PrintSegRegister("SS", context.SegSs);
#else
PrintIntRegister("RIP", context.Rip);
PrintIntRegister("RSP", context.Rsp);
PrintIntRegister("EFL", context.EFlags);
this->NewLine(); this->NewLine(); regs_in_line = 0;
PrintSegRegister("CS", context.SegCs);
PrintSegRegister("SS", context.SegSs);
#endif
}
this->NewLine(); regs_in_line = 0;
// Print segment registers
if (context.ContextFlags & CONTEXT_SEGMENTS)
{
PrintSegRegister("GS", context.SegGs);
PrintSegRegister("FS", context.SegFs);
this->NewLine(); regs_in_line = 0;
PrintSegRegister("ES", context.SegEs);
PrintSegRegister("DS", context.SegDs);
}
this->NewLine(); this->NewLine(); regs_in_line = 0;
// Print floating point registers
if (context.ContextFlags & CONTEXT_FLOATING_POINT)
{
for (int i = 0; i < 8; i++)
{
#if !_M_X64
auto f = *(M128A*) & (context.FloatSave.RegisterArea[i * 10]);
PrintFloatRegister("ST", i, LODWORD(f.Low), HIDWORD(f.Low), LODWORD(f.High), HIDWORD(f.High));
#else
PrintFloatRegister("ST", i,
LODWORD(context.FltSave.FloatRegisters[i].Low), HIDWORD(context.FltSave.FloatRegisters[i].Low),
LODWORD(context.FltSave.FloatRegisters[i].High), HIDWORD(context.FltSave.FloatRegisters[i].High));
#endif
}
this->NewLine();
for (int i = 0; i < 16; i++)
{
#if !_M_X64
auto f = *(M128A*) & (context.ExtendedRegisters[(i + 10) * 16]);
PrintFloatRegister("XMM", i, LODWORD(f.Low), HIDWORD(f.Low), LODWORD(f.High), HIDWORD(f.High));
if (i >= 7)
break;
#else
PrintFloatRegister("XMM", i,
LODWORD(context.FltSave.XmmRegisters[i].Low), HIDWORD(context.FltSave.XmmRegisters[i].Low),
LODWORD(context.FltSave.XmmRegisters[i].High), HIDWORD(context.FltSave.XmmRegisters[i].High));
#endif
}
}
}
LeaveScope();
}
/*
* PrintStackdump
* Prints the content of the stack into the logging buffer
*/
void ExceptionTracer::PrintStackdump()
{
// We need the ESP of the exception context to execute a stack dump, make sure we have access to it
if ((context.ContextFlags & CONTEXT_CONTROL) == 0)
return;
static const auto align = sizeof_word; // Stack aligment
static const auto max_words_in_line_magic = stackdump_words_per_line + 10;
MEMORY_BASIC_INFORMATION mbi;
#if !_M_X64
uintptr_t base, bottom, top = (uintptr_t)context.Esp;
#else
uintptr_t base, bottom, top = (uintptr_t)context.Rsp;
#endif
auto words_in_line = max_words_in_line_magic;
// Finds the bottom of the stack from it's base pointer
// Note: mbi will get overriden on this function
auto GetStackBottom = [&mbi](uintptr_t base)
{
VirtualQuery((void*)base, &mbi, sizeof(mbi)); // Find uncommited region of the stack
VirtualQuery((char*)mbi.BaseAddress + mbi.RegionSize, &mbi, sizeof(mbi)); // Find guard page
VirtualQuery((char*)mbi.BaseAddress + mbi.RegionSize, &mbi, sizeof(mbi)); // Find commited region of the stack
auto last = (uintptr_t)mbi.BaseAddress;
return (base + (last - base) + mbi.RegionSize); // base + distanceToLastRegion + lastRegionSize
};
// Prints an CPU word at the specified stack address
auto PrintWord = [this, &words_in_line](uintptr_t addr)
{
if (words_in_line++ >= stackdump_words_per_line)
{
// Print new line only if it's not the first time we enter here (i.e. words_in_line has magical value)
if (words_in_line != max_words_in_line_magic + 1) NewLine();
words_in_line = 1;
Print("0x%p: ", addr);
}
Print(" %p", *(size_t*)addr);
};
Print("Stack dump:");
EnterScope();
{
// Makes sure the pointer at top (ESP) is valid and readable memory
if (VirtualQuery((void*)(top), &mbi, sizeof(mbi))
&& (mbi.State & MEM_COMMIT)
&& (mbi.Protect & (PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_READWRITE | PAGE_READONLY)) != 0)
{
base = (uintptr_t)mbi.AllocationBase; // Base of the stack (uncommited)
bottom = GetStackBottom(base); // Bottom of the stack (commited)
// Align the stack top (esp) in a 4 bytes boundary
auto remainder = top % align;
uintptr_t current = remainder ? top + (align - remainder) : top;
// on x86 stack grows downward! (i.e. from bottom to base)
for (int n = 0; n < stackdump_max_words && current < bottom; ++n, current += align)
PrintWord(current);
NewLine();
Print("base: 0x%p top: 0x%p bottom: 0x%p", base, top, bottom);
NewLine();
}
}
LeaveScope();
}
/*
* PrintBacktrace
* Prints a call backtrace into the logging buffer
*/
void ExceptionTracer::PrintBacktrace()
{
StackTracer tracer(this->context);
char module_name[MAX_PATH];
char sym_buffer[sizeof(SYMBOL_INFO) + symbol_max];
int backtrace_count = 0; // Num of frames traced
bool has_symbol_api = false; // True if we have the symbol API available for use
DWORD old_options; // Saves old symbol API options
SYMBOL_INFO& symbol = *(SYMBOL_INFO*)sym_buffer;
symbol.SizeOfStruct = sizeof(SYMBOL_INFO);
symbol.MaxNameLen = symbol_max;
// Tries to get the symbol api
if (SymInitialize(GetCurrentProcess(), 0, TRUE))
{
has_symbol_api = true;
old_options = SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES | SYMOPT_NO_PROMPTS | SYMOPT_FAIL_CRITICAL_ERRORS);
}
Print("Backtrace (may be wrong):");
EnterScope();
{
// Walks on the stack until there's no frame to trace or we traced 'max_backtrace' frames
while (auto trace = tracer.Walk())
{
if (++backtrace_count >= max_backtrace)
break;
bool has_sym = false; // This EIP has a symbol associated with it?
DWORD64 displacement; // EIP displacement relative to symbol
// If we have access to the symbol api, try to get symbol name from pc (eip)
if (has_symbol_api)
has_sym = trace->pc ? !!SymFromAddr(GetCurrentProcess(), (DWORD64)trace->pc, &displacement, &symbol) : false;
// Print everything up, this.... Ew, this looks awful!
Print(backtrace_count == 1 ? "=>" : " "); // First line should have '=>' to specify where it crashed
Print("0x%p ", trace->pc); // Print EIP at frame
if (has_sym) Print("%s+0x%x ", symbol.Name, (DWORD)displacement); // Print frame func symbol
Print("in %s (+0x%x) ", // Print module
trace->module ? FindModuleName(trace->module, module_name, sizeof(module_name)) : "unknown",
(uintptr_t)(trace->pc) - (uintptr_t)(trace->module) // Module displacement
);
if (trace->frame) Print("(0x%p) ", trace->frame); // Print frame pointer
NewLine();
}
}
LeaveScope();
// Cleanup the symbol api
if (has_symbol_api)
{
SymSetOptions(old_options);
SymCleanup(GetCurrentProcess());
}
}
/*
* GetExceptionCodeString
* Returns an description by an exception code
*/
static const char* GetExceptionCodeString(unsigned int code)
{
switch (code)
{
case EXCEPTION_ACCESS_VIOLATION: return "Access violation";
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: return "Array bounds exceeded";
case EXCEPTION_BREAKPOINT: return "Breakpoint exception";
case EXCEPTION_DATATYPE_MISALIGNMENT: return "Data type misalignment exception";
case EXCEPTION_FLT_DENORMAL_OPERAND: return "Denormal float operand";
case EXCEPTION_FLT_DIVIDE_BY_ZERO: return "Floating-point division by zero";
case EXCEPTION_FLT_INEXACT_RESULT: return "Floating-point inexact result";
case EXCEPTION_FLT_INVALID_OPERATION: return "Floating-point invalid operation";
case EXCEPTION_FLT_OVERFLOW: return "Floating-point overflow";
case EXCEPTION_FLT_STACK_CHECK: return "Floating-point stack check";
case EXCEPTION_FLT_UNDERFLOW: return "Floating-point underflow";
case EXCEPTION_ILLEGAL_INSTRUCTION: return "Illegal instruction.";
case EXCEPTION_IN_PAGE_ERROR: return "In page error";
case EXCEPTION_INT_DIVIDE_BY_ZERO: return "Integer division by zero";
case EXCEPTION_INT_OVERFLOW: return "Integer overflow";
case EXCEPTION_INVALID_DISPOSITION: return "Invalid disposition";
case EXCEPTION_NONCONTINUABLE_EXCEPTION: return "Non-continuable exception";
case EXCEPTION_PRIV_INSTRUCTION: return "Privileged instruction";
case EXCEPTION_SINGLE_STEP: return "Single step exception";
case EXCEPTION_STACK_OVERFLOW: return "Stack overflow";
default: return "NO_DESCRIPTION";
}
}
/*
* FindModuleName
* Finds module filename or "unknown"
*/
static const char* FindModuleName(HMODULE module, char* output, DWORD maxsize)
{
if (GetModuleFileNameA(module, output, maxsize))
{
// Finds the filename part in the output string
char* filename = strrchr(output, '\\');
if (!filename) filename = strrchr(output, '/');
// If filename found (i.e. output isn't already a filename but full path), make output be filename
if (filename)
{
size_t size = strlen(++filename);
memmove(output, filename, size);
output[size] = 0;
}
}
else
{
// Unknown module
strcpy(output, "unknown");
}
return output;
}
/*
* GetModuleFromAddress
* Finds module handle from some address inside it
*/
static HMODULE GetModuleFromAddress(LPVOID address)
{
HMODULE module;
if (GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
(char*)address, &module))
return module;
return nullptr;
}
/*
* StackTracer
* Constructs the tracer, we basically need to initialize the symbol api
*/
StackTracer::StackTracer(const CONTEXT& context)
{
// Initialise basic values
memset(&this->frame, 0, sizeof(frame));
memcpy(&this->context, &context, sizeof(context));
// Setup the initial frame context
#if !_M_X64
frame.AddrPC.Mode = AddrModeFlat;
frame.AddrPC.Offset = context.Eip;
frame.AddrFrame.Mode = AddrModeFlat;
frame.AddrFrame.Offset = context.Ebp;
frame.AddrStack.Mode = AddrModeFlat;
frame.AddrStack.Offset = context.Esp;
#else
frame.AddrPC.Mode = AddrModeFlat;
frame.AddrPC.Offset = context.Rip;
frame.AddrFrame.Mode = AddrModeFlat;
frame.AddrFrame.Offset = context.Rbp;
frame.AddrStack.Mode = AddrModeFlat;
frame.AddrStack.Offset = context.Rsp;
#endif
}
/*
* StackTracer::Walk
* Walks on the stack, each walk is one frame of backtrace
* Returns a frame or null if the walk on the park is not possible anymore
*/
StackTracer::Trace* StackTracer::Walk()
{
if (StackWalk64(IMAGE_FILE_MACHINE_I386, GetCurrentProcess(), GetCurrentThread(),
&frame, &context, NULL, NULL, NULL, NULL))
{
trace.module = GetModuleFromAddress((void*)frame.AddrPC.Offset);
trace.frame = (void*)frame.AddrFrame.Offset;
trace.stack = (void*)frame.AddrStack.Offset;
trace.pc = (void*)frame.AddrPC.Offset;
trace.ret = (void*)frame.AddrReturn.Offset;
return &trace;
}
return nullptr;
}
+186
View File
@@ -0,0 +1,186 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{B49C6ABE-931C-4F91-9A94-21A41A305FEE}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>fakedll</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<TargetFrameworkVersion>
</TargetFrameworkVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<CLRSupport>false</CLRSupport>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<TargetName>fakednsapi</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<TargetName>fakednsapi</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>X64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<LanguageStandard>stdcpp17</LanguageStandard>
<AdditionalIncludeDirectories>..\MemoryModule;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<ModuleDefinitionFile>x64.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_DEBUG;PDLOADER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>..\dependencies\MemoryModule;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<ModuleDefinitionFile>x64.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;PDLOADER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<ModuleDefinitionFile>x64.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NDEBUG;PDLOADER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>..\dependencies\MemoryModule;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<ModuleDefinitionFile>x64.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="exception.hpp" />
<ClInclude Include="framework.h" />
<ClInclude Include="ModuleList.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="x64.def" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="framework.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ModuleList.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="exception.hpp">
<Filter>Source Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="x64.def">
<Filter>Source Files</Filter>
</None>
</ItemGroup>
</Project>
+89
View File
@@ -0,0 +1,89 @@
#pragma once
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files
#include <windows.h>
#pragma once
#include <string>
#include <shlobj.h>
#include <set>
#include "ModuleList.h"
#include <intrin.h>
#pragma intrinsic(_ReturnAddress)
struct shared
{
FARPROC DllCanUnloadNow;
FARPROC DllGetClassObject;
FARPROC DllRegisterServer;
FARPROC DllUnregisterServer;
FARPROC DebugSetMute;
void LoadOriginalLibrary(HMODULE dll)
{
DllCanUnloadNow = GetProcAddress(dll, "DllCanUnloadNow");
DllGetClassObject = GetProcAddress(dll, "DllGetClassObject");
DllRegisterServer = GetProcAddress(dll, "DllRegisterServer");
DllUnregisterServer = GetProcAddress(dll, "DllUnregisterServer");
DebugSetMute = GetProcAddress(dll, "DebugSetMute");
}
} shared;
struct dnsapi_dll
{
HMODULE dll;
// only some functions are implemented.
// PDAFT doesn't use many, so this should hopefully be fine
FARPROC DnsFree;
FARPROC DnsQuery_A;
FARPROC DnsQueryEx;
FARPROC DnsCancelQuery;
// DnsQueryEx and DnsCancelQuery take pointers to structs as parameters
// (three for DnsQueryEx and one for DnsCancelQuery)
// fortunately they should fit in registers so the stack doesn't matter
// hopefully this works fine... I have no clue what I'm doing
static LONG WINAPI DnsQueryExStub()
{
return 9004; // DNS_ERROR_RCODE_NOT_IMPLEMENTED
}
static LONG WINAPI DnsCancelQueryStub()
{
return 9004; // DNS_ERROR_RCODE_NOT_IMPLEMENTED
}
void LoadOriginalLibrary(HMODULE module)
{
dll = module;
shared.LoadOriginalLibrary(dll);
DnsFree = GetProcAddress(dll, "DnsFree");
DnsQuery_A = GetProcAddress(dll, "DnsQuery_A");
DnsQueryEx = GetProcAddress(dll, "DnsQueryEx");
DnsCancelQuery = GetProcAddress(dll, "DnsCancelQuery");
// if entry points aren't found, GetProcAddress should return null
// I hope this is correct
// Thanks to somewhatlurker
if (DnsQueryEx == NULL) { DnsQueryEx = (FARPROC)& DnsQueryExStub; };
if (DnsCancelQuery == NULL) { DnsCancelQuery = (FARPROC)& DnsCancelQueryStub; };
}
} dnsapi;
void _DnsFree() { dnsapi.DnsFree(); }
void _DnsQuery_A() { dnsapi.DnsQuery_A(); }
void _DnsQueryEx() { dnsapi.DnsQueryEx(); }
void _DnsCancelQuery() { dnsapi.DnsCancelQuery(); }
#pragma runtime_checks( "", off )
#ifdef _DEBUG
#pragma message ("You are compiling the code in Debug - be warned that wrappers for export functions may not have correct code generated")
#endif
void _DllRegisterServer() { shared.DllRegisterServer(); }
void _DllUnregisterServer() { shared.DllUnregisterServer(); }
void _DllCanUnloadNow() { shared.DllCanUnloadNow(); }
void _DllGetClassObject() { shared.DllGetClassObject(); }
#pragma runtime_checks( "", restore )
+10
View File
@@ -0,0 +1,10 @@
LIBRARY "dnsapi"
EXPORTS
DnsFree = _DnsFree
DnsQuery_A = _DnsQuery_A
DnsQueryEx = _DnsQueryEx
DnsCancelQuery = _DnsCancelQuery
DllCanUnloadNow = _DllCanUnloadNow PRIVATE
DllGetClassObject = _DllGetClassObject PRIVATE
DllRegisterServer = _DllRegisterServer PRIVATE
DllUnregisterServer = _DllUnregisterServer PRIVATE