PE格式是Windows系统下最常用的可执行文件格式,有些应用必须建立在了解PE文件格式的基础之上,如可执行文件的加密与解密,文件型病毒的查杀等,熟练掌握PE文件结构,有助于软件的分析.

在PE文件中,代码,已初始化的数据,资源和重定位信息等数据被按照属性分类放到不同的Section(节区/或简称为节)中,而每个节区的属性和位置等信息用一个IMAGE_SECTION_HEADER结构来描述,所有的IMAGE_SECTION_HEADER结构组成了一个节表(Section Table),节表数据在PE文件中被放在所有节数据的前面.

在Win32系统中,当我们执行了可执行文件之后,可执行文件会被映射到内存,并且以4kb的粒度进行对齐,这个4kb也就是一个页面的大小,而每个页面又分别具有,可执行,可读写等属性.

PE格式中的DOS部分由MZ格式的文件头和可执行代码部分组成,可执行代码被称为DOS块(DOS stub).MZ格式的文件头由IMAGE_DOS_HEADER结构定义,以下就是DOS头部分的关键属性.

mov esi,lpMemoryassume esi:ptr IMAGE_DOS_HEADERmovzx eax,[esi].e_magic         ; 读取DOS的头部movzx eax,[esi].e_ss            ; DOS代码段的初始堆栈段movzx eax,[esi].e_sp            ; DOS代码段的初始堆栈指针movzx eax,[esi].e_cs            ; DOS代码的入口地址movzx eax,[esi].e_ip            ; DOS代码的入口IPmovzx eax,[esi].e_lfanew        ; 指向了PE文件的开头(重要)

第一个字段e_magic被定义为MZ,标志着DOS文件的开头部分,最后一个字段e_lfanew则指明了PE文件的开头位置,现在来说除了第一个字段和最后一个字段有些用处,其他的字段几乎已经废弃了,这里也不再介绍了.

解析PE头结构

从DOS文件头的e_lfanew字段(文件头偏移003ch),PE文件格式排列在DOS头的后面,也就是e_lfanew指针所指向的地址,而PE文件的第一个字节就是PE这两个字符,有了这些信息,我们就可以写一个小工具,来检测指定一个程序是否是可执行文件啦.

.dataszFileName db "lyshark.exe",0hhFile dd ?hMapFile dd ?lpMemory dd ?szText db "这是一个PE可执行文件 !",0h
.codemain PROC; 打开文件,并创建内存映射镜像invoke    CreateFile,addr szFileName,GENERIC_READ,FILE_SHARE_READ or \FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE,NULLmov hFile,eaxinvoke CreateFileMapping,hFile,NULL,PAGE_READONLY,0,0,NULLmov hMapFile,eaxinvoke MapViewOfFile,eax,FILE_MAP_READ,0,0,0mov lpMemory,eax
; -------------------------------------------------------------------; 检测PE文件是否有效,是否是一个正常的PEmov esi,lpMemoryassume esi:ptr IMAGE_DOS_HEADER; 判断是否为DOS文件头部.if [esi].e_magic == IMAGE_DOS_SIGNATUREadd esi,[esi].e_lfanew              ; 递增指针assume esi:ptr IMAGE_NT_HEADERS; 判断是否为PE可执行文件.if [esi].Signature == IMAGE_NT_SIGNATUREinvoke MessageBox,NULL,addr szText,0,MB_OK.endif.endif
; -------------------------------------------------------------------invoke UnmapViewOfFile,addr lpMemoryinvoke ExitProcess,NULLmain ENDP
END main

上面的核心代码原理也非常的简单,过程:读入文件,判断第一个字符是不是MZ,如果是MZ,则在判断e_lfanew指针指向的地址是不是PE如果是,则说明这是PE文件.

解析各区块信息

下面的代码,则用于读取PE文件的一些关键区块信息.

.386.model flat,stdcalloption casemap:noneinclude windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
include masm32.inc
includelib masm32.lib.dataszFileName db "lyshark.exe",0hhFile dd ?hMapFile dd ?lpMemory dd ?lpBuffer db 2048 dup(?)
.constszMsg db  "----------------------------------------",0dh,0ahdb  "运行平台:           0x%04X",0dh,0ahdb "节区数量:           %d",0dh,0ahdb "文件属性:           0x%04X",0dh,0ahdb "时间标记:            %d",0dh,0ahdb   "镜像装入基址:       0x%08X",0dh,0ahdb   "程序的入口RVA:      0x%08X",0dh,0ahdb  "代码节起始RVA:      0x%08X",0dh,0ahdb  "数据节起始RVA:      0x%08X",0dh,0ahdb  "----------------------------------------",0dh,0ah,0
.codemain PROC; 打开文件,并创建内存映射镜像invoke    CreateFile,addr szFileName,GENERIC_READ,FILE_SHARE_READ or \FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE,NULLmov hFile,eaxinvoke CreateFileMapping,hFile,NULL,PAGE_READONLY,0,0,NULLmov hMapFile,eaxinvoke MapViewOfFile,eax,FILE_MAP_READ,0,0,0mov lpMemory,eaxmov esi,lpMemoryassume    esi:ptr IMAGE_DOS_HEADERadd esi,[esi].e_lfanewassume esi:ptr IMAGE_NT_HEADERSinvoke wsprintf,addr lpBuffer,addr szMsg,\[esi].FileHeader.Machine, \                 ; 运行平台[esi].FileHeader.NumberOfSections, \        ; 节区数目[esi].FileHeader.Characteristics, \         ; 文件属性[esi].FileHeader.TimeDateStamp, \           ; 时间标记[esi].OptionalHeader.ImageBase, \           ; 镜像基址[esi].OptionalHeader.AddressOfEntryPoint, \ ; 入口RVA地址[esi].OptionalHeader.BaseOfCode, \          ; 代码节起始RVA[esi].OptionalHeader.BaseOfDatainvoke StdOut,addr lpBufferinvoke ExitProcess,NULLmain ENDP
END main

解析节与节表

系统装载可执行文件并不等同于内存映射,内存映射是将整个磁盘文件原封不动的搬到内存中去,而PE的加载则会处理一些其他数据,例如预处理,重定位等,装入以后页面位置,偏移等都会随之发生改变,Windows装载器在装载DOS部分,PE文件头部分和节表部分时不进行任何处理,而装载节的时候将根据节的属性做不同的处理.

.386.model flat,stdcalloption casemap:noneinclude windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
include masm32.inc
includelib masm32.lib.dataszFileName db "lyshark.exe",0hhFile dd ?hMapFile dd ?lpMemory dd ?lpBuffer db 2048 dup(?)
.constszMsg db  "----------------------------------------------------------",0dh,0ahdb    "节区名称  节区大小  虚拟地址  Raw_尺寸  Raw_偏移  节区属性",0dh,0ahdb    "----------------------------------------------------------",0dh,0ah,0szFmt   db  "%s  %08X  %08X  %08X  %08X  %08X",0dh,0ah,0
.codemain PROCinvoke    CreateFile,addr szFileName,GENERIC_READ,FILE_SHARE_READ or \FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE,NULLmov hFile,eaxinvoke CreateFileMapping,hFile,NULL,PAGE_READONLY,0,0,NULLmov hMapFile,eaxinvoke MapViewOfFile,eax,FILE_MAP_READ,0,0,0mov lpMemory,eaxmov esi,lpMemoryassume    esi:ptr IMAGE_DOS_HEADER     ; 指向DOS开头add esi,[esi].e_lfanew               ; 递增指针到PE结构开头assume esi:ptr IMAGE_NT_HEADERSinvoke StdOut,addr szMsg                        ; 输出提示信息movzx ecx,[esi].FileHeader.NumberOfSections     ; 取出节的数量,作为循环条件add esi,sizeof IMAGE_NT_HEADERS      ; 指向.text节assume esi:ptr IMAGE_SECTION_HEADER  ; 指向节中的SECTION.repeatpush ecx      ; wsprintf影响ecx寄存器,所以这里必须压栈保存数据mov eax,[esi].VirtualAddressinvoke wsprintf,addr lpBuffer,addr szFmt,esi, \   ; 节区名称[esi].Misc.VirtualSize, \                 ; 节区大小[esi].VirtualAddress, \                   ; 虚拟地址[esi].SizeOfRawData, \                    ; Raw_尺寸[esi].PointerToRawData, \                 ; Raw_偏移[esi].Characteristics                     ; 节区属性invoke StdOut,addr lpBuffer                       ; 打印节区信息pop ecxadd esi,sizeof IMAGE_SECTION_HEADER.untilcxzinvoke ExitProcess,NULLmain ENDP
END main

Win32汇编:PE结构解析器相关推荐

  1. 汇编版PE结构解析器

    PE格式是Windows系统下最常用的可执行文件格式,有些应用必须建立在了解PE文件格式的基础之上,如可执行文件的加密与解密,文件型病毒的查杀等,熟练掌握PE文件结构,有助于软件的分析,本文章文字描述 ...

  2. 图解VC++版PE文件解析器源码分析

    该源码下载自 http://download.csdn.net/download/witch_soya/4979587 1 Understand 分析的图表 2 PE结构解析的主要代码简要分析 首先看 ...

  3. 手写PE结构解析工具

    PE格式是 Windows下最常用的可执行文件格式,理解PE文件格式不仅可以了解操作系统的加载流程,还可以更好的理解操作系统对进程和内存相关的管理知识,而有些技术必须建立在了解PE文件格式的基础上,如 ...

  4. 编写PE文件解析器(三)

    下面有几个表网上资料比较少,因为几乎用不到,我查文档写写吧,这篇写得比较久很抱歉. 7.IMAGE_DIRECTORY_ENTRY_EXCEPTION[异常处理表] CPU特定的并且基于表的异常处理. ...

  5. windows PE结构解析

    1 基本概念 下表描述了贯穿于本文中的一些概念: 名称 描述 地址 是"虚拟地址"而不是"物理地址".为什么不是"物理地址"呢?因为数据在内 ...

  6. 【逆向工程】在PE结构空白区段插入代码

    最近在学PE结构,遇到了个比较有意思的实验,学过PE结构的都知道因为文件对齐FileAlignment和区块对齐SectionAlignment的缘故,在磁盘中的PE文件的块与块表 块与块之间有许多的 ...

  7. 【Android 逆向】使用 Python 解析 ELF 文件 ( Capstone 反汇编 ELF 文件中的机器码数据 | 创建反汇编解析器实例对象 | 设置汇编解析器显示细节 )

    文章目录 一.创建 Capstone 反汇编解析器实例对象 二.设置 Cs 汇编解析器显示细节 一.创建 Capstone 反汇编解析器实例对象 使用 Capstone 反汇编框架 , 首先创建 Ca ...

  8. boost::spirit模块实现一个雇员结构的解析器的测试程序

    boost::spirit模块实现一个雇员结构的解析器的测试程序 实现功能 C++实现代码 实现功能 boost::spirit模块实现一个雇员结构的解析器的测试程序 C++实现代码 #include ...

  9. 非结构化数据与结构化数据提取---- BeautifulSoup4 解析器

    CSS 选择器:BeautifulSoup4 和 lxml 一样,Beautiful Soup 也是一个HTML/XML的解析器,主要的功能也是如何解析和提取 HTML/XML 数据. lxml 只会 ...

最新文章

  1. get the better of sb
  2. python变量存为matlab,详解如何在python中读写和存储matlab的数据文件(*.mat)
  3. mysql 嵌入式 c开发环境_【Linux】嵌入式C语言MySQL编程(libmysqlclient-dev使用)
  4. lodoop打印控件详解
  5. Android 创建,验证和删除桌面快捷方式 (删除快捷方式测试可用)
  6. uni-app微信小程序image引入图片;background-image背景图引入图片;小程序预览本地图片;小程序图片过大引入报错;获取本地图片的网络地址;
  7. 如何判断字符串已经被url编码_如何判断回文数?不要再将整数转为字符串来解决这个问题了...
  8. python使用opencv实现人脸识别系统
  9. 关于sql备份到其他服务器的问题
  10. linux voip客户端,linux搭建VOIP
  11. C语言mutex使用案例,C语言 如何使用互斥锁严格交替使用两个线程?
  12. python能做什么工作-对话极客晨星:现在学Python 长大可以从事什么工作?
  13. 使用谷歌统计来跟踪网页加载时间
  14. linux查看端口出现unix,linux查看端口被占用状况
  15. 计算机设计大赛作品信息概要表模板
  16. Mac上安装VisualVM
  17. LocalDate 向后推几个月的日期如何计算
  18. 电磁兼容试验项目之谐波电流试验
  19. Java通过itextpdf生成PDF
  20. 计算机毕业设计——基于HTML电商购物商城项目设计与实现---(服装商城 4页 带登录 带动画)

热门文章

  1. context.write
  2. 【备战春招/秋招系列】美团Java面经总结终结篇 (附详解答案) 1
  3. Excel关闭受保护的视图
  4. 如何控制input的输入方向
  5. Android-APK瘦身实践
  6. android中一些特殊字符(如:←↑→↓等箭头符号)的Unicode码值
  7. java货郎担问题求解_货郎担问题(TSP)
  8. php 微信上传素材,微信上传素材php代码
  9. 超级好用 VMWare14 安装Mac OS10.12系统(图解)
  10. 关于计算ico文件hash值脚本