WindowsPE 第五章 导出表编程-1(枚举导出表)
阅读原文时间:2023年07月09日阅读:4

导出表编程-1-枚举导出表

思路:

(1)加载dll到内存里。

(2)获取PE头,逐步找到可选头部。

(3)然后找到里面的第一个结构(导出表)地址,这个地址指向一个IMAGE_EXPORT_DIRECTORY,然后找到里面的

这个地址是一个数组(DWORD),每个值都指向一个导出函数的名字字符串所在地址,然后根据

确定个数,直接枚举就行了。

代码如下:

#include "stdafx.h"
#include <windows.h>
#include <winbase.h>
#include <stdio.h>
#include <tchar.h>
#include <imagehlp.h>
#include <vector>
#include <iostream>
#include <string>
using namespace std;

typedef PVOID (CALLBACK* PFNEXPORTFUNC)(PIMAGE_NT_HEADERS,PVOID,ULONG,PIMAGE_SECTION_HEADER*);

BOOL printAllFuncName(WCHAR* wcFileName ,vector<string> &vcFuncName){
    vcFuncName.clear();
    LPWIN32_FIND_DATA lpwfd_first=new WIN32_FIND_DATA;//接受findfirstfile的结构指针
    HANDLE hFile,hFileMap;//文件句柄和内存映射文件句柄
    DWORD fileAttrib=0;//存储文件属性用,在createfile中用到。
    void* mod_base;//内存映射文件的起始地址,也是模块的起始地址

    PFNEXPORTFUNC ImageRvaToVax=NULL;
    HMODULE hModule=::LoadLibrary(L"DbgHelp.dll");
    if(hModule!=NULL){
        ImageRvaToVax=(PFNEXPORTFUNC)::GetProcAddress(hModule,"ImageRvaToVa");
        if(ImageRvaToVax==NULL){
            ::FreeLibrary(hModule);
            //printf("取得函数失败\n");
            return FALSE;
        }
    }else{
         //printf("加载模块失败\n");
         return FALSE;
    }

    if(FindFirstFile(wcFileName,lpwfd_first)==NULL){//返回值为NULL,则文件不存在,退出
       //printf("文件不存在: %s ",wcFileName);
       return FALSE;
    }else{
       DWORD fileAttrib=lpwfd_first->dwFileAttributes;
    }
    hFile=CreateFile(wcFileName,GENERIC_READ,0,0,OPEN_EXISTING,fileAttrib,0);
    if(hFile==INVALID_HANDLE_VALUE){
       //printf("打开文件出错!");
       return FALSE;
    }
    hFileMap=CreateFileMapping(hFile,0,PAGE_READONLY,0,0,0);
    if(hFileMap==NULL){
        CloseHandle(hFile);
        //printf("建立内存映射文件出错!");
        return FALSE;
    }
     mod_base=MapViewOfFile(hFileMap,FILE_MAP_READ,0,0,0);
     if (mod_base==NULL)
     {
         //printf("建立内存映射文件出错!");
         CloseHandle(hFileMap);
         CloseHandle(hFile);
         return FALSE;
     }
     IMAGE_DOS_HEADER* pDosHeader = (IMAGE_DOS_HEADER*)mod_base;
     IMAGE_NT_HEADERS * pNtHeader =
        (IMAGE_NT_HEADERS *)((BYTE*)mod_base+ pDosHeader->e_lfanew);//得到NT头首址

     IMAGE_OPTIONAL_HEADER * pOptHeader =
        (IMAGE_OPTIONAL_HEADER *)((BYTE*)mod_base + pDosHeader->e_lfanew + 24);//optional头首址

     IMAGE_EXPORT_DIRECTORY* pExportDesc = (IMAGE_EXPORT_DIRECTORY*)ImageRvaToVax(pNtHeader,mod_base,pOptHeader->DataDirectory[0].VirtualAddress,0);
     //导出表首址
     PDWORD nameAddr=(PDWORD)ImageRvaToVax(pNtHeader,mod_base,pExportDesc->AddressOfNames,0);//函数名称表首地址每个DWORD代表一个函数名字字符串的地址
     PCHAR func_name = (PCHAR)ImageRvaToVax(pNtHeader,mod_base,(DWORD)nameAddr[0],0);
     DWORD i=0;
     DWORD unti=pExportDesc->NumberOfNames;
     for(i=0;i<unti;i++){
        func_name = (PCHAR)ImageRvaToVax(pNtHeader,mod_base,(DWORD)nameAddr[i],0);
        //printf("%s\n",func_name);
        vcFuncName.push_back(string(func_name));
     }
     ::FreeLibrary(hModule);
     CloseHandle(hFileMap);
     CloseHandle(hFile);
     return TRUE;
}

int main(int argc, char* argv[]){

    vector<string>vcFuncName;
    printAllFuncName(L"C:\\A.dll" ,vcFuncName);

    for(vector<string>::iterator it  = vcFuncName.begin(); it != vcFuncName.end();it++){
         cout<<*(it)<<endl;
    }
    getchar();
    return 0;
}

下面两个不去实现了,和上面的差不多。

2.根据编号查找函数地址