• PE结构-导入表


    在PE当中,含有导出表和导入表,两者的功能是什么呢?

    一.功能

    导入表:在PE文件中供自己使用的函数在一张表当中,便于寻找和使用

    导出表:在PE文件中供其他PE文件使用的函数在一张表中,便于其他PE文件进行使用

    今天着重介绍导入表

    二.误区

    在大众对PE的认知当中,可能会认为exe文件只有导入表,没有导出表(即只有供自己使用的函数),dll即有导入表又有导出表,其实并不然,exe在本质原理上是可以具有导出表的,只是在使用时并没有那方面的需求,所以就没有提供导出表。

    三.具体分析

    要想分析导出表具体内容,首先要知道如何去定位导出表

    在PE可选头中,观察最后一个属性,数据项目录

     在该属性中,含有16个结构体大小为8的结构体

    前两个结构体分别代表导出表和导入表的RVA值及大小(注意,这里是RVA,即我们在文件中观察时,要明确内存对齐和文件对齐,即RVA 和 FOA 的转换)

    这里写了一个简单的DLL,进行到=导出表的分析(该DLL实现了加减乘除四个功能),下面给出DLL源码

    // newdll.cpp: implementation of the newdll class.
    //
    //////////////////////////////////////////////////////////////////////
    
    #include "stdafx.h"
    #include "newdll.h"
    
    //////////////////////////////////////////////////////////////////////
    // Construction/Destruction
    //////////////////////////////////////////////////////////////////////
    int __stdcall Plus(int x,int y){
        return x+y;
    }
    int __stdcall Min (int x,int y){
        return x-y;
    }
    int __stdcall Mul (int x,int y){
        return x*y;
    }
    int __stdcall Div (int x,int y){
        return x/y;
    }
    
    extern "C" __declspec(dllexport) __stdcall int Plus(int x,int y);
    extern "C" __declspec(dllexport) __stdcall int Min(int x,int y);
    extern "C" __declspec(dllexport) __stdcall int Mul(int x,int y);
    extern "C" __declspec(dllexport) __stdcall int Div(int x,int y);

    用Winhex打开该dll文件进行分析,这里要求必须熟练掌握PE结构

    通过查找发现,从000001C8开始是节表区域,因为可选头与节表是无缝连接的,所以我们可以从节表开始区向前找,因为数据目录项中,每一个结构体为8个字节,有16个结构体,根据该特征向前查找即可

    标记区域即数据目录项,因为前面了解到,前8个字节分别代表导出表的RVA和大小,所以得知,导出表的RVA为2DF10(该DLL内存对齐和文件对齐相同,所以不需要RVA 和 FOA 的转换)

    转到2DF10查看,该处即为导出表

     要理解表中数据的含义,就要求掌握导出表中的属性

     着重介绍几个属性

    Name                    //dll的名称
    Base                    //基数索号 = 序号-基数
    NumberOfFunctions                 //函数的总数
    NumberOfNames                    //有名函数的总数(在dll中函数可以用名称命名也可以用名称命名)
    AddressOfFunctions               //导入函数地址表RVA
    AddressOfNames                  //导入函数名称表RVA
    AddressOfNameOrdinals       //导入函数序号表RVA

    在导入表中,又存在着三张表,即导入函数地址表,导入函数名称表,导入函数序号表,这三张表至关重要,是获取函数的路径

     当得出这个表关系时,就可以真正理解当通过函数名称查询函数地址时,它是经过怎样的步骤进行查询的

    首先,如果要查询Mul,就会先去函数名称表当中查询Mul所在表中的索引号是多少,这里可以看到为2,然后拿着这个2去函数序号表找索引为2的内容,可以发现为3,然后拿着3去找函数地址表中所对应的索引内容,即0000100A,这样就找到了函数的地址

    如果是按照函数的序号查询,这里就会用到基数(Base)的概念,因为在默认情况下(即不改变函数序号的情况下),函数序号都是从1开始的,如果改变了,就需要基数的介入,即在函数序号中最小的数当作0,依次加1,其实就相当于0,1,2,3以此类推,这样就可以直接拿序号去函数地址表通过相应的基数进行查找,就能找到相应的函数地址

               

  • 相关阅读:
    spring中bean的生命周期
    【数据结构与算法】2.2 数组实现循环队列思路、代码
    【数据结构与算法】2.1、数组队列场景、思路、实现
    【Java 基础领域】手气红包实现思路、代码
    【数据结构与算法】1、稀疏数组场景、思路、代码实现
    【Java基础领域】 byte num = 100 没有强制类型转换,为什么也可以编译通过
    【程序人生】程序员发展的7大方向
    【读书笔记】老许的架构
    对于开发中为什么很少用设计模式的思考
    Java编程思想目录
  • 原文地址:https://www.cnblogs.com/Virus-Faker/p/12552777.html
Copyright © 2020-2023  润新知