detours.cpp 91 KB

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