Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

834 lines
22 KiB

  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Module: detours.lib
  4. // File: detours.cpp
  5. // Author: Galen Hunt
  6. //
  7. // Detours for binary functions. Version 1.2. (Build 35)
  8. //
  9. // Copyright 1995-1999, Microsoft Corporation
  10. //
  11. // http://research.microsoft.com/sn/detours
  12. //
  13. //#include <ole2.h>
  14. #include "stdafx.h"
  15. #include <imagehlp.h>
  16. //////////////////////////////////////////////////////////////////////////////
  17. //
  18. enum {
  19. OP_JMP_DS = 0x25,
  20. OP_JA = 0x77,
  21. OP_NOP = 0x90,
  22. OP_CALL = 0xe8,
  23. OP_JMP = 0xe9,
  24. OP_PREFIX = 0xff,
  25. OP_MOV_EAX = 0xa1,
  26. OP_SET_EAX = 0xb8,
  27. OP_JMP_EAX = 0xe0,
  28. OP_RET_POP = 0xc2,
  29. OP_RET = 0xc3,
  30. OP_BRK = 0xcc,
  31. SIZE_OF_JMP = 5,
  32. SIZE_OF_NOP = 1,
  33. SIZE_OF_BRK = 1,
  34. SIZE_OF_TRP_OPS = SIZE_OF_JMP /* + SIZE_OF_BRK */,
  35. };
  36. class CEnableWriteOnCodePage
  37. {
  38. public:
  39. CEnableWriteOnCodePage(PBYTE pbCode, LONG cbCode = DETOUR_TRAMPOLINE_SIZE)
  40. {
  41. m_pbCode = pbCode;
  42. m_cbCode = cbCode;
  43. m_dwOldPerm = 0;
  44. m_hProcess = GetCurrentProcess();
  45. if (m_pbCode && m_cbCode) {
  46. if (!FlushInstructionCache(m_hProcess, pbCode, cbCode)) {
  47. return;
  48. }
  49. if (!VirtualProtect(pbCode,
  50. cbCode,
  51. PAGE_EXECUTE_READWRITE,
  52. &m_dwOldPerm)) {
  53. return;
  54. }
  55. }
  56. }
  57. ~CEnableWriteOnCodePage()
  58. {
  59. if (m_dwOldPerm && m_pbCode && m_cbCode) {
  60. DWORD dwTemp = 0;
  61. if (!FlushInstructionCache(m_hProcess, m_pbCode, m_cbCode)) {
  62. return;
  63. }
  64. if (!VirtualProtect(m_pbCode, m_cbCode, m_dwOldPerm, &dwTemp)) {
  65. return;
  66. }
  67. }
  68. }
  69. BOOL SetPermission(DWORD dwPerms)
  70. {
  71. if (m_dwOldPerm && m_pbCode && m_cbCode) {
  72. m_dwOldPerm = dwPerms;
  73. return TRUE;
  74. }
  75. return FALSE;
  76. }
  77. BOOL IsValid(VOID)
  78. {
  79. return m_pbCode && m_cbCode && m_dwOldPerm;
  80. }
  81. private:
  82. HANDLE m_hProcess;
  83. PBYTE m_pbCode;
  84. LONG m_cbCode;
  85. DWORD m_dwOldPerm;
  86. };
  87. //////////////////////////////////////////////////////////////////////////////
  88. //
  89. static BOOL detour_insert_jump(PBYTE pbCode, PBYTE pbDest, LONG cbCode)
  90. {
  91. if (cbCode < SIZE_OF_JMP)
  92. return FALSE;
  93. *pbCode++ = OP_JMP;
  94. LONG offset = (LONG)pbDest - (LONG)(pbCode + 4);
  95. *((PDWORD&)pbCode)++ = offset;
  96. for (cbCode -= SIZE_OF_JMP; cbCode > 0; cbCode--)
  97. *pbCode++ = OP_BRK;
  98. return TRUE;
  99. }
  100. static BOOL detour_insert_detour(PBYTE pbTarget,
  101. PBYTE pbTrampoline,
  102. PBYTE pbDetour)
  103. {
  104. if (pbTarget[0] == OP_NOP)
  105. return FALSE;
  106. if (pbTarget[0] == OP_JMP) // Already has a detour.
  107. return FALSE;
  108. PBYTE pbCont = pbTarget;
  109. for (LONG cbTarget = 0; cbTarget < SIZE_OF_TRP_OPS;) {
  110. BYTE bOp = *pbCont;
  111. pbCont = DetourCopyInstruction(NULL, pbCont, NULL);
  112. cbTarget = pbCont - pbTarget;
  113. if (bOp == OP_JMP ||
  114. bOp == OP_JMP_DS ||
  115. bOp == OP_JMP_EAX ||
  116. bOp == OP_RET_POP ||
  117. bOp == OP_RET) {
  118. break;
  119. }
  120. }
  121. if (cbTarget < SIZE_OF_TRP_OPS) {
  122. // Too few instructions.
  123. return FALSE;
  124. }
  125. if (cbTarget > (DETOUR_TRAMPOLINE_SIZE - SIZE_OF_JMP - SIZE_OF_NOP - 1)) {
  126. // Too many instructions.
  127. return FALSE;
  128. }
  129. //////////////////////////////////////////////////////// Finalize Reroute.
  130. //
  131. CEnableWriteOnCodePage ewTrampoline(pbTrampoline, DETOUR_TRAMPOLINE_SIZE);
  132. CEnableWriteOnCodePage ewTarget(pbTarget, cbTarget);
  133. if (!ewTrampoline.SetPermission(PAGE_EXECUTE_READWRITE))
  134. return FALSE;
  135. if (!ewTarget.IsValid())
  136. return FALSE;
  137. pbTrampoline[0] = OP_NOP;
  138. PBYTE pbSrc = pbTarget;
  139. PBYTE pbDst = pbTrampoline + SIZE_OF_NOP;
  140. for (LONG cbCopy = 0; cbCopy < cbTarget;) {
  141. pbSrc = DetourCopyInstruction(pbDst, pbSrc, NULL);
  142. cbCopy = pbSrc - pbTarget;
  143. pbDst = pbTrampoline + SIZE_OF_NOP + cbCopy;
  144. }
  145. if (cbCopy != cbTarget) // Count came out different!
  146. return FALSE;
  147. pbCont = pbTarget + cbTarget;
  148. if (!detour_insert_jump(pbTrampoline + 1 + cbTarget, pbCont, SIZE_OF_JMP))
  149. return FALSE;
  150. pbTrampoline[DETOUR_TRAMPOLINE_SIZE-1] = (BYTE)cbTarget;
  151. if (!detour_insert_jump(pbTarget, pbDetour, cbTarget))
  152. return FALSE;
  153. return TRUE;
  154. }
  155. //////////////////////////////////////////////////////////////////////////////
  156. //
  157. BOOL WINAPI DetourRemoveWithTrampoline(PBYTE pbTrampoline,
  158. PBYTE pbDetour)
  159. {
  160. pbTrampoline = DetourFindFinalCode(pbTrampoline);
  161. pbDetour = DetourFindFinalCode(pbDetour);
  162. ////////////////////////////////////// Verify that Trampoline is in place.
  163. //
  164. if (pbTrampoline[0] != OP_NOP) {
  165. SetLastError(ERROR_INVALID_HANDLE);
  166. return FALSE;
  167. }
  168. LONG cbTarget = pbTrampoline[DETOUR_TRAMPOLINE_SIZE-1];
  169. if (cbTarget == 0 || cbTarget >= DETOUR_TRAMPOLINE_SIZE - 1) {
  170. SetLastError(ERROR_INVALID_HANDLE);
  171. return FALSE;
  172. }
  173. if (pbTrampoline[cbTarget + SIZE_OF_NOP] != OP_JMP) {
  174. SetLastError(ERROR_INVALID_HANDLE);
  175. return FALSE;
  176. }
  177. LONG offset = *((PDWORD)&pbTrampoline[cbTarget + SIZE_OF_NOP + 1]);
  178. PBYTE pbTarget = pbTrampoline +
  179. SIZE_OF_NOP + cbTarget + SIZE_OF_JMP + offset - cbTarget;
  180. if (pbTarget[0] != OP_JMP) { // Missing detour.
  181. SetLastError(ERROR_INVALID_BLOCK);
  182. return FALSE;
  183. }
  184. offset = *((PDWORD)&pbTarget[1]);
  185. PBYTE pbTargetDetour = pbTarget + SIZE_OF_JMP + offset;
  186. if (pbTargetDetour != pbDetour) {
  187. SetLastError(ERROR_INVALID_ACCESS);
  188. return FALSE;
  189. }
  190. /////////////////////////////////////////////////////// Remove the Detour.
  191. CEnableWriteOnCodePage ewTarget(pbTarget, cbTarget);
  192. PBYTE pbSrc = pbTrampoline + SIZE_OF_NOP;
  193. PBYTE pbDst = pbTarget;
  194. for (LONG cbCopy = 0; cbCopy < cbTarget; pbDst = pbTarget + cbCopy) {
  195. pbSrc = DetourCopyInstruction(pbDst, pbSrc, NULL);
  196. cbCopy = pbSrc - (pbTrampoline + SIZE_OF_NOP);
  197. }
  198. if (cbCopy != cbTarget) { // Count came out different!
  199. SetLastError(ERROR_INVALID_DATA);
  200. return FALSE;
  201. }
  202. return TRUE;
  203. }
  204. PBYTE WINAPI DetourFunction(PBYTE pbTarget,
  205. PBYTE pbDetour)
  206. {
  207. PBYTE pbTrampoline = new BYTE [DETOUR_TRAMPOLINE_SIZE];
  208. if (pbTrampoline == NULL)
  209. return NULL;
  210. pbTarget = DetourFindFinalCode(pbTarget);
  211. pbDetour = DetourFindFinalCode(pbDetour);
  212. if (detour_insert_detour(pbTarget, pbTrampoline, pbDetour))
  213. return pbTrampoline;
  214. delete[] pbTrampoline;
  215. return NULL;
  216. }
  217. BOOL WINAPI DetourFunctionWithEmptyTrampoline(PBYTE pbTrampoline,
  218. PBYTE pbTarget,
  219. PBYTE pbDetour)
  220. {
  221. return DetourFunctionWithEmptyTrampolineEx(pbTrampoline, pbTarget, pbDetour,
  222. NULL, NULL, NULL);
  223. }
  224. BOOL WINAPI DetourFunctionWithEmptyTrampolineEx(PBYTE pbTrampoline,
  225. PBYTE pbTarget,
  226. PBYTE pbDetour,
  227. PBYTE *ppbRealTrampoline,
  228. PBYTE *ppbRealTarget,
  229. PBYTE *ppbRealDetour)
  230. {
  231. pbTrampoline = DetourFindFinalCode(pbTrampoline);
  232. pbTarget = DetourFindFinalCode(pbTarget);
  233. pbDetour = DetourFindFinalCode(pbDetour);
  234. if (ppbRealTrampoline)
  235. *ppbRealTrampoline = pbTrampoline;
  236. if (ppbRealTarget)
  237. *ppbRealTarget = pbTarget;
  238. if (ppbRealDetour)
  239. *ppbRealDetour = pbDetour;
  240. if (pbTrampoline == NULL || pbDetour == NULL || pbTarget == NULL)
  241. return FALSE;
  242. if (pbTrampoline[0] == OP_NOP && pbTrampoline[1] != OP_NOP) {
  243. // Already Patched.
  244. return 2;
  245. }
  246. if (pbTrampoline[0] != OP_NOP ||
  247. pbTrampoline[1] != OP_NOP) {
  248. return FALSE;
  249. }
  250. return detour_insert_detour(pbTarget, pbTrampoline, pbDetour);
  251. }
  252. BOOL WINAPI DetourFunctionWithTrampoline(PBYTE pbTrampoline,
  253. PBYTE pbDetour)
  254. {
  255. return DetourFunctionWithTrampolineEx(pbTrampoline, pbDetour, NULL, NULL);
  256. }
  257. BOOL WINAPI DetourFunctionWithTrampolineEx(PBYTE pbTrampoline,
  258. PBYTE pbDetour,
  259. PBYTE *ppbRealTrampoline,
  260. PBYTE *ppbRealTarget)
  261. {
  262. PBYTE pbTarget = NULL;
  263. pbTrampoline = DetourFindFinalCode(pbTrampoline);
  264. pbDetour = DetourFindFinalCode(pbDetour);
  265. if (ppbRealTrampoline)
  266. *ppbRealTrampoline = pbTrampoline;
  267. if (ppbRealTarget)
  268. *ppbRealTarget = NULL;
  269. if (pbTrampoline == NULL || pbDetour == NULL)
  270. return FALSE;
  271. if (pbTrampoline[0] == OP_NOP && pbTrampoline[1] != OP_NOP) {
  272. // Already Patched.
  273. return 2;
  274. }
  275. if (pbTrampoline[0] != OP_NOP ||
  276. pbTrampoline[1] != OP_NOP ||
  277. pbTrampoline[2] != OP_CALL ||
  278. pbTrampoline[7] != OP_PREFIX ||
  279. pbTrampoline[8] != OP_JMP_EAX) {
  280. return FALSE;
  281. }
  282. PVOID (__fastcall * pfAddr)(VOID);
  283. pfAddr = (PVOID (__fastcall *)(VOID))(pbTrampoline +
  284. SIZE_OF_NOP + SIZE_OF_NOP + SIZE_OF_JMP +
  285. *(LONG *)&pbTrampoline[3]);
  286. pbTarget = DetourFindFinalCode((PBYTE)(*pfAddr)());
  287. if (ppbRealTarget)
  288. *ppbRealTarget = pbTarget;
  289. return detour_insert_detour(pbTarget, pbTrampoline, pbDetour);
  290. }
  291. //////////////////////////////////////////////////////////////////////////////
  292. //////////////////////////////////////////////////////////////////////////////
  293. //////////////////////////////////////////////////////////////////////////////
  294. //////////////////////////////////////////////////////////////////////////////
  295. //
  296. //////////////////////////////////////////////////////////////////////////////
  297. //
  298. typedef LPAPI_VERSION (NTAPI *PF_ImagehlpApiVersionEx)(LPAPI_VERSION AppVersion);
  299. typedef BOOL (NTAPI *PF_SymInitialize)(IN HANDLE hProcess,
  300. IN LPSTR UserSearchPath,
  301. IN BOOL fInvadeProcess);
  302. typedef DWORD (NTAPI *PF_SymSetOptions)(IN DWORD SymOptions);
  303. typedef DWORD (NTAPI *PF_SymGetOptions)(VOID);
  304. typedef BOOL (NTAPI *PF_SymLoadModule)(IN HANDLE hProcess,
  305. IN HANDLE hFile,
  306. IN PSTR ImageName,
  307. IN PSTR ModuleName,
  308. IN DWORD BaseOfDll,
  309. IN DWORD SizeOfDll);
  310. typedef BOOL (NTAPI *PF_SymGetModuleInfo)(IN HANDLE hProcess,
  311. IN DWORD dwAddr,
  312. OUT PIMAGEHLP_MODULE ModuleInfo);
  313. typedef BOOL (NTAPI *PF_SymGetSymFromName)(IN HANDLE hProcess,
  314. IN LPSTR Name,
  315. OUT PIMAGEHLP_SYMBOL Symbol);
  316. typedef BOOL (NTAPI *PF_BindImage)(IN LPSTR pszImageName,
  317. IN LPSTR pszDllPath,
  318. IN LPSTR pszSymbolPath);
  319. static HANDLE s_hProcess = NULL;
  320. static HINSTANCE s_hImageHlp = NULL;
  321. static PF_ImagehlpApiVersionEx s_pfImagehlpApiVersionEx = NULL;
  322. static PF_SymInitialize s_pfSymInitialize = NULL;
  323. static PF_SymSetOptions s_pfSymSetOptions = NULL;
  324. static PF_SymGetOptions s_pfSymGetOptions = NULL;
  325. static PF_SymLoadModule s_pfSymLoadModule = NULL;
  326. static PF_SymGetModuleInfo s_pfSymGetModuleInfo = NULL;
  327. static PF_SymGetSymFromName s_pfSymGetSymFromName = NULL;
  328. static PF_BindImage s_pfBindImage = NULL;
  329. static BOOL LoadImageHlp(VOID)
  330. {
  331. if (s_hImageHlp)
  332. return TRUE;
  333. if (s_hProcess == NULL) {
  334. s_hProcess = GetCurrentProcess();
  335. s_hImageHlp = LoadLibraryA("imagehlp.dll");
  336. if (s_hImageHlp == NULL)
  337. return FALSE;
  338. s_pfImagehlpApiVersionEx
  339. = (PF_ImagehlpApiVersionEx)GetProcAddress(s_hImageHlp,
  340. "ImagehlpApiVersionEx");
  341. s_pfSymInitialize
  342. = (PF_SymInitialize)GetProcAddress(s_hImageHlp, "SymInitialize");
  343. s_pfSymSetOptions
  344. = (PF_SymSetOptions)GetProcAddress(s_hImageHlp, "SymSetOptions");
  345. s_pfSymGetOptions
  346. = (PF_SymGetOptions)GetProcAddress(s_hImageHlp, "SymGetOptions");
  347. s_pfSymLoadModule
  348. = (PF_SymLoadModule)GetProcAddress(s_hImageHlp, "SymLoadModule");
  349. s_pfSymGetModuleInfo
  350. = (PF_SymGetModuleInfo)GetProcAddress(s_hImageHlp, "SymGetModuleInfo");
  351. s_pfSymGetSymFromName
  352. = (PF_SymGetSymFromName)GetProcAddress(s_hImageHlp, "SymGetSymFromName");
  353. s_pfBindImage
  354. = (PF_BindImage)GetProcAddress(s_hImageHlp, "BindImage");
  355. API_VERSION av;
  356. ZeroMemory(&av, sizeof(av));
  357. av.MajorVersion = API_VERSION_NUMBER;
  358. if (s_pfImagehlpApiVersionEx) {
  359. (*s_pfImagehlpApiVersionEx)(&av);
  360. }
  361. if (s_pfImagehlpApiVersionEx == NULL || av.MajorVersion < API_VERSION_NUMBER) {
  362. FreeLibrary(s_hImageHlp);
  363. s_hImageHlp = NULL;
  364. return FALSE;
  365. }
  366. if (s_pfSymInitialize) {
  367. (*s_pfSymInitialize)(s_hProcess, NULL, FALSE);
  368. }
  369. if (s_pfSymGetOptions && s_pfSymSetOptions) {
  370. DWORD dw = (*s_pfSymGetOptions)();
  371. dw &= (SYMOPT_CASE_INSENSITIVE | SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS);
  372. (*s_pfSymSetOptions)(dw);
  373. }
  374. return TRUE;
  375. }
  376. return FALSE;
  377. }
  378. //////////////////////////////////////////////////////////////////////////////
  379. //
  380. PBYTE WINAPI DetourFindFinalCode(PBYTE pbCode)
  381. {
  382. if (pbCode == NULL)
  383. return NULL;
  384. //BUGBUG PBYTE pbTemp = pbCode;
  385. if (pbCode[0] == OP_JMP) { // Reference passed.
  386. pbCode = pbCode + SIZE_OF_JMP + *(LONG *)&pbCode[1];
  387. }
  388. else if (pbCode[0] == OP_PREFIX && pbCode[1] == OP_JMP_DS) {
  389. pbCode = *(PBYTE *)&pbCode[2];
  390. pbCode = *(PBYTE *)pbCode;
  391. }
  392. return pbCode;
  393. }
  394. PBYTE WINAPI DetourFindFunction(PCHAR pszModule, PCHAR pszFunction)
  395. {
  396. /////////////////////////////////////////////// First, Try GetProcAddress.
  397. //
  398. HINSTANCE hInst = LoadLibraryA(pszModule);
  399. if (hInst == NULL) {
  400. return NULL;
  401. }
  402. PBYTE pbCode = (PBYTE)GetProcAddress(hInst, pszFunction);
  403. if (pbCode) {
  404. return pbCode;
  405. }
  406. ////////////////////////////////////////////////////// Then Try ImageHelp.
  407. //
  408. if (!LoadImageHlp() ||
  409. s_pfSymLoadModule == NULL ||
  410. s_pfSymGetModuleInfo == NULL ||
  411. s_pfSymGetSymFromName == NULL) {
  412. return NULL;
  413. }
  414. (*s_pfSymLoadModule)(s_hProcess, NULL, pszModule, NULL, (DWORD)hInst, 0);
  415. IMAGEHLP_MODULE modinfo;
  416. ZeroMemory(&modinfo, sizeof(modinfo));
  417. if (!(*s_pfSymGetModuleInfo)(s_hProcess, (DWORD)hInst, &modinfo)) {
  418. return NULL;
  419. }
  420. CHAR szFullName[512];
  421. strcpy(szFullName, modinfo.ModuleName);
  422. strcat(szFullName, "!");
  423. strcat(szFullName, pszFunction);
  424. //BUGBUG DWORD nDisplacement = 0;
  425. struct CFullSymbol : IMAGEHLP_SYMBOL {
  426. CHAR szRestOfName[512];
  427. } symbol;
  428. ZeroMemory(&symbol, sizeof(symbol));
  429. symbol.SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
  430. symbol.MaxNameLength = sizeof(symbol.szRestOfName)/sizeof(0);
  431. if (!(*s_pfSymGetSymFromName)(s_hProcess, szFullName, &symbol)) {
  432. return NULL;
  433. }
  434. return (PBYTE)symbol.Address;
  435. }
  436. //////////////////////////////////////////////////// Instance Image Functions.
  437. //
  438. HINSTANCE WINAPI DetourEnumerateInstances(HINSTANCE hinstLast)
  439. {
  440. PBYTE pbLast;
  441. if (hinstLast == NULL) {
  442. pbLast = (PBYTE)0x10000;
  443. }
  444. else {
  445. pbLast = (PBYTE)hinstLast + 0x10000;
  446. }
  447. MEMORY_BASIC_INFORMATION mbi;
  448. ZeroMemory(&mbi, sizeof(mbi));
  449. for (;; pbLast = (PBYTE)mbi.BaseAddress + mbi.RegionSize) {
  450. if (VirtualQuery((PVOID)pbLast, &mbi, sizeof(mbi)) <= 0) {
  451. return NULL;
  452. }
  453. if (mbi.State != MEM_COMMIT)
  454. continue;
  455. __try {
  456. PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pbLast;
  457. if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
  458. continue;
  459. }
  460. PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +
  461. pDosHeader->e_lfanew);
  462. if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
  463. continue;
  464. }
  465. return (HINSTANCE)pDosHeader;
  466. } __except(EXCEPTION_EXECUTE_HANDLER) {
  467. /* nothing. */
  468. }
  469. }
  470. return NULL;
  471. }
  472. PBYTE WINAPI DetourFindEntryPointForInstance(HINSTANCE hInst)
  473. {
  474. PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hInst;
  475. if (hInst == NULL) {
  476. pDosHeader = (PIMAGE_DOS_HEADER)GetModuleHandle(NULL);
  477. }
  478. __try {
  479. if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
  480. SetLastError(ERROR_BAD_EXE_FORMAT);
  481. return NULL;
  482. }
  483. PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +
  484. pDosHeader->e_lfanew);
  485. if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
  486. SetLastError(ERROR_INVALID_EXE_SIGNATURE);
  487. return NULL;
  488. }
  489. if (pNtHeader->FileHeader.SizeOfOptionalHeader == 0) {
  490. SetLastError(ERROR_EXE_MARKED_INVALID);
  491. return NULL;
  492. }
  493. return (PBYTE)pNtHeader->OptionalHeader.AddressOfEntryPoint +
  494. pNtHeader->OptionalHeader.ImageBase;
  495. } __except(EXCEPTION_EXECUTE_HANDLER) {
  496. }
  497. SetLastError(ERROR_EXE_MARKED_INVALID);
  498. return NULL;
  499. }
  500. static inline PBYTE RvaAdjust(HINSTANCE hInst, DWORD raddr)
  501. {
  502. if (raddr != NULL) {
  503. return (PBYTE)hInst + raddr;
  504. }
  505. return NULL;
  506. }
  507. BOOL WINAPI DetourEnumerateExportsForInstance(HINSTANCE hInst,
  508. PVOID pContext,
  509. PF_DETOUR_BINARY_EXPORT_CALLBACK pfExport)
  510. {
  511. PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hInst;
  512. if (hInst == NULL) {
  513. pDosHeader = (PIMAGE_DOS_HEADER)GetModuleHandle(NULL);
  514. }
  515. __try {
  516. if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
  517. SetLastError(ERROR_BAD_EXE_FORMAT);
  518. return NULL;
  519. }
  520. PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +
  521. pDosHeader->e_lfanew);
  522. if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
  523. SetLastError(ERROR_INVALID_EXE_SIGNATURE);
  524. return FALSE;
  525. }
  526. if (pNtHeader->FileHeader.SizeOfOptionalHeader == 0) {
  527. SetLastError(ERROR_EXE_MARKED_INVALID);
  528. return FALSE;
  529. }
  530. PIMAGE_EXPORT_DIRECTORY pExportDir
  531. = (PIMAGE_EXPORT_DIRECTORY)
  532. RvaAdjust(hInst,
  533. pNtHeader->OptionalHeader
  534. .DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
  535. //BUGBUG ULONG cbExportDir = pNtHeader->OptionalHeader
  536. //BUGBUG .DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
  537. if (pExportDir == NULL) {
  538. SetLastError(ERROR_EXE_MARKED_INVALID);
  539. return FALSE;
  540. }
  541. //BUGBUG PCHAR pszName = (PCHAR)RvaAdjust(hInst, pExportDir->Name);
  542. PDWORD pdwFunctions = (PDWORD)RvaAdjust(hInst, pExportDir->AddressOfFunctions);
  543. PDWORD pdwNames = (PDWORD)RvaAdjust(hInst, pExportDir->AddressOfNames);
  544. PWORD pwOrdinals = (PWORD)RvaAdjust(hInst, pExportDir->AddressOfNameOrdinals);
  545. for (DWORD nFunc = 0; nFunc < pExportDir->NumberOfFunctions; nFunc++) {
  546. PBYTE pbCode = (PBYTE)RvaAdjust(hInst, pdwFunctions[nFunc]);
  547. PCHAR pszName = (nFunc < pExportDir->NumberOfNames) ?
  548. (PCHAR)RvaAdjust(hInst, pdwNames[nFunc]) : NULL;
  549. ULONG nOrdinal = pExportDir->Base + pwOrdinals[nFunc];
  550. if (!(*pfExport)(pContext, nOrdinal, pszName, pbCode)) {
  551. break;
  552. }
  553. }
  554. SetLastError(NO_ERROR);
  555. return TRUE;
  556. } __except(EXCEPTION_EXECUTE_HANDLER) {
  557. }
  558. SetLastError(ERROR_EXE_MARKED_INVALID);
  559. return FALSE;
  560. }
  561. PDETOUR_LOADED_BINARY WINAPI DetourBinaryFromInstance(HINSTANCE hInst)
  562. {
  563. PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hInst;
  564. if (hInst == NULL) {
  565. pDosHeader = (PIMAGE_DOS_HEADER)GetModuleHandle(NULL);
  566. }
  567. __try {
  568. if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
  569. SetLastError(ERROR_BAD_EXE_FORMAT);
  570. return NULL;
  571. }
  572. PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +
  573. pDosHeader->e_lfanew);
  574. if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
  575. SetLastError(ERROR_INVALID_EXE_SIGNATURE);
  576. return NULL;
  577. }
  578. if (pNtHeader->FileHeader.SizeOfOptionalHeader == 0) {
  579. SetLastError(ERROR_EXE_MARKED_INVALID);
  580. return NULL;
  581. }
  582. PIMAGE_SECTION_HEADER pSectionHeaders
  583. = (PIMAGE_SECTION_HEADER)((PBYTE)pNtHeader
  584. + sizeof(pNtHeader->Signature)
  585. + sizeof(pNtHeader->FileHeader)
  586. + pNtHeader->FileHeader.SizeOfOptionalHeader);
  587. for (DWORD n = 0; n < pNtHeader->FileHeader.NumberOfSections; n++) {
  588. if (strcmp((PCHAR)pSectionHeaders[n].Name, ".detour") == 0) {
  589. if (pSectionHeaders[n].VirtualAddress == 0 ||
  590. pSectionHeaders[n].SizeOfRawData == 0) {
  591. break;
  592. }
  593. PBYTE pbData = (PBYTE)pDosHeader + pSectionHeaders[n].VirtualAddress;
  594. DETOUR_SECTION_HEADER *pHeader = (DETOUR_SECTION_HEADER *)pbData;
  595. if (pHeader->cbHeaderSize < sizeof(DETOUR_SECTION_HEADER) ||
  596. pHeader->nSignature != DETOUR_SECTION_HEADER_SIGNATURE) {
  597. break;
  598. }
  599. if (pHeader->nDataOffset == 0) {
  600. pHeader->nDataOffset = pHeader->cbHeaderSize;
  601. }
  602. return (PBYTE)pHeader;
  603. }
  604. }
  605. } __except(EXCEPTION_EXECUTE_HANDLER) {
  606. }
  607. SetLastError(ERROR_EXE_MARKED_INVALID);
  608. return NULL;
  609. }
  610. DWORD WINAPI DetourGetSizeOfBinary(PDETOUR_LOADED_BINARY pBinary)
  611. {
  612. __try {
  613. DETOUR_SECTION_HEADER *pHeader = (DETOUR_SECTION_HEADER *)pBinary;
  614. if (pHeader->cbHeaderSize < sizeof(DETOUR_SECTION_HEADER) ||
  615. pHeader->nSignature != DETOUR_SECTION_HEADER_SIGNATURE) {
  616. SetLastError(ERROR_INVALID_HANDLE);
  617. return 0;
  618. }
  619. return pHeader->cbDataSize;
  620. } __except(EXCEPTION_EXECUTE_HANDLER) {
  621. SetLastError(ERROR_INVALID_HANDLE);
  622. return 0;
  623. }
  624. SetLastError(ERROR_INVALID_HANDLE);
  625. return 0;
  626. }
  627. PBYTE WINAPI DetourFindPayloadInBinary(PDETOUR_LOADED_BINARY pBinary,
  628. REFGUID rguid,
  629. DWORD * pcbData)
  630. {
  631. PBYTE pbData = NULL;
  632. //BUGBUG DWORD cbData = 0;
  633. if (pcbData) {
  634. *pcbData = 0;
  635. }
  636. if (pBinary == NULL) {
  637. pBinary = DetourBinaryFromInstance(NULL);
  638. }
  639. __try {
  640. DETOUR_SECTION_HEADER *pHeader = (DETOUR_SECTION_HEADER *)pBinary;
  641. if (pHeader->cbHeaderSize < sizeof(DETOUR_SECTION_HEADER) ||
  642. pHeader->nSignature != DETOUR_SECTION_HEADER_SIGNATURE) {
  643. SetLastError(ERROR_INVALID_EXE_SIGNATURE);
  644. return NULL;
  645. }
  646. PBYTE pbBeg = ((PBYTE)pHeader) + pHeader->nDataOffset;
  647. PBYTE pbEnd = ((PBYTE)pHeader) + pHeader->cbDataSize;
  648. for (pbData = pbBeg; pbData < pbEnd;) {
  649. DETOUR_SECTION_RECORD *pSection = (DETOUR_SECTION_RECORD *)pbData;
  650. if (pSection->guid == rguid) {
  651. if (pcbData) {
  652. *pcbData = pSection->cbBytes - sizeof(*pSection);
  653. return (PBYTE)(pSection + 1);
  654. }
  655. }
  656. pbData = (PBYTE)pSection + pSection->cbBytes;
  657. }
  658. } __except(EXCEPTION_EXECUTE_HANDLER) {
  659. SetLastError(ERROR_INVALID_HANDLE);
  660. return NULL;
  661. }
  662. SetLastError(ERROR_INVALID_HANDLE);
  663. return NULL;
  664. }
  665. //////////////////////////////////////////////////////////////////////////////
  666. //
  667. BOOL WINAPI DetourBinaryBindA(PCHAR pszFile, PCHAR pszDll, PCHAR pszPath)
  668. {
  669. if (!LoadImageHlp()) {
  670. SetLastError(ERROR_MOD_NOT_FOUND);
  671. return FALSE;
  672. }
  673. if (s_pfBindImage) {
  674. return (*s_pfBindImage)(pszFile, pszDll ? pszDll : ".", pszPath ? pszPath : ".");
  675. }
  676. SetLastError(ERROR_INVALID_FUNCTION);
  677. return FALSE;
  678. }
  679. static void UnicodeToOem(PWCHAR pwzIn, PCHAR pszOut, INT cbOut)
  680. {
  681. cbOut = WideCharToMultiByte(CP_OEMCP, 0,
  682. pwzIn, lstrlenW(pwzIn),
  683. pszOut, cbOut-1,
  684. NULL, NULL);
  685. pszOut[cbOut] = '\0';
  686. }
  687. BOOL WINAPI DetourBinaryBindW(PWCHAR pwzFile, PWCHAR pwzDll, PWCHAR pwzPath)
  688. {
  689. if (!LoadImageHlp()) {
  690. SetLastError(ERROR_MOD_NOT_FOUND);
  691. return FALSE;
  692. }
  693. CHAR szFile[MAX_PATH];
  694. CHAR szDll[MAX_PATH];
  695. CHAR szPath[MAX_PATH];
  696. UnicodeToOem(pwzFile, szFile, sizeof(szFile));
  697. UnicodeToOem(pwzDll, szDll, sizeof(szDll));
  698. UnicodeToOem(pwzPath, szPath, sizeof(szPath));
  699. if (s_pfBindImage) {
  700. return (s_pfBindImage)(szFile, szDll, szPath);
  701. }
  702. SetLastError(ERROR_INVALID_FUNCTION);
  703. return FALSE;
  704. }
  705. // End of File