func IsPE(fPath string) error { if _, err := pe.Open(fPath); err != nil { return err } return nil }
func pclnPE() (textStart uint64, symtab, pclntab []byte, err error) { f, err := pe.Open(*flagCompiler) if err != nil { return } defer f.Close() var imageBase uint64 switch oh := f.OptionalHeader.(type) { case *pe.OptionalHeader32: imageBase = uint64(oh.ImageBase) case *pe.OptionalHeader64: imageBase = oh.ImageBase default: return 0, nil, nil, fmt.Errorf("pe file format not recognized") } if sect := f.Section(".text"); sect != nil { textStart = imageBase + uint64(sect.VirtualAddress) } if pclntab, err = loadPETable(f, "runtime.pclntab", "runtime.epclntab"); err != nil { return } if symtab, err = loadPETable(f, "runtime.symtab", "runtime.esymtab"); err != nil { return } return }
func getDwarf(execname string) *dwarf.Data { e, err := elf.Open(execname) if err == nil { defer e.Close() d, err := e.DWARF() if err == nil { return d } } m, err := macho.Open(execname) if err == nil { defer m.Close() d, err := m.DWARF() if err == nil { return d } } p, err := pe.Open(execname) if err == nil { defer p.Close() d, err := p.DWARF() if err == nil { return d } } log.Fatal("can't get dwarf info from executable", err) return nil }
func openBinary(name string) (Binary, error) { f, err := os.Open(name) if err != nil { return nil, err } magic := make([]byte, 4) if _, err := f.ReadAt(magic[:], 0); err != nil { return nil, err } if bytes.HasPrefix(magic, []byte{0x7f, 'E', 'L', 'F'}) { e, err := elf.NewFile(f) if err != nil { return nil, err } return &elfBinary{File: e}, nil } else if bytes.HasPrefix(magic, []byte{'M', 'Z'}) { p, err := pe.Open(name) if err != nil { return nil, err } return &peBinary{File: p}, nil } else if bytes.HasPrefix(magic, []byte{0xcf, 0xfa, 0xed, 0xfe}) { m, err := macho.Open(name) if err != nil { return nil, err } return &machoBinary{File: m}, nil } return nil, fmt.Errorf("unsupported binary format") }
func doit(path string) error { f, e := pe.Open(path) check(e) ws, e := workspace.New(workspace.ARCH_X86, workspace.MODE_32) check(e) loader, e := peloader.New(path, f) check(e) m, e := loader.Load(ws) check(e) e = ws.Disassemble(m.EntryPoint, 0x30, os.Stdout) check(e) emu, e := ws.GetEmulator() check(e) emu.SetInstructionPointer(m.EntryPoint) log.Printf("emudbg: start: 0x%x", emu.GetInstructionPointer()) e = doloop(emu) check(e) return nil }
func main() { file, err := pe.Open("Hello.exe") if err != nil { log.Fatalf("failed opening file: %s", err) } defer file.Close() printFileInformation(file) }
func dynimport(obj string) { if f, err := elf.Open(obj); err == nil { sym, err := f.ImportedSymbols() if err != nil { fatalf("cannot load imported symbols from ELF file %s: %v", obj, err) } for _, s := range sym { targ := s.Name if s.Version != "" { targ += "@" + s.Version } fmt.Printf("#pragma dynimport %s %s %q\n", s.Name, targ, s.Library) } lib, err := f.ImportedLibraries() if err != nil { fatalf("cannot load imported libraries from ELF file %s: %v", obj, err) } for _, l := range lib { fmt.Printf("#pragma dynimport _ _ %q\n", l) } return } if f, err := macho.Open(obj); err == nil { sym, err := f.ImportedSymbols() if err != nil { fatalf("cannot load imported symbols from Mach-O file %s: %v", obj, err) } for _, s := range sym { if len(s) > 0 && s[0] == '_' { s = s[1:] } fmt.Printf("#pragma dynimport %s %s %q\n", s, s, "") } lib, err := f.ImportedLibraries() if err != nil { fatalf("cannot load imported libraries from Mach-O file %s: %v", obj, err) } for _, l := range lib { fmt.Printf("#pragma dynimport _ _ %q\n", l) } return } if f, err := pe.Open(obj); err == nil { sym, err := f.ImportedSymbols() if err != nil { fatalf("cannot load imported symbols from PE file %s: %v", obj, err) } for _, s := range sym { ss := strings.Split(s, ":", -1) fmt.Printf("#pragma dynimport %s %s %q\n", ss[0], ss[0], strings.ToLower(ss[1])) } return } fatalf("cannot parse %s as ELF, Mach-O or PE", obj) }
func PEAnal(input string, symbolsDump bool) ([][]int, error) { // An array of arrays for storing the section offsets var sectionData [][]int fmt.Printf("[+] Analyzing binary: %s\n", input) // Check for executable type peFmt, err := pe.Open(input) if err != nil { fmt.Println("[!] This is not a valid PE file") return sectionData, nil } defer peFmt.Close() fmt.Println("[+] This is a valid PE file") fmt.Printf("[+] Number of sections: %d\n", peFmt.NumberOfSections) sections := peFmt.Sections for k := range sections { sec := sections[k] secName := sec.Name secSize := sec.Size secOffset := sec.Offset + 1 secEnd := secOffset + secSize - 1 secVSize := sec.VirtualSize secVAddr := sec.VirtualAddress fmt.Printf("\t Name: %s\n", secName) fmt.Printf("\t Size: %d\n", secSize) fmt.Printf("\t Offset: %d\n", secOffset) fmt.Printf("\t Section end: %d\n", secEnd) fmt.Printf("\t Virtual size: %d\n", secVSize) fmt.Printf("\t Virtual address: %d\n", secVAddr) fmt.Println("") sectionData = append(sectionData, []int{int(secOffset), int(secEnd)}) } numberOfSymbols := peFmt.NumberOfSymbols fmt.Printf("[+] Found %d symbols\n", numberOfSymbols) if numberOfSymbols > 0 && symbolsDump { symbols := peFmt.Symbols for k := range symbols { sym := symbols[k] symName := sym.Name // symType := sym.Type // symValue := sym.Value fmt.Printf("\t Name: %s\n", symName) // fmt.Printf("\t\t Type: %d", symType) // fmt.Printf("\t\t Value: %d", symValue) } fmt.Println("") } return sectionData, nil }
// gccDebug runs gcc -gdwarf-2 over the C program stdin and // returns the corresponding DWARF data and, if present, debug data block. func (p *Package) gccDebug(stdin []byte) (*dwarf.Data, binary.ByteOrder, []byte) { runGcc(stdin, p.gccCmd()) if f, err := macho.Open(gccTmp); err == nil { d, err := f.DWARF() if err != nil { fatalf("cannot load DWARF output from %s: %v", gccTmp, err) } var data []byte if f.Symtab != nil { for i := range f.Symtab.Syms { s := &f.Symtab.Syms[i] // Mach-O still uses a leading _ to denote non-assembly symbols. if s.Name == "_"+"__cgodebug_data" { // Found it. Now find data section. if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) { sect := f.Sections[i] if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size { if sdat, err := sect.Data(); err == nil { data = sdat[s.Value-sect.Addr:] } } } } } } return d, f.ByteOrder, data } // Can skip debug data block in ELF and PE for now. // The DWARF information is complete. if f, err := elf.Open(gccTmp); err == nil { d, err := f.DWARF() if err != nil { fatalf("cannot load DWARF output from %s: %v", gccTmp, err) } return d, f.ByteOrder, nil } if f, err := pe.Open(gccTmp); err == nil { d, err := f.DWARF() if err != nil { fatalf("cannot load DWARF output from %s: %v", gccTmp, err) } return d, binary.LittleEndian, nil } fatalf("cannot parse gcc output %s as ELF, Mach-O, PE object", gccTmp) panic("not reached") }
func Open(name string) (binaryx.File, error) { elfBinary, err := elf.Open(name) if err == nil { return newFile(&elfx.File{elfBinary}) } machoBinary, err := macho.Open(name) if err == nil { return newFile(&machox.File{machoBinary}) } peBinary, err := pe.Open(name) if err == nil { return newFile(&pex.File{peBinary}) } return nil, err }
func listSections(path string) error { f, err := pe.Open(path) if err != nil { return err } defer f.Close() // print sections fmt.Println() fmt.Println("Sections:") fmt.Println() fmt.Printf("idx virtual virtual disk disk reloc reloc mask\n") fmt.Printf(" address size offset size offset qty \n") fmt.Printf("--- ------- ------- ------- ------- ------- ------ --------\n") for i, s := range f.Sections { fmt.Printf("%3d %7x %7x %7x %7x %7x %6d %x %s\n", i+1, s.VirtualAddress, s.VirtualSize, s.Offset, s.Size, s.PointerToRelocations, s.NumberOfRelocations, s.Characteristics, s.Name) } // print alignments fmt.Println() switch oh := f.OptionalHeader.(type) { case nil: fmt.Printf("no section or file alignment (no optional header present)\n") case *pe.OptionalHeader32: fmt.Printf("section alignment is 0x%x\n", oh.SectionAlignment) fmt.Printf("file alignment is 0x%x\n", oh.FileAlignment) case *pe.OptionalHeader64: fmt.Printf("section alignment is 0x%x\n", oh.SectionAlignment) fmt.Printf("file alignment is 0x%x\n", oh.FileAlignment) default: panic("unknown OptionalHeader type") } // print symbols return printSymbols(f) // TODO: I am not sure I want to print coff strings here fmt.Println() fmt.Println("Strings:") fmt.Println() fmt.Print(hex.Dump(f.StringTable)) return nil }
// Exe returns architecture of execute file. func Exe(name string) (CPU, error) { f, err := pe.Open(name) if err != nil { if os.IsNotExist(err) { return OS() } return 0, err } defer f.Close() switch f.FileHeader.Machine { case 0x014c: return X86, nil case 0x8664: return AMD64, nil } return 0, ErrorUnknownArch }
func loadArch(name string) (arch string, err error) { f, err := pe.Open(name) if err != nil { if os.IsNotExist(err) { err = nil } return } defer f.Close() switch f.FileHeader.Machine { case 0x014c: arch = "x86" case 0x8664: arch = "amd64" } return }
func PEAnal(input string) ([]SectionData, []string, []string, error) { // An array of arrays for storing the section offsets var sectionData []SectionData // Check for executable type peFmt, err := pe.Open(input) if err != nil { return sectionData, nil, nil, NotValidPEFileError } defer peFmt.Close() // Extract sections sections := peFmt.Sections for k := range sections { sec := sections[k] secName := sec.Name secSize := sec.Size secOffset := sec.Offset + 1 secEnd := secOffset + secSize - 1 sd := SectionData{ Name: secName, Size: int(secSize), Offset: int(secOffset), End: int(secEnd), } sectionData = append(sectionData, sd) } // Get imported symbols symbolsArr, err := peFmt.ImportedSymbols() if err != nil { return sectionData, nil, nil, err } // Get imported libraries libraries, err := peFmt.ImportedLibraries() if err != nil { return sectionData, nil, nil, err } return sectionData, libraries, symbolsArr, nil }
func dumpSection(path string, name string) error { f, err := pe.Open(path) if err != nil { return err } defer f.Close() sect := f.Section(name) if sect == nil { return fmt.Errorf("could not find section %q", name) } data, err := sect.Data() if err != nil { return err } fmt.Print(hex.Dump(data)) return printRelocations(f, sect) }
func newpe(path string) (tabler, error) { f, err := pe.Open(path) if err != nil { return nil, err } tbl := petbl{f, nil, 0} switch oh := tbl.OptionalHeader.(type) { case *pe.OptionalHeader32: tbl.base = uint64(oh.ImageBase) tbl.typ = PlatformWindows386 case *pe.OptionalHeader64: tbl.base = oh.ImageBase tbl.typ = PlatformWindowsAMD64 default: tbl.Close() return nil, ErrNotGoExec } return tbl, nil }
func PEAutopsy(fileDir string) error { // Open PE file peFile, err := pe.Open(name) if err != nil { return NotValidPEFileError } defer peFile.Close() // Extract all the valuable info architecture := peFile.Machine librariesArr, err := peFile.ImportedLibraries() if err != nil { return err } importedSymbols, err := peFile.ImportedSymbols() if err != nil { return err } peFile. }
func containsDLLs(dir string) bool { compatible := func(name string) bool { file, err := pe.Open(filepath.Join(dir, name)) if err != nil { return false } defer file.Close() switch file.Machine { case pe.IMAGE_FILE_MACHINE_AMD64: return "amd64" == runtime.GOARCH case pe.IMAGE_FILE_MACHINE_ARM: return "arm" == runtime.GOARCH case pe.IMAGE_FILE_MACHINE_I386: return "386" == runtime.GOARCH } return false } return compatible("libglesv2.dll") && compatible("libegl.dll") && compatible("d3dcompiler_47.dll") }
func TestPE(filename, expectedArch, expectedOs string) error { file, err := pe.Open(filename) if err != nil { return errors.New("NOT a PE file") } defer file.Close() log.Printf("File '%s' is a PE file, arch: %d (%d='X86' and %d='AMD64')\n", filename, file.FileHeader.Machine, pe.IMAGE_FILE_MACHINE_I386, pe.IMAGE_FILE_MACHINE_AMD64) if expectedArch == platforms.X86 { if file.FileHeader.Machine != pe.IMAGE_FILE_MACHINE_I386 { return errors.New("Not a 386 executable") } } if expectedArch == platforms.AMD64 { if file.FileHeader.Machine != pe.IMAGE_FILE_MACHINE_AMD64 { return errors.New("Not an AMD64 executable") } } return nil }
// gccDebug runs gcc -gdwarf-2 over the C program stdin and // returns the corresponding DWARF data and any messages // printed to standard error. func (p *Package) gccDebug(stdin []byte) *dwarf.Data { runGcc(stdin, p.gccCmd()) // Try to parse f as ELF and Mach-O and hope one works. var f interface { DWARF() (*dwarf.Data, os.Error) } var err os.Error if f, err = elf.Open(gccTmp); err != nil { if f, err = macho.Open(gccTmp); err != nil { if f, err = pe.Open(gccTmp); err != nil { fatalf("cannot parse gcc output %s as ELF or Mach-O or PE object", gccTmp) } } } d, err := f.DWARF() if err != nil { fatalf("cannot load DWARF debug information from %s: %s", gccTmp, err) } return d }
func doit(path string) error { logrus.SetLevel(logrus.DebugLevel) f, e := pe.Open(path) check(e) persis, e := config.MakeDefaultPersistence() check(e) ws, e := W.New(W.ARCH_X86, W.MODE_32, persis) check(e) loader, e := peloader.New(path, f) check(e) _, e = loader.Load(ws) check(e) check(config.RegisterDefaultAnalyzers(ws)) ws.AnalyzeAll() return nil }
func dynimport(obj string) { stdout := os.Stdout if *dynout != "" { f, err := os.Create(*dynout) if err != nil { fatalf("%s", err) } stdout = f } fmt.Fprintf(stdout, "package %s\n", *dynpackage) if f, err := elf.Open(obj); err == nil { if *dynlinker { // Emit the cgo_dynamic_linker line. if sec := f.Section(".interp"); sec != nil { if data, err := sec.Data(); err == nil && len(data) > 1 { // skip trailing \0 in data fmt.Fprintf(stdout, "//go:cgo_dynamic_linker %q\n", string(data[:len(data)-1])) } } } sym, err := f.ImportedSymbols() if err != nil { fatalf("cannot load imported symbols from ELF file %s: %v", obj, err) } for _, s := range sym { targ := s.Name if s.Version != "" { targ += "#" + s.Version } fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s.Name, targ, s.Library) } lib, err := f.ImportedLibraries() if err != nil { fatalf("cannot load imported libraries from ELF file %s: %v", obj, err) } for _, l := range lib { fmt.Fprintf(stdout, "//go:cgo_import_dynamic _ _ %q\n", l) } return } if f, err := macho.Open(obj); err == nil { sym, err := f.ImportedSymbols() if err != nil { fatalf("cannot load imported symbols from Mach-O file %s: %v", obj, err) } for _, s := range sym { if len(s) > 0 && s[0] == '_' { s = s[1:] } fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s, s, "") } lib, err := f.ImportedLibraries() if err != nil { fatalf("cannot load imported libraries from Mach-O file %s: %v", obj, err) } for _, l := range lib { fmt.Fprintf(stdout, "//go:cgo_import_dynamic _ _ %q\n", l) } return } if f, err := pe.Open(obj); err == nil { sym, err := f.ImportedSymbols() if err != nil { fatalf("cannot load imported symbols from PE file %s: %v", obj, err) } for _, s := range sym { ss := strings.Split(s, ":") name := strings.Split(ss[0], "@")[0] fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", name, ss[0], strings.ToLower(ss[1])) } return } fatalf("cannot parse %s as ELF, Mach-O or PE", obj) }
// gccDebug runs gcc -gdwarf-2 over the C program stdin and // returns the corresponding DWARF data and, if present, debug data block. func (p *Package) gccDebug(stdin []byte) (*dwarf.Data, binary.ByteOrder, []byte) { runGcc(stdin, p.gccCmd()) isDebugData := func(s string) bool { // Some systems use leading _ to denote non-assembly symbols. return s == "__cgodebug_data" || s == "___cgodebug_data" } if f, err := macho.Open(gccTmp()); err == nil { defer f.Close() d, err := f.DWARF() if err != nil { fatalf("cannot load DWARF output from %s: %v", gccTmp(), err) } var data []byte if f.Symtab != nil { for i := range f.Symtab.Syms { s := &f.Symtab.Syms[i] if isDebugData(s.Name) { // Found it. Now find data section. if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) { sect := f.Sections[i] if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size { if sdat, err := sect.Data(); err == nil { data = sdat[s.Value-sect.Addr:] } } } } } } return d, f.ByteOrder, data } if f, err := elf.Open(gccTmp()); err == nil { defer f.Close() d, err := f.DWARF() if err != nil { fatalf("cannot load DWARF output from %s: %v", gccTmp(), err) } var data []byte symtab, err := f.Symbols() if err == nil { for i := range symtab { s := &symtab[i] if isDebugData(s.Name) { // Found it. Now find data section. if i := int(s.Section); 0 <= i && i < len(f.Sections) { sect := f.Sections[i] if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size { if sdat, err := sect.Data(); err == nil { data = sdat[s.Value-sect.Addr:] } } } } } } return d, f.ByteOrder, data } if f, err := pe.Open(gccTmp()); err == nil { defer f.Close() d, err := f.DWARF() if err != nil { fatalf("cannot load DWARF output from %s: %v", gccTmp(), err) } var data []byte for _, s := range f.Symbols { if isDebugData(s.Name) { if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) { sect := f.Sections[i] if s.Value < sect.Size { if sdat, err := sect.Data(); err == nil { data = sdat[s.Value:] } } } } } return d, binary.LittleEndian, data } fatalf("cannot parse gcc output %s as ELF, Mach-O, PE object", gccTmp()) panic("not reached") }
func doit(path string, fva AS.VA) error { runtime.LockOSThread() logrus.SetLevel(logrus.DebugLevel) exe, e := pe.Open(path) check(e) persis, e := config.MakeDefaultPersistence() check(e) ws, e := W.New(W.ARCH_X86, W.MODE_32, persis) check(e) dis, e := ws.GetDisassembler() check(e) loader, e := peloader.New(path, exe) check(e) _, e = loader.Load(ws) check(e) check(config.RegisterDefaultAnalyzers(ws)) check(ws.MakeFunction(fva)) f, e := ws.Artifacts.GetFunction(fva) check(e) fmt.Printf("digraph asm {\n") fmt.Printf(" node [shape=plain, style=\"rounded\", fontname=\"courier\"]\n") var exploreBBs func(bb *artifacts.BasicBlock) error exploreBBs = func(bb *artifacts.BasicBlock) error { fmt.Printf("bb_%s [label=<\n", bb.Start) fmt.Printf("<TABLE BORDER='1' CELLBORDER='0'>\n") insns, e := bb.GetInstructions(dis, ws) check(e) for _, insn := range insns { d, e := ws.MemRead(AS.VA(insn.Address), uint64(insn.Size)) check(e) // format each of those as hex var bytesPrefix []string for _, b := range d { bytesPrefix = append(bytesPrefix, fmt.Sprintf("%02X", b)) } prefix := strings.Join(bytesPrefix, " ") fmt.Printf(" <TR>\n") fmt.Printf(" <TD ALIGN=\"LEFT\">\n") fmt.Printf(" %s\n", AS.VA(insn.Address)) fmt.Printf(" </TD>\n") fmt.Printf(" <TD ALIGN=\"LEFT\">\n") fmt.Printf(" %s\n", prefix) fmt.Printf(" </TD>\n") fmt.Printf(" <TD ALIGN=\"LEFT\">\n") fmt.Printf(" %s\n", insn.Mnemonic) fmt.Printf(" </TD>\n") fmt.Printf(" <TD ALIGN=\"LEFT\">\n") fmt.Printf(" %s\n", insn.OpStr) fmt.Printf(" </TD>\n") fmt.Printf(" </TR>\n") } fmt.Printf("</TABLE>\n") fmt.Printf(">];\n") nextBBs, e := bb.GetNextBasicBlocks() check(e) for _, nextBB := range nextBBs { exploreBBs(nextBB) } for _, nextBB := range nextBBs { fmt.Printf("bb_%s -> bb_%s;\n", bb.Start, nextBB.Start) } return nil } firstBB, e := f.GetFirstBasicBlock() check(e) exploreBBs(firstBB) defer fmt.Printf("}") runtime.UnlockOSThread() return nil }