滴水导出表

这篇文章详细介绍了如何解析PE文件,包括计算文件偏移地址(FOA)从相对虚拟地址(RVA),以及查找和获取DLL导出函数地址的方法。主要涉及了IMAGE_DOS_HEADER,IMAGE_NT_HEADERS等结构体,以及rvaTofoa函数的实现。
摘要由CSDN通过智能技术生成
#include<iostream>
#include<malloc.h>
#include<Windows.h>
#include<tchar.h>
#include<string.h>
//#pragma comment(lib,"Dll3.lib")
#pragma warning(disable:4996)
//extern "C" _declspec(dllimport) int sum(int x, int y);
typedef int (*lpsum)(int, int);
using namespace std;
int filelen(FILE* pfile)
{
    fseek(pfile, 0, SEEK_END);
    int result = ftell(pfile);
    rewind(pfile);
    return result;
}
int Align(int x, int y)
{
    if (x % y == 0)
    {
        return int(x / y)*y;
    }
    else
    {
        return int(x / y)*y + y;
    }
}
int rvaTofoa(int rva, char* buffer)
{
    PIMAGE_DOS_HEADER pDosH = (PIMAGE_DOS_HEADER)(buffer);
    PIMAGE_NT_HEADERS pNTH = (PIMAGE_NT_HEADERS)(buffer + pDosH->e_lfanew);
    PIMAGE_FILE_HEADER pFH = (PIMAGE_FILE_HEADER)((char*)pNTH + 0x4);
    PIMAGE_OPTIONAL_HEADER pOH = (PIMAGE_OPTIONAL_HEADER)((char*)pFH + 0x14);
    int opHeaderLen = int(pFH->SizeOfOptionalHeader);
    PIMAGE_SECTION_HEADER pSecH = (PIMAGE_SECTION_HEADER)((char*)pOH + opHeaderLen);
    if (rva <= pOH->SizeOfHeaders)
    {
        return rva;
    }
    else
    {
        for (int i = 0; i < pFH->NumberOfSections; i++)
        {
            if ((rva > pSecH[i].VirtualAddress) &&( rva <  pSecH[i].VirtualAddress + pSecH[i].Misc.VirtualSize))
            {
                return rva - pSecH[i].VirtualAddress + pSecH[i].PointerToRawData;
            }
        }
    }
    printf(" rvaTofoa error\r\n");
    return 0;
}
/*
    typedef struct _IMAGE_EXPORT_DIRECTORY {
        DWORD   Characteristics;                // 未使用
        DWORD   TimeDateStamp;                // 时间戳
        WORD    MajorVersion;                // 未使用
        WORD    MinorVersion;                // 未使用
        DWORD   Name;                // 指向该导出表文件名字符串
        DWORD   Base;                // 导出函数起始序号
        DWORD   NumberOfFunctions;                // 所有导出函数的个数
        DWORD   NumberOfNames;                // 以函数名字导出的函数个数
        DWORD   AddressOfFunctions;     // 导出函数地址表RVA
        DWORD   AddressOfNames;         // 导出函数名称表RVA
        DWORD   AddressOfNameOrdinals;  // 导出函数序号表RVA
    } IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

*/
void printExportDir(PIMAGE_EXPORT_DIRECTORY pED,char* buffer)
{
    int nameFAddress = rvaTofoa(pED->Name, buffer);
    char* name = buffer + nameFAddress;
    printf("导出表文件名字为:%s\r\n", name);
    printf("Characteristics:  %08x\r\n", pED->Characteristics);
    printf("TimeDateStamp:  %08x\r\n", pED->TimeDateStamp);
    printf("MajorVersion:  %04x\r\n", pED->MajorVersion);
    printf("MinorVersion:  %04x\r\n", pED->MinorVersion);
    printf("Name:  %08x\r\n", pED->Name);
    printf("Base:  %08x\r\n", pED->Base);
    printf("NumberOfFunctions:  %08x\r\n", pED->NumberOfFunctions);
    printf("NumberOfNames:  %08x\r\n", pED->NumberOfNames);
    printf("AddressOfFunctions:  %08x\r\n", pED->AddressOfFunctions);
    printf("AddressOfNames:  %08x\r\n", pED->AddressOfNames);
    printf("AddressOfNameOrdinals:  %08x\r\n", pED->AddressOfNameOrdinals);
}
int GetFunctionAddrByName(char* buffer, char* name)
{
    PIMAGE_DOS_HEADER pDosH = (PIMAGE_DOS_HEADER)(buffer);
    PIMAGE_NT_HEADERS pNTH = (PIMAGE_NT_HEADERS)(buffer + pDosH->e_lfanew);
    PIMAGE_FILE_HEADER pFH = (PIMAGE_FILE_HEADER)((char*)pNTH + 0x4);
    PIMAGE_OPTIONAL_HEADER pOH = (PIMAGE_OPTIONAL_HEADER)((char*)pFH + 0x14);
    int opHeaderLen = int(pFH->SizeOfOptionalHeader);
    PIMAGE_SECTION_HEADER pSecH = (PIMAGE_SECTION_HEADER)((char*)pOH + opHeaderLen);
    PIMAGE_DATA_DIRECTORY pDD = (PIMAGE_DATA_DIRECTORY)(pOH->DataDirectory);
    int exportVAddress = pDD->VirtualAddress;
    //printf("%08x\r\n", exportAddress);
    int exportFAddress = rvaTofoa(exportVAddress, buffer);
    PIMAGE_EXPORT_DIRECTORY pED = (PIMAGE_EXPORT_DIRECTORY)(buffer + exportFAddress);
    //先在DWORD   AddressOfNames; // 导出函数名称表RVA中寻找
    int* FAddressOfNames = (int*)(rvaTofoa(pED->AddressOfNames,buffer)+buffer);//先得到函数名表在文件中的地址
    printf("函数名表在文件中的地址%08x\r\n", rvaTofoa(pED->AddressOfNames, buffer));
    int num = -1;
    for (int i = 0; i < pED->NumberOfNames; i++)
    {
        //从中取出函数名的rva地址
        int rvaOfname = (int) * (FAddressOfNames + i);
        //转化为函数名在文件中地址
        char* fileOfname = (char*)(buffer + rvaTofoa(rvaOfname, buffer));
        printf("%s\r\n", fileOfname);
        if (strcmp(fileOfname, name) == 0)
        {
            num = i;
            break;
        }
    }
    printf("%d\r\n", num);
    //用获得的索引从序号表中找函数的序号 此处易错类型为word
    WORD ord = *((WORD*)(rvaTofoa(pED->AddressOfNameOrdinals,buffer) + buffer) + num);
    printf("%d\r\n", ord);
    //用查到的序号查函数地址
    int add = *((int*)(rvaTofoa(pED->AddressOfFunctions,buffer) + buffer) + ord);
    return add;
}
int GetFunctionAddrByOrdinals(char* buffer, int num)
{
    PIMAGE_DOS_HEADER pDosH = (PIMAGE_DOS_HEADER)(buffer);
    PIMAGE_NT_HEADERS pNTH = (PIMAGE_NT_HEADERS)(buffer + pDosH->e_lfanew);
    PIMAGE_FILE_HEADER pFH = (PIMAGE_FILE_HEADER)((char*)pNTH + 0x4);
    PIMAGE_OPTIONAL_HEADER pOH = (PIMAGE_OPTIONAL_HEADER)((char*)pFH + 0x14);
    int opHeaderLen = int(pFH->SizeOfOptionalHeader);
    PIMAGE_SECTION_HEADER pSecH = (PIMAGE_SECTION_HEADER)((char*)pOH + opHeaderLen);
    PIMAGE_DATA_DIRECTORY pDD = (PIMAGE_DATA_DIRECTORY)(pOH->DataDirectory);
    int exportVAddress = pDD->VirtualAddress;
    int exportFAddress = rvaTofoa(exportVAddress, buffer);
    PIMAGE_EXPORT_DIRECTORY pED = (PIMAGE_EXPORT_DIRECTORY)(buffer + exportFAddress);
    int ordbase = pED->Base;
    int ord = num - ordbase;
    int add = *((int*)(rvaTofoa(pED->AddressOfFunctions, buffer) + buffer) + ord);
    return add;
}

int main()
{
    FILE* pfile = fopen("C://Users//52511//Desktop//Dll3.dll","rb");
    char* buffer = NULL;
    int len = filelen(pfile);
    buffer = (char*)malloc(len * sizeof(char));
    memset(buffer, 0, len);
    fread(buffer, 1, len, pfile);
    PIMAGE_DOS_HEADER pDosH = (PIMAGE_DOS_HEADER)(buffer);
    PIMAGE_NT_HEADERS pNTH = (PIMAGE_NT_HEADERS)(buffer + pDosH->e_lfanew);
    PIMAGE_FILE_HEADER pFH = (PIMAGE_FILE_HEADER)((char*)pNTH + 0x4);
    PIMAGE_OPTIONAL_HEADER pOH = (PIMAGE_OPTIONAL_HEADER)((char*)pFH + 0x14);
    int opHeaderLen = int(pFH->SizeOfOptionalHeader);
    PIMAGE_SECTION_HEADER pSecH = (PIMAGE_SECTION_HEADER)((char*)pOH + opHeaderLen);
    PIMAGE_DATA_DIRECTORY pDD = (PIMAGE_DATA_DIRECTORY)(pOH->DataDirectory);
    int exportVAddress = pDD->VirtualAddress;
    //printf("%08x\r\n", exportAddress);
    int exportFAddress = rvaTofoa(exportVAddress, buffer);
    PIMAGE_EXPORT_DIRECTORY pED = (PIMAGE_EXPORT_DIRECTORY)(buffer+exportFAddress);
    printExportDir(pED,buffer);
    char* name =(char*) "Plus";
    int address1 = GetFunctionAddrByName(buffer, name);
    printf("Plus函数rva为:%08x\r\n", address1);
    //int fileaddress1 = rvaTofoa(address, buffer);
    //printf("Plus函数foa为%08x\r\n", fileaddress1);
    int address2=GetFunctionAddrByOrdinals(buffer, 15);
    printf("15函数rva为:%08x\r\n", address2);
    int fileaddress2 = rvaTofoa(address2, buffer);
    printf("15函数foa为:%08x\r\n", fileaddress2);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力不当无业游民

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值