detours.cpp 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406
  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Core Detours Functionality (detours.cpp of detours.lib)
  4. //
  5. // Microsoft Research Detours Package, Version 2.1.
  6. //
  7. // Copyright (c) Microsoft Corporation. All rights reserved.
  8. //
  9. #include <windows.h>
  10. #if (_MSC_VER < 1299)
  11. #pragma warning(disable: 4710)
  12. #endif
  13. //#define DETOUR_DEBUG 1
  14. #define DETOURS_INTERNAL
  15. #include "detours.h"
  16. #include "detoured.h"
  17. #if !defined(DETOURS_X86) && !defined(DETOURS_X64) && !defined(DETOURS_IA64)
  18. #error Must define one of DETOURS_X86, DETOURS_X64, or DETOURS_IA64
  19. #endif
  20. //////////////////////////////////////////////////////////////////////////////
  21. //
  22. static bool detour_is_imported(PBYTE pbCode, PBYTE pbAddress)
  23. {
  24. MEMORY_BASIC_INFORMATION mbi;
  25. VirtualQuery((PVOID)pbCode, &mbi, sizeof(mbi));
  26. __try {
  27. PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mbi.AllocationBase;
  28. if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
  29. return false;
  30. }
  31. PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +
  32. pDosHeader->e_lfanew);
  33. if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
  34. return false;
  35. }
  36. if (pbAddress >= ((PBYTE)pDosHeader +
  37. pNtHeader->OptionalHeader
  38. .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress) &&
  39. pbAddress < ((PBYTE)pDosHeader +
  40. pNtHeader->OptionalHeader
  41. .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress +
  42. pNtHeader->OptionalHeader
  43. .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size)) {
  44. return true;
  45. }
  46. return false;
  47. }
  48. __except(EXCEPTION_EXECUTE_HANDLER) {
  49. return false;
  50. }
  51. }
  52. ///////////////////////////////////////////////////////////////////////// X86.
  53. //
  54. #ifdef DETOURS_X86
  55. struct _DETOUR_TRAMPOLINE
  56. {
  57. BYTE rbCode[23]; // target code + jmp to pbRemain
  58. BYTE cbTarget; // size of target code moved.
  59. PBYTE pbRemain; // first instruction after moved code. [free list]
  60. PBYTE pbDetour; // first instruction of detour function.
  61. };
  62. enum {
  63. SIZE_OF_JMP = 5
  64. };
  65. inline PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE pbJmpVal)
  66. {
  67. PBYTE pbJmpSrc = pbCode + 5;
  68. *pbCode++ = 0xE9; // jmp +imm32
  69. *((INT32*&)pbCode)++ = (INT32)(pbJmpVal - pbJmpSrc);
  70. return pbCode;
  71. }
  72. inline PBYTE detour_gen_jmp_indirect(PBYTE pbCode, PBYTE *ppbJmpVal)
  73. {
  74. PBYTE pbJmpSrc = pbCode + 6;
  75. *pbCode++ = 0xff; // jmp [+imm32]
  76. *pbCode++ = 0x25;
  77. *((INT32*&)pbCode)++ = (INT32)((PBYTE)ppbJmpVal - pbJmpSrc);
  78. return pbCode;
  79. }
  80. inline PBYTE detour_gen_brk(PBYTE pbCode, PBYTE pbLimit)
  81. {
  82. while (pbCode < pbLimit) {
  83. *pbCode++ = 0xcc; // brk;
  84. }
  85. return pbCode;
  86. }
  87. inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals)
  88. {
  89. if (pbCode == NULL) {
  90. return NULL;
  91. }
  92. if (ppGlobals != NULL) {
  93. *ppGlobals = NULL;
  94. }
  95. if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [+imm32]
  96. // Looks like an import alias jump, then get the code it points to.
  97. PBYTE pbTarget = *(PBYTE *)&pbCode[2];
  98. if (detour_is_imported(pbCode, pbTarget)) {
  99. PBYTE pbNew = *(PBYTE *)pbTarget;
  100. DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew));
  101. return pbNew;
  102. }
  103. }
  104. else if (pbCode[0] == 0xeb) { // jmp +imm8
  105. // These just started appearing with CL13.
  106. PBYTE pbNew = pbCode + 2 + *(CHAR *)&pbCode[1];
  107. DETOUR_TRACE(("%p->%p: skipped over short jump.\n", pbCode, pbNew));
  108. if (pbNew[0] == 0xe9) { // jmp +imm32
  109. pbCode = pbNew;
  110. pbNew = pbCode + *(INT32 *)&pbCode[1];
  111. DETOUR_TRACE(("%p->%p: skipped over short jump.\n", pbCode, pbNew));
  112. }
  113. return pbNew;
  114. }
  115. return pbCode;
  116. }
  117. inline BOOL detour_does_code_end_function(PBYTE pbCode)
  118. {
  119. if (pbCode[0] == 0xe9 || // jmp +imm32
  120. pbCode[0] == 0xe0 || // jmp eax
  121. pbCode[0] == 0xc2 || // ret +imm8
  122. pbCode[0] == 0xc3 || // ret
  123. pbCode[0] == 0xcc) { // brk
  124. return TRUE;
  125. }
  126. else if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [+imm32]
  127. return TRUE;
  128. }
  129. else if ((pbCode[0] == 0x26 || // jmp es:
  130. pbCode[0] == 0x2e || // jmp cs:
  131. pbCode[0] == 0x36 || // jmp ss:
  132. pbCode[0] == 0xe3 || // jmp ds:
  133. pbCode[0] == 0x64 || // jmp fs:
  134. pbCode[0] == 0x65) && // jmp gs:
  135. pbCode[1] == 0xff && // jmp [+imm32]
  136. pbCode[2] == 0x25) {
  137. return TRUE;
  138. }
  139. return FALSE;
  140. }
  141. #endif // DETOURS_X86
  142. ///////////////////////////////////////////////////////////////////////// X64.
  143. //
  144. #ifdef DETOURS_X64
  145. #error Feature not supported in this release.
  146. #endif // DETOURS_X64
  147. //////////////////////////////////////////////////////////////////////// IA64.
  148. //
  149. #ifdef DETOURS_IA64
  150. #error Feature not supported in this release.
  151. #endif
  152. //////////////////////////////////////////////// Trampoline Memory Management.
  153. //
  154. struct DETOUR_REGION
  155. {
  156. ULONG dwSignature;
  157. DETOUR_REGION * pNext; // Next region in list of regions.
  158. DETOUR_TRAMPOLINE * pFree; // List of free trampolines in this region.
  159. };
  160. typedef DETOUR_REGION * PDETOUR_REGION;
  161. const ULONG DETOUR_REGION_SIGNATURE = 'Rrtd';
  162. const ULONG DETOUR_REGION_SIZE = 0x10000;
  163. const ULONG DETOUR_TRAMPOLINES_PER_REGION = (DETOUR_REGION_SIZE
  164. / sizeof(DETOUR_TRAMPOLINE)) - 1;
  165. static PDETOUR_REGION s_pRegions = NULL; // List of all regions.
  166. static PDETOUR_REGION s_pRegion = NULL; // Default region.
  167. static void detour_writable_trampoline_regions()
  168. {
  169. // Mark all of the regions as writable.
  170. for (PDETOUR_REGION pRegion = s_pRegions; pRegion != NULL; pRegion = pRegion->pNext) {
  171. DWORD dwOld;
  172. VirtualProtect(pRegion, DETOUR_REGION_SIZE, PAGE_EXECUTE_READWRITE, &dwOld);
  173. }
  174. }
  175. static void detour_runnable_trampoline_regions()
  176. {
  177. // Mark all of the regions as executable.
  178. for (PDETOUR_REGION pRegion = s_pRegions; pRegion != NULL; pRegion = pRegion->pNext) {
  179. DWORD dwOld;
  180. VirtualProtect(pRegion, DETOUR_REGION_SIZE, PAGE_EXECUTE_READ, &dwOld);
  181. }
  182. }
  183. static PDETOUR_TRAMPOLINE detour_alloc_trampoline(PBYTE pbTarget)
  184. {
  185. // We have to place trampolines within +/- 2GB of target.
  186. // The allocation code assumes that
  187. PDETOUR_TRAMPOLINE pLo = (PDETOUR_TRAMPOLINE)
  188. ((pbTarget > (PBYTE)0x7ff80000)
  189. ? pbTarget - 0x7ff80000 : (PBYTE)(ULONG_PTR)DETOUR_REGION_SIZE);
  190. PDETOUR_TRAMPOLINE pHi = (PDETOUR_TRAMPOLINE)
  191. ((pbTarget < (PBYTE)0xffffffff80000000)
  192. ? pbTarget + 0x7ff80000 : (PBYTE)0xfffffffffff80000);
  193. DETOUR_TRACE(("[%p..%p..%p]\n", pLo, pbTarget, pHi));
  194. PDETOUR_TRAMPOLINE pTrampoline = NULL;
  195. // Insure that there is a default region.
  196. if (s_pRegion == NULL && s_pRegions != NULL) {
  197. s_pRegion = s_pRegions;
  198. }
  199. // First check the default region for an valid free block.
  200. if (s_pRegion != NULL && s_pRegion->pFree != NULL &&
  201. s_pRegion->pFree >= pLo && s_pRegion->pFree <= pHi) {
  202. found_region:
  203. pTrampoline = s_pRegion->pFree;
  204. // do a last sanity check on region.
  205. if (pTrampoline < pLo || pTrampoline > pHi) {
  206. return NULL;
  207. }
  208. s_pRegion->pFree = (PDETOUR_TRAMPOLINE)pTrampoline->pbRemain;
  209. memset(pTrampoline, 0xcc, sizeof(*pTrampoline));
  210. return pTrampoline;
  211. }
  212. // Then check the existing regions for a valid free block.
  213. for (s_pRegion = s_pRegions; s_pRegion != NULL; s_pRegion = s_pRegion->pNext) {
  214. if (s_pRegion != NULL && s_pRegion->pFree != NULL &&
  215. s_pRegion->pFree >= pLo && s_pRegion->pFree <= pHi) {
  216. goto found_region;
  217. }
  218. }
  219. // We need to allocate a new region.
  220. // Round pbTarget down to 64K block.
  221. pbTarget = pbTarget - (PtrToUlong(pbTarget) & 0xffff);
  222. // First we search down (within the valid region)
  223. DETOUR_TRACE((" Looking for free region below %p:\n", pbTarget));
  224. PBYTE pbTry;
  225. for (pbTry = pbTarget; pbTry > (PBYTE)pLo;) {
  226. MEMORY_BASIC_INFORMATION mbi;
  227. DETOUR_TRACE((" Try %p\n", pbTry));
  228. if (pbTry >= (PBYTE)(ULONG_PTR)0x70000000 &&
  229. pbTry <= (PBYTE)(ULONG_PTR)0x80000000) {
  230. // Skip region reserved for system DLLs.
  231. pbTry = (PBYTE)(ULONG_PTR)(0x70000000 - DETOUR_REGION_SIZE);
  232. }
  233. if (!VirtualQuery(pbTry, &mbi, sizeof(mbi))) {
  234. break;
  235. }
  236. DETOUR_TRACE((" Try %p => %p..%p %6x\n",
  237. pbTry,
  238. mbi.BaseAddress,
  239. (PBYTE)mbi.BaseAddress + mbi.RegionSize - 1,
  240. mbi.State));
  241. if (mbi.State == MEM_FREE && mbi.RegionSize >= DETOUR_REGION_SIZE) {
  242. s_pRegion = (DETOUR_REGION*)VirtualAlloc(pbTry,
  243. DETOUR_REGION_SIZE,
  244. MEM_COMMIT|MEM_RESERVE,
  245. PAGE_EXECUTE_READWRITE);
  246. if (s_pRegion != NULL) {
  247. alloced_region:
  248. s_pRegion->dwSignature = DETOUR_REGION_SIGNATURE;
  249. s_pRegion->pFree = NULL;
  250. s_pRegion->pNext = s_pRegions;
  251. s_pRegions = s_pRegion;
  252. DETOUR_TRACE((" Allocated region %p..%p\n\n",
  253. s_pRegion, ((PBYTE)s_pRegion) + DETOUR_REGION_SIZE - 1));
  254. // Put everything but the first trampoline on the free list.
  255. PBYTE pFree = NULL;
  256. pTrampoline = ((PDETOUR_TRAMPOLINE)s_pRegion) + 1;
  257. for (int i = DETOUR_TRAMPOLINES_PER_REGION - 1; i > 1; i--) {
  258. pTrampoline[i].pbRemain = pFree;
  259. pFree = (PBYTE)&pTrampoline[i];
  260. }
  261. s_pRegion->pFree = (PDETOUR_TRAMPOLINE)pFree;
  262. goto found_region;
  263. }
  264. else {
  265. DETOUR_TRACE(("Error: %p %d\n", pbTry, GetLastError()));
  266. break;
  267. }
  268. }
  269. pbTry = (PBYTE)mbi.AllocationBase - DETOUR_REGION_SIZE;
  270. }
  271. DETOUR_TRACE((" Looking for free region above %p:\n", pbTarget));
  272. for (pbTry = pbTarget; pbTry < (PBYTE)pHi;) {
  273. MEMORY_BASIC_INFORMATION mbi;
  274. if (pbTry >= (PBYTE)(ULONG_PTR)0x70000000 &&
  275. pbTry <= (PBYTE)(ULONG_PTR)0x80000000) {
  276. // Skip region reserved for system DLLs.
  277. pbTry = (PBYTE)(ULONG_PTR)(0x80000000 + DETOUR_REGION_SIZE);
  278. }
  279. if (!VirtualQuery(pbTry, &mbi, sizeof(mbi))) {
  280. break;
  281. }
  282. DETOUR_TRACE((" Try %p => %p..%p %6x\n",
  283. pbTry,
  284. mbi.BaseAddress,
  285. (PBYTE)mbi.BaseAddress + mbi.RegionSize - 1,
  286. mbi.State));
  287. if (mbi.State == MEM_FREE && mbi.RegionSize >= DETOUR_REGION_SIZE) {
  288. ULONG_PTR extra = ((ULONG_PTR)pbTry) & (DETOUR_REGION_SIZE - 1);
  289. if (extra != 0) {
  290. // WinXP64 returns free areas that aren't REGION aligned to
  291. // 32-bit applications.
  292. ULONG_PTR adjust = DETOUR_REGION_SIZE - extra;
  293. mbi.RegionSize -= adjust;
  294. ((PBYTE&)mbi.BaseAddress) += adjust;
  295. DETOUR_TRACE(("--Try %p => %p..%p %6x\n",
  296. pbTry,
  297. mbi.BaseAddress,
  298. (PBYTE)mbi.BaseAddress + mbi.RegionSize - 1,
  299. mbi.State));
  300. pbTry = (PBYTE)mbi.BaseAddress;
  301. }
  302. s_pRegion = (DETOUR_REGION*)VirtualAlloc(pbTry,
  303. DETOUR_REGION_SIZE,
  304. MEM_COMMIT|MEM_RESERVE,
  305. PAGE_EXECUTE_READWRITE);
  306. if (s_pRegion != NULL) {
  307. goto alloced_region;
  308. }
  309. else {
  310. DETOUR_TRACE(("Error: %p %d\n", pbTry, GetLastError()));
  311. }
  312. }
  313. pbTry = (PBYTE)mbi.BaseAddress + mbi.RegionSize;
  314. }
  315. DETOUR_TRACE(("Couldn't find available memory region!\n"));
  316. return NULL;
  317. }
  318. static VOID detour_free_trampoline(PDETOUR_TRAMPOLINE pTrampoline)
  319. {
  320. PDETOUR_REGION pRegion = (PDETOUR_REGION)
  321. ((ULONG_PTR)pTrampoline & ~(ULONG_PTR)0xffff);
  322. memset(pTrampoline, 0, sizeof(*pTrampoline));
  323. pTrampoline->pbRemain = (PBYTE)pRegion->pFree;
  324. pRegion->pFree = pTrampoline;
  325. }
  326. //////////////////////////////////////////////////////////////////////////////
  327. //
  328. static PIMAGE_DOS_HEADER detour_find_header(PBYTE pbTarget)
  329. {
  330. MEMORY_BASIC_INFORMATION mbi;
  331. if (!VirtualQuery(pbTarget, &mbi, sizeof(mbi))) {
  332. return NULL;
  333. }
  334. PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mbi.AllocationBase;
  335. __try {
  336. if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
  337. return NULL;
  338. }
  339. PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +
  340. pDosHeader->e_lfanew);
  341. if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
  342. return NULL;
  343. }
  344. if (pNtHeader->FileHeader.SizeOfOptionalHeader == 0) {
  345. return NULL;
  346. }
  347. return pDosHeader;
  348. } __except(EXCEPTION_EXECUTE_HANDLER) {
  349. return NULL;
  350. }
  351. }
  352. ///////////////////////////////////////////////////////// Transaction Structs.
  353. //
  354. struct DetourThread
  355. {
  356. DetourThread * pNext;
  357. HANDLE hThread;
  358. };
  359. struct DetourOperation
  360. {
  361. DetourOperation * pNext;
  362. BOOL fIsRemove;
  363. PBYTE * ppbPointer;
  364. PBYTE pbTarget;
  365. PDETOUR_TRAMPOLINE pTrampoline;
  366. ULONG dwPerm;
  367. };
  368. static BOOL s_fIgnoreTooSmall = FALSE;
  369. static LONG s_nPendingThreadId = 0; // Thread owning pending transaction.
  370. static LONG s_nPendingError = NO_ERROR;
  371. static PVOID * s_ppPendingError = NULL;
  372. static DetourThread * s_pPendingThreads = NULL;
  373. static DetourOperation * s_pPendingOperations = NULL;
  374. //////////////////////////////////////////////////////////////////////////////
  375. //
  376. PVOID WINAPI DetourCodeFromPointer(PVOID pPointer, PVOID *ppGlobals)
  377. {
  378. return detour_skip_jmp((PBYTE)pPointer, ppGlobals);
  379. }
  380. //////////////////////////////////////////////////////////// Transaction APIs.
  381. //
  382. VOID WINAPI DetourSetIgnoreTooSmall(BOOL fIgnore)
  383. {
  384. s_fIgnoreTooSmall = fIgnore;
  385. }
  386. LONG WINAPI DetourTransactionBegin()
  387. {
  388. // Only one transaction is allowed at a time.
  389. if (s_nPendingThreadId != 0) {
  390. return ERROR_INVALID_OPERATION;
  391. }
  392. // Make sure only one thread can start a transaction.
  393. if (InterlockedCompareExchange(&s_nPendingThreadId, (LONG)GetCurrentThreadId(), 0) != 0) {
  394. return ERROR_INVALID_OPERATION;
  395. }
  396. s_fIgnoreTooSmall = FALSE;
  397. s_pPendingOperations = NULL;
  398. s_pPendingThreads = NULL;
  399. s_nPendingError = NO_ERROR;
  400. s_ppPendingError = NULL;
  401. // Make sure the trampoline pages are writable.
  402. detour_writable_trampoline_regions();
  403. return NO_ERROR;
  404. }
  405. LONG WINAPI DetourTransactionAbort()
  406. {
  407. if (s_nPendingThreadId != (LONG)GetCurrentThreadId()) {
  408. return ERROR_INVALID_OPERATION;
  409. }
  410. // Restore all of the page permissions.
  411. for (DetourOperation *o = s_pPendingOperations; o != NULL;) {
  412. // We don't care if this fails, because the code is still accessible.
  413. DWORD dwOld;
  414. VirtualProtect(o->pbTarget, o->pTrampoline->cbTarget,
  415. o->dwPerm, &dwOld);
  416. if (!o->fIsRemove) {
  417. if (o->pTrampoline) {
  418. detour_free_trampoline(o->pTrampoline);
  419. o->pTrampoline = NULL;
  420. }
  421. }
  422. DetourOperation *n = o->pNext;
  423. delete o;
  424. o = n;
  425. }
  426. s_pPendingOperations = NULL;
  427. // Make sure the trampoline pages are no longer writable.
  428. detour_runnable_trampoline_regions();
  429. // Resume any suspended threads.
  430. for (DetourThread *t = s_pPendingThreads; t != NULL;) {
  431. // There is nothing we can do if this fails.
  432. ResumeThread(t->hThread);
  433. DetourThread *n = t->pNext;
  434. delete t;
  435. t = n;
  436. }
  437. s_pPendingThreads = NULL;
  438. s_nPendingThreadId = 0;
  439. return NO_ERROR;
  440. }
  441. LONG WINAPI DetourTransactionCommit()
  442. {
  443. return DetourTransactionCommitEx(NULL);
  444. }
  445. LONG WINAPI DetourTransactionCommitEx(PVOID **pppFailedPointer)
  446. {
  447. if (pppFailedPointer != NULL) {
  448. // Used to get the last error.
  449. *pppFailedPointer = s_ppPendingError;
  450. }
  451. if (s_nPendingThreadId != (LONG)GetCurrentThreadId()) {
  452. return ERROR_INVALID_OPERATION;
  453. }
  454. // If any of the pending operations failed, then we abort the whole transaction.
  455. if (s_nPendingError != NO_ERROR) {
  456. DETOUR_BREAK();
  457. DetourTransactionAbort();
  458. return s_nPendingError;
  459. }
  460. // Common variables.
  461. DetourOperation *o;
  462. DetourThread *t;
  463. // Insert or remove each of the detours.
  464. for (o = s_pPendingOperations; o != NULL; o = o->pNext) {
  465. if (o->fIsRemove) {
  466. PBYTE pbSrc = o->pTrampoline->rbCode;
  467. LONG cbCopy = 0;
  468. for (; cbCopy < o->pTrampoline->cbTarget;) {
  469. LONG lExtra = 0;
  470. pbSrc = (PBYTE)DetourCopyInstructionEx(o->pbTarget + cbCopy,
  471. pbSrc, NULL, &lExtra);
  472. if (lExtra != 0) {
  473. break; // Abort if offset doesn't fit.
  474. }
  475. cbCopy = (LONG)(pbSrc - o->pTrampoline->rbCode);
  476. }
  477. if (cbCopy != o->pTrampoline->cbTarget) { // Count came out different!
  478. // This is a drastic error as the backward copy should never fail.
  479. s_nPendingError = ERROR_INVALID_DATA;
  480. s_ppPendingError = (PVOID*)o->ppbPointer;
  481. DETOUR_BREAK();
  482. }
  483. #ifdef DETOURS_IA64
  484. #error Feature not supported in this release.
  485. #else // DETOURS_IA64
  486. *o->ppbPointer = o->pbTarget;
  487. #endif
  488. }
  489. else {
  490. DETOUR_TRACE(("detours: pbTramp =%p, pbRemain=%p, pbDetour=%p, cbTarget=%d\n",
  491. o->pTrampoline,
  492. o->pTrampoline->pbRemain,
  493. o->pTrampoline->pbDetour,
  494. o->pTrampoline->cbTarget));
  495. DETOUR_TRACE(("detours: pbTarget=%p: "
  496. "%02x %02x %02x %02x "
  497. "%02x %02x %02x %02x "
  498. "%02x %02x %02x %02x [before]\n",
  499. o->pbTarget,
  500. o->pbTarget[0], o->pbTarget[1], o->pbTarget[2], o->pbTarget[3],
  501. o->pbTarget[4], o->pbTarget[5], o->pbTarget[6], o->pbTarget[7],
  502. o->pbTarget[8], o->pbTarget[9], o->pbTarget[10], o->pbTarget[11]));
  503. #ifdef DETOURS_IA64
  504. #error Feature not supported in this release.
  505. #endif // DETOURS_IA64
  506. #ifdef DETOURS_X64
  507. #error Feature not supported in this release.
  508. #endif // DETOURS_X64
  509. #ifdef DETOURS_X86
  510. PBYTE pbCode = detour_gen_jmp_immediate(o->pbTarget, o->pTrampoline->pbDetour);
  511. pbCode = detour_gen_brk(pbCode, o->pTrampoline->pbRemain);
  512. *o->ppbPointer = o->pTrampoline->rbCode;
  513. #endif // DETOURS_X86
  514. DETOUR_TRACE(("detours: pbTarget=%p: "
  515. "%02x %02x %02x %02x "
  516. "%02x %02x %02x %02x "
  517. "%02x %02x %02x %02x [after]\n",
  518. o->pbTarget,
  519. o->pbTarget[0], o->pbTarget[1], o->pbTarget[2], o->pbTarget[3],
  520. o->pbTarget[4], o->pbTarget[5], o->pbTarget[6], o->pbTarget[7],
  521. o->pbTarget[8], o->pbTarget[9], o->pbTarget[10], o->pbTarget[11]));
  522. DETOUR_TRACE(("detours: pbTramp =%p: "
  523. "%02x %02x %02x %02x "
  524. "%02x %02x %02x %02x "
  525. "%02x %02x %02x %02x\n",
  526. o->pTrampoline,
  527. o->pTrampoline->rbCode[0], o->pTrampoline->rbCode[1],
  528. o->pTrampoline->rbCode[2], o->pTrampoline->rbCode[3],
  529. o->pTrampoline->rbCode[4], o->pTrampoline->rbCode[5],
  530. o->pTrampoline->rbCode[6], o->pTrampoline->rbCode[7],
  531. o->pTrampoline->rbCode[8], o->pTrampoline->rbCode[9],
  532. o->pTrampoline->rbCode[10], o->pTrampoline->rbCode[11]));
  533. #ifdef DETOURS_IA64
  534. #error Feature not supported in this release.
  535. #endif // DETOURS_IA64
  536. }
  537. }
  538. // Update any suspended threads.
  539. for (t = s_pPendingThreads; t != NULL; t = t->pNext) {
  540. CONTEXT cxt;
  541. cxt.ContextFlags = CONTEXT_CONTROL;
  542. #undef DETOURS_EIP
  543. #undef DETOURS_EIP_TYPE
  544. #ifdef DETOURS_X86
  545. #define DETOURS_EIP Eip
  546. #define DETOURS_EIP_TYPE DWORD
  547. #endif // DETOURS_X86
  548. #ifdef DETOURS_X64
  549. #error Feature not supported in this release.
  550. #endif // DETOURS_X64
  551. #ifdef DETOURS_IA64
  552. #error Feature not supported in this release.
  553. #endif // DETOURS_IA64
  554. if (GetThreadContext(t->hThread, &cxt)) {
  555. for (DetourOperation *o = s_pPendingOperations; o != NULL; o = o->pNext) {
  556. if (o->fIsRemove) {
  557. if (cxt.DETOURS_EIP >= (DETOURS_EIP_TYPE)(ULONG_PTR)o->pTrampoline &&
  558. cxt.DETOURS_EIP < (DETOURS_EIP_TYPE)(ULONG_PTR)o->pTrampoline + sizeof(o->pTrampoline)) {
  559. cxt.DETOURS_EIP -= (DETOURS_EIP_TYPE)(ULONG_PTR)o->pTrampoline;
  560. cxt.DETOURS_EIP += (DETOURS_EIP_TYPE)(ULONG_PTR)o->pbTarget;
  561. SetThreadContext(t->hThread, &cxt);
  562. }
  563. }
  564. else {
  565. if (cxt.DETOURS_EIP >= (DETOURS_EIP_TYPE)(ULONG_PTR)o->pbTarget &&
  566. cxt.DETOURS_EIP < ((DETOURS_EIP_TYPE)(ULONG_PTR)o->pbTarget +
  567. o->pTrampoline->cbTarget)) {
  568. cxt.DETOURS_EIP -= (DETOURS_EIP_TYPE)(ULONG_PTR)o->pbTarget;
  569. cxt.DETOURS_EIP += (DETOURS_EIP_TYPE)(ULONG_PTR)o->pTrampoline;
  570. SetThreadContext(t->hThread, &cxt);
  571. }
  572. }
  573. }
  574. }
  575. #undef DETOURS_EIP
  576. }
  577. // Restore all of the page permissions and flush the icache.
  578. HANDLE hProcess = GetCurrentProcess();
  579. for (o = s_pPendingOperations; o != NULL;) {
  580. // We don't care if this fails, because the code is still accessible.
  581. DWORD dwOld;
  582. VirtualProtect(o->pbTarget, o->pTrampoline->cbTarget, o->dwPerm, &dwOld);
  583. FlushInstructionCache(hProcess, o->pbTarget, o->pTrampoline->cbTarget);
  584. if (o->fIsRemove && o->pTrampoline) {
  585. detour_free_trampoline(o->pTrampoline);
  586. o->pTrampoline = NULL;
  587. }
  588. DetourOperation *n = o->pNext;
  589. delete o;
  590. o = n;
  591. }
  592. s_pPendingOperations = NULL;
  593. // Make sure the trampoline pages are no longer writable.
  594. detour_runnable_trampoline_regions();
  595. // Resume any suspended threads.
  596. for (t = s_pPendingThreads; t != NULL;) {
  597. // There is nothing we can do if this fails.
  598. ResumeThread(t->hThread);
  599. DetourThread *n = t->pNext;
  600. delete t;
  601. t = n;
  602. }
  603. s_pPendingThreads = NULL;
  604. s_nPendingThreadId = 0;
  605. if (pppFailedPointer != NULL) {
  606. *pppFailedPointer = s_ppPendingError;
  607. }
  608. return s_nPendingError;
  609. }
  610. LONG WINAPI DetourUpdateThread(HANDLE hThread)
  611. {
  612. LONG error;
  613. // If any of the pending operations failed, then we don't need to do this.
  614. if (s_nPendingError != NO_ERROR) {
  615. return s_nPendingError;
  616. }
  617. // Silently (and safely) drop any attempt to suspend our own thread.
  618. if (hThread == GetCurrentThread()) {
  619. return NO_ERROR;
  620. }
  621. DetourThread *t = new DetourThread;
  622. if (t == NULL) {
  623. error = ERROR_NOT_ENOUGH_MEMORY;
  624. fail:
  625. if (t != NULL) {
  626. delete t;
  627. t = NULL;
  628. }
  629. s_nPendingError = error;
  630. s_ppPendingError = NULL;
  631. DETOUR_BREAK();
  632. return error;
  633. }
  634. if (SuspendThread(hThread) == (DWORD)-1) {
  635. error = GetLastError();
  636. DETOUR_BREAK();
  637. goto fail;
  638. }
  639. t->hThread = hThread;
  640. t->pNext = s_pPendingThreads;
  641. s_pPendingThreads = t;
  642. return NO_ERROR;
  643. }
  644. ///////////////////////////////////////////////////////////// Transacted APIs.
  645. //
  646. LONG WINAPI DetourAttach(PVOID *ppPointer,
  647. PVOID pDetour)
  648. {
  649. return DetourAttachEx(ppPointer, pDetour, NULL, NULL, NULL);
  650. }
  651. LONG WINAPI DetourAttachEx(PVOID *ppPointer,
  652. PVOID pDetour,
  653. PDETOUR_TRAMPOLINE *ppRealTrampoline,
  654. PVOID *ppRealTarget,
  655. PVOID *ppRealDetour)
  656. {
  657. LONG error = NO_ERROR;
  658. if (ppRealTrampoline != NULL) {
  659. *ppRealTrampoline = NULL;
  660. }
  661. if (ppRealTarget != NULL) {
  662. *ppRealTarget = NULL;
  663. }
  664. if (ppRealDetour != NULL) {
  665. *ppRealDetour = NULL;
  666. }
  667. if (s_nPendingThreadId != (LONG)GetCurrentThreadId()) {
  668. DETOUR_TRACE(("transaction conflict with thread id=%d\n", s_nPendingThreadId));
  669. return ERROR_INVALID_OPERATION;
  670. }
  671. // If any of the pending operations failed, then we don't need to do this.
  672. if (s_nPendingError != NO_ERROR) {
  673. DETOUR_TRACE(("pending transaction error=%d\n", s_nPendingError));
  674. return s_nPendingError;
  675. }
  676. if (ppPointer == NULL) {
  677. DETOUR_TRACE(("ppPointer is null\n"));
  678. return ERROR_INVALID_HANDLE;
  679. }
  680. if (*ppPointer == NULL) {
  681. error = ERROR_INVALID_HANDLE;
  682. s_nPendingError = error;
  683. s_ppPendingError = ppPointer;
  684. DETOUR_TRACE(("*ppPointer is null (ppPointer=%p)\n", ppPointer));
  685. DETOUR_BREAK();
  686. return error;
  687. }
  688. PBYTE pbTarget = (PBYTE)*ppPointer;
  689. PDETOUR_TRAMPOLINE pTrampoline = NULL;
  690. DetourOperation *o = NULL;
  691. #ifdef DETOURS_IA64
  692. #error Feature not supported in this release.
  693. #else
  694. pbTarget = (PBYTE)DetourCodeFromPointer(pbTarget, NULL);
  695. pDetour = DetourCodeFromPointer(pDetour, NULL);
  696. #endif
  697. // Don't follow a jump if its destination is the target function.
  698. // This happens when the detour does nothing other than call the target.
  699. if (pDetour == (PVOID)pbTarget) {
  700. if (s_fIgnoreTooSmall) {
  701. goto stop;
  702. }
  703. else {
  704. DETOUR_BREAK();
  705. goto fail;
  706. }
  707. }
  708. if (ppRealTarget != NULL) {
  709. *ppRealTarget = pbTarget;
  710. }
  711. if (ppRealDetour != NULL) {
  712. *ppRealDetour = pDetour;
  713. }
  714. o = new DetourOperation;
  715. if (o == NULL) {
  716. error = ERROR_NOT_ENOUGH_MEMORY;
  717. fail:
  718. s_nPendingError = error;
  719. DETOUR_BREAK();
  720. stop:
  721. if (pTrampoline != NULL) {
  722. detour_free_trampoline(pTrampoline);
  723. pTrampoline = NULL;
  724. }
  725. if (o != NULL) {
  726. delete o;
  727. o = NULL;
  728. }
  729. s_ppPendingError = ppPointer;
  730. return error;
  731. }
  732. // Mark process as having detoured code.
  733. #ifdef DETOURS_INTERNAL_USAGE
  734. #error Feature not supported in this release.
  735. #else
  736. Detoured();
  737. #endif
  738. pTrampoline = detour_alloc_trampoline(pbTarget);
  739. if (pTrampoline == NULL) {
  740. error = ERROR_NOT_ENOUGH_MEMORY;
  741. DETOUR_BREAK();
  742. goto fail;
  743. }
  744. if (ppRealTrampoline != NULL) {
  745. *ppRealTrampoline = pTrampoline;
  746. }
  747. DETOUR_TRACE(("detours: pbTramp=%p, pDetour=%p\n", pTrampoline, pDetour));
  748. // Determine the number of movable target instructions.
  749. PBYTE pbSrc = pbTarget;
  750. LONG cbTarget = 0;
  751. while (cbTarget < SIZE_OF_JMP) {
  752. PBYTE pbOp = pbSrc;
  753. LONG lExtra = 0;
  754. DETOUR_TRACE((" DetourCopyInstructionEx(%p,%p)\n",
  755. pTrampoline->rbCode + cbTarget, pbSrc));
  756. pbSrc = (PBYTE)DetourCopyInstructionEx(pTrampoline->rbCode + cbTarget,
  757. pbSrc, NULL, &lExtra);
  758. DETOUR_TRACE((" DetourCopyInstructionEx() = %p (%d bytes)\n",
  759. pbSrc, (int)(pbSrc - pbOp)));
  760. if (lExtra != 0) {
  761. break; // Abort if offset doesn't fit.
  762. }
  763. cbTarget = (LONG)(pbSrc - pbTarget);
  764. if (detour_does_code_end_function(pbOp)) {
  765. break;
  766. }
  767. }
  768. if (cbTarget < SIZE_OF_JMP) {
  769. // Too few instructions.
  770. error = ERROR_INVALID_BLOCK;
  771. if (s_fIgnoreTooSmall) {
  772. goto stop;
  773. }
  774. else {
  775. DETOUR_BREAK();
  776. goto fail;
  777. }
  778. }
  779. #if !defined(DETOURS_IA64)
  780. if (cbTarget > sizeof(pTrampoline->rbCode) - SIZE_OF_JMP) {
  781. // Too many instructions.
  782. error = ERROR_INVALID_HANDLE;
  783. DETOUR_BREAK();
  784. goto fail;
  785. }
  786. #endif
  787. pTrampoline->pbRemain = pbTarget + cbTarget;
  788. pTrampoline->pbDetour = (PBYTE)pDetour;
  789. pTrampoline->cbTarget = (BYTE)cbTarget;
  790. #ifdef DETOURS_IA64
  791. #error Feature not supported in this release.
  792. #endif // DETOURS_IA64
  793. #ifdef DETOURS_X64
  794. #error Feature not supported in this release.
  795. #endif // DETOURS_X64
  796. #ifdef DETOURS_X86
  797. pbSrc = detour_gen_jmp_immediate(pTrampoline->rbCode + cbTarget, pTrampoline->pbRemain);
  798. pbSrc = detour_gen_brk(pbSrc,
  799. pTrampoline->rbCode + sizeof(pTrampoline->rbCode));
  800. #endif // DETOURS_X86
  801. DWORD dwOld = 0;
  802. if (!VirtualProtect(pbTarget, cbTarget, PAGE_EXECUTE_READWRITE, &dwOld)) {
  803. error = GetLastError();
  804. DETOUR_BREAK();
  805. goto fail;
  806. }
  807. DETOUR_TRACE(("detours: pbTarget=%p: "
  808. "%02x %02x %02x %02x "
  809. "%02x %02x %02x %02x "
  810. "%02x %02x %02x %02x\n",
  811. pbTarget,
  812. pbTarget[0], pbTarget[1], pbTarget[2], pbTarget[3],
  813. pbTarget[4], pbTarget[5], pbTarget[6], pbTarget[7],
  814. pbTarget[8], pbTarget[9], pbTarget[10], pbTarget[11]));
  815. DETOUR_TRACE(("detours: pbTramp =%p: "
  816. "%02x %02x %02x %02x "
  817. "%02x %02x %02x %02x "
  818. "%02x %02x %02x %02x\n",
  819. pTrampoline,
  820. pTrampoline->rbCode[0], pTrampoline->rbCode[1],
  821. pTrampoline->rbCode[2], pTrampoline->rbCode[3],
  822. pTrampoline->rbCode[4], pTrampoline->rbCode[5],
  823. pTrampoline->rbCode[6], pTrampoline->rbCode[7],
  824. pTrampoline->rbCode[8], pTrampoline->rbCode[9],
  825. pTrampoline->rbCode[10], pTrampoline->rbCode[11]));
  826. /////////////////////////////////////////// Mark binary as being detoured.
  827. //
  828. PIMAGE_DOS_HEADER pDosHeader = detour_find_header(pbTarget);
  829. if (pDosHeader != NULL && pDosHeader->e_res[0] != 'eD') {
  830. DWORD dwDos = 0;
  831. if (!VirtualProtect(pDosHeader, sizeof(*pDosHeader), PAGE_EXECUTE_READWRITE, &dwDos)) {
  832. error = GetLastError();
  833. DETOUR_BREAK();
  834. goto fail;
  835. }
  836. pDosHeader->e_res[0] = 'eD';
  837. pDosHeader->e_res[1] = 'ot';
  838. pDosHeader->e_res[2] = 'ru';
  839. pDosHeader->e_res[3] = '!s';
  840. }
  841. o->fIsRemove = FALSE;
  842. o->ppbPointer = (PBYTE*)ppPointer;
  843. o->pTrampoline = pTrampoline;
  844. o->pbTarget = pbTarget;
  845. o->dwPerm = dwOld;
  846. o->pNext = s_pPendingOperations;
  847. s_pPendingOperations = o;
  848. return NO_ERROR;
  849. }
  850. LONG WINAPI DetourDetach(PVOID *ppPointer,
  851. PVOID pDetour)
  852. {
  853. LONG error = NO_ERROR;
  854. if (s_nPendingThreadId != (LONG)GetCurrentThreadId()) {
  855. return ERROR_INVALID_OPERATION;
  856. }
  857. // If any of the pending operations failed, then we don't need to do this.
  858. if (s_nPendingError != NO_ERROR) {
  859. return s_nPendingError;
  860. }
  861. if (ppPointer == NULL) {
  862. return ERROR_INVALID_HANDLE;
  863. }
  864. if (*ppPointer == NULL) {
  865. error = ERROR_INVALID_HANDLE;
  866. s_nPendingError = error;
  867. s_ppPendingError = ppPointer;
  868. DETOUR_BREAK();
  869. return error;
  870. }
  871. DetourOperation *o = new DetourOperation;
  872. if (o == NULL) {
  873. error = ERROR_NOT_ENOUGH_MEMORY;
  874. fail:
  875. s_nPendingError = error;
  876. DETOUR_BREAK();
  877. stop:
  878. if (o != NULL) {
  879. delete o;
  880. o = NULL;
  881. }
  882. s_ppPendingError = ppPointer;
  883. return error;
  884. }
  885. PDETOUR_TRAMPOLINE pTrampoline = (PDETOUR_TRAMPOLINE)*ppPointer;
  886. pDetour = DetourCodeFromPointer(pDetour, NULL);
  887. ////////////////////////////////////// Verify that Trampoline is in place.
  888. //
  889. PBYTE pbTarget = pTrampoline->pbRemain - pTrampoline->cbTarget;
  890. LONG cbTarget = pTrampoline->cbTarget;
  891. if (cbTarget == 0 || cbTarget > sizeof(pTrampoline->rbCode)) {
  892. error = ERROR_INVALID_BLOCK;
  893. if (s_fIgnoreTooSmall) {
  894. goto stop;
  895. }
  896. else {
  897. DETOUR_BREAK();
  898. goto fail;
  899. }
  900. }
  901. if (pTrampoline->pbDetour != pDetour) {
  902. error = ERROR_INVALID_BLOCK;
  903. if (s_fIgnoreTooSmall) {
  904. goto stop;
  905. }
  906. else {
  907. DETOUR_BREAK();
  908. goto fail;
  909. }
  910. }
  911. DWORD dwOld = 0;
  912. if (!VirtualProtect(pbTarget, cbTarget,
  913. PAGE_EXECUTE_READWRITE, &dwOld)) {
  914. error = GetLastError();
  915. DETOUR_BREAK();
  916. goto fail;
  917. }
  918. o->fIsRemove = TRUE;
  919. o->ppbPointer = (PBYTE*)ppPointer;
  920. o->pTrampoline = pTrampoline;
  921. o->pbTarget = pbTarget;
  922. o->dwPerm = dwOld;
  923. o->pNext = s_pPendingOperations;
  924. s_pPendingOperations = o;
  925. return NO_ERROR;
  926. }
  927. HMODULE WINAPI DetourGetDetouredMarker()
  928. {
  929. #ifdef DETOURS_INTERNAL_USAGE
  930. #error Feature not supported in this release.
  931. #else
  932. return Detoured();
  933. #endif
  934. }
  935. // End of File