學習重定位程式非常棒的範例
直接上Code給大家學習囉
// 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;
}