detours.cpp 92 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727
  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Core Detours Functionality (detours.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. //#define DETOUR_DEBUG 1
  10. #define DETOURS_INTERNAL
  11. #include "detours.h"
  12. #if !defined(SUNRISE_DETOURS_ALLOCATOR_PROOF_LEGACY)
  13. #include "../../src/client/hooking/detour/transaction/detour_transaction_storage.h"
  14. #endif
  15. #if DETOURS_VERSION != 0x4c0c1 // 0xMAJORcMINORcPATCH
  16. #error detours.h version mismatch
  17. #endif
  18. #define NOTHROW
  19. //////////////////////////////////////////////////////////////////////////////
  20. //
  21. #ifdef _DEBUG
  22. extern "C" IMAGE_DOS_HEADER __ImageBase;
  23. int Detour_AssertExprWithFunctionName(int reportType, const char* filename, int linenumber, const char* FunctionName, const char* msg)
  24. {
  25. int nRet = 0;
  26. DWORD dwLastError = GetLastError();
  27. CHAR szModuleNameWithFunctionName[MAX_PATH * 2];
  28. szModuleNameWithFunctionName[0] = 0;
  29. GetModuleFileNameA((HMODULE)&__ImageBase, szModuleNameWithFunctionName, ARRAYSIZE(szModuleNameWithFunctionName));
  30. StringCchCatNA(szModuleNameWithFunctionName, ARRAYSIZE(szModuleNameWithFunctionName), ",", ARRAYSIZE(szModuleNameWithFunctionName) - strlen(szModuleNameWithFunctionName) - 1);
  31. StringCchCatNA(szModuleNameWithFunctionName, ARRAYSIZE(szModuleNameWithFunctionName), FunctionName, ARRAYSIZE(szModuleNameWithFunctionName) - strlen(szModuleNameWithFunctionName) - 1);
  32. SetLastError(dwLastError);
  33. nRet = _CrtDbgReport(reportType, filename, linenumber, szModuleNameWithFunctionName, msg);
  34. SetLastError(dwLastError);
  35. return nRet;
  36. }
  37. #endif// _DEBUG
  38. //////////////////////////////////////////////////////////////////////////////
  39. //
  40. struct _DETOUR_ALIGN
  41. {
  42. BYTE obTarget : 3;
  43. BYTE obTrampoline : 5;
  44. };
  45. C_ASSERT(sizeof(_DETOUR_ALIGN) == 1);
  46. //////////////////////////////////////////////////////////////////////////////
  47. //
  48. // Region reserved for system DLLs, which cannot be used for trampolines.
  49. //
  50. static PVOID s_pSystemRegionLowerBound = (PVOID)(ULONG_PTR)0x70000000;
  51. static PVOID s_pSystemRegionUpperBound = (PVOID)(ULONG_PTR)0x80000000;
  52. //////////////////////////////////////////////////////////////////////////////
  53. //
  54. static bool detour_is_imported(PBYTE pbCode, PBYTE pbAddress)
  55. {
  56. MEMORY_BASIC_INFORMATION mbi;
  57. VirtualQuery((PVOID)pbCode, &mbi, sizeof(mbi));
  58. __try {
  59. PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mbi.AllocationBase;
  60. if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
  61. return false;
  62. }
  63. PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +
  64. pDosHeader->e_lfanew);
  65. if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
  66. return false;
  67. }
  68. if (pbAddress >= ((PBYTE)pDosHeader +
  69. pNtHeader->OptionalHeader
  70. .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress) &&
  71. pbAddress < ((PBYTE)pDosHeader +
  72. pNtHeader->OptionalHeader
  73. .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress +
  74. pNtHeader->OptionalHeader
  75. .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size)) {
  76. return true;
  77. }
  78. }
  79. #pragma prefast(suppress:28940, "A bad pointer means this probably isn't a PE header.")
  80. __except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
  81. EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
  82. return false;
  83. }
  84. return false;
  85. }
  86. inline ULONG_PTR detour_2gb_below(ULONG_PTR address)
  87. {
  88. return (address > (ULONG_PTR)0x7ff80000) ? address - 0x7ff80000 : 0x80000;
  89. }
  90. inline ULONG_PTR detour_2gb_above(ULONG_PTR address)
  91. {
  92. #if defined(DETOURS_64BIT)
  93. return (address < (ULONG_PTR)0xffffffff80000000) ? address + 0x7ff80000 : (ULONG_PTR)0xfffffffffff80000;
  94. #else
  95. return (address < (ULONG_PTR)0x80000000) ? address + 0x7ff80000 : (ULONG_PTR)0xfff80000;
  96. #endif
  97. }
  98. ///////////////////////////////////////////////////////////////////////// X86.
  99. //
  100. #ifdef DETOURS_X86
  101. struct _DETOUR_TRAMPOLINE
  102. {
  103. BYTE rbCode[30]; // target code + jmp to pbRemain
  104. BYTE cbCode; // size of moved target code.
  105. BYTE cbCodeBreak; // padding to make debugging easier.
  106. BYTE rbRestore[22]; // original target code.
  107. BYTE cbRestore; // size of original target code.
  108. BYTE cbRestoreBreak; // padding to make debugging easier.
  109. _DETOUR_ALIGN rAlign[8]; // instruction alignment array.
  110. PBYTE pbRemain; // first instruction after moved code. [free list]
  111. PBYTE pbDetour; // first instruction of detour function.
  112. };
  113. C_ASSERT(sizeof(_DETOUR_TRAMPOLINE) == 72);
  114. enum {
  115. SIZE_OF_JMP = 5
  116. };
  117. inline PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE pbJmpVal)
  118. {
  119. PBYTE pbJmpSrc = pbCode + 5;
  120. *pbCode++ = 0xE9; // jmp +imm32
  121. *((INT32*&)pbCode)++ = (INT32)(pbJmpVal - pbJmpSrc);
  122. return pbCode;
  123. }
  124. inline PBYTE detour_gen_jmp_indirect(PBYTE pbCode, PBYTE *ppbJmpVal)
  125. {
  126. *pbCode++ = 0xff; // jmp [+imm32]
  127. *pbCode++ = 0x25;
  128. *((INT32*&)pbCode)++ = (INT32)((PBYTE)ppbJmpVal);
  129. return pbCode;
  130. }
  131. inline PBYTE detour_gen_brk(PBYTE pbCode, PBYTE pbLimit)
  132. {
  133. while (pbCode < pbLimit) {
  134. *pbCode++ = 0xcc; // brk;
  135. }
  136. return pbCode;
  137. }
  138. inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals)
  139. {
  140. PBYTE pbCodeOriginal;
  141. if (pbCode == NULL) {
  142. return NULL;
  143. }
  144. if (ppGlobals != NULL) {
  145. *ppGlobals = NULL;
  146. }
  147. // First, skip over the import vector if there is one.
  148. if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [imm32]
  149. // Looks like an import alias jump, then get the code it points to.
  150. PBYTE pbTarget = *(UNALIGNED PBYTE *)&pbCode[2];
  151. if (detour_is_imported(pbCode, pbTarget)) {
  152. PBYTE pbNew = *(UNALIGNED PBYTE *)pbTarget;
  153. DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew));
  154. pbCode = pbNew;
  155. }
  156. }
  157. // Then, skip over a patch jump
  158. if (pbCode[0] == 0xeb) { // jmp +imm8
  159. PBYTE pbNew = pbCode + 2 + *(CHAR *)&pbCode[1];
  160. DETOUR_TRACE(("%p->%p: skipped over short jump.\n", pbCode, pbNew));
  161. pbCode = pbNew;
  162. pbCodeOriginal = pbCode;
  163. // First, skip over the import vector if there is one.
  164. if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [imm32]
  165. // Looks like an import alias jump, then get the code it points to.
  166. PBYTE pbTarget = *(UNALIGNED PBYTE *)&pbCode[2];
  167. if (detour_is_imported(pbCode, pbTarget)) {
  168. pbNew = *(UNALIGNED PBYTE *)pbTarget;
  169. DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew));
  170. pbCode = pbNew;
  171. }
  172. }
  173. // Finally, skip over a long jump if it is the target of the patch jump.
  174. else if (pbCode[0] == 0xe9) { // jmp +imm32
  175. pbNew = pbCode + 5 + *(UNALIGNED INT32 *)&pbCode[1];
  176. DETOUR_TRACE(("%p->%p: skipped over long jump.\n", pbCode, pbNew));
  177. pbCode = pbNew;
  178. // Patches applied by the OS will jump through an HPAT page to get
  179. // the target function in the patch image. The jump is always performed
  180. // to the target function found at the current instruction pointer +
  181. // PAGE_SIZE - 6 (size of jump).
  182. // If this is an OS patch, we want to detour at the point of the target function
  183. // padding in the base image. Ideally, we would detour at the target function, but
  184. // since it's patched it begins with a short jump (to padding) which isn't long
  185. // enough to hold the detour code bytes.
  186. if (pbCode[0] == 0xff &&
  187. pbCode[1] == 0x25 &&
  188. *(UNALIGNED INT32 *)&pbCode[2] == (UNALIGNED INT32)(pbCode + 0x1000)) { // jmp [eip+PAGE_SIZE-6]
  189. DETOUR_TRACE(("%p->%p: OS patch encountered, reset back to long jump 5 bytes prior to target function.\n", pbCode, pbCodeOriginal));
  190. pbCode = pbCodeOriginal;
  191. }
  192. }
  193. }
  194. return pbCode;
  195. }
  196. inline void detour_find_jmp_bounds(PBYTE pbCode,
  197. PDETOUR_TRAMPOLINE *ppLower,
  198. PDETOUR_TRAMPOLINE *ppUpper)
  199. {
  200. // We have to place trampolines within +/- 2GB of code.
  201. ULONG_PTR lo = detour_2gb_below((ULONG_PTR)pbCode);
  202. ULONG_PTR hi = detour_2gb_above((ULONG_PTR)pbCode);
  203. DETOUR_TRACE(("[%p..%p..%p]\n", (PVOID)lo, pbCode, (PVOID)hi));
  204. // And, within +/- 2GB of relative jmp targets.
  205. if (pbCode[0] == 0xe9) { // jmp +imm32
  206. PBYTE pbNew = pbCode + 5 + *(UNALIGNED INT32 *)&pbCode[1];
  207. if (pbNew < pbCode) {
  208. hi = detour_2gb_above((ULONG_PTR)pbNew);
  209. }
  210. else {
  211. lo = detour_2gb_below((ULONG_PTR)pbNew);
  212. }
  213. DETOUR_TRACE(("[%p..%p..%p] +imm32\n", (PVOID)lo, pbCode, (PVOID)hi));
  214. }
  215. *ppLower = (PDETOUR_TRAMPOLINE)lo;
  216. *ppUpper = (PDETOUR_TRAMPOLINE)hi;
  217. }
  218. inline BOOL detour_does_code_end_function(PBYTE pbCode)
  219. {
  220. if (pbCode[0] == 0xeb || // jmp +imm8
  221. pbCode[0] == 0xe9 || // jmp +imm32
  222. pbCode[0] == 0xe0 || // jmp eax
  223. pbCode[0] == 0xc2 || // ret +imm8
  224. pbCode[0] == 0xc3 || // ret
  225. pbCode[0] == 0xcc) { // brk
  226. return TRUE;
  227. }
  228. else if (pbCode[0] == 0xf3 && pbCode[1] == 0xc3) { // rep ret
  229. return TRUE;
  230. }
  231. else if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [+imm32]
  232. return TRUE;
  233. }
  234. else if ((pbCode[0] == 0x26 || // jmp es:
  235. pbCode[0] == 0x2e || // jmp cs:
  236. pbCode[0] == 0x36 || // jmp ss:
  237. pbCode[0] == 0x3e || // jmp ds:
  238. pbCode[0] == 0x64 || // jmp fs:
  239. pbCode[0] == 0x65) && // jmp gs:
  240. pbCode[1] == 0xff && // jmp [+imm32]
  241. pbCode[2] == 0x25) {
  242. return TRUE;
  243. }
  244. return FALSE;
  245. }
  246. inline ULONG detour_is_code_filler(PBYTE pbCode)
  247. {
  248. // 1-byte through 11-byte NOPs.
  249. if (pbCode[0] == 0x90) {
  250. return 1;
  251. }
  252. if (pbCode[0] == 0x66 && pbCode[1] == 0x90) {
  253. return 2;
  254. }
  255. if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x00) {
  256. return 3;
  257. }
  258. if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x40 &&
  259. pbCode[3] == 0x00) {
  260. return 4;
  261. }
  262. if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x44 &&
  263. pbCode[3] == 0x00 && pbCode[4] == 0x00) {
  264. return 5;
  265. }
  266. if (pbCode[0] == 0x66 && pbCode[1] == 0x0F && pbCode[2] == 0x1F &&
  267. pbCode[3] == 0x44 && pbCode[4] == 0x00 && pbCode[5] == 0x00) {
  268. return 6;
  269. }
  270. if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x80 &&
  271. pbCode[3] == 0x00 && pbCode[4] == 0x00 && pbCode[5] == 0x00 &&
  272. pbCode[6] == 0x00) {
  273. return 7;
  274. }
  275. if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x84 &&
  276. pbCode[3] == 0x00 && pbCode[4] == 0x00 && pbCode[5] == 0x00 &&
  277. pbCode[6] == 0x00 && pbCode[7] == 0x00) {
  278. return 8;
  279. }
  280. if (pbCode[0] == 0x66 && pbCode[1] == 0x0F && pbCode[2] == 0x1F &&
  281. pbCode[3] == 0x84 && pbCode[4] == 0x00 && pbCode[5] == 0x00 &&
  282. pbCode[6] == 0x00 && pbCode[7] == 0x00 && pbCode[8] == 0x00) {
  283. return 9;
  284. }
  285. if (pbCode[0] == 0x66 && pbCode[1] == 0x66 && pbCode[2] == 0x0F &&
  286. pbCode[3] == 0x1F && pbCode[4] == 0x84 && pbCode[5] == 0x00 &&
  287. pbCode[6] == 0x00 && pbCode[7] == 0x00 && pbCode[8] == 0x00 &&
  288. pbCode[9] == 0x00) {
  289. return 10;
  290. }
  291. if (pbCode[0] == 0x66 && pbCode[1] == 0x66 && pbCode[2] == 0x66 &&
  292. pbCode[3] == 0x0F && pbCode[4] == 0x1F && pbCode[5] == 0x84 &&
  293. pbCode[6] == 0x00 && pbCode[7] == 0x00 && pbCode[8] == 0x00 &&
  294. pbCode[9] == 0x00 && pbCode[10] == 0x00) {
  295. return 11;
  296. }
  297. // int 3.
  298. if (pbCode[0] == 0xcc) {
  299. return 1;
  300. }
  301. return 0;
  302. }
  303. #endif // DETOURS_X86
  304. ///////////////////////////////////////////////////////////////////////// X64.
  305. //
  306. #ifdef DETOURS_X64
  307. struct _DETOUR_TRAMPOLINE
  308. {
  309. // An X64 instuction can be 15 bytes long.
  310. // In practice 11 seems to be the limit.
  311. BYTE rbCode[30]; // target code + jmp to pbRemain.
  312. BYTE cbCode; // size of moved target code.
  313. BYTE cbCodeBreak; // padding to make debugging easier.
  314. BYTE rbRestore[30]; // original target code.
  315. BYTE cbRestore; // size of original target code.
  316. BYTE cbRestoreBreak; // padding to make debugging easier.
  317. _DETOUR_ALIGN rAlign[8]; // instruction alignment array.
  318. PBYTE pbRemain; // first instruction after moved code. [free list]
  319. PBYTE pbDetour; // first instruction of detour function.
  320. BYTE rbCodeIn[8]; // jmp [pbDetour]
  321. };
  322. C_ASSERT(sizeof(_DETOUR_TRAMPOLINE) == 96);
  323. enum {
  324. SIZE_OF_JMP = 5
  325. };
  326. inline PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE pbJmpVal)
  327. {
  328. PBYTE pbJmpSrc = pbCode + 5;
  329. *pbCode++ = 0xE9; // jmp +imm32
  330. *((INT32*&)pbCode)++ = (INT32)(pbJmpVal - pbJmpSrc);
  331. return pbCode;
  332. }
  333. inline PBYTE detour_gen_jmp_indirect(PBYTE pbCode, PBYTE *ppbJmpVal)
  334. {
  335. PBYTE pbJmpSrc = pbCode + 6;
  336. *pbCode++ = 0xff; // jmp [+imm32]
  337. *pbCode++ = 0x25;
  338. *((INT32*&)pbCode)++ = (INT32)((PBYTE)ppbJmpVal - pbJmpSrc);
  339. return pbCode;
  340. }
  341. inline PBYTE detour_gen_brk(PBYTE pbCode, PBYTE pbLimit)
  342. {
  343. while (pbCode < pbLimit) {
  344. *pbCode++ = 0xcc; // brk;
  345. }
  346. return pbCode;
  347. }
  348. inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals)
  349. {
  350. PBYTE pbCodeOriginal;
  351. if (pbCode == NULL) {
  352. return NULL;
  353. }
  354. if (ppGlobals != NULL) {
  355. *ppGlobals = NULL;
  356. }
  357. // First, skip over the import vector if there is one.
  358. if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [+imm32]
  359. // Looks like an import alias jump, then get the code it points to.
  360. PBYTE pbTarget = pbCode + 6 + *(UNALIGNED INT32 *)&pbCode[2];
  361. if (detour_is_imported(pbCode, pbTarget)) {
  362. PBYTE pbNew = *(UNALIGNED PBYTE *)pbTarget;
  363. DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew));
  364. pbCode = pbNew;
  365. }
  366. }
  367. // Then, skip over a patch jump
  368. if (pbCode[0] == 0xeb) { // jmp +imm8
  369. PBYTE pbNew = pbCode + 2 + *(CHAR *)&pbCode[1];
  370. DETOUR_TRACE(("%p->%p: skipped over short jump.\n", pbCode, pbNew));
  371. pbCode = pbNew;
  372. pbCodeOriginal = pbCode;
  373. // First, skip over the import vector if there is one.
  374. if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [+imm32]
  375. // Looks like an import alias jump, then get the code it points to.
  376. PBYTE pbTarget = pbCode + 6 + *(UNALIGNED INT32 *)&pbCode[2];
  377. if (detour_is_imported(pbCode, pbTarget)) {
  378. pbNew = *(UNALIGNED PBYTE *)pbTarget;
  379. DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew));
  380. pbCode = pbNew;
  381. }
  382. }
  383. // Finally, skip over a long jump if it is the target of the patch jump.
  384. else if (pbCode[0] == 0xe9) { // jmp +imm32
  385. pbNew = pbCode + 5 + *(UNALIGNED INT32 *)&pbCode[1];
  386. DETOUR_TRACE(("%p->%p: skipped over long jump.\n", pbCode, pbNew));
  387. pbCode = pbNew;
  388. // Patches applied by the OS will jump through an HPAT page to get
  389. // the target function in the patch image. The jump is always performed
  390. // to the target function found at the current instruction pointer +
  391. // PAGE_SIZE - 6 (size of jump).
  392. // If this is an OS patch, we want to detour at the point of the target function
  393. // in the base image. Since we need 5 bytes to perform the jump, detour at the
  394. // point of the long jump instead of the short jump at the start of the target.
  395. if (pbCode[0] == 0xff &&
  396. pbCode[1] == 0x25 &&
  397. *(UNALIGNED INT32 *)&pbCode[2] == 0xFFA) { // jmp [rip+PAGE_SIZE-6]
  398. DETOUR_TRACE(("%p->%p: OS patch encountered, reset back to long jump 5 bytes prior to target function.\n", pbCode, pbCodeOriginal));
  399. pbCode = pbCodeOriginal;
  400. }
  401. }
  402. }
  403. return pbCode;
  404. }
  405. inline void detour_find_jmp_bounds(PBYTE pbCode,
  406. PDETOUR_TRAMPOLINE *ppLower,
  407. PDETOUR_TRAMPOLINE *ppUpper)
  408. {
  409. // We have to place trampolines within +/- 2GB of code.
  410. ULONG_PTR lo = detour_2gb_below((ULONG_PTR)pbCode);
  411. ULONG_PTR hi = detour_2gb_above((ULONG_PTR)pbCode);
  412. DETOUR_TRACE(("[%p..%p..%p]\n", (PVOID)lo, pbCode, (PVOID)hi));
  413. // And, within +/- 2GB of relative jmp vectors.
  414. if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [+imm32]
  415. PBYTE pbNew = pbCode + 6 + *(UNALIGNED INT32 *)&pbCode[2];
  416. if (pbNew < pbCode) {
  417. hi = detour_2gb_above((ULONG_PTR)pbNew);
  418. }
  419. else {
  420. lo = detour_2gb_below((ULONG_PTR)pbNew);
  421. }
  422. DETOUR_TRACE(("[%p..%p..%p] [+imm32]\n", (PVOID)lo, pbCode, (PVOID)hi));
  423. }
  424. // And, within +/- 2GB of relative jmp targets.
  425. else if (pbCode[0] == 0xe9) { // jmp +imm32
  426. PBYTE pbNew = pbCode + 5 + *(UNALIGNED INT32 *)&pbCode[1];
  427. if (pbNew < pbCode) {
  428. hi = detour_2gb_above((ULONG_PTR)pbNew);
  429. }
  430. else {
  431. lo = detour_2gb_below((ULONG_PTR)pbNew);
  432. }
  433. DETOUR_TRACE(("[%p..%p..%p] +imm32\n", (PVOID)lo, pbCode, (PVOID)hi));
  434. }
  435. *ppLower = (PDETOUR_TRAMPOLINE)lo;
  436. *ppUpper = (PDETOUR_TRAMPOLINE)hi;
  437. }
  438. inline BOOL detour_does_code_end_function(PBYTE pbCode)
  439. {
  440. if (pbCode[0] == 0xeb || // jmp +imm8
  441. pbCode[0] == 0xe9 || // jmp +imm32
  442. pbCode[0] == 0xe0 || // jmp eax
  443. pbCode[0] == 0xc2 || // ret +imm8
  444. pbCode[0] == 0xc3 || // ret
  445. pbCode[0] == 0xcc) { // brk
  446. return TRUE;
  447. }
  448. else if (pbCode[0] == 0xf3 && pbCode[1] == 0xc3) { // rep ret
  449. return TRUE;
  450. }
  451. else if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [+imm32]
  452. return TRUE;
  453. }
  454. else if ((pbCode[0] == 0x26 || // jmp es:
  455. pbCode[0] == 0x2e || // jmp cs:
  456. pbCode[0] == 0x36 || // jmp ss:
  457. pbCode[0] == 0x3e || // jmp ds:
  458. pbCode[0] == 0x64 || // jmp fs:
  459. pbCode[0] == 0x65) && // jmp gs:
  460. pbCode[1] == 0xff && // jmp [+imm32]
  461. pbCode[2] == 0x25) {
  462. return TRUE;
  463. }
  464. return FALSE;
  465. }
  466. inline ULONG detour_is_code_filler(PBYTE pbCode)
  467. {
  468. // 1-byte through 11-byte NOPs.
  469. if (pbCode[0] == 0x90) {
  470. return 1;
  471. }
  472. if (pbCode[0] == 0x66 && pbCode[1] == 0x90) {
  473. return 2;
  474. }
  475. if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x00) {
  476. return 3;
  477. }
  478. if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x40 &&
  479. pbCode[3] == 0x00) {
  480. return 4;
  481. }
  482. if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x44 &&
  483. pbCode[3] == 0x00 && pbCode[4] == 0x00) {
  484. return 5;
  485. }
  486. if (pbCode[0] == 0x66 && pbCode[1] == 0x0F && pbCode[2] == 0x1F &&
  487. pbCode[3] == 0x44 && pbCode[4] == 0x00 && pbCode[5] == 0x00) {
  488. return 6;
  489. }
  490. if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x80 &&
  491. pbCode[3] == 0x00 && pbCode[4] == 0x00 && pbCode[5] == 0x00 &&
  492. pbCode[6] == 0x00) {
  493. return 7;
  494. }
  495. if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x84 &&
  496. pbCode[3] == 0x00 && pbCode[4] == 0x00 && pbCode[5] == 0x00 &&
  497. pbCode[6] == 0x00 && pbCode[7] == 0x00) {
  498. return 8;
  499. }
  500. if (pbCode[0] == 0x66 && pbCode[1] == 0x0F && pbCode[2] == 0x1F &&
  501. pbCode[3] == 0x84 && pbCode[4] == 0x00 && pbCode[5] == 0x00 &&
  502. pbCode[6] == 0x00 && pbCode[7] == 0x00 && pbCode[8] == 0x00) {
  503. return 9;
  504. }
  505. if (pbCode[0] == 0x66 && pbCode[1] == 0x66 && pbCode[2] == 0x0F &&
  506. pbCode[3] == 0x1F && pbCode[4] == 0x84 && pbCode[5] == 0x00 &&
  507. pbCode[6] == 0x00 && pbCode[7] == 0x00 && pbCode[8] == 0x00 &&
  508. pbCode[9] == 0x00) {
  509. return 10;
  510. }
  511. if (pbCode[0] == 0x66 && pbCode[1] == 0x66 && pbCode[2] == 0x66 &&
  512. pbCode[3] == 0x0F && pbCode[4] == 0x1F && pbCode[5] == 0x84 &&
  513. pbCode[6] == 0x00 && pbCode[7] == 0x00 && pbCode[8] == 0x00 &&
  514. pbCode[9] == 0x00 && pbCode[10] == 0x00) {
  515. return 11;
  516. }
  517. // int 3.
  518. if (pbCode[0] == 0xcc) {
  519. return 1;
  520. }
  521. return 0;
  522. }
  523. #endif // DETOURS_X64
  524. //////////////////////////////////////////////////////////////////////// IA64.
  525. //
  526. #ifdef DETOURS_IA64
  527. struct _DETOUR_TRAMPOLINE
  528. {
  529. // On the IA64, a trampoline is used for both incoming and outgoing calls.
  530. //
  531. // The trampoline contains the following bundles for the outgoing call:
  532. // movl gp=target_gp;
  533. // <relocated target bundle>
  534. // brl target_code;
  535. //
  536. // The trampoline contains the following bundles for the incoming call:
  537. // alloc r41=ar.pfs, b, 0, 8, 0
  538. // mov r40=rp
  539. //
  540. // adds r50=0, r39
  541. // adds r49=0, r38
  542. // adds r48=0, r37 ;;
  543. //
  544. // adds r47=0, r36
  545. // adds r46=0, r35
  546. // adds r45=0, r34
  547. //
  548. // adds r44=0, r33
  549. // adds r43=0, r32
  550. // adds r42=0, gp ;;
  551. //
  552. // movl gp=ffffffff`ffffffff ;;
  553. //
  554. // brl.call.sptk.few rp=disas!TestCodes+20e0 (00000000`00404ea0) ;;
  555. //
  556. // adds gp=0, r42
  557. // mov rp=r40, +0 ;;
  558. // mov.i ar.pfs=r41
  559. //
  560. // br.ret.sptk.many rp ;;
  561. //
  562. // This way, we only have to relocate a single bundle.
  563. //
  564. // The complicated incoming trampoline is required because we have to
  565. // create an additional stack frame so that we save and restore the gp.
  566. // We must do this because gp is a caller-saved register, but not saved
  567. // if the caller thinks the target is in the same DLL, which changes
  568. // when we insert a detour.
  569. //
  570. DETOUR_IA64_BUNDLE bMovlTargetGp; // Bundle which sets target GP
  571. BYTE rbCode[sizeof(DETOUR_IA64_BUNDLE)]; // moved bundle.
  572. DETOUR_IA64_BUNDLE bBrlRemainEip; // Brl to pbRemain
  573. // This must be adjacent to bBranchIslands.
  574. // Each instruction in the moved bundle could be a IP-relative chk or branch or call.
  575. // Any such instructions are changed to point to a brl in bBranchIslands.
  576. // This must be adjacent to bBrlRemainEip -- see "pbPool".
  577. DETOUR_IA64_BUNDLE bBranchIslands[DETOUR_IA64_INSTRUCTIONS_PER_BUNDLE];
  578. // Target of brl inserted in target function
  579. DETOUR_IA64_BUNDLE bAllocFrame; // alloc frame
  580. DETOUR_IA64_BUNDLE bSave37to39; // save r37, r38, r39.
  581. DETOUR_IA64_BUNDLE bSave34to36; // save r34, r35, r36.
  582. DETOUR_IA64_BUNDLE bSaveGPto33; // save gp, r32, r33.
  583. DETOUR_IA64_BUNDLE bMovlDetourGp; // set detour GP.
  584. DETOUR_IA64_BUNDLE bCallDetour; // call detour.
  585. DETOUR_IA64_BUNDLE bPopFrameGp; // pop frame and restore gp.
  586. DETOUR_IA64_BUNDLE bReturn; // return to caller.
  587. PLABEL_DESCRIPTOR pldTrampoline;
  588. BYTE rbRestore[sizeof(DETOUR_IA64_BUNDLE)]; // original target bundle.
  589. BYTE cbRestore; // size of original target code.
  590. BYTE cbCode; // size of moved target code.
  591. _DETOUR_ALIGN rAlign[14]; // instruction alignment array.
  592. PBYTE pbRemain; // first instruction after moved code. [free list]
  593. PBYTE pbDetour; // first instruction of detour function.
  594. PPLABEL_DESCRIPTOR ppldDetour; // [pbDetour,gpDetour]
  595. PPLABEL_DESCRIPTOR ppldTarget; // [pbTarget,gpDetour]
  596. };
  597. C_ASSERT(sizeof(DETOUR_IA64_BUNDLE) == 16);
  598. C_ASSERT(sizeof(_DETOUR_TRAMPOLINE) == 256 + DETOUR_IA64_INSTRUCTIONS_PER_BUNDLE * 16);
  599. enum {
  600. SIZE_OF_JMP = sizeof(DETOUR_IA64_BUNDLE)
  601. };
  602. inline PBYTE detour_skip_jmp(PBYTE pPointer, PVOID *ppGlobals)
  603. {
  604. PBYTE pGlobals = NULL;
  605. PBYTE pbCode = NULL;
  606. if (pPointer != NULL) {
  607. PPLABEL_DESCRIPTOR ppld = (PPLABEL_DESCRIPTOR)pPointer;
  608. pbCode = (PBYTE)ppld->EntryPoint;
  609. pGlobals = (PBYTE)ppld->GlobalPointer;
  610. }
  611. if (ppGlobals != NULL) {
  612. *ppGlobals = pGlobals;
  613. }
  614. if (pbCode == NULL) {
  615. return NULL;
  616. }
  617. DETOUR_IA64_BUNDLE *pb = (DETOUR_IA64_BUNDLE *)pbCode;
  618. // IA64 Local Import Jumps look like:
  619. // addl r2=ffffffff`ffe021c0, gp ;;
  620. // ld8 r2=[r2]
  621. // nop.i 0 ;;
  622. //
  623. // ld8 r3=[r2], 8 ;;
  624. // ld8 gp=[r2]
  625. // mov b6=r3, +0
  626. //
  627. // nop.m 0
  628. // nop.i 0
  629. // br.cond.sptk.few b6
  630. //
  631. // 002024000200100b
  632. if ((pb[0].wide[0] & 0xfffffc000603ffff) == 0x002024000200100b &&
  633. pb[0].wide[1] == 0x0004000000203008 &&
  634. pb[1].wide[0] == 0x001014180420180a &&
  635. pb[1].wide[1] == 0x07000830c0203008 &&
  636. pb[2].wide[0] == 0x0000000100000010 &&
  637. pb[2].wide[1] == 0x0080006000000200) {
  638. ULONG64 offset =
  639. ((pb[0].wide[0] & 0x0000000001fc0000) >> 18) | // imm7b
  640. ((pb[0].wide[0] & 0x000001ff00000000) >> 25) | // imm9d
  641. ((pb[0].wide[0] & 0x00000000f8000000) >> 11); // imm5c
  642. if (pb[0].wide[0] & 0x0000020000000000) { // sign
  643. offset |= 0xffffffffffe00000;
  644. }
  645. PBYTE pbTarget = pGlobals + offset;
  646. DETOUR_TRACE(("%p: potential import jump, target=%p\n", pb, pbTarget));
  647. if (detour_is_imported(pbCode, pbTarget) && *(PBYTE*)pbTarget != NULL) {
  648. DETOUR_TRACE(("%p: is import jump, label=%p\n", pb, *(PBYTE *)pbTarget));
  649. PPLABEL_DESCRIPTOR ppld = (PPLABEL_DESCRIPTOR)*(PBYTE *)pbTarget;
  650. pbCode = (PBYTE)ppld->EntryPoint;
  651. pGlobals = (PBYTE)ppld->GlobalPointer;
  652. if (ppGlobals != NULL) {
  653. *ppGlobals = pGlobals;
  654. }
  655. }
  656. }
  657. return pbCode;
  658. }
  659. inline void detour_find_jmp_bounds(PBYTE pbCode,
  660. PDETOUR_TRAMPOLINE *ppLower,
  661. PDETOUR_TRAMPOLINE *ppUpper)
  662. {
  663. (void)pbCode;
  664. *ppLower = (PDETOUR_TRAMPOLINE)(ULONG_PTR)0x0000000000080000;
  665. *ppUpper = (PDETOUR_TRAMPOLINE)(ULONG_PTR)0xfffffffffff80000;
  666. }
  667. inline BOOL detour_does_code_end_function(PBYTE pbCode)
  668. {
  669. // Routine not needed on IA64.
  670. (void)pbCode;
  671. return FALSE;
  672. }
  673. inline ULONG detour_is_code_filler(PBYTE pbCode)
  674. {
  675. // Routine not needed on IA64.
  676. (void)pbCode;
  677. return 0;
  678. }
  679. #endif // DETOURS_IA64
  680. #ifdef DETOURS_ARM
  681. struct _DETOUR_TRAMPOLINE
  682. {
  683. // A Thumb-2 instruction can be 2 or 4 bytes long.
  684. BYTE rbCode[62]; // target code + jmp to pbRemain
  685. BYTE cbCode; // size of moved target code.
  686. BYTE cbCodeBreak; // padding to make debugging easier.
  687. BYTE rbRestore[22]; // original target code.
  688. BYTE cbRestore; // size of original target code.
  689. BYTE cbRestoreBreak; // padding to make debugging easier.
  690. _DETOUR_ALIGN rAlign[8]; // instruction alignment array.
  691. PBYTE pbRemain; // first instruction after moved code. [free list]
  692. PBYTE pbDetour; // first instruction of detour function.
  693. };
  694. C_ASSERT(sizeof(_DETOUR_TRAMPOLINE) == 104);
  695. enum {
  696. SIZE_OF_JMP = 8
  697. };
  698. inline PBYTE align4(PBYTE pValue)
  699. {
  700. return (PBYTE)(((ULONG)pValue) & ~(ULONG)3u);
  701. }
  702. inline ULONG fetch_thumb_opcode(PBYTE pbCode)
  703. {
  704. ULONG Opcode = *(UINT16 *)&pbCode[0];
  705. if (Opcode >= 0xe800) {
  706. Opcode = (Opcode << 16) | *(UINT16 *)&pbCode[2];
  707. }
  708. return Opcode;
  709. }
  710. inline void write_thumb_opcode(PBYTE &pbCode, ULONG Opcode)
  711. {
  712. if (Opcode >= 0x10000) {
  713. *((UINT16*&)pbCode)++ = Opcode >> 16;
  714. }
  715. *((UINT16*&)pbCode)++ = (UINT16)Opcode;
  716. }
  717. PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE *ppPool, PBYTE pbJmpVal)
  718. {
  719. PBYTE pbLiteral;
  720. if (ppPool != NULL) {
  721. *ppPool = *ppPool - 4;
  722. pbLiteral = *ppPool;
  723. }
  724. else {
  725. pbLiteral = align4(pbCode + 6);
  726. }
  727. *((PBYTE*&)pbLiteral) = DETOURS_PBYTE_TO_PFUNC(pbJmpVal);
  728. LONG delta = pbLiteral - align4(pbCode + 4);
  729. write_thumb_opcode(pbCode, 0xf8dff000 | delta); // LDR PC,[PC+n]
  730. if (ppPool == NULL) {
  731. if (((ULONG)pbCode & 2) != 0) {
  732. write_thumb_opcode(pbCode, 0xdefe); // BREAK
  733. }
  734. pbCode += 4;
  735. }
  736. return pbCode;
  737. }
  738. inline PBYTE detour_gen_brk(PBYTE pbCode, PBYTE pbLimit)
  739. {
  740. while (pbCode < pbLimit) {
  741. write_thumb_opcode(pbCode, 0xdefe);
  742. }
  743. return pbCode;
  744. }
  745. inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals)
  746. {
  747. if (pbCode == NULL) {
  748. return NULL;
  749. }
  750. if (ppGlobals != NULL) {
  751. *ppGlobals = NULL;
  752. }
  753. // Skip over the import jump if there is one.
  754. pbCode = (PBYTE)DETOURS_PFUNC_TO_PBYTE(pbCode);
  755. ULONG Opcode = fetch_thumb_opcode(pbCode);
  756. if ((Opcode & 0xfbf08f00) == 0xf2400c00) { // movw r12,#xxxx
  757. ULONG Opcode2 = fetch_thumb_opcode(pbCode+4);
  758. if ((Opcode2 & 0xfbf08f00) == 0xf2c00c00) { // movt r12,#xxxx
  759. ULONG Opcode3 = fetch_thumb_opcode(pbCode+8);
  760. if (Opcode3 == 0xf8dcf000) { // ldr pc,[r12]
  761. PBYTE pbTarget = (PBYTE)(((Opcode2 << 12) & 0xf7000000) |
  762. ((Opcode2 << 1) & 0x08000000) |
  763. ((Opcode2 << 16) & 0x00ff0000) |
  764. ((Opcode >> 4) & 0x0000f700) |
  765. ((Opcode >> 15) & 0x00000800) |
  766. ((Opcode >> 0) & 0x000000ff));
  767. if (detour_is_imported(pbCode, pbTarget)) {
  768. PBYTE pbNew = *(PBYTE *)pbTarget;
  769. pbNew = DETOURS_PFUNC_TO_PBYTE(pbNew);
  770. DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew));
  771. return pbNew;
  772. }
  773. }
  774. }
  775. }
  776. return pbCode;
  777. }
  778. inline void detour_find_jmp_bounds(PBYTE pbCode,
  779. PDETOUR_TRAMPOLINE *ppLower,
  780. PDETOUR_TRAMPOLINE *ppUpper)
  781. {
  782. // We have to place trampolines within +/- 2GB of code.
  783. ULONG_PTR lo = detour_2gb_below((ULONG_PTR)pbCode);
  784. ULONG_PTR hi = detour_2gb_above((ULONG_PTR)pbCode);
  785. DETOUR_TRACE(("[%p..%p..%p]\n", (PVOID)lo, pbCode, (PVOID)hi));
  786. *ppLower = (PDETOUR_TRAMPOLINE)lo;
  787. *ppUpper = (PDETOUR_TRAMPOLINE)hi;
  788. }
  789. inline BOOL detour_does_code_end_function(PBYTE pbCode)
  790. {
  791. ULONG Opcode = fetch_thumb_opcode(pbCode);
  792. if ((Opcode & 0xffffff87) == 0x4700 || // bx <reg>
  793. (Opcode & 0xf800d000) == 0xf0009000) { // b <imm20>
  794. return TRUE;
  795. }
  796. if ((Opcode & 0xffff8000) == 0xe8bd8000) { // pop {...,pc}
  797. __debugbreak();
  798. return TRUE;
  799. }
  800. if ((Opcode & 0xffffff00) == 0x0000bd00) { // pop {...,pc}
  801. __debugbreak();
  802. return TRUE;
  803. }
  804. return FALSE;
  805. }
  806. inline ULONG detour_is_code_filler(PBYTE pbCode)
  807. {
  808. if (pbCode[0] == 0x00 && pbCode[1] == 0xbf) { // nop.
  809. return 2;
  810. }
  811. if (pbCode[0] == 0x00 && pbCode[1] == 0x00) { // zero-filled padding.
  812. return 2;
  813. }
  814. return 0;
  815. }
  816. #endif // DETOURS_ARM
  817. #ifdef DETOURS_ARM64
  818. struct _DETOUR_TRAMPOLINE
  819. {
  820. // An ARM64 instruction is 4 bytes long.
  821. //
  822. // The overwrite is always composed of 3 instructions (12 bytes) which perform an indirect jump
  823. // using _DETOUR_TRAMPOLINE::pbDetour as the address holding the target location.
  824. //
  825. // Copied instructions can expand.
  826. //
  827. // The scheme using MovImmediate can cause an instruction
  828. // to grow as much as 6 times.
  829. // That would be Bcc or Tbz with a large address space:
  830. // 4 instructions to form immediate
  831. // inverted tbz/bcc
  832. // br
  833. //
  834. // An expansion of 4 is not uncommon -- bl/blr and small address space:
  835. // 3 instructions to form immediate
  836. // br or brl
  837. //
  838. // A theoretical maximum for rbCode is thefore 4*4*6 + 16 = 112 (another 16 for jmp to pbRemain).
  839. //
  840. // With literals, the maximum expansion is 5, including the literals: 4*4*5 + 16 = 96.
  841. //
  842. // The number is rounded up to 128. m_rbScratchDst should match this.
  843. //
  844. BYTE rbCode[128]; // target code + jmp to pbRemain
  845. BYTE cbCode; // size of moved target code.
  846. BYTE cbCodeBreak[3]; // padding to make debugging easier.
  847. BYTE rbRestore[24]; // original target code.
  848. BYTE cbRestore; // size of original target code.
  849. BYTE cbRestoreBreak[3]; // padding to make debugging easier.
  850. _DETOUR_ALIGN rAlign[8]; // instruction alignment array.
  851. PBYTE pbRemain; // first instruction after moved code. [free list]
  852. PBYTE pbDetour; // first instruction of detour function.
  853. };
  854. C_ASSERT(sizeof(_DETOUR_TRAMPOLINE) == 184);
  855. enum {
  856. SIZE_OF_JMP = 12
  857. };
  858. inline ULONG fetch_opcode(PBYTE pbCode)
  859. {
  860. return *(ULONG *)pbCode;
  861. }
  862. inline void write_opcode(PBYTE &pbCode, ULONG Opcode)
  863. {
  864. *(ULONG *)pbCode = Opcode;
  865. pbCode += 4;
  866. }
  867. struct ARM64_INDIRECT_JMP {
  868. struct {
  869. ULONG Rd : 5;
  870. ULONG immhi : 19;
  871. ULONG iop : 5;
  872. ULONG immlo : 2;
  873. ULONG op : 1;
  874. } ardp;
  875. struct {
  876. ULONG Rt : 5;
  877. ULONG Rn : 5;
  878. ULONG imm : 12;
  879. ULONG opc : 2;
  880. ULONG iop1 : 2;
  881. ULONG V : 1;
  882. ULONG iop2 : 3;
  883. ULONG size : 2;
  884. } ldr;
  885. ULONG br;
  886. };
  887. #pragma warning(push)
  888. #pragma warning(disable:4201)
  889. union ARM64_INDIRECT_IMM {
  890. struct {
  891. ULONG64 pad : 12;
  892. ULONG64 adrp_immlo : 2;
  893. ULONG64 adrp_immhi : 19;
  894. };
  895. LONG64 value;
  896. };
  897. #pragma warning(pop)
  898. PBYTE detour_gen_jmp_indirect(BYTE *pbCode, ULONG64 *pbJmpVal)
  899. {
  900. // adrp x17, [jmpval]
  901. // ldr x17, [x17, jmpval]
  902. // br x17
  903. struct ARM64_INDIRECT_JMP *pIndJmp;
  904. union ARM64_INDIRECT_IMM jmpIndAddr;
  905. jmpIndAddr.value = (((LONG64)pbJmpVal) & 0xFFFFFFFFFFFFF000) -
  906. (((LONG64)pbCode) & 0xFFFFFFFFFFFFF000);
  907. pIndJmp = (struct ARM64_INDIRECT_JMP *)pbCode;
  908. pbCode = (BYTE *)(pIndJmp + 1);
  909. pIndJmp->ardp.Rd = 17;
  910. pIndJmp->ardp.immhi = jmpIndAddr.adrp_immhi;
  911. pIndJmp->ardp.iop = 0x10;
  912. pIndJmp->ardp.immlo = jmpIndAddr.adrp_immlo;
  913. pIndJmp->ardp.op = 1;
  914. pIndJmp->ldr.Rt = 17;
  915. pIndJmp->ldr.Rn = 17;
  916. pIndJmp->ldr.imm = (((ULONG64)pbJmpVal) & 0xFFF) / 8;
  917. pIndJmp->ldr.opc = 1;
  918. pIndJmp->ldr.iop1 = 1;
  919. pIndJmp->ldr.V = 0;
  920. pIndJmp->ldr.iop2 = 7;
  921. pIndJmp->ldr.size = 3;
  922. pIndJmp->br = 0xD61F0220;
  923. return pbCode;
  924. }
  925. PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE *ppPool, PBYTE pbJmpVal)
  926. {
  927. PBYTE pbLiteral;
  928. if (ppPool != NULL) {
  929. *ppPool = *ppPool - 8;
  930. pbLiteral = *ppPool;
  931. }
  932. else {
  933. pbLiteral = pbCode + 8;
  934. }
  935. *((PBYTE*&)pbLiteral) = pbJmpVal;
  936. LONG delta = (LONG)(pbLiteral - pbCode);
  937. write_opcode(pbCode, 0x58000011 | ((delta / 4) << 5)); // LDR X17,[PC+n]
  938. write_opcode(pbCode, 0xd61f0000 | (17 << 5)); // BR X17
  939. if (ppPool == NULL) {
  940. pbCode += 8;
  941. }
  942. return pbCode;
  943. }
  944. inline PBYTE detour_gen_brk(PBYTE pbCode, PBYTE pbLimit)
  945. {
  946. while (pbCode < pbLimit) {
  947. write_opcode(pbCode, 0xd4100000 | (0xf000 << 5));
  948. }
  949. return pbCode;
  950. }
  951. inline INT64 detour_sign_extend(UINT64 value, UINT bits)
  952. {
  953. const UINT left = 64 - bits;
  954. const INT64 m1 = -1;
  955. const INT64 wide = (INT64)(value << left);
  956. const INT64 sign = (wide < 0) ? (m1 << left) : 0;
  957. return value | sign;
  958. }
  959. inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals)
  960. {
  961. if (pbCode == NULL) {
  962. return NULL;
  963. }
  964. if (ppGlobals != NULL) {
  965. *ppGlobals = NULL;
  966. }
  967. // Skip over the import jump if there is one.
  968. pbCode = (PBYTE)pbCode;
  969. ULONG Opcode = fetch_opcode(pbCode);
  970. if ((Opcode & 0x9f00001f) == 0x90000010) { // adrp x16, IAT
  971. ULONG Opcode2 = fetch_opcode(pbCode + 4);
  972. if ((Opcode2 & 0xffe003ff) == 0xf9400210) { // ldr x16, [x16, IAT]
  973. ULONG Opcode3 = fetch_opcode(pbCode + 8);
  974. if (Opcode3 == 0xd61f0200) { // br x16
  975. /* https://static.docs.arm.com/ddi0487/bb/DDI0487B_b_armv8_arm.pdf
  976. The ADRP instruction shifts a signed, 21-bit immediate left by 12 bits, adds it to the value of the program counter with
  977. the bottom 12 bits cleared to zero, and then writes the result to a general-purpose register. This permits the
  978. calculation of the address at a 4KB aligned memory region. In conjunction with an ADD (immediate) instruction, or
  979. a Load/Store instruction with a 12-bit immediate offset, this allows for the calculation of, or access to, any address
  980. within +/- 4GB of the current PC.
  981. PC-rel. addressing
  982. This section describes the encoding of the PC-rel. addressing instruction class. The encodings in this section are
  983. decoded from Data Processing -- Immediate on page C4-226.
  984. Add/subtract (immediate)
  985. This section describes the encoding of the Add/subtract (immediate) instruction class. The encodings in this section
  986. are decoded from Data Processing -- Immediate on page C4-226.
  987. Decode fields
  988. Instruction page
  989. op
  990. 0 ADR
  991. 1 ADRP
  992. C6.2.10 ADRP
  993. Form PC-relative address to 4KB page adds an immediate value that is shifted left by 12 bits, to the PC value to
  994. form a PC-relative address, with the bottom 12 bits masked out, and writes the result to the destination register.
  995. ADRP <Xd>, <label>
  996. imm = SignExtend(immhi:immlo:Zeros(12), 64);
  997. 31 30 29 28 27 26 25 24 23 5 4 0
  998. 1 immlo 1 0 0 0 0 immhi Rd
  999. 9 0
  1000. Rd is hardcoded as 0x10 above.
  1001. Immediate is 21 signed bits split into 2 bits and 19 bits, and is scaled by 4K.
  1002. */
  1003. UINT64 const pageLow2 = (Opcode >> 29) & 3;
  1004. UINT64 const pageHigh19 = (Opcode >> 5) & ~(~0ui64 << 19);
  1005. INT64 const page = detour_sign_extend((pageHigh19 << 2) | pageLow2, 21) << 12;
  1006. /* https://static.docs.arm.com/ddi0487/bb/DDI0487B_b_armv8_arm.pdf
  1007. C6.2.101 LDR (immediate)
  1008. Load Register (immediate) loads a word or doubleword from memory and writes it to a register. The address that is
  1009. used for the load is calculated from a base register and an immediate offset.
  1010. The Unsigned offset variant scales the immediate offset value by the size of the value accessed before adding it
  1011. to the base register value.
  1012. Unsigned offset
  1013. 64-bit variant Applies when size == 11.
  1014. 31 30 29 28 27 26 25 24 23 22 21 10 9 5 4 0
  1015. 1 x 1 1 1 0 0 1 0 1 imm12 Rn Rt
  1016. F 9 4 200 10
  1017. That is, two low 5 bit fields are registers, hardcoded as 0x10 and 0x10 << 5 above,
  1018. then unsigned size-unscaled (8) 12-bit offset, then opcode bits 0xF94.
  1019. */
  1020. UINT64 const offset = ((Opcode2 >> 10) & ~(~0ui64 << 12)) << 3;
  1021. PBYTE const pbTarget = (PBYTE)((ULONG64)pbCode & 0xfffffffffffff000ULL) + page + offset;
  1022. if (detour_is_imported(pbCode, pbTarget)) {
  1023. PBYTE pbNew = *(PBYTE *)pbTarget;
  1024. DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew));
  1025. return pbNew;
  1026. }
  1027. }
  1028. }
  1029. }
  1030. return pbCode;
  1031. }
  1032. inline void detour_find_jmp_bounds(PBYTE pbCode,
  1033. PDETOUR_TRAMPOLINE *ppLower,
  1034. PDETOUR_TRAMPOLINE *ppUpper)
  1035. {
  1036. // The encoding used by detour_gen_jmp_indirect actually enables a
  1037. // displacement of +/- 4GiB. In the future, this could be changed to
  1038. // reflect that. For now, just reuse the x86 logic which is plenty.
  1039. ULONG_PTR lo = detour_2gb_below((ULONG_PTR)pbCode);
  1040. ULONG_PTR hi = detour_2gb_above((ULONG_PTR)pbCode);
  1041. DETOUR_TRACE(("[%p..%p..%p]\n", (PVOID)lo, pbCode, (PVOID)hi));
  1042. *ppLower = (PDETOUR_TRAMPOLINE)lo;
  1043. *ppUpper = (PDETOUR_TRAMPOLINE)hi;
  1044. }
  1045. inline BOOL detour_is_code_os_patched(PBYTE pbCode)
  1046. {
  1047. // Identify whether the provided code pointer is a OS patch jump.
  1048. // We can do this by checking if a branch (b <imm26>) is present, and if so,
  1049. // it must be jumping to an HPAT page containing ldr <reg> [PC+PAGE_SIZE-4], br <reg>.
  1050. ULONG Opcode = fetch_opcode(pbCode);
  1051. if ((Opcode & 0xfc000000) != 0x14000000) {
  1052. return FALSE;
  1053. }
  1054. // The branch must be jumping forward if it's going into the HPAT.
  1055. // Check that the sign bit is cleared.
  1056. if ((Opcode & 0x2000000) != 0) {
  1057. return FALSE;
  1058. }
  1059. ULONG Delta = (ULONG)((Opcode & 0x1FFFFFF) * 4);
  1060. PBYTE BranchTarget = pbCode + Delta;
  1061. // Now inspect the opcodes of the code we jumped to in order to determine if it's HPAT.
  1062. ULONG HpatOpcode1 = fetch_opcode(BranchTarget);
  1063. ULONG HpatOpcode2 = fetch_opcode(BranchTarget + 4);
  1064. if (HpatOpcode1 != 0x58008010) { // ldr <reg> [PC+PAGE_SIZE]
  1065. return FALSE;
  1066. }
  1067. if (HpatOpcode2 != 0xd61f0200) { // br <reg>
  1068. return FALSE;
  1069. }
  1070. return TRUE;
  1071. }
  1072. inline BOOL detour_does_code_end_function(PBYTE pbCode)
  1073. {
  1074. ULONG Opcode = fetch_opcode(pbCode);
  1075. // When the OS has patched a function entry point, it will incorrectly
  1076. // appear as though the function is just a single branch instruction.
  1077. if (detour_is_code_os_patched(pbCode)) {
  1078. return FALSE;
  1079. }
  1080. if ((Opcode & 0xffbffc1f) == 0xd61f0000 || // ret/br <reg>
  1081. (Opcode & 0xfc000000) == 0x14000000) { // b <imm26>
  1082. return TRUE;
  1083. }
  1084. return FALSE;
  1085. }
  1086. inline ULONG detour_is_code_filler(PBYTE pbCode)
  1087. {
  1088. if (*(ULONG *)pbCode == 0xd503201f) { // nop.
  1089. return 4;
  1090. }
  1091. if (*(ULONG *)pbCode == 0x00000000) { // zero-filled padding.
  1092. return 4;
  1093. }
  1094. return 0;
  1095. }
  1096. #endif // DETOURS_ARM64
  1097. //////////////////////////////////////////////// Trampoline Memory Management.
  1098. //
  1099. struct DETOUR_REGION
  1100. {
  1101. ULONG dwSignature;
  1102. DETOUR_REGION * pNext; // Next region in list of regions.
  1103. DETOUR_TRAMPOLINE * pFree; // List of free trampolines in this region.
  1104. };
  1105. typedef DETOUR_REGION * PDETOUR_REGION;
  1106. const ULONG DETOUR_REGION_SIGNATURE = 'Rrtd';
  1107. const ULONG DETOUR_REGION_SIZE = 0x10000;
  1108. const ULONG DETOUR_TRAMPOLINES_PER_REGION = (DETOUR_REGION_SIZE
  1109. / sizeof(DETOUR_TRAMPOLINE)) - 1;
  1110. static PDETOUR_REGION s_pRegions = NULL; // List of all regions.
  1111. static PDETOUR_REGION s_pRegion = NULL; // Default region.
  1112. static DWORD detour_writable_trampoline_regions()
  1113. {
  1114. // Mark all of the regions as writable.
  1115. for (PDETOUR_REGION pRegion = s_pRegions; pRegion != NULL; pRegion = pRegion->pNext) {
  1116. DWORD dwOld;
  1117. if (!VirtualProtect(pRegion, DETOUR_REGION_SIZE, PAGE_EXECUTE_READWRITE, &dwOld)) {
  1118. return GetLastError();
  1119. }
  1120. }
  1121. return NO_ERROR;
  1122. }
  1123. static void detour_runnable_trampoline_regions()
  1124. {
  1125. HANDLE hProcess = GetCurrentProcess();
  1126. // Mark all of the regions as executable.
  1127. for (PDETOUR_REGION pRegion = s_pRegions; pRegion != NULL; pRegion = pRegion->pNext) {
  1128. DWORD dwOld;
  1129. VirtualProtect(pRegion, DETOUR_REGION_SIZE, PAGE_EXECUTE_READ, &dwOld);
  1130. FlushInstructionCache(hProcess, pRegion, DETOUR_REGION_SIZE);
  1131. }
  1132. }
  1133. static PBYTE detour_alloc_round_down_to_region(PBYTE pbTry)
  1134. {
  1135. // WinXP64 returns free areas that aren't REGION aligned to 32-bit applications.
  1136. ULONG_PTR extra = ((ULONG_PTR)pbTry) & (DETOUR_REGION_SIZE - 1);
  1137. if (extra != 0) {
  1138. pbTry -= extra;
  1139. }
  1140. return pbTry;
  1141. }
  1142. static PBYTE detour_alloc_round_up_to_region(PBYTE pbTry)
  1143. {
  1144. // WinXP64 returns free areas that aren't REGION aligned to 32-bit applications.
  1145. ULONG_PTR extra = ((ULONG_PTR)pbTry) & (DETOUR_REGION_SIZE - 1);
  1146. if (extra != 0) {
  1147. ULONG_PTR adjust = DETOUR_REGION_SIZE - extra;
  1148. pbTry += adjust;
  1149. }
  1150. return pbTry;
  1151. }
  1152. // Starting at pbLo, try to allocate a memory region, continue until pbHi.
  1153. static PVOID detour_alloc_region_from_lo(PBYTE pbLo, PBYTE pbHi)
  1154. {
  1155. PBYTE pbTry = detour_alloc_round_up_to_region(pbLo);
  1156. DETOUR_TRACE((" Looking for free region in %p..%p from %p:\n", pbLo, pbHi, pbTry));
  1157. for (; pbTry < pbHi;) {
  1158. MEMORY_BASIC_INFORMATION mbi;
  1159. if (pbTry >= s_pSystemRegionLowerBound && pbTry <= s_pSystemRegionUpperBound) {
  1160. // Skip region reserved for system DLLs, but preserve address space entropy.
  1161. pbTry += 0x08000000;
  1162. continue;
  1163. }
  1164. ZeroMemory(&mbi, sizeof(mbi));
  1165. if (!VirtualQuery(pbTry, &mbi, sizeof(mbi))) {
  1166. break;
  1167. }
  1168. DETOUR_TRACE((" Try %p => %p..%p %6lx\n",
  1169. pbTry,
  1170. mbi.BaseAddress,
  1171. (PBYTE)mbi.BaseAddress + mbi.RegionSize - 1,
  1172. mbi.State));
  1173. if (mbi.State == MEM_FREE && mbi.RegionSize >= DETOUR_REGION_SIZE) {
  1174. PVOID pv = VirtualAlloc(pbTry,
  1175. DETOUR_REGION_SIZE,
  1176. MEM_COMMIT|MEM_RESERVE,
  1177. PAGE_EXECUTE_READWRITE);
  1178. if (pv != NULL) {
  1179. return pv;
  1180. }
  1181. else if (GetLastError() == ERROR_DYNAMIC_CODE_BLOCKED) {
  1182. return NULL;
  1183. }
  1184. pbTry += DETOUR_REGION_SIZE;
  1185. }
  1186. else {
  1187. pbTry = detour_alloc_round_up_to_region((PBYTE)mbi.BaseAddress + mbi.RegionSize);
  1188. }
  1189. }
  1190. return NULL;
  1191. }
  1192. // Starting at pbHi, try to allocate a memory region, continue until pbLo.
  1193. static PVOID detour_alloc_region_from_hi(PBYTE pbLo, PBYTE pbHi)
  1194. {
  1195. PBYTE pbTry = detour_alloc_round_down_to_region(pbHi - DETOUR_REGION_SIZE);
  1196. DETOUR_TRACE((" Looking for free region in %p..%p from %p:\n", pbLo, pbHi, pbTry));
  1197. for (; pbTry > pbLo;) {
  1198. MEMORY_BASIC_INFORMATION mbi;
  1199. DETOUR_TRACE((" Try %p\n", pbTry));
  1200. if (pbTry >= s_pSystemRegionLowerBound && pbTry <= s_pSystemRegionUpperBound) {
  1201. // Skip region reserved for system DLLs, but preserve address space entropy.
  1202. pbTry -= 0x08000000;
  1203. continue;
  1204. }
  1205. ZeroMemory(&mbi, sizeof(mbi));
  1206. if (!VirtualQuery(pbTry, &mbi, sizeof(mbi))) {
  1207. break;
  1208. }
  1209. DETOUR_TRACE((" Try %p => %p..%p %6lx\n",
  1210. pbTry,
  1211. mbi.BaseAddress,
  1212. (PBYTE)mbi.BaseAddress + mbi.RegionSize - 1,
  1213. mbi.State));
  1214. if (mbi.State == MEM_FREE && mbi.RegionSize >= DETOUR_REGION_SIZE) {
  1215. PVOID pv = VirtualAlloc(pbTry,
  1216. DETOUR_REGION_SIZE,
  1217. MEM_COMMIT|MEM_RESERVE,
  1218. PAGE_EXECUTE_READWRITE);
  1219. if (pv != NULL) {
  1220. return pv;
  1221. }
  1222. else if (GetLastError() == ERROR_DYNAMIC_CODE_BLOCKED) {
  1223. return NULL;
  1224. }
  1225. pbTry -= DETOUR_REGION_SIZE;
  1226. }
  1227. else {
  1228. pbTry = detour_alloc_round_down_to_region((PBYTE)mbi.AllocationBase
  1229. - DETOUR_REGION_SIZE);
  1230. }
  1231. }
  1232. return NULL;
  1233. }
  1234. static PVOID detour_alloc_trampoline_allocate_new(PBYTE pbTarget,
  1235. PDETOUR_TRAMPOLINE pLo,
  1236. PDETOUR_TRAMPOLINE pHi)
  1237. {
  1238. PVOID pbTry = NULL;
  1239. // NB: We must always also start the search at an offset from pbTarget
  1240. // in order to maintain ASLR entropy.
  1241. #if defined(DETOURS_64BIT)
  1242. // Try looking 1GB below or lower.
  1243. if (pbTry == NULL && pbTarget > (PBYTE)0x40000000) {
  1244. pbTry = detour_alloc_region_from_hi((PBYTE)pLo, pbTarget - 0x40000000);
  1245. }
  1246. // Try looking 1GB above or higher.
  1247. if (pbTry == NULL && pbTarget < (PBYTE)0xffffffff40000000) {
  1248. pbTry = detour_alloc_region_from_lo(pbTarget + 0x40000000, (PBYTE)pHi);
  1249. }
  1250. // Try looking 1GB below or higher.
  1251. if (pbTry == NULL && pbTarget > (PBYTE)0x40000000) {
  1252. pbTry = detour_alloc_region_from_lo(pbTarget - 0x40000000, pbTarget);
  1253. }
  1254. // Try looking 1GB above or lower.
  1255. if (pbTry == NULL && pbTarget < (PBYTE)0xffffffff40000000) {
  1256. pbTry = detour_alloc_region_from_hi(pbTarget, pbTarget + 0x40000000);
  1257. }
  1258. #endif
  1259. // Try anything below.
  1260. if (pbTry == NULL) {
  1261. pbTry = detour_alloc_region_from_hi((PBYTE)pLo, pbTarget);
  1262. }
  1263. // try anything above.
  1264. if (pbTry == NULL) {
  1265. pbTry = detour_alloc_region_from_lo(pbTarget, (PBYTE)pHi);
  1266. }
  1267. return pbTry;
  1268. }
  1269. PVOID WINAPI DetourAllocateRegionWithinJumpBounds(_In_ LPCVOID pbTarget,
  1270. _Out_ PDWORD pcbAllocatedSize)
  1271. {
  1272. PDETOUR_TRAMPOLINE pLo;
  1273. PDETOUR_TRAMPOLINE pHi;
  1274. detour_find_jmp_bounds((PBYTE)pbTarget, &pLo, &pHi);
  1275. PVOID pbNewlyAllocated =
  1276. detour_alloc_trampoline_allocate_new((PBYTE)pbTarget, pLo, pHi);
  1277. if (pbNewlyAllocated == NULL) {
  1278. DETOUR_TRACE(("Couldn't find available memory region!\n"));
  1279. *pcbAllocatedSize = 0;
  1280. return NULL;
  1281. }
  1282. *pcbAllocatedSize = DETOUR_REGION_SIZE;
  1283. return pbNewlyAllocated;
  1284. }
  1285. BOOL WINAPI DetourIsFunctionImported(_In_ PBYTE pbCode,
  1286. _In_ PBYTE pbAddress)
  1287. {
  1288. return detour_is_imported(pbCode, pbAddress);
  1289. }
  1290. static PDETOUR_TRAMPOLINE detour_alloc_trampoline(PBYTE pbTarget)
  1291. {
  1292. // We have to place trampolines within +/- 2GB of target.
  1293. PDETOUR_TRAMPOLINE pLo;
  1294. PDETOUR_TRAMPOLINE pHi;
  1295. detour_find_jmp_bounds(pbTarget, &pLo, &pHi);
  1296. PDETOUR_TRAMPOLINE pTrampoline = NULL;
  1297. // Insure that there is a default region.
  1298. if (s_pRegion == NULL && s_pRegions != NULL) {
  1299. s_pRegion = s_pRegions;
  1300. }
  1301. // First check the default region for an valid free block.
  1302. if (s_pRegion != NULL && s_pRegion->pFree != NULL &&
  1303. s_pRegion->pFree >= pLo && s_pRegion->pFree <= pHi) {
  1304. found_region:
  1305. pTrampoline = s_pRegion->pFree;
  1306. // do a last sanity check on region.
  1307. if (pTrampoline < pLo || pTrampoline > pHi) {
  1308. return NULL;
  1309. }
  1310. s_pRegion->pFree = (PDETOUR_TRAMPOLINE)pTrampoline->pbRemain;
  1311. memset(pTrampoline, 0xcc, sizeof(*pTrampoline));
  1312. return pTrampoline;
  1313. }
  1314. // Then check the existing regions for a valid free block.
  1315. for (s_pRegion = s_pRegions; s_pRegion != NULL; s_pRegion = s_pRegion->pNext) {
  1316. if (s_pRegion != NULL && s_pRegion->pFree != NULL &&
  1317. s_pRegion->pFree >= pLo && s_pRegion->pFree <= pHi) {
  1318. goto found_region;
  1319. }
  1320. }
  1321. // We need to allocate a new region.
  1322. // Round pbTarget down to 64KB block.
  1323. // /RTCc RuntimeChecks breaks PtrToUlong.
  1324. pbTarget = pbTarget - (ULONG)((ULONG_PTR)pbTarget & 0xffff);
  1325. PVOID pbNewlyAllocated =
  1326. detour_alloc_trampoline_allocate_new(pbTarget, pLo, pHi);
  1327. if (pbNewlyAllocated != NULL) {
  1328. s_pRegion = (DETOUR_REGION*)pbNewlyAllocated;
  1329. s_pRegion->dwSignature = DETOUR_REGION_SIGNATURE;
  1330. s_pRegion->pFree = NULL;
  1331. s_pRegion->pNext = s_pRegions;
  1332. s_pRegions = s_pRegion;
  1333. DETOUR_TRACE((" Allocated region %p..%p\n\n",
  1334. s_pRegion, ((PBYTE)s_pRegion) + DETOUR_REGION_SIZE - 1));
  1335. // Put everything but the first trampoline on the free list.
  1336. PBYTE pFree = NULL;
  1337. pTrampoline = ((PDETOUR_TRAMPOLINE)s_pRegion) + 1;
  1338. for (int i = DETOUR_TRAMPOLINES_PER_REGION - 1; i > 1; i--) {
  1339. pTrampoline[i].pbRemain = pFree;
  1340. pFree = (PBYTE)&pTrampoline[i];
  1341. }
  1342. s_pRegion->pFree = (PDETOUR_TRAMPOLINE)pFree;
  1343. goto found_region;
  1344. }
  1345. DETOUR_TRACE(("Couldn't find available memory region!\n"));
  1346. return NULL;
  1347. }
  1348. static void detour_free_trampoline(PDETOUR_TRAMPOLINE pTrampoline)
  1349. {
  1350. PDETOUR_REGION pRegion = (PDETOUR_REGION)
  1351. ((ULONG_PTR)pTrampoline & ~(ULONG_PTR)0xffff);
  1352. memset(pTrampoline, 0, sizeof(*pTrampoline));
  1353. pTrampoline->pbRemain = (PBYTE)pRegion->pFree;
  1354. pRegion->pFree = pTrampoline;
  1355. }
  1356. static BOOL detour_is_region_empty(PDETOUR_REGION pRegion)
  1357. {
  1358. // Stop if the region isn't a region (this would be bad).
  1359. if (pRegion->dwSignature != DETOUR_REGION_SIGNATURE) {
  1360. return FALSE;
  1361. }
  1362. PBYTE pbRegionBeg = (PBYTE)pRegion;
  1363. PBYTE pbRegionLim = pbRegionBeg + DETOUR_REGION_SIZE;
  1364. // Stop if any of the trampolines aren't free.
  1365. PDETOUR_TRAMPOLINE pTrampoline = ((PDETOUR_TRAMPOLINE)pRegion) + 1;
  1366. for (int i = 0; i < DETOUR_TRAMPOLINES_PER_REGION; i++) {
  1367. if (pTrampoline[i].pbRemain != NULL &&
  1368. (pTrampoline[i].pbRemain < pbRegionBeg ||
  1369. pTrampoline[i].pbRemain >= pbRegionLim)) {
  1370. return FALSE;
  1371. }
  1372. }
  1373. // OK, the region is empty.
  1374. return TRUE;
  1375. }
  1376. static void detour_free_unused_trampoline_regions()
  1377. {
  1378. PDETOUR_REGION *ppRegionBase = &s_pRegions;
  1379. PDETOUR_REGION pRegion = s_pRegions;
  1380. while (pRegion != NULL) {
  1381. if (detour_is_region_empty(pRegion)) {
  1382. *ppRegionBase = pRegion->pNext;
  1383. VirtualFree(pRegion, 0, MEM_RELEASE);
  1384. s_pRegion = NULL;
  1385. }
  1386. else {
  1387. ppRegionBase = &pRegion->pNext;
  1388. }
  1389. pRegion = *ppRegionBase;
  1390. }
  1391. }
  1392. ///////////////////////////////////////////////////////// Transaction Structs.
  1393. //
  1394. struct DetourThread
  1395. {
  1396. DetourThread * pNext;
  1397. HANDLE hThread;
  1398. #if !defined(SUNRISE_DETOURS_ALLOCATOR_PROOF_LEGACY)
  1399. static void* operator new(size_t size) noexcept
  1400. {
  1401. return sunrise::client::hooking::detour::storage::allocate(
  1402. sunrise::client::hooking::detour::storage::Kind::thread, size);
  1403. }
  1404. static void operator delete(void* pointer) noexcept
  1405. {
  1406. (void)sunrise::client::hooking::detour::storage::release(
  1407. sunrise::client::hooking::detour::storage::Kind::thread, pointer);
  1408. }
  1409. #endif
  1410. };
  1411. struct DetourOperation
  1412. {
  1413. DetourOperation * pNext;
  1414. BOOL fIsRemove;
  1415. PBYTE * ppbPointer;
  1416. PBYTE pbTarget;
  1417. PDETOUR_TRAMPOLINE pTrampoline;
  1418. ULONG dwPerm;
  1419. #if !defined(SUNRISE_DETOURS_ALLOCATOR_PROOF_LEGACY)
  1420. static void* operator new(size_t size) noexcept
  1421. {
  1422. return sunrise::client::hooking::detour::storage::allocate(
  1423. sunrise::client::hooking::detour::storage::Kind::operation, size);
  1424. }
  1425. static void operator delete(void* pointer) noexcept
  1426. {
  1427. (void)sunrise::client::hooking::detour::storage::release(
  1428. sunrise::client::hooking::detour::storage::Kind::operation, pointer);
  1429. }
  1430. #endif
  1431. };
  1432. #if !defined(SUNRISE_DETOURS_ALLOCATOR_PROOF_LEGACY)
  1433. static_assert(sizeof(DetourThread) <= sunrise::client::hooking::detour::storage::kThreadBytes);
  1434. static_assert(sizeof(DetourOperation) <= sunrise::client::hooking::detour::storage::kOperationBytes);
  1435. static_assert(alignof(DetourThread) <= sunrise::client::hooking::detour::storage::kAlignment);
  1436. static_assert(alignof(DetourOperation) <= sunrise::client::hooking::detour::storage::kAlignment);
  1437. #endif
  1438. static BOOL s_fIgnoreTooSmall = FALSE;
  1439. static BOOL s_fRetainRegions = FALSE;
  1440. static LONG s_nPendingThreadId = 0; // Thread owning pending transaction.
  1441. static LONG s_nPendingError = NO_ERROR;
  1442. static PVOID * s_ppPendingError = NULL;
  1443. static DetourThread * s_pPendingThreads = NULL;
  1444. static DetourOperation * s_pPendingOperations = NULL;
  1445. //////////////////////////////////////////////////////////////////////////////
  1446. //
  1447. PVOID WINAPI DetourCodeFromPointer(_In_ PVOID pPointer,
  1448. _Out_opt_ PVOID *ppGlobals)
  1449. {
  1450. return detour_skip_jmp((PBYTE)pPointer, ppGlobals);
  1451. }
  1452. //////////////////////////////////////////////////////////// Transaction APIs.
  1453. //
  1454. BOOL WINAPI DetourSetIgnoreTooSmall(_In_ BOOL fIgnore)
  1455. {
  1456. BOOL fPrevious = s_fIgnoreTooSmall;
  1457. s_fIgnoreTooSmall = fIgnore;
  1458. return fPrevious;
  1459. }
  1460. BOOL WINAPI DetourSetRetainRegions(_In_ BOOL fRetain)
  1461. {
  1462. BOOL fPrevious = s_fRetainRegions;
  1463. s_fRetainRegions = fRetain;
  1464. return fPrevious;
  1465. }
  1466. PVOID WINAPI DetourSetSystemRegionLowerBound(_In_ PVOID pSystemRegionLowerBound)
  1467. {
  1468. PVOID pPrevious = s_pSystemRegionLowerBound;
  1469. s_pSystemRegionLowerBound = pSystemRegionLowerBound;
  1470. return pPrevious;
  1471. }
  1472. PVOID WINAPI DetourSetSystemRegionUpperBound(_In_ PVOID pSystemRegionUpperBound)
  1473. {
  1474. PVOID pPrevious = s_pSystemRegionUpperBound;
  1475. s_pSystemRegionUpperBound = pSystemRegionUpperBound;
  1476. return pPrevious;
  1477. }
  1478. LONG WINAPI DetourTransactionBegin()
  1479. {
  1480. // Only one transaction is allowed at a time.
  1481. _Benign_race_begin_
  1482. if (s_nPendingThreadId != 0) {
  1483. return ERROR_INVALID_OPERATION;
  1484. }
  1485. _Benign_race_end_
  1486. // Make sure only one thread can start a transaction.
  1487. if (InterlockedCompareExchange(&s_nPendingThreadId, (LONG)GetCurrentThreadId(), 0) != 0) {
  1488. return ERROR_INVALID_OPERATION;
  1489. }
  1490. s_pPendingOperations = NULL;
  1491. s_pPendingThreads = NULL;
  1492. s_ppPendingError = NULL;
  1493. // Make sure the trampoline pages are writable.
  1494. s_nPendingError = detour_writable_trampoline_regions();
  1495. return s_nPendingError;
  1496. }
  1497. LONG WINAPI DetourTransactionAbort()
  1498. {
  1499. if (s_nPendingThreadId != (LONG)GetCurrentThreadId()) {
  1500. return ERROR_INVALID_OPERATION;
  1501. }
  1502. // Restore all of the page permissions.
  1503. for (DetourOperation *o = s_pPendingOperations; o != NULL;) {
  1504. // We don't care if this fails, because the code is still accessible.
  1505. DWORD dwOld;
  1506. VirtualProtect(o->pbTarget, o->pTrampoline->cbRestore,
  1507. o->dwPerm, &dwOld);
  1508. if (!o->fIsRemove) {
  1509. if (o->pTrampoline) {
  1510. detour_free_trampoline(o->pTrampoline);
  1511. o->pTrampoline = NULL;
  1512. }
  1513. }
  1514. DetourOperation *n = o->pNext;
  1515. delete o;
  1516. o = n;
  1517. }
  1518. s_pPendingOperations = NULL;
  1519. // Make sure the trampoline pages are no longer writable.
  1520. detour_runnable_trampoline_regions();
  1521. // Resume any suspended threads.
  1522. for (DetourThread *t = s_pPendingThreads; t != NULL;) {
  1523. // There is nothing we can do if this fails.
  1524. ResumeThread(t->hThread);
  1525. DetourThread *n = t->pNext;
  1526. delete t;
  1527. t = n;
  1528. }
  1529. s_pPendingThreads = NULL;
  1530. s_nPendingThreadId = 0;
  1531. return NO_ERROR;
  1532. }
  1533. LONG WINAPI DetourTransactionCommit()
  1534. {
  1535. return DetourTransactionCommitEx(NULL);
  1536. }
  1537. static BYTE detour_align_from_trampoline(PDETOUR_TRAMPOLINE pTrampoline, BYTE obTrampoline)
  1538. {
  1539. for (LONG n = 0; n < ARRAYSIZE(pTrampoline->rAlign); n++) {
  1540. if (pTrampoline->rAlign[n].obTrampoline == obTrampoline) {
  1541. return pTrampoline->rAlign[n].obTarget;
  1542. }
  1543. }
  1544. return 0;
  1545. }
  1546. static LONG detour_align_from_target(PDETOUR_TRAMPOLINE pTrampoline, LONG obTarget)
  1547. {
  1548. for (LONG n = 0; n < ARRAYSIZE(pTrampoline->rAlign); n++) {
  1549. if (pTrampoline->rAlign[n].obTarget == obTarget) {
  1550. return pTrampoline->rAlign[n].obTrampoline;
  1551. }
  1552. }
  1553. return 0;
  1554. }
  1555. LONG WINAPI DetourTransactionCommitEx(_Out_opt_ PVOID **pppFailedPointer)
  1556. {
  1557. if (pppFailedPointer != NULL) {
  1558. // Used to get the last error.
  1559. *pppFailedPointer = s_ppPendingError;
  1560. }
  1561. if (s_nPendingThreadId != (LONG)GetCurrentThreadId()) {
  1562. return ERROR_INVALID_OPERATION;
  1563. }
  1564. // If any of the pending operations failed, then we abort the whole transaction.
  1565. if (s_nPendingError != NO_ERROR) {
  1566. DETOUR_BREAK();
  1567. DetourTransactionAbort();
  1568. return s_nPendingError;
  1569. }
  1570. // Common variables.
  1571. DetourOperation *o;
  1572. DetourThread *t;
  1573. BOOL freed = FALSE;
  1574. // Insert or remove each of the detours.
  1575. for (o = s_pPendingOperations; o != NULL; o = o->pNext) {
  1576. if (o->fIsRemove) {
  1577. CopyMemory(o->pbTarget,
  1578. o->pTrampoline->rbRestore,
  1579. o->pTrampoline->cbRestore);
  1580. #ifdef DETOURS_IA64
  1581. *o->ppbPointer = (PBYTE)o->pTrampoline->ppldTarget;
  1582. #endif // DETOURS_IA64
  1583. #ifdef DETOURS_X86
  1584. *o->ppbPointer = o->pbTarget;
  1585. #endif // DETOURS_X86
  1586. #ifdef DETOURS_X64
  1587. *o->ppbPointer = o->pbTarget;
  1588. #endif // DETOURS_X64
  1589. #ifdef DETOURS_ARM
  1590. *o->ppbPointer = DETOURS_PBYTE_TO_PFUNC(o->pbTarget);
  1591. #endif // DETOURS_ARM
  1592. #ifdef DETOURS_ARM64
  1593. *o->ppbPointer = o->pbTarget;
  1594. #endif // DETOURS_ARM
  1595. }
  1596. else {
  1597. DETOUR_TRACE(("detours: pbTramp =%p, pbRemain=%p, pbDetour=%p, cbRestore=%u\n",
  1598. o->pTrampoline,
  1599. o->pTrampoline->pbRemain,
  1600. o->pTrampoline->pbDetour,
  1601. o->pTrampoline->cbRestore));
  1602. DETOUR_TRACE(("detours: pbTarget=%p: "
  1603. "%02x %02x %02x %02x "
  1604. "%02x %02x %02x %02x "
  1605. "%02x %02x %02x %02x [before]\n",
  1606. o->pbTarget,
  1607. o->pbTarget[0], o->pbTarget[1], o->pbTarget[2], o->pbTarget[3],
  1608. o->pbTarget[4], o->pbTarget[5], o->pbTarget[6], o->pbTarget[7],
  1609. o->pbTarget[8], o->pbTarget[9], o->pbTarget[10], o->pbTarget[11]));
  1610. #ifdef DETOURS_IA64
  1611. ((DETOUR_IA64_BUNDLE*)o->pbTarget)
  1612. ->SetBrl((UINT64)&o->pTrampoline->bAllocFrame);
  1613. *o->ppbPointer = (PBYTE)&o->pTrampoline->pldTrampoline;
  1614. #endif // DETOURS_IA64
  1615. #ifdef DETOURS_X64
  1616. detour_gen_jmp_indirect(o->pTrampoline->rbCodeIn, &o->pTrampoline->pbDetour);
  1617. PBYTE pbCode = detour_gen_jmp_immediate(o->pbTarget, o->pTrampoline->rbCodeIn);
  1618. pbCode = detour_gen_brk(pbCode, o->pTrampoline->pbRemain);
  1619. *o->ppbPointer = o->pTrampoline->rbCode;
  1620. UNREFERENCED_PARAMETER(pbCode);
  1621. #endif // DETOURS_X64
  1622. #ifdef DETOURS_X86
  1623. PBYTE pbCode = detour_gen_jmp_immediate(o->pbTarget, o->pTrampoline->pbDetour);
  1624. pbCode = detour_gen_brk(pbCode, o->pTrampoline->pbRemain);
  1625. *o->ppbPointer = o->pTrampoline->rbCode;
  1626. UNREFERENCED_PARAMETER(pbCode);
  1627. #endif // DETOURS_X86
  1628. #ifdef DETOURS_ARM
  1629. PBYTE pbCode = detour_gen_jmp_immediate(o->pbTarget, NULL, o->pTrampoline->pbDetour);
  1630. pbCode = detour_gen_brk(pbCode, o->pTrampoline->pbRemain);
  1631. *o->ppbPointer = DETOURS_PBYTE_TO_PFUNC(o->pTrampoline->rbCode);
  1632. UNREFERENCED_PARAMETER(pbCode);
  1633. #endif // DETOURS_ARM
  1634. #ifdef DETOURS_ARM64
  1635. PBYTE pbCode = detour_gen_jmp_indirect(o->pbTarget, (ULONG64*)&(o->pTrampoline->pbDetour));
  1636. pbCode = detour_gen_brk(pbCode, o->pTrampoline->pbRemain);
  1637. *o->ppbPointer = o->pTrampoline->rbCode;
  1638. UNREFERENCED_PARAMETER(pbCode);
  1639. #endif // DETOURS_ARM64
  1640. DETOUR_TRACE(("detours: pbTarget=%p: "
  1641. "%02x %02x %02x %02x "
  1642. "%02x %02x %02x %02x "
  1643. "%02x %02x %02x %02x [after]\n",
  1644. o->pbTarget,
  1645. o->pbTarget[0], o->pbTarget[1], o->pbTarget[2], o->pbTarget[3],
  1646. o->pbTarget[4], o->pbTarget[5], o->pbTarget[6], o->pbTarget[7],
  1647. o->pbTarget[8], o->pbTarget[9], o->pbTarget[10], o->pbTarget[11]));
  1648. DETOUR_TRACE(("detours: pbTramp =%p: "
  1649. "%02x %02x %02x %02x "
  1650. "%02x %02x %02x %02x "
  1651. "%02x %02x %02x %02x\n",
  1652. o->pTrampoline,
  1653. o->pTrampoline->rbCode[0], o->pTrampoline->rbCode[1],
  1654. o->pTrampoline->rbCode[2], o->pTrampoline->rbCode[3],
  1655. o->pTrampoline->rbCode[4], o->pTrampoline->rbCode[5],
  1656. o->pTrampoline->rbCode[6], o->pTrampoline->rbCode[7],
  1657. o->pTrampoline->rbCode[8], o->pTrampoline->rbCode[9],
  1658. o->pTrampoline->rbCode[10], o->pTrampoline->rbCode[11]));
  1659. #ifdef DETOURS_IA64
  1660. DETOUR_TRACE(("\n"));
  1661. DETOUR_TRACE(("detours: &pldTrampoline =%p\n",
  1662. &o->pTrampoline->pldTrampoline));
  1663. DETOUR_TRACE(("detours: &bMovlTargetGp =%p [%p]\n",
  1664. &o->pTrampoline->bMovlTargetGp,
  1665. o->pTrampoline->bMovlTargetGp.GetMovlGp()));
  1666. DETOUR_TRACE(("detours: &rbCode =%p [%p]\n",
  1667. &o->pTrampoline->rbCode,
  1668. ((DETOUR_IA64_BUNDLE&)o->pTrampoline->rbCode).GetBrlTarget()));
  1669. DETOUR_TRACE(("detours: &bBrlRemainEip =%p [%p]\n",
  1670. &o->pTrampoline->bBrlRemainEip,
  1671. o->pTrampoline->bBrlRemainEip.GetBrlTarget()));
  1672. DETOUR_TRACE(("detours: &bMovlDetourGp =%p [%p]\n",
  1673. &o->pTrampoline->bMovlDetourGp,
  1674. o->pTrampoline->bMovlDetourGp.GetMovlGp()));
  1675. DETOUR_TRACE(("detours: &bBrlDetourEip =%p [%p]\n",
  1676. &o->pTrampoline->bCallDetour,
  1677. o->pTrampoline->bCallDetour.GetBrlTarget()));
  1678. DETOUR_TRACE(("detours: pldDetour =%p [%p]\n",
  1679. o->pTrampoline->ppldDetour->EntryPoint,
  1680. o->pTrampoline->ppldDetour->GlobalPointer));
  1681. DETOUR_TRACE(("detours: pldTarget =%p [%p]\n",
  1682. o->pTrampoline->ppldTarget->EntryPoint,
  1683. o->pTrampoline->ppldTarget->GlobalPointer));
  1684. DETOUR_TRACE(("detours: pbRemain =%p\n",
  1685. o->pTrampoline->pbRemain));
  1686. DETOUR_TRACE(("detours: pbDetour =%p\n",
  1687. o->pTrampoline->pbDetour));
  1688. DETOUR_TRACE(("\n"));
  1689. #endif // DETOURS_IA64
  1690. }
  1691. }
  1692. #undef DETOURS_EIP
  1693. #undef DETOURS_CONTEXT_FLAGS
  1694. #ifdef DETOURS_X86
  1695. #define DETOURS_EIP Eip
  1696. #define DETOURS_CONTEXT_FLAGS CONTEXT_CONTROL
  1697. #endif // DETOURS_X86
  1698. #ifdef DETOURS_X64
  1699. #define DETOURS_EIP Rip
  1700. #define DETOURS_CONTEXT_FLAGS (CONTEXT_CONTROL | CONTEXT_INTEGER)
  1701. #endif // DETOURS_X64
  1702. #ifdef DETOURS_IA64
  1703. #define DETOURS_EIP StIIP
  1704. #define DETOURS_CONTEXT_FLAGS CONTEXT_CONTROL
  1705. #endif // DETOURS_IA64
  1706. #ifdef DETOURS_ARM
  1707. #define DETOURS_EIP Pc
  1708. #define DETOURS_CONTEXT_FLAGS CONTEXT_CONTROL
  1709. #endif // DETOURS_ARM
  1710. #ifdef DETOURS_ARM64
  1711. #define DETOURS_EIP Pc
  1712. #define DETOURS_CONTEXT_FLAGS (CONTEXT_CONTROL | CONTEXT_INTEGER)
  1713. #endif // DETOURS_ARM64
  1714. typedef ULONG_PTR DETOURS_EIP_TYPE;
  1715. // Update any suspended threads.
  1716. for (t = s_pPendingThreads; t != NULL; t = t->pNext) {
  1717. CONTEXT cxt;
  1718. cxt.ContextFlags = DETOURS_CONTEXT_FLAGS;
  1719. if (GetThreadContext(t->hThread, &cxt)) {
  1720. for (o = s_pPendingOperations; o != NULL; o = o->pNext) {
  1721. if (o->fIsRemove) {
  1722. if (cxt.DETOURS_EIP >= (DETOURS_EIP_TYPE)(ULONG_PTR)o->pTrampoline &&
  1723. cxt.DETOURS_EIP < (DETOURS_EIP_TYPE)((ULONG_PTR)o->pTrampoline
  1724. + sizeof(*o->pTrampoline))
  1725. ) {
  1726. cxt.DETOURS_EIP = (DETOURS_EIP_TYPE)
  1727. ((ULONG_PTR)o->pbTarget
  1728. + detour_align_from_trampoline(o->pTrampoline,
  1729. (BYTE)(cxt.DETOURS_EIP
  1730. - (DETOURS_EIP_TYPE)(ULONG_PTR)
  1731. o->pTrampoline)));
  1732. SetThreadContext(t->hThread, &cxt);
  1733. }
  1734. }
  1735. else {
  1736. if (cxt.DETOURS_EIP >= (DETOURS_EIP_TYPE)(ULONG_PTR)o->pbTarget &&
  1737. cxt.DETOURS_EIP < (DETOURS_EIP_TYPE)((ULONG_PTR)o->pbTarget
  1738. + o->pTrampoline->cbRestore)
  1739. ) {
  1740. cxt.DETOURS_EIP = (DETOURS_EIP_TYPE)
  1741. ((ULONG_PTR)o->pTrampoline
  1742. + detour_align_from_target(o->pTrampoline,
  1743. (BYTE)(cxt.DETOURS_EIP
  1744. - (DETOURS_EIP_TYPE)(ULONG_PTR)
  1745. o->pbTarget)));
  1746. SetThreadContext(t->hThread, &cxt);
  1747. }
  1748. }
  1749. }
  1750. }
  1751. #undef DETOURS_EIP
  1752. }
  1753. // Restore all of the page permissions and flush the icache.
  1754. HANDLE hProcess = GetCurrentProcess();
  1755. for (o = s_pPendingOperations; o != NULL;) {
  1756. // We don't care if this fails, because the code is still accessible.
  1757. DWORD dwOld;
  1758. VirtualProtect(o->pbTarget, o->pTrampoline->cbRestore, o->dwPerm, &dwOld);
  1759. FlushInstructionCache(hProcess, o->pbTarget, o->pTrampoline->cbRestore);
  1760. if (o->fIsRemove && o->pTrampoline) {
  1761. detour_free_trampoline(o->pTrampoline);
  1762. o->pTrampoline = NULL;
  1763. freed = true;
  1764. }
  1765. DetourOperation *n = o->pNext;
  1766. delete o;
  1767. o = n;
  1768. }
  1769. s_pPendingOperations = NULL;
  1770. // Free any trampoline regions that are now unused.
  1771. if (freed && !s_fRetainRegions) {
  1772. detour_free_unused_trampoline_regions();
  1773. }
  1774. // Make sure the trampoline pages are no longer writable.
  1775. detour_runnable_trampoline_regions();
  1776. // Resume any suspended threads.
  1777. for (t = s_pPendingThreads; t != NULL;) {
  1778. // There is nothing we can do if this fails.
  1779. ResumeThread(t->hThread);
  1780. DetourThread *n = t->pNext;
  1781. delete t;
  1782. t = n;
  1783. }
  1784. s_pPendingThreads = NULL;
  1785. s_nPendingThreadId = 0;
  1786. if (pppFailedPointer != NULL) {
  1787. *pppFailedPointer = s_ppPendingError;
  1788. }
  1789. return s_nPendingError;
  1790. }
  1791. LONG WINAPI DetourUpdateThread(_In_ HANDLE hThread)
  1792. {
  1793. LONG error;
  1794. // If any of the pending operations failed, then we don't need to do this.
  1795. if (s_nPendingError != NO_ERROR) {
  1796. return s_nPendingError;
  1797. }
  1798. // Silently (and safely) drop any attempt to suspend our own thread.
  1799. if (hThread == GetCurrentThread()) {
  1800. return NO_ERROR;
  1801. }
  1802. DetourThread *t = new NOTHROW DetourThread;
  1803. if (t == NULL) {
  1804. error = ERROR_NOT_ENOUGH_MEMORY;
  1805. fail:
  1806. if (t != NULL) {
  1807. delete t;
  1808. t = NULL;
  1809. }
  1810. s_nPendingError = error;
  1811. s_ppPendingError = NULL;
  1812. DETOUR_BREAK();
  1813. return error;
  1814. }
  1815. if (SuspendThread(hThread) == (DWORD)-1) {
  1816. error = GetLastError();
  1817. DETOUR_BREAK();
  1818. goto fail;
  1819. }
  1820. t->hThread = hThread;
  1821. t->pNext = s_pPendingThreads;
  1822. s_pPendingThreads = t;
  1823. return NO_ERROR;
  1824. }
  1825. ///////////////////////////////////////////////////////////// Transacted APIs.
  1826. //
  1827. LONG WINAPI DetourAttach(_Inout_ PVOID *ppPointer,
  1828. _In_ PVOID pDetour)
  1829. {
  1830. return DetourAttachEx(ppPointer, pDetour, NULL, NULL, NULL);
  1831. }
  1832. LONG WINAPI DetourAttachEx(_Inout_ PVOID *ppPointer,
  1833. _In_ PVOID pDetour,
  1834. _Out_opt_ PDETOUR_TRAMPOLINE *ppRealTrampoline,
  1835. _Out_opt_ PVOID *ppRealTarget,
  1836. _Out_opt_ PVOID *ppRealDetour)
  1837. {
  1838. LONG error = NO_ERROR;
  1839. if (ppRealTrampoline != NULL) {
  1840. *ppRealTrampoline = NULL;
  1841. }
  1842. if (ppRealTarget != NULL) {
  1843. *ppRealTarget = NULL;
  1844. }
  1845. if (ppRealDetour != NULL) {
  1846. *ppRealDetour = NULL;
  1847. }
  1848. if (pDetour == NULL) {
  1849. DETOUR_TRACE(("empty detour\n"));
  1850. return ERROR_INVALID_PARAMETER;
  1851. }
  1852. if (s_nPendingThreadId != (LONG)GetCurrentThreadId()) {
  1853. DETOUR_TRACE(("transaction conflict with thread id=%ld\n", s_nPendingThreadId));
  1854. return ERROR_INVALID_OPERATION;
  1855. }
  1856. // If any of the pending operations failed, then we don't need to do this.
  1857. if (s_nPendingError != NO_ERROR) {
  1858. DETOUR_TRACE(("pending transaction error=%ld\n", s_nPendingError));
  1859. return s_nPendingError;
  1860. }
  1861. if (ppPointer == NULL) {
  1862. DETOUR_TRACE(("ppPointer is null\n"));
  1863. return ERROR_INVALID_HANDLE;
  1864. }
  1865. if (*ppPointer == NULL) {
  1866. error = ERROR_INVALID_HANDLE;
  1867. s_nPendingError = error;
  1868. s_ppPendingError = ppPointer;
  1869. DETOUR_TRACE(("*ppPointer is null (ppPointer=%p)\n", ppPointer));
  1870. DETOUR_BREAK();
  1871. return error;
  1872. }
  1873. PBYTE pbTarget = (PBYTE)*ppPointer;
  1874. PDETOUR_TRAMPOLINE pTrampoline = NULL;
  1875. DetourOperation *o = NULL;
  1876. #ifdef DETOURS_IA64
  1877. PPLABEL_DESCRIPTOR ppldDetour = (PPLABEL_DESCRIPTOR)pDetour;
  1878. PPLABEL_DESCRIPTOR ppldTarget = (PPLABEL_DESCRIPTOR)pbTarget;
  1879. PVOID pDetourGlobals = NULL;
  1880. PVOID pTargetGlobals = NULL;
  1881. pDetour = (PBYTE)DetourCodeFromPointer(ppldDetour, &pDetourGlobals);
  1882. pbTarget = (PBYTE)DetourCodeFromPointer(ppldTarget, &pTargetGlobals);
  1883. DETOUR_TRACE((" ppldDetour=%p, code=%p [gp=%p]\n",
  1884. ppldDetour, pDetour, pDetourGlobals));
  1885. DETOUR_TRACE((" ppldTarget=%p, code=%p [gp=%p]\n",
  1886. ppldTarget, pbTarget, pTargetGlobals));
  1887. #else // DETOURS_IA64
  1888. #if defined(_M_ARM64EC)
  1889. if (RtlIsEcCode(reinterpret_cast<DWORD64>(*ppPointer))) {
  1890. DETOUR_TRACE(("*ppPointer is an Arm64EC address (ppPointer=%p). "
  1891. "An Arm64EC address cannot be legitimately detoured with an x64 jmp. "
  1892. "Mark the target function with __declspec(hybrid_patchable) to make it detour-able. "
  1893. "We still allow an Arm64EC function to be detoured with an x64 jmp to make it easy (crash) to debug.\n", ppPointer));
  1894. DETOUR_BREAK();
  1895. }
  1896. #endif
  1897. pbTarget = (PBYTE)DetourCodeFromPointer(pbTarget, NULL);
  1898. pDetour = DetourCodeFromPointer(pDetour, NULL);
  1899. #endif // !DETOURS_IA64
  1900. // Don't follow a jump if its destination is the target function.
  1901. // This happens when the detour does nothing other than call the target.
  1902. if (pDetour == (PVOID)pbTarget) {
  1903. if (s_fIgnoreTooSmall) {
  1904. goto stop;
  1905. }
  1906. else {
  1907. DETOUR_BREAK();
  1908. goto fail;
  1909. }
  1910. }
  1911. if (ppRealTarget != NULL) {
  1912. *ppRealTarget = pbTarget;
  1913. }
  1914. if (ppRealDetour != NULL) {
  1915. *ppRealDetour = pDetour;
  1916. }
  1917. o = new NOTHROW DetourOperation;
  1918. if (o == NULL) {
  1919. error = ERROR_NOT_ENOUGH_MEMORY;
  1920. fail:
  1921. s_nPendingError = error;
  1922. DETOUR_BREAK();
  1923. stop:
  1924. if (pTrampoline != NULL) {
  1925. detour_free_trampoline(pTrampoline);
  1926. pTrampoline = NULL;
  1927. if (ppRealTrampoline != NULL) {
  1928. *ppRealTrampoline = NULL;
  1929. }
  1930. }
  1931. if (o != NULL) {
  1932. delete o;
  1933. o = NULL;
  1934. }
  1935. if (ppRealDetour != NULL) {
  1936. *ppRealDetour = NULL;
  1937. }
  1938. if (ppRealTarget != NULL) {
  1939. *ppRealTarget = NULL;
  1940. }
  1941. s_ppPendingError = ppPointer;
  1942. return error;
  1943. }
  1944. pTrampoline = detour_alloc_trampoline(pbTarget);
  1945. if (pTrampoline == NULL) {
  1946. error = ERROR_NOT_ENOUGH_MEMORY;
  1947. DETOUR_BREAK();
  1948. goto fail;
  1949. }
  1950. if (ppRealTrampoline != NULL) {
  1951. *ppRealTrampoline = pTrampoline;
  1952. }
  1953. DETOUR_TRACE(("detours: pbTramp=%p, pDetour=%p\n", pTrampoline, pDetour));
  1954. memset(pTrampoline->rAlign, 0, sizeof(pTrampoline->rAlign));
  1955. // Determine the number of movable target instructions.
  1956. PBYTE pbSrc = pbTarget;
  1957. PBYTE pbTrampoline = pTrampoline->rbCode;
  1958. #ifdef DETOURS_IA64
  1959. PBYTE pbPool = (PBYTE)(&pTrampoline->bBranchIslands + 1);
  1960. #else
  1961. PBYTE pbPool = pbTrampoline + sizeof(pTrampoline->rbCode);
  1962. #endif
  1963. ULONG cbTarget = 0;
  1964. ULONG cbJump = SIZE_OF_JMP;
  1965. ULONG nAlign = 0;
  1966. #ifdef DETOURS_ARM
  1967. // On ARM, we need an extra instruction when the function isn't 32-bit aligned.
  1968. // Check if the existing code is another detour (or at least a similar
  1969. // "ldr pc, [PC+0]" jump.
  1970. if ((ULONG)pbTarget & 2) {
  1971. cbJump += 2;
  1972. ULONG op = fetch_thumb_opcode(pbSrc);
  1973. if (op == 0xbf00) {
  1974. op = fetch_thumb_opcode(pbSrc + 2);
  1975. if (op == 0xf8dff000) { // LDR PC,[PC]
  1976. *((PUSHORT&)pbTrampoline)++ = *((PUSHORT&)pbSrc)++;
  1977. *((PULONG&)pbTrampoline)++ = *((PULONG&)pbSrc)++;
  1978. *((PULONG&)pbTrampoline)++ = *((PULONG&)pbSrc)++;
  1979. cbTarget = (LONG)(pbSrc - pbTarget);
  1980. // We will fall through the "while" because cbTarget is now >= cbJump.
  1981. }
  1982. }
  1983. }
  1984. else {
  1985. ULONG op = fetch_thumb_opcode(pbSrc);
  1986. if (op == 0xf8dff000) { // LDR PC,[PC]
  1987. *((PULONG&)pbTrampoline)++ = *((PULONG&)pbSrc)++;
  1988. *((PULONG&)pbTrampoline)++ = *((PULONG&)pbSrc)++;
  1989. cbTarget = (LONG)(pbSrc - pbTarget);
  1990. // We will fall through the "while" because cbTarget is now >= cbJump.
  1991. }
  1992. }
  1993. #endif
  1994. while (cbTarget < cbJump) {
  1995. PBYTE pbOp = pbSrc;
  1996. LONG lExtra = 0;
  1997. DETOUR_TRACE((" DetourCopyInstruction(%p,%p)\n",
  1998. pbTrampoline, pbSrc));
  1999. pbSrc = (PBYTE)
  2000. DetourCopyInstruction(pbTrampoline, (PVOID*)&pbPool, pbSrc, NULL, &lExtra);
  2001. DETOUR_TRACE((" DetourCopyInstruction() = %p (%d bytes)\n",
  2002. pbSrc, (int)(pbSrc - pbOp)));
  2003. pbTrampoline += (pbSrc - pbOp) + lExtra;
  2004. cbTarget = (LONG)(pbSrc - pbTarget);
  2005. pTrampoline->rAlign[nAlign].obTarget = cbTarget;
  2006. pTrampoline->rAlign[nAlign].obTrampoline = pbTrampoline - pTrampoline->rbCode;
  2007. nAlign++;
  2008. if (nAlign >= ARRAYSIZE(pTrampoline->rAlign)) {
  2009. break;
  2010. }
  2011. if (detour_does_code_end_function(pbOp)) {
  2012. break;
  2013. }
  2014. }
  2015. // Consume, but don't duplicate padding if it is needed and available.
  2016. while (cbTarget < cbJump) {
  2017. LONG cFiller = detour_is_code_filler(pbSrc);
  2018. if (cFiller == 0) {
  2019. break;
  2020. }
  2021. pbSrc += cFiller;
  2022. cbTarget = (LONG)(pbSrc - pbTarget);
  2023. }
  2024. #if DETOUR_DEBUG
  2025. {
  2026. DETOUR_TRACE((" detours: rAlign ["));
  2027. LONG n = 0;
  2028. for (n = 0; n < ARRAYSIZE(pTrampoline->rAlign); n++) {
  2029. if (pTrampoline->rAlign[n].obTarget == 0 &&
  2030. pTrampoline->rAlign[n].obTrampoline == 0) {
  2031. break;
  2032. }
  2033. DETOUR_TRACE((" %u/%u",
  2034. pTrampoline->rAlign[n].obTarget,
  2035. pTrampoline->rAlign[n].obTrampoline
  2036. ));
  2037. }
  2038. DETOUR_TRACE((" ]\n"));
  2039. }
  2040. #endif
  2041. if (cbTarget < cbJump || nAlign > ARRAYSIZE(pTrampoline->rAlign)) {
  2042. // Too few instructions.
  2043. error = ERROR_INVALID_BLOCK;
  2044. if (s_fIgnoreTooSmall) {
  2045. goto stop;
  2046. }
  2047. else {
  2048. DETOUR_BREAK();
  2049. goto fail;
  2050. }
  2051. }
  2052. if (pbTrampoline > pbPool) {
  2053. __debugbreak();
  2054. }
  2055. pTrampoline->cbCode = (BYTE)(pbTrampoline - pTrampoline->rbCode);
  2056. pTrampoline->cbRestore = (BYTE)cbTarget;
  2057. CopyMemory(pTrampoline->rbRestore, pbTarget, cbTarget);
  2058. #if !defined(DETOURS_IA64)
  2059. if (cbTarget > sizeof(pTrampoline->rbCode) - cbJump) {
  2060. // Too many instructions.
  2061. error = ERROR_INVALID_HANDLE;
  2062. DETOUR_BREAK();
  2063. goto fail;
  2064. }
  2065. #endif // !DETOURS_IA64
  2066. pTrampoline->pbRemain = pbTarget + cbTarget;
  2067. pTrampoline->pbDetour = (PBYTE)pDetour;
  2068. #ifdef DETOURS_IA64
  2069. pTrampoline->ppldDetour = ppldDetour;
  2070. pTrampoline->ppldTarget = ppldTarget;
  2071. pTrampoline->pldTrampoline.EntryPoint = (UINT64)&pTrampoline->bMovlTargetGp;
  2072. pTrampoline->pldTrampoline.GlobalPointer = (UINT64)pDetourGlobals;
  2073. ((DETOUR_IA64_BUNDLE *)pTrampoline->rbCode)->SetStop();
  2074. pTrampoline->bMovlTargetGp.SetMovlGp((UINT64)pTargetGlobals);
  2075. pTrampoline->bBrlRemainEip.SetBrl((UINT64)pTrampoline->pbRemain);
  2076. // Alloc frame: alloc r41=ar.pfs,11,0,8,0; mov r40=rp
  2077. pTrampoline->bAllocFrame.wide[0] = 0x00000580164d480c;
  2078. pTrampoline->bAllocFrame.wide[1] = 0x00c4000500000200;
  2079. // save r36, r37, r38.
  2080. pTrampoline->bSave37to39.wide[0] = 0x031021004e019001;
  2081. pTrampoline->bSave37to39.wide[1] = 0x8401280600420098;
  2082. // save r34,r35,r36: adds r47=0,r36; adds r46=0,r35; adds r45=0,r34
  2083. pTrampoline->bSave34to36.wide[0] = 0x02e0210048017800;
  2084. pTrampoline->bSave34to36.wide[1] = 0x84011005a042008c;
  2085. // save gp,r32,r33" adds r44=0,r33; adds r43=0,r32; adds r42=0,gp ;;
  2086. pTrampoline->bSaveGPto33.wide[0] = 0x02b0210042016001;
  2087. pTrampoline->bSaveGPto33.wide[1] = 0x8400080540420080;
  2088. // set detour GP.
  2089. pTrampoline->bMovlDetourGp.SetMovlGp((UINT64)pDetourGlobals);
  2090. // call detour: brl.call.sptk.few rp=detour ;;
  2091. pTrampoline->bCallDetour.wide[0] = 0x0000000100000005;
  2092. pTrampoline->bCallDetour.wide[1] = 0xd000001000000000;
  2093. pTrampoline->bCallDetour.SetBrlTarget((UINT64)pDetour);
  2094. // pop frame & gp: adds gp=0,r42; mov rp=r40,+0;; mov.i ar.pfs=r41
  2095. pTrampoline->bPopFrameGp.wide[0] = 0x4000210054000802;
  2096. pTrampoline->bPopFrameGp.wide[1] = 0x00aa029000038005;
  2097. // return to caller: br.ret.sptk.many rp ;;
  2098. pTrampoline->bReturn.wide[0] = 0x0000000100000019;
  2099. pTrampoline->bReturn.wide[1] = 0x0084000880000200;
  2100. DETOUR_TRACE(("detours: &bMovlTargetGp=%p\n", &pTrampoline->bMovlTargetGp));
  2101. DETOUR_TRACE(("detours: &bMovlDetourGp=%p\n", &pTrampoline->bMovlDetourGp));
  2102. #endif // DETOURS_IA64
  2103. pbTrampoline = pTrampoline->rbCode + pTrampoline->cbCode;
  2104. #ifdef DETOURS_X64
  2105. pbTrampoline = detour_gen_jmp_indirect(pbTrampoline, &pTrampoline->pbRemain);
  2106. pbTrampoline = detour_gen_brk(pbTrampoline, pbPool);
  2107. #endif // DETOURS_X64
  2108. #ifdef DETOURS_X86
  2109. pbTrampoline = detour_gen_jmp_immediate(pbTrampoline, pTrampoline->pbRemain);
  2110. pbTrampoline = detour_gen_brk(pbTrampoline, pbPool);
  2111. #endif // DETOURS_X86
  2112. #ifdef DETOURS_ARM
  2113. pbTrampoline = detour_gen_jmp_immediate(pbTrampoline, &pbPool, pTrampoline->pbRemain);
  2114. pbTrampoline = detour_gen_brk(pbTrampoline, pbPool);
  2115. #endif // DETOURS_ARM
  2116. #ifdef DETOURS_ARM64
  2117. pbTrampoline = detour_gen_jmp_immediate(pbTrampoline, &pbPool, pTrampoline->pbRemain);
  2118. pbTrampoline = detour_gen_brk(pbTrampoline, pbPool);
  2119. #endif // DETOURS_ARM64
  2120. (void)pbTrampoline;
  2121. DWORD dwOld = 0;
  2122. if (!VirtualProtect(pbTarget, cbTarget, PAGE_EXECUTE_READWRITE, &dwOld)) {
  2123. error = GetLastError();
  2124. DETOUR_BREAK();
  2125. goto fail;
  2126. }
  2127. DETOUR_TRACE(("detours: pbTarget=%p: "
  2128. "%02x %02x %02x %02x "
  2129. "%02x %02x %02x %02x "
  2130. "%02x %02x %02x %02x\n",
  2131. pbTarget,
  2132. pbTarget[0], pbTarget[1], pbTarget[2], pbTarget[3],
  2133. pbTarget[4], pbTarget[5], pbTarget[6], pbTarget[7],
  2134. pbTarget[8], pbTarget[9], pbTarget[10], pbTarget[11]));
  2135. DETOUR_TRACE(("detours: pbTramp =%p: "
  2136. "%02x %02x %02x %02x "
  2137. "%02x %02x %02x %02x "
  2138. "%02x %02x %02x %02x\n",
  2139. pTrampoline,
  2140. pTrampoline->rbCode[0], pTrampoline->rbCode[1],
  2141. pTrampoline->rbCode[2], pTrampoline->rbCode[3],
  2142. pTrampoline->rbCode[4], pTrampoline->rbCode[5],
  2143. pTrampoline->rbCode[6], pTrampoline->rbCode[7],
  2144. pTrampoline->rbCode[8], pTrampoline->rbCode[9],
  2145. pTrampoline->rbCode[10], pTrampoline->rbCode[11]));
  2146. o->fIsRemove = FALSE;
  2147. o->ppbPointer = (PBYTE*)ppPointer;
  2148. o->pTrampoline = pTrampoline;
  2149. o->pbTarget = pbTarget;
  2150. o->dwPerm = dwOld;
  2151. o->pNext = s_pPendingOperations;
  2152. s_pPendingOperations = o;
  2153. return NO_ERROR;
  2154. }
  2155. LONG WINAPI DetourDetach(_Inout_ PVOID *ppPointer,
  2156. _In_ PVOID pDetour)
  2157. {
  2158. LONG error = NO_ERROR;
  2159. if (s_nPendingThreadId != (LONG)GetCurrentThreadId()) {
  2160. return ERROR_INVALID_OPERATION;
  2161. }
  2162. // If any of the pending operations failed, then we don't need to do this.
  2163. if (s_nPendingError != NO_ERROR) {
  2164. return s_nPendingError;
  2165. }
  2166. if (pDetour == NULL) {
  2167. return ERROR_INVALID_PARAMETER;
  2168. }
  2169. if (ppPointer == NULL) {
  2170. return ERROR_INVALID_HANDLE;
  2171. }
  2172. if (*ppPointer == NULL) {
  2173. error = ERROR_INVALID_HANDLE;
  2174. s_nPendingError = error;
  2175. s_ppPendingError = ppPointer;
  2176. DETOUR_BREAK();
  2177. return error;
  2178. }
  2179. DetourOperation *o = new NOTHROW DetourOperation;
  2180. if (o == NULL) {
  2181. error = ERROR_NOT_ENOUGH_MEMORY;
  2182. fail:
  2183. s_nPendingError = error;
  2184. DETOUR_BREAK();
  2185. stop:
  2186. if (o != NULL) {
  2187. delete o;
  2188. o = NULL;
  2189. }
  2190. s_ppPendingError = ppPointer;
  2191. return error;
  2192. }
  2193. #ifdef DETOURS_IA64
  2194. PPLABEL_DESCRIPTOR ppldTrampo = (PPLABEL_DESCRIPTOR)*ppPointer;
  2195. PPLABEL_DESCRIPTOR ppldDetour = (PPLABEL_DESCRIPTOR)pDetour;
  2196. PVOID pDetourGlobals = NULL;
  2197. PVOID pTrampoGlobals = NULL;
  2198. pDetour = (PBYTE)DetourCodeFromPointer(ppldDetour, &pDetourGlobals);
  2199. PDETOUR_TRAMPOLINE pTrampoline = (PDETOUR_TRAMPOLINE)
  2200. DetourCodeFromPointer(ppldTrampo, &pTrampoGlobals);
  2201. DETOUR_TRACE((" ppldDetour=%p, code=%p [gp=%p]\n",
  2202. ppldDetour, pDetour, pDetourGlobals));
  2203. DETOUR_TRACE((" ppldTrampo=%p, code=%p [gp=%p]\n",
  2204. ppldTrampo, pTrampoline, pTrampoGlobals));
  2205. DETOUR_TRACE(("\n"));
  2206. DETOUR_TRACE(("detours: &pldTrampoline =%p\n",
  2207. &pTrampoline->pldTrampoline));
  2208. DETOUR_TRACE(("detours: &bMovlTargetGp =%p [%p]\n",
  2209. &pTrampoline->bMovlTargetGp,
  2210. pTrampoline->bMovlTargetGp.GetMovlGp()));
  2211. DETOUR_TRACE(("detours: &rbCode =%p [%p]\n",
  2212. &pTrampoline->rbCode,
  2213. ((DETOUR_IA64_BUNDLE&)pTrampoline->rbCode).GetBrlTarget()));
  2214. DETOUR_TRACE(("detours: &bBrlRemainEip =%p [%p]\n",
  2215. &pTrampoline->bBrlRemainEip,
  2216. pTrampoline->bBrlRemainEip.GetBrlTarget()));
  2217. DETOUR_TRACE(("detours: &bMovlDetourGp =%p [%p]\n",
  2218. &pTrampoline->bMovlDetourGp,
  2219. pTrampoline->bMovlDetourGp.GetMovlGp()));
  2220. DETOUR_TRACE(("detours: &bBrlDetourEip =%p [%p]\n",
  2221. &pTrampoline->bCallDetour,
  2222. pTrampoline->bCallDetour.GetBrlTarget()));
  2223. DETOUR_TRACE(("detours: pldDetour =%p [%p]\n",
  2224. pTrampoline->ppldDetour->EntryPoint,
  2225. pTrampoline->ppldDetour->GlobalPointer));
  2226. DETOUR_TRACE(("detours: pldTarget =%p [%p]\n",
  2227. pTrampoline->ppldTarget->EntryPoint,
  2228. pTrampoline->ppldTarget->GlobalPointer));
  2229. DETOUR_TRACE(("detours: pbRemain =%p\n",
  2230. pTrampoline->pbRemain));
  2231. DETOUR_TRACE(("detours: pbDetour =%p\n",
  2232. pTrampoline->pbDetour));
  2233. DETOUR_TRACE(("\n"));
  2234. #else // !DETOURS_IA64
  2235. PDETOUR_TRAMPOLINE pTrampoline =
  2236. (PDETOUR_TRAMPOLINE)DetourCodeFromPointer(*ppPointer, NULL);
  2237. pDetour = DetourCodeFromPointer(pDetour, NULL);
  2238. #endif // !DETOURS_IA64
  2239. ////////////////////////////////////// Verify that Trampoline is in place.
  2240. //
  2241. LONG cbTarget = pTrampoline->cbRestore;
  2242. PBYTE pbTarget = pTrampoline->pbRemain - cbTarget;
  2243. if (cbTarget == 0 || cbTarget > sizeof(pTrampoline->rbCode)) {
  2244. error = ERROR_INVALID_BLOCK;
  2245. if (s_fIgnoreTooSmall) {
  2246. goto stop;
  2247. }
  2248. else {
  2249. DETOUR_BREAK();
  2250. goto fail;
  2251. }
  2252. }
  2253. if (pTrampoline->pbDetour != pDetour) {
  2254. error = ERROR_INVALID_BLOCK;
  2255. if (s_fIgnoreTooSmall) {
  2256. goto stop;
  2257. }
  2258. else {
  2259. DETOUR_BREAK();
  2260. goto fail;
  2261. }
  2262. }
  2263. DWORD dwOld = 0;
  2264. if (!VirtualProtect(pbTarget, cbTarget,
  2265. PAGE_EXECUTE_READWRITE, &dwOld)) {
  2266. error = GetLastError();
  2267. DETOUR_BREAK();
  2268. goto fail;
  2269. }
  2270. o->fIsRemove = TRUE;
  2271. o->ppbPointer = (PBYTE*)ppPointer;
  2272. o->pTrampoline = pTrampoline;
  2273. o->pbTarget = pbTarget;
  2274. o->dwPerm = dwOld;
  2275. o->pNext = s_pPendingOperations;
  2276. s_pPendingOperations = o;
  2277. return NO_ERROR;
  2278. }
  2279. //////////////////////////////////////////////////////////////////////////////
  2280. //
  2281. // Helpers for manipulating page protection.
  2282. //
  2283. // For reference:
  2284. // PAGE_NOACCESS 0x01
  2285. // PAGE_READONLY 0x02
  2286. // PAGE_READWRITE 0x04
  2287. // PAGE_WRITECOPY 0x08
  2288. // PAGE_EXECUTE 0x10
  2289. // PAGE_EXECUTE_READ 0x20
  2290. // PAGE_EXECUTE_READWRITE 0x40
  2291. // PAGE_EXECUTE_WRITECOPY 0x80
  2292. // PAGE_GUARD ...
  2293. // PAGE_NOCACHE ...
  2294. // PAGE_WRITECOMBINE ...
  2295. #define DETOUR_PAGE_EXECUTE_ALL (PAGE_EXECUTE | \
  2296. PAGE_EXECUTE_READ | \
  2297. PAGE_EXECUTE_READWRITE | \
  2298. PAGE_EXECUTE_WRITECOPY)
  2299. #define DETOUR_PAGE_NO_EXECUTE_ALL (PAGE_NOACCESS | \
  2300. PAGE_READONLY | \
  2301. PAGE_READWRITE | \
  2302. PAGE_WRITECOPY)
  2303. #define DETOUR_PAGE_ATTRIBUTES (~(DETOUR_PAGE_EXECUTE_ALL | DETOUR_PAGE_NO_EXECUTE_ALL))
  2304. C_ASSERT((DETOUR_PAGE_NO_EXECUTE_ALL << 4) == DETOUR_PAGE_EXECUTE_ALL);
  2305. static DWORD DetourPageProtectAdjustExecute(_In_ DWORD dwOldProtect,
  2306. _In_ DWORD dwNewProtect)
  2307. // Copy EXECUTE from dwOldProtect to dwNewProtect.
  2308. {
  2309. bool const fOldExecute = ((dwOldProtect & DETOUR_PAGE_EXECUTE_ALL) != 0);
  2310. bool const fNewExecute = ((dwNewProtect & DETOUR_PAGE_EXECUTE_ALL) != 0);
  2311. if (fOldExecute && !fNewExecute) {
  2312. dwNewProtect = ((dwNewProtect & DETOUR_PAGE_NO_EXECUTE_ALL) << 4)
  2313. | (dwNewProtect & DETOUR_PAGE_ATTRIBUTES);
  2314. }
  2315. else if (!fOldExecute && fNewExecute) {
  2316. dwNewProtect = ((dwNewProtect & DETOUR_PAGE_EXECUTE_ALL) >> 4)
  2317. | (dwNewProtect & DETOUR_PAGE_ATTRIBUTES);
  2318. }
  2319. return dwNewProtect;
  2320. }
  2321. _Success_(return != FALSE)
  2322. BOOL WINAPI DetourVirtualProtectSameExecuteEx(_In_ HANDLE hProcess,
  2323. _In_ PVOID pAddress,
  2324. _In_ SIZE_T nSize,
  2325. _In_ DWORD dwNewProtect,
  2326. _Out_ PDWORD pdwOldProtect)
  2327. // Some systems do not allow executability of a page to change. This function applies
  2328. // dwNewProtect to [pAddress, nSize), but preserving the previous executability.
  2329. // This function is meant to be a drop-in replacement for some uses of VirtualProtectEx.
  2330. // When "restoring" page protection, there is no need to use this function.
  2331. {
  2332. MEMORY_BASIC_INFORMATION mbi;
  2333. // Query to get existing execute access.
  2334. ZeroMemory(&mbi, sizeof(mbi));
  2335. if (VirtualQueryEx(hProcess, pAddress, &mbi, sizeof(mbi)) == 0) {
  2336. return FALSE;
  2337. }
  2338. return VirtualProtectEx(hProcess, pAddress, nSize,
  2339. DetourPageProtectAdjustExecute(mbi.Protect, dwNewProtect),
  2340. pdwOldProtect);
  2341. }
  2342. _Success_(return != FALSE)
  2343. BOOL WINAPI DetourVirtualProtectSameExecute(_In_ PVOID pAddress,
  2344. _In_ SIZE_T nSize,
  2345. _In_ DWORD dwNewProtect,
  2346. _Out_ PDWORD pdwOldProtect)
  2347. {
  2348. return DetourVirtualProtectSameExecuteEx(GetCurrentProcess(),
  2349. pAddress, nSize, dwNewProtect, pdwOldProtect);
  2350. }
  2351. BOOL WINAPI DetourAreSameGuid(_In_ REFGUID left, _In_ REFGUID right)
  2352. {
  2353. return
  2354. left.Data1 == right.Data1 &&
  2355. left.Data2 == right.Data2 &&
  2356. left.Data3 == right.Data3 &&
  2357. left.Data4[0] == right.Data4[0] &&
  2358. left.Data4[1] == right.Data4[1] &&
  2359. left.Data4[2] == right.Data4[2] &&
  2360. left.Data4[3] == right.Data4[3] &&
  2361. left.Data4[4] == right.Data4[4] &&
  2362. left.Data4[5] == right.Data4[5] &&
  2363. left.Data4[6] == right.Data4[6] &&
  2364. left.Data4[7] == right.Data4[7];
  2365. }
  2366. // End of File