mirror of
https://github.com/Binject/debug
synced 2026-06-08 10:28:33 +00:00
171 lines
5.2 KiB
Go
171 lines
5.2 KiB
Go
package pe
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"errors"
|
|
"os"
|
|
)
|
|
|
|
func (peFile *File) Bytes() ([]byte, error) {
|
|
var bytesWritten uint64
|
|
peBuf := bytes.NewBuffer(nil)
|
|
|
|
// write DOS header and stub
|
|
binary.Write(peBuf, binary.LittleEndian, peFile.DosHeader)
|
|
bytesWritten += uint64(binary.Size(peFile.DosHeader))
|
|
binary.Write(peBuf, binary.LittleEndian, peFile.DosStub)
|
|
bytesWritten += uint64(binary.Size(peFile.DosStub))
|
|
|
|
// write Rich header
|
|
if peFile.RichHeader != nil {
|
|
binary.Write(peBuf, binary.LittleEndian, peFile.RichHeader)
|
|
bytesWritten += uint64(len(peFile.RichHeader))
|
|
}
|
|
|
|
// apply padding before PE header if necessary
|
|
if uint32(bytesWritten) != peFile.DosHeader.AddressOfNewExeHeader {
|
|
padding := make([]byte, peFile.DosHeader.AddressOfNewExeHeader - uint32(bytesWritten))
|
|
binary.Write(peBuf, binary.LittleEndian, padding)
|
|
bytesWritten += uint64(len(padding))
|
|
}
|
|
|
|
// write PE header
|
|
peMagic := []byte{'P', 'E', 0x00, 0x00}
|
|
binary.Write(peBuf, binary.LittleEndian, peMagic)
|
|
binary.Write(peBuf, binary.LittleEndian, peFile.FileHeader)
|
|
bytesWritten += uint64(binary.Size(peFile.FileHeader) + len(peMagic))
|
|
|
|
var (
|
|
is32bit bool
|
|
oldCertTableOffset, oldCertTableSize uint32
|
|
)
|
|
|
|
switch peFile.FileHeader.Machine {
|
|
case IMAGE_FILE_MACHINE_I386:
|
|
is32bit = true
|
|
optionalHeader := peFile.OptionalHeader.(*OptionalHeader32)
|
|
binary.Write(peBuf, binary.LittleEndian, peFile.OptionalHeader.(*OptionalHeader32))
|
|
bytesWritten += uint64(binary.Size(optionalHeader))
|
|
|
|
oldCertTableOffset = optionalHeader.DataDirectory[CERTIFICATE_TABLE].VirtualAddress
|
|
oldCertTableSize = optionalHeader.DataDirectory[CERTIFICATE_TABLE].Size
|
|
case IMAGE_FILE_MACHINE_AMD64:
|
|
is32bit = false
|
|
optionalHeader := peFile.OptionalHeader.(*OptionalHeader64)
|
|
binary.Write(peBuf, binary.LittleEndian, optionalHeader)
|
|
bytesWritten += uint64(binary.Size(optionalHeader))
|
|
|
|
oldCertTableOffset = optionalHeader.DataDirectory[CERTIFICATE_TABLE].VirtualAddress
|
|
oldCertTableSize = optionalHeader.DataDirectory[CERTIFICATE_TABLE].Size
|
|
default:
|
|
return nil, errors.New("architecture not supported")
|
|
}
|
|
|
|
// write section headers
|
|
sectionHeaders := make([]SectionHeader32, len(peFile.Sections))
|
|
for idx, section := range peFile.Sections {
|
|
// write section header
|
|
sectionHeader := SectionHeader32 {
|
|
Name: section.OriginalName,
|
|
VirtualSize: section.VirtualSize,
|
|
VirtualAddress: section.VirtualAddress,
|
|
SizeOfRawData: section.Size,
|
|
PointerToRawData: section.Offset,
|
|
PointerToRelocations: section.PointerToRelocations,
|
|
PointerToLineNumbers: section.PointerToLineNumbers,
|
|
NumberOfRelocations: section.NumberOfRelocations,
|
|
NumberOfLineNumbers: section.NumberOfLineNumbers,
|
|
Characteristics: section.Characteristics,
|
|
}
|
|
sectionHeaders[idx] = sectionHeader
|
|
|
|
binary.Write(peBuf, binary.LittleEndian, sectionHeader)
|
|
bytesWritten += uint64(binary.Size(sectionHeader))
|
|
}
|
|
|
|
// write sections' data
|
|
for idx, sectionHeader := range sectionHeaders {
|
|
sectionData, err := peFile.Sections[idx].Data()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// pad section if there is a gap between PointerToRawData end of last section
|
|
if sectionHeader.PointerToRawData != uint32(bytesWritten) {
|
|
paddingSize := sectionHeader.PointerToRawData - uint32(bytesWritten)
|
|
padding := make([]byte, paddingSize, paddingSize)
|
|
sectionData = append(padding, sectionData...)
|
|
}
|
|
|
|
binary.Write(peBuf, binary.LittleEndian, sectionData)
|
|
bytesWritten += uint64(len(sectionData))
|
|
}
|
|
|
|
// write symbols
|
|
binary.Write(peBuf, binary.LittleEndian, peFile.COFFSymbols)
|
|
bytesWritten += uint64(binary.Size(peFile.COFFSymbols))
|
|
|
|
// write the string table
|
|
binary.Write(peBuf, binary.LittleEndian, peFile.StringTable)
|
|
bytesWritten += uint64(binary.Size(peFile.StringTable))
|
|
|
|
var newCertTableOffset, newCertTableSize uint32
|
|
|
|
// write the certificate table
|
|
if peFile.CertificateTable != nil {
|
|
newCertTableOffset = uint32(bytesWritten)
|
|
newCertTableSize = uint32(len(peFile.CertificateTable))
|
|
} else {
|
|
newCertTableOffset = 0
|
|
newCertTableSize = 0
|
|
}
|
|
|
|
binary.Write(peBuf, binary.LittleEndian, peFile.CertificateTable)
|
|
bytesWritten += uint64(len(peFile.CertificateTable))
|
|
|
|
peData := peBuf.Bytes()
|
|
|
|
// write the offset and size of the new Certificate Table if it changed
|
|
if newCertTableOffset != oldCertTableOffset || newCertTableSize != oldCertTableSize {
|
|
certTableInfo := &DataDirectory{
|
|
VirtualAddress: newCertTableOffset,
|
|
Size: newCertTableSize,
|
|
}
|
|
|
|
var certTableInfoBuf bytes.Buffer
|
|
binary.Write(&certTableInfoBuf, binary.LittleEndian, certTableInfo)
|
|
|
|
var certTableLoc int64
|
|
if is32bit {
|
|
certTableLoc = int64(peFile.DosHeader.AddressOfNewExeHeader) + 24 + 128
|
|
} else {
|
|
certTableLoc = int64(peFile.DosHeader.AddressOfNewExeHeader) + 24 + 144
|
|
}
|
|
|
|
peData = append(peData[:certTableLoc], append(certTableInfoBuf.Bytes(), peData[int(certTableLoc) + binary.Size(certTableInfo):]...)...)
|
|
}
|
|
|
|
return peData, nil
|
|
}
|
|
|
|
func (peFile *File) WriteFile(destFile string) error {
|
|
f, err := os.Create(destFile)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
|
|
peData, err := peFile.Bytes()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = f.Write(peData)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|