PE文件基础补注

PMF5.0计算 EPA PMF5.0 计算步骤 阅读详情
E文件基础补注

关键词: PE文件  地址转换 IAT  IMAGE_IMPORT_BY_NAME

前言: 最近学习PE, 略有心得, 拿来和大家分享. 

感谢: 小虾斑斑, 非安全  ,Bookworm对我的帮助.

附件:pe.rar

1.IMAGE_SECTION_HEADER小结:
  
1.1   获得节表数 :NumberOfSections = NtHeader->FileHeader.NumberOfSections;

1.2   节表获得方法
      
      方法1.因为NT头之后就是节表,故,节表头地址就是nt头地址加上NT结构大小.
      SectionHeader=(PIMAGE_SECTION_HEADER)((UINT32)NtHeader+(UINT32)(sizeof(IMAGE_NT_HEADERS)));
  
      方法2.或者用ImageBase+SizeOfHeaders的办法直接定位.
      SectionHeader=(PIMAGE_SECTION_HEADER)((UINT32)(NtHeader->OptionalHeader.ImageBase)+
                                          (UINT32)(NtHeader->OptionalHeader.SizeOfHeaders));
  
      方法3.既然节都是连在一起的,那么,也就可以这样: 
              SectionHeader= (PIMAGE_SECTION_HEADER) (NtHeader + 1),
  
      方法4.论坛里面 hmimys 告诉的办法:    
              SectionHeader=(PIMAGE_SECTION_HEADER)((UINT32)NtHeader+0x18+
                                                   (UINT32)(NtHeader->FileHeader.SizeOfOptionalHeader));
              到现在我还没有弄懂为什么 hmimys 说最好要用方法4而不用方法3.
    
    
2. IMAGE_IMPORT_DECSRITOR 小结:

2.1:获得引入表结构起始地址:
     
     方法1:ImportDec = (PIMAGE_IMPORT_DESCRIPTOR)(NtHeader->OptionalHeader.DataDirectory[12].VirtualAddress);
            这个方法我觉得理论上是对的,但是我在运行的时候总是得不到正确的地址.后来知道,似乎不能用'12',而要用IMAGE_DIRECTORY_ENTRY_IAT这个宏

     方法2:ImportDes = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)(NtHeader->OptionalHeader.DataDirectory)+
                                                    (DWORD)(sizeof(IMAGE_DATA_DIRECTORY)*12));
   
     方法3 : ImportDes = (PIMAGE_IMPORT_DESCRIPTOR)(NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress-
                Offset + (PBYTE)pMapping);

     注 : 前两种方法都是从 IAT 中得出 IMAGE_IMPORT_DESCRIPTOR,而后面的那个是 非安全 大哥教的. 这里有个疑问: 
          3种方法都可以得到 IMAGE_IMPORT_DESCRIPTOR 结构,都可以得到函数名, 区别在于前两种方法枚举的函数名不全. 
          难道说两个结构都指向同一个结构PIMAGE_IMPORT_DESCRIPTOR?
 
2.2  IMAGE_IMPORT_DESCRIPTOR 结构既不是在Import Symbols中,也不是在IAT (IMAGE_IMPORT_ADDRESS_TABLE)中。它就是一个结构. 
     我原来说:"IMAGE_IMPORT_DESCRIPTOR 结构不是在Import Symbols中,是在IAT (IMAGE_IMPORT_ADDRESS_TABLE)中。" 有问题.
     就是因为这个错误的理解, 让我走了好多死路.
     
     这个是Winnt.h中关于 IMAGE_SYNMBOL的结构信息

     typedef struct _IMAGE_SYMBOL {
      union {
        BYTE    ShortName[8];
        struct {
            DWORD   Short;     // if 0, use LongName
            DWORD   Long;      // offset into string table
        } Name;
        PBYTE   LongName[2];
     } N;
     DWORD   Value;
     SHORT   SectionNumber;
     WORD    Type;
     BYTE    StorageClass;
     BYTE    NumberOfAuxSymbols;
     } IMAGE_SYMBOL;
     
     typedef IMAGE_SYMBOL UNALIGNED *PIMAGE_SYMBOL;

     而下面的是IAT: 

     typedef struct _IMAGE_IMPORT_BY_NAME {
      WORD    Hint;
      BYTE    Name[1];
     } IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

     typedef struct _IMAGE_IMPORT_DESCRIPTOR {
      union {
          DWORD   Characteristics;            // 0 for terminating null import descriptor
          DWORD   OriginalFirstThunk;         // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
      };
      DWORD   TimeDateStamp;                  // 0 if not bound,
                                            // -1 if bound, and real date/time stamp
                                            //     in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
                                            // O.W. date/time stamp of DLL bound to (Old BIND)

      DWORD   ForwarderChain;                 // -1 if no forwarders
      DWORD   Name;
      DWORD   FirstThunk;                     // RVA to IAT (if bound this IAT has actual addresses)
     } IMAGE_IMPORT_DESCRIPTOR;
     typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;

     _IMAGE_IMPORT_DESCRIPTOR 结构联合中的OriginalFirstThunk , 就是到IMAGE_THUNK_DATA的RVA. 
     如果像下面这样写,也许更明白

     typedef struct _IMAGE_THUNK_DATA {
        union {
            PBYTE ForwarderString;
            PDWORD Function;
            DWORD Ordinal;
            PIMAGE_IMPORT_BY_NAME AddressOfData;
        } ;
     } IMAGE_THUNK_DATA,*PIMAGE_THUNK_DATA;

     typedef struct _IMAGE_IMPORT_DESCRIPTOR {
        union {
            DWORD Characteristics;
            PIMAGE_THUNK_DATA OriginalFirstThunk;
        } ;
        DWORD TimeDateStamp;
        DWORD ForwarderChain;
        DWORD Name;
        PIMAGE_THUNK_DATA FirstThunk;
     } IMAGE_IMPORT_DESCRIPTOR,*PIMAGE_IMPORT_DESCRIPTOR;
     

3. 地址转换小结(RVAToOffset): 

   为什么要地址转换, 前人的文章说了很多,下面给出我的转换方法:  
   
   3.1 函数,它能给出RVA返回此RVA所在的节,来自 Matt Pietrek的书: 

   PIMAGE_SECTION_HEADER GetEnclosingSectionHeader(DWORD rva){
        unsigned i;
      PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION32(NtHeader);
      for ( i=0; i < NtHeader->FileHeader.NumberOfSections; i++,section++){
               if ( (rva >=section->VirtualAddress) && 
             (rva < (section->VirtualAddress + section->Misc.VirtualSize)))
            return section;
      }
         return 0; 
   }

   注: hnhuqiong 给的 ollydump300110 的源码里面也有类似函数,但是,
       很明显的有漏洞,那就是若RVA不在任何一个Section那么函数会返回最后
       一个Section, 而不是像这里返回 0 .下面是原始连接
   http://bbs.pediy.com/showthread.php?threadid=26520

   3.2 RVAToOffset:

   我一直没有注意的就是'Offset'这个词. Offset其实还是一个偏移,只不过是
   在文件中, 要想得到目标文件的IAT, 就要将这个值加上由 MapViewOfFile 返回
   的文件基址指针.

   Offset的的获得 : 
            pSection = GetEnclosingSectionHeader(NtHeader->OptionalHeader.DataDirectory                                       

                                           [IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress);
            Offset = (DWORD) (pSection->VirtualAddress - pSection->PointerToRawData);
  
   以获得IMAGE_THUNK_DATA结构为例,给出用法: 

        ThunkData = (PIMAGE_THUNK_DATA)((DWORD)ImportDes->OriginalFirstThunk -
                                       Offset + (PBYTE)pMapping);
   呵呵, (DWORD)ImportDes->OriginalFirstThunk -Offset 得到的只是文件中的偏移, 
   注意加上由 MapViewOfFile 返回的pMapping. 如果你象我原来一样,加上的是
   NtHeader->OptionalHeader.ImageBase , 那么恭喜你, 访问错误.            
  

4. 用VC 6.0 + API获得IMAGE_IMPORT_BY_NAME结构的一点问题.

   在 VC 里面,  在一个结构指针比如ThunkData后面加上'->'时, vc会自动的列出
   结构的成员供你选择, 十分方便. 但是, 通过ThunkData继续想获得IMAGE_IMPORT_BY_NAME
   结构的时候, 你在ThunkData后面加'->'时, 出来的是一个'u1'. 此时不要疑惑,
   这个'u1'就是 IMAGE_THUNK_DATA 里面的那个 union 的名称, 所以你可以这样得到
   IMAGE_IMPORT_BY_NAME结构: 

       ImportBN = (PIMAGE_IMPORT_BY_NAME)((DWORD)(ThunkData->u1.AddressOfData)-
                                Offset +(PBYTE)pMapping);

5.   Iczelion的PE教程关于导入表的描述没有讲清楚,只是说用IMAGE_THUNK_DATA
      的每个数组元素和IMAGE_ORDINAL_FLAG32,比较可以推断如果某个函数是由函数序数引出的,
      我就误解成用ImportDes->OriginalFirstThunk或者ImportDes->FirstThunk 判断。是不是错的很远?
      参考(【翻译】“PE文件格式”1.9版 完整译文(附注释))http://bbs.pediy.com/showthread.php?threadid=21932,
      我们应该用IMAGE_THUNK_DATA结构里面的AddressOfData来判断。下面的代码可行:

      while(ThunkData->u1.AddressOfData!=NULL){
         ImportBN = (PIMAGE_IMPORT_BY_NAME)((DWORD)(ThunkData->u1.AddressOfData) - Offset +(PBYTE)pMapping); 
   //显示导入函数
   if(((DWORD)ThunkData->u1.AddressOfData & IMAGE_ORDINAL_FLAG32) == 0){
    AddText(hEdit,TEXT("%03d:  %s/r/n"),i++,ImportBN->Name);
   }
   else{
    AddText(hEdit,TEXT("%03d:  Ord by Hint/r/n"),i++);
   }
   ThunkData ++;  
      }//End of while

6      导出表:
6.1    导出表的结构,
   typedef struct _IMAGE_EXPORT_DIRECTORY {
      DWORD   Characteristics;
      DWORD   TimeDateStamp;
      WORD    MajorVersion;
      WORD    MinorVersion;
      DWORD   Name;
      DWORD   Base;
      DWORD   NumberOfFunctions;
      DWORD   NumberOfNames;
      DWORD   AddressOfFunctions;     // RVA from base of image
      DWORD   AddressOfNames;         // RVA from base of image
      DWORD   AddressOfNameOrdinals;  // RVA from base of image
   } IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

6.2   AddressOfNames 和AddressOfNameOrdinals 是一一对应的,只不过一个用于名字,
      一个用于序号, 同一个函数的索引都相同。

6.3   NumberOfFunctions – NumberOfNames 应该就是由序号引出的函数数目了

6.4   对于由序号导出的函数,不知道有没有办法能通过序数找到函数名。个人考虑似乎不可能这样
      找函数名字,不然,微软未公开的函数就都被我们通过函数序数枚举出来了? :)

7:  把我的PE查看器修改了下, 原来的在处理用序号引出的函数时会出错.:)

UFS 3.1协议分析(第一至四章) -- UFS概述 Contents协议规范规范参考术语和定义简单概述通用特性接口特性功能特性 协议规范     UFS3.1协议规定了UFS电气接口和存储器件的特性以及系统架构。 特性:低功耗、高数据吞吐量、低电磁干扰、大容量存储器子系统效率的优化 电气接口:使用基于MIPI M-PHY的高级差分接口;M-PHY作为物理层,MIPI UniPro作为链路层,二者结合形成UFS接口的互联。 架构模型:参考 INCITS T10(SCSI) SAM 标准,命令协议基于 INCITS T1 阅读详情

相关推荐

DIY音乐播放器:用VS1053模块+Arduino打造你的专属MP3播放器(附完整代码)

本文详细介绍了如何使用VS1053音频解码模块与Arduino开发板,从零开始构建一个功能完备的桌面级MP3播放器。内容涵盖硬件架构设计、SPI总线共享、底层驱动编写、双缓冲区数据流管理以及用户交互实现,并提供完整的代码示例与性能优化建议,帮助创客打造高度可定制的专属音乐播放设备。

weixin_29189003的博客 287

如何从PIMAGE_IMPORT_DESCRIPTOR节,得到某个API函数(导入函数)代码地址

//功能:得到某个API函数(导入函数)代码地址//参数://pImport: PIMAGE_IMPORT_DESCRIPTOR//pProcName: 函数名或序号const FARPROC GetFunctionFARPROC( PIMAGE_IMPORT_DESCRIPTOR pImport, LPCSTR pProcName) { PIMAGE_THUNK_DATA pThunk;

lessonzhe的专栏 3903

【Cubietruck】Qt5.8.0 x64、x86、armhf三个版本的编译安装

一、       Preparation 以下环境配置支持虚拟机和实体机,但是实体机生产效率会相对高一点,实体机编译Qt的速度是虚拟机两倍以上。 若使用虚拟机,推荐使用VirtualBox,开源免费,尽量不要使用Vmware破解版。   Download List   名称 链接 下载项目 OS https://mirro

beatfan的博客 3658

12.PE文件之导入表(IMAGE_IMPORT_DESCRIPTOR)

目录 导入表定位以及解析(手动FileBuffer) 导入表定位以及解析(手动ImageBuffer) 代码定位导入表并打印其数据 导入表注入 导入表是PE数据组织中的一个很重要的组成部分,它是为实现代码重用而设置的.通过分析导入表数据,可以获得诸如PE文件的指令中调用了多少外来的函数,以及这些外来函数都存在于哪些动态链接库里等信息. Windows加载器在运行PE时会将导入表中声明的动态链接库一并加载到进程的地址空间,并修正指令代码中调用的函数地址. 在数据目录项中一共有四种类型的数据与导入

kernelhack 6700

华硕电脑Win10改Win7系统:BIOS设置详解

通过上述步骤,华硕电脑用户可以将系统从Windows 10更改为Windows 7。虽然这个过程可能涉及一些技术细节和潜在的风险(如数据丢失和驱动不兼容),但只要按照指南仔细操作并做好准备工作,大多数用户应该能够成功完成系统回滚。请记住,在进行任何系统更改之前都要备份重要数据,并确保已了解所有潜在的风险和限制。希望本文能够帮助到需要回滚到Windows 7的华硕电脑用户!

nntxthml的博客 2262

mcgs数据导出到U盘

mcgs触摸屏在工业中应用还是很多的,尤其他的脚本功能策略功能等将开放性放到了最大,让用户可以根据实际需求进行自由创作,正因为这样,对一些初学者就不是很友好,初学者想要简单操作就能实现功能,但是mcgs不可能两者兼备,在做工业设备,一些数据的采集保存就比较常见,但是mcgs没有相关按钮能够直接实现将数据导出到U盘的功能。这里我给大家讲解关于mcgs将报警历史记录、日志记录、历史数据记录导出到U盘的方法。

qq_24866535的博客 6234

PE文件(1)导入表

PE文件(1)导入表 概念 导入函数的代码位于一个或者多个DLL中,在调用者程序中只保留一些相关的函数信息,包括函数名及其对应的DLL名等。 对于磁盘上的PE 文件来说,它无法得知这些输入函数将来在内存中的地址,只有当PE 文件被装入内存后,Windows的 加载器才将相关DLL 装入,并将调用导入函数的指令和函数实际所处的地址联系起来。 这就是“动态链接”的概念。动态链接是通过PE 文件...

nyzdmc的博客 865

【Python】-- 趣味代码 - 发牌游戏

Python -- 趣味代码 - 发牌游戏

银尘博客 351

5.PE文件之节表(IMAGE_SECTION_HEADER)

PE头IMAGE_NT_HEADERS后紧跟着节表(也可以理解为IMAGE_OPTIONAL_HEADER后为节表).它由许多个节表项(IMAGE_SECTION_HEADER)组成,每个节表项记录了PE中与某个特定的节有关的信息,如节的属性、节的大小、节在文件和内存中的起始位置等.节表中节的数量由IMAGE_FILE_HEADER.NumberOfSection来定义. IMAGE_SECTION_HEADER 结构及成员含义如下: #define IMAGE_SIZEOF_SECTION_HEA

kernelhack 6219

【局部规划模块轨迹优化算法】EM_planner最大期望滚动优化算法

认知有限,望大家多多包涵,有什么问题也希望能够与大家多交流,共同成长!本文先对EM_planner最大期望滚动优化算法做个简单的介绍,具体内容后续再更,其他模块可以参考去我其他文章提示:以下是本篇文章正文内容。

qq_35635374的博客 760

芯片ATE测试PAT(Part Average Testing)学习总结-20250916

文章摘要:零件平均测试(PAT)是半导体制造中基于统计学的质量控制方法,分为静态和动态两种类型。静态PAT通过预先设定的固定限值(每6-8批次更新)筛选异常芯片,计算采用稳健平均值和四分位间距。动态PAT则根据实时数据调整限值,能更精确识别异常而不误判合格芯片。两种方法均采用"均值±6倍标准差"的计算公式,但动态PAT具有更好的适应性和准确性。该方法通过统计分析提高了芯片产品的质量和可靠性。

歌颂苦难的行为是无耻的; 1190

一个指针与地址的例子

例句: PIMAGE_SECTION_HEADER pSecHeader = (PIMAGE_SECTION_HEADER)(*(DWORD*)&pNtHeader + sizeof(IMAGE_NT_HEADERS32)); pNtHeader是一个结构体指针,指向一个IMAGE_NT_HEADER结构体; pSecHeader 是一个结构体指针,指向一个IMAGE_SECTI

GVFDBDF的专栏 854

把 LDB 讲透:SAP ABAP 逻辑数据库的结构、事件模型、动态选择与现代替代方案

摘要:SAP中的Logical Database(LDB)是一种将表组织成树形结构并统一生成选择屏幕的技术,通过事件驱动方式向报表程序传递数据。虽然被标记为过时,但在理解标准代码和优化性能方面仍有价值。LDB通过SE36事务码创建,其结构包含层级关系、选择屏幕和数据库程序。报表通过NODES声明和GET事件处理数据,支持动态选择以减少数据库访问。在S/4HANA和ABAP Cloud环境下,建议使用CDS View和ABAP SQL等现代方案替代LDB,以提升可测试性和架构清晰度。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 215

PE文件基础补注(VC + 纯API版)

http://www.chinaitpower.com/2006Aug/2006-12-15/222429.html 

cnrandy 的专栏 809

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

STM32 + RT Thread OS 学习笔记[四]

1、  补注 a)      硬件,打通通讯通道 若学习者购买了学习板,通常可以在学习板提供的示例代码中找到LCD的相关驱动代码,基本上,这里的驱动的所有代码都可以从里面找到。 从上面的示意图可见,MCU要在LCD上显示内容,需要经过: 1、  Core 2、  Dbus,SystemBus 3、  Bus Matrix 4、  FSMC 5、  SSD1963 6、  LC

的米-漠石's Blog 6715

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

STM32 RTT LCD

转载于http://blog.youkuaiyun.com/mostone/article/details/9318589 1、  补注 a)      硬件,打通通讯通道 若学习者购买了学习板,通常可以在学习板提供的示例代码中找到LCD的相关驱动代码,基本上,这里的驱动的所有代码都可以从里面找到。 从上面的示意图可见,MCU要在LCD上显示内容,需要经过:

Jorry Zhao的专栏 1317

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

Ponytail:让AI少写代码

Ponytail 是一套给 AI 编码 Agent 用的“少写代码”规则、插件和评测资产。

lifallen的博客 285

PE结构-节

首先,节的话有两部分,一部分是节表,另外一部分就是节区了,节表是用于描述节区信息的,而节区呢,简单点说就是数据块。 在上一篇博客中有提及过如何定位节表,重点就是需要根据选项头的大小来定位,这里的话就直接上一点代码吧,前两篇概念较多 PIMAGE_DOS_HEADER pDosHeader = GetDosHeader(); //获取dos头 if (pDosHeader ==...

小喇叭儿滴滴的吹 640

C语言实现遍历PE文件导入表

C++ 编程实现遍历PE文件导入表,可以遍历延迟导入的函数

溡漪幽博客 821

一段仿真PE加载器行为的程序

bool PELoader(char *lpStaticPEBuff, long lStaticPELen) {   long lPESignOffset = *(long *)(lpStaticPEBuff + 0x3c);   IMAGE_NT_HEADERS *pINH = (IMAGE_NT_HEADERS *)(lpStaticPEBuff + lPESignOffset);   /

Chinawash 专栏 1654

怎么拦截系统函数

 主  题:  怎么拦截系统函数?(超高度难题!)    在Dos下,我们可以拦截中断,用自己的处理替换系统中断,然后调用原来的中断,在Windows中,没有了中断,只有函数,那么我们如何来拦截系统的函数,然后我们的函数又调用原来的系统函数呢?比如说系统有一个GetSystemDirectory()函数,我想用我自己的函数替换它,经过我的函数MyGetSystemDirectory()进行处理,然

6559

C语言实现导入表注入

导入表注入原理: 当exe被加载时,系统会根据exe导入表信息来加载需要用到的DLL,导入表注入的原理就是修改exe导入表,将自己的DLL写入exe中 导入表注入的实现步骤: 第一步:根据目录项(第二个就是导入表)得到导入表信息 typedef struct _IMAGE_DATA_DIRECTORY { DWORD VirtualAddress;:指向导入表结构 DWO...

jxust_xiaoxiong 733

PE中节表IMAGE_SECTION_HEADER详(四)

typedef struct _IMAGE_SECTION_HEADER { BYTE Name[IMAGE_ SIZEOF_ SHORT_ NAME]; //ASCI字符串 可自定义只截取8个 union { DWORD PhysicalAddress; DWORD VirtualSize; } Mlisc; DWORD VirtualAddress;//在内存中的偏移地址,加上Im...

想喝奶茶的胖大海 1363

PE文件导入表代码解析

解析导入表就需要先认识下面这三个结构体 //导入表结构体 typedef struct _IMAGE_IMPORT_DESCRIPTOR { union { DWORD Characteristics; //主要这个,包含指向INT的RVA DWORD OriginalFirstThunk; }; //时间标识 DWORD TimeDateStamp...

做一个快乐学习者 759
上一篇: 编写自定义PE结构的程序
下一篇: 高级语言实现文件感染的方法
iiprogram
博客等级 码龄25年 1068粉丝 1515原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值