解析重定位表

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();
}
结果:
 
 
 
posted @ 2019-11-09 13:00  L丶银甲闪闪  阅读(1268)  评论(0编辑  收藏  举报