creatwth.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878
  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Create a process with a DLL (creatwth.cpp of detours.lib)
  4. //
  5. // Microsoft Research Detours Package, Version 2.1.
  6. //
  7. // Copyright (c) Microsoft Corporation. All rights reserved.
  8. //
  9. #include <windows.h>
  10. #include <stddef.h>
  11. #if (_MSC_VER < 1299)
  12. typedef DWORD DWORD_PTR;
  13. #endif
  14. #if (_MSC_VER < 1310)
  15. #else
  16. #include <strsafe.h>
  17. #endif
  18. //#define DETOUR_DEBUG 1
  19. #define DETOURS_INTERNAL
  20. #include "detours.h"
  21. #define IMPORT_DIRECTORY OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
  22. #define BOUND_DIRECTORY OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT]
  23. #define CLR_DIRECTORY OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR]
  24. #define IAT_DIRECTORY OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT]
  25. //////////////////////////////////////////////////////////////////////////////
  26. //
  27. #ifndef _STRSAFE_H_INCLUDED_
  28. static inline HRESULT StringCchLengthA(const char* psz, size_t cchMax, size_t* pcch)
  29. {
  30. HRESULT hr = S_OK;
  31. size_t cchMaxPrev = cchMax;
  32. if (cchMax > 2147483647)
  33. {
  34. return ERROR_INVALID_PARAMETER;
  35. }
  36. while (cchMax && (*psz != '\0'))
  37. {
  38. psz++;
  39. cchMax--;
  40. }
  41. if (cchMax == 0)
  42. {
  43. // the string is longer than cchMax
  44. hr = ERROR_INVALID_PARAMETER;
  45. }
  46. if (SUCCEEDED(hr) && pcch)
  47. {
  48. *pcch = cchMaxPrev - cchMax;
  49. }
  50. return hr;
  51. }
  52. static inline HRESULT StringCchCopyA(char* pszDest, size_t cchDest, const char* pszSrc)
  53. {
  54. HRESULT hr = S_OK;
  55. if (cchDest == 0)
  56. {
  57. // can not null terminate a zero-byte dest buffer
  58. hr = ERROR_INVALID_PARAMETER;
  59. }
  60. else
  61. {
  62. while (cchDest && (*pszSrc != '\0'))
  63. {
  64. *pszDest++ = *pszSrc++;
  65. cchDest--;
  66. }
  67. if (cchDest == 0)
  68. {
  69. // we are going to truncate pszDest
  70. pszDest--;
  71. hr = ERROR_INVALID_PARAMETER;
  72. }
  73. *pszDest= '\0';
  74. }
  75. return hr;
  76. }
  77. static inline HRESULT StringCchCatA(char* pszDest, size_t cchDest, const char* pszSrc)
  78. {
  79. HRESULT hr;
  80. size_t cchDestCurrent;
  81. if (cchDest > 2147483647)
  82. {
  83. return ERROR_INVALID_PARAMETER;
  84. }
  85. hr = StringCchLengthA(pszDest, cchDest, &cchDestCurrent);
  86. if (SUCCEEDED(hr))
  87. {
  88. hr = StringCchCopyA(pszDest + cchDestCurrent,
  89. cchDest - cchDestCurrent,
  90. pszSrc);
  91. }
  92. return hr;
  93. }
  94. #endif
  95. //////////////////////////////////////////////////////////////////////////////
  96. //
  97. static WORD detour_sum_minus(WORD wSum, WORD wMinus)
  98. {
  99. wSum = (WORD)(wSum - ((wSum < wMinus) ? 1 : 0));
  100. wSum = (WORD)(wSum - wMinus);
  101. return wSum;
  102. }
  103. static WORD detour_sum_done(DWORD PartialSum)
  104. {
  105. // Fold final carry into a single word result and return the resultant value.
  106. return (WORD)(((PartialSum >> 16) + PartialSum) & 0xffff);
  107. }
  108. static WORD detour_sum_data(DWORD dwSum, PBYTE pbData, DWORD cbData)
  109. {
  110. while (cbData > 0) {
  111. dwSum += *((PWORD&)pbData)++;
  112. dwSum = (dwSum >> 16) + (dwSum & 0xffff);
  113. cbData -= sizeof(WORD);
  114. }
  115. return detour_sum_done(dwSum);
  116. }
  117. static WORD detour_sum_final(WORD wSum, PIMAGE_NT_HEADERS pinh)
  118. {
  119. DETOUR_TRACE((".... : %08x (value: %08x)\n", wSum, pinh->OptionalHeader.CheckSum));
  120. // Subtract the two checksum words in the optional header from the computed.
  121. wSum = detour_sum_minus(wSum, ((PWORD)(&pinh->OptionalHeader.CheckSum))[0]);
  122. wSum = detour_sum_minus(wSum, ((PWORD)(&pinh->OptionalHeader.CheckSum))[1]);
  123. return wSum;
  124. }
  125. static WORD ChkSumRange(WORD wSum, HANDLE hProcess, PBYTE pbBeg, PBYTE pbEnd)
  126. {
  127. BYTE rbPage[4096];
  128. while (pbBeg < pbEnd) {
  129. if (!ReadProcessMemory(hProcess, pbBeg, rbPage, sizeof(rbPage), NULL)) {
  130. DETOUR_TRACE(("ReadProcessMemory(idh) failed: %d\n", GetLastError()));
  131. break;
  132. }
  133. wSum = detour_sum_data(wSum, rbPage, sizeof(rbPage));
  134. pbBeg += sizeof(rbPage);
  135. }
  136. return wSum;
  137. }
  138. static WORD ComputeChkSum(HANDLE hProcess, PBYTE pbModule, PIMAGE_NT_HEADERS pinh)
  139. {
  140. // See LdrVerifyMappedImageMatchesChecksum.
  141. MEMORY_BASIC_INFORMATION mbi;
  142. ZeroMemory(&mbi, sizeof(mbi));
  143. WORD wSum = 0;
  144. for (PBYTE pbLast = pbModule;;
  145. pbLast = (PBYTE)mbi.BaseAddress + mbi.RegionSize) {
  146. if (VirtualQueryEx(hProcess, (PVOID)pbLast, &mbi, sizeof(mbi)) <= 0) {
  147. if (GetLastError() == ERROR_INVALID_PARAMETER) {
  148. break;
  149. }
  150. DETOUR_TRACE(("VirtualQueryEx(%08x) failed: %d\n",
  151. pbLast, GetLastError()));
  152. break;
  153. }
  154. if (mbi.AllocationBase != pbModule) {
  155. break;
  156. }
  157. wSum = ChkSumRange(wSum,
  158. hProcess,
  159. (PBYTE)mbi.BaseAddress,
  160. (PBYTE)mbi.BaseAddress + mbi.RegionSize);
  161. DETOUR_TRACE(("[%8p..%8p] : %04x\n",
  162. (PBYTE)mbi.BaseAddress,
  163. (PBYTE)mbi.BaseAddress + mbi.RegionSize,
  164. wSum));
  165. }
  166. return detour_sum_final(wSum, pinh);
  167. }
  168. //////////////////////////////////////////////////////////////////////////////
  169. //
  170. // Find a region of memory in which we can create a replacement import table.
  171. //
  172. static PBYTE FindAndAllocateNearBase(HANDLE hProcess, PBYTE pbBase, DWORD cbAlloc)
  173. {
  174. MEMORY_BASIC_INFORMATION mbi;
  175. ZeroMemory(&mbi, sizeof(mbi));
  176. for (PBYTE pbLast = pbBase;;
  177. pbLast = (PBYTE)mbi.BaseAddress + mbi.RegionSize) {
  178. if (VirtualQueryEx(hProcess, (PVOID)pbLast, &mbi, sizeof(mbi)) <= 0) {
  179. if (GetLastError() == ERROR_INVALID_PARAMETER) {
  180. break;
  181. }
  182. DETOUR_TRACE(("VirtualQueryEx(%08x) failed: %d\n",
  183. pbLast, GetLastError()));
  184. break;
  185. }
  186. // Skip uncommitted regions and guard pages.
  187. //
  188. if ((mbi.State != MEM_FREE)) {
  189. continue;
  190. }
  191. PBYTE pbAddress = (PBYTE)(((DWORD_PTR)mbi.BaseAddress + 0xffff) & ~(DWORD_PTR)0xffff);
  192. DETOUR_TRACE(("Free region %p..%p\n",
  193. mbi.BaseAddress,
  194. (PBYTE)mbi.BaseAddress + mbi.RegionSize));
  195. for (; pbAddress < (PBYTE)mbi.BaseAddress + mbi.RegionSize; pbAddress += 0x10000) {
  196. PBYTE pbAlloc = (PBYTE)VirtualAllocEx(hProcess, pbAddress, cbAlloc,
  197. MEM_RESERVE, PAGE_READWRITE);
  198. if (pbAlloc == NULL) {
  199. DETOUR_TRACE(("VirtualAllocEx(%p) failed: %d\n", pbAddress, GetLastError()));
  200. continue;
  201. }
  202. pbAlloc = (PBYTE)VirtualAllocEx(hProcess, pbAddress, cbAlloc,
  203. MEM_COMMIT, PAGE_READWRITE);
  204. if (pbAlloc == NULL) {
  205. DETOUR_TRACE(("VirtualAllocEx(%p) failed: %d\n", pbAddress, GetLastError()));
  206. continue;
  207. }
  208. DETOUR_TRACE(("[%p..%p] Allocated for import table.\n",
  209. pbAlloc, pbAlloc + cbAlloc));
  210. return pbAlloc;
  211. }
  212. }
  213. return NULL;
  214. }
  215. static inline DWORD PadToDword(DWORD dw)
  216. {
  217. return (dw + 3) & ~3u;
  218. }
  219. static inline DWORD PadToDwordPtr(DWORD dw)
  220. {
  221. return (dw + 7) & ~7u;
  222. }
  223. static BOOL IsExe(HANDLE hProcess, PBYTE pbModule)
  224. {
  225. IMAGE_DOS_HEADER idh;
  226. ZeroMemory(&idh, sizeof(idh));
  227. if (!ReadProcessMemory(hProcess, pbModule, &idh, sizeof(idh), NULL)) {
  228. DETOUR_TRACE(("ReadProcessMemory(idh) failed: %d\n", GetLastError()));
  229. return FALSE;
  230. }
  231. if (idh.e_magic != IMAGE_DOS_SIGNATURE) {
  232. // DETOUR_TRACE((" No IMAGE_DOS_SIGNATURE\n"));
  233. return FALSE;
  234. }
  235. IMAGE_NT_HEADERS inh;
  236. ZeroMemory(&inh, sizeof(inh));
  237. if (!ReadProcessMemory(hProcess, pbModule + idh.e_lfanew, &inh, sizeof(inh), NULL)) {
  238. DETOUR_TRACE(("ReadProcessMemory(inh) failed: %d\n", GetLastError()));
  239. return FALSE;
  240. }
  241. if (inh.Signature != IMAGE_NT_SIGNATURE) {
  242. DETOUR_TRACE((" No IMAGE_NT_SIGNATURE\n"));
  243. return FALSE;
  244. }
  245. if (inh.FileHeader.Characteristics & IMAGE_FILE_DLL) {
  246. DETOUR_TRACE((" Characteristics: %08x\n", inh.FileHeader.Characteristics));
  247. return FALSE;
  248. }
  249. return TRUE;
  250. }
  251. PVOID FindExe(HANDLE hProcess)
  252. {
  253. MEMORY_BASIC_INFORMATION mbi;
  254. ZeroMemory(&mbi, sizeof(mbi));
  255. // Find the next memory region that contains a mapped PE image.
  256. //
  257. for (PBYTE pbLast = (PBYTE)0x10000;;
  258. pbLast = (PBYTE)mbi.BaseAddress + mbi.RegionSize) {
  259. if (VirtualQueryEx(hProcess, (PVOID)pbLast, &mbi, sizeof(mbi)) <= 0) {
  260. if (GetLastError() == ERROR_INVALID_PARAMETER) {
  261. break;
  262. }
  263. DETOUR_TRACE(("VirtualQueryEx(%08x) failed: %d\n",
  264. pbLast, GetLastError()));
  265. break;
  266. }
  267. // Skip uncommitted regions and guard pages.
  268. //
  269. if ((mbi.State != MEM_COMMIT) || (mbi.Protect & PAGE_GUARD)) {
  270. continue;
  271. }
  272. DETOUR_TRACE(("%8p..%8p [%8p]\n",
  273. mbi.BaseAddress,
  274. (PBYTE)mbi.BaseAddress + mbi.RegionSize,
  275. mbi.AllocationBase));
  276. if (IsExe(hProcess, pbLast)) {
  277. #if DETOUR_DEBUG
  278. for (PBYTE pbNext = (PBYTE)mbi.BaseAddress + mbi.RegionSize;;
  279. pbNext = (PBYTE)mbi.BaseAddress + mbi.RegionSize) {
  280. if (VirtualQueryEx(hProcess, (PVOID)pbNext, &mbi, sizeof(mbi)) <= 0) {
  281. if (GetLastError() == ERROR_INVALID_PARAMETER) {
  282. break;
  283. }
  284. DETOUR_TRACE(("VirtualQueryEx(%08x) failed: %d\n",
  285. pbNext, GetLastError()));
  286. break;
  287. }
  288. // Skip uncommitted regions and guard pages.
  289. //
  290. if ((mbi.State != MEM_COMMIT) || (mbi.Protect & PAGE_GUARD)) {
  291. continue;
  292. }
  293. DETOUR_TRACE(("%8p..%8p [%8p]\n",
  294. mbi.BaseAddress,
  295. (PBYTE)mbi.BaseAddress + mbi.RegionSize,
  296. mbi.AllocationBase));
  297. IsExe(hProcess, pbNext);
  298. }
  299. #endif
  300. return pbLast;
  301. }
  302. }
  303. return NULL;
  304. }
  305. static BOOL UpdateImports(HANDLE hProcess, LPCSTR *plpDlls, DWORD nDlls)
  306. {
  307. BOOL fSucceeded = FALSE;
  308. BYTE * pbNew = NULL;
  309. DETOUR_EXE_RESTORE der;
  310. DWORD i;
  311. ZeroMemory(&der, sizeof(der));
  312. der.cb = sizeof(der);
  313. PBYTE pbModule = (PBYTE)FindExe(hProcess);
  314. IMAGE_DOS_HEADER idh;
  315. ZeroMemory(&idh, sizeof(idh));
  316. if (!ReadProcessMemory(hProcess, pbModule, &idh, sizeof(idh), NULL)) {
  317. DETOUR_TRACE(("ReadProcessMemory(idh) failed: %d\n", GetLastError()));
  318. finish:
  319. if (pbNew != NULL) {
  320. delete[] pbNew;
  321. pbNew = NULL;
  322. }
  323. return fSucceeded;
  324. }
  325. CopyMemory(&der.idh, &idh, sizeof(idh));
  326. der.pidh = (PIMAGE_DOS_HEADER)pbModule;
  327. if (idh.e_magic != IMAGE_DOS_SIGNATURE) {
  328. goto finish;
  329. }
  330. IMAGE_NT_HEADERS inh;
  331. ZeroMemory(&inh, sizeof(inh));
  332. if (!ReadProcessMemory(hProcess, pbModule + idh.e_lfanew, &inh, sizeof(inh), NULL)) {
  333. DETOUR_TRACE(("ReadProcessMemory(inh) failed: %d\n", GetLastError()));
  334. goto finish;
  335. }
  336. CopyMemory(&der.inh, &inh, sizeof(inh));
  337. der.pinh = (PIMAGE_NT_HEADERS)(pbModule + idh.e_lfanew);
  338. if (inh.Signature != IMAGE_NT_SIGNATURE) {
  339. goto finish;
  340. }
  341. if (inh.IMPORT_DIRECTORY.VirtualAddress == 0) {
  342. DETOUR_TRACE(("No IMAGE_DIRECTORY_ENTRY_IMPORT\n"));
  343. goto finish;
  344. }
  345. // Zero out the bound table so loader doesn't use it instead of our new table.
  346. inh.BOUND_DIRECTORY.VirtualAddress = 0;
  347. inh.BOUND_DIRECTORY.Size = 0;
  348. // Find the size of the mapped file.
  349. DWORD dwFileSize = 0;
  350. DWORD dwSec = idh.e_lfanew +
  351. FIELD_OFFSET( IMAGE_NT_HEADERS, OptionalHeader ) +
  352. inh.FileHeader.SizeOfOptionalHeader;
  353. for (i = 0; i < inh.FileHeader.NumberOfSections; i++) {
  354. IMAGE_SECTION_HEADER ish;
  355. ZeroMemory(&ish, sizeof(ish));
  356. if (!ReadProcessMemory(hProcess, pbModule + dwSec + sizeof(ish) * i, &ish,
  357. sizeof(ish), NULL)) {
  358. DETOUR_TRACE(("ReadProcessMemory(inh) failed: %d\n", GetLastError()));
  359. goto finish;
  360. }
  361. DETOUR_TRACE(("ish[%d] : va=%p sr=%d\n", i, ish.VirtualAddress, ish.SizeOfRawData));
  362. // If the file didn't have an IAT_DIRECTORY, we create one...
  363. if (inh.IAT_DIRECTORY.VirtualAddress == 0 &&
  364. inh.IMPORT_DIRECTORY.VirtualAddress >= ish.VirtualAddress &&
  365. inh.IMPORT_DIRECTORY.VirtualAddress < ish.VirtualAddress + ish.SizeOfRawData) {
  366. inh.IAT_DIRECTORY.VirtualAddress = ish.VirtualAddress;
  367. inh.IAT_DIRECTORY.Size = ish.SizeOfRawData;
  368. }
  369. // Find the end of the file...
  370. if (dwFileSize < ish.PointerToRawData + ish.SizeOfRawData) {
  371. dwFileSize = ish.PointerToRawData + ish.SizeOfRawData;
  372. }
  373. }
  374. DETOUR_TRACE(("dwFileSize = %08x\n", dwFileSize));
  375. // Find the current checksum.
  376. WORD wBefore = ComputeChkSum(hProcess, pbModule, &inh);
  377. DETOUR_TRACE(("ChkSum: %04x + %08x => %08x\n", wBefore, dwFileSize, wBefore + dwFileSize));
  378. DETOUR_TRACE((" Imports: %8p..%8p\n",
  379. (DWORD_PTR)pbModule + inh.IMPORT_DIRECTORY.VirtualAddress,
  380. (DWORD_PTR)pbModule + inh.IMPORT_DIRECTORY.VirtualAddress +
  381. inh.IMPORT_DIRECTORY.Size));
  382. DWORD obRem = sizeof(IMAGE_IMPORT_DESCRIPTOR) * nDlls;
  383. DWORD obTab = PadToDwordPtr(obRem + inh.IMPORT_DIRECTORY.Size);
  384. DWORD obDll = obTab + sizeof(DWORD_PTR) * 4 * nDlls;
  385. DWORD obStr = obDll;
  386. DWORD cbNew = obStr;
  387. DWORD n;
  388. for (n = 0; n < nDlls; n++) {
  389. cbNew += PadToDword((DWORD)strlen(plpDlls[n]) + 1);
  390. }
  391. pbNew = new BYTE [cbNew];
  392. if (pbNew == NULL) {
  393. DETOUR_TRACE(("new BYTE [cbNew] failed.\n"));
  394. goto finish;
  395. }
  396. ZeroMemory(pbNew, cbNew);
  397. PBYTE pbBase = pbModule;
  398. PBYTE pbNext = pbBase
  399. + inh.OptionalHeader.BaseOfCode
  400. + inh.OptionalHeader.SizeOfCode
  401. + inh.OptionalHeader.SizeOfInitializedData
  402. + inh.OptionalHeader.SizeOfUninitializedData;
  403. if (pbBase < pbNext) {
  404. pbBase = pbNext;
  405. }
  406. DETOUR_TRACE(("pbBase = %p\n", pbBase));
  407. PBYTE pbNewIid = FindAndAllocateNearBase(hProcess, pbBase, cbNew);
  408. if (pbNewIid == NULL) {
  409. DETOUR_TRACE(("FindAndAllocateNearBase failed.\n"));
  410. goto finish;
  411. }
  412. DWORD dwProtect = 0;
  413. der.impDirProt = 0;
  414. if (!VirtualProtectEx(hProcess,
  415. pbModule + inh.IMPORT_DIRECTORY.VirtualAddress,
  416. inh.IMPORT_DIRECTORY.Size, PAGE_EXECUTE_READWRITE, &dwProtect)) {
  417. DETOUR_TRACE(("VirtualProtextEx(import) write failed: %d\n", GetLastError()));
  418. goto finish;
  419. }
  420. DETOUR_TRACE(("IMPORT_DIRECTORY perms=%x\n", dwProtect));
  421. der.impDirProt = dwProtect;
  422. DWORD obBase = (DWORD)(pbNewIid - pbModule);
  423. if (!ReadProcessMemory(hProcess,
  424. pbModule + inh.IMPORT_DIRECTORY.VirtualAddress,
  425. pbNew + obRem,
  426. inh.IMPORT_DIRECTORY.Size, NULL)) {
  427. DETOUR_TRACE(("ReadProcessMemory(imports) failed: %d\n", GetLastError()));
  428. goto finish;
  429. }
  430. PIMAGE_IMPORT_DESCRIPTOR piid = (PIMAGE_IMPORT_DESCRIPTOR)pbNew;
  431. DWORD_PTR *pt;
  432. for (n = 0; n < nDlls; n++) {
  433. HRESULT hrRet = StringCchCopyA((char*)pbNew + obStr, cbNew - obStr, plpDlls[n]);
  434. if (FAILED(hrRet))
  435. {
  436. DETOUR_TRACE(("StringCchCopyA failed: %d\n", GetLastError()));
  437. goto finish;
  438. }
  439. DWORD nOffset = obTab + (sizeof(DWORD_PTR) * (4 * n));
  440. piid[n].OriginalFirstThunk = obBase + nOffset;
  441. pt = ((DWORD_PTR*)(pbNew + nOffset));
  442. pt[0] = IMAGE_ORDINAL_FLAG + 1;
  443. pt[1] = 0;
  444. nOffset = obTab + (sizeof(DWORD_PTR) * ((4 * n) + 2));
  445. piid[n].FirstThunk = obBase + nOffset;
  446. pt = ((DWORD_PTR*)(pbNew + nOffset));
  447. pt[0] = IMAGE_ORDINAL_FLAG + 1;
  448. pt[1] = 0;
  449. piid[n].TimeDateStamp = 0;
  450. piid[n].ForwarderChain = 0;
  451. piid[n].Name = obBase + obStr;
  452. obStr += PadToDword((DWORD)strlen(plpDlls[n]) + 1);
  453. }
  454. for (i = 0; i < nDlls + (inh.IMPORT_DIRECTORY.Size / sizeof(*piid)); i++) {
  455. DETOUR_TRACE(("%8d. Look=%08x Time=%08x Fore=%08x Name=%08x Addr=%08x\n",
  456. i,
  457. piid[i].OriginalFirstThunk,
  458. piid[i].TimeDateStamp,
  459. piid[i].ForwarderChain,
  460. piid[i].Name,
  461. piid[i].FirstThunk));
  462. if (piid[i].OriginalFirstThunk == 0 && piid[i].FirstThunk == 0) {
  463. break;
  464. }
  465. }
  466. if (!WriteProcessMemory(hProcess, pbNewIid, pbNew, obStr, NULL)) {
  467. DETOUR_TRACE(("WriteProcessMemory(iid) failed: %d\n", GetLastError()));
  468. goto finish;
  469. }
  470. DETOUR_TRACE(("obBase = %p..%p\n",
  471. inh.IMPORT_DIRECTORY.VirtualAddress,
  472. inh.IMPORT_DIRECTORY.VirtualAddress + inh.IMPORT_DIRECTORY.Size));
  473. DETOUR_TRACE(("obBase = %p..%p\n", obBase, obBase + obStr));
  474. inh.IMPORT_DIRECTORY.VirtualAddress = obBase;
  475. inh.IMPORT_DIRECTORY.Size = cbNew;
  476. /////////////////////////////////////////////////// Update the CLR header.
  477. //
  478. if (inh.CLR_DIRECTORY.VirtualAddress != 0 &&
  479. inh.CLR_DIRECTORY.Size != 0) {
  480. DETOUR_CLR_HEADER clr;
  481. PBYTE pbClr = pbModule + inh.CLR_DIRECTORY.VirtualAddress;
  482. if (!ReadProcessMemory(hProcess, pbClr, &clr, sizeof(clr), NULL)) {
  483. DETOUR_TRACE(("ReadProcessMemory(clr) failed: %d\n", GetLastError()));
  484. goto finish;
  485. }
  486. der.pclrFlags = (PULONG)(pbClr + offsetof(DETOUR_CLR_HEADER, Flags));
  487. der.clrFlags = clr.Flags;
  488. clr.Flags &= 0xfffffffe; // Clear the IL_ONLY flag.
  489. if (!VirtualProtectEx(hProcess, pbClr, sizeof(clr), PAGE_READWRITE, &dwProtect)) {
  490. DETOUR_TRACE(("VirtualProtextEx(clr) write failed: %d\n", GetLastError()));
  491. goto finish;
  492. }
  493. if (!WriteProcessMemory(hProcess, pbClr, &clr, sizeof(clr), NULL)) {
  494. DETOUR_TRACE(("WriteProcessMemory(clr) failed: %d\n", GetLastError()));
  495. goto finish;
  496. }
  497. if (!VirtualProtectEx(hProcess, pbClr, sizeof(clr), dwProtect, &dwProtect)) {
  498. DETOUR_TRACE(("VirtualProtextEx(clr) restore failed: %d\n", GetLastError()));
  499. goto finish;
  500. }
  501. }
  502. /////////////////////// Update the NT header for the import new directory.
  503. /////////////////////////////// Update the DOS header to fix the checksum.
  504. //
  505. if (!VirtualProtectEx(hProcess, pbModule, inh.OptionalHeader.SizeOfHeaders,
  506. PAGE_EXECUTE_READWRITE, &dwProtect)) {
  507. DETOUR_TRACE(("VirtualProtextEx(inh) write failed: %d\n", GetLastError()));
  508. goto finish;
  509. }
  510. idh.e_res[0] = 0;
  511. if (!WriteProcessMemory(hProcess, pbModule, &idh, sizeof(idh), NULL)) {
  512. DETOUR_TRACE(("WriteProcessMemory(idh) failed: %d\n", GetLastError()));
  513. goto finish;
  514. }
  515. if (!WriteProcessMemory(hProcess, pbModule + idh.e_lfanew, &inh, sizeof(inh), NULL)) {
  516. DETOUR_TRACE(("WriteProcessMemory(inh) failed: %d\n", GetLastError()));
  517. goto finish;
  518. }
  519. WORD wDuring = ComputeChkSum(hProcess, pbModule, &inh);
  520. DETOUR_TRACE(("ChkSum: %04x + %08x => %08x\n", wDuring, dwFileSize, wDuring + dwFileSize));
  521. idh.e_res[0] = detour_sum_minus(idh.e_res[0], detour_sum_minus(wDuring, wBefore));
  522. if (!WriteProcessMemory(hProcess, pbModule, &idh, sizeof(idh), NULL)) {
  523. DETOUR_TRACE(("WriteProcessMemory(idh) failed: %d\n", GetLastError()));
  524. goto finish;
  525. }
  526. if (!VirtualProtectEx(hProcess, pbModule, inh.OptionalHeader.SizeOfHeaders,
  527. dwProtect, &dwProtect)) {
  528. DETOUR_TRACE(("VirtualProtextEx(idh) restore failed: %d\n", GetLastError()));
  529. goto finish;
  530. }
  531. WORD wAfter = ComputeChkSum(hProcess, pbModule, &inh);
  532. DETOUR_TRACE(("ChkSum: %04x + %08x => %08x\n", wAfter, dwFileSize, wAfter + dwFileSize));
  533. DETOUR_TRACE(("Before: %08x, After: %08x\n", wBefore + dwFileSize, wAfter + dwFileSize));
  534. if (wBefore != wAfter) {
  535. DETOUR_TRACE(("Restore of checksum failed %04x != %04x.\n", wBefore, wAfter));
  536. goto finish;
  537. }
  538. if (!DetourCopyPayloadToProcess(hProcess, DETOUR_EXE_RESTORE_GUID, &der, sizeof(der))) {
  539. DETOUR_TRACE(("DetourCopyPayloadToProcess failed: %d\n", GetLastError()));
  540. goto finish;
  541. }
  542. fSucceeded = TRUE;
  543. goto finish;
  544. }
  545. //////////////////////////////////////////////////////////////////////////////
  546. //
  547. BOOL WINAPI DetourCreateProcessWithDllA(LPCSTR lpApplicationName,
  548. __in_z LPSTR lpCommandLine,
  549. LPSECURITY_ATTRIBUTES lpProcessAttributes,
  550. LPSECURITY_ATTRIBUTES lpThreadAttributes,
  551. BOOL bInheritHandles,
  552. DWORD dwCreationFlags,
  553. LPVOID lpEnvironment,
  554. LPCSTR lpCurrentDirectory,
  555. LPSTARTUPINFOA lpStartupInfo,
  556. LPPROCESS_INFORMATION lpProcessInformation,
  557. LPCSTR lpDetouredDllFullName,
  558. LPCSTR lpDllName,
  559. PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA)
  560. {
  561. DWORD dwMyCreationFlags = (dwCreationFlags | CREATE_SUSPENDED);
  562. PROCESS_INFORMATION pi;
  563. if (pfCreateProcessA == NULL) {
  564. pfCreateProcessA = CreateProcessA;
  565. }
  566. if (!pfCreateProcessA(lpApplicationName,
  567. lpCommandLine,
  568. lpProcessAttributes,
  569. lpThreadAttributes,
  570. bInheritHandles,
  571. dwMyCreationFlags,
  572. lpEnvironment,
  573. lpCurrentDirectory,
  574. lpStartupInfo,
  575. &pi)) {
  576. return FALSE;
  577. }
  578. LPCSTR rlpDlls[2];
  579. DWORD nDlls = 0;
  580. if (lpDetouredDllFullName != NULL) {
  581. rlpDlls[nDlls++] = lpDetouredDllFullName;
  582. }
  583. if (lpDllName != NULL) {
  584. rlpDlls[nDlls++] = lpDllName;
  585. }
  586. if (!UpdateImports(pi.hProcess, rlpDlls, nDlls)) {
  587. return FALSE;
  588. }
  589. if (lpProcessInformation) {
  590. CopyMemory(lpProcessInformation, &pi, sizeof(pi));
  591. }
  592. if (!(dwCreationFlags & CREATE_SUSPENDED)) {
  593. ResumeThread(pi.hThread);
  594. }
  595. return TRUE;
  596. }
  597. BOOL WINAPI DetourCreateProcessWithDllW(LPCWSTR lpApplicationName,
  598. __in_z LPWSTR lpCommandLine,
  599. LPSECURITY_ATTRIBUTES lpProcessAttributes,
  600. LPSECURITY_ATTRIBUTES lpThreadAttributes,
  601. BOOL bInheritHandles,
  602. DWORD dwCreationFlags,
  603. LPVOID lpEnvironment,
  604. LPCWSTR lpCurrentDirectory,
  605. LPSTARTUPINFOW lpStartupInfo,
  606. LPPROCESS_INFORMATION lpProcessInformation,
  607. LPCSTR lpDetouredDllFullName,
  608. LPCSTR lpDllName,
  609. PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW)
  610. {
  611. DWORD dwMyCreationFlags = (dwCreationFlags | CREATE_SUSPENDED);
  612. PROCESS_INFORMATION pi;
  613. if (pfCreateProcessW == NULL) {
  614. pfCreateProcessW = CreateProcessW;
  615. }
  616. if (!pfCreateProcessW(lpApplicationName,
  617. lpCommandLine,
  618. lpProcessAttributes,
  619. lpThreadAttributes,
  620. bInheritHandles,
  621. dwMyCreationFlags,
  622. lpEnvironment,
  623. lpCurrentDirectory,
  624. lpStartupInfo,
  625. &pi)) {
  626. return FALSE;
  627. }
  628. LPCSTR rlpDlls[2];
  629. DWORD nDlls = 0;
  630. if (lpDetouredDllFullName != NULL) {
  631. rlpDlls[nDlls++] = lpDetouredDllFullName;
  632. }
  633. if (lpDllName != NULL) {
  634. rlpDlls[nDlls++] = lpDllName;
  635. }
  636. if (!UpdateImports(pi.hProcess, rlpDlls, nDlls)) {
  637. return FALSE;
  638. }
  639. if (lpProcessInformation) {
  640. CopyMemory(lpProcessInformation, &pi, sizeof(pi));
  641. }
  642. if (!(dwCreationFlags & CREATE_SUSPENDED)) {
  643. ResumeThread(pi.hThread);
  644. }
  645. return TRUE;
  646. }
  647. BOOL WINAPI DetourCopyPayloadToProcess(HANDLE hProcess,
  648. REFGUID rguid,
  649. PVOID pData,
  650. DWORD cbData)
  651. {
  652. DWORD cbTotal = (sizeof(IMAGE_DOS_HEADER) +
  653. sizeof(IMAGE_NT_HEADERS) +
  654. sizeof(IMAGE_SECTION_HEADER) +
  655. sizeof(DETOUR_SECTION_HEADER) +
  656. sizeof(DETOUR_SECTION_RECORD) +
  657. cbData);
  658. PBYTE pbBase = (PBYTE)VirtualAllocEx(hProcess, NULL, cbTotal,
  659. MEM_COMMIT, PAGE_READWRITE);
  660. if (pbBase == NULL) {
  661. DETOUR_TRACE(("VirtualAllocEx(%d) failed: %d\n", cbTotal, GetLastError()));
  662. return FALSE;
  663. }
  664. PBYTE pbTarget = pbBase;
  665. IMAGE_DOS_HEADER idh;
  666. IMAGE_NT_HEADERS inh;
  667. IMAGE_SECTION_HEADER ish;
  668. DETOUR_SECTION_HEADER dsh;
  669. DETOUR_SECTION_RECORD dsr;
  670. SIZE_T cbWrote = 0;
  671. ZeroMemory(&idh, sizeof(idh));
  672. idh.e_magic = IMAGE_DOS_SIGNATURE;
  673. idh.e_lfanew = sizeof(idh);
  674. if (!WriteProcessMemory(hProcess, pbTarget, &idh, sizeof(idh), &cbWrote) ||
  675. cbWrote != sizeof(idh)) {
  676. DETOUR_TRACE(("WriteProcessMemory(idh) failed: %d\n", GetLastError()));
  677. return FALSE;
  678. }
  679. pbTarget += sizeof(idh);
  680. ZeroMemory(&inh, sizeof(inh));
  681. inh.Signature = IMAGE_NT_SIGNATURE;
  682. inh.FileHeader.SizeOfOptionalHeader = sizeof(inh.OptionalHeader);
  683. inh.FileHeader.Characteristics = IMAGE_FILE_DLL;
  684. inh.FileHeader.NumberOfSections = 1;
  685. if (!WriteProcessMemory(hProcess, pbTarget, &inh, sizeof(inh), &cbWrote) ||
  686. cbWrote != sizeof(inh)) {
  687. return FALSE;
  688. }
  689. pbTarget += sizeof(inh);
  690. ZeroMemory(&ish, sizeof(ish));
  691. memcpy(ish.Name, ".detour", sizeof(ish.Name));
  692. ish.VirtualAddress = (DWORD)((pbTarget + sizeof(ish)) - pbBase);
  693. ish.SizeOfRawData = (sizeof(DETOUR_SECTION_HEADER) +
  694. sizeof(DETOUR_SECTION_RECORD) +
  695. cbData);
  696. if (!WriteProcessMemory(hProcess, pbTarget, &ish, sizeof(ish), &cbWrote) ||
  697. cbWrote != sizeof(ish)) {
  698. return FALSE;
  699. }
  700. pbTarget += sizeof(ish);
  701. ZeroMemory(&dsh, sizeof(dsh));
  702. dsh.cbHeaderSize = sizeof(dsh);
  703. dsh.nSignature = DETOUR_SECTION_HEADER_SIGNATURE;
  704. dsh.nDataOffset = sizeof(DETOUR_SECTION_HEADER);
  705. dsh.cbDataSize = (sizeof(DETOUR_SECTION_HEADER) +
  706. sizeof(DETOUR_SECTION_RECORD) +
  707. cbData);
  708. if (!WriteProcessMemory(hProcess, pbTarget, &dsh, sizeof(dsh), &cbWrote) ||
  709. cbWrote != sizeof(dsh)) {
  710. return FALSE;
  711. }
  712. pbTarget += sizeof(dsh);
  713. ZeroMemory(&dsr, sizeof(dsr));
  714. dsr.cbBytes = cbData + sizeof(DETOUR_SECTION_RECORD);
  715. dsr.nReserved = 0;
  716. dsr.guid = rguid;
  717. if (!WriteProcessMemory(hProcess, pbTarget, &dsr, sizeof(dsr), &cbWrote) ||
  718. cbWrote != sizeof(dsr)) {
  719. return FALSE;
  720. }
  721. pbTarget += sizeof(dsr);
  722. if (!WriteProcessMemory(hProcess, pbTarget, pData, cbData, &cbWrote) ||
  723. cbWrote != cbData) {
  724. return FALSE;
  725. }
  726. pbTarget += cbData;
  727. DETOUR_TRACE(("Copied %d bytes into target process at %p\n",
  728. cbTotal, pbTarget - cbTotal));
  729. return TRUE;
  730. }
  731. //
  732. ///////////////////////////////////////////////////////////////// End of File.