saferwall/pe

GitHub: saferwall/pe

这是一个轻量级的 Go 语言库,用于解析和分析 Windows PE 二进制文件元数据,专为恶意软件分析设计且对畸形文件具备鲁棒性。

Stars: 382 | Forks: 60

Saferwall logo # Portable Executable 解析器 [![GoDoc](http://godoc.org/github.com/saferwall/pe?status.svg)](https://pkg.go.dev/github.com/saferwall/pe) ![Go Version](https://img.shields.io/badge/go%20version-%3E=1.15-61CFDD.svg) [![Report Card](https://goreportcard.com/badge/github.com/saferwall/pe)](https://goreportcard.com/report/github.com/saferwall/pe) [![codecov](https://codecov.io/gh/saferwall/pe/branch/main/graph/badge.svg?token=W7WTOUZLRY)](https://codecov.io/gh/saferwall/pe) ![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/saferwall/pe/ci.yaml?branch=main) **pe** 是一个用于解析 [portable executable](https://docs.microsoft.com/en-us/windows/win32/debug/pe-format) 文件格式的 go 包。该包的设计初衷是用于恶意软件分析,并且能够抵抗 PE 格式的畸形文件。 ## 目录 - [Portable Executable 解析器](#portable-executable-parser) - [目录](#table-of-content) - [功能特性](#features) - [安装说明](#installing) - [使用该库](#using-the-library) - [PE 头](#pe-header) - [Rich 头](#rich-header) - [遍历节区](#iterating-over-sections) - [路线图](#roadmap) - [模糊测试](#fuzz-testing) - [使用本库的项目](#projects-using-this-library) - [参考资料](#references) ## 功能特性 - 支持 PE32/PE32+ 文件格式。 - 支持 Intel x86/AMD64/ARM7ARM7 Thumb/ARM8-64/IA64/CHPE 架构。 - MS DOS 头。 - Rich 头(计算校验和与哈希)。 - NT 头(文件头 + 可选头)。 - COFF 符号表和字符串表。 - 节区头 + 熵计算。 - 数据目录 - 导入表 + ImpHash 计算。 - 导出表 - 资源表 - 异常表 - 安全表 + Authentihash 计算。 - 重定位表 - 调试表(CODEVIEW, POGO, VC FEATURE, REPRO, FPO, EXDLL CHARACTERISTICS 等调试类型)。 - TLS 表 - 加载配置目录(SEH, GFID, GIAT, Guard LongJumps, CHPE, Dynamic Value Reloc Table, Enclave Configuration, Volatile Metadata 表)。 - 绑定导入表 - 延迟导入表 - COM 表(CLR 元数据头,元数据表流) - 报告多种异常情况 ## 安装说明 使用这个 go 包非常简单。首先,使用 `go get` 安装最新版本的库。此命令将安装 `pedumper` 可执行文件以及库及其依赖项: ``` go get -u github.com/saferwall/pe ``` 接下来,在你的应用程序中包含 `pe` 包: ``` import "github.com/saferwall/pe" ``` ## 使用该库 ``` package main import ( peparser "github.com/saferwall/pe" ) func main() { filename := "C:\\Binaries\\notepad.exe" pe, err := peparser.New(filename, &peparser.Options{}) if err != nil { log.Fatalf("Error while opening file: %s, reason: %v", filename, err) } err = pe.Parse() if err != nil { log.Fatalf("Error while parsing file: %s, reason: %v", filename, err) } } ``` 首先通过调用 `New()` 方法实例化一个 pe 对象,该方法接受要解析的文件的路径以及一些可选参数。 之后,调用 `Parse()` 方法即可访问 PE 格式的所有不同部分,这些部分可直接供你使用。以下是该结构的定义: ``` type File struct { DOSHeader ImageDOSHeader `json:"dos_header,omitempty"` RichHeader RichHeader `json:"rich_header,omitempty"` NtHeader ImageNtHeader `json:"nt_header,omitempty"` COFF COFF `json:"coff,omitempty"` Sections []Section `json:"sections,omitempty"` Imports []Import `json:"imports,omitempty"` Export Export `json:"export,omitempty"` Debugs []DebugEntry `json:"debugs,omitempty"` Relocations []Relocation `json:"relocations,omitempty"` Resources ResourceDirectory `json:"resources,omitempty"` TLS TLSDirectory `json:"tls,omitempty"` LoadConfig LoadConfig `json:"load_config,omitempty"` Exceptions []Exception `json:"exceptions,omitempty"` Certificates CertificateSection `json:"certificates,omitempty"` DelayImports []DelayImport `json:"delay_imports,omitempty"` BoundImports []BoundImportDescriptorData `json:"bound_imports,omitempty"` GlobalPtr uint32 `json:"global_ptr,omitempty"` CLR CLRData `json:"clr,omitempty"` IAT []IATEntry `json:"iat,omitempty"` Anomalies []string `json:"anomalies,omitempty"` Header []byte data mmap.MMap FileInfo size uint32 OverlayOffset int64 f *os.File opts *Options logger *log.Helper } ``` ### PE 头 如前所述,结构体的所有成员都是直接可访问的(没有 getter),此外,字段类型已按照规范定义予以保留,这意味着如果你需要显示 `int` 类型的美化版本,必须调用相应的辅助函数。 ``` fmt.Printf("Magic is: 0x%x\n", pe.DOSHeader.Magic) fmt.Printf("Signature is: 0x%x\n", pe.NtHeader.Signature) fmt.Printf("Machine is: 0x%x, Meaning: %s\n", pe.NtHeader.FileHeader.Machine, pe.NtHeader.FileHeader.Machine.String()) ``` 输出: ``` Magic is: 0x5a4d Signature is: 0x4550 Machine is: 0x8664, Meaning: x64 ``` ### Rich 头 示例: ``` richHeader, _ := json.Marshal(pe.RichHeader) fmt.Print(prettyPrint(richHeader)) ``` 输出: ``` { "XorKey": 2796214951, "CompIDs": [ { "MinorCV": 27412, "ProdID": 257, "Count": 4, "Unmasked": 16870164 }, { "MinorCV": 30729, "ProdID": 147, "Count": 193, "Unmasked": 9664521 }, { "MinorCV": 0, "ProdID": 1, "Count": 1325, "Unmasked": 65536 }, { "MinorCV": 27412, "ProdID": 260, "Count": 9, "Unmasked": 17066772 }, { "MinorCV": 27412, "ProdID": 259, "Count": 3, "Unmasked": 17001236 }, { "MinorCV": 27412, "ProdID": 256, "Count": 1, "Unmasked": 16804628 }, { "MinorCV": 27412, "ProdID": 269, "Count": 209, "Unmasked": 17656596 }, { "MinorCV": 27412, "ProdID": 255, "Count": 1, "Unmasked": 16739092 }, { "MinorCV": 27412, "ProdID": 258, "Count": 1, "Unmasked": 16935700 } ], "DansOffset": 128, "Raw": "47vE9afaqqan2qqmp9qqprOxq6ej2qqmrqI5pmbaqqan2qumit+qprOxrqeu2qqms7Gpp6TaqqazsaqnptqqprOxp6d22qqms7FVpqbaqqazsainptqqplJpY2in2qqm" } ``` ### 遍历节区 ``` for _, sec := range pe.Sections { fmt.Printf("Section Name : %s\n", sec.NameString()) fmt.Printf("Section VirtualSize : %x\n", sec.Header.VirtualSize) fmt.Printf("Section Flags : %x, Meaning: %v\n\n", sec.Header.Characteristics, sec.PrettySectionFlags()) } ``` 输出: ``` Section Name : .text Section VirtualSize : 2ea58 Section Flags : 60500060, Meaning: [Align8Bytes Readable Align16Bytes Executable Contains Code Initialized Data Align1Bytes] Section Name : .data Section VirtualSize : 58 Section Flags : c0500040, Meaning: [Readable Initialized Data Writable Align1Bytes Align16Bytes Align8Bytes] Section Name : .rdata Section VirtualSize : 18d0 Section Flags : 40600040, Meaning: [Align2Bytes Align8Bytes Readable Initialized Data Align32Bytes] ... ``` ## 路线图 - 导入 MS 风格的名称修饰(name mangling) - PE:VB5 和 VB6 典型结构:项目信息、DLLCall 导入、引用的模块、对象表 ## 模糊测试 为了验证解析器,我们使用了 [go-fuzz](https://github.com/dvyukov/go-fuzz) 以及来自 [corkami](https://github.com/corkami/pocs/tree/master/PE) 的已知畸形和棘手的 PE 文件语料库。 ## 使用本库的项目 Fibratus [Fibratus](https://github.com/rabbitstack/fibratus) 一个专注于安全的现代 Windows 内核探索和跟踪工具。 ## 参考资料 - [Peering Inside the PE: A Tour of the Win32 Portable Executable File Format by Matt Pietrek](http://bytepointer.com/resources/pietrek_peering_inside_pe.htm) - [An In-Depth Look into the Win32 Portable Executable File Format - Part 1 by Matt Pietrek](http://www.delphibasics.info/home/delphibasicsarticles/anin-depthlookintothewin32portableexecutablefileformat-part1) - [An In-Depth Look into the Win32 Portable Executable File Format - Part 2 by Matt Pietrek](http://www.delphibasics.info/home/delphibasicsarticles/anin-depthlookintothewin32portableexecutablefileformat-part2) - [Portable Executable File Format](https://blog.kowalczyk.info/articles/pefileformat.html) - [PE Format MSDN spec](https://docs.microsoft.com/en-us/windows/win32/debug/pe-format) - [DotNET format](https://www.ntcore.com/files/dotnetformat.htm) - [BlackHat 2011 - CONSTANT INSECURITY: (PECOFF) Portable Executable FIle Format](https://www.youtube.com/watch?v=uoQL3CE24ls)
标签:Authentihash, COFF, Conpot, DAST, EVTX分析, Golang, Go语言, ImpHash, LangChain, PE文件解析, PE格式, Rich Header, Windows安全, 二进制分析, 云安全监控, 云安全运维, 云资产清单, 安全编程, 导入表, 导出表, 恶意代码分析, 恶意软件分析, 文件格式, 日志审计, 熵计算, 程序破解, 节区分析, 资源解析, 轻量级, 逆向工程, 配置文件, 重定位表, 静态分析