PE图

DM
package main
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"io"
"os"
"unsafe"
)
type ImageDOSHeader struct {
Signature [2]byte
BytesOnLastPage uint16
PagesInFile uint16
Relocations uint16
SizeOfHeader uint16
MinExtraParagraphs uint16
MaxExtraParagraphs uint16
InitialSS uint16
InitialSP uint16
Checksum uint16
InitialIP uint16
InitialCS uint16
AddressOfRelocationTable uint16
OverlayNumber uint16
Reserved1 [4]uint16
OEMID uint16
OEMInfo uint16
Reserved2 [10]uint16
AddressOfNewExeHeader uint32
}
type ImageNTHeaders struct {
Signature [4]byte
FileHeader ImageFileHeader
OptionalHeader ImageOptionalHeader
}
type ImageFileHeader struct {
Machine uint16
NumberOfSections uint16
TimeDateStamp uint32
PointerToSymbolTable uint32
NumberOfSymbols uint32
SizeOfOptionalHeader uint16
Characteristics uint16
}
type ImageOptionalHeader struct {
Magic uint16
MajorLinkerVersion uint8
MinorLinkerVersion uint8
SizeOfCode uint32
SizeOfInitializedData uint32
SizeOfUninitializedData uint32
AddressOfEntryPoint uint32
BaseOfCode uint32
BaseOfData uint32
ImageBase uint64
SectionAlignment uint32
FileAlignment uint32
MajorOperatingSystemVersion uint16
MinorOperatingSystemVersion uint16
MajorImageVersion uint16
MinorImageVersion uint16
MajorSubsystemVersion uint16
MinorSubsystemVersion uint16
Win32VersionValue uint32
SizeOfImage uint32
SizeOfHeaders uint32
CheckSum uint32
Subsystem uint16
DllCharacteristics uint16
SizeOfStackReserve uint64
SizeOfStackCommit uint64
SizeOfHeapReserve uint64
SizeOfHeapCommit uint64
LoaderFlags uint32
NumberOfRvaAndSizes uint32
DataDirectory [16]ImageDataDirectory
}
type ImageDataDirectory struct {
VirtualAddress uint32
Size uint32
}
type ImageSectionHeader struct {
Name [8]byte
VirtualSize uint32
VirtualAddress uint32
SizeOfRawData uint32
PointerToRawData uint32
PointerToRelocations uint32
PointerToLinenumbers uint32
NumberOfRelocations uint16
NumberOfLinenumbers uint16
Characteristics uint32
}
type PEResolver struct {
file *os.File
dosHeader ImageDOSHeader
ntHeaders ImageNTHeaders
sectionHeaders []ImageSectionHeader
is64Bit bool
data []byte
imageBuffer []byte
fileBuffer []byte
}
func OpenPEFile(filename string) (*PEResolver, error) {
file, err := os.Open(filename)
if err != nil {
return nil, err
}
data, err := io.ReadAll(file)
if err != nil {
file.Close()
return nil, err
}
pe := &PEResolver{
file: file,
data: data,
}
if err := pe.parseDOSHeader(); err != nil {
return nil, err
}
if err := pe.parseNTHeaders(); err != nil {
return nil, err
}
if err := pe.parseSectionHeaders(); err != nil {
return nil, err
}
return pe, nil
}
func (pe *PEResolver) parseDOSHeader() error {
if len(pe.data) < int(unsafe.Sizeof(ImageDOSHeader{})) {
return errors.New("文件太小,不是有效的 PE 文件")
}
buf := bytes.NewReader(pe.data)
if err := binary.Read(buf, binary.LittleEndian, &pe.dosHeader); err != nil {
return err
}
if string(pe.dosHeader.Signature[:]) != "MZ" {
return errors.New("不是有效的 PE 文件: 缺少 MZ 签名")
}
return nil
}
func (pe *PEResolver) parseNTHeaders() error {
offset := int64(pe.dosHeader.AddressOfNewExeHeader)
if offset+int64(unsafe.Sizeof(ImageNTHeaders{})) > int64(len(pe.data)) {
return errors.New("文件太小,无法包含 NT 头部")
}
var signature [4]byte
copy(signature[:], pe.data[offset:offset+4])
if string(signature[:]) != "PE\x00\x00" {
fmt.Println(string(signature[:]))
return errors.New("不是有效的 PE 文件: 缺少 PE 签名")
}
buf := bytes.NewReader(pe.data[offset+4:])
if err := binary.Read(buf, binary.LittleEndian, &pe.ntHeaders.FileHeader); err != nil {
return err
}
pe.is64Bit = (pe.ntHeaders.FileHeader.Machine == 0x8664)
if pe.is64Bit {
var optionalHeader64 ImageOptionalHeader64
if err := binary.Read(buf, binary.LittleEndian, &optionalHeader64); err != nil {
return err
}
pe.ntHeaders.OptionalHeader.Magic = optionalHeader64.Magic
pe.ntHeaders.OptionalHeader.MajorLinkerVersion = optionalHeader64.MajorLinkerVersion
pe.ntHeaders.OptionalHeader.MinorLinkerVersion = optionalHeader64.MinorLinkerVersion
pe.ntHeaders.OptionalHeader.SizeOfCode = optionalHeader64.SizeOfCode
pe.ntHeaders.OptionalHeader.SizeOfInitializedData = optionalHeader64.SizeOfInitializedData
pe.ntHeaders.OptionalHeader.SizeOfUninitializedData = optionalHeader64.SizeOfUninitializedData
pe.ntHeaders.OptionalHeader.AddressOfEntryPoint = optionalHeader64.AddressOfEntryPoint
pe.ntHeaders.OptionalHeader.BaseOfCode = optionalHeader64.BaseOfCode
pe.ntHeaders.OptionalHeader.ImageBase = optionalHeader64.ImageBase
pe.ntHeaders.OptionalHeader.SectionAlignment = optionalHeader64.SectionAlignment
pe.ntHeaders.OptionalHeader.FileAlignment = optionalHeader64.FileAlignment
pe.ntHeaders.OptionalHeader.MajorOperatingSystemVersion = optionalHeader64.MajorOperatingSystemVersion
pe.ntHeaders.OptionalHeader.MinorOperatingSystemVersion = optionalHeader64.MinorOperatingSystemVersion
pe.ntHeaders.OptionalHeader.MajorImageVersion = optionalHeader64.MajorImageVersion
pe.ntHeaders.OptionalHeader.MinorImageVersion = optionalHeader64.MinorImageVersion
pe.ntHeaders.OptionalHeader.MajorSubsystemVersion = optionalHeader64.MajorSubsystemVersion
pe.ntHeaders.OptionalHeader.MinorSubsystemVersion = optionalHeader64.MinorSubsystemVersion
pe.ntHeaders.OptionalHeader.Win32VersionValue = optionalHeader64.Win32VersionValue
pe.ntHeaders.OptionalHeader.SizeOfImage = optionalHeader64.SizeOfImage
pe.ntHeaders.OptionalHeader.SizeOfHeaders = optionalHeader64.SizeOfHeaders
pe.ntHeaders.OptionalHeader.CheckSum = optionalHeader64.CheckSum
pe.ntHeaders.OptionalHeader.Subsystem = optionalHeader64.Subsystem
pe.ntHeaders.OptionalHeader.DllCharacteristics = optionalHeader64.DllCharacteristics
pe.ntHeaders.OptionalHeader.SizeOfStackReserve = optionalHeader64.SizeOfStackReserve
pe.ntHeaders.OptionalHeader.SizeOfStackCommit = optionalHeader64.SizeOfStackCommit
pe.ntHeaders.OptionalHeader.SizeOfHeapReserve = optionalHeader64.SizeOfHeapReserve
pe.ntHeaders.OptionalHeader.SizeOfHeapCommit = optionalHeader64.SizeOfHeapCommit
pe.ntHeaders.OptionalHeader.LoaderFlags = optionalHeader64.LoaderFlags
pe.ntHeaders.OptionalHeader.NumberOfRvaAndSizes = optionalHeader64.NumberOfRvaAndSizes
copy(pe.ntHeaders.OptionalHeader.DataDirectory[:], optionalHeader64.DataDirectory[:])
} else {
var optionalHeader32 ImageOptionalHeader32
if err := binary.Read(buf, binary.LittleEndian, &optionalHeader32); err != nil {
return err
}
pe.ntHeaders.OptionalHeader.Magic = optionalHeader32.Magic
pe.ntHeaders.OptionalHeader.MajorLinkerVersion = optionalHeader32.MajorLinkerVersion
pe.ntHeaders.OptionalHeader.MinorLinkerVersion = optionalHeader32.MinorLinkerVersion
pe.ntHeaders.OptionalHeader.SizeOfCode = optionalHeader32.SizeOfCode
pe.ntHeaders.OptionalHeader.SizeOfInitializedData = optionalHeader32.SizeOfInitializedData
pe.ntHeaders.OptionalHeader.SizeOfUninitializedData = optionalHeader32.SizeOfUninitializedData
pe.ntHeaders.OptionalHeader.AddressOfEntryPoint = optionalHeader32.AddressOfEntryPoint
pe.ntHeaders.OptionalHeader.BaseOfCode = optionalHeader32.BaseOfCode
pe.ntHeaders.OptionalHeader.BaseOfData = optionalHeader32.BaseOfData
pe.ntHeaders.OptionalHeader.ImageBase = uint64(optionalHeader32.ImageBase)
pe.ntHeaders.OptionalHeader.SectionAlignment = optionalHeader32.SectionAlignment
pe.ntHeaders.OptionalHeader.FileAlignment = optionalHeader32.FileAlignment
pe.ntHeaders.OptionalHeader.MajorOperatingSystemVersion = optionalHeader32.MajorOperatingSystemVersion
pe.ntHeaders.OptionalHeader.MinorOperatingSystemVersion = optionalHeader32.MinorOperatingSystemVersion
pe.ntHeaders.OptionalHeader.MajorImageVersion = optionalHeader32.MajorImageVersion
pe.ntHeaders.OptionalHeader.MinorImageVersion = optionalHeader32.MinorImageVersion
pe.ntHeaders.OptionalHeader.MajorSubsystemVersion = optionalHeader32.MajorSubsystemVersion
pe.ntHeaders.OptionalHeader.MinorSubsystemVersion = optionalHeader32.MinorSubsystemVersion
pe.ntHeaders.OptionalHeader.Win32VersionValue = optionalHeader32.Win32VersionValue
pe.ntHeaders.OptionalHeader.SizeOfImage = optionalHeader32.SizeOfImage
pe.ntHeaders.OptionalHeader.SizeOfHeaders = optionalHeader32.SizeOfHeaders
pe.ntHeaders.OptionalHeader.CheckSum = optionalHeader32.CheckSum
pe.ntHeaders.OptionalHeader.Subsystem = optionalHeader32.Subsystem
pe.ntHeaders.OptionalHeader.DllCharacteristics = optionalHeader32.DllCharacteristics
pe.ntHeaders.OptionalHeader.SizeOfStackReserve = uint64(optionalHeader32.SizeOfStackReserve)
pe.ntHeaders.OptionalHeader.SizeOfStackCommit = uint64(optionalHeader32.SizeOfStackCommit)
pe.ntHeaders.OptionalHeader.SizeOfHeapReserve = uint64(optionalHeader32.SizeOfHeapReserve)
pe.ntHeaders.OptionalHeader.SizeOfHeapCommit = uint64(optionalHeader32.SizeOfHeapCommit)
pe.ntHeaders.OptionalHeader.LoaderFlags = optionalHeader32.LoaderFlags
pe.ntHeaders.OptionalHeader.NumberOfRvaAndSizes = optionalHeader32.NumberOfRvaAndSizes
copy(pe.ntHeaders.OptionalHeader.DataDirectory[:], optionalHeader32.DataDirectory[:])
}
return nil
}
func (pe *PEResolver) parseSectionHeaders() error {
numSections := pe.ntHeaders.FileHeader.NumberOfSections
if numSections == 0 {
return errors.New("PE 文件没有节表")
}
offset := int64(pe.dosHeader.AddressOfNewExeHeader) + 4 +
int64(unsafe.Sizeof(ImageFileHeader{})) +
int64(pe.ntHeaders.FileHeader.SizeOfOptionalHeader)
if offset+int64(numSections)*int64(unsafe.Sizeof(ImageSectionHeader{})) > int64(len(pe.data)) {
return errors.New("文件太小,无法包含完整的节表")
}
pe.sectionHeaders = make([]ImageSectionHeader, numSections)
buf := bytes.NewReader(pe.data[offset:])
for i := 0; i < int(numSections); i++ {
if err := binary.Read(buf, binary.LittleEndian, &pe.sectionHeaders[i]); err != nil {
return err
}
}
return nil
}
func (pe *PEResolver) StretchToImageBuffer() error {
imageSize := pe.ntHeaders.OptionalHeader.SizeOfImage
if imageSize == 0 {
return errors.New("PE 文件的 SizeOfImage 为 0,无法拉伸")
}
pe.imageBuffer = make([]byte, imageSize)
headerSize := pe.ntHeaders.OptionalHeader.SizeOfHeaders
if int(headerSize) > len(pe.data) {
return errors.New("PE 文件头大小超过实际文件大小")
}
copy(pe.imageBuffer[:headerSize], pe.data[:headerSize])
for _, section := range pe.sectionHeaders {
virtualAddr := section.VirtualAddress
rawDataSize := section.SizeOfRawData
rawDataPtr := section.PointerToRawData
virtualSize := section.VirtualSize
if virtualAddr+virtualSize > imageSize {
return fmt.Errorf("节 %s 超出内存映像范围", string(bytes.TrimRight(section.Name[:], "\x00")))
}
if rawDataSize > 0 && rawDataPtr > 0 {
if int(rawDataPtr+rawDataSize) > len(pe.data) {
return fmt.Errorf("节 %s 的原始数据超出文件范围", string(bytes.TrimRight(section.Name[:], "\x00")))
}
copy(pe.imageBuffer[virtualAddr:virtualAddr+rawDataSize],
pe.data[rawDataPtr:rawDataPtr+rawDataSize])
}
if virtualSize > rawDataSize {
zeroStart := virtualAddr + rawDataSize
zeroLen := virtualSize - rawDataSize
for i := uint32(0); i < zeroLen; i++ {
pe.imageBuffer[zeroStart+i] = 0
}
}
}
return nil
}
func (pe *PEResolver) ConvertImageToFileBuffer() error {
if pe.imageBuffer == nil {
return errors.New("请先调用 StretchToImageBuffer 生成内存映像")
}
headerSize := pe.ntHeaders.OptionalHeader.SizeOfHeaders
maxFileSize := headerSize
for _, section := range pe.sectionHeaders {
sectionEnd := section.PointerToRawData + section.SizeOfRawData
if sectionEnd > maxFileSize {
maxFileSize = sectionEnd
}
}
pe.fileBuffer = make([]byte, maxFileSize)
copy(pe.fileBuffer[:headerSize], pe.imageBuffer[:headerSize])
for _, section := range pe.sectionHeaders {
virtualAddr := section.VirtualAddress
rawDataSize := section.SizeOfRawData
rawDataPtr := section.PointerToRawData
virtualSize := section.VirtualSize
if virtualAddr+virtualSize > uint32(len(pe.imageBuffer)) {
return fmt.Errorf("节 %s 超出内存映像范围", string(bytes.TrimRight(section.Name[:], "\x00")))
}
if rawDataPtr+rawDataSize > uint32(len(pe.fileBuffer)) {
return fmt.Errorf("节 %s 超出文件缓冲区范围", string(bytes.TrimRight(section.Name[:], "\x00")))
}
if rawDataSize > 0 {
copySize := rawDataSize
if virtualSize < rawDataSize {
copySize = virtualSize
}
copy(pe.fileBuffer[rawDataPtr:rawDataPtr+copySize],
pe.imageBuffer[virtualAddr:virtualAddr+copySize])
if copySize < rawDataSize {
paddingSize := rawDataSize - copySize
paddingStart := rawDataPtr + copySize
for i := uint32(0); i < paddingSize; i++ {
pe.fileBuffer[paddingStart+i] = 0
}
}
}
}
return nil
}
func (pe *PEResolver) GetImageBuffer() []byte {
return pe.imageBuffer
}
func (pe *PEResolver) GetFileBuffer() []byte {
return pe.fileBuffer
}
func (pe *PEResolver) PrintInfo() {
fmt.Println("=== PE 文件信息 ===")
fmt.Printf("DOS 签名: %s\n", string(pe.dosHeader.Signature[:]))
fmt.Printf("NT 签名: %s\n", string(pe.ntHeaders.Signature[:]))
machineType := "Unknown"
switch pe.ntHeaders.FileHeader.Machine {
case 0x014c:
machineType = "Intel 386"
case 0x8664:
machineType = "AMD64"
}
fmt.Printf("机器类型: %s\n", machineType)
fmt.Printf("入口点地址: 0x%X\n", pe.ntHeaders.OptionalHeader.AddressOfEntryPoint)
fmt.Printf("映像基址: 0x%X\n", pe.ntHeaders.OptionalHeader.ImageBase)
fmt.Printf("映像大小: 0x%X (%d 字节)\n",
pe.ntHeaders.OptionalHeader.SizeOfImage,
pe.ntHeaders.OptionalHeader.SizeOfImage)
fmt.Printf("文件头大小: 0x%X (%d 字节)\n",
pe.ntHeaders.OptionalHeader.SizeOfHeaders,
pe.ntHeaders.OptionalHeader.SizeOfHeaders)
fmt.Println("\n=== 节表信息 ===")
for i, section := range pe.sectionHeaders {
fmt.Printf("节 #%d: %s\n", i+1, string(bytes.TrimRight(section.Name[:], "\x00")))
fmt.Printf(" 虚拟地址: 0x%X\n", section.VirtualAddress)
fmt.Printf(" 虚拟大小: 0x%X\n", section.VirtualSize)
fmt.Printf(" 原始数据大小: 0x%X\n", section.SizeOfRawData)
fmt.Printf(" 原始数据指针: 0x%X\n", section.PointerToRawData)
}
}
func (pe *PEResolver) Close() {
pe.file.Close()
}
func main() {
if len(os.Args) < 2 {
fmt.Println("用法: go run pe_parser.go <PE文件路径>")
return
}
filename := os.Args[1]
pe, err := OpenPEFile(filename)
if err != nil {
fmt.Printf("打开 PE 文件失败: %v\n", err)
return
}
defer pe.Close()
pe.PrintInfo()
err = pe.StretchToImageBuffer()
if err != nil {
fmt.Printf("拉伸 PE 文件失败: %v\n", err)
return
}
imageBuffer := pe.GetImageBuffer()
fmt.Printf("\n=== 内存映像信息 ===\n")
fmt.Printf("内存映像大小: %d 字节\n", len(imageBuffer))
err = pe.ConvertImageToFileBuffer()
if err != nil {
fmt.Printf("转换回文件格式失败: %v\n", err)
return
}
fileBuffer := pe.GetFileBuffer()
fmt.Printf("\n=== 文件缓冲区信息 ===\n")
fmt.Printf("文件缓冲区大小: %d 字节\n", len(fileBuffer))
pwd, _ := os.Getwd()
outputImageFile := pwd + "ss.stretched"
err = saveBufferToFile(outputImageFile, imageBuffer)
if err != nil {
fmt.Printf("保存内存映像失败: %v\n", err)
} else {
fmt.Printf("\n内存映像已保存到: %s\n", outputImageFile)
}
outputFile := pwd + "ss.rebuilt"
err = saveBufferToFile(outputFile, fileBuffer)
if err != nil {
fmt.Printf("保存重建文件失败: %v\n", err)
} else {
fmt.Printf("重建文件已保存到: %s\n", outputFile)
}
}
func saveBufferToFile(filename string, buffer []byte) error {
file, err := os.Create(filename)
if err != nil {
return err
}
defer file.Close()
_, err = file.Write(buffer)
return err
}
type ImageOptionalHeader64 struct {
Magic uint16
MajorLinkerVersion uint8
MinorLinkerVersion uint8
SizeOfCode uint32
SizeOfInitializedData uint32
SizeOfUninitializedData uint32
AddressOfEntryPoint uint32
BaseOfCode uint32
ImageBase uint64
SectionAlignment uint32
FileAlignment uint32
MajorOperatingSystemVersion uint16
MinorOperatingSystemVersion uint16
MajorImageVersion uint16
MinorImageVersion uint16
MajorSubsystemVersion uint16
MinorSubsystemVersion uint16
Win32VersionValue uint32
SizeOfImage uint32
SizeOfHeaders uint32
CheckSum uint32
Subsystem uint16
DllCharacteristics uint16
SizeOfStackReserve uint64
SizeOfStackCommit uint64
SizeOfHeapReserve uint64
SizeOfHeapCommit uint64
LoaderFlags uint32
NumberOfRvaAndSizes uint32
DataDirectory [16]ImageDataDirectory
}
type ImageOptionalHeader32 struct {
Magic uint16
MajorLinkerVersion uint8
MinorLinkerVersion uint8
SizeOfCode uint32
SizeOfInitializedData uint32
SizeOfUninitializedData uint32
AddressOfEntryPoint uint32
BaseOfCode uint32
BaseOfData uint32
ImageBase uint32
SectionAlignment uint32
FileAlignment uint32
MajorOperatingSystemVersion uint16
MinorOperatingSystemVersion uint16
MajorImageVersion uint16
MinorImageVersion uint16
MajorSubsystemVersion uint16
MinorSubsystemVersion uint16
Win32VersionValue uint32
SizeOfImage uint32
SizeOfHeaders uint32
CheckSum uint32
Subsystem uint16
DllCharacteristics uint16
SizeOfStackReserve uint32
SizeOfStackCommit uint32
SizeOfHeapReserve uint32
SizeOfHeapCommit uint32
LoaderFlags uint32
NumberOfRvaAndSizes uint32
DataDirectory [16]ImageDataDirectory
}