creatwth.cpp 23 KB

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