├── .gitignore ├── Detours ├── Detours.vcxproj ├── Detours.vcxproj.filters └── src │ ├── DetoursNotify.cpp │ ├── DetoursNotify.h │ ├── Makefile │ ├── creatwth.cpp │ ├── detours.cpp │ ├── detours.h │ ├── detours_patch.cpp │ ├── detver.h │ ├── disasm.cpp │ ├── disolarm.cpp │ ├── disolarm64.cpp │ ├── disolia64.cpp │ ├── disolx64.cpp │ ├── disolx86.cpp │ ├── image.cpp │ ├── mem_patch.cpp │ ├── mem_patch.h │ ├── modules.cpp │ ├── uimports.cpp │ └── windows_shim.h ├── DetoursTest.sln ├── DetoursTest ├── DetoursTest.cpp ├── DetoursTest.vcxproj └── DetoursTest.vcxproj.filters ├── LICENSE ├── README.md └── config.props /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | *.user 10 | 11 | # Precompiled Headers 12 | *.gch 13 | *.pch 14 | 15 | # Compiled Dynamic libraries 16 | *.so 17 | *.dylib 18 | *.dll 19 | 20 | # Fortran module files 21 | *.mod 22 | *.smod 23 | 24 | # Compiled Static libraries 25 | *.lai 26 | *.la 27 | *.a 28 | *.lib 29 | 30 | # Executables 31 | *.exe 32 | *.out 33 | *.app 34 | 35 | #Exception dir 36 | .vs 37 | .git -------------------------------------------------------------------------------- /Detours/Detours.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | ARM 7 | 8 | 9 | Debug 10 | ARM64 11 | 12 | 13 | Debug 14 | Win32 15 | 16 | 17 | Release 18 | ARM 19 | 20 | 21 | Release 22 | ARM64 23 | 24 | 25 | Release 26 | Win32 27 | 28 | 29 | Debug 30 | x64 31 | 32 | 33 | Release 34 | x64 35 | 36 | 37 | 38 | 39 | 40 | true 41 | true 42 | true 43 | true 44 | true 45 | true 46 | true 47 | true 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 15.0 65 | {3B8C6EDE-D8B8-4297-94A4-30C90A850F12} 66 | Win32Proj 67 | Detours 68 | 10.0.17763.0 69 | 70 | 71 | 72 | StaticLibrary 73 | true 74 | v141_xp 75 | Unicode 76 | false 77 | 78 | 79 | StaticLibrary 80 | true 81 | v141 82 | Unicode 83 | false 84 | 85 | 86 | StaticLibrary 87 | true 88 | v141 89 | Unicode 90 | false 91 | 92 | 93 | StaticLibrary 94 | false 95 | v141_xp 96 | true 97 | Unicode 98 | false 99 | 100 | 101 | StaticLibrary 102 | false 103 | v141 104 | true 105 | Unicode 106 | false 107 | 108 | 109 | StaticLibrary 110 | false 111 | v141 112 | true 113 | Unicode 114 | false 115 | 116 | 117 | StaticLibrary 118 | true 119 | v141_xp 120 | Unicode 121 | false 122 | 123 | 124 | StaticLibrary 125 | false 126 | v141_xp 127 | true 128 | Unicode 129 | false 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | true 171 | 172 | 173 | true 174 | 175 | 176 | true 177 | 178 | 179 | true 180 | 181 | 182 | false 183 | 184 | 185 | false 186 | 187 | 188 | false 189 | 190 | 191 | false 192 | 193 | 194 | 195 | NotUsing 196 | Level3 197 | Disabled 198 | 199 | 200 | WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) 201 | 202 | 203 | MultiThreadedDebug 204 | false 205 | true 206 | 207 | 208 | Windows 209 | true 210 | 211 | 212 | 213 | 214 | NotUsing 215 | Level3 216 | Disabled 217 | 218 | 219 | WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) 220 | 221 | 222 | MultiThreadedDebug 223 | false 224 | true 225 | 226 | 227 | Windows 228 | true 229 | 230 | 231 | 232 | 233 | NotUsing 234 | Level3 235 | Disabled 236 | 237 | 238 | WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) 239 | 240 | 241 | MultiThreadedDebug 242 | false 243 | true 244 | 245 | 246 | Windows 247 | true 248 | 249 | 250 | 251 | 252 | NotUsing 253 | Level3 254 | Disabled 255 | 256 | 257 | _DEBUG;_LIB;%(PreprocessorDefinitions) 258 | 259 | 260 | MultiThreadedDebug 261 | false 262 | true 263 | 264 | 265 | Windows 266 | true 267 | 268 | 269 | 270 | 271 | NotUsing 272 | Level3 273 | MaxSpeed 274 | true 275 | true 276 | 277 | 278 | WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) 279 | 280 | 281 | MultiThreaded 282 | false 283 | true 284 | 285 | 286 | Windows 287 | true 288 | true 289 | true 290 | 291 | 292 | 293 | 294 | NotUsing 295 | Level3 296 | MaxSpeed 297 | true 298 | true 299 | 300 | 301 | WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) 302 | 303 | 304 | MultiThreaded 305 | false 306 | true 307 | 308 | 309 | Windows 310 | true 311 | true 312 | true 313 | 314 | 315 | 316 | 317 | NotUsing 318 | Level3 319 | MaxSpeed 320 | true 321 | true 322 | 323 | 324 | WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) 325 | 326 | 327 | MultiThreaded 328 | false 329 | true 330 | 331 | 332 | Windows 333 | true 334 | true 335 | true 336 | 337 | 338 | 339 | 340 | NotUsing 341 | Level3 342 | MaxSpeed 343 | true 344 | true 345 | 346 | 347 | NDEBUG;_LIB;%(PreprocessorDefinitions) 348 | 349 | 350 | MultiThreaded 351 | false 352 | true 353 | 354 | 355 | Windows 356 | true 357 | true 358 | true 359 | 360 | 361 | 362 | 363 | 364 | -------------------------------------------------------------------------------- /Detours/Detours.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {052c3ff8-1732-4f83-acee-8e25f57f3c72} 18 | 19 | 20 | {9aee9e28-9e23-4b40-b0cd-2e79a28293ef} 21 | 22 | 23 | 24 | 25 | 源文件 26 | 27 | 28 | DeeoursNotify 29 | 30 | 31 | patch 32 | 33 | 34 | patch 35 | 36 | 37 | 源文件 38 | 39 | 40 | 41 | 42 | 头文件 43 | 44 | 45 | 头文件 46 | 47 | 48 | DeeoursNotify 49 | 50 | 51 | patch 52 | 53 | 54 | patch 55 | 56 | 57 | 58 | 59 | 资源文件 60 | 61 | 62 | -------------------------------------------------------------------------------- /Detours/src/DetoursNotify.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxxzhang/DetoursEx/194f97661acde8d2f44428733888f805b2fb765c/Detours/src/DetoursNotify.cpp -------------------------------------------------------------------------------- /Detours/src/DetoursNotify.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxxzhang/DetoursEx/194f97661acde8d2f44428733888f805b2fb765c/Detours/src/DetoursNotify.h -------------------------------------------------------------------------------- /Detours/src/Makefile: -------------------------------------------------------------------------------- 1 | ############################################################################## 2 | ## 3 | ## Makefile for Detours. 4 | ## 5 | ## Microsoft Research Detours Package, Version 4.0.1 6 | ## 7 | ## Copyright (c) Microsoft Corporation. All rights reserved. 8 | ## 9 | 10 | ROOT = .. 11 | !include "$(ROOT)\system.mak" 12 | 13 | !IF "$(DETOURS_SOURCE_BROWSING)" == "" 14 | DETOURS_SOURCE_BROWSING = 0 15 | !ENDIF 16 | 17 | #######################/####################################################### 18 | ## 19 | CFLAGS=/nologo /W4 /WX /we4777 /we4800 /Zi /MT /Gy /Gm- /Zl /Od /DDETOUR_DEBUG=$(DETOURS_DEBUG) 20 | 21 | !IF $(DETOURS_SOURCE_BROWSING)==1 22 | CFLAGS=$(CFLAGS) /FR 23 | !ELSE 24 | CFLAGS=$(CFLAGS) /DWIN32_LEAN_AND_MEAN /D_WIN32_WINNT=0x501 25 | !ENDIF 26 | 27 | !IF "$(DETOURS_TARGET_PROCESSOR)" == "IA64" 28 | CFLAGS=$(CFLAGS) /wd4163 # intrinsic rdtebex not available; using newer Windows headers with older compiler 29 | !ENDIF 30 | 31 | !if defined(DETOURS_WIN_7) && defined(DETOURS_CL_17_OR_NEWER) 32 | CFLAGS=$(CFLAGS) /D_USING_V110_SDK71_ 33 | !elseif defined(DETOURS_ANALYZE) 34 | CFLAGS=$(CFLAGS) /analyze 35 | !endif 36 | 37 | OBJS = \ 38 | $(OBJD)\detours.obj \ 39 | $(OBJD)\modules.obj \ 40 | $(OBJD)\disasm.obj \ 41 | $(OBJD)\image.obj \ 42 | $(OBJD)\creatwth.obj \ 43 | $(OBJD)\disolx86.obj \ 44 | $(OBJD)\disolx64.obj \ 45 | $(OBJD)\disolia64.obj \ 46 | $(OBJD)\disolarm.obj \ 47 | $(OBJD)\disolarm64.obj \ 48 | 49 | ############################################################################## 50 | ## 51 | .SUFFIXES: .cpp .h .obj 52 | 53 | !ifdef DETOURS_ANALYZE 54 | .cpp{$(OBJD)}.obj: 55 | $(CC) $(CFLAGS) /Fd$(LIBD)\detours.pdb /Fo$(OBJD)\ /c $< 56 | !else 57 | .cpp{$(OBJD)}.obj:: 58 | $(CC) $(CFLAGS) /Fd$(LIBD)\detours.pdb /Fo$(OBJD)\ /c $< 59 | !endif 60 | 61 | ############################################################################## 62 | 63 | all: dirs \ 64 | $(LIBD)\detours.lib \ 65 | $(INCD)\detours.h \ 66 | $(INCD)\detver.h \ 67 | !IF $(DETOURS_SOURCE_BROWSING)==1 68 | $(OBJD)\detours.bsc \ 69 | !endif 70 | 71 | ############################################################################## 72 | 73 | clean: 74 | -del *~ 2>nul 75 | -del $(LIBD)\detours.pdb $(LIBD)\detours.lib 2>nul 76 | -rmdir /q /s $(OBJD) 2>nul 77 | 78 | realclean: clean 79 | -rmdir /q /s $(OBJDS) 2>nul 80 | 81 | ############################################################################## 82 | 83 | dirs: 84 | @if not exist "$(INCD)" mkdir "$(INCD)" && echo. Created $(INCD) 85 | @if not exist "$(LIBD)" mkdir "$(LIBD)" && echo. Created $(LIBD) 86 | @if not exist "$(BIND)" mkdir "$(BIND)" && echo. Created $(BIND) 87 | @if not exist "$(OBJD)" mkdir "$(OBJD)" && echo. Created $(OBJD) 88 | 89 | $(OBJD)\detours.bsc : $(OBJS) 90 | bscmake /v /n /o $@ $(OBJS:.obj=.sbr) 91 | 92 | $(LIBD)\detours.lib : $(OBJS) 93 | link /lib /out:$@ /nologo $(OBJS) 94 | 95 | $(INCD)\detours.h : detours.h 96 | copy detours.h $@ 97 | 98 | $(INCD)\detver.h : detver.h 99 | copy detver.h $@ 100 | 101 | $(OBJD)\detours.obj : detours.cpp detours.h 102 | $(OBJD)\modules.obj : modules.cpp detours.h 103 | $(OBJD)\disasm.obj : disasm.cpp detours.h 104 | $(OBJD)\image.obj : image.cpp detours.h 105 | $(OBJD)\creatwth.obj : creatwth.cpp uimports.cpp detours.h 106 | $(OBJD)\disolx86.obj: disasm.cpp detours.h 107 | $(OBJD)\disolx64.obj: disasm.cpp detours.h 108 | $(OBJD)\disolia64.obj: disasm.cpp detours.h 109 | $(OBJD)\disolarm.obj: disasm.cpp detours.h 110 | $(OBJD)\disolarm64.obj: disasm.cpp detours.h 111 | 112 | test: all 113 | cd $(MAKEDIR)\..\samples\slept 114 | nmake /nologo test 115 | cd $(MAKEDIR) 116 | 117 | ################################################################# End of File. 118 | -------------------------------------------------------------------------------- /Detours/src/detours.h: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Core Detours Functionality (detours.h of detours.lib) 4 | // 5 | // Microsoft Research Detours Package, Version 4.0.1 6 | // 7 | // Copyright (c) Microsoft Corporation. All rights reserved. 8 | // 9 | 10 | #pragma once 11 | #ifndef _DETOURS_H_ 12 | #define _DETOURS_H_ 13 | 14 | #define DETOURS_VERSION 0x4c0c1 // 0xMAJORcMINORcPATCH 15 | 16 | ////////////////////////////////////////////////////////////////////////////// 17 | // 18 | 19 | #include "windows_shim.h" 20 | #include "mem_patch.h" 21 | 22 | #ifdef DETOURS_INTERNAL 23 | 24 | #define _CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS 1 25 | #ifndef _ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE 26 | #define _ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE 1 27 | #endif 28 | 29 | #pragma warning(disable:4068) // unknown pragma (suppress) 30 | 31 | #if _MSC_VER >= 1900 32 | #pragma warning(push) 33 | #pragma warning(disable:4091) // empty typedef 34 | #endif 35 | 36 | // Suppress declspec(dllimport) for the sake of Detours 37 | // users that provide kernel32 functionality themselves. 38 | // This is ok in the mainstream case, it will just cost 39 | // an extra instruction calling some functions, which 40 | // LTCG optimizes away. 41 | // 42 | #define _KERNEL32_ 1 43 | #define _USER32_ 1 44 | 45 | #endif // DETOURS_INTERNAL 46 | 47 | ////////////////////////////////////////////////////////////////////////////// 48 | // 49 | 50 | #undef DETOURS_X64 51 | #undef DETOURS_X86 52 | #undef DETOURS_IA64 53 | #undef DETOURS_ARM 54 | #undef DETOURS_ARM64 55 | #undef DETOURS_BITS 56 | #undef DETOURS_32BIT 57 | #undef DETOURS_64BIT 58 | 59 | #if defined(_X86_) 60 | #define DETOURS_X86 61 | #define DETOURS_OPTION_BITS 64 62 | 63 | #elif defined(_AMD64_) 64 | #define DETOURS_X64 65 | #define DETOURS_OPTION_BITS 32 66 | 67 | #elif defined(_IA64_) 68 | #define DETOURS_IA64 69 | #define DETOURS_OPTION_BITS 32 70 | 71 | #elif defined(_ARM_) 72 | #define DETOURS_ARM 73 | 74 | #elif defined(_ARM64_) 75 | #define DETOURS_ARM64 76 | 77 | #else 78 | #error Unknown architecture (x86, amd64, ia64, arm, arm64) 79 | #endif 80 | 81 | #if defined(DETOURS_ARM64) || defined(DETOURS_X64) || defined(DETOURS_IA64) 82 | #undef DETOURS_32BIT 83 | #define DETOURS_64BIT 1 84 | #define DETOURS_BITS 64 85 | // If all 64bit kernels can run one and only one 32bit architecture. 86 | //#define DETOURS_OPTION_BITS 32 87 | #else 88 | #define DETOURS_32BIT 1 89 | #undef DETOURS_64BIT 90 | #define DETOURS_BITS 32 91 | // If all 64bit kernels can run one and only one 32bit architecture. 92 | //#define DETOURS_OPTION_BITS 32 93 | #endif 94 | 95 | /////////////////////////////////////////////////////////////// Helper Macros. 96 | // 97 | #define DETOURS_STRINGIFY_(x) #x 98 | #define DETOURS_STRINGIFY(x) DETOURS_STRINGIFY_(x) 99 | 100 | #define VER_DETOURS_BITS DETOURS_STRINGIFY(DETOURS_BITS) 101 | 102 | ////////////////////////////////////////////////////////////////////////////// 103 | // 104 | ///////////////////////////////////////////////// SAL 2.0 Annotations w/o SAL. 105 | // 106 | // These definitions are include so that Detours will build even if the 107 | // compiler doesn't have full SAL 2.0 support. 108 | // 109 | #ifndef DETOURS_DONT_REMOVE_SAL_20 110 | 111 | #ifdef DETOURS_TEST_REMOVE_SAL_20 112 | #undef _Analysis_assume_ 113 | #undef _Benign_race_begin_ 114 | #undef _Benign_race_end_ 115 | #undef _Field_range_ 116 | #undef _Field_size_ 117 | #undef _In_ 118 | #undef _In_bytecount_ 119 | #undef _In_count_ 120 | #undef __in_ecount 121 | #undef _In_opt_ 122 | #undef _In_opt_bytecount_ 123 | #undef _In_opt_count_ 124 | #undef _In_opt_z_ 125 | #undef _In_range_ 126 | #undef _In_reads_ 127 | #undef _In_reads_bytes_ 128 | #undef _In_reads_opt_ 129 | #undef _In_reads_opt_bytes_ 130 | #undef _In_reads_or_z_ 131 | #undef _In_z_ 132 | #undef _Inout_ 133 | #undef _Inout_opt_ 134 | #undef _Inout_z_count_ 135 | #undef _Out_ 136 | #undef _Out_opt_ 137 | #undef _Out_writes_ 138 | #undef _Outptr_result_maybenull_ 139 | #undef _Readable_bytes_ 140 | #undef _Success_ 141 | #undef _Writable_bytes_ 142 | #undef _Pre_notnull_ 143 | #endif 144 | 145 | #if defined(_Deref_out_opt_z_) && !defined(_Outptr_result_maybenull_) 146 | #define _Outptr_result_maybenull_ _Deref_out_opt_z_ 147 | #endif 148 | 149 | #if defined(_In_count_) && !defined(_In_reads_) 150 | #define _In_reads_(x) _In_count_(x) 151 | #endif 152 | 153 | #if defined(_In_opt_count_) && !defined(_In_reads_opt_) 154 | #define _In_reads_opt_(x) _In_opt_count_(x) 155 | #endif 156 | 157 | #if defined(_In_opt_bytecount_) && !defined(_In_reads_opt_bytes_) 158 | #define _In_reads_opt_bytes_(x) _In_opt_bytecount_(x) 159 | #endif 160 | 161 | #if defined(_In_bytecount_) && !defined(_In_reads_bytes_) 162 | #define _In_reads_bytes_(x) _In_bytecount_(x) 163 | #endif 164 | 165 | #ifndef _In_ 166 | #define _In_ 167 | #endif 168 | 169 | #ifndef _In_bytecount_ 170 | #define _In_bytecount_(x) 171 | #endif 172 | 173 | #ifndef _In_count_ 174 | #define _In_count_(x) 175 | #endif 176 | 177 | #ifndef __in_ecount 178 | #define __in_ecount(x) 179 | #endif 180 | 181 | #ifndef _In_opt_ 182 | #define _In_opt_ 183 | #endif 184 | 185 | #ifndef _In_opt_bytecount_ 186 | #define _In_opt_bytecount_(x) 187 | #endif 188 | 189 | #ifndef _In_opt_count_ 190 | #define _In_opt_count_(x) 191 | #endif 192 | 193 | #ifndef _In_opt_z_ 194 | #define _In_opt_z_ 195 | #endif 196 | 197 | #ifndef _In_range_ 198 | #define _In_range_(x,y) 199 | #endif 200 | 201 | #ifndef _In_reads_ 202 | #define _In_reads_(x) 203 | #endif 204 | 205 | #ifndef _In_reads_bytes_ 206 | #define _In_reads_bytes_(x) 207 | #endif 208 | 209 | #ifndef _In_reads_opt_ 210 | #define _In_reads_opt_(x) 211 | #endif 212 | 213 | #ifndef _In_reads_opt_bytes_ 214 | #define _In_reads_opt_bytes_(x) 215 | #endif 216 | 217 | #ifndef _In_reads_or_z_ 218 | #define _In_reads_or_z_ 219 | #endif 220 | 221 | #ifndef _In_z_ 222 | #define _In_z_ 223 | #endif 224 | 225 | #ifndef _Inout_ 226 | #define _Inout_ 227 | #endif 228 | 229 | #ifndef _Inout_opt_ 230 | #define _Inout_opt_ 231 | #endif 232 | 233 | #ifndef _Inout_z_count_ 234 | #define _Inout_z_count_(x) 235 | #endif 236 | 237 | #ifndef _Out_ 238 | #define _Out_ 239 | #endif 240 | 241 | #ifndef _Out_opt_ 242 | #define _Out_opt_ 243 | #endif 244 | 245 | #ifndef _Out_writes_ 246 | #define _Out_writes_(x) 247 | #endif 248 | 249 | #ifndef _Outptr_result_maybenull_ 250 | #define _Outptr_result_maybenull_ 251 | #endif 252 | 253 | #ifndef _Writable_bytes_ 254 | #define _Writable_bytes_(x) 255 | #endif 256 | 257 | #ifndef _Readable_bytes_ 258 | #define _Readable_bytes_(x) 259 | #endif 260 | 261 | #ifndef _Success_ 262 | #define _Success_(x) 263 | #endif 264 | 265 | #ifndef _Pre_notnull_ 266 | #define _Pre_notnull_ 267 | #endif 268 | 269 | #ifdef DETOURS_INTERNAL 270 | 271 | #pragma warning(disable:4615) // unknown warning type (suppress with older compilers) 272 | 273 | #ifndef _Benign_race_begin_ 274 | #define _Benign_race_begin_ 275 | #endif 276 | 277 | #ifndef _Benign_race_end_ 278 | #define _Benign_race_end_ 279 | #endif 280 | 281 | #ifndef _Field_size_ 282 | #define _Field_size_(x) 283 | #endif 284 | 285 | #ifndef _Field_range_ 286 | #define _Field_range_(x,y) 287 | #endif 288 | 289 | #ifndef _Analysis_assume_ 290 | #define _Analysis_assume_(x) 291 | #endif 292 | 293 | #endif // DETOURS_INTERNAL 294 | #endif // DETOURS_DONT_REMOVE_SAL_20 295 | 296 | ////////////////////////////////////////////////////////////////////////////// 297 | // 298 | #ifndef GUID_DEFINED 299 | #define GUID_DEFINED 300 | typedef struct _GUID 301 | { 302 | DWORD Data1; 303 | WORD Data2; 304 | WORD Data3; 305 | BYTE Data4[ 8 ]; 306 | } GUID; 307 | 308 | #ifdef INITGUID 309 | #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ 310 | const GUID name \ 311 | = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } 312 | #else 313 | #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ 314 | const GUID name 315 | #endif // INITGUID 316 | #endif // !GUID_DEFINED 317 | 318 | #if defined(__cplusplus) 319 | #ifndef _REFGUID_DEFINED 320 | #define _REFGUID_DEFINED 321 | #define REFGUID const GUID & 322 | #endif // !_REFGUID_DEFINED 323 | #else // !__cplusplus 324 | #ifndef _REFGUID_DEFINED 325 | #define _REFGUID_DEFINED 326 | #define REFGUID const GUID * const 327 | #endif // !_REFGUID_DEFINED 328 | #endif // !__cplusplus 329 | 330 | #ifndef ARRAYSIZE 331 | #define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0])) 332 | #endif 333 | 334 | // 335 | ////////////////////////////////////////////////////////////////////////////// 336 | 337 | #ifdef __cplusplus 338 | extern "C" { 339 | #endif // __cplusplus 340 | 341 | /////////////////////////////////////////////////// Instruction Target Macros. 342 | // 343 | #define DETOUR_INSTRUCTION_TARGET_NONE ((PVOID)0) 344 | #define DETOUR_INSTRUCTION_TARGET_DYNAMIC ((PVOID)(LONG_PTR)-1) 345 | #define DETOUR_SECTION_HEADER_SIGNATURE 0x00727444 // "Dtr\0" 346 | 347 | extern const GUID DETOUR_EXE_RESTORE_GUID; 348 | extern const GUID DETOUR_EXE_HELPER_GUID; 349 | 350 | #define DETOUR_TRAMPOLINE_SIGNATURE 0x21727444 // Dtr! 351 | typedef struct _DETOUR_TRAMPOLINE DETOUR_TRAMPOLINE, *PDETOUR_TRAMPOLINE; 352 | 353 | #ifndef DETOUR_MAX_SUPPORTED_IMAGE_SECTION_HEADERS 354 | #define DETOUR_MAX_SUPPORTED_IMAGE_SECTION_HEADERS 32 355 | #endif // !DETOUR_MAX_SUPPORTED_IMAGE_SECTION_HEADERS 356 | 357 | /////////////////////////////////////////////////////////// Binary Structures. 358 | // 359 | #pragma pack(push, 8) 360 | typedef struct _DETOUR_SECTION_HEADER 361 | { 362 | DWORD cbHeaderSize; 363 | DWORD nSignature; 364 | DWORD nDataOffset; 365 | DWORD cbDataSize; 366 | 367 | DWORD nOriginalImportVirtualAddress; 368 | DWORD nOriginalImportSize; 369 | DWORD nOriginalBoundImportVirtualAddress; 370 | DWORD nOriginalBoundImportSize; 371 | 372 | DWORD nOriginalIatVirtualAddress; 373 | DWORD nOriginalIatSize; 374 | DWORD nOriginalSizeOfImage; 375 | DWORD cbPrePE; 376 | 377 | DWORD nOriginalClrFlags; 378 | DWORD reserved1; 379 | DWORD reserved2; 380 | DWORD reserved3; 381 | 382 | // Followed by cbPrePE bytes of data. 383 | } DETOUR_SECTION_HEADER, *PDETOUR_SECTION_HEADER; 384 | 385 | typedef struct _DETOUR_SECTION_RECORD 386 | { 387 | DWORD cbBytes; 388 | DWORD nReserved; 389 | GUID guid; 390 | } DETOUR_SECTION_RECORD, *PDETOUR_SECTION_RECORD; 391 | 392 | #pragma pack(pop) 393 | 394 | #define DETOUR_SECTION_HEADER_DECLARE(cbSectionSize) \ 395 | { \ 396 | sizeof(DETOUR_SECTION_HEADER),\ 397 | DETOUR_SECTION_HEADER_SIGNATURE,\ 398 | sizeof(DETOUR_SECTION_HEADER),\ 399 | (cbSectionSize),\ 400 | \ 401 | 0,\ 402 | 0,\ 403 | 0,\ 404 | 0,\ 405 | \ 406 | 0,\ 407 | 0,\ 408 | 0,\ 409 | 0,\ 410 | } 411 | 412 | ///////////////////////////////////////////////////////////// Binary Typedefs. 413 | // 414 | typedef BOOL (CALLBACK *PF_DETOUR_BINARY_BYWAY_CALLBACK)( 415 | _In_opt_ PVOID pContext, 416 | _In_opt_ LPCSTR pszFile, 417 | _Outptr_result_maybenull_ LPCSTR *ppszOutFile); 418 | 419 | typedef BOOL (CALLBACK *PF_DETOUR_BINARY_FILE_CALLBACK)( 420 | _In_opt_ PVOID pContext, 421 | _In_ LPCSTR pszOrigFile, 422 | _In_ LPCSTR pszFile, 423 | _Outptr_result_maybenull_ LPCSTR *ppszOutFile); 424 | 425 | typedef BOOL (CALLBACK *PF_DETOUR_BINARY_SYMBOL_CALLBACK)( 426 | _In_opt_ PVOID pContext, 427 | _In_ ULONG nOrigOrdinal, 428 | _In_ ULONG nOrdinal, 429 | _Out_ ULONG *pnOutOrdinal, 430 | _In_opt_ LPCSTR pszOrigSymbol, 431 | _In_opt_ LPCSTR pszSymbol, 432 | _Outptr_result_maybenull_ LPCSTR *ppszOutSymbol); 433 | 434 | typedef BOOL (CALLBACK *PF_DETOUR_BINARY_COMMIT_CALLBACK)( 435 | _In_opt_ PVOID pContext); 436 | 437 | typedef BOOL (CALLBACK *PF_DETOUR_ENUMERATE_EXPORT_CALLBACK)(_In_opt_ PVOID pContext, 438 | _In_ ULONG nOrdinal, 439 | _In_opt_ LPCSTR pszName, 440 | _In_opt_ PVOID pCode); 441 | 442 | typedef BOOL (CALLBACK *PF_DETOUR_IMPORT_FILE_CALLBACK)(_In_opt_ PVOID pContext, 443 | _In_opt_ HMODULE hModule, 444 | _In_opt_ LPCSTR pszFile); 445 | 446 | typedef BOOL (CALLBACK *PF_DETOUR_IMPORT_FUNC_CALLBACK)(_In_opt_ PVOID pContext, 447 | _In_ DWORD nOrdinal, 448 | _In_opt_ LPCSTR pszFunc, 449 | _In_opt_ PVOID pvFunc); 450 | 451 | // Same as PF_DETOUR_IMPORT_FUNC_CALLBACK but extra indirection on last parameter. 452 | typedef BOOL (CALLBACK *PF_DETOUR_IMPORT_FUNC_CALLBACK_EX)(_In_opt_ PVOID pContext, 453 | _In_ DWORD nOrdinal, 454 | _In_opt_ LPCSTR pszFunc, 455 | _In_opt_ PVOID* ppvFunc); 456 | 457 | typedef VOID * PDETOUR_BINARY; 458 | typedef VOID * PDETOUR_LOADED_BINARY; 459 | 460 | typedef struct _DETROUS_HOOK_NOTIFY_INFO_STRCUT 461 | { 462 | PVOID pContext; 463 | PVOID pFunInfo;//PF_DETOUR_HOOK_NOTIFY 464 | 465 | PVOID pParam1;//address saved params. most support 16 pararms, if not enough? you can count offset by yourself. 466 | PVOID pParam2; 467 | PVOID pParam3; 468 | PVOID pParam4; 469 | PVOID pParam5; 470 | PVOID pParam6; 471 | PVOID pParam7; 472 | PVOID pParam8; 473 | PVOID pParam9; 474 | PVOID pParam10; 475 | PVOID pParam11; 476 | PVOID pParam12; 477 | PVOID pParam13; 478 | PVOID pParam14; 479 | PVOID pParam15; 480 | PVOID pParam16; 481 | 482 | #if defined(_X86_) 483 | PVOID ESP; 484 | PVOID pEAX;//address saved eax value 485 | PVOID pECX; 486 | PVOID pEDX; 487 | PVOID pEBX; 488 | PVOID pESP; 489 | PVOID pEBP; 490 | PVOID pESI; 491 | PVOID pEDI; 492 | #elif defined(_AMD64_) 493 | PVOID RSP; 494 | PVOID pRSP; 495 | PVOID pRAX; 496 | PVOID pRCX; 497 | PVOID pRDX; 498 | PVOID pRBX; 499 | PVOID pRBP; 500 | PVOID pRSI; 501 | PVOID pRDI; 502 | PVOID pR8; 503 | PVOID pR9; 504 | PVOID pR10; 505 | PVOID pR11; 506 | PVOID pR12; 507 | PVOID pR13; 508 | PVOID pR14; 509 | PVOID pR15; 510 | #elif defined(_ARM64_) 511 | PVOID SP; 512 | PVOID pX0; 513 | PVOID pX1; 514 | PVOID pX2; 515 | PVOID pX3; 516 | PVOID pX4; 517 | PVOID pX5; 518 | PVOID pX6; 519 | PVOID pX7; 520 | PVOID pX8; 521 | PVOID pX9; 522 | PVOID pX10; 523 | PVOID pX11; 524 | PVOID pX12; 525 | PVOID pX13; 526 | PVOID pX14; 527 | PVOID pX15; 528 | PVOID pX16; 529 | PVOID pX17; 530 | PVOID pX18; 531 | PVOID pX19; 532 | PVOID pX20; 533 | PVOID pX21; 534 | PVOID pX22; 535 | PVOID pX23; 536 | PVOID pX24; 537 | PVOID pX25; 538 | PVOID pX26; 539 | PVOID pX27; 540 | PVOID pX28; 541 | PVOID pX29; 542 | PVOID pX30; 543 | #elif defined(_ARM_) 544 | PVOID SP; 545 | PVOID pR0; 546 | PVOID pR1; 547 | PVOID pR2; 548 | PVOID pR3; 549 | PVOID pR4; 550 | PVOID pR5; 551 | PVOID pR6; 552 | PVOID pR7; 553 | PVOID pR8; 554 | PVOID pR9; 555 | PVOID pR10; 556 | PVOID pR11; 557 | PVOID pR12; 558 | #endif 559 | }DETROUS_HOOK_NOTIFY_INFO_STRCUT, *PDETROUS_HOOK_NOTIFY_INFO_STRCUT; 560 | 561 | typedef BOOL (CALLBACK* PF_DETOUR_HOOK_NOTIFY)(_In_ PDETROUS_HOOK_NOTIFY_INFO_STRCUT pInfo); 562 | 563 | //////////////////////////////////////////////////////////// Transaction APIs. 564 | // 565 | LONG WINAPI DetourTransactionBegin(VOID); 566 | LONG WINAPI DetourTransactionAbort(VOID); 567 | LONG WINAPI DetourTransactionCommit(VOID); 568 | LONG WINAPI DetourTransactionCommitEx(_Out_opt_ PVOID **pppFailedPointer); 569 | 570 | LONG WINAPI DetourUpdateThread(_In_ HANDLE hThread); 571 | 572 | LONG WINAPI DetourAttach(_Inout_ PVOID *ppPointer, 573 | _In_ PVOID pDetour); 574 | 575 | LONG WINAPI DetourAttachEx(_Inout_ PVOID *ppPointer, 576 | _In_ PVOID pDetour, 577 | _Out_opt_ PDETOUR_TRAMPOLINE *ppRealTrampoline, 578 | _Out_opt_ PVOID *ppRealTarget, 579 | _Out_opt_ PVOID *ppRealDetour); 580 | 581 | LONG WINAPI DetourDetach(_Inout_ PVOID *ppPointer, 582 | _In_ PVOID pDetour); 583 | 584 | LONG WINAPI DetourInstallNotify(_Inout_ PVOID *ppPointer, _In_ PF_DETOUR_HOOK_NOTIFY pNotify,PVOID pContext = NULL ); 585 | LONG WINAPI DetourInstallNotifyEx(_Inout_ PVOID *ppPointer, _In_ PF_DETOUR_HOOK_NOTIFY pNotify, PVOID pContext, USHORT ulEspAddWhenBlock); 586 | LONG WINAPI DetourUnInstallNotify(_Inout_ PVOID *ppPointer, _In_ PF_DETOUR_HOOK_NOTIFY pNotify); 587 | UCHAR* WINAPI SkipJump(UCHAR* Ptr); 588 | 589 | BOOL WINAPI DetourSetIgnoreTooSmall(_In_ BOOL fIgnore); 590 | BOOL WINAPI DetourSetRetainRegions(_In_ BOOL fRetain); 591 | PVOID WINAPI DetourSetSystemRegionLowerBound(_In_ PVOID pSystemRegionLowerBound); 592 | PVOID WINAPI DetourSetSystemRegionUpperBound(_In_ PVOID pSystemRegionUpperBound); 593 | 594 | ////////////////////////////////////////////////////////////// Code Functions. 595 | // 596 | PVOID WINAPI DetourFindFunction(_In_ LPCSTR pszModule, 597 | _In_ LPCSTR pszFunction); 598 | PVOID WINAPI DetourCodeFromPointer(_In_ PVOID pPointer, 599 | _Out_opt_ PVOID *ppGlobals); 600 | PVOID WINAPI DetourCopyInstruction(_In_opt_ PVOID pDst, 601 | _Inout_opt_ PVOID *ppDstPool, 602 | _In_ PVOID pSrc, 603 | _Out_opt_ PVOID *ppTarget, 604 | _Out_opt_ LONG *plExtra); 605 | BOOL WINAPI DetourSetCodeModule(_In_ HMODULE hModule, 606 | _In_ BOOL fLimitReferencesToModule); 607 | PVOID WINAPI DetourAllocateRegionWithinJumpBounds(_In_ LPCVOID pbTarget, 608 | _Out_ PDWORD pcbAllocatedSize); 609 | 610 | ///////////////////////////////////////////////////// Loaded Binary Functions. 611 | // 612 | ///////////////////////////////////////////////// Persistent Binary Functions. 613 | // 614 | 615 | 616 | /////////////////////////////////////////////////// Create Process & Load Dll. 617 | // 618 | 619 | // 620 | ////////////////////////////////////////////////////////////////////////////// 621 | #ifdef __cplusplus 622 | } 623 | #endif // __cplusplus 624 | 625 | /////////////////////////////////////////////////// Type-safe overloads for C++ 626 | // 627 | // 628 | ////////////////////////////////////////////////////////////////////////////// 629 | 630 | //////////////////////////////////////////////// Detours Internal Definitions. 631 | // 632 | #ifdef __cplusplus 633 | #ifdef DETOURS_INTERNAL 634 | 635 | #define NOTHROW 636 | // #define NOTHROW (nothrow) 637 | 638 | ////////////////////////////////////////////////////////////////////////////// 639 | // 640 | 641 | #if defined(_INC_STDIO) && !defined(_CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS) 642 | #error detours.h must be included before stdio.h (or at least define _CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS earlier) 643 | #endif 644 | #define _CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS 1 645 | 646 | #ifdef _DEBUG 647 | 648 | int Detour_AssertExprWithFunctionName(int reportType, const char* filename, int linenumber, const char* FunctionName, const char* msg); 649 | 650 | #define DETOUR_ASSERT_EXPR_WITH_FUNCTION(expr, msg) \ 651 | (void) ((expr) || \ 652 | (1 != Detour_AssertExprWithFunctionName(_CRT_ASSERT, __FILE__, __LINE__,__FUNCTION__, msg)) || \ 653 | (_CrtDbgBreak(), 0)) 654 | 655 | #define DETOUR_ASSERT(expr) DETOUR_ASSERT_EXPR_WITH_FUNCTION((expr), #expr) 656 | 657 | #else// _DEBUG 658 | #define DETOUR_ASSERT(expr) 659 | #endif// _DEBUG 660 | 661 | #ifndef DETOUR_TRACE 662 | #if DETOUR_DEBUG 663 | #define DETOUR_TRACE(x) printf x 664 | #define DETOUR_BREAK() __debugbreak() 665 | #include 666 | #include 667 | #else 668 | #define DETOUR_TRACE(x) 669 | #define DETOUR_BREAK() 670 | #endif 671 | #endif 672 | 673 | #if 1 || defined(DETOURS_IA64) 674 | 675 | // 676 | // IA64 instructions are 41 bits, 3 per bundle, plus 5 bit bundle template => 128 bits per bundle. 677 | // 678 | 679 | #define DETOUR_IA64_INSTRUCTIONS_PER_BUNDLE (3) 680 | 681 | #define DETOUR_IA64_TEMPLATE_OFFSET (0) 682 | #define DETOUR_IA64_TEMPLATE_SIZE (5) 683 | 684 | #define DETOUR_IA64_INSTRUCTION_SIZE (41) 685 | #define DETOUR_IA64_INSTRUCTION0_OFFSET (DETOUR_IA64_TEMPLATE_SIZE) 686 | #define DETOUR_IA64_INSTRUCTION1_OFFSET (DETOUR_IA64_TEMPLATE_SIZE + DETOUR_IA64_INSTRUCTION_SIZE) 687 | #define DETOUR_IA64_INSTRUCTION2_OFFSET (DETOUR_IA64_TEMPLATE_SIZE + DETOUR_IA64_INSTRUCTION_SIZE + DETOUR_IA64_INSTRUCTION_SIZE) 688 | 689 | C_ASSERT(DETOUR_IA64_TEMPLATE_SIZE + DETOUR_IA64_INSTRUCTIONS_PER_BUNDLE * DETOUR_IA64_INSTRUCTION_SIZE == 128); 690 | 691 | #if defined(_MSC_VER) 692 | #define ALIGNED_(x) __declspec(align(x)) 693 | #else 694 | #if defined(__GNUC__) 695 | #define ALIGNED_(x) __attribute__ ((aligned(x))) 696 | #endif 697 | #endif 698 | 699 | struct ALIGNED_(16) DETOUR_IA64_BUNDLE 700 | { 701 | public: 702 | union 703 | { 704 | BYTE data[16]; 705 | UINT64 wide[2]; 706 | }; 707 | 708 | enum { 709 | A_UNIT = 1u, 710 | I_UNIT = 2u, 711 | M_UNIT = 3u, 712 | B_UNIT = 4u, 713 | F_UNIT = 5u, 714 | L_UNIT = 6u, 715 | X_UNIT = 7u, 716 | }; 717 | struct DETOUR_IA64_METADATA 718 | { 719 | ULONG nTemplate : 8; // Instruction template. 720 | ULONG nUnit0 : 4; // Unit for slot 0 721 | ULONG nUnit1 : 4; // Unit for slot 1 722 | ULONG nUnit2 : 4; // Unit for slot 2 723 | }; 724 | 725 | protected: 726 | static const DETOUR_IA64_METADATA s_rceCopyTable[33]; 727 | 728 | UINT RelocateBundle(_Inout_ DETOUR_IA64_BUNDLE* pDst, _Inout_opt_ DETOUR_IA64_BUNDLE* pBundleExtra) const; 729 | 730 | bool RelocateInstruction(_Inout_ DETOUR_IA64_BUNDLE* pDst, 731 | _In_ BYTE slot, 732 | _Inout_opt_ DETOUR_IA64_BUNDLE* pBundleExtra) const; 733 | 734 | // 120 112 104 96 88 80 72 64 56 48 40 32 24 16 8 0 735 | // f. e. d. c. b. a. 9. 8. 7. 6. 5. 4. 3. 2. 1. 0. 736 | 737 | // 00 738 | // f.e. d.c. b.a. 9.8. 7.6. 5.4. 3.2. 1.0. 739 | // 0000 0000 0000 0000 0000 0000 0000 001f : Template [4..0] 740 | // 0000 0000 0000 0000 0000 03ff ffff ffe0 : Zero [ 41.. 5] 741 | // 0000 0000 0000 0000 0000 3c00 0000 0000 : Zero [ 45.. 42] 742 | // 0000 0000 0007 ffff ffff c000 0000 0000 : One [ 82.. 46] 743 | // 0000 0000 0078 0000 0000 0000 0000 0000 : One [ 86.. 83] 744 | // 0fff ffff ff80 0000 0000 0000 0000 0000 : Two [123.. 87] 745 | // f000 0000 0000 0000 0000 0000 0000 0000 : Two [127..124] 746 | BYTE GetTemplate() const; 747 | // Get 4 bit opcodes. 748 | BYTE GetInst0() const; 749 | BYTE GetInst1() const; 750 | BYTE GetInst2() const; 751 | BYTE GetUnit(BYTE slot) const; 752 | BYTE GetUnit0() const; 753 | BYTE GetUnit1() const; 754 | BYTE GetUnit2() const; 755 | // Get 37 bit data. 756 | UINT64 GetData0() const; 757 | UINT64 GetData1() const; 758 | UINT64 GetData2() const; 759 | 760 | // Get/set the full 41 bit instructions. 761 | UINT64 GetInstruction(BYTE slot) const; 762 | UINT64 GetInstruction0() const; 763 | UINT64 GetInstruction1() const; 764 | UINT64 GetInstruction2() const; 765 | void SetInstruction(BYTE slot, UINT64 instruction); 766 | void SetInstruction0(UINT64 instruction); 767 | void SetInstruction1(UINT64 instruction); 768 | void SetInstruction2(UINT64 instruction); 769 | 770 | // Get/set bitfields. 771 | static UINT64 GetBits(UINT64 Value, UINT64 Offset, UINT64 Count); 772 | static UINT64 SetBits(UINT64 Value, UINT64 Offset, UINT64 Count, UINT64 Field); 773 | 774 | // Get specific read-only fields. 775 | static UINT64 GetOpcode(UINT64 instruction); // 4bit opcode 776 | static UINT64 GetX(UINT64 instruction); // 1bit opcode extension 777 | static UINT64 GetX3(UINT64 instruction); // 3bit opcode extension 778 | static UINT64 GetX6(UINT64 instruction); // 6bit opcode extension 779 | 780 | // Get/set specific fields. 781 | static UINT64 GetImm7a(UINT64 instruction); 782 | static UINT64 SetImm7a(UINT64 instruction, UINT64 imm7a); 783 | static UINT64 GetImm13c(UINT64 instruction); 784 | static UINT64 SetImm13c(UINT64 instruction, UINT64 imm13c); 785 | static UINT64 GetSignBit(UINT64 instruction); 786 | static UINT64 SetSignBit(UINT64 instruction, UINT64 signBit); 787 | static UINT64 GetImm20a(UINT64 instruction); 788 | static UINT64 SetImm20a(UINT64 instruction, UINT64 imm20a); 789 | static UINT64 GetImm20b(UINT64 instruction); 790 | static UINT64 SetImm20b(UINT64 instruction, UINT64 imm20b); 791 | 792 | static UINT64 SignExtend(UINT64 Value, UINT64 Offset); 793 | 794 | BOOL IsMovlGp() const; 795 | 796 | VOID SetInst(BYTE Slot, BYTE nInst); 797 | VOID SetInst0(BYTE nInst); 798 | VOID SetInst1(BYTE nInst); 799 | VOID SetInst2(BYTE nInst); 800 | VOID SetData(BYTE Slot, UINT64 nData); 801 | VOID SetData0(UINT64 nData); 802 | VOID SetData1(UINT64 nData); 803 | VOID SetData2(UINT64 nData); 804 | BOOL SetNop(BYTE Slot); 805 | BOOL SetNop0(); 806 | BOOL SetNop1(); 807 | BOOL SetNop2(); 808 | 809 | public: 810 | BOOL IsBrl() const; 811 | VOID SetBrl(); 812 | VOID SetBrl(UINT64 target); 813 | UINT64 GetBrlTarget() const; 814 | VOID SetBrlTarget(UINT64 target); 815 | VOID SetBrlImm(UINT64 imm); 816 | UINT64 GetBrlImm() const; 817 | 818 | UINT64 GetMovlGp() const; 819 | VOID SetMovlGp(UINT64 gp); 820 | 821 | VOID SetStop(); 822 | 823 | UINT Copy(_Out_ DETOUR_IA64_BUNDLE *pDst, _Inout_opt_ DETOUR_IA64_BUNDLE* pBundleExtra = NULL) const; 824 | }; 825 | #endif // DETOURS_IA64 826 | 827 | #ifdef DETOURS_ARM 828 | 829 | #define DETOURS_PFUNC_TO_PBYTE(p) ((PBYTE)(((ULONG_PTR)(p)) & ~(ULONG_PTR)1)) 830 | #define DETOURS_PBYTE_TO_PFUNC(p) ((PBYTE)(((ULONG_PTR)(p)) | (ULONG_PTR)1)) 831 | 832 | #endif // DETOURS_ARM 833 | 834 | ////////////////////////////////////////////////////////////////////////////// 835 | 836 | #ifdef __cplusplus 837 | extern "C" { 838 | #endif // __cplusplus 839 | 840 | #define DETOUR_OFFLINE_LIBRARY(x) \ 841 | PVOID WINAPI DetourCopyInstruction##x(_In_opt_ PVOID pDst, \ 842 | _Inout_opt_ PVOID *ppDstPool, \ 843 | _In_ PVOID pSrc, \ 844 | _Out_opt_ PVOID *ppTarget, \ 845 | _Out_opt_ LONG *plExtra); \ 846 | \ 847 | BOOL WINAPI DetourSetCodeModule##x(_In_ HMODULE hModule, \ 848 | _In_ BOOL fLimitReferencesToModule); \ 849 | 850 | DETOUR_OFFLINE_LIBRARY(X86) 851 | DETOUR_OFFLINE_LIBRARY(X64) 852 | DETOUR_OFFLINE_LIBRARY(ARM) 853 | DETOUR_OFFLINE_LIBRARY(ARM64) 854 | DETOUR_OFFLINE_LIBRARY(IA64) 855 | 856 | #undef DETOUR_OFFLINE_LIBRARY 857 | 858 | #ifdef __cplusplus 859 | } 860 | #endif // __cplusplus 861 | 862 | 863 | #endif // DETOURS_INTERNAL 864 | 865 | 866 | ////////////////////////////////////////////////////////////////////////////// 867 | // 868 | // Helpers for manipulating page protection. 869 | // 870 | 871 | #ifdef __cplusplus 872 | extern "C" { 873 | #endif // __cplusplus 874 | 875 | _Success_(return != FALSE) 876 | BOOL WINAPI DetourVirtualProtectSameExecuteEx(_In_ HANDLE hProcess, 877 | _In_ PVOID pAddress, 878 | _In_ SIZE_T nSize, 879 | _In_ DWORD dwNewProtect, 880 | _Out_ PDWORD pdwOldProtect); 881 | 882 | _Success_(return != FALSE) 883 | BOOL WINAPI DetourVirtualProtectSameExecute(_In_ PVOID pAddress, 884 | _In_ SIZE_T nSize, 885 | _In_ DWORD dwNewProtect, 886 | _Out_ PDWORD pdwOldProtect); 887 | 888 | // Detours must depend only on kernel32.lib, so we cannot use IsEqualGUID 889 | BOOL WINAPI DetourAreSameGuid(_In_ REFGUID left, _In_ REFGUID right); 890 | 891 | #ifdef __cplusplus 892 | } 893 | #endif // __cplusplus 894 | 895 | ////////////////////////////////////////////////////////////////////////////// 896 | 897 | #define MM_ALLOCATION_GRANULARITY 0x10000 898 | 899 | ////////////////////////////////////////////////////////////////////////////// 900 | 901 | #endif // __cplusplus 902 | 903 | #endif // _DETOURS_H_ 904 | // 905 | //////////////////////////////////////////////////////////////// End of File. -------------------------------------------------------------------------------- /Detours/src/detours_patch.cpp: -------------------------------------------------------------------------------- 1 | #define DETOURS_INTERNAL 2 | #include "detours.h" 3 | #undef DETOURS_INTERNAL 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | typedef unsigned char BYTE_,*PBYTE_; 10 | typedef PBYTE_ ULONG_PTR_; 11 | typedef uint64_t ULONG64_; 12 | PBYTE_ detour_gen_jmp_immediate(PBYTE_ pbCode, PBYTE_ pbJmpVal); 13 | PBYTE_ detour_gen_jmp_indirect(PBYTE_ pbCode, PBYTE_ *ppbJmpVal); 14 | PBYTE_ detour_gen_brk(PBYTE_ pbCode, PBYTE_ pbLimit); 15 | PBYTE_ detour_gen_jmp_immediate(PBYTE_ pbCode, PBYTE_ *ppPool, PBYTE_ pbJmpVal); 16 | PBYTE_ detour_gen_jmp_indirect(BYTE_ *pbCode, ULONG64_ *pbJmpVal); 17 | 18 | struct DetourMemoryOpWrapper { 19 | DetourMemoryOpWrapper *pNext; 20 | DetourMemoryOpWrapper *pPrev; 21 | void *pbCode; 22 | char rbCode[0x100]; 23 | int iCodeSize; 24 | }; 25 | 26 | static DetourMemoryOpWrapper *s_detoursMemoryOp = nullptr; 27 | 28 | 29 | static BOOL is_trampoline(ULONG_PTR_ addr); 30 | 31 | inline static void push_op(DetourMemoryOpWrapper *o) { 32 | o->pPrev = s_detoursMemoryOp; 33 | if (s_detoursMemoryOp) { 34 | s_detoursMemoryOp->pNext = o; 35 | } 36 | o->pNext = nullptr; 37 | s_detoursMemoryOp = o; 38 | } 39 | 40 | #define MAX_PAGE_SIZE 0x1000 41 | #define MAX_PATCH_SIZE 0x100 42 | 43 | // do 's|detour_gen_(.*?)\((.*?)\);|detour_gen_$1_($2);|' on detours.cpp 44 | template 45 | PBYTE_ detour_gen_jmp_indirect_(T1 pbCode, T2 value) { 46 | DETOUR_TRACE(("detour_gen_jmp_indirect_(%p, %p)\n", pbCode, value)); 47 | #if !defined(_DARWIN) 48 | return detour_gen_jmp_indirect((T1)pbCode, (T2)value); 49 | #endif 50 | if (is_trampoline((ULONG_PTR_)(pbCode))) return detour_gen_jmp_indirect((T1)pbCode, (T2)value); 51 | 52 | char _pbCodeBuf[2 * MAX_PAGE_SIZE + 0x100] = { 0 }; 53 | char *pbCodeBuf = _pbCodeBuf + MAX_PAGE_SIZE - ((ULONG64_)(ULONG_PTR_)_pbCodeBuf & 0xfff) + ((ULONG64_)(ULONG_PTR_)pbCode & 0xfff); 54 | memcpy(pbCodeBuf, pbCode, MAX_PATCH_SIZE); 55 | ULONG_PTR_ newvalue = 0; 56 | if (value != nullptr) { 57 | newvalue = (ULONG_PTR_)value - (ULONG_PTR_)pbCode + (ULONG_PTR_)pbCodeBuf; 58 | } 59 | PBYTE_ ret = detour_gen_jmp_indirect((T1)pbCodeBuf, (T2)newvalue); 60 | 61 | DetourMemoryOpWrapper *o = new DetourMemoryOpWrapper; 62 | o->pbCode = pbCode; 63 | o->iCodeSize = (int)(ret - (PBYTE_)pbCodeBuf); 64 | memcpy(o->rbCode, pbCodeBuf, sizeof(o->rbCode)); 65 | push_op(o); 66 | 67 | ret = (PBYTE_)((ULONG_PTR_)ret - (ULONG_PTR_)pbCodeBuf + (ULONG_PTR_)pbCode); 68 | return ret; 69 | } 70 | 71 | template 72 | PBYTE_ detour_gen_jmp_immediate_(T1 pbCode, T2 value) { 73 | DETOUR_TRACE(("detour_gen_jmp_immediate_(%p, %p)\n", pbCode, value)); 74 | #if !defined(_DARWIN) 75 | return detour_gen_jmp_immediate((T1)pbCode, (T2)value); 76 | #endif 77 | if (is_trampoline((ULONG_PTR_)(pbCode))) return detour_gen_jmp_immediate((T1)pbCode, (T2)value); 78 | 79 | 80 | char _pbCodeBuf[2 * MAX_PAGE_SIZE + 0x100] = { 0 }; 81 | char *pbCodeBuf = _pbCodeBuf + MAX_PAGE_SIZE - ((ULONG64_)(ULONG_PTR_)_pbCodeBuf & 0xfff) + ((ULONG64_)(ULONG_PTR_)pbCode & 0xfff); 82 | memcpy(pbCodeBuf, pbCode, MAX_PATCH_SIZE); 83 | ULONG_PTR_ newvalue = 0; 84 | if (value != nullptr) { 85 | newvalue = (ULONG_PTR_)value - (ULONG_PTR_)pbCode + (ULONG_PTR_)pbCodeBuf; 86 | } 87 | PBYTE_ ret = detour_gen_jmp_immediate((T1)pbCodeBuf, (T2)(ULONG_PTR_)newvalue); 88 | 89 | DetourMemoryOpWrapper *o = new DetourMemoryOpWrapper; 90 | o->pbCode = pbCode; 91 | o->iCodeSize = (int)(ret - (PBYTE_)pbCodeBuf); 92 | memcpy(o->rbCode, pbCodeBuf, sizeof(o->rbCode)); 93 | push_op(o); 94 | 95 | ret = (PBYTE_)((ULONG_PTR_)ret - (ULONG_PTR_)pbCodeBuf + (ULONG_PTR_)pbCode); 96 | return ret; 97 | } 98 | 99 | template 100 | PBYTE_ detour_gen_jmp_immediate_(T1 pbCode, T2 ppPool, T3 pbJmpVal) { 101 | DETOUR_TRACE(("detour_gen_jmp_immediate_(%p, %p, %p)\n", pbCode, ppPool, pbJmpVal)); 102 | #if !defined(_DARWIN) 103 | return detour_gen_jmp_immediate((T1)pbCode, (T2)ppPool, (T3)pbJmpVal); 104 | #endif 105 | if (is_trampoline((ULONG_PTR_)(pbCode))) return detour_gen_jmp_immediate((T1)pbCode, (T2)ppPool, (T3)pbJmpVal); 106 | 107 | 108 | if (ppPool) { 109 | DETOUR_TRACE(("detour_gen_jmp_immediate_: Warning, cannot handle ppPool cases!\n")); 110 | return detour_gen_jmp_immediate(pbCode, ppPool, pbJmpVal); 111 | } 112 | 113 | char _pbCodeBuf[2 * MAX_PAGE_SIZE + 0x100] = { 0 }; 114 | char *pbCodeBuf = _pbCodeBuf + MAX_PAGE_SIZE - ((ULONG64_)(ULONG_PTR_)_pbCodeBuf & 0xfff) + ((ULONG64_)(ULONG_PTR_)pbCode & 0xfff); 115 | memcpy(pbCodeBuf, pbCode, MAX_PATCH_SIZE); 116 | ULONG_PTR_ newvalue = pbJmpVal; 117 | //if (pbJmpVal != nullptr) { 118 | // newvalue = (ULONG_PTR_)pbJmpVal - (ULONG_PTR_)pbCode + (ULONG_PTR_)pbCodeBuf; 119 | //} 120 | PBYTE_ ret = detour_gen_jmp_immediate((T1)pbCodeBuf, nullptr, (T3)newvalue); 121 | 122 | DetourMemoryOpWrapper *o = new DetourMemoryOpWrapper; 123 | o->pbCode = pbCode; 124 | o->iCodeSize = (int)(ret - (PBYTE_)pbCodeBuf); 125 | memcpy(o->rbCode, pbCodeBuf, sizeof(o->rbCode)); 126 | push_op(o); 127 | 128 | ret = (PBYTE_)((ULONG_PTR_)ret - (ULONG_PTR_)pbCodeBuf + (ULONG_PTR_)pbCode); 129 | return ret; 130 | } 131 | 132 | template 133 | PBYTE_ detour_gen_brk_(T1 pbCode, T2 value) { 134 | DETOUR_TRACE(("detour_gen_brk_(%p, %p)\n", pbCode, value)); 135 | #if !defined(_DARWIN) 136 | return detour_gen_brk((T1)pbCode, (T2)value); 137 | #endif 138 | if (is_trampoline((ULONG_PTR_)(pbCode))) return detour_gen_brk((T1)pbCode, (T2)value); 139 | 140 | char _pbCodeBuf[2 * MAX_PAGE_SIZE + 0x100] = { 0 }; 141 | char *pbCodeBuf = _pbCodeBuf + MAX_PAGE_SIZE - ((ULONG64_)(ULONG_PTR_)_pbCodeBuf & 0xfff) + ((ULONG64_)(ULONG_PTR_)pbCode & 0xfff); 142 | memcpy(pbCodeBuf, pbCode, MAX_PATCH_SIZE); 143 | ULONG_PTR_ newvalue = 0; 144 | if (value != nullptr) { 145 | newvalue = (ULONG_PTR_)value - (ULONG_PTR_)pbCode + (ULONG_PTR_)pbCodeBuf; 146 | } 147 | PBYTE_ ret = detour_gen_brk((T1)pbCodeBuf, (T2)newvalue); 148 | 149 | DetourMemoryOpWrapper *o = new DetourMemoryOpWrapper; 150 | o->pbCode = pbCode; 151 | o->iCodeSize = (int)(ret - (PBYTE_)pbCodeBuf); 152 | memcpy(o->rbCode, pbCodeBuf, sizeof(o->rbCode)); 153 | push_op(o); 154 | ret = (PBYTE_)((ULONG_PTR_)ret - (ULONG_PTR_)pbCodeBuf + (ULONG_PTR_)pbCode); 155 | return ret; 156 | } 157 | 158 | 159 | #define DetourTransactionCommit _DetourTransactionCommit 160 | #include "detours.cpp" 161 | #undef DetourTransactionCommit 162 | 163 | static BOOL is_trampoline(ULONG_PTR_ addr) { 164 | for (PDETOUR_REGION pRegion = s_pRegions; pRegion != NULL; pRegion = pRegion->pNext) { 165 | ULONG_PTR_ addrRegion = (ULONG_PTR_)pRegion; 166 | if ( addrRegion <= addr && addr < addrRegion + DETOUR_REGION_SIZE ) { 167 | return TRUE; 168 | } 169 | } 170 | return FALSE; 171 | } 172 | 173 | 174 | #include 175 | 176 | extern "C" { 177 | 178 | // struct DetourOperationWrapper { 179 | // DetourOperationWrapper *pNext; 180 | // PBYTE oldPbTarget; 181 | // PBYTE newPbTarget; 182 | // DWORD cbTarget; 183 | // DWORD flOld; 184 | // }; 185 | LONG WINAPI DetourTransactionCommit() { 186 | // DetourOperationWrapper *ori_s_pPendingOperations = nullptr; 187 | // LONG ret = 0; 188 | // for (DetourOperation *o = s_pPendingOperations; o != nullptr;) { 189 | // DetourOperationWrapper *o_ = new DetourOperationWrapper; 190 | // o_->oldPbTarget = o->pbTarget; 191 | // o_->cbTarget = o->pTrampoline->pbRemain - o->pbTarget; 192 | // o_->newPbTarget = new BYTE[o_->cbTarget + 0x100]; 193 | // memcpy(o_->newPbTarget, o_->oldPbTarget, o_->cbTarget); 194 | // o_->flOld = o->dwPerm; 195 | // if (!VirtualProtect(o_->oldPbTarget, o_->cbTarget, PAGE_READWRITE, &o_->flOld)) { 196 | // // wait for ret 197 | // ret = GetLastError(); 198 | // delete o_; 199 | // break; 200 | // } 201 | 202 | // o_->pNext = ori_s_pPendingOperations; 203 | // ori_s_pPendingOperations = o_; 204 | // DETOUR_TRACE(("Before transaction commit: %p (%x)\n", o_->oldPbTarget, o_->cbTarget)); 205 | // // o->pbTarget = o_->newPbTarget; 206 | // // o->pTrampoline->pbRemain = o_->newPbTarget + o_->cbTarget; 207 | // // o->pTrampoline->rbCodeIn 208 | // o = o->pNext; 209 | // } 210 | // if (!ret) { 211 | // ret = _DetourTransactionCommit(); 212 | // DETOUR_TRACE(("Transaction Result: %d\n", ret)); 213 | // } else { 214 | // DETOUR_TRACE(("Error During VirtualProtect prepare: %d\n", ret)); 215 | // } 216 | 217 | // for (DetourOperationWrapper *o_ = ori_s_pPendingOperations; o_ != nullptr;) { 218 | // //if (!!memcmp(o_->oldPbTarget, o_->newPbTarget, o_->cbTarget)) { 219 | // // DETOUR_TRACE(("Applying After transaction commit: %p (%x) <- %p\n", o_->oldPbTarget, o_->cbTarget, o_->newPbTarget)); 220 | // // CodePatch(o_->oldPbTarget, o_->newPbTarget, o_->cbTarget); 221 | // //} 222 | // DWORD flOld = 0; 223 | // if (!VirtualProtect(o_->oldPbTarget, o_->cbTarget, o_->flOld, &flOld)) { 224 | // // wait for ret 225 | // ret = GetLastError(); 226 | // DETOUR_TRACE(("Failed to restore page permission for %p: error %d\n", o_->oldPbTarget, ret)); 227 | // } 228 | 229 | // delete[] o_->newPbTarget; 230 | // DetourOperationWrapper *n_ = o_->pNext; 231 | // delete o_; 232 | // o_ = n_; 233 | // } 234 | // return ret; 235 | LONG ret = _DetourTransactionCommit(); 236 | DetourMemoryOpWrapper *begin = nullptr; 237 | for (DetourMemoryOpWrapper *o = s_detoursMemoryOp; o != nullptr; ) { 238 | begin = o; 239 | o = o->pPrev; 240 | } 241 | for (DetourMemoryOpWrapper *o = begin; o != nullptr; ) { 242 | BYTE *rbCode = (BYTE *)o->rbCode; 243 | DETOUR_TRACE(("Applying Code Changes: %p\n", o->pbCode)); 244 | DETOUR_TRACE(("detours: pbCode=%p: " 245 | "%02x %02x %02x %02x " 246 | "%02x %02x %02x %02x " 247 | "%02x %02x %02x %02x [after]\n", 248 | o->pbCode, 249 | rbCode[0], rbCode[1], rbCode[2], rbCode[3], 250 | rbCode[4], rbCode[5], rbCode[6], rbCode[7], 251 | rbCode[8], rbCode[9], rbCode[10], rbCode[11])); 252 | if (!CodePatch(o->pbCode, o->rbCode, o->iCodeSize/* sizeof(o->rbCode)*/)) 253 | ret = GetLastError(); 254 | DetourMemoryOpWrapper *n = o->pNext; 255 | delete o; 256 | o = n; 257 | } 258 | s_detoursMemoryOp = NULL; 259 | // Mark all of the regions as executable. 260 | // for (PDETOUR_REGION pRegion = s_pRegions; pRegion != NULL; pRegion = pRegion->pNext) { 261 | // DETOUR_TRACE(("Marking Trampolines as RX: %p\n", pRegion)); 262 | // CodePatch(pRegion, NULL, DETOUR_REGION_SIZE); 263 | // } 264 | return ret; 265 | } 266 | 267 | 268 | 269 | } 270 | -------------------------------------------------------------------------------- /Detours/src/detver.h: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Common version parameters. 4 | // 5 | // Microsoft Research Detours Package, Version 4.0.1 6 | // 7 | // Copyright (c) Microsoft Corporation. All rights reserved. 8 | // 9 | 10 | #define _USING_V110_SDK71_ 1 11 | #include "winver.h" 12 | #if 0 13 | #include 14 | #include "detours.h" 15 | #else 16 | #ifndef DETOURS_STRINGIFY 17 | #define DETOURS_STRINGIFY_(x) #x 18 | #define DETOURS_STRINGIFY(x) DETOURS_STRINGIFY_(x) 19 | #endif 20 | 21 | #define VER_FILEFLAGSMASK 0x3fL 22 | #define VER_FILEFLAGS 0x0L 23 | #define VER_FILEOS 0x00040004L 24 | #define VER_FILETYPE 0x00000002L 25 | #define VER_FILESUBTYPE 0x00000000L 26 | #endif 27 | #define VER_DETOURS_BITS DETOURS_STRINGIFY(DETOURS_BITS) 28 | -------------------------------------------------------------------------------- /Detours/src/disolarm.cpp: -------------------------------------------------------------------------------- 1 | #define DETOURS_ARM_OFFLINE_LIBRARY 2 | #include "disasm.cpp" 3 | -------------------------------------------------------------------------------- /Detours/src/disolarm64.cpp: -------------------------------------------------------------------------------- 1 | #define DETOURS_ARM64_OFFLINE_LIBRARY 2 | #include "disasm.cpp" 3 | -------------------------------------------------------------------------------- /Detours/src/disolia64.cpp: -------------------------------------------------------------------------------- 1 | #define DETOURS_IA64_OFFLINE_LIBRARY 2 | #include "disasm.cpp" 3 | -------------------------------------------------------------------------------- /Detours/src/disolx64.cpp: -------------------------------------------------------------------------------- 1 | #define DETOURS_X64_OFFLINE_LIBRARY 2 | #include "disasm.cpp" 3 | -------------------------------------------------------------------------------- /Detours/src/disolx86.cpp: -------------------------------------------------------------------------------- 1 | #define DETOURS_X86_OFFLINE_LIBRARY 2 | #include "disasm.cpp" 3 | -------------------------------------------------------------------------------- /Detours/src/mem_patch.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #define DETOURS_INTERNAL 4 | #include "detours.h" 5 | 6 | 7 | #define patch_min(a,b) ((a) < (b) ? (a) : (b)) 8 | 9 | #if defined(_DARWIN) 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | void ClearCache(void *start, void *end) { 19 | return sys_icache_invalidate(start, (uint64_t)end - (uint64_t)start); 20 | } 21 | 22 | 23 | 24 | #define KERN_RETURN_ERROR(kr, failure) \ 25 | do { \ 26 | if (kr != KERN_SUCCESS) { \ 27 | return failure; \ 28 | } \ 29 | } while (0); 30 | 31 | #include 32 | typedef uintptr_t addr_t; 33 | #if defined(TARGET_ARCH_ARM64) 34 | #define SYS_mprotect 74 35 | int mprotect_impl(void *addr, size_t len, int prot) { 36 | int ret = 0; 37 | __asm__ __volatile__("mov x16, %[_SYS_mprotect]\n" 38 | "svc 0x80\n" 39 | "mov %w[_ret], w0\n" 40 | "add %w[_ret], %w[_ret], #0x0\n" 41 | : [_ret] "=r"(ret) 42 | : [_SYS_mprotect] "n"(SYS_mprotect) 43 | :); 44 | return ret; 45 | } 46 | #endif 47 | 48 | #define ALIGN_FLOOR(address, range) ((uintptr_t)address & ~((uintptr_t)range - 1)) 49 | #define ALIGN_CEIL(address, range) (((uintptr_t)address + (uintptr_t)range - 1) & ~((uintptr_t)range - 1)) 50 | int _CodePatchPage(void *address, uint8_t *buffer, uint32_t buffer_size) { 51 | if (address == nullptr || buffer == nullptr || buffer_size == 0) { 52 | return -1; 53 | } 54 | 55 | size_t page_size = PAGE_SIZE; 56 | addr_t patch_page = ALIGN_FLOOR(address, page_size); 57 | 58 | // cross over page 59 | if ((addr_t)address + buffer_size > patch_page + page_size) { 60 | void *address_a = address; 61 | uint8_t *buffer_a = buffer; 62 | uint32_t buffer_size_a = (patch_page + page_size - (addr_t)address); 63 | auto ret = _CodePatchPage(address_a, buffer_a, buffer_size_a); 64 | if (ret == -1) { 65 | return ret; 66 | } 67 | 68 | void *address_b = (void *)((addr_t)address + buffer_size_a); 69 | uint8_t *buffer_b = buffer + buffer_size_a; 70 | uint32_t buffer_size_b = buffer_size - buffer_size_a; 71 | ret = _CodePatchPage(address_b, buffer_b, buffer_size_b); 72 | return ret; 73 | } 74 | 75 | addr_t remap_dest_page = patch_page; 76 | mach_vm_address_t remap_dummy_page = 0; 77 | 78 | auto self_task = mach_task_self(); 79 | kern_return_t kr; 80 | 81 | int orig_prot = 0; 82 | int orig_max_prot = 0; 83 | int share_mode = 0; 84 | int is_enable_remap = -1; 85 | if (is_enable_remap == -1) { 86 | auto get_region_info = [&](addr_t region_start) -> void { 87 | vm_region_submap_info_64 region_submap_info; 88 | mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64; 89 | mach_vm_address_t addr = region_start; 90 | mach_vm_size_t size = 0; 91 | natural_t depth = 0; 92 | while (1) { 93 | kr = mach_vm_region_recurse(mach_task_self(), (mach_vm_address_t *)&addr, (mach_vm_size_t *)&size, &depth, 94 | (vm_region_recurse_info_t)®ion_submap_info, &count); 95 | if (region_submap_info.is_submap) { 96 | depth++; 97 | } else { 98 | orig_prot = region_submap_info.protection; 99 | orig_max_prot = region_submap_info.max_protection; 100 | share_mode = region_submap_info.share_mode; 101 | return; 102 | } 103 | } 104 | }; 105 | get_region_info(remap_dest_page); 106 | if (orig_max_prot != 5 && share_mode != 2) { 107 | is_enable_remap = 1; 108 | } else { 109 | is_enable_remap = 0; 110 | } 111 | } 112 | if (is_enable_remap == 1) { 113 | addr_t remap_dummy_page = 0; 114 | { 115 | kr = mach_vm_allocate(self_task, (mach_vm_address_t *)&remap_dummy_page, page_size, VM_FLAGS_ANYWHERE); 116 | KERN_RETURN_ERROR(kr, -1); 117 | 118 | memcpy((void *)remap_dummy_page, (void *)patch_page, page_size); 119 | 120 | int offset = (int)((addr_t)address - patch_page); 121 | memcpy((void *)(remap_dummy_page + offset), buffer, buffer_size); 122 | 123 | kr = mach_vm_protect(self_task, remap_dummy_page, page_size, false, VM_PROT_READ | VM_PROT_EXECUTE); 124 | KERN_RETURN_ERROR(kr, -1); 125 | } 126 | 127 | vm_prot_t prot, max_prot; 128 | kr = mach_vm_remap(self_task, (mach_vm_address_t *)&remap_dest_page, page_size, 0, 129 | VM_FLAGS_OVERWRITE | VM_FLAGS_FIXED, self_task, remap_dummy_page, true, &prot, &max_prot, 130 | VM_INHERIT_COPY); 131 | KERN_RETURN_ERROR(kr, -1); 132 | 133 | kr = mach_vm_deallocate(self_task, remap_dummy_page, page_size); 134 | KERN_RETURN_ERROR(kr, -1); 135 | } else { 136 | 137 | if (0) { 138 | { 139 | auto kr = mach_vm_allocate(self_task, &remap_dummy_page, page_size, VM_FLAGS_ANYWHERE); 140 | KERN_RETURN_ERROR(kr, -1); 141 | 142 | kr = mach_vm_deallocate(self_task, remap_dummy_page, page_size); 143 | KERN_RETURN_ERROR(kr, -1); 144 | } 145 | 146 | vm_prot_t prot, max_prot; 147 | kr = mach_vm_remap(self_task, &remap_dummy_page, page_size, 0, VM_FLAGS_ANYWHERE, self_task, remap_dest_page, 148 | false, &prot, &max_prot, VM_INHERIT_SHARE); 149 | KERN_RETURN_ERROR(kr, -1); 150 | 151 | kr = mach_vm_protect(self_task, remap_dummy_page, page_size, false, VM_PROT_READ | VM_PROT_WRITE); 152 | // the kr always return KERN_PROTECTION_FAILURE 153 | kr = KERN_PROTECTION_FAILURE; 154 | 155 | memcpy((void *)(remap_dummy_page + ((uint64_t)address - remap_dest_page)), buffer, buffer_size); 156 | } 157 | 158 | static __typeof(vm_protect) *vm_protect_impl = vm_protect; 159 | 160 | { 161 | kr = vm_protect_impl(self_task, remap_dest_page, page_size, false, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_COPY); 162 | KERN_RETURN_ERROR(kr, -1); 163 | 164 | memcpy((void *)(patch_page + ((uint64_t)address - remap_dest_page)), buffer, buffer_size); 165 | 166 | kr = vm_protect_impl(self_task, remap_dest_page, page_size, false, 5); 167 | KERN_RETURN_ERROR(kr, -1); 168 | 169 | ClearCache((void *)remap_dest_page, (void *)((addr_t)remap_dest_page + page_size)); 170 | } 171 | } 172 | ClearCache(address, (void*)((addr_t)address + buffer_size)); 173 | 174 | 175 | return 0; 176 | } 177 | 178 | #elif defined(_LINUX) 179 | 180 | BOOL _CodePatchPage(void *target, void *buffer, size_t count) { 181 | DWORD flOld = 0; 182 | if (!VirtualProtect(target, count, PAGE_EXECUTE_READWRITE, &flOld)) { 183 | return FALSE; 184 | } 185 | memcpy(target, buffer, count); 186 | if (!VirtualProtect(target, count, flOld, &flOld)) { 187 | return FALSE; 188 | } 189 | return TRUE; 190 | } 191 | 192 | #elif defined(_WIN32) 193 | 194 | #include 195 | 196 | BOOL _CodePatchPage(void *target, void *buffer, size_t count) { 197 | DWORD flOld = 0; 198 | if (!VirtualProtect(target, count, PAGE_EXECUTE_READWRITE, &flOld)) { 199 | return FALSE; 200 | } 201 | memcpy(target, buffer, count); 202 | if (!VirtualProtect(target, count, flOld, &flOld)) { 203 | return FALSE; 204 | } 205 | return TRUE; 206 | } 207 | 208 | #endif 209 | 210 | 211 | #if !defined(_WIN32) 212 | extern "C" { 213 | 214 | static int g_lastError = 0; 215 | 216 | void SetLastError(int err) { 217 | g_lastError = err; 218 | } 219 | 220 | int GetLastError() { 221 | return g_lastError; 222 | } 223 | 224 | } 225 | #endif 226 | 227 | 228 | #include 229 | 230 | extern "C" { 231 | 232 | BOOL CodePatch(void *address, void *buffer, size_t buffer_size) { 233 | std::vector _buffer; 234 | if (!buffer) { 235 | _buffer.resize(buffer_size); 236 | buffer = _buffer.data(); 237 | memcpy(buffer, address, buffer_size); 238 | } 239 | char * start_addr = (char *)address; 240 | char * startPage = (char *)((uintptr_t)(start_addr + getpagesize()) & ~(getpagesize() - 1)); 241 | BOOL ret = TRUE; 242 | if (!(ret = _CodePatchPage(start_addr, (uint8_t *)buffer, patch_min(startPage - start_addr, (int)buffer_size)))) { 243 | return ret; 244 | } 245 | uint32_t bufloc = (uint32_t)patch_min(startPage - start_addr, (int)buffer_size); 246 | while (bufloc < buffer_size) { 247 | uint32_t nextbufloc = (uint32_t)patch_min(bufloc + 0x1000, buffer_size); 248 | if (!(ret = _CodePatchPage(start_addr + bufloc,(uint8_t *)( (char *)buffer + bufloc), nextbufloc - bufloc))) { 249 | return ret; 250 | } 251 | bufloc = nextbufloc; 252 | } 253 | return ret; 254 | } 255 | 256 | } 257 | -------------------------------------------------------------------------------- /Detours/src/mem_patch.h: -------------------------------------------------------------------------------- 1 | extern "C" { 2 | 3 | BOOL CodePatch(void *address, void *buffer, size_t buffer_size); 4 | 5 | } -------------------------------------------------------------------------------- /Detours/src/modules.cpp: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Module Enumeration Functions (modules.cpp of detours.lib) 4 | // 5 | // Microsoft Research Detours Package, Version 4.0.1 6 | // 7 | // Copyright (c) Microsoft Corporation. All rights reserved. 8 | // 9 | // Module enumeration functions. 10 | // 11 | 12 | // #define DETOUR_DEBUG 1 13 | #define DETOURS_INTERNAL 14 | #include "detours.h" 15 | 16 | #if DETOURS_VERSION != 0x4c0c1 // 0xMAJORcMINORcPATCH 17 | #error detours.h version mismatch 18 | #endif 19 | 20 | #define CLR_DIRECTORY OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR] 21 | #define IAT_DIRECTORY OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT] 22 | 23 | ////////////////////////////////////////////////////////////////////////////// 24 | // 25 | const GUID DETOUR_EXE_RESTORE_GUID = { 26 | 0xbda26f34, 0xbc82, 0x4829, 27 | { 0x9e, 0x64, 0x74, 0x2c, 0x4, 0xc8, 0x4f, 0xa0 } }; 28 | 29 | ////////////////////////////////////////////////////////////////////////////// 30 | // 31 | PDETOUR_SYM_INFO DetourLoadImageHlp(VOID) 32 | { 33 | static DETOUR_SYM_INFO symInfo; 34 | static PDETOUR_SYM_INFO pSymInfo = NULL; 35 | static BOOL failed = false; 36 | 37 | if (failed) { 38 | return NULL; 39 | } 40 | if (pSymInfo != NULL) { 41 | return pSymInfo; 42 | } 43 | 44 | ZeroMemory(&symInfo, sizeof(symInfo)); 45 | // Create a real handle to the process. 46 | #if 0 47 | DuplicateHandle(GetCurrentProcess(), 48 | GetCurrentProcess(), 49 | GetCurrentProcess(), 50 | &symInfo.hProcess, 51 | 0, 52 | FALSE, 53 | DUPLICATE_SAME_ACCESS); 54 | #else 55 | symInfo.hProcess = GetCurrentProcess(); 56 | #endif 57 | 58 | symInfo.hDbgHelp = LoadLibraryExW(L"dbghelp.dll", NULL, 0); 59 | if (symInfo.hDbgHelp == NULL) { 60 | abort: 61 | failed = true; 62 | if (symInfo.hDbgHelp != NULL) { 63 | FreeLibrary(symInfo.hDbgHelp); 64 | } 65 | symInfo.pfImagehlpApiVersionEx = NULL; 66 | symInfo.pfSymInitialize = NULL; 67 | symInfo.pfSymSetOptions = NULL; 68 | symInfo.pfSymGetOptions = NULL; 69 | symInfo.pfSymLoadModule64 = NULL; 70 | symInfo.pfSymGetModuleInfo64 = NULL; 71 | symInfo.pfSymFromName = NULL; 72 | return NULL; 73 | } 74 | 75 | symInfo.pfImagehlpApiVersionEx 76 | = (PF_ImagehlpApiVersionEx)GetProcAddress(symInfo.hDbgHelp, 77 | "ImagehlpApiVersionEx"); 78 | symInfo.pfSymInitialize 79 | = (PF_SymInitialize)GetProcAddress(symInfo.hDbgHelp, "SymInitialize"); 80 | symInfo.pfSymSetOptions 81 | = (PF_SymSetOptions)GetProcAddress(symInfo.hDbgHelp, "SymSetOptions"); 82 | symInfo.pfSymGetOptions 83 | = (PF_SymGetOptions)GetProcAddress(symInfo.hDbgHelp, "SymGetOptions"); 84 | symInfo.pfSymLoadModule64 85 | = (PF_SymLoadModule64)GetProcAddress(symInfo.hDbgHelp, "SymLoadModule64"); 86 | symInfo.pfSymGetModuleInfo64 87 | = (PF_SymGetModuleInfo64)GetProcAddress(symInfo.hDbgHelp, "SymGetModuleInfo64"); 88 | symInfo.pfSymFromName 89 | = (PF_SymFromName)GetProcAddress(symInfo.hDbgHelp, "SymFromName"); 90 | 91 | API_VERSION av; 92 | ZeroMemory(&av, sizeof(av)); 93 | av.MajorVersion = API_VERSION_NUMBER; 94 | 95 | if (symInfo.pfImagehlpApiVersionEx == NULL || 96 | symInfo.pfSymInitialize == NULL || 97 | symInfo.pfSymLoadModule64 == NULL || 98 | symInfo.pfSymGetModuleInfo64 == NULL || 99 | symInfo.pfSymFromName == NULL) { 100 | goto abort; 101 | } 102 | 103 | symInfo.pfImagehlpApiVersionEx(&av); 104 | if (av.MajorVersion < API_VERSION_NUMBER) { 105 | goto abort; 106 | } 107 | 108 | if (!symInfo.pfSymInitialize(symInfo.hProcess, NULL, FALSE)) { 109 | // We won't retry the initialize if it fails. 110 | goto abort; 111 | } 112 | 113 | if (symInfo.pfSymGetOptions != NULL && symInfo.pfSymSetOptions != NULL) { 114 | DWORD dw = symInfo.pfSymGetOptions(); 115 | 116 | dw &= ~(SYMOPT_CASE_INSENSITIVE | 117 | SYMOPT_UNDNAME | 118 | SYMOPT_DEFERRED_LOADS | 119 | 0); 120 | dw |= ( 121 | #if defined(SYMOPT_EXACT_SYMBOLS) 122 | SYMOPT_EXACT_SYMBOLS | 123 | #endif 124 | #if defined(SYMOPT_NO_UNQUALIFIED_LOADS) 125 | SYMOPT_NO_UNQUALIFIED_LOADS | 126 | #endif 127 | SYMOPT_DEFERRED_LOADS | 128 | #if defined(SYMOPT_FAIL_CRITICAL_ERRORS) 129 | SYMOPT_FAIL_CRITICAL_ERRORS | 130 | #endif 131 | #if defined(SYMOPT_INCLUDE_32BIT_MODULES) 132 | SYMOPT_INCLUDE_32BIT_MODULES | 133 | #endif 134 | 0); 135 | symInfo.pfSymSetOptions(dw); 136 | } 137 | 138 | pSymInfo = &symInfo; 139 | return pSymInfo; 140 | } 141 | 142 | PVOID WINAPI DetourFindFunction(_In_ LPCSTR pszModule, 143 | _In_ LPCSTR pszFunction) 144 | { 145 | if (pszFunction == NULL) { 146 | SetLastError(ERROR_INVALID_PARAMETER); 147 | return NULL; 148 | } 149 | 150 | /////////////////////////////////////////////// First, try GetProcAddress. 151 | // 152 | #pragma prefast(suppress:28752, "We don't do the unicode conversion for LoadLibraryExA.") 153 | HMODULE hModule = LoadLibraryExA(pszModule, NULL, 0); 154 | if (hModule == NULL) { 155 | return NULL; 156 | } 157 | 158 | PBYTE pbCode = (PBYTE)GetProcAddress(hModule, pszFunction); 159 | if (pbCode) { 160 | return pbCode; 161 | } 162 | 163 | ////////////////////////////////////////////////////// Then try ImageHelp. 164 | // 165 | DETOUR_TRACE(("DetourFindFunction(%hs, %hs)\n", pszModule, pszFunction)); 166 | PDETOUR_SYM_INFO pSymInfo = DetourLoadImageHlp(); 167 | if (pSymInfo == NULL) { 168 | DETOUR_TRACE(("DetourLoadImageHlp failed: %lu\n", 169 | GetLastError())); 170 | return NULL; 171 | } 172 | 173 | if (pSymInfo->pfSymLoadModule64(pSymInfo->hProcess, NULL, 174 | (PCHAR)pszModule, NULL, 175 | (DWORD64)hModule, 0) == 0) { 176 | if (ERROR_SUCCESS != GetLastError()) { 177 | DETOUR_TRACE(("SymLoadModule64(%p) failed: %lu\n", 178 | pSymInfo->hProcess, GetLastError())); 179 | return NULL; 180 | } 181 | } 182 | 183 | HRESULT hrRet; 184 | CHAR szFullName[512]; 185 | IMAGEHLP_MODULE64 modinfo; 186 | ZeroMemory(&modinfo, sizeof(modinfo)); 187 | modinfo.SizeOfStruct = sizeof(modinfo); 188 | if (!pSymInfo->pfSymGetModuleInfo64(pSymInfo->hProcess, (DWORD64)hModule, &modinfo)) { 189 | DETOUR_TRACE(("SymGetModuleInfo64(%p, %p) failed: %lu\n", 190 | pSymInfo->hProcess, hModule, GetLastError())); 191 | return NULL; 192 | } 193 | 194 | hrRet = StringCchCopyA(szFullName, sizeof(szFullName)/sizeof(CHAR), modinfo.ModuleName); 195 | if (FAILED(hrRet)) { 196 | DETOUR_TRACE(("StringCchCopyA failed: %08lx\n", hrRet)); 197 | return NULL; 198 | } 199 | hrRet = StringCchCatA(szFullName, sizeof(szFullName)/sizeof(CHAR), "!"); 200 | if (FAILED(hrRet)) { 201 | DETOUR_TRACE(("StringCchCatA failed: %08lx\n", hrRet)); 202 | return NULL; 203 | } 204 | hrRet = StringCchCatA(szFullName, sizeof(szFullName)/sizeof(CHAR), pszFunction); 205 | if (FAILED(hrRet)) { 206 | DETOUR_TRACE(("StringCchCatA failed: %08lx\n", hrRet)); 207 | return NULL; 208 | } 209 | 210 | struct CFullSymbol : SYMBOL_INFO { 211 | CHAR szRestOfName[512]; 212 | } symbol; 213 | ZeroMemory(&symbol, sizeof(symbol)); 214 | //symbol.ModBase = (ULONG64)hModule; 215 | symbol.SizeOfStruct = sizeof(SYMBOL_INFO); 216 | #ifdef DBHLPAPI 217 | symbol.MaxNameLen = sizeof(symbol.szRestOfName)/sizeof(symbol.szRestOfName[0]); 218 | #else 219 | symbol.MaxNameLength = sizeof(symbol.szRestOfName)/sizeof(symbol.szRestOfName[0]); 220 | #endif 221 | 222 | if (!pSymInfo->pfSymFromName(pSymInfo->hProcess, szFullName, &symbol)) { 223 | DETOUR_TRACE(("SymFromName(%hs) failed: %lu\n", szFullName, GetLastError())); 224 | return NULL; 225 | } 226 | 227 | #if defined(DETOURS_IA64) 228 | // On the IA64, we get a raw code pointer from the symbol engine 229 | // and have to convert it to a wrapped [code pointer, global pointer]. 230 | // 231 | PPLABEL_DESCRIPTOR pldEntry = (PPLABEL_DESCRIPTOR)DetourGetEntryPoint(hModule); 232 | PPLABEL_DESCRIPTOR pldSymbol = new PLABEL_DESCRIPTOR; 233 | 234 | pldSymbol->EntryPoint = symbol.Address; 235 | pldSymbol->GlobalPointer = pldEntry->GlobalPointer; 236 | return (PBYTE)pldSymbol; 237 | #elif defined(DETOURS_ARM) 238 | // On the ARM, we get a raw code pointer, which we must convert into a 239 | // valied Thumb2 function pointer. 240 | return DETOURS_PBYTE_TO_PFUNC(symbol.Address); 241 | #else 242 | return (PBYTE)symbol.Address; 243 | #endif 244 | } 245 | 246 | //////////////////////////////////////////////////// Module Image Functions. 247 | // 248 | 249 | HMODULE WINAPI DetourEnumerateModules(_In_opt_ HMODULE hModuleLast) 250 | { 251 | PBYTE pbLast = (PBYTE)hModuleLast + MM_ALLOCATION_GRANULARITY; 252 | 253 | MEMORY_BASIC_INFORMATION mbi; 254 | ZeroMemory(&mbi, sizeof(mbi)); 255 | 256 | // Find the next memory region that contains a mapped PE image. 257 | // 258 | for (;; pbLast = (PBYTE)mbi.BaseAddress + mbi.RegionSize) { 259 | if (VirtualQuery(pbLast, &mbi, sizeof(mbi)) <= 0) { 260 | break; 261 | } 262 | 263 | // Skip uncommitted regions and guard pages. 264 | // 265 | if ((mbi.State != MEM_COMMIT) || 266 | ((mbi.Protect & 0xff) == PAGE_NOACCESS) || 267 | (mbi.Protect & PAGE_GUARD)) { 268 | continue; 269 | } 270 | 271 | __try { 272 | PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pbLast; 273 | if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE || 274 | (DWORD)pDosHeader->e_lfanew > mbi.RegionSize || 275 | (DWORD)pDosHeader->e_lfanew < sizeof(*pDosHeader)) { 276 | continue; 277 | } 278 | 279 | PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader + 280 | pDosHeader->e_lfanew); 281 | if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) { 282 | continue; 283 | } 284 | 285 | SetLastError(NO_ERROR); 286 | return (HMODULE)pDosHeader; 287 | } 288 | #pragma prefast(suppress:28940, "A bad pointer means this probably isn't a PE header.") 289 | __except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? 290 | EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { 291 | continue; 292 | } 293 | } 294 | return NULL; 295 | } 296 | 297 | PVOID WINAPI DetourGetEntryPoint(_In_opt_ HMODULE hModule) 298 | { 299 | PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hModule; 300 | if (hModule == NULL) { 301 | pDosHeader = (PIMAGE_DOS_HEADER)GetModuleHandleW(NULL); 302 | } 303 | 304 | __try { 305 | #pragma warning(suppress:6011) // GetModuleHandleW(NULL) never returns NULL. 306 | if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) { 307 | SetLastError(ERROR_BAD_EXE_FORMAT); 308 | return NULL; 309 | } 310 | 311 | PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader + 312 | pDosHeader->e_lfanew); 313 | if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) { 314 | SetLastError(ERROR_INVALID_EXE_SIGNATURE); 315 | return NULL; 316 | } 317 | if (pNtHeader->FileHeader.SizeOfOptionalHeader == 0) { 318 | SetLastError(ERROR_EXE_MARKED_INVALID); 319 | return NULL; 320 | } 321 | 322 | PDETOUR_CLR_HEADER pClrHeader = NULL; 323 | if (pNtHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { 324 | if (((PIMAGE_NT_HEADERS32)pNtHeader)->CLR_DIRECTORY.VirtualAddress != 0 && 325 | ((PIMAGE_NT_HEADERS32)pNtHeader)->CLR_DIRECTORY.Size != 0) { 326 | pClrHeader = (PDETOUR_CLR_HEADER) 327 | (((PBYTE)pDosHeader) 328 | + ((PIMAGE_NT_HEADERS32)pNtHeader)->CLR_DIRECTORY.VirtualAddress); 329 | } 330 | } 331 | else if (pNtHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) { 332 | if (((PIMAGE_NT_HEADERS64)pNtHeader)->CLR_DIRECTORY.VirtualAddress != 0 && 333 | ((PIMAGE_NT_HEADERS64)pNtHeader)->CLR_DIRECTORY.Size != 0) { 334 | pClrHeader = (PDETOUR_CLR_HEADER) 335 | (((PBYTE)pDosHeader) 336 | + ((PIMAGE_NT_HEADERS64)pNtHeader)->CLR_DIRECTORY.VirtualAddress); 337 | } 338 | } 339 | 340 | if (pClrHeader != NULL) { 341 | // For MSIL assemblies, we want to use the _Cor entry points. 342 | 343 | HMODULE hClr = GetModuleHandleW(L"MSCOREE.DLL"); 344 | if (hClr == NULL) { 345 | return NULL; 346 | } 347 | 348 | SetLastError(NO_ERROR); 349 | return (PVOID)GetProcAddress(hClr, "_CorExeMain"); 350 | } 351 | 352 | SetLastError(NO_ERROR); 353 | 354 | // Pure resource DLLs have neither an entry point nor CLR information 355 | // so handle them by returning NULL (LastError is NO_ERROR) 356 | if (pNtHeader->OptionalHeader.AddressOfEntryPoint == 0) { 357 | return NULL; 358 | } 359 | 360 | return ((PBYTE)pDosHeader) + 361 | pNtHeader->OptionalHeader.AddressOfEntryPoint; 362 | } 363 | __except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? 364 | EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { 365 | SetLastError(ERROR_EXE_MARKED_INVALID); 366 | return NULL; 367 | } 368 | } 369 | 370 | ULONG WINAPI DetourGetModuleSize(_In_opt_ HMODULE hModule) 371 | { 372 | PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hModule; 373 | if (hModule == NULL) { 374 | pDosHeader = (PIMAGE_DOS_HEADER)GetModuleHandleW(NULL); 375 | } 376 | 377 | __try { 378 | #pragma warning(suppress:6011) // GetModuleHandleW(NULL) never returns NULL. 379 | if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) { 380 | SetLastError(ERROR_BAD_EXE_FORMAT); 381 | return NULL; 382 | } 383 | 384 | PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader + 385 | pDosHeader->e_lfanew); 386 | if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) { 387 | SetLastError(ERROR_INVALID_EXE_SIGNATURE); 388 | return NULL; 389 | } 390 | if (pNtHeader->FileHeader.SizeOfOptionalHeader == 0) { 391 | SetLastError(ERROR_EXE_MARKED_INVALID); 392 | return NULL; 393 | } 394 | SetLastError(NO_ERROR); 395 | 396 | return (pNtHeader->OptionalHeader.SizeOfImage); 397 | } 398 | __except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? 399 | EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { 400 | SetLastError(ERROR_EXE_MARKED_INVALID); 401 | return NULL; 402 | } 403 | } 404 | 405 | HMODULE WINAPI DetourGetContainingModule(_In_ PVOID pvAddr) 406 | { 407 | MEMORY_BASIC_INFORMATION mbi; 408 | ZeroMemory(&mbi, sizeof(mbi)); 409 | 410 | __try { 411 | if (VirtualQuery(pvAddr, &mbi, sizeof(mbi)) <= 0) { 412 | SetLastError(ERROR_BAD_EXE_FORMAT); 413 | return NULL; 414 | } 415 | 416 | // Skip uncommitted regions and guard pages. 417 | // 418 | if ((mbi.State != MEM_COMMIT) || 419 | ((mbi.Protect & 0xff) == PAGE_NOACCESS) || 420 | (mbi.Protect & PAGE_GUARD)) { 421 | SetLastError(ERROR_BAD_EXE_FORMAT); 422 | return NULL; 423 | } 424 | 425 | PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mbi.AllocationBase; 426 | if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) { 427 | SetLastError(ERROR_BAD_EXE_FORMAT); 428 | return NULL; 429 | } 430 | 431 | PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader + 432 | pDosHeader->e_lfanew); 433 | if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) { 434 | SetLastError(ERROR_INVALID_EXE_SIGNATURE); 435 | return NULL; 436 | } 437 | if (pNtHeader->FileHeader.SizeOfOptionalHeader == 0) { 438 | SetLastError(ERROR_EXE_MARKED_INVALID); 439 | return NULL; 440 | } 441 | SetLastError(NO_ERROR); 442 | 443 | return (HMODULE)pDosHeader; 444 | } 445 | __except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? 446 | EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { 447 | SetLastError(ERROR_INVALID_EXE_SIGNATURE); 448 | return NULL; 449 | } 450 | } 451 | 452 | 453 | static inline PBYTE RvaAdjust(_Pre_notnull_ PIMAGE_DOS_HEADER pDosHeader, _In_ DWORD raddr) 454 | { 455 | if (raddr != NULL) { 456 | return ((PBYTE)pDosHeader) + raddr; 457 | } 458 | return NULL; 459 | } 460 | 461 | BOOL WINAPI DetourEnumerateExports(_In_ HMODULE hModule, 462 | _In_opt_ PVOID pContext, 463 | _In_ PF_DETOUR_ENUMERATE_EXPORT_CALLBACK pfExport) 464 | { 465 | if (pfExport == NULL) { 466 | SetLastError(ERROR_INVALID_PARAMETER); 467 | return FALSE; 468 | } 469 | 470 | PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hModule; 471 | if (hModule == NULL) { 472 | pDosHeader = (PIMAGE_DOS_HEADER)GetModuleHandleW(NULL); 473 | } 474 | 475 | __try { 476 | #pragma warning(suppress:6011) // GetModuleHandleW(NULL) never returns NULL. 477 | if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) { 478 | SetLastError(ERROR_BAD_EXE_FORMAT); 479 | return NULL; 480 | } 481 | 482 | PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader + 483 | pDosHeader->e_lfanew); 484 | if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) { 485 | SetLastError(ERROR_INVALID_EXE_SIGNATURE); 486 | return FALSE; 487 | } 488 | if (pNtHeader->FileHeader.SizeOfOptionalHeader == 0) { 489 | SetLastError(ERROR_EXE_MARKED_INVALID); 490 | return FALSE; 491 | } 492 | 493 | PIMAGE_EXPORT_DIRECTORY pExportDir 494 | = (PIMAGE_EXPORT_DIRECTORY) 495 | RvaAdjust(pDosHeader, 496 | pNtHeader->OptionalHeader 497 | .DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); 498 | 499 | if (pExportDir == NULL) { 500 | SetLastError(ERROR_EXE_MARKED_INVALID); 501 | return FALSE; 502 | } 503 | 504 | PBYTE pExportDirEnd = (PBYTE)pExportDir + pNtHeader->OptionalHeader 505 | .DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; 506 | PDWORD pdwFunctions = (PDWORD)RvaAdjust(pDosHeader, pExportDir->AddressOfFunctions); 507 | PDWORD pdwNames = (PDWORD)RvaAdjust(pDosHeader, pExportDir->AddressOfNames); 508 | PWORD pwOrdinals = (PWORD)RvaAdjust(pDosHeader, pExportDir->AddressOfNameOrdinals); 509 | 510 | for (DWORD nFunc = 0; nFunc < pExportDir->NumberOfFunctions; nFunc++) { 511 | PBYTE pbCode = (pdwFunctions != NULL) 512 | ? (PBYTE)RvaAdjust(pDosHeader, pdwFunctions[nFunc]) : NULL; 513 | PCHAR pszName = NULL; 514 | 515 | // if the pointer is in the export region, then it is a forwarder. 516 | if (pbCode > (PBYTE)pExportDir && pbCode < pExportDirEnd) { 517 | pbCode = NULL; 518 | } 519 | 520 | for (DWORD n = 0; n < pExportDir->NumberOfNames; n++) { 521 | if (pwOrdinals[n] == nFunc) { 522 | pszName = (pdwNames != NULL) 523 | ? (PCHAR)RvaAdjust(pDosHeader, pdwNames[n]) : NULL; 524 | break; 525 | } 526 | } 527 | ULONG nOrdinal = pExportDir->Base + nFunc; 528 | 529 | if (!pfExport(pContext, nOrdinal, pszName, pbCode)) { 530 | break; 531 | } 532 | } 533 | SetLastError(NO_ERROR); 534 | return TRUE; 535 | } 536 | __except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? 537 | EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { 538 | SetLastError(ERROR_EXE_MARKED_INVALID); 539 | return NULL; 540 | } 541 | } 542 | 543 | BOOL WINAPI DetourEnumerateImportsEx(_In_opt_ HMODULE hModule, 544 | _In_opt_ PVOID pContext, 545 | _In_opt_ PF_DETOUR_IMPORT_FILE_CALLBACK pfImportFile, 546 | _In_opt_ PF_DETOUR_IMPORT_FUNC_CALLBACK_EX pfImportFunc) 547 | { 548 | PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hModule; 549 | if (hModule == NULL) { 550 | pDosHeader = (PIMAGE_DOS_HEADER)GetModuleHandleW(NULL); 551 | } 552 | 553 | __try { 554 | #pragma warning(suppress:6011) // GetModuleHandleW(NULL) never returns NULL. 555 | if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) { 556 | SetLastError(ERROR_BAD_EXE_FORMAT); 557 | return FALSE; 558 | } 559 | 560 | PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader + 561 | pDosHeader->e_lfanew); 562 | if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) { 563 | SetLastError(ERROR_INVALID_EXE_SIGNATURE); 564 | return FALSE; 565 | } 566 | if (pNtHeader->FileHeader.SizeOfOptionalHeader == 0) { 567 | SetLastError(ERROR_EXE_MARKED_INVALID); 568 | return FALSE; 569 | } 570 | 571 | PIMAGE_IMPORT_DESCRIPTOR iidp 572 | = (PIMAGE_IMPORT_DESCRIPTOR) 573 | RvaAdjust(pDosHeader, 574 | pNtHeader->OptionalHeader 575 | .DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); 576 | 577 | if (iidp == NULL) { 578 | SetLastError(ERROR_EXE_MARKED_INVALID); 579 | return FALSE; 580 | } 581 | 582 | for (; iidp->OriginalFirstThunk != 0; iidp++) { 583 | 584 | PCSTR pszName = (PCHAR)RvaAdjust(pDosHeader, iidp->Name); 585 | if (pszName == NULL) { 586 | SetLastError(ERROR_EXE_MARKED_INVALID); 587 | return FALSE; 588 | } 589 | 590 | PIMAGE_THUNK_DATA pThunks = (PIMAGE_THUNK_DATA) 591 | RvaAdjust(pDosHeader, iidp->OriginalFirstThunk); 592 | PVOID * pAddrs = (PVOID *) 593 | RvaAdjust(pDosHeader, iidp->FirstThunk); 594 | 595 | HMODULE hFile = DetourGetContainingModule(pAddrs[0]); 596 | 597 | if (pfImportFile != NULL) { 598 | if (!pfImportFile(pContext, hFile, pszName)) { 599 | break; 600 | } 601 | } 602 | 603 | DWORD nNames = 0; 604 | if (pThunks) { 605 | for (; pThunks[nNames].u1.Ordinal; nNames++) { 606 | DWORD nOrdinal = 0; 607 | PCSTR pszFunc = NULL; 608 | 609 | if (IMAGE_SNAP_BY_ORDINAL(pThunks[nNames].u1.Ordinal)) { 610 | nOrdinal = (DWORD)IMAGE_ORDINAL(pThunks[nNames].u1.Ordinal); 611 | } 612 | else { 613 | pszFunc = (PCSTR)RvaAdjust(pDosHeader, 614 | (DWORD)pThunks[nNames].u1.AddressOfData + 2); 615 | } 616 | 617 | if (pfImportFunc != NULL) { 618 | if (!pfImportFunc(pContext, 619 | nOrdinal, 620 | pszFunc, 621 | &pAddrs[nNames])) { 622 | break; 623 | } 624 | } 625 | } 626 | if (pfImportFunc != NULL) { 627 | pfImportFunc(pContext, 0, NULL, NULL); 628 | } 629 | } 630 | } 631 | if (pfImportFile != NULL) { 632 | pfImportFile(pContext, NULL, NULL); 633 | } 634 | SetLastError(NO_ERROR); 635 | return TRUE; 636 | } 637 | __except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? 638 | EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { 639 | SetLastError(ERROR_EXE_MARKED_INVALID); 640 | return FALSE; 641 | } 642 | } 643 | 644 | // Context for DetourEnumerateImportsThunk, which adapts "regular" callbacks for use with "Ex". 645 | struct _DETOUR_ENUMERATE_IMPORTS_THUNK_CONTEXT 646 | { 647 | PVOID pContext; 648 | PF_DETOUR_IMPORT_FUNC_CALLBACK pfImportFunc; 649 | }; 650 | 651 | // Callback for DetourEnumerateImportsEx that adapts DetourEnumerateImportsEx 652 | // for use with a DetourEnumerateImports callback -- derefence the IAT and pass the value on. 653 | 654 | static 655 | BOOL 656 | CALLBACK 657 | DetourEnumerateImportsThunk(_In_ PVOID VoidContext, 658 | _In_ DWORD nOrdinal, 659 | _In_opt_ PCSTR pszFunc, 660 | _In_opt_ PVOID* ppvFunc) 661 | { 662 | _DETOUR_ENUMERATE_IMPORTS_THUNK_CONTEXT const * const 663 | pContext = (_DETOUR_ENUMERATE_IMPORTS_THUNK_CONTEXT*)VoidContext; 664 | return pContext->pfImportFunc(pContext->pContext, nOrdinal, pszFunc, ppvFunc ? *ppvFunc : NULL); 665 | } 666 | 667 | BOOL WINAPI DetourEnumerateImports(_In_opt_ HMODULE hModule, 668 | _In_opt_ PVOID pContext, 669 | _In_opt_ PF_DETOUR_IMPORT_FILE_CALLBACK pfImportFile, 670 | _In_opt_ PF_DETOUR_IMPORT_FUNC_CALLBACK pfImportFunc) 671 | { 672 | if (pfImportFile == NULL || pfImportFunc == NULL) { 673 | SetLastError(ERROR_INVALID_PARAMETER); 674 | return FALSE; 675 | } 676 | 677 | _DETOUR_ENUMERATE_IMPORTS_THUNK_CONTEXT const context = { pContext, pfImportFunc }; 678 | 679 | return DetourEnumerateImportsEx(hModule, 680 | (PVOID)&context, 681 | pfImportFile, 682 | &DetourEnumerateImportsThunk); 683 | } 684 | 685 | static PDETOUR_LOADED_BINARY WINAPI GetPayloadSectionFromModule(HMODULE hModule) 686 | { 687 | PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hModule; 688 | if (hModule == NULL) { 689 | pDosHeader = (PIMAGE_DOS_HEADER)GetModuleHandleW(NULL); 690 | } 691 | 692 | __try { 693 | #pragma warning(suppress:6011) // GetModuleHandleW(NULL) never returns NULL. 694 | if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) { 695 | SetLastError(ERROR_BAD_EXE_FORMAT); 696 | return NULL; 697 | } 698 | 699 | PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader + 700 | pDosHeader->e_lfanew); 701 | if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) { 702 | SetLastError(ERROR_INVALID_EXE_SIGNATURE); 703 | return NULL; 704 | } 705 | if (pNtHeader->FileHeader.SizeOfOptionalHeader == 0) { 706 | SetLastError(ERROR_EXE_MARKED_INVALID); 707 | return NULL; 708 | } 709 | 710 | PIMAGE_SECTION_HEADER pSectionHeaders 711 | = (PIMAGE_SECTION_HEADER)((PBYTE)pNtHeader 712 | + sizeof(pNtHeader->Signature) 713 | + sizeof(pNtHeader->FileHeader) 714 | + pNtHeader->FileHeader.SizeOfOptionalHeader); 715 | 716 | for (DWORD n = 0; n < pNtHeader->FileHeader.NumberOfSections; n++) { 717 | if (strcmp((PCHAR)pSectionHeaders[n].Name, ".detour") == 0) { 718 | if (pSectionHeaders[n].VirtualAddress == 0 || 719 | pSectionHeaders[n].SizeOfRawData == 0) { 720 | 721 | break; 722 | } 723 | 724 | PBYTE pbData = (PBYTE)pDosHeader + pSectionHeaders[n].VirtualAddress; 725 | DETOUR_SECTION_HEADER *pHeader = (DETOUR_SECTION_HEADER *)pbData; 726 | if (pHeader->cbHeaderSize < sizeof(DETOUR_SECTION_HEADER) || 727 | pHeader->nSignature != DETOUR_SECTION_HEADER_SIGNATURE) { 728 | 729 | break; 730 | } 731 | 732 | if (pHeader->nDataOffset == 0) { 733 | pHeader->nDataOffset = pHeader->cbHeaderSize; 734 | } 735 | SetLastError(NO_ERROR); 736 | return (PBYTE)pHeader; 737 | } 738 | } 739 | SetLastError(ERROR_EXE_MARKED_INVALID); 740 | return NULL; 741 | } 742 | __except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? 743 | EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { 744 | SetLastError(ERROR_EXE_MARKED_INVALID); 745 | return NULL; 746 | } 747 | } 748 | 749 | DWORD WINAPI DetourGetSizeOfPayloads(_In_opt_ HMODULE hModule) 750 | { 751 | PDETOUR_LOADED_BINARY pBinary = GetPayloadSectionFromModule(hModule); 752 | if (pBinary == NULL) { 753 | // Error set by GetPayloadSectionFromModule. 754 | return 0; 755 | } 756 | 757 | __try { 758 | DETOUR_SECTION_HEADER *pHeader = (DETOUR_SECTION_HEADER *)pBinary; 759 | if (pHeader->cbHeaderSize < sizeof(DETOUR_SECTION_HEADER) || 760 | pHeader->nSignature != DETOUR_SECTION_HEADER_SIGNATURE) { 761 | 762 | SetLastError(ERROR_INVALID_HANDLE); 763 | return 0; 764 | } 765 | SetLastError(NO_ERROR); 766 | return pHeader->cbDataSize; 767 | } 768 | __except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? 769 | EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { 770 | SetLastError(ERROR_INVALID_HANDLE); 771 | return 0; 772 | } 773 | } 774 | 775 | _Writable_bytes_(*pcbData) 776 | _Readable_bytes_(*pcbData) 777 | _Success_(return != NULL) 778 | PVOID WINAPI DetourFindPayload(_In_opt_ HMODULE hModule, 779 | _In_ REFGUID rguid, 780 | _Out_opt_ DWORD *pcbData) 781 | { 782 | PBYTE pbData = NULL; 783 | if (pcbData) { 784 | *pcbData = 0; 785 | } 786 | 787 | PDETOUR_LOADED_BINARY pBinary = GetPayloadSectionFromModule(hModule); 788 | if (pBinary == NULL) { 789 | // Error set by GetPayloadSectionFromModule. 790 | return NULL; 791 | } 792 | 793 | __try { 794 | DETOUR_SECTION_HEADER *pHeader = (DETOUR_SECTION_HEADER *)pBinary; 795 | if (pHeader->cbHeaderSize < sizeof(DETOUR_SECTION_HEADER) || 796 | pHeader->nSignature != DETOUR_SECTION_HEADER_SIGNATURE) { 797 | 798 | SetLastError(ERROR_INVALID_EXE_SIGNATURE); 799 | return NULL; 800 | } 801 | 802 | PBYTE pbBeg = ((PBYTE)pHeader) + pHeader->nDataOffset; 803 | PBYTE pbEnd = ((PBYTE)pHeader) + pHeader->cbDataSize; 804 | 805 | for (pbData = pbBeg; pbData < pbEnd;) { 806 | DETOUR_SECTION_RECORD *pSection = (DETOUR_SECTION_RECORD *)pbData; 807 | 808 | if (DetourAreSameGuid(pSection->guid, rguid)) { 809 | if (pcbData) { 810 | *pcbData = pSection->cbBytes - sizeof(*pSection); 811 | } 812 | SetLastError(NO_ERROR); 813 | return (PBYTE)(pSection + 1); 814 | } 815 | 816 | pbData = (PBYTE)pSection + pSection->cbBytes; 817 | } 818 | SetLastError(ERROR_INVALID_HANDLE); 819 | return NULL; 820 | } 821 | __except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? 822 | EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { 823 | SetLastError(ERROR_INVALID_HANDLE); 824 | return NULL; 825 | } 826 | } 827 | 828 | _Writable_bytes_(*pcbData) 829 | _Readable_bytes_(*pcbData) 830 | _Success_(return != NULL) 831 | PVOID WINAPI DetourFindPayloadEx(_In_ REFGUID rguid, 832 | _Out_opt_ DWORD *pcbData) 833 | { 834 | for (HMODULE hMod = NULL; (hMod = DetourEnumerateModules(hMod)) != NULL;) { 835 | PVOID pvData; 836 | 837 | pvData = DetourFindPayload(hMod, rguid, pcbData); 838 | if (pvData != NULL) { 839 | return pvData; 840 | } 841 | } 842 | SetLastError(ERROR_MOD_NOT_FOUND); 843 | return NULL; 844 | } 845 | 846 | BOOL WINAPI DetourFreePayload(_In_ PVOID pvData) 847 | { 848 | BOOL fSucceeded = FALSE; 849 | 850 | // If you have any doubts about the following code, please refer to the comments in DetourCopyPayloadToProcess. 851 | HMODULE hModule = DetourGetContainingModule(pvData); 852 | DETOUR_ASSERT(hModule != NULL); 853 | if (hModule != NULL) { 854 | fSucceeded = VirtualFree(hModule, 0, MEM_RELEASE); 855 | DETOUR_ASSERT(fSucceeded); 856 | if (fSucceeded) { 857 | hModule = NULL; 858 | } 859 | } 860 | 861 | return fSucceeded; 862 | } 863 | 864 | BOOL WINAPI DetourRestoreAfterWithEx(_In_reads_bytes_(cbData) PVOID pvData, 865 | _In_ DWORD cbData) 866 | { 867 | PDETOUR_EXE_RESTORE pder = (PDETOUR_EXE_RESTORE)pvData; 868 | 869 | if (pder->cb != sizeof(*pder) || pder->cb > cbData) { 870 | SetLastError(ERROR_BAD_EXE_FORMAT); 871 | return FALSE; 872 | } 873 | 874 | DWORD dwPermIdh = ~0u; 875 | DWORD dwPermInh = ~0u; 876 | DWORD dwPermClr = ~0u; 877 | DWORD dwIgnore; 878 | BOOL fSucceeded = FALSE; 879 | BOOL fUpdated32To64 = FALSE; 880 | 881 | if (pder->pclr != NULL && pder->clr.Flags != ((PDETOUR_CLR_HEADER)pder->pclr)->Flags) { 882 | // If we had to promote the 32/64-bit agnostic IL to 64-bit, we can't restore 883 | // that. 884 | fUpdated32To64 = TRUE; 885 | } 886 | 887 | if (DetourVirtualProtectSameExecute(pder->pidh, pder->cbidh, 888 | PAGE_EXECUTE_READWRITE, &dwPermIdh)) { 889 | if (DetourVirtualProtectSameExecute(pder->pinh, pder->cbinh, 890 | PAGE_EXECUTE_READWRITE, &dwPermInh)) { 891 | 892 | CopyMemory(pder->pidh, &pder->idh, pder->cbidh); 893 | CopyMemory(pder->pinh, &pder->inh, pder->cbinh); 894 | 895 | if (pder->pclr != NULL && !fUpdated32To64) { 896 | if (DetourVirtualProtectSameExecute(pder->pclr, pder->cbclr, 897 | PAGE_EXECUTE_READWRITE, &dwPermClr)) { 898 | CopyMemory(pder->pclr, &pder->clr, pder->cbclr); 899 | VirtualProtect(pder->pclr, pder->cbclr, dwPermClr, &dwIgnore); 900 | fSucceeded = TRUE; 901 | } 902 | } 903 | else { 904 | fSucceeded = TRUE; 905 | } 906 | VirtualProtect(pder->pinh, pder->cbinh, dwPermInh, &dwIgnore); 907 | } 908 | VirtualProtect(pder->pidh, pder->cbidh, dwPermIdh, &dwIgnore); 909 | } 910 | // Delete the payload after successful recovery to prevent repeated restore 911 | if (fSucceeded) { 912 | DetourFreePayload(pder); 913 | pder = NULL; 914 | } 915 | return fSucceeded; 916 | } 917 | 918 | BOOL WINAPI DetourRestoreAfterWith() 919 | { 920 | PVOID pvData; 921 | DWORD cbData; 922 | 923 | pvData = DetourFindPayloadEx(DETOUR_EXE_RESTORE_GUID, &cbData); 924 | 925 | if (pvData != NULL && cbData != 0) { 926 | return DetourRestoreAfterWithEx(pvData, cbData); 927 | } 928 | SetLastError(ERROR_MOD_NOT_FOUND); 929 | return FALSE; 930 | } 931 | 932 | // End of File 933 | -------------------------------------------------------------------------------- /Detours/src/uimports.cpp: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Add DLLs to a module import table (uimports.cpp of detours.lib) 4 | // 5 | // Microsoft Research Detours Package, Version 4.0.1 6 | // 7 | // Copyright (c) Microsoft Corporation. All rights reserved. 8 | // 9 | // Note that this file is included into creatwth.cpp one or more times 10 | // (once for each supported module format). 11 | // 12 | 13 | #if DETOURS_VERSION != 0x4c0c1 // 0xMAJORcMINORcPATCH 14 | #error detours.h version mismatch 15 | #endif 16 | 17 | // UpdateImports32 aka UpdateImports64 18 | static BOOL UPDATE_IMPORTS_XX(HANDLE hProcess, 19 | HMODULE hModule, 20 | __in_ecount(nDlls) LPCSTR *plpDlls, 21 | DWORD nDlls) 22 | { 23 | BOOL fSucceeded = FALSE; 24 | DWORD cbNew = 0; 25 | 26 | BYTE * pbNew = NULL; 27 | DWORD i; 28 | SIZE_T cbRead; 29 | DWORD n; 30 | 31 | PBYTE pbModule = (PBYTE)hModule; 32 | 33 | IMAGE_DOS_HEADER idh; 34 | ZeroMemory(&idh, sizeof(idh)); 35 | if (!ReadProcessMemory(hProcess, pbModule, &idh, sizeof(idh), &cbRead) 36 | || cbRead < sizeof(idh)) { 37 | 38 | DETOUR_TRACE(("ReadProcessMemory(idh@%p..%p) failed: %lu\n", 39 | pbModule, pbModule + sizeof(idh), GetLastError())); 40 | 41 | finish: 42 | if (pbNew != NULL) { 43 | delete[] pbNew; 44 | pbNew = NULL; 45 | } 46 | return fSucceeded; 47 | } 48 | 49 | IMAGE_NT_HEADERS_XX inh; 50 | ZeroMemory(&inh, sizeof(inh)); 51 | 52 | if (!ReadProcessMemory(hProcess, pbModule + idh.e_lfanew, &inh, sizeof(inh), &cbRead) 53 | || cbRead < sizeof(inh)) { 54 | DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p) failed: %lu\n", 55 | pbModule + idh.e_lfanew, 56 | pbModule + idh.e_lfanew + sizeof(inh), 57 | GetLastError())); 58 | goto finish; 59 | } 60 | 61 | if (inh.OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC_XX) { 62 | DETOUR_TRACE(("Wrong size image (%04x != %04x).\n", 63 | inh.OptionalHeader.Magic, IMAGE_NT_OPTIONAL_HDR_MAGIC_XX)); 64 | SetLastError(ERROR_INVALID_BLOCK); 65 | goto finish; 66 | } 67 | 68 | // Zero out the bound table so loader doesn't use it instead of our new table. 69 | inh.BOUND_DIRECTORY.VirtualAddress = 0; 70 | inh.BOUND_DIRECTORY.Size = 0; 71 | 72 | // Find the size of the mapped file. 73 | DWORD dwSec = idh.e_lfanew + 74 | FIELD_OFFSET(IMAGE_NT_HEADERS_XX, OptionalHeader) + 75 | inh.FileHeader.SizeOfOptionalHeader; 76 | 77 | for (i = 0; i < inh.FileHeader.NumberOfSections; i++) { 78 | IMAGE_SECTION_HEADER ish; 79 | ZeroMemory(&ish, sizeof(ish)); 80 | 81 | if (!ReadProcessMemory(hProcess, pbModule + dwSec + sizeof(ish) * i, &ish, 82 | sizeof(ish), &cbRead) 83 | || cbRead < sizeof(ish)) { 84 | 85 | DETOUR_TRACE(("ReadProcessMemory(ish@%p..%p) failed: %lu\n", 86 | pbModule + dwSec + sizeof(ish) * i, 87 | pbModule + dwSec + sizeof(ish) * (i + 1), 88 | GetLastError())); 89 | goto finish; 90 | } 91 | 92 | DETOUR_TRACE(("ish[%lu] : va=%08lx sr=%lu\n", i, ish.VirtualAddress, ish.SizeOfRawData)); 93 | 94 | // If the linker didn't suggest an IAT in the data directories, the 95 | // loader will look for the section of the import directory to be used 96 | // for this instead. Since we put out new IMPORT_DIRECTORY outside any 97 | // section boundary, the loader will not find it. So we provide one 98 | // explicitly to avoid the search. 99 | // 100 | if (inh.IAT_DIRECTORY.VirtualAddress == 0 && 101 | inh.IMPORT_DIRECTORY.VirtualAddress >= ish.VirtualAddress && 102 | inh.IMPORT_DIRECTORY.VirtualAddress < ish.VirtualAddress + ish.SizeOfRawData) { 103 | 104 | inh.IAT_DIRECTORY.VirtualAddress = ish.VirtualAddress; 105 | inh.IAT_DIRECTORY.Size = ish.SizeOfRawData; 106 | } 107 | } 108 | 109 | if (inh.IMPORT_DIRECTORY.VirtualAddress != 0 && inh.IMPORT_DIRECTORY.Size == 0) { 110 | 111 | // Don't worry about changing the PE file, 112 | // because the load information of the original PE header has been saved and will be restored. 113 | // The change here is just for the following code to work normally 114 | 115 | PIMAGE_IMPORT_DESCRIPTOR pImageImport = (PIMAGE_IMPORT_DESCRIPTOR)(pbModule + inh.IMPORT_DIRECTORY.VirtualAddress); 116 | 117 | do { 118 | IMAGE_IMPORT_DESCRIPTOR ImageImport; 119 | if (!ReadProcessMemory(hProcess, pImageImport, &ImageImport, sizeof(ImageImport), NULL)) { 120 | DETOUR_TRACE(("ReadProcessMemory failed: %lu\n", GetLastError())); 121 | goto finish; 122 | } 123 | inh.IMPORT_DIRECTORY.Size += sizeof(IMAGE_IMPORT_DESCRIPTOR); 124 | if (!ImageImport.Name) { 125 | break; 126 | } 127 | ++pImageImport; 128 | } while (TRUE); 129 | 130 | DWORD dwLastError = GetLastError(); 131 | OutputDebugString(TEXT("[This PE file has an import table, but the import table size is marked as 0. This is an error.") 132 | TEXT("If it is not repaired, the launched program will not work properly, Detours has automatically repaired its import table size for you! ! !]\r\n")); 133 | if (GetLastError() != dwLastError) { 134 | SetLastError(dwLastError); 135 | } 136 | } 137 | 138 | DETOUR_TRACE((" Imports: %p..%p\n", 139 | pbModule + inh.IMPORT_DIRECTORY.VirtualAddress, 140 | pbModule + inh.IMPORT_DIRECTORY.VirtualAddress + 141 | inh.IMPORT_DIRECTORY.Size)); 142 | 143 | // Calculate new import directory size. Note that since inh is from another 144 | // process, inh could have been corrupted. We need to protect against 145 | // integer overflow in allocation calculations. 146 | DWORD nOldDlls = inh.IMPORT_DIRECTORY.Size / sizeof(IMAGE_IMPORT_DESCRIPTOR); 147 | DWORD obRem; 148 | if (DWordMult(sizeof(IMAGE_IMPORT_DESCRIPTOR), nDlls, &obRem) != S_OK) { 149 | DETOUR_TRACE(("too many new DLLs.\n")); 150 | goto finish; 151 | } 152 | DWORD obOld; 153 | if (DWordAdd(obRem, sizeof(IMAGE_IMPORT_DESCRIPTOR) * nOldDlls, &obOld) != S_OK) { 154 | DETOUR_TRACE(("DLL entries overflow.\n")); 155 | goto finish; 156 | } 157 | DWORD obTab = PadToDwordPtr(obOld); 158 | // Check for integer overflow. 159 | if (obTab < obOld) { 160 | DETOUR_TRACE(("DLL entries padding overflow.\n")); 161 | goto finish; 162 | } 163 | DWORD stSize; 164 | if (DWordMult(sizeof(DWORD_XX) * 4, nDlls, &stSize) != S_OK) { 165 | DETOUR_TRACE(("String table overflow.\n")); 166 | goto finish; 167 | } 168 | DWORD obDll; 169 | if (DWordAdd(obTab, stSize, &obDll) != S_OK) { 170 | DETOUR_TRACE(("Import table size overflow\n")); 171 | goto finish; 172 | } 173 | DWORD obStr = obDll; 174 | cbNew = obStr; 175 | for (n = 0; n < nDlls; n++) { 176 | if (DWordAdd(cbNew, PadToDword((DWORD)strlen(plpDlls[n]) + 1), &cbNew) != S_OK) { 177 | DETOUR_TRACE(("Overflow adding string table entry\n")); 178 | goto finish; 179 | } 180 | } 181 | pbNew = new BYTE [cbNew]; 182 | if (pbNew == NULL) { 183 | DETOUR_TRACE(("new BYTE [cbNew] failed.\n")); 184 | goto finish; 185 | } 186 | ZeroMemory(pbNew, cbNew); 187 | 188 | PBYTE pbBase = pbModule; 189 | PBYTE pbNext = pbBase 190 | + inh.OptionalHeader.BaseOfCode 191 | + inh.OptionalHeader.SizeOfCode 192 | + inh.OptionalHeader.SizeOfInitializedData 193 | + inh.OptionalHeader.SizeOfUninitializedData; 194 | if (pbBase < pbNext) { 195 | pbBase = pbNext; 196 | } 197 | DETOUR_TRACE(("pbBase = %p\n", pbBase)); 198 | 199 | PBYTE pbNewIid = FindAndAllocateNearBase(hProcess, pbModule, pbBase, cbNew); 200 | if (pbNewIid == NULL) { 201 | DETOUR_TRACE(("FindAndAllocateNearBase failed.\n")); 202 | goto finish; 203 | } 204 | 205 | PIMAGE_IMPORT_DESCRIPTOR piid = (PIMAGE_IMPORT_DESCRIPTOR)pbNew; 206 | IMAGE_THUNK_DATAXX *pt = NULL; 207 | 208 | DWORD obBase = (DWORD)(pbNewIid - pbModule); 209 | DWORD dwProtect = 0; 210 | 211 | if (inh.IMPORT_DIRECTORY.VirtualAddress != 0) { 212 | // Read the old import directory if it exists. 213 | DETOUR_TRACE(("IMPORT_DIRECTORY perms=%lx\n", dwProtect)); 214 | 215 | if (!ReadProcessMemory(hProcess, 216 | pbModule + inh.IMPORT_DIRECTORY.VirtualAddress, 217 | &piid[nDlls], 218 | nOldDlls * sizeof(IMAGE_IMPORT_DESCRIPTOR), &cbRead) 219 | || cbRead < nOldDlls * sizeof(IMAGE_IMPORT_DESCRIPTOR)) { 220 | 221 | DETOUR_TRACE(("ReadProcessMemory(imports) failed: %lu\n", GetLastError())); 222 | goto finish; 223 | } 224 | } 225 | 226 | for (n = 0; n < nDlls; n++) { 227 | HRESULT hrRet = StringCchCopyA((char*)pbNew + obStr, cbNew - obStr, plpDlls[n]); 228 | if (FAILED(hrRet)) { 229 | DETOUR_TRACE(("StringCchCopyA failed: %08lx\n", hrRet)); 230 | goto finish; 231 | } 232 | 233 | // After copying the string, we patch up the size "??" bits if any. 234 | hrRet = ReplaceOptionalSizeA((char*)pbNew + obStr, 235 | cbNew - obStr, 236 | DETOURS_STRINGIFY(DETOURS_BITS_XX)); 237 | if (FAILED(hrRet)) { 238 | DETOUR_TRACE(("ReplaceOptionalSizeA failed: %08lx\n", hrRet)); 239 | goto finish; 240 | } 241 | 242 | DWORD nOffset = obTab + (sizeof(IMAGE_THUNK_DATAXX) * (4 * n)); 243 | piid[n].OriginalFirstThunk = obBase + nOffset; 244 | 245 | // We need 2 thunks for the import table and 2 thunks for the IAT. 246 | // One for an ordinal import and one to mark the end of the list. 247 | pt = ((IMAGE_THUNK_DATAXX*)(pbNew + nOffset)); 248 | pt[0].u1.Ordinal = IMAGE_ORDINAL_FLAG_XX + 1; 249 | pt[1].u1.Ordinal = 0; 250 | 251 | nOffset = obTab + (sizeof(IMAGE_THUNK_DATAXX) * ((4 * n) + 2)); 252 | piid[n].FirstThunk = obBase + nOffset; 253 | pt = ((IMAGE_THUNK_DATAXX*)(pbNew + nOffset)); 254 | pt[0].u1.Ordinal = IMAGE_ORDINAL_FLAG_XX + 1; 255 | pt[1].u1.Ordinal = 0; 256 | piid[n].TimeDateStamp = 0; 257 | piid[n].ForwarderChain = 0; 258 | piid[n].Name = obBase + obStr; 259 | 260 | obStr += PadToDword((DWORD)strlen(plpDlls[n]) + 1); 261 | } 262 | _Analysis_assume_(obStr <= cbNew); 263 | 264 | #if 0 265 | for (i = 0; i < nDlls + nOldDlls; i++) { 266 | DETOUR_TRACE(("%8d. Look=%08x Time=%08x Fore=%08x Name=%08x Addr=%08x\n", 267 | i, 268 | piid[i].OriginalFirstThunk, 269 | piid[i].TimeDateStamp, 270 | piid[i].ForwarderChain, 271 | piid[i].Name, 272 | piid[i].FirstThunk)); 273 | if (piid[i].OriginalFirstThunk == 0 && piid[i].FirstThunk == 0) { 274 | break; 275 | } 276 | } 277 | #endif 278 | 279 | if (!WriteProcessMemory(hProcess, pbNewIid, pbNew, obStr, NULL)) { 280 | DETOUR_TRACE(("WriteProcessMemory(iid) failed: %lu\n", GetLastError())); 281 | goto finish; 282 | } 283 | 284 | DETOUR_TRACE(("obBaseBef = %08lx..%08lx\n", 285 | inh.IMPORT_DIRECTORY.VirtualAddress, 286 | inh.IMPORT_DIRECTORY.VirtualAddress + inh.IMPORT_DIRECTORY.Size)); 287 | DETOUR_TRACE(("obBaseAft = %08lx..%08lx\n", obBase, obBase + obStr)); 288 | 289 | // In this case the file didn't have an import directory in first place, 290 | // so we couldn't fix the missing IAT above. We still need to explicitly 291 | // provide an IAT to prevent to loader from looking for one. 292 | // 293 | if (inh.IAT_DIRECTORY.VirtualAddress == 0) { 294 | inh.IAT_DIRECTORY.VirtualAddress = obBase; 295 | inh.IAT_DIRECTORY.Size = cbNew; 296 | } 297 | 298 | inh.IMPORT_DIRECTORY.VirtualAddress = obBase; 299 | inh.IMPORT_DIRECTORY.Size = cbNew; 300 | 301 | /////////////////////// Update the NT header for the new import directory. 302 | // 303 | if (!DetourVirtualProtectSameExecuteEx(hProcess, pbModule, inh.OptionalHeader.SizeOfHeaders, 304 | PAGE_EXECUTE_READWRITE, &dwProtect)) { 305 | DETOUR_TRACE(("VirtualProtectEx(inh) write failed: %lu\n", GetLastError())); 306 | goto finish; 307 | } 308 | 309 | inh.OptionalHeader.CheckSum = 0; 310 | 311 | if (!WriteProcessMemory(hProcess, pbModule, &idh, sizeof(idh), NULL)) { 312 | DETOUR_TRACE(("WriteProcessMemory(idh) failed: %lu\n", GetLastError())); 313 | goto finish; 314 | } 315 | DETOUR_TRACE(("WriteProcessMemory(idh:%p..%p)\n", pbModule, pbModule + sizeof(idh))); 316 | 317 | if (!WriteProcessMemory(hProcess, pbModule + idh.e_lfanew, &inh, sizeof(inh), NULL)) { 318 | DETOUR_TRACE(("WriteProcessMemory(inh) failed: %lu\n", GetLastError())); 319 | goto finish; 320 | } 321 | DETOUR_TRACE(("WriteProcessMemory(inh:%p..%p)\n", 322 | pbModule + idh.e_lfanew, 323 | pbModule + idh.e_lfanew + sizeof(inh))); 324 | 325 | if (!VirtualProtectEx(hProcess, pbModule, inh.OptionalHeader.SizeOfHeaders, 326 | dwProtect, &dwProtect)) { 327 | DETOUR_TRACE(("VirtualProtectEx(idh) restore failed: %lu\n", GetLastError())); 328 | goto finish; 329 | } 330 | 331 | fSucceeded = TRUE; 332 | goto finish; 333 | } 334 | -------------------------------------------------------------------------------- /Detours/src/windows_shim.h: -------------------------------------------------------------------------------- 1 | // Define DETOUR_TRACE macro 2 | // #define DETOUR_DEBUG 1 3 | #ifndef DETOUR_TRACE 4 | #if DETOUR_DEBUG 5 | #define DETOUR_TRACE(x) printf x 6 | #include 7 | #else 8 | #define DETOUR_TRACE(x) 9 | #endif 10 | #endif 11 | 12 | // Definition for Windows related things 13 | #ifndef _WIN32 14 | 15 | #include 16 | #include 17 | 18 | #define CALLBACK 19 | #define WINAPI 20 | 21 | typedef uint32_t DWORD, *PDWORD; 22 | typedef int16_t SHORT, *PSHORT; 23 | typedef uint16_t USHORT, *PUSHORT; 24 | 25 | typedef uint16_t UINT16; 26 | typedef unsigned char UCHAR; 27 | typedef char CHAR; 28 | typedef uint8_t BYTE; 29 | typedef uint8_t *PBYTE; 30 | typedef int16_t SHORT; 31 | typedef uint16_t USHORT, WORD; 32 | typedef int32_t BOOL; 33 | typedef int32_t INT, INT32; 34 | typedef uint32_t UINT, UINT32; 35 | typedef int64_t INT64, LONG64; 36 | typedef int64_t __int64; 37 | typedef uint64_t UINT64, ULONG64; 38 | typedef long long LONGLONG; 39 | typedef void VOID, *HMODULE, *PVOID, *LPVOID; 40 | #define TRUE ((BOOL)1) 41 | #define FALSE ((BOOL)0) 42 | // long is 8bytes in Clang/GCC, but 4bytes on Windows 43 | typedef int LONG; 44 | typedef unsigned int ULONG, *PULONG; 45 | typedef unsigned int ULONG32, * PULONG32; 46 | typedef uintptr_t ULONG_PTR; 47 | typedef intptr_t LONG_PTR; 48 | typedef size_t SIZE_T; 49 | 50 | typedef char *LPSTR; 51 | typedef const char *LPCSTR; 52 | typedef const void *LPCVOID; 53 | typedef void *HANDLE; 54 | 55 | #define ERROR_INVALID_DATA 0x10001 56 | #define ERROR_INVALID_OPERATION 0x10002 57 | #define ERROR_NOT_ENOUGH_MEMORY 0x10003 58 | #define ERROR_INVALID_PARAMETER 0x10004 59 | #define ERROR_INVALID_HANDLE 0x10005 60 | #define ERROR_INVALID_BLOCK 0x10006 61 | #define ERROR_DYNAMIC_CODE_BLOCKED 1655L 62 | #define ERROR_NOT_SAME_THREAD 0x10020 63 | 64 | #define ERROR_MACH_FAIL_BASE 0x20100 65 | #define ERROR_ERRNO_FAIL_BASE 0x20200 66 | #define NO_ERROR 0 67 | 68 | extern "C" { 69 | extern void SetLastError(int err); 70 | extern int GetLastError(); 71 | } 72 | 73 | static int GetCurrentThreadId() { 74 | return 0; 75 | } 76 | 77 | static HANDLE GetCurrentThread() { 78 | return (HANDLE)-2; 79 | } 80 | 81 | static HANDLE GetCurrentProcess() { 82 | return (HANDLE)-1; 83 | } 84 | 85 | #else 86 | 87 | #include 88 | 89 | #endif // _WIN32 90 | 91 | 92 | #ifdef DETOURS_INTERNAL 93 | 94 | extern "C" { 95 | static unsigned long DetourGetModuleSize(void *) { 96 | return 0x1337; 97 | } 98 | } 99 | 100 | #include 101 | #undef LONG_MAX 102 | #undef LONG_MIN 103 | #define LONG_MAX INT_MAX 104 | #define LONG_MIN INT_MIN 105 | 106 | // Definition for windows shim functions 107 | #ifdef _WIN32 108 | 109 | static int getpagesize() { 110 | return 0x1000; 111 | } 112 | 113 | #else 114 | 115 | #include 116 | #include 117 | #include 118 | 119 | #include 120 | #include 121 | 122 | #ifdef _LINUX 123 | #include 124 | #include 125 | #endif 126 | 127 | #ifdef _DARWIN 128 | #include 129 | #include 130 | #include 131 | #include 132 | #include 133 | #include 134 | #endif 135 | 136 | #define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] 137 | #define ARRAYSIZE(A) (sizeof(A)/sizeof(A[0])) 138 | 139 | #define UNALIGNED 140 | 141 | #define UNREFERENCED_PARAMETER(P) (P) 142 | 143 | static inline 144 | LONG InterlockedCompareExchange(LONG *ptr, LONG nval, LONG oval) 145 | { 146 | return __sync_val_compare_and_swap (ptr, nval, oval); 147 | } 148 | 149 | static inline ULONG PtrToUlong(PVOID ptr) { 150 | return (ULONG)(ULONG_PTR)(ptr); 151 | } 152 | 153 | static void CopyMemory( 154 | PVOID Destination, 155 | const VOID *Source, 156 | SIZE_T Length 157 | ) { 158 | memcpy(Destination, Source, Length); 159 | } 160 | 161 | #define PAGE_NOACCESS 1 162 | #define PAGE_READONLY 2 163 | #define PAGE_READWRITE 4 164 | #define PAGE_EXECUTE 0x10 165 | #define PAGE_WRITECOPY 0x8 166 | #define PAGE_EXECUTE_READ (PAGE_READONLY * PAGE_EXECUTE) 167 | #define PAGE_EXECUTE_READWRITE (PAGE_READWRITE * PAGE_EXECUTE) 168 | #define PAGE_EXECUTE_WRITECOPY (PAGE_WRITECOPY * PAGE_EXECUTE) 169 | 170 | #define MEM_COMMIT 0x00001000 171 | #define MEM_FREE 0x00010000 172 | #define MEM_RESERVE 0x00002000 173 | 174 | #define MEM_RELEASE 0 175 | 176 | typedef struct _MEMORY_BASIC_INFORMATION { 177 | PVOID BaseAddress; 178 | PVOID AllocationBase; 179 | DWORD AllocationProtect; 180 | WORD PartitionId; 181 | SIZE_T RegionSize; 182 | DWORD State; 183 | DWORD Protect; 184 | DWORD Type; 185 | } MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION; 186 | 187 | static void WinProtToRWX(DWORD flProtect, int *r, int *w, int *x) { 188 | if (flProtect && (flProtect & 0xF) == 0) { 189 | *x = 1; 190 | flProtect >>= 4; 191 | } 192 | switch (flProtect) { 193 | case PAGE_READONLY: 194 | *r = 1; 195 | *w = 0; 196 | break; 197 | case PAGE_READWRITE: 198 | *r = 1; 199 | *w = 1; 200 | break; 201 | default: 202 | *r = 1; 203 | *w = 1; 204 | break; 205 | } 206 | } 207 | 208 | static DWORD RWXToWinProt(int r, int w, int x) { 209 | DWORD ret = PAGE_NOACCESS; 210 | if (r && w) { 211 | ret = PAGE_READWRITE; 212 | } else if (r) { 213 | ret = PAGE_READONLY; 214 | } 215 | if (x) { 216 | ret *= PAGE_EXECUTE; 217 | } 218 | return ret; 219 | } 220 | 221 | static SIZE_T VirtualQuery( 222 | LPCVOID lpAddress, 223 | PMEMORY_BASIC_INFORMATION lpBuffer, 224 | SIZE_T dwLength 225 | ) { 226 | if (!lpBuffer) return 0; 227 | #if defined(_LINUX) 228 | int a = 0; 229 | unsigned int prot = 0; 230 | int f = open("/proc/self/maps", O_RDONLY); 231 | char b[1024] = { 0 }; 232 | int b_pos = 0; 233 | unsigned long last_addr0 = 0, last_addr1 = 0; 234 | while ((read(f, &a, 1)) >= 0) { 235 | b[b_pos++] = a; 236 | if (b_pos >= sizeof(b) || a == '\n') { 237 | char*end0 = NULL; 238 | unsigned long addr0 = strtoul(b, &end0, 16); 239 | char*end1 = NULL; 240 | unsigned long addr1 = strtoul(end0+1, &end1, 16); 241 | if ((void*)addr0 <= lpAddress && lpAddress < (void*)addr1) { 242 | lpBuffer->BaseAddress = (PVOID)addr0; 243 | lpBuffer->AllocationBase = (PVOID)addr0; 244 | lpBuffer->RegionSize = addr1 - addr0; 245 | int r = (end1+1)[0] == 'r'; 246 | int w = (end1+1)[1] == 'w'; 247 | int x = (end1+1)[2] == 'x'; 248 | int prot = RWXToWinProt(r,w,x); 249 | lpBuffer->AllocationProtect = prot; 250 | lpBuffer->PartitionId = 0; 251 | lpBuffer->State = MEM_COMMIT; 252 | break; 253 | } else if (lpAddress < (void*)addr0) { 254 | lpBuffer->BaseAddress = (PVOID)last_addr1; 255 | lpBuffer->AllocationBase = (PVOID)addr0; 256 | lpBuffer->RegionSize = addr0 - last_addr1; 257 | lpBuffer->AllocationProtect = 0; 258 | lpBuffer->PartitionId = 0; 259 | lpBuffer->State = MEM_FREE; 260 | break; 261 | } 262 | memset(b, 0, sizeof(b)); 263 | b_pos = 0; 264 | last_addr0 = addr0; 265 | last_addr1 = addr1; 266 | } 267 | } 268 | 269 | close(f); 270 | return sizeof(MEMORY_BASIC_INFORMATION); 271 | #elif defined(_DARWIN) 272 | kern_return_t kr = KERN_SUCCESS; 273 | mach_port_t object_name; 274 | mach_vm_size_t size_info; 275 | mach_vm_address_t address_info = (mach_vm_address_t)lpAddress; 276 | mach_msg_type_number_t info_cnt = sizeof (vm_region_basic_info_data_64_t); 277 | vm_region_basic_info_data_64_t info; 278 | kr = mach_vm_region(mach_task_self(), &address_info, &size_info, VM_REGION_BASIC_INFO_64, (vm_region_info_t)&info, &info_cnt, &object_name); 279 | if (kr) { 280 | SetLastError(kr + ERROR_MACH_FAIL_BASE); 281 | } 282 | if ((ULONG_PTR)address_info <= (ULONG_PTR)lpAddress) { 283 | lpBuffer->BaseAddress = (PVOID)address_info; 284 | lpBuffer->AllocationBase = (PVOID)address_info; 285 | lpBuffer->RegionSize = size_info; 286 | lpBuffer->State = MEM_COMMIT; 287 | } else { 288 | lpBuffer->BaseAddress = (PVOID)lpAddress; 289 | lpBuffer->AllocationBase = (PVOID)lpAddress; 290 | lpBuffer->RegionSize = (ULONG_PTR)address_info - (ULONG_PTR)lpAddress; 291 | lpBuffer->State = MEM_FREE; 292 | } 293 | int r = info.protection & VM_PROT_READ; 294 | int w = info.protection & VM_PROT_WRITE; 295 | int x = info.protection & VM_PROT_EXECUTE; 296 | int prot = RWXToWinProt(r,w,x); 297 | lpBuffer->AllocationProtect = prot; 298 | lpBuffer->PartitionId = 0; 299 | return sizeof(MEMORY_BASIC_INFORMATION); 300 | #endif 301 | return 0; 302 | } 303 | 304 | static BOOL VirtualProtect(PVOID addr, SIZE_T dwSize, DWORD flNewProtect, DWORD *flOld) { 305 | DETOUR_TRACE(("VirtualProtect(%p, %lx, 0x%x)\n", addr, dwSize, flNewProtect)); 306 | int newR = 0, newW = 0, newX = 0; 307 | WinProtToRWX(flNewProtect, &newR, &newW, &newX); 308 | 309 | #if defined(_LINUX) || defined(_DARWIN) 310 | ULONG_PTR aligned_addr = (ULONG_PTR)addr & ~(getpagesize() - 1); 311 | SIZE_T aligned_size = (ULONG_PTR)addr - aligned_addr + dwSize; 312 | MEMORY_BASIC_INFORMATION mbi; 313 | if (!VirtualQuery((void *)aligned_addr, &mbi, sizeof(mbi))) { 314 | return FALSE; 315 | } 316 | int oldProt = mbi.AllocationProtect; 317 | *flOld = oldProt; 318 | BOOL ignoreRet = FALSE; 319 | #ifdef _DARWIN 320 | if (newW && newX) { 321 | DETOUR_TRACE(("W^X detected, removing executing bit & ignoring error!\n")); 322 | newX = 0; 323 | ignoreRet = TRUE; 324 | // DETOUR_TRACE(("VirtualProtect: W^X detected, ignoring and directly return!\n")); 325 | // return TRUE; 326 | } 327 | #endif 328 | int newProt = 0; 329 | newProt |= newR ? PROT_READ : 0; 330 | newProt |= newW ? PROT_WRITE : 0; 331 | newProt |= newX ? PROT_EXEC : 0; 332 | int ret = mprotect((void *)aligned_addr, aligned_size, newProt); 333 | if (!ignoreRet && ret == -1){ 334 | DETOUR_TRACE(("VirtualProtect mprotect fail... errno=%d\n", errno)); 335 | SetLastError(ERROR_ERRNO_FAIL_BASE + errno); 336 | return FALSE; 337 | } 338 | return TRUE; 339 | #else 340 | #error Unknown OS (Please define _LINUX or _DARWIN) 341 | #endif 342 | return FALSE; 343 | } 344 | 345 | static SIZE_T VirtualQueryEx( 346 | HANDLE hProcess, 347 | LPCVOID lpAddress, 348 | PMEMORY_BASIC_INFORMATION lpBuffer, 349 | SIZE_T dwLength 350 | ) { 351 | if (hProcess != GetCurrentProcess()) { 352 | return 0; 353 | } 354 | return VirtualQuery(lpAddress, lpBuffer, dwLength); 355 | } 356 | 357 | static BOOL VirtualProtectEx(HANDLE hProcess, PVOID addr, SIZE_T dwSize, DWORD flNewProtect, DWORD *flOld) { 358 | if (hProcess != GetCurrentProcess()) { 359 | return FALSE; 360 | } 361 | return VirtualProtect(addr, dwSize, flNewProtect, flOld); 362 | } 363 | 364 | static LPVOID VirtualAlloc( 365 | LPVOID lpAddress, 366 | SIZE_T dwSize, 367 | DWORD flAllocationType, 368 | DWORD flProtect 369 | ) { 370 | DETOUR_TRACE(("VirtualAlloc(%p, 0x%lx, %d, 0x%x)\n", lpAddress, dwSize, flAllocationType, flProtect)); 371 | int newR = 0, newW = 0, newX = 0; 372 | WinProtToRWX(flProtect, &newR, &newW, &newX); 373 | DETOUR_TRACE(("RWX parsed: %d %d %d\n", newR, newW, newX)); 374 | #ifdef _DARWIN 375 | if (newW && newX) { 376 | DETOUR_TRACE(("W^X detected, removing executing bit!\n")); 377 | newX = 0; 378 | } 379 | #endif 380 | int newProt = 0; 381 | newProt |= newR ? PROT_READ : 0; 382 | newProt |= newW ? PROT_WRITE : 0; 383 | newProt |= newX ? PROT_EXEC : 0; 384 | 385 | LPVOID retAddr = mmap(lpAddress, dwSize, newProt, MAP_SHARED | MAP_ANONYMOUS, 0, 0); 386 | DETOUR_TRACE(("mmap(%p, 0x%lx, %d) = %p, errno = %d\n", lpAddress, dwSize, newProt, retAddr, errno)); 387 | 388 | if (retAddr == (LPVOID)-1) { 389 | SetLastError(ERROR_ERRNO_FAIL_BASE + errno); 390 | return NULL; 391 | } 392 | return retAddr; 393 | } 394 | 395 | #define FlushInstructionCache _FlushInstructionCache 396 | 397 | #ifdef _DARWIN 398 | #include 399 | #endif 400 | static BOOL FlushInstructionCache( 401 | HANDLE hProcess, 402 | LPCVOID lpBaseAddress, 403 | SIZE_T dwSize 404 | ) { 405 | #ifdef _DARWIN 406 | sys_icache_invalidate(( void *)lpBaseAddress,dwSize); 407 | #endif 408 | return TRUE; 409 | } 410 | 411 | static BOOL VirtualFree( 412 | LPVOID lpAddress, 413 | SIZE_T dwSize, 414 | DWORD dwFreeType 415 | ) { 416 | if(munmap(lpAddress, dwSize)) { 417 | SetLastError(ERROR_ERRNO_FAIL_BASE + errno); 418 | return FALSE; 419 | }; 420 | return TRUE; 421 | } 422 | 423 | static DWORD ResumeThread( 424 | HANDLE hThread 425 | ) { 426 | return 1; 427 | } 428 | 429 | static DWORD SuspendThread( 430 | HANDLE hThread 431 | ) { 432 | return 0; 433 | } 434 | 435 | #define ZeroMemory(a,s) memset((a), 0, (s)) 436 | #define __debugbreak() (void)0 437 | #define DebugBreak() (void)0 438 | 439 | #endif // _WIN32 440 | 441 | #endif // DETOURS_INTERNAL 442 | 443 | #undef DETOUR_TRACE 444 | -------------------------------------------------------------------------------- /DetoursTest.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.33529.398 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DetoursTest", "DetoursTest\DetoursTest.vcxproj", "{57941E38-685B-44C3-9D74-2E8B061B5862}" 7 | ProjectSection(ProjectDependencies) = postProject 8 | {3B8C6EDE-D8B8-4297-94A4-30C90A850F12} = {3B8C6EDE-D8B8-4297-94A4-30C90A850F12} 9 | EndProjectSection 10 | EndProject 11 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Detours", "Detours\Detours.vcxproj", "{3B8C6EDE-D8B8-4297-94A4-30C90A850F12}" 12 | EndProject 13 | Global 14 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 15 | Debug|ARM = Debug|ARM 16 | Debug|ARM64 = Debug|ARM64 17 | Debug|x64 = Debug|x64 18 | Debug|x86 = Debug|x86 19 | Release|ARM = Release|ARM 20 | Release|ARM64 = Release|ARM64 21 | Release|x64 = Release|x64 22 | Release|x86 = Release|x86 23 | EndGlobalSection 24 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 25 | {57941E38-685B-44C3-9D74-2E8B061B5862}.Debug|ARM.ActiveCfg = Debug|ARM 26 | {57941E38-685B-44C3-9D74-2E8B061B5862}.Debug|ARM.Build.0 = Debug|ARM 27 | {57941E38-685B-44C3-9D74-2E8B061B5862}.Debug|ARM64.ActiveCfg = Debug|ARM64 28 | {57941E38-685B-44C3-9D74-2E8B061B5862}.Debug|ARM64.Build.0 = Debug|ARM64 29 | {57941E38-685B-44C3-9D74-2E8B061B5862}.Debug|x64.ActiveCfg = Debug|x64 30 | {57941E38-685B-44C3-9D74-2E8B061B5862}.Debug|x64.Build.0 = Debug|x64 31 | {57941E38-685B-44C3-9D74-2E8B061B5862}.Debug|x86.ActiveCfg = Debug|Win32 32 | {57941E38-685B-44C3-9D74-2E8B061B5862}.Debug|x86.Build.0 = Debug|Win32 33 | {57941E38-685B-44C3-9D74-2E8B061B5862}.Release|ARM.ActiveCfg = Release|ARM 34 | {57941E38-685B-44C3-9D74-2E8B061B5862}.Release|ARM.Build.0 = Release|ARM 35 | {57941E38-685B-44C3-9D74-2E8B061B5862}.Release|ARM64.ActiveCfg = Release|ARM64 36 | {57941E38-685B-44C3-9D74-2E8B061B5862}.Release|ARM64.Build.0 = Release|ARM64 37 | {57941E38-685B-44C3-9D74-2E8B061B5862}.Release|x64.ActiveCfg = Release|x64 38 | {57941E38-685B-44C3-9D74-2E8B061B5862}.Release|x64.Build.0 = Release|x64 39 | {57941E38-685B-44C3-9D74-2E8B061B5862}.Release|x86.ActiveCfg = Release|Win32 40 | {57941E38-685B-44C3-9D74-2E8B061B5862}.Release|x86.Build.0 = Release|Win32 41 | {3B8C6EDE-D8B8-4297-94A4-30C90A850F12}.Debug|ARM.ActiveCfg = Debug|ARM 42 | {3B8C6EDE-D8B8-4297-94A4-30C90A850F12}.Debug|ARM.Build.0 = Debug|ARM 43 | {3B8C6EDE-D8B8-4297-94A4-30C90A850F12}.Debug|ARM64.ActiveCfg = Debug|ARM64 44 | {3B8C6EDE-D8B8-4297-94A4-30C90A850F12}.Debug|ARM64.Build.0 = Debug|ARM64 45 | {3B8C6EDE-D8B8-4297-94A4-30C90A850F12}.Debug|x64.ActiveCfg = Debug|x64 46 | {3B8C6EDE-D8B8-4297-94A4-30C90A850F12}.Debug|x64.Build.0 = Debug|x64 47 | {3B8C6EDE-D8B8-4297-94A4-30C90A850F12}.Debug|x86.ActiveCfg = Debug|Win32 48 | {3B8C6EDE-D8B8-4297-94A4-30C90A850F12}.Debug|x86.Build.0 = Debug|Win32 49 | {3B8C6EDE-D8B8-4297-94A4-30C90A850F12}.Release|ARM.ActiveCfg = Release|ARM 50 | {3B8C6EDE-D8B8-4297-94A4-30C90A850F12}.Release|ARM.Build.0 = Release|ARM 51 | {3B8C6EDE-D8B8-4297-94A4-30C90A850F12}.Release|ARM64.ActiveCfg = Release|ARM64 52 | {3B8C6EDE-D8B8-4297-94A4-30C90A850F12}.Release|ARM64.Build.0 = Release|ARM64 53 | {3B8C6EDE-D8B8-4297-94A4-30C90A850F12}.Release|x64.ActiveCfg = Release|x64 54 | {3B8C6EDE-D8B8-4297-94A4-30C90A850F12}.Release|x64.Build.0 = Release|x64 55 | {3B8C6EDE-D8B8-4297-94A4-30C90A850F12}.Release|x86.ActiveCfg = Release|Win32 56 | {3B8C6EDE-D8B8-4297-94A4-30C90A850F12}.Release|x86.Build.0 = Release|Win32 57 | EndGlobalSection 58 | GlobalSection(SolutionProperties) = preSolution 59 | HideSolutionNode = FALSE 60 | EndGlobalSection 61 | GlobalSection(ExtensibilityGlobals) = postSolution 62 | SolutionGuid = {77981E05-F1A3-4E9A-9966-2BB23AC1CA5B} 63 | EndGlobalSection 64 | EndGlobal 65 | -------------------------------------------------------------------------------- /DetoursTest/DetoursTest.cpp: -------------------------------------------------------------------------------- 1 | // DetoursTest.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 2 | // 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef _WIN32 9 | #include 10 | #define TEST_CALL_TYPE __stdcall 11 | #else 12 | #define TEST_CALL_TYPE 13 | #endif 14 | 15 | #include 16 | 17 | 18 | #ifdef _WIN32 19 | __declspec(noinline) 20 | #endif 21 | int TEST_CALL_TYPE test2(int i) 22 | { 23 | std::cout << "test2 start,i=" << i << std::endl; 24 | 25 | std::cout << "test2 end\n"; 26 | return 0; 27 | } 28 | 29 | typedef int (TEST_CALL_TYPE* Api_test2)(int i); 30 | Api_test2 true_test2 = NULL; 31 | 32 | int TEST_CALL_TYPE hook_test2(int i) 33 | { 34 | std::cout << "hook_test2 start\n"; 35 | 36 | int i_ret = true_test2(i+100); 37 | 38 | std::cout << "hook_test2 end\n"; 39 | return i_ret; 40 | } 41 | 42 | 43 | 44 | #ifdef _WIN32 45 | __declspec(noinline) 46 | #endif 47 | int TEST_CALL_TYPE test1(int i1, int i2, int i3, int i4, int i5, int i6, int i7, int i8, int i9, int i10, int i11, int i12, int i13, int i14, int i15, int i16) 48 | { 49 | std::cout << "test1 start\n"; 50 | 51 | int i_ret = i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8 + i9 + i10 + i11 + i12 + i13 + i14 + i15 + i16; 52 | 53 | test2(i_ret); 54 | 55 | std::cout << "test1 end\n"; 56 | return i_ret; 57 | } 58 | 59 | 60 | class TestClass { 61 | public: 62 | TestClass() {}; 63 | long TEST_CALL_TYPE call(long a, long b) 64 | { 65 | std::cout << "TestClass::call start\n"; 66 | long l_ret = m_i + a + b; 67 | 68 | std::cout << "TestClass::call end ,ret "<< l_ret <<"\n"; 69 | 70 | return l_ret; 71 | } 72 | 73 | private: 74 | long m_i = 100; 75 | }; 76 | 77 | 78 | 79 | 80 | 81 | class HookTestClass { 82 | public: 83 | long TEST_CALL_TYPE call(long a, long b) 84 | { 85 | std::cout << "HookTestClass::call start\n"; 86 | long l_ret = (this->*m_true_call)(a+10,b+10); 87 | 88 | std::cout << "HookTestClass::call end\n"; 89 | 90 | return l_ret; 91 | } 92 | public: 93 | typedef long (TEST_CALL_TYPE HookTestClass::*Api_hook_testclass_call)(long, long); 94 | static Api_hook_testclass_call m_true_call; 95 | }; 96 | 97 | typedef long (TEST_CALL_TYPE HookTestClass::*Api_hook_testclass_call)(long, long); 98 | typedef long (TEST_CALL_TYPE TestClass::*Api_true_testclass_call)(long, long); 99 | 100 | Api_hook_testclass_call HookTestClass::m_true_call = NULL; 101 | 102 | 103 | BOOL WINAPI DetoursHookNoitfy(_In_ PDETROUS_HOOK_NOTIFY_INFO_STRCUT pInfo) 104 | { 105 | std::string str_context = (char*)(ULONG_PTR)pInfo->pContext; 106 | 107 | if (str_context.find("test1_notify") != -1) 108 | { 109 | std::cout << "DetoursHookNoitfy called,context=" << str_context 110 | << ",i1=" << *(int*)pInfo->pParam1 111 | << ",i16=" << *(int*)pInfo->pParam16 112 | << std::endl; 113 | 114 | *(int*)pInfo->pParam1 = 10086;//如果不在函数的起始位置hook的话,一般不能返回阻止(平衡栈,一些析构函数的执行等),但是修改参数的方式让它失败。 115 | 116 | } 117 | else if (str_context.find("test2_notify") != -1) 118 | { 119 | std::cout << "DetoursHookNoitfy called,context=" << str_context 120 | << ",i1=" << *(int*)pInfo->pParam1 121 | << std::endl; 122 | } 123 | else if (str_context.find("test3_notify") != -1) 124 | { 125 | 126 | std::cout << "DetoursHookNoitfy called,context=" << str_context 127 | << ",i1=" << *(int*)pInfo->pParam2 128 | << std::endl; 129 | } 130 | 131 | 132 | return TRUE; 133 | } 134 | 135 | 136 | //s_rceCopyTable 137 | int main() 138 | { 139 | 140 | #if defined(DETOURS_X86) 141 | std::cout << "x86 start!\n\n"; 142 | #elif defined(DETOURS_X64) 143 | std::cout << "x64 start!\n\n"; 144 | #elif defined(DETOURS_ARM) 145 | std::cout << "arm start!\n\n"; 146 | #elif defined(DETOURS_ARM64) 147 | std::cout << "arm64 start!\n\n"; 148 | #endif 149 | 150 | true_test2 = test2; 151 | 152 | auto true_tmp = &TestClass::call; 153 | HookTestClass::m_true_call = (Api_hook_testclass_call)true_tmp; 154 | 155 | auto hook_tmp = &HookTestClass::call; 156 | UCHAR *hook_call = (UCHAR *)*(&(PVOID&)hook_tmp); 157 | 158 | UCHAR *true_test1_notify = (UCHAR *)test1; 159 | UCHAR *true_test2_notify = (UCHAR *)true_test2; 160 | UCHAR *true_test3_notify = (UCHAR *)*(&(PVOID&)true_tmp); 161 | 162 | 163 | 164 | std::unique_ptr test_class = std::make_unique(); 165 | 166 | //#define TEST_ORG_HOOK 167 | 168 | //hook 169 | DetourTransactionBegin(); 170 | DetourUpdateThread(GetCurrentThread()); 171 | #ifdef TEST_ORG_HOOK 172 | DetourAttach(&(PVOID&)true_test2, (PVOID)hook_test2); 173 | DetourAttach(&(PVOID&)HookTestClass::m_true_call, (PVOID)hook_call); 174 | #else 175 | DetourInstallNotify(&(PVOID&)true_test1_notify, DetoursHookNoitfy, (PVOID)"test1_notify"); 176 | DetourInstallNotify(&(PVOID&)true_test2_notify, DetoursHookNoitfy, (PVOID)"test2_notify"); 177 | DetourInstallNotify(&(PVOID&)true_test3_notify, DetoursHookNoitfy, (PVOID)"test3_notify"); 178 | #endif 179 | DetourTransactionCommit(); 180 | 181 | test1(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); 182 | test_class->call(10, 20); 183 | 184 | std::cout << "\nunhook\n\n"; 185 | //unhook 186 | DetourTransactionBegin(); 187 | DetourUpdateThread(GetCurrentThread()); 188 | #ifdef TEST_ORG_HOOK 189 | DetourDetach(&(PVOID&)true_test2, (PVOID)hook_test2); 190 | DetourDetach(&(PVOID&)HookTestClass::m_true_call, (PVOID)hook_call); 191 | #else 192 | DetourUnInstallNotify(&(PVOID&)true_test1_notify, DetoursHookNoitfy); 193 | DetourUnInstallNotify(&(PVOID&)true_test2_notify, DetoursHookNoitfy); 194 | DetourUnInstallNotify(&(PVOID&)true_test3_notify, DetoursHookNoitfy); 195 | #endif 196 | DetourTransactionCommit(); 197 | 198 | test1(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); 199 | test_class->call(10, 20); 200 | 201 | 202 | 203 | std::cout << "\nend!\n"; 204 | return 0; 205 | } 206 | -------------------------------------------------------------------------------- /DetoursTest/DetoursTest.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | ARM 7 | 8 | 9 | Debug 10 | ARM64 11 | 12 | 13 | Debug 14 | Win32 15 | 16 | 17 | Release 18 | ARM 19 | 20 | 21 | Release 22 | ARM64 23 | 24 | 25 | Release 26 | Win32 27 | 28 | 29 | Debug 30 | x64 31 | 32 | 33 | Release 34 | x64 35 | 36 | 37 | 38 | 15.0 39 | {57941E38-685B-44C3-9D74-2E8B061B5862} 40 | Win32Proj 41 | DetoursTest 42 | 10.0.17763.0 43 | 44 | 45 | 46 | Application 47 | true 48 | v141 49 | Unicode 50 | 51 | 52 | Application 53 | true 54 | v141 55 | Unicode 56 | 57 | 58 | Application 59 | true 60 | v141 61 | Unicode 62 | 63 | 64 | Application 65 | false 66 | v141 67 | true 68 | Unicode 69 | 70 | 71 | Application 72 | false 73 | v141 74 | true 75 | Unicode 76 | 77 | 78 | Application 79 | false 80 | v141 81 | true 82 | Unicode 83 | 84 | 85 | Application 86 | true 87 | v141 88 | Unicode 89 | 90 | 91 | Application 92 | false 93 | v141 94 | true 95 | Unicode 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | true 137 | 138 | 139 | true 140 | 141 | 142 | true 143 | 144 | 145 | true 146 | 147 | 148 | false 149 | 150 | 151 | false 152 | 153 | 154 | false 155 | 156 | 157 | false 158 | 159 | 160 | 161 | NotUsing 162 | Level3 163 | Disabled 164 | 165 | 166 | KEYSTONE_STATIC;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_SCL_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_WARNINGS;__STDC_CONSTANT_MACROS;__STDC_FORMAT_MACROS;__STDC_LIMIT_MACROS;LLVM_ENABLE_ARCH_AArch64;LLVM_ENABLE_ARCH_ARM;LLVM_ENABLE_ARCH_X86;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 167 | false 168 | false 169 | MultiThreadedDebug 170 | ..\Detours\src;%(AdditionalIncludeDirectories) 171 | true 172 | 173 | 174 | Console 175 | true 176 | Detours.lib;%(AdditionalDependencies) 177 | 178 | 179 | 180 | 181 | NotUsing 182 | Level3 183 | Disabled 184 | 185 | 186 | KEYSTONE_STATIC;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_SCL_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_WARNINGS;__STDC_CONSTANT_MACROS;__STDC_FORMAT_MACROS;__STDC_LIMIT_MACROS;LLVM_ENABLE_ARCH_AArch64;LLVM_ENABLE_ARCH_ARM;LLVM_ENABLE_ARCH_X86;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 187 | false 188 | false 189 | MultiThreadedDebug 190 | ..\Detours\src;%(AdditionalIncludeDirectories) 191 | true 192 | 193 | 194 | Console 195 | true 196 | Detours.lib;%(AdditionalDependencies) 197 | 198 | 199 | 200 | 201 | NotUsing 202 | Level3 203 | Disabled 204 | 205 | 206 | KEYSTONE_STATIC;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_SCL_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_WARNINGS;__STDC_CONSTANT_MACROS;__STDC_FORMAT_MACROS;__STDC_LIMIT_MACROS;LLVM_ENABLE_ARCH_AArch64;LLVM_ENABLE_ARCH_ARM;LLVM_ENABLE_ARCH_X86;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 207 | false 208 | false 209 | MultiThreadedDebug 210 | ..\Detours\src;%(AdditionalIncludeDirectories) 211 | true 212 | 213 | 214 | Console 215 | true 216 | Detours.lib;%(AdditionalDependencies) 217 | 218 | 219 | 220 | 221 | NotUsing 222 | Level3 223 | Disabled 224 | 225 | 226 | KEYSTONE_STATIC;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_SCL_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_WARNINGS;__STDC_CONSTANT_MACROS;__STDC_FORMAT_MACROS;__STDC_LIMIT_MACROS;LLVM_ENABLE_ARCH_AArch64;LLVM_ENABLE_ARCH_ARM;LLVM_ENABLE_ARCH_X86;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 227 | false 228 | false 229 | MultiThreadedDebug 230 | ..\Detours\src;%(AdditionalIncludeDirectories) 231 | true 232 | 233 | 234 | Console 235 | true 236 | Detours.lib;%(AdditionalDependencies) 237 | 238 | 239 | 240 | 241 | NotUsing 242 | Level3 243 | true 244 | true 245 | 246 | 247 | KEYSTONE_STATIC;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_SCL_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_WARNINGS;__STDC_CONSTANT_MACROS;__STDC_FORMAT_MACROS;__STDC_LIMIT_MACROS;LLVM_ENABLE_ARCH_AArch64;LLVM_ENABLE_ARCH_ARM;LLVM_ENABLE_ARCH_X86;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 248 | false 249 | false 250 | MultiThreaded 251 | ..\Detours\src;%(AdditionalIncludeDirectories) 252 | true 253 | 254 | 255 | Console 256 | true 257 | true 258 | true 259 | 260 | Detours.lib;%(AdditionalDependencies) 261 | 262 | 263 | 264 | 265 | NotUsing 266 | Level3 267 | MaxSpeed 268 | true 269 | true 270 | 271 | 272 | KEYSTONE_STATIC;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_SCL_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_WARNINGS;__STDC_CONSTANT_MACROS;__STDC_FORMAT_MACROS;__STDC_LIMIT_MACROS;LLVM_ENABLE_ARCH_AArch64;LLVM_ENABLE_ARCH_ARM;LLVM_ENABLE_ARCH_X86;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 273 | false 274 | false 275 | MultiThreaded 276 | ..\Detours\src;%(AdditionalIncludeDirectories) 277 | true 278 | 279 | 280 | Console 281 | true 282 | true 283 | true 284 | Detours.lib;%(AdditionalDependencies) 285 | 286 | 287 | 288 | 289 | NotUsing 290 | Level3 291 | MaxSpeed 292 | true 293 | true 294 | 295 | 296 | KEYSTONE_STATIC;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_SCL_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_WARNINGS;__STDC_CONSTANT_MACROS;__STDC_FORMAT_MACROS;__STDC_LIMIT_MACROS;LLVM_ENABLE_ARCH_AArch64;LLVM_ENABLE_ARCH_ARM;LLVM_ENABLE_ARCH_X86;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 297 | false 298 | false 299 | MultiThreaded 300 | ..\Detours\src;%(AdditionalIncludeDirectories) 301 | true 302 | 303 | 304 | Console 305 | true 306 | true 307 | true 308 | Detours.lib;%(AdditionalDependencies) 309 | 310 | 311 | 312 | 313 | NotUsing 314 | Level3 315 | MaxSpeed 316 | true 317 | true 318 | 319 | 320 | KEYSTONE_STATIC;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_SCL_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_WARNINGS;__STDC_CONSTANT_MACROS;__STDC_FORMAT_MACROS;__STDC_LIMIT_MACROS;LLVM_ENABLE_ARCH_AArch64;LLVM_ENABLE_ARCH_ARM;LLVM_ENABLE_ARCH_X86;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 321 | false 322 | false 323 | MultiThreaded 324 | ..\Detours\src;%(AdditionalIncludeDirectories) 325 | true 326 | 327 | 328 | Console 329 | true 330 | true 331 | true 332 | Detours.lib;%(AdditionalDependencies) 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | -------------------------------------------------------------------------------- /DetoursTest/DetoursTest.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 源文件 20 | 21 | 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DetoursEx 2 | Modified by Mircosoft detours.Support Window/Linux/Macos. Support X86/x64/ARM64/ARM/MIPS/LongArch. 3 | Can Hook in any address but not only the function beginning address. 4 | 5 | ## Usage 6 | 7 | ```c++ 8 | __declspec(noinline) int test1(int i1, int i2, int i3, int i4, int i5) 9 | { 10 | std::cout << "test1 start\n"; 11 | 12 | test2(i1); 13 | int i_ret = i1 + i2 + i3 + i4 + i5; 14 | 15 | std::cout << "test1 end\n"; 16 | return i_ret; 17 | } 18 | 19 | int hook_test1(int i1, int i2, int i3, int i4, int i5) 20 | { 21 | std::cout << "hook_test1 start\n"; 22 | 23 | int i_ret = true_test1(i1, i2, i3, i4, i5); 24 | 25 | std::cout << "hook_test1 end\n"; 26 | return i_ret; 27 | } 28 | 29 | BOOL CALLBACK DetoursHookNoitfy(_In_ PDETROUS_HOOK_NOTIFY_INFO_STRCUT pInfo) 30 | { 31 | std::cout << "DetoursHookNoitfy called,context=" << (int)(ULONG_PTR)pInfo->pContext << std::endl; 32 | 33 | return TRUE;//return FALSE means block 34 | } 35 | 36 | typedef int(*pfn_test1)(int i1, int i2, int i3, int i4, int i5); 37 | pfn_test1 true_test1 = nullptr; 38 | 39 | int test_hook() 40 | { 41 | DetourRestoreAfterWith(); 42 | DetourTransactionBegin(); 43 | DetourUpdateThread(GetCurrentThread()); 44 | #if 0 45 | DetourAttach(&(PVOID&)true_test1, hook_test1); 46 | #else 47 | DetourInstallNotify(&(PVOID&)true_test1, DetoursHookNoitfy, (PVOID)1); 48 | #endif 49 | DetourTransactionCommit(); 50 | } 51 | ``` 52 | -------------------------------------------------------------------------------- /config.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 5.01 6 | 5.02 7 | 8 | 9 | 10 | NoName 11 | $(SolutionDir)..\ 12 | $(ProductRootDir)Output\ 13 | 14 | 15 | $(OutputBaseDir)BinDebugX86\$(SolutionName)\ 16 | $(OutputBaseDir)LibDebugX86\$(SolutionName)\ 17 | $(OutputBaseDir)PdbDebugX86\$(SolutionName)\ 18 | $(OutputBaseDir)TmpDebugX86\$(SolutionName)\ 19 | 20 | 21 | $(OutputBaseDir)BinX86\$(SolutionName)\ 22 | $(OutputBaseDir)LibX86\$(SolutionName)\ 23 | $(OutputBaseDir)PdbX86\$(SolutionName)\ 24 | $(OutputBaseDir)TmpX86\$(SolutionName)\ 25 | 26 | 27 | $(OutputBaseDir)BinDebugX64\$(SolutionName)\ 28 | $(OutputBaseDir)LibDebugX64\$(SolutionName)\ 29 | $(OutputBaseDir)PdbDebugX64\$(SolutionName)\ 30 | $(OutputBaseDir)TmpDebugX64\$(SolutionName)\ 31 | 32 | 33 | $(OutputBaseDir)BinX64\$(SolutionName)\ 34 | $(OutputBaseDir)LibX64\$(SolutionName)\ 35 | $(OutputBaseDir)PdbX64\$(SolutionName)\ 36 | $(OutputBaseDir)TmpX64\$(SolutionName)\ 37 | 38 | 39 | $(OutputBaseDir)BinDebugARM64\$(SolutionName)\ 40 | $(OutputBaseDir)LibDebugARM64\$(SolutionName)\ 41 | $(OutputBaseDir)PdbDebugARM64\$(SolutionName)\ 42 | $(OutputBaseDir)TmpDebugARM64\$(SolutionName)\ 43 | 44 | 45 | $(OutputBaseDir)BinARM64\$(SolutionName)\ 46 | $(OutputBaseDir)LibARM64\$(SolutionName)\ 47 | $(OutputBaseDir)PdbARM64\$(SolutionName)\ 48 | $(OutputBaseDir)TmpARM64\$(SolutionName)\ 49 | 50 | 51 | $(OutputBaseDir)BinDebugARM\$(SolutionName)\ 52 | $(OutputBaseDir)LibDebugARM\$(SolutionName)\ 53 | $(OutputBaseDir)PdbDebugARM\$(SolutionName)\ 54 | $(OutputBaseDir)TmpDebugARM\$(SolutionName)\ 55 | 56 | 57 | $(OutputBaseDir)BinARM\$(SolutionName)\ 58 | $(OutputBaseDir)LibARM\$(SolutionName)\ 59 | $(OutputBaseDir)PdbARM\$(SolutionName)\ 60 | $(OutputBaseDir)TmpARM\$(SolutionName)\ 61 | 62 | 63 | <_PropertySheetDisplayName>global_setting 64 | $(LibPath) 65 | $(BinPath) 66 | $(ObjPath)$(ProjectName)\ 67 | $(ProjectName) 68 | 69 | 70 | false 71 | 72 | 73 | 74 | $(LibPath) 75 | $(PdbPath)$(TargetName).pdb 76 | $(LibPath)$(TargetName).lib 77 | 78 | 79 | $(PdbPath)$(TargetName).pdb 80 | true 81 | true 82 | /Zc:sizedDealloc- /Zc:threadSafeInit- /Zc:strictStrings- %(AdditionalOptions) 83 | $(IntDir)%(RelativeDir)\ 84 | $(ProductRootDir)include;%(AdditionalIncludeDirectories) 85 | 86 | 87 | 88 | 89 | $(ProductRootDir) 90 | 91 | 92 | $(OutputBaseDir) 93 | 94 | 95 | $(ProductName) 96 | 97 | 98 | $(BinPath) 99 | 100 | 101 | $(LibPath) 102 | 103 | 104 | $(PdbPath) 105 | 106 | 107 | $(ObjPath) 108 | 109 | 110 | --------------------------------------------------------------------------------