解析重定位表


1.創建一個用來試驗的目標dll
頭文件:
#if !defined(AFX_HELLO_H__87AA4900_2935_4604_AFB2_7CD004B103D8__INCLUDED_)
#define AFX_HELLO_H__87AA4900_2935_4604_AFB2_7CD004B103D8__INCLUDED_
 
#if _MSC_VER > 1000
#pragma once
#endif 
 
#include "stdio.h"
#define ONE "hello"
#define TWO "Jim"
 
extern "C" _declspec(dllexport) void __stdcall hello();    //導出函數
 
#endif 
實現:
#include "Hello.h"
#define THREE "nice to meet you"
 
void __stdcall hello(){
    printf("%s %s %s",ONE,TWO,THREE);
}
 
該dll提供一個函數hello();作用是輸出“hello jim nice to meet you”;
 
在main中測試dll:
    復制編譯后生成的.lib和.dll文件到測試工程目錄下;
    導入dll,這里使用靜態導入;
    使用dll中的函數;
代碼:
#include <stdio.h>
#pragma comment(lib, "HelloDll.lib")    //加載dll
extern "C" __declspec(dllimport) void __stdcall hello();    //引入dll中的函數
 
int main(){
    hello();    //使用dll中的函數
    getchar();
}
結果:
    
 
2.手動查重定向表
用winhex打開dll;
重定向表在可選pe頭最后的一個結構數組中;
該結構數組有16個結構,每個結構各兩個元素,各占4位;前4位表示RVA地址;
重定向表為第6個結構;
查找技巧:可以看到右邊的注釋,找到.text很明顯是節表開始的地方;
    .text前面就是可選pe頭的結尾;可選pe頭最后的結構數組也就是數據目錄占8X16個字節,也就是往上數8行即可找到數據目錄開始的地方;
    找到第6個結構,可以看到:重定向表的RVA是37000;
 
將RVA轉為FOA;
用pe工具打開節表信息,可以看到37000對應的FOA正好是35000;
因為37000是.reloc節的開始處;也就是找文件中.reloc節偏移為0的地方,可以看到是35000;
 
繼續看winhex,35000處就是重定向表開始的地方:
可以看到重定向表有多個塊;
第一個塊的VirtualAddress是1000;SizeOfBlock是D8;
也就是說,到350D8之后就是下一個重定位表,VirtualAddress為2000,SizeOfBlock是1000;
以此類推,直到VirtualAddress和SizeOfBlock都是0的時候也就是最后一個重定位表;
 
3.用程序解析重定位表
大體思路:
    將dll讀入內存;
    通過可選pe頭獲取重定位表的RVA,因為實在文件鏡像中操作,需要將RVA轉為FOA;
    通過FOA找到重定位表;
    循環解析重定位表的每一個塊,判斷最后一個重定位表的條件是VirtualAddress和SizeOfBlock都是0;
    在每個塊中循環輸出每個可能需要修改的地址的RVA;RVA=的VirtualAddress + 具體項的后12位;
    具體項的個數 = (SizeOfBlock - 8)/2,也就是循環這些次數;
    具體項的高4位表示是否為有效具體項,如果是3則表示有效,需要標記出來;
 
代碼:
#include "stdafx.h"
#include "PeTool.h"
 
#define SRC "C:\\Users\\Administrator\\Desktop\\HelloDll.dll"
 
//打印重定位表信息
void printRelocInfo(){
    //定義pe頭結構指針
    PIMAGE_DOS_HEADER dosHeader = NULL;        //dos頭指針
    PIMAGE_FILE_HEADER peHeader = NULL;        //pe頭指針
    PIMAGE_OPTIONAL_HEADER32 opHeader = NULL;    //可選pe頭指針
    PIMAGE_DATA_DIRECTORY dataDir = NULL;        //數據目錄指針
    PIMAGE_BASE_RELOCATION relocDir= NULL;                //重定位表指針
 
    //1.將dll讀入內存
    LPVOID  pFileBuffer = NULL;
    ReadPEFile(SRC, &pFileBuffer);
    if(!pFileBuffer){
        printf("讀取Dll失敗\n");
        return;
    }
 
    //2.找到重定位表
    dosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
    if(dosHeader->e_magic != IMAGE_DOS_SIGNATURE){
        printf("不是有效MZ標記\n");
        free(pFileBuffer);
        return;
    }
    if(*((PDWORD)((DWORD)pFileBuffer + dosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE){
        printf("不是有效PE標記\n");
        free(pFileBuffer);
        return;
    }
    peHeader = (PIMAGE_FILE_HEADER) ((DWORD)pFileBuffer + dosHeader->e_lfanew + 4);
    opHeader = (PIMAGE_OPTIONAL_HEADER32) ((DWORD)peHeader + IMAGE_SIZEOF_FILE_HEADER);
    dataDir = opHeader ->DataDirectory;
    if(!((dataDir + 5)->VirtualAddress)){
        printf("該pe文件沒有重定位表\n");
        free(pFileBuffer);
        return;
    }
    relocDir = (PIMAGE_BASE_RELOCATION)((DWORD)pFileBuffer + RvaToFileOffset(pFileBuffer, (dataDir + 5)->VirtualAddress));
 
    //3.循環解析重定位表
    int i = 0;
    while(relocDir->SizeOfBlock){    //重定位表的塊大小為0時是最后一個塊
        printf("*************第%d個重定位表塊************\n", i+1);
        printf("VirtualAddress:%x\n",relocDir->VirtualAddress);
        printf("SizeOfBlock:%x\n",relocDir->SizeOfBlock);
        printf("#####要修改的地址#####\n");
        printf("RVA\t前4位的值\n");
        //獲取具體項的數量
        int j = (relocDir->SizeOfBlock -8)/2;
 
        //循環解析每個具體項
        PWORD item = (PWORD)((DWORD)relocDir + 8);
        for(int k=0;k<j;k++){
            //獲取具體項低12位
            WORD low = item[k] & 0x0fff;
            //獲取高4位的值
            WORD hig = (item[k] & 0xf000) >> 12;
 
 
            DWORD rva = (DWORD)low + relocDir->VirtualAddress;
            printf("%x\t%d\n",rva,hig);
        }
 
        //找到下一個塊
        relocDir = (PIMAGE_BASE_RELOCATION) ((DWORD)relocDir + relocDir->SizeOfBlock);
        i++;
    }
 
    //4.釋放內存
    free(pFileBuffer);
    return;
}
 
int main(int argc, char* argv[])
{
    printRelocInfo();
    getchar();
}
結果:
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM