关于go:go-hack十八go-对PE文件解析

go网络安全代码地址

  1. 应用debug/pe规范库进行解析
  2. 应用Reader对象对PE文件内容进行解析

PE文件构造

  1. DOSheader 蕴含签名(0x5a4d)peheader(0x3c指向0x50 0x45 0x00 0x00)
  2. dos stub
  3. coff file header
  4. optional header
  5. section table
// pe头
type FileHeader struct {
    Machine              uint16
    NumberOfSections     uint16  // 分区数
    TimeDateStamp        uint32
    PointerToSymbolTable uint32
    NumberOfSymbols      uint32
    SizeOfOptionalHeader uint16
    Characteristics      uint16
}
  1. 如果须要减少新分区,插入后门代码,须要批改这里的分区数属性
  2. 减少新的Sections
  3. 或者在imagebase中减少shellcode
package main

import (
    "debug/pe"
    "encoding/binary"
    "fmt"
    "io"
    "log"
    "os"
)

func main() {
    f, err := os.Open("G:\\Windows\\WinSxS\\amd64_microsoft-windows-calc_31bf3856ad364e35_10.0.18362.1_none_7c1b713697f466dd\\calc.exe") // Modify for binary or change to accept args
    check(err)
    pefile, err := pe.NewFile(f) // 创立pe文件对象
    check(err)
    defer f.Close()
    defer pefile.Close()

    dosHeader := make([]byte, 96) // 读取前96个字节
    sizeOffset := make([]byte, 4)

    // Dec to Ascii (searching for MZ)
    _, err = f.Read(dosHeader)
    check(err)
    fmt.Println("[-----DOS Header / Stub----- header和stub解析]")
    fmt.Printf("[+] Magic Value: %s%s\n", string(dosHeader[0]), string(dosHeader[1]))

    // Validate PE+0+0 (Valid PE format)
    pe_sig_offset := int64(binary.LittleEndian.Uint32(dosHeader[0x3c:])) // 从0x3c后开始读取
    f.ReadAt(sizeOffset, pe_sig_offset)                                  // sizeoffset为buffer,pe_sig_offset是读取的地位  这里不加:能够吗?? 读取0x50 0x45 0x00 0x00

    fmt.Println("[-----Signature Header-----]")
    fmt.Printf("[+] LFANEW Value: %s\n", string(sizeOffset))

    // Create the reader and read COFF Header
    sr := io.NewSectionReader(f, 0, 1<<63-1)       // 读取到2^64次方-1
    _, err = sr.Seek(pe_sig_offset+4, os.SEEK_SET) // 重置指针
    check(err)
    binary.Read(sr, binary.LittleEndian, &pefile.FileHeader) // 二进制读取

    // Get size of OptionalHeader
    // 可选头解析  向加载程序提供重要数据,加载程序将可执行文件加载到虚拟内存
    var sizeofOptionalHeader32 = uint16(binary.Size(pe.OptionalHeader32{}))
    var sizeofOptionalHeader64 = uint16(binary.Size(pe.OptionalHeader64{}))
    var oh32 pe.OptionalHeader32
    var oh64 pe.OptionalHeader64

    // type FileHeader struct {
    //     Machine              uint16
    //     NumberOfSections     uint16
    //     TimeDateStamp        uint32
    //     PointerToSymbolTable uint32
    //     NumberOfSymbols      uint32
    //     SizeOfOptionalHeader uint16
    //     Characteristics      uint16
    // }

    // Read OptionalHeader
    switch pefile.FileHeader.SizeOfOptionalHeader {
    case sizeofOptionalHeader32:
        binary.Read(sr, binary.LittleEndian, &oh32)
    case sizeofOptionalHeader64:
        binary.Read(sr, binary.LittleEndian, &oh64)
    }
    // Print File Header
    fmt.Println("[-----COFF File Header-----]")
    fmt.Printf("[+] Machine Architecture: %#x\n", pefile.FileHeader.Machine)
    fmt.Printf("[+] Number of Sections: %#x\n", pefile.FileHeader.NumberOfSections)
    fmt.Printf("[+] Size of Optional Header: %#x\n", pefile.FileHeader.SizeOfOptionalHeader)
    // Print section names
    fmt.Println("[-----Section Offsets-----]")
    fmt.Printf("[+] Number of Sections Field Offset: %#x\n", pe_sig_offset+6)
    // this is the end of the Signature header (0x7c) + coff (20bytes) + oh32 (224bytes)
    fmt.Printf("[+] Section Table Offset: %#x\n", pe_sig_offset+0xF8)
    // Print Optional Header
    fmt.Println("[-----Optional Header-----]")

    // 如果对pe文件退出后门,须要对上面两项有所理解
    fmt.Printf("[+] Entry Point: %#x\n", oh32.AddressOfEntryPoint) // 绝对于imageBase的可执行代码地位
    fmt.Printf("[+] ImageBase: %#x\n", oh32.ImageBase)             // 将图像加载到内存时第一个字节地位

    fmt.Printf("[+] Size of Image: %#x\n", oh32.SizeOfImage) // 图像的理论大小
    fmt.Printf("[+] Sections Alignment: %#x\n", oh32.SectionAlignment)
    fmt.Printf("[+] File Alignment: %#x\n", oh32.FileAlignment)
    fmt.Printf("[+] Characteristics: %#x\n", pefile.FileHeader.Characteristics)
    fmt.Printf("[+] Size of Headers: %#x\n", oh32.SizeOfHeaders)
    fmt.Printf("[+] Checksum: %#x\n", oh32.CheckSum)
    fmt.Printf("[+] Machine: %#x\n", pefile.FileHeader.Machine)
    fmt.Printf("[+] Subsystem: %#x\n", oh32.Subsystem)
    fmt.Printf("[+] DLLCharacteristics: %#x\n", oh32.DllCharacteristics)

    // Print Data Directory
    fmt.Println("[-----Data Directory----- 数据目录解析,可选头的最初128字节]")
    var winnt_datadirs = []string{
        "IMAGE_DIRECTORY_ENTRY_EXPORT",
        "IMAGE_DIRECTORY_ENTRY_IMPORT",
        "IMAGE_DIRECTORY_ENTRY_RESOURCE",
        "IMAGE_DIRECTORY_ENTRY_EXCEPTION",
        "IMAGE_DIRECTORY_ENTRY_SECURITY",
        "IMAGE_DIRECTORY_ENTRY_BASERELOC",
        "IMAGE_DIRECTORY_ENTRY_DEBUG",
        "IMAGE_DIRECTORY_ENTRY_COPYRIGHT",
        "IMAGE_DIRECTORY_ENTRY_GLOBALPTR",
        "IMAGE_DIRECTORY_ENTRY_TLS",
        "IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG",
        "IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT",
        "IMAGE_DIRECTORY_ENTRY_IAT",
        "IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT",
        "IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR",
        "IMAGE_NUMBEROF_DIRECTORY_ENTRIES",
    }
    for idx, directory := range oh32.DataDirectory {
        fmt.Printf("[!] Data Directory: %s\n", winnt_datadirs[idx])
        fmt.Printf("[+] Image Virtual Address: %#x\n", directory.VirtualAddress)
        fmt.Printf("[+] Image Size: %#x\n", directory.Size)
    }

    fmt.Println("[-----Section Table----- 解析分区表]")
    // 蕴含了相干分区的详细信息,与coff file header中numberofsections 匹配
    for _, section := range pefile.Sections {
        fmt.Println("[+] --------------------")
        fmt.Printf("[+] Section Name: %s\n", section.Name)
        fmt.Printf("[+] Section Characteristics: %#x\n", section.Characteristics)
        fmt.Printf("[+] Section Virtual Size: %#x\n", section.VirtualSize)
        fmt.Printf("[+] Section Virtual Offset: %#x\n", section.VirtualAddress)
        fmt.Printf("[+] Section Raw Size: %#x\n", section.Size)
        fmt.Printf("[+] Section Raw Offset to Data: %#x\n", section.Offset)
        fmt.Printf("[+] Section Append Offset (Next Section): %#x\n", section.Offset+section.Size)
    }

    // s := pefile.Section(".text")
    // fmt.Printf("%v", *s)

    // "Section Table Offset" + (40bytes * number of sections)

}

func check(e error) {
    if e != nil {
        log.Fatal(e)
    }
}

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理