2011年5月18日 星期三

重定位程式的實現Code

學習重定位程式非常棒的範例


 


直接上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]; 


 


    hFileCreateFileA(  


                    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



 


 


沒有留言:

張貼留言