逆向-第五次实验-PE文件解析
前几天随便贴了点代码,实际上只是拿来作为网页读的(ai可以读网页html文本)
给自己留个坑而已
结构分析
PE文件解析,我拿py实现的,因为用了库,蛮简单的,C写肯定麻烦点,但是显然实验并不是这个目的,所以写两版,一个是用了pefile的,一个是没用的,思路是一致的
首先分析必须的结构与其作用:
1. DOS头:DOS头是PE文件第一个结构,长度是64字节,它包含一个DOSStub程序和PE文件的指针,使非PE识别的系统认为该文件是一个正常的可执行文件,可供DOS系统加载执行,是PE文件必不可少的部分。
2. PE文件头:PE文件头紧跟在DOS头之后,长度是20字节,它包含PE文件的标识和结构信息,如PE标记、区段数、时间日期戳等,这些信息是加载和解析PE文件必需的,所以PE文件头是必不可少的部分。
3. 可选头:可选头包含PE文件加载和执行所必需的信息,如代码区段大小、数据区段大小、目标系统版本等。这些信息是PE文件在Windows下正确加载和执行所必需的,所以可选头是必不可少的部分。
4. 区段表:区段表定义了PE文件中多个区段的信息,如区段名、起始RVA、大小、权限等。PE文件中实际的数据是通过区段来组织和映射的,区段表作为这个映射的基础,是解析实际数据必不可少的信息,所以它是PE文件必不可少的部分。
5. 导入表:导入表列出了PE文件引用的外部函数和DLL。PE文件需要调用导入表中列出的外部函数和DLL,否则无法正常执行,所以导入表是PE文件必不可少的部分。
6. 代码区段:代码区段包含了PE文件执行所需的代码和数据。没有代码区段,PE文件无法执行任何操作,所以代码区段是PE文件必不可少的部分。
接着分析解析的流程:
1. 解析PE文件头。读取前128字节,解析MAGIC,PE标记,文件大小等信息。
2. 解析可选头。读取可选头大小,解析可选头中的数据目录等。
3. 解析区段表。读取区段个数,对每个区段解析区段名、区段大小、区段偏移等信息。
4. 解析导出表。读取导出表目录入口的RVA和大小,解析导出表得到函数名、函数RVA等信息。
5. 解析导入表。读取导入表目录入口的RVA和大小,解析导入表得到DLL名、函数名、函数RVA等信息。
6. 解析代码区段。读取代码区段。RVA和Raw size,提取代码区段的数据。
7. 解析数据区段。读取数据区段RVA和大小,提取数据。
8. 解析调试信息。读取调试目录入口,解析调试信息中的代码View和数据View信息。
9. 解析资源。读取资源目录入口,解析各种资源类型、资源名和资源数据。
python实现PE文件解析1.py
实际无法使用,有点小问题,而且我都用py了得用库吧
filepath=input(":") # DOS def parse_dos_header(data): dos_header = {} dos_header['magic'] = data[:2] # 魔数MZ dos_header['lastsize'] = data[2:4] # 最后一页大小 dos_header['nblocks'] = data[4:6] # 内存块数 dos_header['nrelocs'] = data[6:8] # 重定位项数 dos_header['header_size'] = data[8:12] # 头部大小PE文件 dos_header['min_extra_paragraphs'] = data[12:14] # 最小额外段数 dos_header['max_extra_paragraphs'] = data[14:16] # 最大额外段数 dos_header['ss'] = data[16:18] # 初始(相对)SS值 dos_header['sp'] = data[18:20] # 初始SP值 dos_header['checksum'] = data[20:24] # 检验和 dos_header['ip'] = data[24:26] # 初始IP值 dos_header['cs'] = data[26:28] # 初始(相对)CS值 dos_header['lfarlc'] = data[28:32] # 重定位表偏移地址 dos_header['ovno'] = data[32:34] # 叠加号 return dos_header # 解析PE文件头 def parse_pe_header(data): header = {} header['signature'] = data[:2] # PE标记 header['machine'] = data[4:6] # 机器类型 header['sections'] = data[6:8] # 区段数 header['time'] = data[8:12] # 时间日期戳 return header # 解析可选头 def parse_optional_header(data): optional_header = {} optional_header['magic'] = data[:2] # 魔数 0x10B optional_header['majorlinker'] = data[2:4] # Linker 版本号 主版本 optional_header['minorlinker'] = data[4:6] # Linker 版本号 次版本 optional_header['codesize'] = data[16:20] # 代码区段大小 optional_header['initedata'] = data[20:24] # 已初始化数据大小 optional_header['uninitedata'] = data[24:28]# 未初始化数据大小 return optional_header # 解析区段表 def parse_section_table(data): section_table = [] for i in range(len(data) // 40): # 每个区段描述占用40字节 section = {} section['name'] = data[i*40:(i+1)*40][:8].decode('utf-8').strip('\x00') section['virtualsize'] = data[i*40+8:i*40+12] # 区段虚拟大小 section['virtualaddress'] = data[i*40+12:i*40+16] # 区段虚拟地址 section['sizeofraw'] = data[i*40+16:i*40+20] # 原始大小 section['pointertoraw'] = data[i*40+20:i*40+24] # 文件指针 section_table.append(section) return section_table # 解析导入表 def parse_import_table(data): import_table = {} import_table['importlookup'] = data[:4] # 导入查找表RVA # 遍历导入描述表,每个表占用20字节 for i in range(len(data[4:]) // 20): import_desc = {} import_desc['origfirstthunk'] = data[4+i*20:8+i*20] # 未绑定的导入地址表RVA import_desc['timedatestamp'] = data[8+i*20:12+i*20] # 时间日期戳 import_desc['forwarderchain'] = data[12+i*20:16+i*20] # 链到下一个导入描述表 import_desc['name'] = data[16+i*20:20+i*20] # 模块名地址RVA import_desc['firstthunk'] = data[20+i*20:24+i*20] # 绑定的导入地址表RVA import_table[i] = import_desc # 解析导入查找表,每个元素占用4字节 for j in range(len(data[import_table['importlookup']:]) // 4): thunk_data = {} thunk_data['lookup'] = data[import_table['importlookup']+j*4:import_table['importlookup']+4+j*4] thunk_data['name'] = data[import_table[0]['name']+thunk_data['lookup']-import_table['importlookup']+2: data.find(b'\x00', import_table[0]['name']+thunk_data['lookup']-import_table['importlookup'])].decode('utf-8') import_table[j] = thunk_data return import_table # 解析导出表 def parse_export_table(data): export_table = {} export_table['exportflags'] = data[:4] # 导出标志 export_table['timedatestamp'] = data[4:8] # 时间日期戳 export_table['majorversion'] = data[8:12] # 主版本 export_table['minorversion'] = data[12:16] # 次版本 export_table['name'] = data[16:32].decode('utf-8').strip('\x00') # 表名 export_table['ordinalbase'] = data[32:36] # 基础序号 export_table['numberofnames'] = data[36:40] # 名称个数 export_table['numberOfFunctions'] = data[40:44] # 函数个数 export_table['addressoffunctions'] = data[44:48] # 函数地址索引的RVA export_table['nameptrs'] = data[48:52] # 名称指针RVA export_table['ordinals'] = data[52:56] # 序数表RVA return export_table # 主函数 def main(): with open(filepath, 'rb') as f: data = f.read() dos_header = parse_dos_header(data) # 解析PE头 header = parse_pe_header(data) # 解析各个表和区段 optional_header = parse_optional_header(data[128:]) import_table=parse_import_table(data) section_table = parse_section_table(data[128+224:]) export_table = parse_export_table(data[section_table[0]['pointerto raw']:]) if __name__ == '__main__': main()
以上代码是一个不算完整但还可以的代码(指运行起来还需要改很多),下面这个就很一般了,只是加了pefile和一些用户体验感(主要问题在于用py不用库很难受)
Python实现PE文件解析代码2.py
import pefile import os filepath= input("input your exe path:") pe = pefile.PE(filepath) names=[] start_line=None with open(f"PEreader.txt", 'w', encoding='utf8') as f: f.write(pe.dump_info()) with open(f"PEreader.txt",'r',encoding="utf8") as f: lines = f.readlines() for line in lines: if line.startswith('----------'): names.append(line) while(1): for name in names: print(name) name= input('Enter your find name(or Enter all): ') if name == "all": for line in lines: print(line) else: judge=0 for line in lines: if line.startswith('----------'): if name in line: start_line = lines.index(line) for line in lines[start_line:]: if line.startswith('----------'): judge=judge+1 if judge==2: break print(line) if judge == 2: print("succes to find") print() else: print("failed to find") print()
py打包挺头疼的,不如直接编译,我用了pyinstaller这个库,当然,使用的时候也是蛮难受的,因为需要保持你拥有这个库的同时还拥有你的py文件权限,意思是cd到文件夹那里,因为使用的是anaconda,所以要在conda 的命令行运行
大约就是这样,然后你在文件夹里找dist文件夹,里面会有exe文件,点开就有了
本文来自博客园,作者:逆世混沌,转载请注明原文链接:https://www.cnblogs.com/nish1hundun/p/17381106.html
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步