TEB/PEB定位PE文件导入导出表

TEB/PEB定位PE文件导入导出表

基本思路:
TEB/PEB定位PE文件基址

  1. 通过FS寄存器找到当前的TEB
  2. 通过[TEB+0x30]找到PEB的地址
  3. 通过[PEB+0x0C]找到PEB_LDR_DATA的结构体指针
  4. 通过[PEB_LDR_DATA+0x1C]找到此结构体的成员InInitializationOrderModuleList,此成员保存着模块链表的头部地址
  5. InInitializationOrderModuleList按照顺序保存进程加载的模块基址,其中第一个始终为ntdll.dll,第二个视系统的不同可能保存有Kernel32.dll或KernelBase.dll的信息
  6. 不管Kernel32.dll或KernelBase.dll都导出有我们需要的函数GetprocAddress和LoadLibraryEx
  7. LoadLibrary只在Kernel32.dll导出

PE文件定位导入导出表

  1. [ImageBase+0x3C]是是DOS头指向NT头的偏移:e_lfanew
  2. NT头的地址:pNt=ImageBase+e_lfanew,数据目录表[0]的偏移:DirectoryRVA=[pNt+0x78]
  3. 数据目录表的地址:pDataDirectory=ImageBase+DirectoryRVA
  4. 导出表地址:pExport=ImageBase+VirtualAddress
    4.1 导入地址表:pEAT=[pExport+0x1C]
    4.2 导入名称表:pENT=[pExport+0x20]
    4.3 导入序号表:pEOT=[pExport+0x24]
    4.4 导出表名称数量:NumberOfNames=[pExport+0x18]
  5. 导入表地址:pImport=[pDataDirectory+0x8]+ImageBase

TEB-线程环境块

TEB保存了和一个线程相关的大量的信息,Windows将TEB结构的变量保存在内存中的一个位置上. 这个地址是无法直接获取到的。TIB(Thread Information Block)线程信息块是保存线程基本信息的数据结构,在用户模式下,它位于TEB的头部。

  • x86系统:
    TEB总是由FS:[0]指向的,TEB的偏移0x18是指向自己的指针,偏移0x30是PEB
    在这里插入图片描述

  • x64系统:
    TEB是由GS:[0]指向的,TEB的偏移0x30是指向自己的指针,偏移0x60是PEB
    在这里插入图片描述

PEB-进程环境块

PEB保存进程相关信息,通过PEB找到模块链表,获取模块基址

  • [PEB+0xC]找到DllList成员,此成员指向PEB_LDR_DATA 结构体
    在这里插入图片描述

  • [PEB_LDR_DATA+0x1C]找到InInitializationOrderModuleList,此成员保存模块链表的头部地址

// PEB_LDR_DATA结构
typedef struct _PEB_LDR_DATA
{
 ULONG Length;                 // +0x00
 BOOLEAN Initialized;         // +0x04
 PVOID SsHandle;              // +0x08
 LIST_ENTRY InLoadOrderModuleList;     // +0x0c 
 LIST_ENTRY InMemoryOrderModuleList;     // +0x14  
 LIST_ENTRY InInitializationOrderModuleList;    // +0x1c
} PEB_LDR_DATA,*PPEB_LDR_DATA; // +0x24

InLoadOrderModuleList 、InMemoryOrderModuleList、InInitializationOrderModuleList都是双向链表的头部,访问模块顺序的不同,列表中的每一项都是指向LDR_DATA_TABLE_ENTRY结构的指针。

  • [InInitializationOrderModuleList + 0x8] 取出模块基址
    [InInitializationOrderModuleList + 0x14] 取出模块名偏移
    [InInitializationOrderModuleList] 指向下一个模块
// struct _LIST_ENTRY结构体
typedef struct _LIST_ENTRY { 
 struct _LIST_ENTRY *Flink; 
 struct _LIST_ENTRY *Blink; 
} LIST_ENTRY, *PLIST_ENTRY, *RESTRICTED_POINTER PRLIST_ENTRY;
// LDR_DATA_TABLE_ENTRY结构体
typedef struct _LDR_DATA_TABLE_ENTRY { 
/*0x00*/ PVOID Reserved1[2]; 
/*0x08*/ LIST_ENTRY InMemoryOrderLinks;     // 模块基址
/*0x0C*/ PVOID Reserved2[2]; 
/*0x14*/ PVOID DllBase;                    // 模块名字 
/*0x18*/ PVOID EntryPoint; 
/*0x1C*/ PVOID Reserved3; 
/*0x20*/ UNICODE_STRING FullDllName; 
/*0x24*/ BYTE Reserved4[8]; 
/*0x2C*/ PVOID Reserved5[3]; 
/*0x38*/ union { 
                ULONG CheckSum; 
                PVOID Reserved6; 
            }; 
/*0x40*/ ULONG TimeDateStamp; 
 } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
  1. 示例程序
DWORD GetKernel32Addr()
{
     _asm {
          push esi
          mov esi, dword ptr fs : [0x30]    //esi=PEB地址
          mov esi, [esi + 0x0C]    //esi=PEB_LDR_DATA结构体的地址
          mov esi, [esi + 0x1C]    //esi=模块链表指针InInitializationOrderModuleList
          mov esi, [esi]    //esi=访问链表的第二个条目
          mov eax, [esi + 0x08]    //ebx=Kernel32.dll模块基址
          pop esi
     }
}

定位导入导出表

  1. 在Dos头部找到NT头偏移
    在这里插入图片描述
  2. 偏移加模块基址定位到NT头后,在扩展头找到数据目录表RVA=[pNtHeader+0x78]
    在这里插入图片描述
  3. 数据目录表的地址=模块基址+RVA,每个数据目录表成员大小占8字节。
    在这里插入图片描述
  4. 导出表地址:pExport=模块基址+VirtualAddress
    4.1 导入地址表:pEAT=[pExport+0x1C]
    4.2 导入名称表:pENT=[pExport+0x20]
    4.3 导入序号表:pEOT=[pExport+0x24]
    4.4 导出表名称数量:NumberOfNames=[pExport+0x18]
typedef struct _IMAGE_EXPORT_DIRECTORY {
    DWORD Characteristics;	// 0
    DWORD TimeDateStamp;	// 0x4
    WORD MajorVersion;	// 0x6
    WORD MinorVersion;	// 0x8
    DWORD Name;	// 0xC 指向该导出表文件名字字符串
    DWORD Base;	// 0x10 导出函数起始序号
    DWORD NumberOfFunctions;	// 0x14 地址表成员个数 导出序号最大-最小
    DWORD NumberOfNames;	// 0x18 以函数名字导出的函数个数
    DWORD AddressOfFunctions; // 0x1C 导出函数地址表RVA
    DWORD AddressOfNames; // 0x20 导出函数名称表RVA
    DWORD AddressOfNameOrdinals; // 0x24 导出函数序号表RVA
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
  1. 导入表地址:pImport=[pDataDirectory+0x8]+ImageBase
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值