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
+3 -2
View File
@@ -1,2 +1,3 @@
This is the source code!
If you just want to play PDAFT, please read the wiki at https://notabug.org/nastys/PD-Loader/wiki
This is the source code! It can NOT be used to play the game!
If you just want to play PDAFT, you downloaded the wrong thing.
Please read the wiki at https://notabug.org/nastys/PD-Loader/wiki for information on getting and installing the latest release.
BIN
View File
Binary file not shown.
+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