saferwall/pe
GitHub: saferwall/pe
这是一个轻量级的 Go 语言库,用于解析和分析 Windows PE 二进制文件元数据,专为恶意软件分析设计且对畸形文件具备鲁棒性。
Stars: 382 | Forks: 60
# Portable Executable 解析器
[](https://pkg.go.dev/github.com/saferwall/pe)  [](https://goreportcard.com/report/github.com/saferwall/pe) [](https://codecov.io/gh/saferwall/pe) 
**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](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安全, 二进制分析, 云安全监控, 云安全运维, 云资产清单, 安全编程, 导入表, 导出表, 恶意代码分析, 恶意软件分析, 文件格式, 日志审计, 熵计算, 程序破解, 节区分析, 资源解析, 轻量级, 逆向工程, 配置文件, 重定位表, 静态分析