detours.cpp 28 KB

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