//Create a process with a DLL (creatwth.cpp of detours.lib) //Microsoft Research Detours Package, Version 2.1. //Copyright (c) Microsoft Corporation. All rights reserved. #include #include #if (_MSC_VER < 1299) typedef DWORD DWORD_PTR; #endif #if (_MSC_VER < 1310) #else #include #endif //#define DETOUR_DEBUG 1 #define DETOURS_INTERNAL #include "detours.h" #define IMPORT_DIRECTORY OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] #define BOUND_DIRECTORY OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT] #define CLR_DIRECTORY OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR] #define IAT_DIRECTORY OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT] #ifndef _STRSAFE_H_INCLUDED_ static inline HRESULT StringCchLengthA( const char * psz , size_t cchMax , size_t * pcch ) { HRESULT hr = S_OK; size_t cchMaxPrev = cchMax; if ( cchMax > 2147483647 ) { return ERROR_INVALID_PARAMETER; } while ( cchMax && ( *psz != '\0' ) ) { psz++; cchMax--; } if ( cchMax == 0 ) { //the string is longer than cchMax hr = ERROR_INVALID_PARAMETER; } if ( SUCCEEDED( hr ) && pcch ) { *pcch = cchMaxPrev - cchMax; } return hr; } static inline HRESULT StringCchCopyA( char * pszDest , size_t cchDest , const char * pszSrc ) { HRESULT hr = S_OK; if ( cchDest == 0 ) { //can not null terminate a zero-byte dest buffer hr = ERROR_INVALID_PARAMETER; } else { while ( cchDest && ( *pszSrc != '\0' ) ) { *pszDest++ = *pszSrc++; cchDest--; } if ( cchDest == 0 ) { //we are going to truncate pszDest pszDest--; hr = ERROR_INVALID_PARAMETER; } *pszDest = '\0'; } return hr; } static inline HRESULT StringCchCatA( char * pszDest , size_t cchDest , const char * pszSrc ) { HRESULT hr; size_t cchDestCurrent; if ( cchDest > 2147483647 ) { return ERROR_INVALID_PARAMETER; } hr = StringCchLengthA( pszDest,cchDest,&cchDestCurrent ); if ( SUCCEEDED( hr ) ) { hr = StringCchCopyA( pszDest + cchDestCurrent,cchDest - cchDestCurrent,pszSrc ); } return hr; } #endif static WORD detour_sum_minus( WORD wSum , WORD wMinus ) { wSum = ( WORD ) ( wSum - ( ( wSum < wMinus ) ? 1 : 0 ) ); wSum = ( WORD ) ( wSum - wMinus ); return wSum; } static WORD detour_sum_done( DWORD PartialSum ) { //Fold final carry into a single word result and return the resultant value. return ( WORD ) ( ( ( PartialSum >> 16 ) + PartialSum ) & 0xffff ); } static WORD detour_sum_data( DWORD dwSum , PBYTE pbData , DWORD cbData ) { while ( cbData > 0 ) { dwSum += *( ( PWORD & ) pbData )++; dwSum = ( dwSum >> 16 ) + ( dwSum & 0xffff ); cbData -= sizeof( WORD ); } return detour_sum_done( dwSum ); } static WORD detour_sum_final( WORD wSum , PIMAGE_NT_HEADERS pinh ) { DETOUR_TRACE( ( ".... : %08x (value: %08x)\n",wSum,pinh->OptionalHeader.CheckSum ) ); //Subtract the two checksum words in the optional header from the computed. wSum = detour_sum_minus( wSum,( ( PWORD ) ( &pinh->OptionalHeader.CheckSum ) )[0] ); wSum = detour_sum_minus( wSum,( ( PWORD ) ( &pinh->OptionalHeader.CheckSum ) )[1] ); return wSum; } static WORD ChkSumRange( WORD wSum , HANDLE hProcess , PBYTE pbBeg , PBYTE pbEnd ) { BYTE rbPage[4096]; while ( pbBeg < pbEnd ) { if ( !ReadProcessMemory( hProcess,pbBeg,rbPage,sizeof( rbPage ),NULL ) ) { DETOUR_TRACE( ( "ReadProcessMemory(idh) failed: %d\n",GetLastError() ) ); break; } wSum = detour_sum_data( wSum,rbPage,sizeof( rbPage ) ); pbBeg += sizeof( rbPage ); } return wSum; } static WORD ComputeChkSum( HANDLE hProcess , PBYTE pbModule , PIMAGE_NT_HEADERS pinh ) { //See LdrVerifyMappedImageMatchesChecksum. MEMORY_BASIC_INFORMATION mbi; ZeroMemory( &mbi,sizeof( mbi ) ); WORD wSum = 0; for ( PBYTE pbLast = pbModule; ; pbLast = ( PBYTE ) mbi.BaseAddress + mbi.RegionSize ) { if ( VirtualQueryEx( hProcess,( PVOID ) pbLast,&mbi,sizeof( mbi ) ) <= 0 ) { if ( GetLastError() == ERROR_INVALID_PARAMETER ) { break; } DETOUR_TRACE( ( "VirtualQueryEx(%08x) failed: %d\n",pbLast,GetLastError() ) ); break; } if ( mbi.AllocationBase != pbModule ) { break; } wSum = ChkSumRange( wSum,hProcess,( PBYTE ) mbi.BaseAddress,( PBYTE ) mbi.BaseAddress + mbi.RegionSize ); DETOUR_TRACE( ( "[%8p..%8p] : %04x\n",( PBYTE ) mbi.BaseAddress,( PBYTE ) mbi.BaseAddress + mbi.RegionSize,wSum ) ); } return detour_sum_final( wSum,pinh ); } //Find a region of memory in which we can create a replacement import table. static PBYTE FindAndAllocateNearBase( HANDLE hProcess , PBYTE pbBase , DWORD cbAlloc ) { MEMORY_BASIC_INFORMATION mbi; ZeroMemory( &mbi,sizeof( mbi ) ); for ( PBYTE pbLast = pbBase; ; pbLast = ( PBYTE ) mbi.BaseAddress + mbi.RegionSize ) { if ( VirtualQueryEx( hProcess,( PVOID ) pbLast,&mbi,sizeof( mbi ) ) <= 0 ) { if ( GetLastError() == ERROR_INVALID_PARAMETER ) { break; } DETOUR_TRACE( ( "VirtualQueryEx(%08x) failed: %d\n",pbLast,GetLastError() ) ); break; } //Skip uncommitted regions and guard pages. if ( ( mbi.State != MEM_FREE ) ) { continue; } PBYTE pbAddress = ( PBYTE ) ( ( ( DWORD_PTR ) mbi.BaseAddress + 0xffff ) & ~( DWORD_PTR ) 0xffff ); DETOUR_TRACE( ( "Free region %p..%p\n",mbi.BaseAddress,( PBYTE ) mbi.BaseAddress + mbi.RegionSize ) ); for ( ; pbAddress < ( PBYTE ) mbi.BaseAddress + mbi.RegionSize; pbAddress += 0x10000 ) { PBYTE pbAlloc = ( PBYTE ) VirtualAllocEx( hProcess,pbAddress,cbAlloc,MEM_RESERVE,PAGE_READWRITE ); if ( pbAlloc == NULL ) { DETOUR_TRACE( ( "VirtualAllocEx(%p) failed: %d\n",pbAddress,GetLastError() ) ); continue; } pbAlloc = ( PBYTE ) VirtualAllocEx( hProcess,pbAddress,cbAlloc,MEM_COMMIT,PAGE_READWRITE ); if ( pbAlloc == NULL ) { DETOUR_TRACE( ( "VirtualAllocEx(%p) failed: %d\n",pbAddress,GetLastError() ) ); continue; } DETOUR_TRACE( ( "[%p..%p] Allocated for import table.\n",pbAlloc,pbAlloc + cbAlloc ) ); return pbAlloc; } } return NULL; } static inline DWORD PadToDword( DWORD dw ) { return ( dw + 3 ) & ~3u; } static inline DWORD PadToDwordPtr( DWORD dw ) { return ( dw + 7 ) & ~7u; } static BOOL IsExe( HANDLE hProcess , PBYTE pbModule ) { IMAGE_DOS_HEADER idh; ZeroMemory( &idh,sizeof( idh ) ); if ( !ReadProcessMemory( hProcess,pbModule,&idh,sizeof( idh ),NULL ) ) { DETOUR_TRACE( ( "ReadProcessMemory(idh) failed: %d\n",GetLastError() ) ); return FALSE; } if ( idh.e_magic != IMAGE_DOS_SIGNATURE ) { //DETOUR_TRACE((" No IMAGE_DOS_SIGNATURE\n")); return FALSE; } IMAGE_NT_HEADERS inh; ZeroMemory( &inh,sizeof( inh ) ); if ( !ReadProcessMemory( hProcess,pbModule + idh.e_lfanew,&inh,sizeof( inh ),NULL ) ) { DETOUR_TRACE( ( "ReadProcessMemory(inh) failed: %d\n",GetLastError() ) ); return FALSE; } if ( inh.Signature != IMAGE_NT_SIGNATURE ) { DETOUR_TRACE( ( " No IMAGE_NT_SIGNATURE\n" ) ); return FALSE; } if ( inh.FileHeader.Characteristics & IMAGE_FILE_DLL ) { DETOUR_TRACE( ( " Characteristics: %08x\n",inh.FileHeader.Characteristics ) ); return FALSE; } return TRUE; } PVOID FindExe( HANDLE hProcess ) { MEMORY_BASIC_INFORMATION mbi; ZeroMemory( &mbi,sizeof( mbi ) ); //Find the next memory region that contains a mapped PE image. for ( PBYTE pbLast = ( PBYTE ) 0x10000; ; pbLast = ( PBYTE ) mbi.BaseAddress + mbi.RegionSize ) { if ( VirtualQueryEx( hProcess,( PVOID ) pbLast,&mbi,sizeof( mbi ) ) <= 0 ) { if ( GetLastError() == ERROR_INVALID_PARAMETER ) { break; } DETOUR_TRACE( ( "VirtualQueryEx(%08x) failed: %d\n",pbLast,GetLastError() ) ); break; } //Skip uncommitted regions and guard pages. if ( ( mbi.State != MEM_COMMIT ) || ( mbi.Protect & PAGE_GUARD ) ) { continue; } DETOUR_TRACE( ( "%8p..%8p [%8p]\n",mbi.BaseAddress,( PBYTE ) mbi.BaseAddress + mbi.RegionSize,mbi.AllocationBase ) ); if ( IsExe( hProcess,pbLast ) ) { #if DETOUR_DEBUG for ( PBYTE pbNext = ( PBYTE ) mbi.BaseAddress + mbi.RegionSize; ; pbNext = ( PBYTE ) mbi.BaseAddress + mbi.RegionSize ) { if ( VirtualQueryEx( hProcess,( PVOID ) pbNext,&mbi,sizeof( mbi ) ) <= 0 ) { if ( GetLastError() == ERROR_INVALID_PARAMETER ) { break; } DETOUR_TRACE( ( "VirtualQueryEx(%08x) failed: %d\n",pbNext,GetLastError() ) ); break; } //Skip uncommitted regions and guard pages. if ( ( mbi.State != MEM_COMMIT ) || ( mbi.Protect & PAGE_GUARD ) ) { continue; } DETOUR_TRACE( ( "%8p..%8p [%8p]\n",mbi.BaseAddress,( PBYTE ) mbi.BaseAddress + mbi.RegionSize,mbi.AllocationBase ) ); IsExe( hProcess,pbNext ); } #endif return pbLast; } } return NULL; } static BOOL UpdateImports( HANDLE hProcess , LPCSTR * plpDlls , DWORD nDlls ) { BOOL fSucceeded = FALSE; BYTE * pbNew = NULL; DETOUR_EXE_RESTORE der; DWORD i; ZeroMemory( &der,sizeof( der ) ); der.cb = sizeof( der ); PBYTE pbModule = ( PBYTE ) FindExe( hProcess ); IMAGE_DOS_HEADER idh; ZeroMemory( &idh,sizeof( idh ) ); if ( !ReadProcessMemory( hProcess,pbModule,&idh,sizeof( idh ),NULL ) ) { DETOUR_TRACE( ( "ReadProcessMemory(idh) failed: %d\n",GetLastError() ) ); finish: if ( pbNew != NULL ) { delete[] pbNew; pbNew = NULL; } return fSucceeded; } CopyMemory( &der.idh,&idh,sizeof( idh ) ); der.pidh = ( PIMAGE_DOS_HEADER ) pbModule; if ( idh.e_magic != IMAGE_DOS_SIGNATURE ) { goto finish; } IMAGE_NT_HEADERS inh; ZeroMemory( &inh,sizeof( inh ) ); if ( !ReadProcessMemory( hProcess,pbModule + idh.e_lfanew,&inh,sizeof( inh ),NULL ) ) { DETOUR_TRACE( ( "ReadProcessMemory(inh) failed: %d\n",GetLastError() ) ); goto finish; } CopyMemory( &der.inh,&inh,sizeof( inh ) ); der.pinh = ( PIMAGE_NT_HEADERS ) ( pbModule + idh.e_lfanew ); if ( inh.Signature != IMAGE_NT_SIGNATURE ) { goto finish; } if ( inh.IMPORT_DIRECTORY.VirtualAddress == 0 ) { DETOUR_TRACE( ( "No IMAGE_DIRECTORY_ENTRY_IMPORT\n" ) ); goto finish; } //Zero out the bound table so loader doesn't use it instead of our new table. inh.BOUND_DIRECTORY.VirtualAddress = 0; inh.BOUND_DIRECTORY.Size = 0; //Find the size of the mapped file. DWORD dwFileSize = 0; DWORD dwSec = idh.e_lfanew + FIELD_OFFSET( IMAGE_NT_HEADERS,OptionalHeader ) + inh.FileHeader.SizeOfOptionalHeader; for ( i = 0; i < inh.FileHeader.NumberOfSections; i++ ) { IMAGE_SECTION_HEADER ish; ZeroMemory( &ish,sizeof( ish ) ); if ( !ReadProcessMemory( hProcess,pbModule + dwSec + sizeof( ish ) * i,&ish,sizeof( ish ),NULL ) ) { DETOUR_TRACE( ( "ReadProcessMemory(inh) failed: %d\n",GetLastError() ) ); goto finish; } DETOUR_TRACE( ( "ish[%d] : va=%p sr=%d\n",i,ish.VirtualAddress,ish.SizeOfRawData ) ); //If the file didn't have an IAT_DIRECTORY, we create one... if ( inh.IAT_DIRECTORY.VirtualAddress == 0 && inh.IMPORT_DIRECTORY.VirtualAddress >= ish.VirtualAddress && inh.IMPORT_DIRECTORY.VirtualAddress < ish.VirtualAddress + ish.SizeOfRawData ) { inh.IAT_DIRECTORY.VirtualAddress = ish.VirtualAddress; inh.IAT_DIRECTORY.Size = ish.SizeOfRawData; } //Find the end of the file... if ( dwFileSize < ish.PointerToRawData + ish.SizeOfRawData ) { dwFileSize = ish.PointerToRawData + ish.SizeOfRawData; } } DETOUR_TRACE( ( "dwFileSize = %08x\n",dwFileSize ) ); //Find the current checksum. WORD wBefore = ComputeChkSum( hProcess,pbModule,&inh ); DETOUR_TRACE( ( "ChkSum: %04x + %08x => %08x\n",wBefore,dwFileSize,wBefore + dwFileSize ) ); DETOUR_TRACE( ( " Imports: %8p..%8p\n",( DWORD_PTR ) pbModule + inh.IMPORT_DIRECTORY.VirtualAddress,( DWORD_PTR ) pbModule + inh.IMPORT_DIRECTORY.VirtualAddress + inh.IMPORT_DIRECTORY.Size ) ); DWORD obRem = sizeof( IMAGE_IMPORT_DESCRIPTOR ) * nDlls; DWORD obTab = PadToDwordPtr( obRem + inh.IMPORT_DIRECTORY.Size ); DWORD obDll = obTab + sizeof( DWORD_PTR ) * 4 * nDlls; DWORD obStr = obDll; DWORD cbNew = obStr; DWORD n; for ( n = 0; n < nDlls; n++ ) { cbNew += PadToDword( ( DWORD ) strlen( plpDlls[n] ) + 1 ); } pbNew = new BYTE[cbNew]; if ( pbNew == NULL ) { DETOUR_TRACE( ( "new BYTE [cbNew] failed.\n" ) ); goto finish; } ZeroMemory( pbNew,cbNew ); PBYTE pbBase = pbModule; PBYTE pbNext = pbBase + inh.OptionalHeader.BaseOfCode + inh.OptionalHeader.SizeOfCode + inh.OptionalHeader.SizeOfInitializedData + inh.OptionalHeader.SizeOfUninitializedData; if ( pbBase < pbNext ) { pbBase = pbNext; } DETOUR_TRACE( ( "pbBase = %p\n",pbBase ) ); PBYTE pbNewIid = FindAndAllocateNearBase( hProcess,pbBase,cbNew ); if ( pbNewIid == NULL ) { DETOUR_TRACE( ( "FindAndAllocateNearBase failed.\n" ) ); goto finish; } DWORD dwProtect = 0; der.impDirProt = 0; if ( !VirtualProtectEx( hProcess,pbModule + inh.IMPORT_DIRECTORY.VirtualAddress,inh.IMPORT_DIRECTORY.Size,PAGE_EXECUTE_READWRITE,&dwProtect ) ) { DETOUR_TRACE( ( "VirtualProtextEx(import) write failed: %d\n",GetLastError() ) ); goto finish; } DETOUR_TRACE( ( "IMPORT_DIRECTORY perms=%x\n",dwProtect ) ); der.impDirProt = dwProtect; DWORD obBase = ( DWORD ) ( pbNewIid - pbModule ); if ( !ReadProcessMemory( hProcess,pbModule + inh.IMPORT_DIRECTORY.VirtualAddress,pbNew + obRem,inh.IMPORT_DIRECTORY.Size,NULL ) ) { DETOUR_TRACE( ( "ReadProcessMemory(imports) failed: %d\n",GetLastError() ) ); goto finish; } PIMAGE_IMPORT_DESCRIPTOR piid = ( PIMAGE_IMPORT_DESCRIPTOR ) pbNew; DWORD_PTR * pt; for ( n = 0; n < nDlls; n++ ) { HRESULT hrRet = StringCchCopyA( ( char * ) pbNew + obStr,cbNew - obStr,plpDlls[n] ); if ( FAILED( hrRet ) ) { DETOUR_TRACE( ( "StringCchCopyA failed: %d\n",GetLastError() ) ); goto finish; } DWORD nOffset = obTab + ( sizeof( DWORD_PTR ) * ( 4 * n ) ); piid[n].OriginalFirstThunk = obBase + nOffset; pt = ( ( DWORD_PTR * ) ( pbNew + nOffset ) ); pt[0] = IMAGE_ORDINAL_FLAG + 1; pt[1] = 0; nOffset = obTab + ( sizeof( DWORD_PTR ) * ( ( 4 * n ) + 2 ) ); piid[n].FirstThunk = obBase + nOffset; pt = ( ( DWORD_PTR * ) ( pbNew + nOffset ) ); pt[0] = IMAGE_ORDINAL_FLAG + 1; pt[1] = 0; piid[n].TimeDateStamp = 0; piid[n].ForwarderChain = 0; piid[n].Name = obBase + obStr; obStr += PadToDword( ( DWORD ) strlen( plpDlls[n] ) + 1 ); } for ( i = 0; i < nDlls + ( inh.IMPORT_DIRECTORY.Size / sizeof( *piid ) ); i++ ) { 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 ) ); if ( piid[i].OriginalFirstThunk == 0 && piid[i].FirstThunk == 0 ) { break; } } if ( !WriteProcessMemory( hProcess,pbNewIid,pbNew,obStr,NULL ) ) { DETOUR_TRACE( ( "WriteProcessMemory(iid) failed: %d\n",GetLastError() ) ); goto finish; } DETOUR_TRACE( ( "obBase = %p..%p\n",inh.IMPORT_DIRECTORY.VirtualAddress,inh.IMPORT_DIRECTORY.VirtualAddress + inh.IMPORT_DIRECTORY.Size ) ); DETOUR_TRACE( ( "obBase = %p..%p\n",obBase,obBase + obStr ) ); inh.IMPORT_DIRECTORY.VirtualAddress = obBase; inh.IMPORT_DIRECTORY.Size = cbNew; //Update the CLR header. if ( inh.CLR_DIRECTORY.VirtualAddress != 0 && inh.CLR_DIRECTORY.Size != 0 ) { DETOUR_CLR_HEADER clr; PBYTE pbClr = pbModule + inh.CLR_DIRECTORY.VirtualAddress; if ( !ReadProcessMemory( hProcess,pbClr,&clr,sizeof( clr ),NULL ) ) { DETOUR_TRACE( ( "ReadProcessMemory(clr) failed: %d\n",GetLastError() ) ); goto finish; } der.pclrFlags = ( PULONG ) ( pbClr + offsetof( DETOUR_CLR_HEADER,Flags ) ); der.clrFlags = clr.Flags; clr.Flags &= 0xfffffffe; //Clear the IL_ONLY flag. if ( !VirtualProtectEx( hProcess,pbClr,sizeof( clr ),PAGE_READWRITE,&dwProtect ) ) { DETOUR_TRACE( ( "VirtualProtextEx(clr) write failed: %d\n",GetLastError() ) ); goto finish; } if ( !WriteProcessMemory( hProcess,pbClr,&clr,sizeof( clr ),NULL ) ) { DETOUR_TRACE( ( "WriteProcessMemory(clr) failed: %d\n",GetLastError() ) ); goto finish; } if ( !VirtualProtectEx( hProcess,pbClr,sizeof( clr ),dwProtect,&dwProtect ) ) { DETOUR_TRACE( ( "VirtualProtextEx(clr) restore failed: %d\n",GetLastError() ) ); goto finish; } } //Update the NT header for the import new directory. //Update the DOS header to fix the checksum. if ( !VirtualProtectEx( hProcess,pbModule,inh.OptionalHeader.SizeOfHeaders,PAGE_EXECUTE_READWRITE,&dwProtect ) ) { DETOUR_TRACE( ( "VirtualProtextEx(inh) write failed: %d\n",GetLastError() ) ); goto finish; } idh.e_res[0] = 0; if ( !WriteProcessMemory( hProcess,pbModule,&idh,sizeof( idh ),NULL ) ) { DETOUR_TRACE( ( "WriteProcessMemory(idh) failed: %d\n",GetLastError() ) ); goto finish; } if ( !WriteProcessMemory( hProcess,pbModule + idh.e_lfanew,&inh,sizeof( inh ),NULL ) ) { DETOUR_TRACE( ( "WriteProcessMemory(inh) failed: %d\n",GetLastError() ) ); goto finish; } WORD wDuring = ComputeChkSum( hProcess,pbModule,&inh ); DETOUR_TRACE( ( "ChkSum: %04x + %08x => %08x\n",wDuring,dwFileSize,wDuring + dwFileSize ) ); idh.e_res[0] = detour_sum_minus( idh.e_res[0],detour_sum_minus( wDuring,wBefore ) ); if ( !WriteProcessMemory( hProcess,pbModule,&idh,sizeof( idh ),NULL ) ) { DETOUR_TRACE( ( "WriteProcessMemory(idh) failed: %d\n",GetLastError() ) ); goto finish; } if ( !VirtualProtectEx( hProcess,pbModule,inh.OptionalHeader.SizeOfHeaders,dwProtect,&dwProtect ) ) { DETOUR_TRACE( ( "VirtualProtextEx(idh) restore failed: %d\n",GetLastError() ) ); goto finish; } WORD wAfter = ComputeChkSum( hProcess,pbModule,&inh ); DETOUR_TRACE( ( "ChkSum: %04x + %08x => %08x\n",wAfter,dwFileSize,wAfter + dwFileSize ) ); DETOUR_TRACE( ( "Before: %08x, After: %08x\n",wBefore + dwFileSize,wAfter + dwFileSize ) ); if ( wBefore != wAfter ) { DETOUR_TRACE( ( "Restore of checksum failed %04x != %04x.\n",wBefore,wAfter ) ); goto finish; } if ( !DetourCopyPayloadToProcess( hProcess,DETOUR_EXE_RESTORE_GUID,&der,sizeof( der ) ) ) { DETOUR_TRACE( ( "DetourCopyPayloadToProcess failed: %d\n",GetLastError() ) ); goto finish; } fSucceeded = TRUE; goto finish; } 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 ) { DWORD dwMyCreationFlags = ( dwCreationFlags | CREATE_SUSPENDED ); PROCESS_INFORMATION pi; if ( pfCreateProcessA == NULL ) { pfCreateProcessA = CreateProcessA; } if ( !pfCreateProcessA( lpApplicationName,lpCommandLine,lpProcessAttributes,lpThreadAttributes,bInheritHandles,dwMyCreationFlags,lpEnvironment,lpCurrentDirectory,lpStartupInfo,&pi ) ) { return FALSE; } LPCSTR rlpDlls[2]; DWORD nDlls = 0; if ( lpDetouredDllFullName != NULL ) { rlpDlls[nDlls++] = lpDetouredDllFullName; } if ( lpDllName != NULL ) { rlpDlls[nDlls++] = lpDllName; } if ( !UpdateImports( pi.hProcess,rlpDlls,nDlls ) ) { return FALSE; } if ( lpProcessInformation ) { CopyMemory( lpProcessInformation,&pi,sizeof( pi ) ); } if ( !( dwCreationFlags & CREATE_SUSPENDED ) ) { ResumeThread( pi.hThread ); } return TRUE; } 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 ) { DWORD dwMyCreationFlags = ( dwCreationFlags | CREATE_SUSPENDED ); PROCESS_INFORMATION pi; if ( pfCreateProcessW == NULL ) { pfCreateProcessW = CreateProcessW; } if ( !pfCreateProcessW( lpApplicationName,lpCommandLine,lpProcessAttributes,lpThreadAttributes,bInheritHandles,dwMyCreationFlags,lpEnvironment,lpCurrentDirectory,lpStartupInfo,&pi ) ) { return FALSE; } LPCSTR rlpDlls[2]; DWORD nDlls = 0; if ( lpDetouredDllFullName != NULL ) { rlpDlls[nDlls++] = lpDetouredDllFullName; } if ( lpDllName != NULL ) { rlpDlls[nDlls++] = lpDllName; } if ( !UpdateImports( pi.hProcess,rlpDlls,nDlls ) ) { return FALSE; } if ( lpProcessInformation ) { CopyMemory( lpProcessInformation,&pi,sizeof( pi ) ); } if ( !( dwCreationFlags & CREATE_SUSPENDED ) ) { ResumeThread( pi.hThread ); } return TRUE; } BOOL WINAPI DetourCopyPayloadToProcess( HANDLE hProcess , REFGUID rguid , PVOID pData , DWORD cbData ) { DWORD cbTotal = ( sizeof( IMAGE_DOS_HEADER ) + sizeof( IMAGE_NT_HEADERS ) + sizeof( IMAGE_SECTION_HEADER ) + sizeof( DETOUR_SECTION_HEADER ) + sizeof( DETOUR_SECTION_RECORD ) + cbData ); PBYTE pbBase = ( PBYTE ) VirtualAllocEx( hProcess,NULL,cbTotal,MEM_COMMIT,PAGE_READWRITE ); if ( pbBase == NULL ) { DETOUR_TRACE( ( "VirtualAllocEx(%d) failed: %d\n",cbTotal,GetLastError() ) ); return FALSE; } PBYTE pbTarget = pbBase; IMAGE_DOS_HEADER idh; IMAGE_NT_HEADERS inh; IMAGE_SECTION_HEADER ish; DETOUR_SECTION_HEADER dsh; DETOUR_SECTION_RECORD dsr; SIZE_T cbWrote = 0; ZeroMemory( &idh,sizeof( idh ) ); idh.e_magic = IMAGE_DOS_SIGNATURE; idh.e_lfanew = sizeof( idh ); if ( !WriteProcessMemory( hProcess,pbTarget,&idh,sizeof( idh ),&cbWrote ) || cbWrote != sizeof( idh ) ) { DETOUR_TRACE( ( "WriteProcessMemory(idh) failed: %d\n",GetLastError() ) ); return FALSE; } pbTarget += sizeof( idh ); ZeroMemory( &inh,sizeof( inh ) ); inh.Signature = IMAGE_NT_SIGNATURE; inh.FileHeader.SizeOfOptionalHeader = sizeof( inh.OptionalHeader ); inh.FileHeader.Characteristics = IMAGE_FILE_DLL; inh.FileHeader.NumberOfSections = 1; if ( !WriteProcessMemory( hProcess,pbTarget,&inh,sizeof( inh ),&cbWrote ) || cbWrote != sizeof( inh ) ) { return FALSE; } pbTarget += sizeof( inh ); ZeroMemory( &ish,sizeof( ish ) ); memcpy( ish.Name,".detour",sizeof( ish.Name ) ); ish.VirtualAddress = ( DWORD ) ( ( pbTarget + sizeof( ish ) ) - pbBase ); ish.SizeOfRawData = ( sizeof( DETOUR_SECTION_HEADER ) + sizeof( DETOUR_SECTION_RECORD ) + cbData ); if ( !WriteProcessMemory( hProcess,pbTarget,&ish,sizeof( ish ),&cbWrote ) || cbWrote != sizeof( ish ) ) { return FALSE; } pbTarget += sizeof( ish ); ZeroMemory( &dsh,sizeof( dsh ) ); dsh.cbHeaderSize = sizeof( dsh ); dsh.nSignature = DETOUR_SECTION_HEADER_SIGNATURE; dsh.nDataOffset = sizeof( DETOUR_SECTION_HEADER ); dsh.cbDataSize = ( sizeof( DETOUR_SECTION_HEADER ) + sizeof( DETOUR_SECTION_RECORD ) + cbData ); if ( !WriteProcessMemory( hProcess,pbTarget,&dsh,sizeof( dsh ),&cbWrote ) || cbWrote != sizeof( dsh ) ) { return FALSE; } pbTarget += sizeof( dsh ); ZeroMemory( &dsr,sizeof( dsr ) ); dsr.cbBytes = cbData + sizeof( DETOUR_SECTION_RECORD ); dsr.nReserved = 0; dsr.guid = rguid; if ( !WriteProcessMemory( hProcess,pbTarget,&dsr,sizeof( dsr ),&cbWrote ) || cbWrote != sizeof( dsr ) ) { return FALSE; } pbTarget += sizeof( dsr ); if ( !WriteProcessMemory( hProcess,pbTarget,pData,cbData,&cbWrote ) || cbWrote != cbData ) { return FALSE; } pbTarget += cbData; DETOUR_TRACE( ( "Copied %d bytes into target process at %p\n",cbTotal,pbTarget - cbTotal ) ); return TRUE; }