diff --git a/pe/cert.go b/pe/cert.go index 8ca5fbc..40cb175 100644 --- a/pe/cert.go +++ b/pe/cert.go @@ -11,6 +11,10 @@ import ( const CERTIFICATE_TABLE = 4 func readCertTable(f *File, r io.ReadSeeker) ([]byte, error) { + if f.OptionalHeader == nil { // Optional header is optional, might not exist + return nil, nil + } + var certTableOffset, certTableSize uint32 switch f.FileHeader.Machine { diff --git a/pe/file.go b/pe/file.go index a72dc94..815b120 100644 --- a/pe/file.go +++ b/pe/file.go @@ -29,15 +29,17 @@ type File struct { DosStub [64]byte // TODO(capnspacehook) make slice and correctly parse any DOS stub RichHeader []byte FileHeader - OptionalHeader interface{} // of type *OptionalHeader32 or *OptionalHeader64 - Sections []*Section - Symbols []*Symbol // COFF symbols with auxiliary symbol records removed - COFFSymbols []COFFSymbol // all COFF symbols (including auxiliary symbol records) - StringTable StringTable - CertificateTable []byte + OptionalHeader interface{} // of type *OptionalHeader32 or *OptionalHeader64 + Sections []*Section + BaseRelocationTable *[]RelocationTableEntry + Symbols []*Symbol // COFF symbols with auxiliary symbol records removed + COFFSymbols []COFFSymbol // all COFF symbols (including auxiliary symbol records) + StringTable StringTable + CertificateTable []byte - InsertionAddr uint32 - InsertionBytes []byte + OptionalHeaderOffset int64 // offset of the start of the Optional Header + InsertionAddr uint32 + InsertionBytes []byte Net Net //If a managed executable, Net provides an interface to some of the metadata @@ -183,7 +185,8 @@ func newFileInternal(r io.ReaderAt, memoryMode bool) (*File, error) { } // Read optional header. - sr.Seek(peHeaderOffset+int64(binary.Size(f.FileHeader)), seekStart) + f.OptionalHeaderOffset = peHeaderOffset + int64(binary.Size(f.FileHeader)) + sr.Seek(f.OptionalHeaderOffset, seekStart) var oh32 OptionalHeader32 var oh64 OptionalHeader64 @@ -251,6 +254,12 @@ func newFileInternal(r io.ReaderAt, memoryMode bool) (*File, error) { } } + // Read Base Relocation Block and Items + f.BaseRelocationTable, err = f.readBaseRelocationTable() + if err != nil { + return nil, err + } + // Read certificate table f.CertificateTable, err = readCertTable(f, sr) if err != nil { @@ -456,65 +465,3 @@ func (f *File) IsManaged() bool { return false } - -// RelocationBlock - for base relocation entries -type RelocationBlock struct { - VirtualAddress uint32 - SizeOfBlock uint32 -} - -// BlockItem - relocation block item -type BlockItem struct { - Val uint16 - Type uint16 - Offset uint16 -} - -// Relocate - performs base relocations on this image to the given offset -func (f *File) Relocate(offset uint32) { - - pe64 := f.Machine == IMAGE_FILE_MACHINE_AMD64 - var addr uint32 - var imageBase uint64 - if pe64 { - addr = f.OptionalHeader.(*OptionalHeader64).DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress - imageBase = f.OptionalHeader.(*OptionalHeader64).ImageBase - } else { - addr = f.OptionalHeader.(*OptionalHeader32).DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress - imageBase = uint64(f.OptionalHeader.(*OptionalHeader32).ImageBase) - } - firstSectionRawDataPtr := uint32(0) - for i, val := range f.Sections { - if i == 0 { - firstSectionRawDataPtr = val.Offset - } - if val.VirtualAddress == addr { // name should be .reloc? - cur := val.Offset - d, _ := val.Data() - for cur-val.Offset < val.VirtualSize { - var reloBlock RelocationBlock - binary.Read(bytes.NewBuffer(d[cur:cur+8]), binary.LittleEndian, &reloBlock) - cur += 8 - for i := uint32(0); i < reloBlock.SizeOfBlock-8; i += 2 { - var bi BlockItem - bi.Val = binary.LittleEndian.Uint16(d[cur : cur+2]) - bi.Type = uint16(bi.Val >> 12) - bi.Offset = bi.Val & 0x0fff - localOffset := firstSectionRawDataPtr + uint32(bi.Offset) - relAddr := binary.LittleEndian.Uint32(d[localOffset : localOffset+4]) - relAddr += offset - uint32(imageBase) - byts := make([]byte, 4) - binary.LittleEndian.PutUint32(byts, relAddr) - copy(d[localOffset:localOffset+4], byts) - cur += 2 - } - } - break - } - } - if pe64 { - f.OptionalHeader.(*OptionalHeader64).ImageBase = uint64(offset) - } else { - f.OptionalHeader.(*OptionalHeader32).ImageBase = uint32(offset) - } -} diff --git a/pe/file_test.go b/pe/file_test.go index 9613af3..0c97e06 100644 --- a/pe/file_test.go +++ b/pe/file_test.go @@ -6,7 +6,6 @@ package pe import ( "debug/dwarf" - "internal/testenv" "io/ioutil" "os" "os/exec" @@ -28,23 +27,25 @@ type fileTest struct { hasNoDwarfInfo bool } +var zero8 [8]uint8 + var fileTests = []fileTest{ { file: "testdata/gcc-386-mingw-obj", hdr: FileHeader{0x014c, 0x000c, 0x0, 0x64a, 0x1e, 0x0, 0x104}, sections: []*SectionHeader{ - {".text", 0, 0, 36, 500, 1440, 0, 3, 0, 0x60300020}, - {".data", 0, 0, 0, 0, 0, 0, 0, 0, 3224371264}, - {".bss", 0, 0, 0, 0, 0, 0, 0, 0, 3224371328}, - {".debug_abbrev", 0, 0, 137, 536, 0, 0, 0, 0, 0x42100000}, - {".debug_info", 0, 0, 418, 673, 1470, 0, 7, 0, 1108344832}, - {".debug_line", 0, 0, 128, 1091, 1540, 0, 1, 0, 1108344832}, - {".rdata", 0, 0, 16, 1219, 0, 0, 0, 0, 1076887616}, - {".debug_frame", 0, 0, 52, 1235, 1550, 0, 2, 0, 1110441984}, - {".debug_loc", 0, 0, 56, 1287, 0, 0, 0, 0, 1108344832}, - {".debug_pubnames", 0, 0, 27, 1343, 1570, 0, 1, 0, 1108344832}, - {".debug_pubtypes", 0, 0, 38, 1370, 1580, 0, 1, 0, 1108344832}, - {".debug_aranges", 0, 0, 32, 1408, 1590, 0, 2, 0, 1108344832}, + {".text", [8]uint8{0x2e, 0x74, 0x65, 0x78, 0x74, 0x0, 0x0, 0x0}, 0, 0, 36, 500, 1440, 0, 3, 0, 0x60300020}, + {".data", [8]uint8{0x2e, 0x64, 0x61, 0x74, 0x61, 0x0, 0x0, 0x0}, 0, 0, 0, 0, 0, 0, 0, 0, 3224371264}, + {".bss", [8]uint8{0x2e, 0x62, 0x73, 0x73, 0x0, 0x0, 0x0, 0x0}, 0, 0, 0, 0, 0, 0, 0, 0, 3224371328}, + {".debug_abbrev", [8]uint8{0x2f, 0x34, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, 0, 0, 137, 536, 0, 0, 0, 0, 0x42100000}, + {".debug_info", [8]uint8{0x2f, 0x31, 0x38, 0x0, 0x0, 0x0, 0x0, 0x0}, 0, 0, 418, 673, 1470, 0, 7, 0, 1108344832}, + {".debug_line", [8]uint8{0x2f, 0x33, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0}, 0, 0, 128, 1091, 1540, 0, 1, 0, 1108344832}, + {".rdata", [8]uint8{0x2e, 0x72, 0x64, 0x61, 0x74, 0x61, 0x0, 0x0}, 0, 0, 16, 1219, 0, 0, 0, 0, 1076887616}, + {".debug_frame", [8]uint8{0x2f, 0x34, 0x32, 0x0, 0x0, 0x0, 0x0, 0x0}, 0, 0, 52, 1235, 1550, 0, 2, 0, 1110441984}, + {".debug_loc", [8]uint8{0x2f, 0x35, 0x35, 0x0, 0x0, 0x0, 0x0, 0x0}, 0, 0, 56, 1287, 0, 0, 0, 0, 1108344832}, + {".debug_pubnames", [8]uint8{0x2f, 0x36, 0x36, 0x0, 0x0, 0x0, 0x0, 0x0}, 0, 0, 27, 1343, 1570, 0, 1, 0, 1108344832}, + {".debug_pubtypes", [8]uint8{0x2f, 0x38, 0x32, 0x0, 0x0, 0x0, 0x0, 0x0}, 0, 0, 38, 1370, 1580, 0, 1, 0, 1108344832}, + {".debug_aranges", [8]uint8{0x2f, 0x39, 0x38, 0x0, 0x0, 0x0, 0x0, 0x0}, 0, 0, 32, 1408, 1590, 0, 2, 0, 1108344832}, }, symbols: []*Symbol{ {".file", 0x0, -2, 0x0, 0x67}, @@ -90,21 +91,21 @@ var fileTests = []fileTest{ }, }, sections: []*SectionHeader{ - {".text", 0xcd8, 0x1000, 0xe00, 0x400, 0x0, 0x0, 0x0, 0x0, 0x60500060}, - {".data", 0x10, 0x2000, 0x200, 0x1200, 0x0, 0x0, 0x0, 0x0, 0xc0300040}, - {".rdata", 0x120, 0x3000, 0x200, 0x1400, 0x0, 0x0, 0x0, 0x0, 0x40300040}, - {".bss", 0xdc, 0x4000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0400080}, - {".idata", 0x3c8, 0x5000, 0x400, 0x1600, 0x0, 0x0, 0x0, 0x0, 0xc0300040}, - {".CRT", 0x18, 0x6000, 0x200, 0x1a00, 0x0, 0x0, 0x0, 0x0, 0xc0300040}, - {".tls", 0x20, 0x7000, 0x200, 0x1c00, 0x0, 0x0, 0x0, 0x0, 0xc0300040}, - {".debug_aranges", 0x20, 0x8000, 0x200, 0x1e00, 0x0, 0x0, 0x0, 0x0, 0x42100000}, - {".debug_pubnames", 0x51, 0x9000, 0x200, 0x2000, 0x0, 0x0, 0x0, 0x0, 0x42100000}, - {".debug_pubtypes", 0x91, 0xa000, 0x200, 0x2200, 0x0, 0x0, 0x0, 0x0, 0x42100000}, - {".debug_info", 0xe22, 0xb000, 0x1000, 0x2400, 0x0, 0x0, 0x0, 0x0, 0x42100000}, - {".debug_abbrev", 0x157, 0xc000, 0x200, 0x3400, 0x0, 0x0, 0x0, 0x0, 0x42100000}, - {".debug_line", 0x144, 0xd000, 0x200, 0x3600, 0x0, 0x0, 0x0, 0x0, 0x42100000}, - {".debug_frame", 0x34, 0xe000, 0x200, 0x3800, 0x0, 0x0, 0x0, 0x0, 0x42300000}, - {".debug_loc", 0x38, 0xf000, 0x200, 0x3a00, 0x0, 0x0, 0x0, 0x0, 0x42100000}, + {".text", [8]uint8{0x2e, 0x74, 0x65, 0x78, 0x74, 0x0, 0x0, 0x0}, 0xcd8, 0x1000, 0xe00, 0x400, 0x0, 0x0, 0x0, 0x0, 0x60500060}, + {".data", [8]uint8{0x2e, 0x64, 0x61, 0x74, 0x61, 0x0, 0x0, 0x0}, 0x10, 0x2000, 0x200, 0x1200, 0x0, 0x0, 0x0, 0x0, 0xc0300040}, + {".rdata", [8]uint8{0x2e, 0x72, 0x64, 0x61, 0x74, 0x61, 0x0, 0x0}, 0x120, 0x3000, 0x200, 0x1400, 0x0, 0x0, 0x0, 0x0, 0x40300040}, + {".bss", [8]uint8{0x2e, 0x62, 0x73, 0x73, 0x0, 0x0, 0x0, 0x0}, 0xdc, 0x4000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0400080}, + {".idata", [8]uint8{0x2e, 0x69, 0x64, 0x61, 0x74, 0x61, 0x0, 0x0}, 0x3c8, 0x5000, 0x400, 0x1600, 0x0, 0x0, 0x0, 0x0, 0xc0300040}, + {".CRT", [8]uint8{0x2e, 0x43, 0x52, 0x54, 0x0, 0x0, 0x0, 0x0}, 0x18, 0x6000, 0x200, 0x1a00, 0x0, 0x0, 0x0, 0x0, 0xc0300040}, + {".tls", [8]uint8{0x2e, 0x74, 0x6c, 0x73, 0x0, 0x0, 0x0, 0x0}, 0x20, 0x7000, 0x200, 0x1c00, 0x0, 0x0, 0x0, 0x0, 0xc0300040}, + {".debug_aranges", [8]uint8{0x2f, 0x34, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, 0x20, 0x8000, 0x200, 0x1e00, 0x0, 0x0, 0x0, 0x0, 0x42100000}, + {".debug_pubnames", [8]uint8{0x2f, 0x31, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0}, 0x51, 0x9000, 0x200, 0x2000, 0x0, 0x0, 0x0, 0x0, 0x42100000}, + {".debug_pubtypes", [8]uint8{0x2f, 0x33, 0x35, 0x0, 0x0, 0x0, 0x0, 0x0}, 0x91, 0xa000, 0x200, 0x2200, 0x0, 0x0, 0x0, 0x0, 0x42100000}, + {".debug_info", [8]uint8{0x2f, 0x35, 0x31, 0x0, 0x0, 0x0, 0x0, 0x0}, 0xe22, 0xb000, 0x1000, 0x2400, 0x0, 0x0, 0x0, 0x0, 0x42100000}, + {".debug_abbrev", [8]uint8{0x2f, 0x36, 0x33, 0x0, 0x0, 0x0, 0x0, 0x0}, 0x157, 0xc000, 0x200, 0x3400, 0x0, 0x0, 0x0, 0x0, 0x42100000}, + {".debug_line", [8]uint8{0x2f, 0x37, 0x37, 0x0, 0x0, 0x0, 0x0, 0x0}, 0x144, 0xd000, 0x200, 0x3600, 0x0, 0x0, 0x0, 0x0, 0x42100000}, + {".debug_frame", [8]uint8{0x2f, 0x38, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0}, 0x34, 0xe000, 0x200, 0x3800, 0x0, 0x0, 0x0, 0x0, 0x42300000}, + {".debug_loc", [8]uint8{0x2f, 0x31, 0x30, 0x32, 0x0, 0x0, 0x0, 0x0}, 0x38, 0xf000, 0x200, 0x3a00, 0x0, 0x0, 0x0, 0x0, 0x42100000}, }, }, { @@ -131,14 +132,14 @@ var fileTests = []fileTest{ }, }, sections: []*SectionHeader{ - {".text", 0xc64, 0x1000, 0xe00, 0x400, 0x0, 0x0, 0x0, 0x0, 0x60500060}, - {".data", 0x10, 0x2000, 0x200, 0x1200, 0x0, 0x0, 0x0, 0x0, 0xc0300040}, - {".rdata", 0x134, 0x3000, 0x200, 0x1400, 0x0, 0x0, 0x0, 0x0, 0x40300040}, - {".eh_fram", 0x3a0, 0x4000, 0x400, 0x1600, 0x0, 0x0, 0x0, 0x0, 0x40300040}, - {".bss", 0x60, 0x5000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0300080}, - {".idata", 0x378, 0x6000, 0x400, 0x1a00, 0x0, 0x0, 0x0, 0x0, 0xc0300040}, - {".CRT", 0x18, 0x7000, 0x200, 0x1e00, 0x0, 0x0, 0x0, 0x0, 0xc0300040}, - {".tls", 0x20, 0x8000, 0x200, 0x2000, 0x0, 0x0, 0x0, 0x0, 0xc0300040}, + {".text", [8]uint8{0x2e, 0x74, 0x65, 0x78, 0x74, 0x0, 0x0, 0x0}, 0xc64, 0x1000, 0xe00, 0x400, 0x0, 0x0, 0x0, 0x0, 0x60500060}, + {".data", [8]uint8{0x2e, 0x64, 0x61, 0x74, 0x61, 0x0, 0x0, 0x0}, 0x10, 0x2000, 0x200, 0x1200, 0x0, 0x0, 0x0, 0x0, 0xc0300040}, + {".rdata", [8]uint8{0x2e, 0x72, 0x64, 0x61, 0x74, 0x61, 0x0, 0x0}, 0x134, 0x3000, 0x200, 0x1400, 0x0, 0x0, 0x0, 0x0, 0x40300040}, + {".eh_fram", [8]uint8{0x2e, 0x65, 0x68, 0x5f, 0x66, 0x72, 0x61, 0x6d}, 0x3a0, 0x4000, 0x400, 0x1600, 0x0, 0x0, 0x0, 0x0, 0x40300040}, + {".bss", [8]uint8{0x2e, 0x62, 0x73, 0x73, 0x0, 0x0, 0x0, 0x0}, 0x60, 0x5000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0300080}, + {".idata", [8]uint8{0x2e, 0x69, 0x64, 0x61, 0x74, 0x61, 0x0, 0x0}, 0x378, 0x6000, 0x400, 0x1a00, 0x0, 0x0, 0x0, 0x0, 0xc0300040}, + {".CRT", [8]uint8{0x2e, 0x43, 0x52, 0x54, 0x0, 0x0, 0x0, 0x0}, 0x18, 0x7000, 0x200, 0x1e00, 0x0, 0x0, 0x0, 0x0, 0xc0300040}, + {".tls", [8]uint8{0x2e, 0x74, 0x6c, 0x73, 0x0, 0x0, 0x0, 0x0}, 0x20, 0x8000, 0x200, 0x2000, 0x0, 0x0, 0x0, 0x0, 0xc0300040}, }, hasNoDwarfInfo: true, }, @@ -146,12 +147,12 @@ var fileTests = []fileTest{ file: "testdata/gcc-amd64-mingw-obj", hdr: FileHeader{0x8664, 0x6, 0x0, 0x198, 0x12, 0x0, 0x4}, sections: []*SectionHeader{ - {".text", 0x0, 0x0, 0x30, 0x104, 0x15c, 0x0, 0x3, 0x0, 0x60500020}, - {".data", 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0500040}, - {".bss", 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0500080}, - {".rdata", 0x0, 0x0, 0x10, 0x134, 0x0, 0x0, 0x0, 0x0, 0x40500040}, - {".xdata", 0x0, 0x0, 0xc, 0x144, 0x0, 0x0, 0x0, 0x0, 0x40300040}, - {".pdata", 0x0, 0x0, 0xc, 0x150, 0x17a, 0x0, 0x3, 0x0, 0x40300040}, + {".text", [8]uint8{0x2e, 0x74, 0x65, 0x78, 0x74, 0x0, 0x0, 0x0}, 0x0, 0x0, 0x30, 0x104, 0x15c, 0x0, 0x3, 0x0, 0x60500020}, + {".data", [8]uint8{0x2e, 0x64, 0x61, 0x74, 0x61, 0x0, 0x0, 0x0}, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0500040}, + {".bss", [8]uint8{0x2e, 0x62, 0x73, 0x73, 0x0, 0x0, 0x0, 0x0}, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0500080}, + {".rdata", [8]uint8{0x2e, 0x72, 0x64, 0x61, 0x74, 0x61, 0x0, 0x0}, 0x0, 0x0, 0x10, 0x134, 0x0, 0x0, 0x0, 0x0, 0x40500040}, + {".xdata", [8]uint8{0x2e, 0x78, 0x64, 0x61, 0x74, 0x61, 0x0, 0x0}, 0x0, 0x0, 0xc, 0x144, 0x0, 0x0, 0x0, 0x0, 0x40300040}, + {".pdata", [8]uint8{0x2e, 0x70, 0x64, 0x61, 0x74, 0x61, 0x0, 0x0}, 0x0, 0x0, 0xc, 0x150, 0x17a, 0x0, 0x3, 0x0, 0x40300040}, }, symbols: []*Symbol{ {".file", 0x0, -2, 0x0, 0x67}, @@ -191,23 +192,23 @@ var fileTests = []fileTest{ {0x0, 0x0}, }}, sections: []*SectionHeader{ - {".text", 0x6860, 0x1000, 0x6a00, 0x600, 0x0, 0x0, 0x0, 0x0, 0x60500020}, - {".data", 0xe0, 0x8000, 0x200, 0x7000, 0x0, 0x0, 0x0, 0x0, 0xc0500040}, - {".rdata", 0x6b0, 0x9000, 0x800, 0x7200, 0x0, 0x0, 0x0, 0x0, 0x40600040}, - {".pdata", 0x498, 0xa000, 0x600, 0x7a00, 0x0, 0x0, 0x0, 0x0, 0x40300040}, - {".xdata", 0x488, 0xb000, 0x600, 0x8000, 0x0, 0x0, 0x0, 0x0, 0x40300040}, - {".bss", 0x1410, 0xc000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0600080}, - {".idata", 0x990, 0xe000, 0xa00, 0x8600, 0x0, 0x0, 0x0, 0x0, 0xc0300040}, - {".CRT", 0x68, 0xf000, 0x200, 0x9000, 0x0, 0x0, 0x0, 0x0, 0xc0400040}, - {".tls", 0x48, 0x10000, 0x200, 0x9200, 0x0, 0x0, 0x0, 0x0, 0xc0600040}, - {".debug_aranges", 0x600, 0x11000, 0x600, 0x9400, 0x0, 0x0, 0x0, 0x0, 0x42500040}, - {".debug_info", 0x1316e, 0x12000, 0x13200, 0x9a00, 0x0, 0x0, 0x0, 0x0, 0x42100040}, - {".debug_abbrev", 0x2ccb, 0x26000, 0x2e00, 0x1cc00, 0x0, 0x0, 0x0, 0x0, 0x42100040}, - {".debug_line", 0x3c4d, 0x29000, 0x3e00, 0x1fa00, 0x0, 0x0, 0x0, 0x0, 0x42100040}, - {".debug_frame", 0x18b8, 0x2d000, 0x1a00, 0x23800, 0x0, 0x0, 0x0, 0x0, 0x42400040}, - {".debug_str", 0x396, 0x2f000, 0x400, 0x25200, 0x0, 0x0, 0x0, 0x0, 0x42100040}, - {".debug_loc", 0x13240, 0x30000, 0x13400, 0x25600, 0x0, 0x0, 0x0, 0x0, 0x42100040}, - {".debug_ranges", 0xa70, 0x44000, 0xc00, 0x38a00, 0x0, 0x0, 0x0, 0x0, 0x42100040}, + {".text", [8]uint8{0x2e, 0x74, 0x65, 0x78, 0x74, 0x0, 0x0, 0x0}, 0x6860, 0x1000, 0x6a00, 0x600, 0x0, 0x0, 0x0, 0x0, 0x60500020}, + {".data", [8]uint8{0x2e, 0x64, 0x61, 0x74, 0x61, 0x0, 0x0, 0x0}, 0xe0, 0x8000, 0x200, 0x7000, 0x0, 0x0, 0x0, 0x0, 0xc0500040}, + {".rdata", [8]uint8{0x2e, 0x72, 0x64, 0x61, 0x74, 0x61, 0x0, 0x0}, 0x6b0, 0x9000, 0x800, 0x7200, 0x0, 0x0, 0x0, 0x0, 0x40600040}, + {".pdata", [8]uint8{0x2e, 0x70, 0x64, 0x61, 0x74, 0x61, 0x0, 0x0}, 0x498, 0xa000, 0x600, 0x7a00, 0x0, 0x0, 0x0, 0x0, 0x40300040}, + {".xdata", [8]uint8{0x2e, 0x78, 0x64, 0x61, 0x74, 0x61, 0x0, 0x0}, 0x488, 0xb000, 0x600, 0x8000, 0x0, 0x0, 0x0, 0x0, 0x40300040}, + {".bss", [8]uint8{0x2e, 0x62, 0x73, 0x73, 0x0, 0x0, 0x0, 0x0}, 0x1410, 0xc000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0600080}, + {".idata", [8]uint8{0x2e, 0x69, 0x64, 0x61, 0x74, 0x61, 0x0, 0x0}, 0x990, 0xe000, 0xa00, 0x8600, 0x0, 0x0, 0x0, 0x0, 0xc0300040}, + {".CRT", [8]uint8{0x2e, 0x43, 0x52, 0x54, 0x0, 0x0, 0x0, 0x0}, 0x68, 0xf000, 0x200, 0x9000, 0x0, 0x0, 0x0, 0x0, 0xc0400040}, + {".tls", [8]uint8{0x2e, 0x74, 0x6c, 0x73, 0x0, 0x0, 0x0, 0x0}, 0x48, 0x10000, 0x200, 0x9200, 0x0, 0x0, 0x0, 0x0, 0xc0600040}, + {".debug_aranges", [8]uint8{0x2f, 0x34, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, 0x600, 0x11000, 0x600, 0x9400, 0x0, 0x0, 0x0, 0x0, 0x42500040}, + {".debug_info", [8]uint8{0x2f, 0x31, 0x39, 0x0, 0x0, 0x0, 0x0, 0x0}, 0x1316e, 0x12000, 0x13200, 0x9a00, 0x0, 0x0, 0x0, 0x0, 0x42100040}, + {".debug_abbrev", [8]uint8{0x2f, 0x33, 0x31, 0x0, 0x0, 0x0, 0x0, 0x0}, 0x2ccb, 0x26000, 0x2e00, 0x1cc00, 0x0, 0x0, 0x0, 0x0, 0x42100040}, + {".debug_line", [8]uint8{0x2f, 0x34, 0x35, 0x0, 0x0, 0x0, 0x0, 0x0}, 0x3c4d, 0x29000, 0x3e00, 0x1fa00, 0x0, 0x0, 0x0, 0x0, 0x42100040}, + {".debug_frame", [8]uint8{0x2f, 0x35, 0x37, 0x0, 0x0, 0x0, 0x0, 0x0}, 0x18b8, 0x2d000, 0x1a00, 0x23800, 0x0, 0x0, 0x0, 0x0, 0x42400040}, + {".debug_str", [8]uint8{0x2f, 0x37, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0}, 0x396, 0x2f000, 0x400, 0x25200, 0x0, 0x0, 0x0, 0x0, 0x42100040}, + {".debug_loc", [8]uint8{0x2f, 0x38, 0x31, 0x0, 0x0, 0x0, 0x0, 0x0}, 0x13240, 0x30000, 0x13400, 0x25600, 0x0, 0x0, 0x0, 0x0, 0x42100040}, + {".debug_ranges", [8]uint8{0x2f, 0x39, 0x32, 0x0, 0x0, 0x0, 0x0, 0x0}, 0xa70, 0x44000, 0xc00, 0x38a00, 0x0, 0x0, 0x0, 0x0, 0x42100040}, }, }, } @@ -313,7 +314,6 @@ func testDWARF(t *testing.T, linktype int) { if runtime.GOOS != "windows" { t.Skip("skipping windows only test") } - testenv.MustHaveGoRun(t) tmpdir, err := ioutil.TempDir("", "TestDWARF") if err != nil { @@ -350,7 +350,7 @@ func testDWARF(t *testing.T, linktype int) { t.Fatalf("invalid linktype parameter of %v", linktype) } args = append(args, src) - out, err := exec.Command(testenv.GoToolPath(t), args...).CombinedOutput() + out, err := exec.Command("go", args...).CombinedOutput() if err != nil { t.Fatalf("building test executable for linktype %d failed: %s %s", linktype, err, out) } @@ -424,7 +424,6 @@ func testDWARF(t *testing.T, linktype int) { } func TestBSSHasZeros(t *testing.T) { - testenv.MustHaveExec(t) if runtime.GOOS != "windows" { t.Skip("skipping windows only test") @@ -553,7 +552,6 @@ func main() { ` func TestBuildingWindowsGUI(t *testing.T) { - testenv.MustHaveGoBuild(t) if runtime.GOOS != "windows" { t.Skip("skipping windows only test") @@ -570,7 +568,7 @@ func TestBuildingWindowsGUI(t *testing.T) { t.Fatal(err) } exe := filepath.Join(tmpdir, "a.exe") - cmd := exec.Command(testenv.GoToolPath(t), "build", "-ldflags", "-H=windowsgui", "-o", exe, src) + cmd := exec.Command("go", "build", "-ldflags", "-H=windowsgui", "-o", exe, src) out, err := cmd.CombinedOutput() if err != nil { t.Fatalf("building test executable failed: %s %s", err, out) diff --git a/pe/reloc.go b/pe/reloc.go new file mode 100644 index 0000000..e29ee8e --- /dev/null +++ b/pe/reloc.go @@ -0,0 +1,171 @@ +package pe + +import ( + "bytes" + "encoding/binary" + "fmt" + "io" +) + +// RelocationTable - for base relocation entries +type RelocationTableEntry struct { + RelocationBlock + BlockItems []BlockItem +} + +// RelocationBlock - for base relocation entries +type RelocationBlock struct { + VirtualAddress uint32 + SizeOfBlock uint32 +} + +// BlockItem - relocation block item +type BlockItem struct { + Type byte // 4 bits + Offset uint16 // 12 bits +} + +// Reloc represents a PE COFF relocation. +// Each section contains its own relocation list. +type Reloc struct { + VirtualAddress uint32 + SymbolTableIndex uint32 + Type uint16 +} + +const ( + //IMAGE_REL_BASED_ABSOLUTE - The base relocation is skipped. This type can be used to pad a block. + IMAGE_REL_BASED_ABSOLUTE = 0 + + //IMAGE_REL_BASED_HIGH = 1 + //IMAGE_REL_BASED_LOW = 2 + + //IMAGE_REL_BASED_HIGHLOW - The base relocation applies all 32 bits of the difference to the 32-bit field at offset. + IMAGE_REL_BASED_HIGHLOW = 3 + + //IMAGE_REL_BASED_HIGHADJ = 4 + //IMAGE_REL_BASED_MIPS_JMPADDR = 5 + //IMAGE_REL_BASED_ARM_MOV32 = 5 + //IMAGE_REL_BASED_RISCV_HIGH20 = 5 + //IMAGE_REL_BASED_THUMB_MOV32 = 7 + //IMAGE_REL_BASED_RISCV_LOW12I = 7 + //IMAGE_REL_BASED_RISCV_LOW12S = 8 + //IMAGE_REL_BASED_MIPS_JMPADDR16 = 9 + IMAGE_REL_BASED_DIR64 = 10 +) + +// readBaseRelocationTable - reads the base relocation table from the file and stores it +func (f *File) readBaseRelocationTable() (*[]RelocationTableEntry, error) { + + if f.OptionalHeader == nil { // Optional header is optional, might not exist + return nil, nil + } + + var dd DataDirectory + if f.Machine == IMAGE_FILE_MACHINE_AMD64 { + dd = f.OptionalHeader.(*OptionalHeader64).DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC] + } else { + dd = f.OptionalHeader.(*OptionalHeader32).DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC] + } + var sectionData []byte + var err error + for _, section := range f.Sections { + if section.VirtualAddress == dd.VirtualAddress { + sectionData, err = section.Data() + if err != nil { + return nil, err + } + break + } + } + r := bytes.NewReader(sectionData) + var reloBlocks []RelocationTableEntry + bytesRead := uint32(0) + for bytesRead < dd.Size { + var reloBlock RelocationBlock + err = binary.Read(r, binary.LittleEndian, &reloBlock) + bytesRead += 8 + if err != nil { + return nil, fmt.Errorf("fail to read relocation block: %v", err) + } + numBlocks := (reloBlock.SizeOfBlock - 8) / 2 + blocks := make([]BlockItem, numBlocks) + for i := uint32(0); i < numBlocks; i++ { + var buf [2]byte + err = binary.Read(r, binary.LittleEndian, &buf) + bytesRead += 2 + if err != nil { + return nil, fmt.Errorf("fail to read relocation block item %d: %v", i, err) + } + var item BlockItem + val := binary.LittleEndian.Uint16(buf[:2]) + item.Type = byte(val >> 12) + item.Offset = val & 0x0fff + blocks[i] = item + } + reloBlocks = append(reloBlocks, RelocationTableEntry{reloBlock, blocks}) + } + return &reloBlocks, nil +} + +// Relocate - performs base relocations on this image to the given offset +func (f *File) Relocate(baseAddr uint64, image *[]byte) { + var imageBase uint64 + pe64 := f.Machine == IMAGE_FILE_MACHINE_AMD64 + if pe64 { + imageBase = f.OptionalHeader.(*OptionalHeader64).ImageBase + } else { + imageBase = uint64(f.OptionalHeader.(*OptionalHeader32).ImageBase) + } + for _, block := range *f.BaseRelocationTable { + pageRVA := block.VirtualAddress + for _, item := range block.BlockItems { + if item.Type == IMAGE_REL_BASED_HIGHLOW { // 32 bit + delta := uint32(baseAddr - imageBase) + fileOffset := f.RVAToFileOffset(pageRVA) + idx := fileOffset + uint32(item.Offset) + originalAddress := binary.LittleEndian.Uint32((*image)[idx : idx+4]) + b := make([]byte, 4) + binary.LittleEndian.PutUint32(b, originalAddress+delta) + copy((*image)[idx:idx+4], b) + } else if item.Type == IMAGE_REL_BASED_DIR64 { // 64 bit + delta := baseAddr - imageBase + fileOffset := f.RVAToFileOffset(pageRVA) + idx := fileOffset + uint32(item.Offset) + originalAddress := binary.LittleEndian.Uint64((*image)[idx : idx+8]) + b := make([]byte, 8) + binary.LittleEndian.PutUint64(b, originalAddress+delta) + copy((*image)[idx:idx+8], b) + } + } + } + + // update imageBase in the optional header + if pe64 { + b := make([]byte, 8) + binary.LittleEndian.PutUint64(b, baseAddr) + idx := f.OptionalHeaderOffset + 24 + copy((*image)[idx:idx+8], b) + } else { + b := make([]byte, 4) + binary.LittleEndian.PutUint32(b, uint32(baseAddr)) + idx := f.OptionalHeaderOffset + 28 + copy((*image)[idx:idx+4], b) + } +} + +func readRelocs(sh *SectionHeader, r io.ReadSeeker) ([]Reloc, error) { + if sh.NumberOfRelocations <= 0 { + return nil, nil + } + _, err := r.Seek(int64(sh.PointerToRelocations), seekStart) + if err != nil { + return nil, fmt.Errorf("fail to seek to %q section relocations: %v", sh.Name, err) + } + relocs := make([]Reloc, sh.NumberOfRelocations) + err = binary.Read(r, binary.LittleEndian, relocs) + if err != nil { + return nil, fmt.Errorf("fail to read section relocations: %v", err) + } + return relocs, nil +} diff --git a/pe/section.go b/pe/section.go index be3e589..e386a6c 100644 --- a/pe/section.go +++ b/pe/section.go @@ -5,8 +5,6 @@ package pe import ( - "encoding/binary" - "fmt" "io" "strconv" ) @@ -39,32 +37,6 @@ func (sh *SectionHeader32) fullName(st StringTable) (string, error) { return st.String(uint32(i)) } -// TODO(brainman): copy all IMAGE_REL_* consts from ldpe.go here - -// Reloc represents a PE COFF relocation. -// Each section contains its own relocation list. -type Reloc struct { - VirtualAddress uint32 - SymbolTableIndex uint32 - Type uint16 -} - -func readRelocs(sh *SectionHeader, r io.ReadSeeker) ([]Reloc, error) { - if sh.NumberOfRelocations <= 0 { - return nil, nil - } - _, err := r.Seek(int64(sh.PointerToRelocations), seekStart) - if err != nil { - return nil, fmt.Errorf("fail to seek to %q section relocations: %v", sh.Name, err) - } - relocs := make([]Reloc, sh.NumberOfRelocations) - err = binary.Read(r, binary.LittleEndian, relocs) - if err != nil { - return nil, fmt.Errorf("fail to read section relocations: %v", err) - } - return relocs, nil -} - // SectionHeader is similar to SectionHeader32 with Name // field replaced by Go string. OriginalName is the // original name of the section on disk. diff --git a/pe/string.go b/pe/string.go index 832593f..1cefe68 100644 --- a/pe/string.go +++ b/pe/string.go @@ -49,7 +49,11 @@ func readStringTable(fh *FileHeader, r io.ReadSeeker) (StringTable, error) { if err != nil { return nil, fmt.Errorf("fail to read string table: %v", err) } - return StringTable(buf), nil + // re-add the length to the first four bytes of the string table + lbuf := make([]byte, 4) + binary.LittleEndian.PutUint32(lbuf, l) + + return StringTable(append(lbuf, buf...)), nil } // String extracts string from COFF string table st at offset start. @@ -58,7 +62,7 @@ func (st StringTable) String(start uint32) (string, error) { if start < 4 { return "", fmt.Errorf("offset %d is before the start of string table", start) } - start -= 4 + //start -= 4 // we are now including the uint32 length in the StringTable buffer as a prefix, this might change if int(start) > len(st) { return "", fmt.Errorf("offset %d is beyond the end of string table", start) }