首页
社区
课程
招聘
[旧帖] [原创]pe文件的导入导出表的分析 0.00雪花
发表于: 2012-6-3 13:48 1648

[旧帖] [原创]pe文件的导入导出表的分析 0.00雪花

2012-6-3 13:48
1648
三月份写的代码,拉出来,重新整理一下。
第一次来看雪发帖,也是第一次发技术贴,求顶求支持,求精华
pe结构为:
 

 
这里我只关注导入导出表,即图的输入输出表
先说段开场白吧,pe文件在磁盘映射或者加载到内存的时候,dos头,PE头不会有任何修改,但是在节表,也就section这块会有一定的修正,其实这个问题最开始给我很大的困惑。
具体几个步骤,详细步骤在代码里有
1.创建文件
2.映射文件,保留一个基地址
3.dos头=基地住
4.pe头=dos头+pe文件的偏移
5.导出表的偏移RVA=p_NTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
6.导出表的地址=RVA+基地址,此时的导出表应该为第一个导出表
7.此时我们可以取得导出表的所有的数据,本程序取得其中的函数名,函数地址,以及导出函数的总数---------此处注意,因为这些数据都是存放在section里面的,在导出表中只是存的是一个指针,然后根据第一段的开场白,这个地址不准了,此时,要做一个修正了。
8.我们找到section头的位置,pe头+pe的大小
9.把section里面的磁盘的偏移-内存中的偏移+导出表原来指向RVA,这样就找到了导出表函数的位置了-----------这句再详解一下,按照我的测试条件下,磁盘上的pe文件较内存上的小些,即可以把磁盘上的看做为压缩文件,而导出表的RVA也是压缩的RVA,要转化成内存的RVA,实际内存里的RVA =磁盘RVA+磁盘section偏移-内存section偏移
10找到导出表的函数存储的地址就可以找到所要的函数名,函数个数,以及函数地址
同理找到导出表。】
代码:【附件里也有】

#include "stdafx.h"
#include <Windows.h>
#include <stdio.h>
#pragma comment(lib, "advapi32.lib")
//
//提权
//
bool enableDebugPriv()
{
    HANDLE hToken;
    LUID sedebugnameValue;
    TOKEN_PRIVILEGES tkp;
    if (!OpenProcessToken(GetCurrentProcess(),
        TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
            return false;
    }

    if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sedebugnameValue)) {
        CloseHandle(hToken);
        return false;
    }

    tkp.PrivilegeCount = 1;
    tkp.Privileges[0].Luid = sedebugnameValue;
    tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL)) {
        CloseHandle(hToken);
        return false;
    }

    return true;
}
//
//修正RVA
//
DWORD update_RVA(PIMAGE_NT_HEADERS pNTHeader, DWORD dwRVA){

    PIMAGE_SECTION_HEADER pSection = (PIMAGE_SECTION_HEADER)((DWORD)pNTHeader + sizeof(IMAGE_NT_HEADERS));

    for(int i = 0; i < pNTHeader->FileHeader.NumberOfSections; i++)
    {
        if(dwRVA >= pSection[i].VirtualAddress && dwRVA < (pSection[i].VirtualAddress + pSection[i].SizeOfRawData))
        {
            return pSection[i].PointerToRawData + (dwRVA - pSection[i].VirtualAddress);
        }
    }

    return 0;
}
//
//打印导出表
//
int show_Export(char *file){
    //创建文件
    HANDLE h_File = CreateFileA(file, GENERIC_ALL, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL);
     if (h_File==NULL){
        printf("创建失败\n");
        if (INVALID_HANDLE_VALUE != h_File){

            CloseHandle(h_File);
        }
        return 1;
    }
       //映射文件到内存
    HANDLE h_Mapping = CreateFileMapping(h_File, NULL, PAGE_READWRITE, 0, 0, NULL);
     if (h_Mapping==NULL){
        printf("文件映射失败\n");
        if(NULL != h_Mapping){

            CloseHandle(h_Mapping);
        }
        CloseHandle(h_File);
     return 1;

    }
       //基地址
    PVOID BaseAdress= MapViewOfFile(h_Mapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
    
     if(BaseAdress==NULL){
        printf("取基地址失败\n");
        if(NULL != h_File){
            
            UnmapViewOfFile(h_File);
        }
       
        CloseHandle(h_Mapping);
        CloseHandle(h_File);
    return 1;
    }
  
       //DOS头
    PIMAGE_DOS_HEADER p_DosHeader = (PIMAGE_DOS_HEADER)BaseAdress;
       //PE头
    PIMAGE_NT_HEADERS p_NTHeader = (PIMAGE_NT_HEADERS)((DWORD)BaseAdress + p_DosHeader->e_lfanew);
  
      //导出表的RVA
    DWORD dwExp= p_NTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
    if(dwExp==0){
        printf("没有导出表\n");
         UnmapViewOfFile(h_File);
          CloseHandle(h_Mapping);
          CloseHandle(h_File);
          return 1;
    }
     
  
    //内存里导出表的地址,此处需要修正
     PIMAGE_EXPORT_DIRECTORY p_Export = (PIMAGE_EXPORT_DIRECTORY)((DWORD)BaseAdress + update_RVA(p_NTHeader,dwExp));
     //
   
     //第一个函数名称的地址
      DWORD* p_NamesAddress = (DWORD*)((DWORD)BaseAdress +update_RVA(p_NTHeader,p_Export->AddressOfNames));
      //
      //指向函数导出表地址的RVA+基地址
      DWORD* p_FunctionAddress = (DWORD*)((DWORD)BaseAdress + update_RVA(p_NTHeader,p_Export->AddressOfFunctions));
      //指向函数名序号表的RVA+基地址
      WORD* p_Ordinals = (WORD*)((DWORD)BaseAdress +update_RVA(p_NTHeader,p_Export->AddressOfNameOrdinals));

      int num=p_Export->NumberOfNames;
      for(int i = 0;i<num; i++)
      {
          DWORD dwFunctionAddress = p_FunctionAddress[p_Ordinals[i]];

          DWORD p_FunName = (DWORD)BaseAdress +update_RVA(p_NTHeader,p_NamesAddress[i]);
          //pExport->Base导出函数的起始序号
          //
          printf("[导出表序号]: %-4d  [函数名]: %-30s  [地址]: 0x%08X\n", p_Export->Base + i, p_FunName, dwFunctionAddress);
      }
      UnmapViewOfFile(h_File);
      CloseHandle(h_Mapping);
      CloseHandle(h_File);
      return 0;
}
//
//打印导入表
//
int show_Import(char *file){
    //创建文件
    HANDLE h_File = CreateFileA(file, GENERIC_ALL, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL);
    if (h_File==NULL){
        printf("创建文件失败\n");
        if (INVALID_HANDLE_VALUE != h_File){

            CloseHandle(h_File);
        }
        return 1;
    }
    //映射文件到内存
    HANDLE h_Mapping = CreateFileMapping(h_File, NULL, PAGE_READWRITE, 0, 0, NULL);
     if (h_Mapping==NULL){
         
         printf("文件映射失败\n");
         if(NULL != h_Mapping){
            
               CloseHandle(h_Mapping);
            }

         CloseHandle(h_File);
        return 1;
    }
    //基地址
    PVOID BaseAdress= MapViewOfFile(h_Mapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
    if (BaseAdress==NULL){
        printf("获取基地址失败\n");
        if(NULL != h_File){

            UnmapViewOfFile(h_File);
        }

        CloseHandle(h_Mapping);
        CloseHandle(h_File);

        return 1;
    }
    //DOS头
    PIMAGE_DOS_HEADER p_DosHeader = (PIMAGE_DOS_HEADER)BaseAdress;
    //PE头
    PIMAGE_NT_HEADERS p_NTHeader = (PIMAGE_NT_HEADERS)((DWORD)BaseAdress + p_DosHeader->e_lfanew);

    //导出表的RVA
    DWORD dwImp= p_NTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
   if (dwImp==0){
       printf("没有导入表\n");
       UnmapViewOfFile(h_File);
       CloseHandle(h_Mapping);
       CloseHandle(h_File);
       return 1;
   }
    //内存里导出表的地址,此处需要修正
    PIMAGE_IMPORT_DESCRIPTOR p_Import = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)BaseAdress + update_RVA(p_NTHeader,dwImp));
    DWORD* p_NamesAddress = (DWORD*)((DWORD)BaseAdress +update_RVA(p_NTHeader,p_Import->OriginalFirstThunk));
    int i=0;
    while(1)
    {
        //俩个位子的函数序列号,名字要往后移俩位
        DWORD p_FunName = (DWORD)BaseAdress +update_RVA(p_NTHeader,p_NamesAddress[i])+2;
         printf("[导入函数名:]  %-30s \n",p_FunName);
         i++;
         if(p_NamesAddress[i]==0){
             break;
         }
    }
    UnmapViewOfFile(h_File);
    CloseHandle(h_Mapping);
    CloseHandle(h_File);
    return 0;
}
int main()
{
    bool power=enableDebugPriv();//提权
    if(power==false){
        printf("提权失败\n");
        return 1;
    }
    while(power==true){
    
        printf("请输入文件路径以及文件名:\n");
    
        char file[30];
        scanf("%s",file);
        printf("导出表为:\n");
        show_Export(file);
         printf("导入表为:\n");
        show_Import(file);
     
    }
   
  
    return 0;

}

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

上传的附件:
收藏
免费 0
支持
分享
最新回复 (2)
雪    币: 1015
活跃值: (235)
能力值: ( LV12,RANK:440 )
在线值:
发帖
回帖
粉丝
2
不错,希望和楼主一起在看雪上面学到更多的东西。
2012-6-3 15:55
0
雪    币: 44
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
谢谢楼主 拿回去研究
2012-7-20 11:46
0
游客
登录 | 注册 方可回帖
返回
//