200 lines
5.2 KiB
Go
200 lines
5.2 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"strings"
|
|
)
|
|
|
|
type IMAGE_DOS_HEADER struct {
|
|
Emagic uint16
|
|
Ecblp uint16
|
|
Ecp uint16
|
|
Ecrlc uint16
|
|
Ecparhdr uint16
|
|
Eminalloc uint16
|
|
Emaxalloc uint16
|
|
Ess uint16
|
|
Esp uint16
|
|
Ecsum uint16
|
|
Eip uint16
|
|
Ecs uint16
|
|
Elfarlc uint16
|
|
Eovno uint16
|
|
Eres uint64
|
|
Eoemid uint16
|
|
Eoeminfo uint16
|
|
Eres2 [20]byte
|
|
Elfanew uint32
|
|
}
|
|
|
|
type IMAGE_NT_HEADERS32 struct {
|
|
Signature uint32
|
|
FileHeader IMAGE_FILE_HEADER
|
|
OptionalHeader IMAGE_OPTIONAL_HEADER32
|
|
}
|
|
|
|
type IMAGE_FILE_HEADER struct {
|
|
Machine uint16
|
|
NumberOfSections uint16
|
|
TimeDateStamp uint32
|
|
PointerToSymbolTable uint32
|
|
NumberOfSymbols uint32
|
|
SizeOfOptionalHeader uint16
|
|
Characteristics uint16
|
|
}
|
|
|
|
type IMAGE_OPTIONAL_HEADER32 struct {
|
|
Magic uint16
|
|
MajorLinkerVersion byte
|
|
MinorLinkerVersion byte
|
|
SizeOfCode uint32
|
|
SizeOfInitializedData uint32
|
|
SizeOfUninitializedData uint32
|
|
AddressOfEntryPoint uint32
|
|
BaseOfCode uint32
|
|
BaseOfData uint32
|
|
ImageBase 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 uint32
|
|
SizeOfStackCommit uint32
|
|
SizeOfHeapReserve uint32
|
|
SizeOfHeapCommit uint32
|
|
//SizeOfStackReserve uint64
|
|
//SizeOfStackCommit uint64
|
|
//SizeOfHeapReserve uint64
|
|
//SizeOfHeapCommit uint64
|
|
LoaderFlags uint32
|
|
NumberOfRvaAndSizes uint32
|
|
DataDirectory [IMAGE_NUMBEROF_DIRECTORY_ENTRIES]IMAGE_DATA_DIRECTORY
|
|
}
|
|
|
|
type IMAGE_DATA_DIRECTORY struct {
|
|
VirtualAddress uint32
|
|
Size uint32
|
|
}
|
|
|
|
const IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16
|
|
|
|
type IMAGE_SECTION_HEADER struct {
|
|
Name [8]byte
|
|
Misc uint32
|
|
VirtualAddress uint32
|
|
SizeOfRawData uint32
|
|
PointerToRawData uint32
|
|
PointerToRelocations uint32
|
|
PointerToLinenumbers uint32
|
|
NumberOfRelocations uint16
|
|
NumberOfLinenumbers uint16
|
|
Characteristics uint32
|
|
}
|
|
|
|
type IMAGE_RESOURCE_DIRECTORY struct {
|
|
Characteristics uint32
|
|
TimeDateStamp uint32
|
|
MajorVersion uint16
|
|
MinorVersion uint16
|
|
NumberOfNamedEntries uint16
|
|
NumberOfIdEntries uint16
|
|
}
|
|
|
|
type IMAGE_RESOURCE_Entity struct {
|
|
Id uint32
|
|
Offset uint32
|
|
}
|
|
|
|
type Resource struct {
|
|
Directory *IMAGE_RESOURCE_DIRECTORY
|
|
Entities []RealEntity
|
|
}
|
|
|
|
type RealEntity struct {
|
|
IMAGE_RESOURCE_Entity
|
|
Childern Resource
|
|
IsFolder bool
|
|
}
|
|
|
|
func ParsePe() {
|
|
data, _ := os.Open("D:\\software\\qq\\Bin\\QQ.exe")
|
|
doc := new(IMAGE_DOS_HEADER)
|
|
binary.Read(data, binary.LittleEndian, doc)
|
|
data.Seek(int64(doc.Elfanew), 0)
|
|
nt := new(IMAGE_NT_HEADERS32)
|
|
binary.Read(data, binary.LittleEndian, nt)
|
|
fmt.Printf("%v", nt.FileHeader.NumberOfSections)
|
|
//for _, directory := range nt.OptionalHeader.DataDirectory {
|
|
// fmt.Printf("\n%X,%X ", directory.VirtualAddress, directory.Size)
|
|
//}
|
|
sectionTables := make(map[string]*IMAGE_SECTION_HEADER)
|
|
for i := 0; i < int(nt.FileHeader.NumberOfSections); i++ {
|
|
head := new(IMAGE_SECTION_HEADER)
|
|
binary.Read(data, binary.LittleEndian, head)
|
|
sectionTables[strings.ReplaceAll(fmt.Sprintf("%s", head.Name), "\x00", "")] = head
|
|
fmt.Println(strings.ReplaceAll(fmt.Sprintf("%s", head.Name), "\x00", "") == ".rsrc")
|
|
}
|
|
resourceTable := sectionTables[".rsrc"]
|
|
for s, h := range sectionTables {
|
|
fmt.Printf("\n%q,%v", s, h.PointerToRawData)
|
|
}
|
|
fmt.Println(resourceTable)
|
|
|
|
resource := ParseResource(data, int64(resourceTable.PointerToRawData), 0)
|
|
|
|
fmt.Println(resource)
|
|
}
|
|
|
|
func ParseResource(reader io.ReadSeeker, startOffset int64, offset int64) Resource {
|
|
reader.Seek(startOffset+offset, 0)
|
|
dir := new(IMAGE_RESOURCE_DIRECTORY)
|
|
binary.Read(reader, binary.LittleEndian, dir)
|
|
entities := make([]RealEntity, dir.NumberOfIdEntries+dir.NumberOfNamedEntries)
|
|
for i := 0; i < int(dir.NumberOfIdEntries+dir.NumberOfNamedEntries); i++ {
|
|
entity := new(IMAGE_RESOURCE_Entity)
|
|
binary.Read(reader, binary.LittleEndian, entity)
|
|
realEntity := &RealEntity{}
|
|
realEntity.IMAGE_RESOURCE_Entity = *entity
|
|
if isHighestBitSet(entity.Offset) {
|
|
realEntity.IsFolder = true
|
|
realEntity.Offset = entity.Offset & 0x7FFFFFFF
|
|
}
|
|
entities[i] = *realEntity
|
|
}
|
|
newEntities := make([]RealEntity, dir.NumberOfIdEntries+dir.NumberOfNamedEntries)
|
|
for i, entity := range entities {
|
|
if entity.IsFolder {
|
|
entity.Childern = ParseResource(reader, startOffset, int64(entity.Offset))
|
|
}
|
|
newEntities[i] = entity
|
|
|
|
}
|
|
return Resource{Directory: dir, Entities: newEntities}
|
|
}
|
|
|
|
func isHighestBitSet(value uint32) bool {
|
|
// 右移 24 位,使最高位移到最低位
|
|
highestBit := (value >> 31) & 0x01
|
|
|
|
// 判断最高位是否为 1
|
|
return highestBit == 1
|
|
}
|
|
|
|
func main() {
|
|
ParsePe()
|
|
}
|