From 784f155d91c158ba0d17b087e344a09e4eabc73f Mon Sep 17 00:00:00 2001 From: Charles Milette Date: Tue, 2 Mar 2021 04:34:30 -0500 Subject: [PATCH] Feature: Add safe DetoursAttach (and friends) overloads (#178) Fixes #176 I've also added a sample (a copy of the `simple` sample, but without the `(PVOID&)` casts) to validate the functionality. --- samples/Makefile | 8 ++ samples/simple_safe/Makefile | 121 ++++++++++++++++++++++++++++ samples/simple_safe/simple_safe.cpp | 79 ++++++++++++++++++ samples/simple_safe/simple_safe.rc | 17 ++++ samples/simple_safe/sleep5.cpp | 29 +++++++ src/detours.h | 54 +++++++++++++ vc/Detours.vcxproj | 4 + vc/Detours.vcxproj.filters | 15 ++++ 8 files changed, 327 insertions(+) create mode 100644 samples/simple_safe/Makefile create mode 100644 samples/simple_safe/simple_safe.cpp create mode 100644 samples/simple_safe/simple_safe.rc create mode 100644 samples/simple_safe/sleep5.cpp diff --git a/samples/Makefile b/samples/Makefile index 79520954..c2d5c116 100644 --- a/samples/Makefile +++ b/samples/Makefile @@ -21,6 +21,8 @@ all: @$(MAKE) /NOLOGO /$(MAKEFLAGS) cd "$(MAKEDIR)\simple" @$(MAKE) /NOLOGO /$(MAKEFLAGS) + cd "$(MAKEDIR)\simple_safe" + @$(MAKE) /NOLOGO /$(MAKEFLAGS) cd "$(MAKEDIR)\slept" @$(MAKE) /NOLOGO /$(MAKEFLAGS) cd "$(MAKEDIR)\setdll" @@ -96,6 +98,8 @@ clean: @$(MAKE) /NOLOGO /$(MAKEFLAGS) clean cd "$(MAKEDIR)\simple" @$(MAKE) /NOLOGO /$(MAKEFLAGS) clean + cd "$(MAKEDIR)\simple_safe" + @$(MAKE) /NOLOGO /$(MAKEFLAGS) clean cd "$(MAKEDIR)\slept" @$(MAKE) /NOLOGO /$(MAKEFLAGS) clean cd "$(MAKEDIR)\setdll" @@ -162,6 +166,8 @@ realclean: @$(MAKE) /NOLOGO /$(MAKEFLAGS) realclean cd "$(MAKEDIR)\simple" @$(MAKE) /NOLOGO /$(MAKEFLAGS) realclean + cd "$(MAKEDIR)\simple_safe" + @$(MAKE) /NOLOGO /$(MAKEFLAGS) realclean cd "$(MAKEDIR)\slept" @$(MAKE) /NOLOGO /$(MAKEFLAGS) realclean cd "$(MAKEDIR)\setdll" @@ -228,6 +234,8 @@ test: @$(MAKE) /NOLOGO /$(MAKEFLAGS) test cd "$(MAKEDIR)\simple" @$(MAKE) /NOLOGO /$(MAKEFLAGS) test + cd "$(MAKEDIR)\simple_safe" + @$(MAKE) /NOLOGO /$(MAKEFLAGS) test !IF "$(DETOURS_TARGET_PROCESSOR)" != "ARM64" cd "$(MAKEDIR)\slept" @$(MAKE) /NOLOGO /$(MAKEFLAGS) test diff --git a/samples/simple_safe/Makefile b/samples/simple_safe/Makefile new file mode 100644 index 00000000..9782ecdd --- /dev/null +++ b/samples/simple_safe/Makefile @@ -0,0 +1,121 @@ +############################################################################## +## +## API Extention to Measure time slept. +## +## Microsoft Research Detours Package +## +## Copyright (c) Microsoft Corporation. All rights reserved. +## + +!include ..\common.mak + +LIBS=$(LIBS) kernel32.lib +CFLAGS=$(CFLAGS) /std:c++14 + +############################################################################## + +all: dirs \ + $(BIND)\simple_safe$(DETOURS_BITS).dll \ + $(BIND)\sleep5.exe \ + \ +!IF $(DETOURS_SOURCE_BROWSING)==1 + $(OBJD)\simple_safe$(DETOURS_BITS).bsc \ + $(OBJD)\sleep5.bsc \ +!ENDIF + option + +############################################################################## + +dirs: + @if not exist $(BIND) mkdir $(BIND) && echo. Created $(BIND) + @if not exist $(OBJD) mkdir $(OBJD) && echo. Created $(OBJD) + +$(OBJD)\simple_safe.obj : simple_safe.cpp + +$(OBJD)\simple_safe.res : simple_safe.rc + +$(BIND)\simple_safe$(DETOURS_BITS).dll $(BIND)\simple_safe$(DETOURS_BITS).lib: \ + $(OBJD)\simple_safe.obj $(OBJD)\simple_safe.res $(DEPS) + cl /LD $(CFLAGS) /Fe$(@R).dll /Fd$(@R).pdb \ + $(OBJD)\simple_safe.obj $(OBJD)\simple_safe.res \ + /link $(LINKFLAGS) /subsystem:console \ + /export:DetourFinishHelperProcess,@1,NONAME \ + /export:TimedSleepEx \ + $(LIBS) + +$(OBJD)\simple_safe$(DETOURS_BITS).bsc : $(OBJD)\simple_safe.obj + bscmake /v /n /o $@ $(OBJD)\simple_safe.sbr + +$(OBJD)\sleep5.obj : sleep5.cpp + +$(BIND)\sleep5.exe : $(OBJD)\sleep5.obj $(DEPS) + cl $(CFLAGS) /Fe$@ /Fd$(@R).pdb $(OBJD)\sleep5.obj \ + /link $(LINKFLAGS) $(LIBS) \ + /subsystem:console + +$(OBJD)\sleep5.bsc : $(OBJD)\sleep5.obj + bscmake /v /n /o $@ $(OBJD)\sleep5.sbr + +############################################################################## + +clean: + -del *~ 2>nul + -del $(BIND)\simple_safe*.* 2>nul + -del $(BIND)\sleep5.* 2>nul + -rmdir /q /s $(OBJD) 2>nul + +realclean: clean + -rmdir /q /s $(OBJDS) 2>nul + +############################################### Install non-bit-size binaries. + +!IF "$(DETOURS_OPTION_PROCESSOR)" != "" + +$(OPTD)\simple_safe$(DETOURS_OPTION_BITS).dll: +$(OPTD)\simple_safe$(DETOURS_OPTION_BITS).pdb: + +$(BIND)\simple_safe$(DETOURS_OPTION_BITS).dll : $(OPTD)\simple_safe$(DETOURS_OPTION_BITS).dll + @if exist $? copy /y $? $(BIND) >nul && echo $@ copied from $(DETOURS_OPTION_PROCESSOR). +$(BIND)\simple_safe$(DETOURS_OPTION_BITS).pdb : $(OPTD)\simple_safe$(DETOURS_OPTION_BITS).pdb + @if exist $? copy /y $? $(BIND) >nul && echo $@ copied from $(DETOURS_OPTION_PROCESSOR). + +option: \ + $(BIND)\simple_safe$(DETOURS_OPTION_BITS).dll \ + $(BIND)\simple_safe$(DETOURS_OPTION_BITS).pdb \ + +!ELSE + +option: + +!ENDIF + +############################################################################## + +test: all + @echo -------- Reseting test binaries to initial state. --------------------- + $(BIND)\setdll.exe -r $(BIND)\sleep5.exe + @echo. + @echo -------- Should not load simple_safe$(DETOURS_BITS).dll ----------------------------------- + $(BIND)\sleep5.exe + @echo. + @echo -------- Adding simple_safe$(DETOURS_BITS).dll to sleep5.exe ------------------------------ + $(BIND)\setdll.exe -d:$(BIND)\simple_safe$(DETOURS_BITS).dll $(BIND)\sleep5.exe + @echo. + @echo -------- Should load simple_safe$(DETOURS_BITS).dll statically ---------------------------- + $(BIND)\sleep5.exe + @echo. + @echo -------- Removing simple_safe$(DETOURS_BITS).dll from sleep5.exe -------------------------- + $(BIND)\setdll.exe -r $(BIND)\sleep5.exe + @echo. + @echo -------- Should not load simple_safe$(DETOURS_BITS).dll ----------------------------------- + $(BIND)\sleep5.exe + @echo. + @echo -------- Should load simple_safe$(DETOURS_BITS).dll dynamically using withdll.exe---------- + $(BIND)\withdll.exe -d:$(BIND)\simple_safe$(DETOURS_BITS).dll $(BIND)\sleep5.exe + @echo. + +debug: all + windbg -o $(BIND)\withdll.exe -d:$(BIND)\simple_safe$(DETOURS_BITS).dll $(BIND)\sleep5.exe + + +################################################################# End of File. diff --git a/samples/simple_safe/simple_safe.cpp b/samples/simple_safe/simple_safe.cpp new file mode 100644 index 00000000..e994a465 --- /dev/null +++ b/samples/simple_safe/simple_safe.cpp @@ -0,0 +1,79 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Detours Test Program (simple_safe.cpp of simple_safe.dll) +// +// Microsoft Research Detours Package +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// This DLL will detour the Windows SleepEx API so that TimedSleep function +// gets called instead. TimedSleepEx records the before and after times, and +// calls the real SleepEx API through the TrueSleepEx function pointer. +// +// The difference between simple and simple_safe is that simple_safe +// uses the C++ 14 overloads which help prevent mismatching types. +// +#include +#include +#include "detours.h" + +static LONG dwSlept = 0; +static DWORD (WINAPI * TrueSleepEx)(DWORD dwMilliseconds, BOOL bAlertable) = SleepEx; + +DWORD WINAPI TimedSleepEx(DWORD dwMilliseconds, BOOL bAlertable) +{ + DWORD dwBeg = GetTickCount(); + DWORD ret = TrueSleepEx(dwMilliseconds, bAlertable); + DWORD dwEnd = GetTickCount(); + + InterlockedExchangeAdd(&dwSlept, dwEnd - dwBeg); + + return ret; +} + +BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID reserved) +{ + LONG error; + (void)hinst; + (void)reserved; + + if (DetourIsHelperProcess()) { + return TRUE; + } + + if (dwReason == DLL_PROCESS_ATTACH) { + DetourRestoreAfterWith(); + + printf("simple_safe" DETOURS_STRINGIFY(DETOURS_BITS) ".dll:" + " Starting.\n"); + fflush(stdout); + + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + DetourAttach(&TrueSleepEx, TimedSleepEx); + error = DetourTransactionCommit(); + + if (error == NO_ERROR) { + printf("simple_safe" DETOURS_STRINGIFY(DETOURS_BITS) ".dll:" + " Detoured SleepEx().\n"); + } + else { + printf("simple_safe" DETOURS_STRINGIFY(DETOURS_BITS) ".dll:" + " Error detouring SleepEx(): %ld\n", error); + } + } + else if (dwReason == DLL_PROCESS_DETACH) { + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + DetourDetach(&TrueSleepEx, TimedSleepEx); + error = DetourTransactionCommit(); + + printf("simple_safe" DETOURS_STRINGIFY(DETOURS_BITS) ".dll:" + " Removed SleepEx() (result=%ld), slept %ld ticks.\n", error, dwSlept); + fflush(stdout); + } + return TRUE; +} + +// +///////////////////////////////////////////////////////////////// End of File. diff --git a/samples/simple_safe/simple_safe.rc b/samples/simple_safe/simple_safe.rc new file mode 100644 index 00000000..33b568d6 --- /dev/null +++ b/samples/simple_safe/simple_safe.rc @@ -0,0 +1,17 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Version information for simple_safe.rc. +// +// Microsoft Research Detours Package +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// + +#include "detver.h" + +#define VER_INTERNALNAME_STR "simple_safe" DETOURS_STRINGIFY(DETOURS_BITS) +#define VER_ORIGINALFILENAME_STR "simple_safe" DETOURS_STRINGIFY(DETOURS_BITS) ".dll" +#define VER_FILEDESCRIPTION_STR "Detours Test Module" +#define VER_COMPANYNAME_STR "Microsoft Corporation" + +#include "common.ver" diff --git a/samples/simple_safe/sleep5.cpp b/samples/simple_safe/sleep5.cpp new file mode 100644 index 00000000..bb282265 --- /dev/null +++ b/samples/simple_safe/sleep5.cpp @@ -0,0 +1,29 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Detours Test Program (sleep5.cpp of sleep5.exe) +// +// Microsoft Research Detours Package +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// + +#include +#include +#include + +int __cdecl main(int argc, char ** argv) +{ + if (argc == 2) { + Sleep(atoi(argv[1]) * 1000); + } + else { + printf("sleep5.exe: Starting.\n"); + + Sleep(5000); + + printf("sleep5.exe: Done sleeping.\n"); + } + return 0; +} +// +///////////////////////////////////////////////////////////////// End of File. diff --git a/src/detours.h b/src/detours.h index bc044a34..01b881db 100644 --- a/src/detours.h +++ b/src/detours.h @@ -844,6 +844,60 @@ VOID CALLBACK DetourFinishHelperProcess(_In_ HWND, } #endif // __cplusplus +/////////////////////////////////////////////////// Type-safe overloads for C++ +// +#if __cplusplus >= 201402L || _MSVC_LANG >= 201402L +#include + +template +struct DetoursIsFunctionPointer : std::false_type {}; + +template +struct DetoursIsFunctionPointer : std::is_function> {}; + +template< + typename T, + std::enable_if_t::value, int> = 0> +LONG DetourAttach(_Inout_ T *ppPointer, + _In_ T pDetour) noexcept +{ + return DetourAttach( + reinterpret_cast(ppPointer), + reinterpret_cast(pDetour)); +} + +template< + typename T, + std::enable_if_t::value, int> = 0> +LONG DetourAttachEx(_Inout_ T *ppPointer, + _In_ T pDetour, + _Out_opt_ PDETOUR_TRAMPOLINE *ppRealTrampoline, + _Out_opt_ T *ppRealTarget, + _Out_opt_ T *ppRealDetour) noexcept +{ + return DetourAttachEx( + reinterpret_cast(ppPointer), + reinterpret_cast(pDetour), + ppRealTrampoline, + reinterpret_cast(ppRealTarget), + reinterpret_cast(ppRealDetour)); +} + +template< + typename T, + std::enable_if_t::value, int> = 0> +LONG DetourDetach(_Inout_ T *ppPointer, + _In_ T pDetour) noexcept +{ + return DetourDetach( + reinterpret_cast(ppPointer), + reinterpret_cast(pDetour)); +} + +#endif // __cplusplus >= 201402L || _MSVC_LANG >= 201402L +// +////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////// Detours Internal Definitions. // #ifdef __cplusplus diff --git a/vc/Detours.vcxproj b/vc/Detours.vcxproj index 63af3495..9a3f966f 100644 --- a/vc/Detours.vcxproj +++ b/vc/Detours.vcxproj @@ -452,6 +452,8 @@ nmake + + @@ -542,6 +544,7 @@ nmake + @@ -579,6 +582,7 @@ nmake + diff --git a/vc/Detours.vcxproj.filters b/vc/Detours.vcxproj.filters index 75d8dd83..b70aa5b7 100644 --- a/vc/Detours.vcxproj.filters +++ b/vc/Detours.vcxproj.filters @@ -58,6 +58,9 @@ {D9D7E0B0-4E14-473F-AE28-B4A5AF4EB427} + + {1F157B88-D9DA-41E3-9B18-FC5600777FB1} + {88EFC740-5E28-484E-97FC-E7BBA6D36454} @@ -183,6 +186,12 @@ samples\simple + + samples\simple_safe + + + samples\simple_safe + samples\slept @@ -400,6 +409,9 @@ samples\simple + + samples\simple_safe + samples\slept @@ -560,6 +572,9 @@ samples\simple + + samples\simple_safe + samples\slept