diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..1489084 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "Deviare-InProc"] + path = Deviare-InProc + url = https://github.com/nektra/Deviare-InProc.git diff --git a/Deviare-InProc b/Deviare-InProc new file mode 160000 index 0000000..ef115d5 --- /dev/null +++ b/Deviare-InProc @@ -0,0 +1 @@ +Subproject commit ef115d5354f48bf7917c9d529260c3e33a297c5f diff --git a/README.md b/README.md index 037d65c..33435ae 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,13 @@ # WingDbg -Friends don't let friends debug alone +Friends don't let friends debug alone. + + +## !regfix +Fixes that nasty bug in WinDbg that makes it not show any +registers when performing kernel debugging on targets older +than Windows 8 (approximately). Present since around WinDbg version 6.2. + +For more information, see [here][1]. + + + [1]: http://stackoverflow.com/q/35961246/851560 diff --git a/WingDbg.sln b/WingDbg.sln new file mode 100644 index 0000000..9c496a6 --- /dev/null +++ b/WingDbg.sln @@ -0,0 +1,41 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.24720.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WingDbg", "WingDbg\WingDbg.vcxproj", "{FB9DB05A-769F-47BA-B115-9DDA49F82197}" + ProjectSection(ProjectDependencies) = postProject + {7DE03078-DA93-4D66-8164-76277522D3F6} = {7DE03078-DA93-4D66-8164-76277522D3F6} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NktHookLib", "Deviare-InProc\Src\vs2015\NktHookLib.vcxproj", "{7DE03078-DA93-4D66-8164-76277522D3F6}" +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 + {FB9DB05A-769F-47BA-B115-9DDA49F82197}.Debug|x64.ActiveCfg = Debug|x64 + {FB9DB05A-769F-47BA-B115-9DDA49F82197}.Debug|x64.Build.0 = Debug|x64 + {FB9DB05A-769F-47BA-B115-9DDA49F82197}.Debug|x86.ActiveCfg = Debug|Win32 + {FB9DB05A-769F-47BA-B115-9DDA49F82197}.Debug|x86.Build.0 = Debug|Win32 + {FB9DB05A-769F-47BA-B115-9DDA49F82197}.Release|x64.ActiveCfg = Release|x64 + {FB9DB05A-769F-47BA-B115-9DDA49F82197}.Release|x64.Build.0 = Release|x64 + {FB9DB05A-769F-47BA-B115-9DDA49F82197}.Release|x86.ActiveCfg = Release|Win32 + {FB9DB05A-769F-47BA-B115-9DDA49F82197}.Release|x86.Build.0 = Release|Win32 + {7DE03078-DA93-4D66-8164-76277522D3F6}.Debug|x64.ActiveCfg = Debug|x64 + {7DE03078-DA93-4D66-8164-76277522D3F6}.Debug|x64.Build.0 = Debug|x64 + {7DE03078-DA93-4D66-8164-76277522D3F6}.Debug|x86.ActiveCfg = Debug|Win32 + {7DE03078-DA93-4D66-8164-76277522D3F6}.Debug|x86.Build.0 = Debug|Win32 + {7DE03078-DA93-4D66-8164-76277522D3F6}.Release|x64.ActiveCfg = Release|x64 + {7DE03078-DA93-4D66-8164-76277522D3F6}.Release|x64.Build.0 = Release|x64 + {7DE03078-DA93-4D66-8164-76277522D3F6}.Release|x86.ActiveCfg = Release|Win32 + {7DE03078-DA93-4D66-8164-76277522D3F6}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/WingDbg/DbgEngGuids.c b/WingDbg/DbgEngGuids.c new file mode 100644 index 0000000..19fb415 --- /dev/null +++ b/WingDbg/DbgEngGuids.c @@ -0,0 +1,2 @@ +#define INITGUID +#include diff --git a/WingDbg/Exceptions.cpp b/WingDbg/Exceptions.cpp new file mode 100644 index 0000000..f1992b2 --- /dev/null +++ b/WingDbg/Exceptions.cpp @@ -0,0 +1,99 @@ +#include "StdAfx.hpp" + +#include "Exceptions.hpp" + + +namespace WingDbg { +namespace Exceptions { + + +namespace { + +std::string FormatSystemMessage(DWORD message_id) +{ + // ntdll should always be loaded for the lifetime + // of the process. No need to bump the reference count. + HMODULE ntdll_handle = ::GetModuleHandleW(L"ntdll.dll"); + if (NULL == ntdll_handle) + { + THROW_WIN32_EXCEPTION(GetLastError()); + } + + PSTR message_unsafe_ptr = nullptr; + DWORD result = ::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, + ntdll_handle, + message_id, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + reinterpret_cast(&message_unsafe_ptr), + 0, + nullptr); + std::unique_ptr message_ptr(message_unsafe_ptr, &::LocalFree); + if (0 == result) + { + return std::string(); + } + + std::string message(message_ptr.get()); + boost::trim(message); + + return message; +} + +} + + + +std::string to_string(const ComErrorInfo & com_error_info) +{ + std::ostringstream temp; + + temp << "COM error: 0x" << std::hex << com_error_info.value(); + + auto message = FormatSystemMessage(com_error_info.value()); + if (!message.empty()) + { + temp << ", \"" << message << "\""; + } + + temp << std::endl; + + return temp.str(); +} + +std::string to_string(const Win32ErrorInfo & win32_error_info) +{ + std::ostringstream temp; + + temp << "Win32 error: " << win32_error_info.value(); + + auto message = FormatSystemMessage(win32_error_info.value()); + if (!message.empty()) + { + temp << ", \"" << message << "\""; + } + + temp << std::endl; + + return temp.str(); +} + +std::string to_string(const NtErrorInfo & nt_error_info) +{ + std::ostringstream temp; + + temp << "NTSTATUS: 0x" << std::hex << nt_error_info.value(); + + auto message = FormatSystemMessage(nt_error_info.value()); + if (!message.empty()) + { + temp << ", \"" << message << "\""; + } + + temp << std::endl; + + return temp.str(); +} + + +} +} \ No newline at end of file diff --git a/WingDbg/Exceptions.hpp b/WingDbg/Exceptions.hpp new file mode 100644 index 0000000..38cd941 --- /dev/null +++ b/WingDbg/Exceptions.hpp @@ -0,0 +1,48 @@ +#pragma once + +#include "StdAfx.hpp" + + +#define THROW_COM_EXCEPTION(hrResult) \ + BOOST_THROW_EXCEPTION(Exceptions::WingDbgException() << Exceptions::ComErrorInfo(hrResult)) + +#define THROW_WIN32_EXCEPTION(dwError) \ + BOOST_THROW_EXCEPTION(Exceptions::WingDbgException() << Exceptions::Win32ErrorInfo(dwError)) + +#define THROW_NT_EXCEPTION(eNtStatus) \ + BOOST_THROW_EXCEPTION(Exceptions::WingDbgException() << Exceptions::NtErrorInfo(eNtStatus)) + +#define CHECK_HRESULT_AND_THROW(hrResult) \ + do \ + { \ + HRESULT hrResultTemp = (hrResult); \ + if (FAILED(hrResultTemp)) \ + { \ + THROW_COM_EXCEPTION(hrResultTemp); \ + } \ + } while (0) + + +namespace WingDbg { +namespace Exceptions { + + + +typedef boost::error_info ComErrorInfo; +std::string to_string(const ComErrorInfo & com_error_info); + +typedef boost::error_info Win32ErrorInfo; +std::string to_string(const Win32ErrorInfo & win32_error_info); + +typedef boost::error_info NtErrorInfo; +std::string to_string(const NtErrorInfo & nt_error_info); + +typedef boost::error_info ErrorMessage; + +struct WingDbgException : virtual boost::exception, virtual std::exception +{ +}; + + +} +} diff --git a/WingDbg/Exports.cpp b/WingDbg/Exports.cpp new file mode 100644 index 0000000..a450b5a --- /dev/null +++ b/WingDbg/Exports.cpp @@ -0,0 +1,42 @@ +#include "StdAfx.hpp" + +#include "Utils.h" +#include "RegFix.hpp" + + +HRESULT CALLBACK DebugExtensionInitialize( + _Out_ PULONG pnVersion, + _Out_ PULONG pfFlags + ) +{ + UNREFERENCED_PARAMETER(pfFlags); + + if (NULL == pnVersion) + { + return E_INVALIDARG; + } + + *pnVersion = DEBUG_EXTENSION_VERSION(1, 0); + + return S_OK; +} + +HRESULT CALLBACK regfix( + _In_ PDEBUG_CLIENT piClient, + _In_opt_ PCSTR pszArgs + ) +{ + try + { + WingDbg::Extensions::RegFix(piClient, pszArgs); + } + catch (...) + { + (void)::UTILS_OutputString(piClient, + DEBUG_OUTPUT_ERROR, + boost::current_exception_diagnostic_information().c_str()); + return E_FAIL; + } + + return S_OK; +} diff --git a/WingDbg/Exports.def b/WingDbg/Exports.def new file mode 100644 index 0000000..a33eee0 --- /dev/null +++ b/WingDbg/Exports.def @@ -0,0 +1,4 @@ +LIBRARY WingDbg +EXPORTS + DebugExtensionInitialize + regfix diff --git a/WingDbg/RegFix.cpp b/WingDbg/RegFix.cpp new file mode 100644 index 0000000..a58648a --- /dev/null +++ b/WingDbg/RegFix.cpp @@ -0,0 +1,145 @@ +#include "StdAfx.hpp" + +#include "Utils.h" +#include "Exceptions.hpp" + +#include "RegFixHelper.h" + + +namespace po = boost::program_options; + + +namespace WingDbg { +namespace Extensions { + + +namespace { + +struct ProcessHeapDeleter +{ + void operator()(void * memory) + { + ::HeapFree(GetProcessHeap(), 0, memory); + } +}; + +class HookManager final +{ +public: + HookManager(const HookManager & other) = delete; + HookManager & operator=(const HookManager & other) = delete; + ~HookManager() = default; + + static HookManager & GetInstance() + { + static HookManager instance; + + return instance; + } + + void Hook(CComPtr client, bool hook_single) + { + std::lock_guard lock(guard_); + + if (hooked_) + { + BOOST_THROW_EXCEPTION(Exceptions::WingDbgException() << Exceptions::ErrorMessage("Already hooked!")); + } + + // Initialize the low-level state and obtain + // the addresses of the hook functions. + PHOOK_DESCRIPTOR descriptors_unsafe_ptr = nullptr; + DWORD number_descriptors = 0; + CHECK_HRESULT_AND_THROW(::REGFIXHELPER_Initialize(client, hook_single, &descriptors_unsafe_ptr, &number_descriptors)); + std::unique_ptr descriptors(descriptors_unsafe_ptr, ProcessHeapDeleter()); + + // Initialize the array to be passed to the hooking framework. + std::vector hooks(number_descriptors); + for (DWORD index = 0; index < number_descriptors; ++index) + { + hooks[index].lpProcToHook = (PVOID)(DWORD_PTR)(descriptors[index].pfnFunctionToHook); + hooks[index].lpNewProcAddr = (PVOID)(DWORD_PTR)(descriptors[index].pfnHookFunction); + } + + // I love to hook it, hook it! + DWORD error = hook_library_.Hook(hooks.data(), + hooks.size(), + NKTHOOKLIB_DisallowReentrancy | NKTHOOKLIB_SkipNullProcsToHook); + if (ERROR_SUCCESS != error) + { + THROW_WIN32_EXCEPTION(error); + } + + hooked_ = true; + } + + void Unhook() + { + std::lock_guard lock(guard_); + + if (!hooked_) + { + BOOST_THROW_EXCEPTION(Exceptions::WingDbgException() << Exceptions::ErrorMessage("What's not hooked cannot be unhooked!")); + } + + hook_library_.UnhookAll(); + hooked_ = false; + } + +private: + HookManager() : + hooked_(false) + { + } + + std::mutex guard_; + bool hooked_; + CNktHookLib hook_library_; +}; + +} + + +void RegFix(CComPtr client, const std::string & arguments) +{ + po::options_description desc("Allowed options"); + desc.add_options() + ("help,h", "show this help message") + ("single", "also hook the the GetValue method, in addition to GetValues and GetValues2") + ("unhook,u", "uninstall all hooks") + ; + + po::variables_map vm; + po::store(po::command_line_parser(po::split_winmain(arguments)).options(desc).run(), vm); + po::notify(vm); + + if (vm.count("help")) + { + std::ostringstream help_message; + desc.print(help_message); + (void)::UTILS_OutputString(client, DEBUG_OUTPUT_NORMAL, help_message.str().c_str()); + return; + } + + if (vm.count("unhook")) + { + HookManager::GetInstance().Unhook(); + (void)::UTILS_OutputString(client, DEBUG_OUTPUT_NORMAL, "The bugs are back!\n"); + return; + } + + HookManager::GetInstance().Hook(client, (0 != vm.count("single"))); + (void)::UTILS_OutputString(client, + DEBUG_OUTPUT_NORMAL, + "\n" + "Hooked into machine\n" + "Hooked into machine\n" + "Hooked into machine\n" + "I'm hooked into, hooked into\n" + "Machine\n" + "\t(C) Regina Spektor, Far (2009)\n"); +} + + +} +} diff --git a/WingDbg/RegFix.hpp b/WingDbg/RegFix.hpp new file mode 100644 index 0000000..cf07d23 --- /dev/null +++ b/WingDbg/RegFix.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include "StdAfx.hpp" + + +namespace WingDbg { +namespace Extensions { + + +void RegFix(CComPtr client, const std::string & arguments); + + +} +} diff --git a/WingDbg/RegFixHelper.c b/WingDbg/RegFixHelper.c new file mode 100644 index 0000000..2f4b7c6 --- /dev/null +++ b/WingDbg/RegFixHelper.c @@ -0,0 +1,334 @@ +#include +#include + +#include + +#include "Utils.h" +#include "RegFixHelper.h" + + +// +// Enums +// + +typedef enum _HOOK_INDEX +{ + HOOK_INDEX_GET_VALUE = 0, + HOOK_INDEX_GET_VALUES, + HOOK_INDEX_GET_VALUES2, + + // Must be last: + HOOKS_COUNT +} HOOK_INDEX, *PHOOK_INDEX; + + +// +// Globals +// + +FARPROC g_apfnOriginalFunctions[HOOKS_COUNT] = { NULL }; + + +// +// Typedefs +// + +typedef HRESULT(STDMETHODCALLTYPE * PFN_GETVALUE)( + _In_ IDebugRegisters2 * piThis, + _In_ ULONG nRegister, + _Out_ PDEBUG_VALUE ptValue + ); + +typedef HRESULT(STDMETHODCALLTYPE * PFN_GETVALUES)( + _In_ IDebugRegisters2 * piThis, + _In_ ULONG nCount, + _In_reads_opt_(nCount) PULONG pnIndices, + _In_ ULONG nStartIndex, + _Out_writes_(nCount) PDEBUG_VALUE ptValues + ); + +typedef HRESULT(STDMETHODCALLTYPE * PFN_GETVALUES2)( + _In_ IDebugRegisters2 * piThis, + _In_ ULONG eSource, + _In_ ULONG nCount, + _In_reads_opt_(nCount) PULONG pnIndices, + _In_ ULONG nStartIndex, + _Out_writes_(nCount) PDEBUG_VALUE ptValues + ); + + +// +// Functions +// + +static HRESULT regfixhelper_HandleGet( + _In_ IDebugRegisters2 * piDebugRegisters, + _In_ ULONG nCount, + _In_reads_opt_(nCount) PULONG pnIndices, + _In_ ULONG nStartIndex, + _Out_writes_(nCount) PDEBUG_VALUE ptValues + ) +{ + HRESULT hrResult = E_FAIL; + ULONG nBadRegisterIndex = 0; + ULONG nCurrentElement = 0; + ULONG nCurrentRegisterIndex = 0; + + hrResult = piDebugRegisters->lpVtbl->GetIndexByName(piDebugRegisters, + "xcr0", + &nBadRegisterIndex); + if (FAILED(hrResult)) + { + goto lblCleanup; + } + + for (nCurrentElement = 0; nCurrentElement < nCount; ++nCurrentElement) + { + nCurrentRegisterIndex = (NULL == pnIndices) ? (nCurrentElement + nStartIndex) : (pnIndices[nCurrentElement]); + + if (DEBUG_VALUE_INVALID == ptValues[nCurrentElement].Type) + { + if (nCurrentRegisterIndex != nBadRegisterIndex) + { + // Function failed on some other register. + // Be conservative and don't do anything. + hrResult = E_NOTIMPL; + goto lblCleanup; + } + else + { + // This is the bad register. + // Set it to some valid value. + ptValues[nCurrentElement].Type = DEBUG_VALUE_INT32; + ptValues[nCurrentElement].I32 = 0xBADC0DE; + } + } + } + + // Handled! + hrResult = S_OK; + +lblCleanup: + return hrResult; +} + +static HRESULT STDMETHODCALLTYPE regfixhelper_GetValueHook( + _In_ IDebugRegisters2 * piThis, + _In_ ULONG nRegister, + _Out_ PDEBUG_VALUE ptValue + ) +{ + HRESULT hrResult = E_FAIL; + PFN_GETVALUE pfnGetValue = NULL; + + // First, zero the output buffer to parse the results + // when the original method returns + SecureZeroMemory(ptValue, sizeof(*ptValue)); + + // Invoke the original method + pfnGetValue = (PFN_GETVALUE)(g_apfnOriginalFunctions[HOOK_INDEX_GET_VALUE]); + hrResult = pfnGetValue(piThis, nRegister, ptValue); + if (E_INVALIDARG == hrResult) + { + if (SUCCEEDED(regfixhelper_HandleGet(piThis, + 1, + NULL, + nRegister, + ptValue))) + { + // Handled, so return success to the caller. + hrResult = S_OK; + } + } + + // Keep last status + +//lblCleanup: + return hrResult; +} + +static HRESULT STDMETHODCALLTYPE regfixhelper_GetValuesHook( + _In_ IDebugRegisters2 * piThis, + _In_ ULONG nCount, + _In_reads_opt_(nCount) PULONG pnIndices, + _In_ ULONG nStartIndex, + _Out_writes_(nCount) PDEBUG_VALUE ptValues + ) +{ + HRESULT hrResult = E_FAIL; + PFN_GETVALUES pfnGetValues = NULL; + + // First, zero the output buffer to parse the results + // when the original method returns + SecureZeroMemory(ptValues, nCount * sizeof(ptValues[0])); + + // Invoke the original method + pfnGetValues = (PFN_GETVALUES)(g_apfnOriginalFunctions[HOOK_INDEX_GET_VALUES]); + hrResult = pfnGetValues(piThis, nCount, pnIndices, nStartIndex, ptValues); + if (E_INVALIDARG == hrResult) + { + if (SUCCEEDED(regfixhelper_HandleGet(piThis, + nCount, + pnIndices, + nStartIndex, + ptValues))) + { + // Handled, so return success to the caller. + hrResult = S_OK; + } + } + + // Keep last status + +//lblCleanup: + return hrResult; +} + +static HRESULT STDMETHODCALLTYPE regfixhelper_GetValues2Hook( + _In_ IDebugRegisters2 * piThis, + _In_ ULONG eSource, + _In_ ULONG nCount, + _In_reads_opt_(nCount) PULONG pnIndices, + _In_ ULONG nStartIndex, + _Out_writes_(nCount) PDEBUG_VALUE ptValues + ) +{ + HRESULT hrResult = E_FAIL; + PFN_GETVALUES2 pfnGetValues2 = NULL; + + // First, zero the output buffer to parse the results + // when the original method returns + SecureZeroMemory(ptValues, nCount * sizeof(ptValues[0])); + + // Invoke the original method + pfnGetValues2 = (PFN_GETVALUES2)(g_apfnOriginalFunctions[HOOK_INDEX_GET_VALUES2]); + hrResult = pfnGetValues2(piThis, eSource, nCount, pnIndices, nStartIndex, ptValues); + if (E_INVALIDARG == hrResult) + { + if (SUCCEEDED(regfixhelper_HandleGet(piThis, + nCount, + pnIndices, + nStartIndex, + ptValues))) + { + // Handled, so return success to the caller. + hrResult = S_OK; + } + } + + // Keep last status + +//lblCleanup: + return hrResult; +} + +static HRESULT regfixhelper_ObtainInterface( + _In_ IDebugClient * piClient, + _COM_Outptr_ IDebugRegisters2 ** ppiDebugRegisters2 + ) +{ + HRESULT hrResult = E_FAIL; + IDebugRegisters * piDebugRegisters = NULL; + IDebugRegisters2 * piDebugRegisters2 = NULL; + + assert(NULL != piClient); + assert(NULL != ppiDebugRegisters2); + + // COM pointers should be NULL on failure. + *ppiDebugRegisters2 = NULL; + + hrResult = piClient->lpVtbl->QueryInterface(piClient, &IID_IDebugRegisters, &piDebugRegisters); + if (FAILED(hrResult)) + { + goto lblCleanup; + } + + hrResult = piClient->lpVtbl->QueryInterface(piClient, &IID_IDebugRegisters2, &piDebugRegisters2); + if (FAILED(hrResult)) + { + goto lblCleanup; + } + + if ((PVOID)(piDebugRegisters->lpVtbl) != (PVOID)(piDebugRegisters2->lpVtbl)) + { + (VOID)UTILS_OutputString(piClient, + DEBUG_OUTPUT_EXTENSION_WARNING, + "Huh? IDebugRegisters and IDebugRegisters2 are implemented by two separate objects.\n"); + } + + // Transfer ownership: + *ppiDebugRegisters2 = piDebugRegisters2; + piDebugRegisters2 = NULL; + + hrResult = S_OK; + +lblCleanup: + RELEASE_INTERFACE(piDebugRegisters2); + RELEASE_INTERFACE(piDebugRegisters); + + return hrResult; +} + +HRESULT REGFIXHELPER_Initialize( + _In_ IDebugClient * piClient, + _In_ BOOL bHookSingle, + _Outptr_result_buffer_(*pnHooks) PHOOK_DESCRIPTOR * pptDescriptors, + _Out_ PDWORD pnHooks + ) +{ + HRESULT hrResult = E_FAIL; + IDebugRegisters2 * piDebugRegisters2 = NULL; + PHOOK_DESCRIPTOR ptDescriptors = NULL; + + if ((NULL == piClient) || + (NULL == pptDescriptors) || + (NULL == pnHooks)) + { + hrResult = E_INVALIDARG; + goto lblCleanup; + } + + hrResult = regfixhelper_ObtainInterface(piClient, &piDebugRegisters2); + if (FAILED(hrResult)) + { + goto lblCleanup; + } + + ptDescriptors = HEAPALLOC(HOOKS_COUNT * sizeof(ptDescriptors[0])); + if (NULL == ptDescriptors) + { + hrResult = E_OUTOFMEMORY; + goto lblCleanup; + } + + // GetValue + if (bHookSingle) + { + g_apfnOriginalFunctions[HOOK_INDEX_GET_VALUE] = (FARPROC)(piDebugRegisters2->lpVtbl->GetValue); + ptDescriptors[HOOK_INDEX_GET_VALUE].pfnFunctionToHook = (FARPROC)(piDebugRegisters2->lpVtbl->GetValue); + ptDescriptors[HOOK_INDEX_GET_VALUE].pfnHookFunction = (FARPROC)®fixhelper_GetValueHook; + } + + // GetValues + g_apfnOriginalFunctions[HOOK_INDEX_GET_VALUES] = (FARPROC)(piDebugRegisters2->lpVtbl->GetValues); + ptDescriptors[HOOK_INDEX_GET_VALUES].pfnFunctionToHook = (FARPROC)(piDebugRegisters2->lpVtbl->GetValues); + ptDescriptors[HOOK_INDEX_GET_VALUES].pfnHookFunction = (FARPROC)®fixhelper_GetValuesHook; + + // GetValues2 + g_apfnOriginalFunctions[HOOK_INDEX_GET_VALUES2] = (FARPROC)(piDebugRegisters2->lpVtbl->GetValues2); + ptDescriptors[HOOK_INDEX_GET_VALUES2].pfnFunctionToHook = (FARPROC)(piDebugRegisters2->lpVtbl->GetValues2); + ptDescriptors[HOOK_INDEX_GET_VALUES2].pfnHookFunction = (FARPROC)®fixhelper_GetValues2Hook; + + // Transfer ownership: + *pptDescriptors = ptDescriptors; + ptDescriptors = NULL; + *pnHooks = HOOKS_COUNT; + + hrResult = S_OK; + +lblCleanup: + HEAPFREE(ptDescriptors); + RELEASE_INTERFACE(piDebugRegisters2); + + return hrResult; +} diff --git a/WingDbg/RegFixHelper.h b/WingDbg/RegFixHelper.h new file mode 100644 index 0000000..62903f9 --- /dev/null +++ b/WingDbg/RegFixHelper.h @@ -0,0 +1,41 @@ +#pragma once + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#if 0 +} +#endif +#endif // __cplusplus + + +// +// Typedefs +// + +typedef struct _HOOK_DESCRIPTOR +{ + FARPROC pfnFunctionToHook; + FARPROC pfnHookFunction; +} HOOK_DESCRIPTOR, *PHOOK_DESCRIPTOR; + + +// +// Functions +// + +HRESULT REGFIXHELPER_Initialize( + _In_ IDebugClient * piClient, + _In_ BOOL bHookSingle, + _Outptr_result_buffer_(*pnHooks) PHOOK_DESCRIPTOR * pptDescriptors, + _Out_ PDWORD pnHooks + ); + + +#ifdef __cplusplus +} +#endif // __cplusplus + diff --git a/WingDbg/StdAfx.cpp b/WingDbg/StdAfx.cpp new file mode 100644 index 0000000..d4f62d3 --- /dev/null +++ b/WingDbg/StdAfx.cpp @@ -0,0 +1 @@ +#include "StdAfx.hpp" diff --git a/WingDbg/StdAfx.hpp b/WingDbg/StdAfx.hpp new file mode 100644 index 0000000..c6d7903 --- /dev/null +++ b/WingDbg/StdAfx.hpp @@ -0,0 +1,22 @@ +#pragma once + +#define WIN32_NO_STATUS +#include +#undef WIN32_NO_STATUS + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include diff --git a/WingDbg/Utils.c b/WingDbg/Utils.c new file mode 100644 index 0000000..d66007b --- /dev/null +++ b/WingDbg/Utils.c @@ -0,0 +1,52 @@ +#include +#include + +#include + +#include "Utils.h" + + +HRESULT UTILS_OutputString( + _In_ IDebugClient * piClient, + _In_ ULONG nMask, + _In_ PCSTR pszFormat, + ... + ) +{ + HRESULT hrResult = E_FAIL; + IDebugControl * piDebugControl = NULL; + va_list vaArguments = NULL; + BOOL bArgsInitialized = FALSE; + + hrResult = piClient->lpVtbl->QueryInterface(piClient, + &IID_IDebugControl, + &piDebugControl); + if (FAILED(hrResult)) + { + goto lblCleanup; + } + + va_start(vaArguments, pszFormat); + bArgsInitialized = TRUE; + + hrResult = piDebugControl->lpVtbl->OutputVaList(piDebugControl, + nMask, + pszFormat, + vaArguments); + if (FAILED(hrResult)) + { + goto lblCleanup; + } + + hrResult = S_OK; + +lblCleanup: + if (bArgsInitialized) + { + va_end(vaArguments); + bArgsInitialized = FALSE; + } + RELEASE_INTERFACE(piDebugControl); + + return hrResult; +} diff --git a/WingDbg/Utils.h b/WingDbg/Utils.h new file mode 100644 index 0000000..a7fd63f --- /dev/null +++ b/WingDbg/Utils.h @@ -0,0 +1,56 @@ +#pragma once + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#if 0 +} +#endif +#endif // __cplusplus + + +// +// Macros +// + +#define HEAPALLOC(cbSize) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (cbSize)) + +#define HEAPFREE(pvMemory) \ + do \ + { \ + if (NULL != (pvMemory)) \ + { \ + HeapFree(GetProcessHeap(), 0, (pvMemory)); \ + (pvMemory) = NULL; \ + } \ + } while (0) + +#define RELEASE_INTERFACE(piInterface) \ + do \ + { \ + if (NULL != (piInterface)) \ + { \ + (VOID)((piInterface)->lpVtbl->Release(piInterface)); \ + (piInterface) = NULL; \ + } \ + } while (0) + + +// +// Functions +// + +HRESULT UTILS_OutputString( + _In_ IDebugClient * piClient, + _In_ ULONG nMask, + _In_ PCSTR pszFormat, + ... + ); + + +#ifdef __cplusplus +} +#endif // __cplusplus diff --git a/WingDbg/WingDbg.vcxproj b/WingDbg/WingDbg.vcxproj new file mode 100644 index 0000000..4c2ce5a --- /dev/null +++ b/WingDbg/WingDbg.vcxproj @@ -0,0 +1,204 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {FB9DB05A-769F-47BA-B115-9DDA49F82197} + Win32Proj + WingDbg + 8.1 + WingDbg + + + + DynamicLibrary + true + v140_xp + Unicode + + + DynamicLibrary + false + v140_xp + true + Unicode + + + + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + false + false + + + + Level4 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;WINGDBG_EXPORTS;%(PreprocessorDefinitions) + true + ProgramDatabase + true + Guard + true + MultiThreadedDebug + false + Use + StdAfx.hpp + $(SolutionDir)Deviare-InProc\Include;%(AdditionalIncludeDirectories) + + + Windows + Debug + true + true + true + false + true + Exports.def + + + + + Level4 + Disabled + _DEBUG;_WINDOWS;_USRDLL;WINGDBG_EXPORTS;%(PreprocessorDefinitions) + ProgramDatabase + false + true + Guard + true + MultiThreadedDebug + false + Use + StdAfx.hpp + $(SolutionDir)Deviare-InProc\Include;%(AdditionalIncludeDirectories) + true + + + Windows + Debug + true + true + true + false + Exports.def + + + + + Level4 + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;WINGDBG_EXPORTS;%(PreprocessorDefinitions) + true + true + None + AnySuitable + Speed + true + true + Guard + MultiThreaded + $(SolutionDir)Deviare-InProc\Include;%(AdditionalIncludeDirectories) + + + Windows + true + true + No + true + UseLinkTimeCodeGeneration + false + Exports.def + + + + + Level4 + MaxSpeed + true + true + NDEBUG;_WINDOWS;_USRDLL;WINGDBG_EXPORTS;%(PreprocessorDefinitions) + true + None + AnySuitable + Speed + true + true + Guard + MultiThreaded + $(SolutionDir)Deviare-InProc\Include;%(AdditionalIncludeDirectories) + true + + + Windows + true + true + No + true + UseLinkTimeCodeGeneration + false + Exports.def + + + + + + + NotUsing + + + NotUsing + + + + Create + + + NotUsing + + + + + + + + + + + + + + + + {7de03078-da93-4d66-8164-76277522d3f6} + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + \ No newline at end of file diff --git a/WingDbg/WingDbg.vcxproj.filters b/WingDbg/WingDbg.vcxproj.filters new file mode 100644 index 0000000..30741a4 --- /dev/null +++ b/WingDbg/WingDbg.vcxproj.filters @@ -0,0 +1,69 @@ + + + + + {ca8b4467-1f63-48bc-87f4-cff295cde829} + + + {11058101-afb0-4e8f-8196-10fdd3e4237d} + + + {10813afc-d4d5-401d-aaf9-2f1652b8c708} + + + {faa2a103-143a-490c-ad0d-7d73c73c27d0} + + + {056d14e0-94f6-4479-80cc-eb2e560d2a40} + + + {ced99964-ddef-4213-866b-0372c5f7e4b0} + + + + + Exports + + + Exceptions + + + PCH + + + Extensions\RegFix + + + Extensions\RegFix + + + Utils + + + Utils + + + + + Exports + + + + + + Exceptions + + + PCH + + + Extensions\RegFix + + + Extensions\RegFix + + + Utils + + + \ No newline at end of file diff --git a/WingDbg/packages.config b/WingDbg/packages.config new file mode 100644 index 0000000..3a9592f --- /dev/null +++ b/WingDbg/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file