代码:
// 11-Nov-2008 Create by Benyanwk // Enviroment: Windows all platfrom. // Note: (1) Do not support x64 // (2) Do not support file large than 4GB. // (3) Do not use SEH. // Revision: // 11-Nov-2008 ver1.0 #define UNICODE #include <windows.h> #include <winnt.h> // include PE file header definition. #include <stdio.h> LPCTSTR GetErrMsg(void); DWORD GetSectionsInfo( PVOID pFile, PIMAGE_SECTION_HEADER *pSections ); DWORD Reloc( HANDLE hFile, ULONG BaseAddr ); BOOL RelocFile( PVOID pFile, ULONG BaseAddr ); DWORD RvaToFileOff( PVOID pFile, DWORD Rva ); BOOL VerifyPE( PVOID pFile ); ULONG char2ul(char *lpUlNum); int main( int argc, char *argv[] ) { LPCTSTR lpErrMsg; HANDLE hFile; // // Check the arguments // if( argc != 4 ) { wprintf( L"Usage: \n" ); wprintf( L"rebase -b baseaddr filepath \n"); return 1; // indicate argument error } if( strcmp( argv[1], "-b" ) != 0 ) { wprintf( L"Usage: \n" ); wprintf( L"rebase -b baseaddr filepath \n"); return 1; } // // Check the File (existence) // char *lpFilePath = argv[3]; hFile = CreateFileA( lpFilePath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, (LPSECURITY_ATTRIBUTES)NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL ); if( hFile == INVALID_HANDLE_VALUE ) { lpErrMsg = GetErrMsg(); wsprintf( L"CreateFile Failed!errorcode = %s", lpErrMsg ); LocalFree( (HLOCAL)lpErrMsg ); return 2; // indicate open file error } // // Get the base address // ULONG ulBaseAddr = char2ul( argv[2] ); // // Reloc the file // if( Reloc( hFile, ulBaseAddr ) != 0 ) { wprintf( L" Reloc file failed! I'm sorry \n" ); CloseHandle( hFile ); return 3; // indicate reloc error } return 0; // indicate success } LPCTSTR GetErrMsg(void) { DWORD dwErrCode; LPCTSTR lpErrMsg; dwErrCode = GetLastError(); FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, (LPCVOID)NULL, dwErrCode, MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL ), (LPWSTR)&lpErrMsg, 0, NULL ); return lpErrMsg; } DWORD Reloc( HANDLE hFile, ULONG BaseAddr ) { DWORD dwFileSize; HGLOBAL pFile; // HGLOBAL = HANDLE = void* = LPVOID DWORD dwReturnBytes; LPCTSTR lpErrMsg; // // Read the File to memory // dwFileSize = GetFileSize( hFile, NULL ); pFile = GlobalAlloc( GMEM_FIXED, (SIZE_T)dwFileSize ); if( ReadFile( hFile, pFile, dwFileSize, &dwReturnBytes, (LPOVERLAPPED)NULL ) == 0 ) { lpErrMsg = GetErrMsg(); wprintf( L"ReadFile failed! error message = %s", lpErrMsg ); GlobalFree( hFile ); // // indicate read file error. // return 1; } // // Verify PE file // if( VerifyPE( pFile ) == FALSE ) { wprintf( L" this is not a PE file \n"); GlobalFree( pFile ); return 1; // indicate not pe file } // // Reloc PE file // if( RelocFile( pFile, BaseAddr ) != TRUE ) { wprintf( L" reloc PE file failed!\n"); GlobalFree( pFile ); return 2; // indicate reloc pe file failed; } // // Jmp to the begining of the PE file // SetFilePointer( hFile, 0, (PLONG)NULL, FILE_BEGIN ); // // Write back the file // if( WriteFile( hFile, pFile, dwFileSize, &dwReturnBytes, (LPOVERLAPPED)NULL ) == 0 ) { lpErrMsg = GetErrMsg(); wprintf( L" WriteFile failed! %s\n", lpErrMsg ); GlobalFree( pFile ); CloseHandle( hFile ); return 3; // indicate write file failed! } GlobalFree( pFile ); CloseHandle( hFile ); printf(" Yes you get it\n" ); return 0; // indicate success } DWORD RvaToFileOff( PVOID pFile, DWORD Rva ) { /*++ Routine Name: RvaToFileOffset Description: Translate the Relative Virtual Address to Raw File Offset Arugments: File Map; Rva; Return: File Offset --*/ static DWORD dwSections; DWORD i; static PIMAGE_SECTION_HEADER pSections; ULONG ulDiffer = 0; static BOOL bFunExecute = FALSE; // GetSectionInfo should only execute once.(?) if( bFunExecute == FALSE ) { dwSections = GetSectionsInfo( pFile, &pSections ); bFunExecute = TRUE; } for ( i = 0; i < dwSections; i++ ) { if( (Rva >= pSections[i].VirtualAddress) && (Rva <= (pSections[i].VirtualAddress + pSections[i].Misc.VirtualSize)) ) { // // indicate in the this section. // ulDiffer = pSections[i].VirtualAddress - pSections[i].PointerToRawData; break; } } return (Rva - ulDiffer); } DWORD GetSectionsInfo( PVOID pFile, PIMAGE_SECTION_HEADER *pSections ) /* Return number of sections Return pointer to sections table */ { DWORD dwSections; PIMAGE_SECTION_HEADER hSections; // // Jump to section table // PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFile; PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PCHAR)pFile + pDosHeader->e_lfanew); // e_lfanew + 0x3c dwSections = pNtHeader->FileHeader.NumberOfSections; // NumberOfSections + 0x02 // // Allocate the memory for section table // hSections = (PIMAGE_SECTION_HEADER)GlobalAlloc( GMEM_FIXED, dwSections*sizeof(IMAGE_SECTION_HEADER) ); // // Copy the section table information // PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)(++pNtHeader); memcpy( (PVOID)hSections, (PVOID)pSectionHeader, (SIZE_T)dwSections*sizeof(IMAGE_SECTION_HEADER) ); *pSections = hSections; return dwSections; } BOOL VerifyPE( PVOID pFile ) { PIMAGE_DOS_HEADER pDosHeader; PIMAGE_NT_HEADERS pNtHeader; pDosHeader = (PIMAGE_DOS_HEADER)pFile; if ( pDosHeader->e_magic != 0x5A4D ) // compare with 'MZ' return FALSE; pNtHeader = (PIMAGE_NT_HEADERS)((PCHAR)pFile + pDosHeader->e_lfanew); // e_lfanew + 0x3c if ( pNtHeader->Signature != 0x00004550 ) // compare with 'PE\0\0' return FALSE; return TRUE; } ULONG char2ul(char* lpUlNum) { ULONG ulSum = 0; while(*lpUlNum) { if(*lpUlNum>='0' && *lpUlNum<='9') *lpUlNum = *lpUlNum - '0'; else if(*lpUlNum>='A' && *lpUlNum<='F') *lpUlNum = *lpUlNum - 'A' + 10; else *lpUlNum = *lpUlNum - 'a' + 10; ulSum = ulSum*16 + *lpUlNum; lpUlNum++; } return ulSum; } BOOL RelocFile( PVOID pFile, ULONG BaseAddr ) { PIMAGE_NT_HEADERS pNtHeader; PIMAGE_DOS_HEADER pDosHeader; DWORD dwImageBase; DWORD pRelocAddr,dwRelocAddr; DWORD dwDiffer; PWORD pType; PIMAGE_RELOCATION pRelocBlock; pDosHeader = (PIMAGE_DOS_HEADER)pFile; pNtHeader = (PIMAGE_NT_HEADERS)((PCHAR)pFile + pDosHeader->e_lfanew); // e_lfanew + 0x3c dwImageBase = pNtHeader->OptionalHeader.ImageBase; dwDiffer = dwImageBase - BaseAddr; // pay attention to the order // Get reloc table RVA PIMAGE_DATA_DIRECTORY pRelocTable = (PIMAGE_DATA_DIRECTORY) pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress; // Get reloc table File Offset pRelocBlock = (PIMAGE_RELOCATION)( (PCHAR)pFile + RvaToFileOff( pFile, (DWORD)pRelocTable ) ); // the pRelocTable is file offset? do { pType = &pRelocBlock->Type; do { // Get reloc address's RVA if( ( *pType && 0x3000) == 0 ) { if( ( *pType && 0xf000) == 0 ) continue; return TRUE; } pRelocAddr = pRelocBlock->VirtualAddress + (*pType & 0x0fff); // pRelocAddr += dwImageBase; // Get reloc address's File Offset pRelocAddr = RvaToFileOff( pFile, pRelocAddr ); // DWORD test = pRelocAddr; // Go to the Buffer offset pRelocAddr += (DWORD)pFile; // Get the reloc address dwRelocAddr = *(PDWORD)pRelocAddr; // Calculate the new address dwRelocAddr -= dwDiffer; // Copy to the file *(PDWORD)pRelocAddr = dwRelocAddr; } while( ++pType < (PWORD)((PCHAR)pRelocBlock + pRelocBlock->SymbolTableIndex) ); pRelocBlock = (PIMAGE_RELOCATION)((PCHAR)pRelocBlock + pRelocBlock->SymbolTableIndex ); } while( pRelocBlock->VirtualAddress != 0 );// loop the reloc block entry pNtHeader->OptionalHeader.ImageBase = BaseAddr; return TRUE; }