diff --git a/macho-go/internal/wrapper/action/remove_exports.go b/macho-go/internal/wrapper/action/remove_exports.go index f4c257b..5920024 100644 --- a/macho-go/internal/wrapper/action/remove_exports.go +++ b/macho-go/internal/wrapper/action/remove_exports.go @@ -18,4 +18,3 @@ func (action *removeExports) withFat(ff *FatFile) error { func NewRemoveExportsAction() *removeExports { return &removeExports{} } - diff --git a/macho-go/internal/wrapper/action/remove_imports.go b/macho-go/internal/wrapper/action/remove_imports.go index d40beac..310c21f 100644 --- a/macho-go/internal/wrapper/action/remove_imports.go +++ b/macho-go/internal/wrapper/action/remove_imports.go @@ -20,4 +20,3 @@ func (action *removeImports) withFat(ff *FatFile) error { func NewRemoveImportsAction() *removeImports { return &removeImports{} } - diff --git a/macho-go/internal/wrapper/action/save_imports.go b/macho-go/internal/wrapper/action/save_imports.go index c24c30c..094d47a 100644 --- a/macho-go/internal/wrapper/action/save_imports.go +++ b/macho-go/internal/wrapper/action/save_imports.go @@ -1,7 +1,7 @@ package action import ( - "fmt" + "fmt" // log "github.com/sirupsen/logrus" . "ios-wrapper/internal/wrapper/ofile" @@ -11,52 +11,52 @@ import ( type saveImports struct{} func (action *saveImports) withMacho(mf *MachoFile) error { - calculateHash := func(name string) uint32 { - var h uint32 = 0x811c9dc5 - for _, s := range name { - h ^= uint32(s) - h *= 0x01000193 - } - return h - } + calculateHash := func(name string) uint32 { + var h uint32 = 0x811c9dc5 + for _, s := range name { + h ^= uint32(s) + h *= 0x01000193 + } + return h + } - mc := mf.Context() + mc := mf.Context() symbols := []*protomodel.MachoInfo_BindSymbol{} - fmt.Println("struct imported_symbol {const char* name; const char* lib; uint32_t hash; int segment_i; uint64_t offset;};") - fmt.Println("const char* lib_to_resolve = \"main\";") - fmt.Println("struct imported_symbol imported_table[] = {") - for _, symbol := range mc.CollectBindSymbols() { - if symbol.Type() != "lazy" { - continue - } - dylib_hash := calculateHash(symbol.Dylib()) - seg := mc.Segments()[symbol.Segment()] + fmt.Println("struct imported_symbol {const char* name; const char* lib; uint32_t hash; int segment_i; uint64_t offset;};") + fmt.Println("const char* lib_to_resolve = \"main\";") + fmt.Println("struct imported_symbol imported_table[] = {") + for _, symbol := range mc.CollectBindSymbols() { + if symbol.Type() != "lazy" { + continue + } + dylib_hash := calculateHash(symbol.Dylib()) + seg := mc.Segments()[symbol.Segment()] - var offset uint64 + var offset uint64 - if symbol.Address() >= seg.Vmaddr() { - // this is virtual address - offset = symbol.Address() - seg.Vmaddr() - } else { - // this is file address - offset = symbol.Address() - seg.Fileoff() - } + if symbol.Address() >= seg.Vmaddr() { + // this is virtual address + offset = symbol.Address() - seg.Vmaddr() + } else { + // this is file address + offset = symbol.Address() - seg.Fileoff() + } - fmt.Printf("{\"%s\", \"%s\", 0x%x, 0x%x, 0x%x},\n", - symbol.Name(), symbol.Dylib(), dylib_hash, symbol.Segment(), offset); + fmt.Printf("{\"%s\", \"%s\", 0x%x, 0x%x, 0x%x},\n", + symbol.Name(), symbol.Dylib(), dylib_hash, symbol.Segment(), offset) symbols = append(symbols, &protomodel.MachoInfo_BindSymbol{ - Name: symbol.Name(), - Libname: symbol.Dylib(), - Libhash: dylib_hash, - Segment: symbol.Segment(), - Offset: offset, + Name: symbol.Name(), + Libname: symbol.Dylib(), + Libhash: dylib_hash, + Segment: symbol.Segment(), + Offset: offset, }) - } - fmt.Println("};") - fmt.Printf("uint32_t nimports = %d;\n", len(symbols)); + } + fmt.Println("};") + fmt.Printf("uint32_t nimports = %d;\n", len(symbols)) mf.Info().Symbols = symbols return nil } @@ -68,4 +68,3 @@ func (action *saveImports) withFat(ff *FatFile) error { func NewSaveImportsAction() *saveImports { return &saveImports{} } - diff --git a/macho-go/internal/wrapper/cli.go b/macho-go/internal/wrapper/cli.go index 4771aa7..1b992ed 100644 --- a/macho-go/internal/wrapper/cli.go +++ b/macho-go/internal/wrapper/cli.go @@ -4,7 +4,7 @@ import ( "fmt" "io/ioutil" "os" - "strings" + "strings" "github.com/alecthomas/kong" log "github.com/sirupsen/logrus" @@ -65,10 +65,10 @@ func Cli() { fat.FatJoin(arg.Macho, arg.Out) return } else if command == "bcell2header" { - arg := cli.BcellToHeader - bcell2header(arg.Bcell, arg.Out) - return - } + arg := cli.BcellToHeader + bcell2header(arg.Bcell, arg.Out) + return + } var pc ProgramContext var ofile OFile = nil @@ -106,23 +106,23 @@ func Cli() { pc.outfile = arg.Out pc.bcellfile = arg.Bcell - case "pepe": + case "pepe": arg := cli.Pepe ofile = NewOFile(arg.OFile) - if arg.FullRemoval { - pc.remove_exports = true - pc.remove_symbol_table = true - pc.remove_imports = true - pc.remove_inits = true - pc.remove_codesign = true - pc.remove_others = true - } + if arg.FullRemoval { + pc.remove_exports = true + pc.remove_symbol_table = true + pc.remove_imports = true + pc.remove_inits = true + pc.remove_codesign = true + pc.remove_others = true + } pc.remove_imports = arg.RemoveBindSymbols - pc.remove_codesign = arg.RemoveCodeSign + pc.remove_codesign = arg.RemoveCodeSign pc.remove_inits = arg.RemoveInitFunctions - pc.remove_others = arg.RemoveOthers - pc.remove_exports = arg.RemoveExports - pc.remove_symbol_table = arg.RemoveSymbolTable + pc.remove_others = arg.RemoveOthers + pc.remove_exports = arg.RemoveExports + pc.remove_symbol_table = arg.RemoveSymbolTable pc.dylib_to_add = arg.Dylibs pc.rpath_to_add = arg.Rpath pc.outfile = arg.Out @@ -195,7 +195,7 @@ func displayBcell(bfile string) { } fmt.Printf(" | Bind Symbols:\n") for _, symbol := range info.Symbols { - lib := strings.Replace(symbol.Libname, "/System/Library/Frameworks/", "", 1) + lib := strings.Replace(symbol.Libname, "/System/Library/Frameworks/", "", 1) fmt.Printf(" | %s offset=0x%x segmentID=0x%x\n", symbol.Name, symbol.Offset, symbol.Segment) fmt.Printf(" | from=%s\n", lib) } @@ -255,7 +255,7 @@ func bcell2header(bfile string, header string) { } fmt.Printf(" | Bind Symbols:\n") for _, symbol := range info.Symbols { - lib := strings.Replace(symbol.Libname, "/System/Library/Frameworks/", "", 1) + lib := strings.Replace(symbol.Libname, "/System/Library/Frameworks/", "", 1) fmt.Printf(" | %s offset=0x%x segmentID=0x%x\n", symbol.Name, symbol.Offset, symbol.Segment) fmt.Printf(" | from=%s\n", lib) } diff --git a/macho-go/internal/wrapper/cli_parser.go b/macho-go/internal/wrapper/cli_parser.go index 9179b13..74b54f4 100644 --- a/macho-go/internal/wrapper/cli_parser.go +++ b/macho-go/internal/wrapper/cli_parser.go @@ -26,7 +26,7 @@ type RemoveCodesignArgument struct { type RemoveImportsArgument struct { Out string `short:"o" required name:"outfile" help:"Modified Mach-O/Fat binary output file" type:"path"` - Bcell string `short:"b" required help:"bcell.dat output file" type:"path"` + Bcell string `short:"b" required help:"bcell.dat output file" type:"path"` OFile string `arg help:"Path to Mach-O/Fat binary file" type:"existingfile"` } @@ -56,26 +56,26 @@ type LipoArgument struct { } type PepeArgument struct { - Out string `short:"o" required name:"outfile" help:"Output file after transformation" type:"path"` - Bcell string `short:"b" required help:"bcell.dat output file" type:"path"` - OFile string `arg help:"Path to Mach-O/Fat binary file" type:"existingfile"` - Dylibs []string `short:"l" help:"Add more LC_DYLIB"` - Rpath []string `short:"r" help:"Add more LC_RPATH"` - RemoveCodeSign bool `default:"false" negatable:"" help:"Remove LC_CODE_SIGNATURE"` - RemoveExports bool `default:"false" negatable:"" help:"Clear the export table/trie"` - RemoveSymbolTable bool `default:"true" negatable:"" help:"Remove LC_SYMTAB and LC_DYSYMTAB"` - RemoveOthers bool `default:"false" negatable:"" help:"Remove LC_FUNCTION_STARTS, LC_DATA_IN_CODE, ..."` - RemoveID bool `default:"false" negatable:"" help:"(TODO) Remove LC_ID_DYLIB"` - RemoveInitFunctions bool `default:"false" name:"remove-inits" negatable:"" help:"Clear MOD_INIT_FUNC section"` - RemoveBindSymbols bool `default:"false" name:"remove-imports" negatable:"" help:"Remove all bind symbols information"` - RemoveObjCString bool `default:"false" negatable:"" help:"(TODO) Remove references, string litteral to Objctive-C strings"` - RebuildLinkEdit bool `default:"false" negatable:"" help:"(TODO) Rebuild the LINKEDIT section"` - FullRemoval bool `default:"false" help:"Apply every removal possible"` + Out string `short:"o" required name:"outfile" help:"Output file after transformation" type:"path"` + Bcell string `short:"b" required help:"bcell.dat output file" type:"path"` + OFile string `arg help:"Path to Mach-O/Fat binary file" type:"existingfile"` + Dylibs []string `short:"l" help:"Add more LC_DYLIB"` + Rpath []string `short:"r" help:"Add more LC_RPATH"` + RemoveCodeSign bool `default:"false" negatable:"" help:"Remove LC_CODE_SIGNATURE"` + RemoveExports bool `default:"false" negatable:"" help:"Clear the export table/trie"` + RemoveSymbolTable bool `default:"true" negatable:"" help:"Remove LC_SYMTAB and LC_DYSYMTAB"` + RemoveOthers bool `default:"false" negatable:"" help:"Remove LC_FUNCTION_STARTS, LC_DATA_IN_CODE, ..."` + RemoveID bool `default:"false" negatable:"" help:"(TODO) Remove LC_ID_DYLIB"` + RemoveInitFunctions bool `default:"false" name:"remove-inits" negatable:"" help:"Clear MOD_INIT_FUNC section"` + RemoveBindSymbols bool `default:"false" name:"remove-imports" negatable:"" help:"Remove all bind symbols information"` + RemoveObjCString bool `default:"false" negatable:"" help:"(TODO) Remove references, string litteral to Objctive-C strings"` + RebuildLinkEdit bool `default:"false" negatable:"" help:"(TODO) Rebuild the LINKEDIT section"` + FullRemoval bool `default:"false" help:"Apply every removal possible"` } type BcellToHeaderArgument struct { - Out string `short:"o" required name:"outfile" help:"Header file name to output to" type:"path"` - Bcell string `short:"b" required help:"Input bcell.dat file" type:"existingfile"` + Out string `short:"o" required name:"outfile" help:"Header file name to output to" type:"path"` + Bcell string `short:"b" required help:"Input bcell.dat file" type:"existingfile"` } type Argument struct { @@ -89,13 +89,13 @@ type Argument struct { Addr2Line Addr2LineArgument `cmd name:"addr2line" help:"Resolve crash address from DWARF file"` Lipo LipoArgument `cmd help:"split Fat binary or join Mach-O binares"` Pepe PepeArgument `cmd help:"custom command"` - BcellToHeader BcellToHeaderArgument `cmd name:"bcell2header" help:"Build C header file from bcell file"` - AddSection struct { - Out string `short:"o" required name:"outfile" help:"Output file after transformation"` - Data string `arg help:"Input data file to fill in this section, or null if not provided" type:"existingfile"` - OFile string `arg help:"Path to Mach-O/Fat binary file" type:"existingfile"` - Segment string `required help:"Segment name"` - Section string `required help:"Section name"` - Size int `required help:"Size of segment/section"` - } `cmd:"" default:"false" help:"(TODO) Add a new segment with 1 section, segment starts at the end of last segment"` + BcellToHeader BcellToHeaderArgument `cmd name:"bcell2header" help:"Build C header file from bcell file"` + AddSection struct { + Out string `short:"o" required name:"outfile" help:"Output file after transformation"` + Data string `arg help:"Input data file to fill in this section, or null if not provided" type:"existingfile"` + OFile string `arg help:"Path to Mach-O/Fat binary file" type:"existingfile"` + Segment string `required help:"Segment name"` + Section string `required help:"Section name"` + Size int `required help:"Size of segment/section"` + } `cmd:"" default:"false" help:"(TODO) Add a new segment with 1 section, segment starts at the end of last segment"` } diff --git a/macho-go/internal/wrapper/info.go b/macho-go/internal/wrapper/info.go index 3f2bb8f..e3fef8e 100644 --- a/macho-go/internal/wrapper/info.go +++ b/macho-go/internal/wrapper/info.go @@ -35,16 +35,16 @@ func (printer *InfoPrinter) Print() { } symbols := mc.CollectBindSymbols() - for _, sym := range symbols { - fmt.Printf( - "%s (%s)\n\tStub=0x%x Address=0x%x\n\tDylib=%s\n", - sym.Name(), - sym.Type(), - sym.Stub(), - sym.Address(), - sym.Dylib(), - ) - } + for _, sym := range symbols { + fmt.Printf( + "%s (%s)\n\tStub=0x%x Address=0x%x\n\tDylib=%s\n", + sym.Name(), + sym.Type(), + sym.Stub(), + sym.Address(), + sym.Dylib(), + ) + } fmt.Println("======") } diff --git a/macho-go/internal/wrapper/program_context.go b/macho-go/internal/wrapper/program_context.go index 7f3b242..5711a57 100644 --- a/macho-go/internal/wrapper/program_context.go +++ b/macho-go/internal/wrapper/program_context.go @@ -38,12 +38,12 @@ func (uc *UserConfig) Protomodel() *protomodel.Config { } type ProgramContext struct { - remove_inits bool + remove_inits bool remove_codesign bool remove_imports bool - remove_others bool - remove_exports bool - remove_symbol_table bool + remove_others bool + remove_exports bool + remove_symbol_table bool dylib_to_add []string rpath_to_add []string @@ -96,18 +96,18 @@ func (pc *ProgramContext) Process(ofile OFile) { } if pc.remove_imports { pc.AddAction(NewSaveImportsAction()) - pc.AddAction(NewRemoveImportsAction()) + pc.AddAction(NewRemoveImportsAction()) } - if pc.remove_symbol_table { + if pc.remove_symbol_table { pc.AddAction(NewRemoveClassicSymbolAction()) - } - if pc.remove_exports { - pc.AddAction(NewRemoveExportsAction()) - } + } + if pc.remove_exports { + pc.AddAction(NewRemoveExportsAction()) + } ExperimentalFeature("Remove Unnecessary Info", func() { - if pc.remove_others { - pc.AddAction(NewRemoveUnnecessaryInfoAction()) - } + if pc.remove_others { + pc.AddAction(NewRemoveUnnecessaryInfoAction()) + } }) pc.AddAction(NewAddRpathAction(pc.rpath_to_add)) pc.AddAction(NewAddDylibAction(pc.dylib_to_add)) diff --git a/macho-go/pkg/ios/macho/dyld_info.go b/macho-go/pkg/ios/macho/dyld_info.go index 494f4ba..10c3c54 100644 --- a/macho-go/pkg/ios/macho/dyld_info.go +++ b/macho-go/pkg/ios/macho/dyld_info.go @@ -4,9 +4,9 @@ import ( "bytes" "encoding/binary" "fmt" - "unsafe" + "unsafe" // "bufio" - "io" + "io" log "github.com/sirupsen/logrus" @@ -19,7 +19,7 @@ import "C" type ImportSymbol struct { name string - typ string + typ string dylib string segment uint32 segment_offset uint32 @@ -30,7 +30,7 @@ type ImportSymbol struct { pnum uint32 stub uint64 - next int // only for LC_DYLD_CHAINED_FIXUPS + next int // only for LC_DYLD_CHAINED_FIXUPS } func (sym *ImportSymbol) Name() string { @@ -70,140 +70,140 @@ func (mc *MachoContext) CollectBindSymbols() []*ImportSymbol { } func (mc *MachoContext) findSegmentIndexAt(address uint64) int { - for i, segment := range mc.Segments() { - if segment.Fileoff() <= address && segment.Fileoff() + segment.Filesize() > address { - return i - } - } - return -1 + for i, segment := range mc.Segments() { + if segment.Fileoff() <= address && segment.Fileoff()+segment.Filesize() > address { + return i + } + } + return -1 } // New convention using LC_DYLD_CHAINED_FIXUPS func (mc *MachoContext) CollectBindSymbolsModern() []*ImportSymbol { - start := mc.fixups.dataoff - size := mc.fixups.datasize - buf := mc.buf[start:start+size] + start := mc.fixups.dataoff + size := mc.fixups.datasize + buf := mc.buf[start : start+size] - // all pointers used are based from this **buf** - // until buf is freed, all pointers are valid - // remember to copy before moving out - header := (*C.uchar)(unsafe.Pointer(&buf[0])) - imports_table := C.GetImportsTable(header); + // all pointers used are based from this **buf** + // until buf is freed, all pointers are valid + // remember to copy before moving out + header := (*C.uchar)(unsafe.Pointer(&buf[0])) + imports_table := C.GetImportsTable(header) - // for i := 0; i < int(imports_table.size); i++ { - // s := C.GetImportsAt(&imports_table, C.int(i)) - // name := C.GoString(s.name) - // symbol.dylib := string(mc.dylibs[int(s.lib_ordinal)-1].name[:]) - // symbol_table = append(symbol_table, symbol) - // fmt.Printf("id=%d lib=%s name=%s\n", i, dylib, name) - // } + // for i := 0; i < int(imports_table.size); i++ { + // s := C.GetImportsAt(&imports_table, C.int(i)) + // name := C.GoString(s.name) + // symbol.dylib := string(mc.dylibs[int(s.lib_ordinal)-1].name[:]) + // symbol_table = append(symbol_table, symbol) + // fmt.Printf("id=%d lib=%s name=%s\n", i, dylib, name) + // } var syms []*ImportSymbol var sym ImportSymbol - segment_i := 0 - for { - var fix C.struct_SegmentFix - fix_ptr := (*C.struct_SegmentFix)(unsafe.Pointer(&fix)) - status := int(C.GetSegmentFixAt(header, C.uint(segment_i), fix_ptr)) - segment_i += 1 - if status == 2 { - break; - } - if status == 3 { - continue - } - // fmt.Printf("segment=%x format=%x page_count=%d\n", fix.segment, fix.format, fix.page_count) - // fmt.Printf("pages=%x\n", fix.pages) - pages := ([]C.ushort)(unsafe.Slice(fix.pages, fix.page_count)) - for page_i := 0; page_i < int(fix.page_count); page_i++ { - // fmt.Printf(" page offset=%x\n", pages[page_i]) + segment_i := 0 + for { + var fix C.struct_SegmentFix + fix_ptr := (*C.struct_SegmentFix)(unsafe.Pointer(&fix)) + status := int(C.GetSegmentFixAt(header, C.uint(segment_i), fix_ptr)) + segment_i += 1 + if status == 2 { + break + } + if status == 3 { + continue + } + // fmt.Printf("segment=%x format=%x page_count=%d\n", fix.segment, fix.format, fix.page_count) + // fmt.Printf("pages=%x\n", fix.pages) + pages := ([]C.ushort)(unsafe.Slice(fix.pages, fix.page_count)) + for page_i := 0; page_i < int(fix.page_count); page_i++ { + // fmt.Printf(" page offset=%x\n", pages[page_i]) - address := int64(fix.segment) + int64(pages[page_i]) - mc.file.Seek(address, io.SeekStart) + address := int64(fix.segment) + int64(pages[page_i]) + mc.file.Seek(address, io.SeekStart) - code := make([]byte, 8) + code := make([]byte, 8) - for { - mc.file.Read(code) - v := mc.byteorder.Uint64(code) + for { + mc.file.Read(code) + v := mc.byteorder.Uint64(code) - var bind C.int - var ret1 C.ulonglong - var ret2 C.ulonglong - next := C.ParseFixValue(C.int(fix.format), C.ulonglong(v), - &bind, &ret1, &ret2) + var bind C.int + var ret1 C.ulonglong + var ret2 C.ulonglong + next := C.ParseFixValue(C.int(fix.format), C.ulonglong(v), + &bind, &ret1, &ret2) - if bind == 1 { - s := C.GetImportsAt(&imports_table, C.int(ret1)) - name := C.GoString(s.name) - dylib := string(mc.dylibs[int(s.lib_ordinal)-1].name[:]) + if bind == 1 { + s := C.GetImportsAt(&imports_table, C.int(ret1)) + name := C.GoString(s.name) + dylib := string(mc.dylibs[int(s.lib_ordinal)-1].name[:]) - fmt.Printf("// 0x%x bind=%d (%s)%s\n", address, bind, dylib, name) + fmt.Printf("// 0x%x bind=%d (%s)%s\n", address, bind, dylib, name) - sym.address = uint64(address) - sym.name = name - sym.dylib = dylib - sym.typ = "lazy" + sym.address = uint64(address) + sym.name = name + sym.dylib = dylib + sym.typ = "lazy" - sym.segment = uint32(mc.findSegmentIndexAt(uint64(address))) - sym.file_address = uint64(address) - sym.next = int(next) - new_sym := sym - syms = append(syms, &new_sym) - } else { - fmt.Printf("// 0x%x rebase=%d target=0x%x high8=0x%x\n", address, bind, ret1, ret2) - } + sym.segment = uint32(mc.findSegmentIndexAt(uint64(address))) + sym.file_address = uint64(address) + sym.next = int(next) + new_sym := sym + syms = append(syms, &new_sym) + } else { + fmt.Printf("// 0x%x rebase=%d target=0x%x high8=0x%x\n", address, bind, ret1, ret2) + } - if int(next) == 0 { - break - } - // because the pointer move up 8 bytes already so we minus 8 - address += int64(next * 4) - mc.file.Seek(int64(next * 4) - 8, io.SeekCurrent) - } - mc.file.Seek(0, io.SeekStart) - } - } + if int(next) == 0 { + break + } + // because the pointer move up 8 bytes already so we minus 8 + address += int64(next * 4) + mc.file.Seek(int64(next*4)-8, io.SeekCurrent) + } + mc.file.Seek(0, io.SeekStart) + } + } return syms } // Old convention using LC_DYLD_INFO_ONLY section and bytecode runner func (mc *MachoContext) CollectBindSymbolsLegacy() []*ImportSymbol { - noLazy := (func() []*ImportSymbol { - start := mc.dyldinfo.bind_off - size := mc.dyldinfo.bind_size - end := start + size - buf := bytes.NewBuffer(mc.buf[start:end]) - return mc.readBindStream(buf, "no lazy") - })() + noLazy := (func() []*ImportSymbol { + start := mc.dyldinfo.bind_off + size := mc.dyldinfo.bind_size + end := start + size + buf := bytes.NewBuffer(mc.buf[start:end]) + return mc.readBindStream(buf, "no lazy") + })() - lazy := (func() []*ImportSymbol { - start := mc.dyldinfo.lazy_bind_off - size := mc.dyldinfo.lazy_bind_size - end := start + size - buf := bytes.NewBuffer(mc.buf[start:end]) - return mc.readBindStream(buf, "lazy") - })() + lazy := (func() []*ImportSymbol { + start := mc.dyldinfo.lazy_bind_off + size := mc.dyldinfo.lazy_bind_size + end := start + size + buf := bytes.NewBuffer(mc.buf[start:end]) + return mc.readBindStream(buf, "lazy") + })() - weak := (func() []*ImportSymbol { - start := mc.dyldinfo.weak_bind_off - size := mc.dyldinfo.weak_bind_size - end := start + size - buf := bytes.NewBuffer(mc.buf[start:end]) - return mc.readBindStream(buf, "weak") - })() + weak := (func() []*ImportSymbol { + start := mc.dyldinfo.weak_bind_off + size := mc.dyldinfo.weak_bind_size + end := start + size + buf := bytes.NewBuffer(mc.buf[start:end]) + return mc.readBindStream(buf, "weak") + })() - var symbols []*ImportSymbol - symbols = append(symbols, noLazy...) - symbols = append(symbols, lazy...) - symbols = append(symbols, weak...) + var symbols []*ImportSymbol + symbols = append(symbols, noLazy...) + symbols = append(symbols, lazy...) + symbols = append(symbols, weak...) - return symbols + return symbols } func (mc *MachoContext) readBindStream(buf *bytes.Buffer, typ string) []*ImportSymbol { - size := buf.Len() + size := buf.Len() if size == 0 { return []*ImportSymbol{} } @@ -237,7 +237,7 @@ func (mc *MachoContext) readBindStream(buf *bytes.Buffer, typ string) []*ImportS case BIND_OPCODE_DO_BIND: if sym.name != "" { new_sym := sym - new_sym.typ = typ + new_sym.typ = typ syms = append(syms, &new_sym) // fmt.Printf("Offset 0x%x: Symbol %+v\n", symoffset, sym) @@ -246,7 +246,7 @@ func (mc *MachoContext) readBindStream(buf *bytes.Buffer, typ string) []*ImportS "symbol": sym.name, }).Trace("Bind") sym.name = "" - sym.address += 8 + sym.address += 8 } offset += 1 break @@ -275,9 +275,9 @@ func (mc *MachoContext) readBindStream(buf *bytes.Buffer, typ string) []*ImportS case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: sym.name, _ = buf.ReadString(0) - // ReadString input the 0x00 byte to buffer - // while we are string so we can remove that - sym.name = sym.name[:len(sym.name)-1] + // ReadString input the 0x00 byte to buffer + // while we are string so we can remove that + sym.name = sym.name[:len(sym.name)-1] offset += uint(len(sym.name)) break @@ -301,12 +301,12 @@ func (mc *MachoContext) readBindStream(buf *bytes.Buffer, typ string) []*ImportS offset += br break - case BIND_OPCODE_SET_TYPE_IMM: - fmt.Println("// symbol type", imm) - break + case BIND_OPCODE_SET_TYPE_IMM: + fmt.Println("// symbol type", imm) + break default: - fmt.Println("BIND OPCODE NOT SUPPORTED", op, imm) + fmt.Println("BIND OPCODE NOT SUPPORTED", op, imm) break } } diff --git a/macho-go/pkg/ios/macho/edit.go b/macho-go/pkg/ios/macho/edit.go index 79c5b00..c6eb69b 100644 --- a/macho-go/pkg/ios/macho/edit.go +++ b/macho-go/pkg/ios/macho/edit.go @@ -1,11 +1,11 @@ package macho import ( + "bytes" "fmt" "io" - "math/rand" - "time" - "bytes" + "math/rand" + "time" log "github.com/sirupsen/logrus" @@ -272,93 +272,93 @@ func (mc *MachoContext) UpdateHeaderRemoveLcmd(size uint32) { func (mc *MachoContext) RemoveBindSymbols() { if !mc.WriteEnabled() { - return - } + return + } - rand.Seed(time.Now().UnixNano()) + rand.Seed(time.Now().UnixNano()) if mc.dyldinfo == nil { mc.removeBindSymbolsModern() } else { mc.removeBindSymbolsLegacy() } - mc.ReworkForObjc() + mc.ReworkForObjc() - // due to some limitations when design this tool - // we write the c code to stdout lol - for _, symbol := range mc.CollectBindSymbols() { - if symbol.Type() != "lazy" { - continue - } + // due to some limitations when design this tool + // we write the c code to stdout lol + for _, symbol := range mc.CollectBindSymbols() { + if symbol.Type() != "lazy" { + continue + } - if mc.dyldinfo != nil { - // for legacy resolve the opcodes can be rewritten as 0x00 - mc.file.WriteAt(make([]byte, 8), int64(symbol.file_address)) - } else { - // for modern resolve the opcodes must not be rewritten as 0x00 - // because it contains 2 types of opcodes, BIND and REBASE - // we only fix BIND and leave REBASE intact - // However, each opcodes has a *next* field to the next opcode - // So if we want to leave the header intact (contains pointers, size) - // We should rewrite this as REBASE opcode (so no symbol lookup happens) - // and it can continue + if mc.dyldinfo != nil { + // for legacy resolve the opcodes can be rewritten as 0x00 + mc.file.WriteAt(make([]byte, 8), int64(symbol.file_address)) + } else { + // for modern resolve the opcodes must not be rewritten as 0x00 + // because it contains 2 types of opcodes, BIND and REBASE + // we only fix BIND and leave REBASE intact + // However, each opcodes has a *next* field to the next opcode + // So if we want to leave the header intact (contains pointers, size) + // We should rewrite this as REBASE opcode (so no symbol lookup happens) + // and it can continue - // we can write random values, because the loader just do - // (high8 << 56 | target) - mach_header - // or something, so no symbol lookup and no error at runtime - target := rand.Int() - high8 := rand.Int() - value := C.MakeRebaseFixupOpcode(C.int(symbol.next), C.ulonglong(target), C.ulonglong(high8)) - v := make([]byte, 8) - mc.byteorder.PutUint64(v, uint64(value)) - mc.file.WriteAt(v, int64(symbol.file_address)) - } - } + // we can write random values, because the loader just do + // (high8 << 56 | target) - mach_header + // or something, so no symbol lookup and no error at runtime + target := rand.Int() + high8 := rand.Int() + value := C.MakeRebaseFixupOpcode(C.int(symbol.next), C.ulonglong(target), C.ulonglong(high8)) + v := make([]byte, 8) + mc.byteorder.PutUint64(v, uint64(value)) + mc.file.WriteAt(v, int64(symbol.file_address)) + } + } } func (mc *MachoContext) removeBindSymbolsModern() { - // we don't mess up the chain - // we clear the imports table, and the raw opcodes - // clearing imports table disables static analysis - // clearing opcodes forces runtime manual mapping + // we don't mess up the chain + // we clear the imports table, and the raw opcodes + // clearing imports table disables static analysis + // clearing opcodes forces runtime manual mapping - // imports item are defined by mc.fixups.imports_format - // basic case is dyld_chained_import, 4 bytes + // imports item are defined by mc.fixups.imports_format + // basic case is dyld_chained_import, 4 bytes - start := mc.fixups.dataoff - size := mc.fixups.datasize - fixups := new(Fixups) - fixups.Deserialize(mc, mc.buf[start:start+size]) + start := mc.fixups.dataoff + size := mc.fixups.datasize + fixups := new(Fixups) + fixups.Deserialize(mc, mc.buf[start:start+size]) - start = mc.fixups.dataoff + fixups.imports_offset - size = fixups.imports_count * 4 - fmt.Printf("// Erase at=0x%x size=0x%x\n", start, size) - mc.file.WriteAt(make([]byte, size), int64(start)) + start = mc.fixups.dataoff + fixups.imports_offset + size = fixups.imports_count * 4 + fmt.Printf("// Erase at=0x%x size=0x%x\n", start, size) + mc.file.WriteAt(make([]byte, size), int64(start)) - // string reference are at the end of this section - start = mc.fixups.dataoff + fixups.symbols_offset - size = mc.fixups.Datasize() - fixups.symbols_offset - fmt.Printf("// Erase at=0x%x size=0x%x\n", start, size) - mc.file.WriteAt(make([]byte, size), int64(start)) + // string reference are at the end of this section + start = mc.fixups.dataoff + fixups.symbols_offset + size = mc.fixups.Datasize() - fixups.symbols_offset + fmt.Printf("// Erase at=0x%x size=0x%x\n", start, size) + mc.file.WriteAt(make([]byte, size), int64(start)) - fixups.imports_count = 0 - mc.file.WriteAt(fixups.Serialize(mc), int64(mc.fixups.dataoff)) + fixups.imports_count = 0 + mc.file.WriteAt(fixups.Serialize(mc), int64(mc.fixups.dataoff)) } func (mc *MachoContext) removeBindSymbolsLegacy() { - start := mc.dyldinfo.lazy_bind_off - size := mc.dyldinfo.lazy_bind_size - // set lazy opcodes to 0x00 == DO_BIND - // but no symbol state to bind - mc.file.WriteAt(make([]byte, size), int64(start)) + start := mc.dyldinfo.lazy_bind_off + size := mc.dyldinfo.lazy_bind_size + // set lazy opcodes to 0x00 == DO_BIND + // but no symbol state to bind + mc.file.WriteAt(make([]byte, size), int64(start)) } func (mc *MachoContext) ReworkForObjc() { - text_start := 0 - data_end := 0 - lc_main_offset := int64(0) + text_start := 0 + data_end := 0 + lc_main_offset := int64(0) - ptr := int64(0) + ptr := int64(0) if mc.Is64bit() { ptr, _ = mc.file.Seek(int64(Header_size_64), io.SeekStart) } else { @@ -366,218 +366,217 @@ func (mc *MachoContext) ReworkForObjc() { } for _, cmd := range mc.commands { - if cmd.Cmd() == LC_MAIN { - lc_main_offset = ptr + 8 - ptr += int64(cmd.Cmdsize()) - continue - } - if cmd.Cmd() != LC_SEGMENT_64 { - ptr += int64(cmd.Cmdsize()) + if cmd.Cmd() == LC_MAIN { + lc_main_offset = ptr + 8 + ptr += int64(cmd.Cmdsize()) continue } - var segment = cmd.(*Segment64) + if cmd.Cmd() != LC_SEGMENT_64 { + ptr += int64(cmd.Cmdsize()) + continue + } + var segment = cmd.(*Segment64) - if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__TEXT")) == 0 { - section_ptr := ptr + 0x40 + 8 - for _, section := range segment.Sections() { - if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__text")) == 0 { - text_start = int(section.Offset()) - } - if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__init_offsets")) == 0 { - // mc.file.WriteAt([]byte("__init_offsetx"), section_ptr) - // edit flags to not S_MOD_INIT_FUNC - mc.file.WriteAt([]byte{0, 0, 0, 0}, section_ptr + 0x40) - } - section_ptr += 16 * 2 + 8 * 2 + 4 * 8 - } - } - if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__DATA_CONST")) == 0 { - section_ptr := ptr + 0x40 + 8 - for _, section := range segment.Sections() { - if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_classlist")) == 0 { - mc.file.WriteAt([]byte("__objc_classbruh"), section_ptr) - } - if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_nlclslist")) == 0 { - mc.file.WriteAt([]byte("__objc_nlclsbruh"), section_ptr) - } - section_ptr += 16 * 2 + 8 * 2 + 4 * 8 - } - } - if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__DATA")) == 0 { - // end of __DATA segment, should have enough space for a pointer + if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__TEXT")) == 0 { + section_ptr := ptr + 0x40 + 8 + for _, section := range segment.Sections() { + if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__text")) == 0 { + text_start = int(section.Offset()) + } + if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__init_offsets")) == 0 { + // mc.file.WriteAt([]byte("__init_offsetx"), section_ptr) + // edit flags to not S_MOD_INIT_FUNC + mc.file.WriteAt([]byte{0, 0, 0, 0}, section_ptr+0x40) + } + section_ptr += 16*2 + 8*2 + 4*8 + } + } + if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__DATA_CONST")) == 0 { + section_ptr := ptr + 0x40 + 8 + for _, section := range segment.Sections() { + if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_classlist")) == 0 { + mc.file.WriteAt([]byte("__objc_classbruh"), section_ptr) + } + if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_nlclslist")) == 0 { + mc.file.WriteAt([]byte("__objc_nlclsbruh"), section_ptr) + } + section_ptr += 16*2 + 8*2 + 4*8 + } + } + if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__DATA")) == 0 { + // end of __DATA segment, should have enough space for a pointer - // __bss section is dynamically allocated at the end to or something, hmmge - // assume that it order correctly, which it should if compiled and not modified - sections := segment.Sections() - last := sections[len(sections) - 1] - data_end = int(last.Offset()) + int(last.Size()) + // __bss section is dynamically allocated at the end to or something, hmmge + // assume that it order correctly, which it should if compiled and not modified + sections := segment.Sections() + last := sections[len(sections)-1] + data_end = int(last.Offset()) + int(last.Size()) - if (last.Offset() == 0) { - before_last := sections[len(sections) - 2] - data_end += int(before_last.Offset()) + int(before_last.Size()) - } - } - ptr += int64(cmd.Cmdsize()) + if last.Offset() == 0 { + before_last := sections[len(sections)-2] + data_end += int(before_last.Offset()) + int(before_last.Size()) + } + } + ptr += int64(cmd.Cmdsize()) } - mc.file.Seek(0, io.SeekStart) + mc.file.Seek(0, io.SeekStart) - // dummy value past the end of __DATA segment (logical size), - // its physical size is still a page - // mc.file.WriteAt([]byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7}, int64(0x81d8)) + // dummy value past the end of __DATA segment (logical size), + // its physical size is still a page + // mc.file.WriteAt([]byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7}, int64(0x81d8)) - // we use 2 registers, x8 x9 - // stack values: - // [ return address, header, argc, argv, env, apple ] - // we need to store the return address, and parameters passed to main - // we also store our header address to not calculate many times + // we use 2 registers, x8 x9 + // stack values: + // [ return address, header, argc, argv, env, apple ] + // we need to store the return address, and parameters passed to main + // we also store our header address to not calculate many times - /* - adr x8, 0 - sub sp, sp, #0x30 - str x30, [sp] - movz x9, #0x3d68 ; offset at this point - sub x8, x8, x9 - str x8, [sp, #0x8] - str x0, [sp, #0x10] - str x1, [sp, #0x18] - str x2, [sp, #0x20] - str x3, [sp, #0x28] + /* + adr x8, 0 + sub sp, sp, #0x30 + str x30, [sp] + movz x9, #0x3d68 ; offset at this point + sub x8, x8, x9 + str x8, [sp, #0x8] + str x0, [sp, #0x10] + str x1, [sp, #0x18] + str x2, [sp, #0x20] + str x3, [sp, #0x28] - movz x9, #0x81d8 ; offset to end of __DATA - add x9, x8, x9 - ldr x9, [x9] - blr x9 - ldr x8, [sp, #0x8] - ldr x0, [sp, #0x10] - ldr x1, [sp, #0x18] - ldr x2, [sp, #0x20] - ldr x3, [sp, #0x28] - movz x9, #0x3e3c ; offset to original main - add x9, x8, x9 - blr x9 - ldr x30, [sp] - add sp, sp, #0x10 - ret - */ + movz x9, #0x81d8 ; offset to end of __DATA + add x9, x8, x9 + ldr x9, [x9] + blr x9 + ldr x8, [sp, #0x8] + ldr x0, [sp, #0x10] + ldr x1, [sp, #0x18] + ldr x2, [sp, #0x20] + ldr x3, [sp, #0x28] + movz x9, #0x3e3c ; offset to original main + add x9, x8, x9 + blr x9 + ldr x30, [sp] + add sp, sp, #0x10 + ret + */ - // TODO: fix to work with offset larger than 0xffff - shellcode := []uint32{ - 0x10000008, - 0xD100C3FF, - 0xF90003FE, - 0, // movz_shellcode_offset, - 0xCB090108, - 0xF90007E8, - 0xF9000BE0, - 0xF9000FE1, - 0xF90013E2, - 0xF90017E3, - 0, // movz_data_end_offset, - 0x8B090109, - 0xF9400129, - 0xD63F0120, - 0xF94007E8, - 0xF9400BE0, - 0xF9400FE1, - 0xF94013E2, - 0xF94017E3, - 0, // movz_main_offset, - 0x8B090109, - 0xD63F0120, - 0xF94003FE, - 0x910043FF, - 0xD65F03C0, - } + // TODO: fix to work with offset larger than 0xffff + shellcode := []uint32{ + 0x10000008, + 0xD100C3FF, + 0xF90003FE, + 0, // movz_shellcode_offset, + 0xCB090108, + 0xF90007E8, + 0xF9000BE0, + 0xF9000FE1, + 0xF90013E2, + 0xF90017E3, + 0, // movz_data_end_offset, + 0x8B090109, + 0xF9400129, + 0xD63F0120, + 0xF94007E8, + 0xF9400BE0, + 0xF9400FE1, + 0xF94013E2, + 0xF94017E3, + 0, // movz_main_offset, + 0x8B090109, + 0xD63F0120, + 0xF94003FE, + 0x910043FF, + 0xD65F03C0, + } - ins_size_byte := 4 - shellcode_offset := text_start - (ins_size_byte * len(shellcode)) - main_offset := int(mc.entryoff) + ins_size_byte := 4 + shellcode_offset := text_start - (ins_size_byte * len(shellcode)) + main_offset := int(mc.entryoff) - encode_movz := func(v int) uint32 { - return uint32(uint32(v)<<5 | uint32(0x694)<<21 | uint32(0x09)) - } + encode_movz := func(v int) uint32 { + return uint32(uint32(v)<<5 | uint32(0x694)<<21 | uint32(0x09)) + } - movz_shellcode_offset := encode_movz(shellcode_offset) - movz_main_offset := encode_movz(main_offset) - movz_data_end_offset := encode_movz(data_end) + movz_shellcode_offset := encode_movz(shellcode_offset) + movz_main_offset := encode_movz(main_offset) + movz_data_end_offset := encode_movz(data_end) - shellcode[3] = movz_shellcode_offset - shellcode[10] = movz_data_end_offset - shellcode[19] = movz_main_offset + shellcode[3] = movz_shellcode_offset + shellcode[10] = movz_data_end_offset + shellcode[19] = movz_main_offset - fmt.Printf("// shellcode_offset=%x\n", shellcode_offset) - fmt.Printf("// main_offset=%x\n", main_offset) - fmt.Printf("// data_end=%x\n", data_end) - fmt.Printf("// movz_shellcode_offset=%x\n", movz_shellcode_offset) - fmt.Printf("// movz_main_offset=%x\n", movz_main_offset) - fmt.Printf("// movz_data_end_offset=%x\n", movz_data_end_offset) - fmt.Printf("// lc_main_offset=%x\n", lc_main_offset) + fmt.Printf("// shellcode_offset=%x\n", shellcode_offset) + fmt.Printf("// main_offset=%x\n", main_offset) + fmt.Printf("// data_end=%x\n", data_end) + fmt.Printf("// movz_shellcode_offset=%x\n", movz_shellcode_offset) + fmt.Printf("// movz_main_offset=%x\n", movz_main_offset) + fmt.Printf("// movz_data_end_offset=%x\n", movz_data_end_offset) + fmt.Printf("// lc_main_offset=%x\n", lc_main_offset) - offset := int64(shellcode_offset) - { - // fix main to point to our newly created shellcode - bs := make([]byte, 8) - mc.byteorder.PutUint64(bs, uint64(offset)) - mc.file.WriteAt(bs, int64(lc_main_offset)) - } + offset := int64(shellcode_offset) + { + // fix main to point to our newly created shellcode + bs := make([]byte, 8) + mc.byteorder.PutUint64(bs, uint64(offset)) + mc.file.WriteAt(bs, int64(lc_main_offset)) + } - bs := make([]byte, 4) - for _, ins := range shellcode { - mc.byteorder.PutUint32(bs, ins) - mc.file.WriteAt(bs, offset) - offset += 4 - } + bs := make([]byte, 4) + for _, ins := range shellcode { + mc.byteorder.PutUint32(bs, ins) + mc.file.WriteAt(bs, offset) + offset += 4 + } } - func (mc *MachoContext) RemoveSymbolTable() { - // try to remove symtab and dysymtab - mc.removeSymtabCommand() - mc.removeDySymtabCommand() + // try to remove symtab and dysymtab + mc.removeSymtabCommand() + mc.removeDySymtabCommand() } func (mc *MachoContext) removeSymtabCommand() { - ptr := int64(0) + ptr := int64(0) if mc.Is64bit() { ptr, _ = mc.file.Seek(int64(Header_size_64), io.SeekStart) } else { ptr, _ = mc.file.Seek(int64(Header_size), io.SeekStart) } - var symtab_fix *Symtab + var symtab_fix *Symtab for _, cmd := range mc.commands { if cmd.Cmd() != LC_SYMTAB { - ptr += int64(cmd.Cmdsize()) + ptr += int64(cmd.Cmdsize()) continue } - var symtab = cmd.(*Symtab) - symtab_fix = symtab + var symtab = cmd.(*Symtab) + symtab_fix = symtab - // erase strings referenced - start := int64(symtab_fix.stroff) - size := symtab_fix.strsize - fmt.Printf("// Erase at=0x%x size=0x%x\n", start, size) - mc.file.WriteAt(make([]byte, size), start) + // erase strings referenced + start := int64(symtab_fix.stroff) + size := symtab_fix.strsize + fmt.Printf("// Erase at=0x%x size=0x%x\n", start, size) + mc.file.WriteAt(make([]byte, size), start) - // erase nlist64 symbol items - start = int64(symtab_fix.symoff) - size = symtab_fix.nsyms * 16 - fmt.Printf("// Erase at=0x%x size=0x%x\n", start, size) - mc.file.WriteAt(make([]byte, size), start) + // erase nlist64 symbol items + start = int64(symtab_fix.symoff) + size = symtab_fix.nsyms * 16 + fmt.Printf("// Erase at=0x%x size=0x%x\n", start, size) + mc.file.WriteAt(make([]byte, size), start) - symtab_fix.symoff = 0 - symtab_fix.nsyms = 0 - symtab_fix.stroff = 0 - symtab_fix.strsize = 0 + symtab_fix.symoff = 0 + symtab_fix.nsyms = 0 + symtab_fix.stroff = 0 + symtab_fix.strsize = 0 mc.file.Seek(ptr, io.SeekStart) mc.file.Write(symtab_fix.Serialize(mc)) - break + break } - mc.file.Seek(0, io.SeekStart) + mc.file.Seek(0, io.SeekStart) } func (mc *MachoContext) removeDySymtabCommand() { - ptr := int64(0) + ptr := int64(0) if mc.Is64bit() { ptr, _ = mc.file.Seek(int64(Header_size_64), io.SeekStart) } else { @@ -585,33 +584,33 @@ func (mc *MachoContext) removeDySymtabCommand() { } for _, cmd := range mc.commands { if cmd.Cmd() != LC_DYSYMTAB { - ptr += int64(cmd.Cmdsize()) + ptr += int64(cmd.Cmdsize()) continue } - var dysymtab = cmd.(*DySymtab) - dysymtab_fix := dysymtab - dysymtab_fix.indirectsymoff = 0 - dysymtab_fix.nindirectsyms = 0 + var dysymtab = cmd.(*DySymtab) + dysymtab_fix := dysymtab + dysymtab_fix.indirectsymoff = 0 + dysymtab_fix.nindirectsyms = 0 mc.file.Seek(ptr, io.SeekStart) mc.file.Write(dysymtab_fix.Serialize(mc)) } } func (mc *MachoContext) RemoveExportTrie() { - var start int64 - var size int - if mc.dyldinfo != nil { - // legacy export trie - start = int64(mc.dyldinfo.export_off) - size = int(mc.dyldinfo.export_size) - mc.file.WriteAt(make([]byte, size), start) - } else if mc.exports != nil { - // modern export trie - start = int64(mc.exports.dataoff) - size = int(mc.exports.datasize) - mc.file.WriteAt(make([]byte, size), start) - } else { - // no export trie (??) - // should never occur unless this binary is modified - } + var start int64 + var size int + if mc.dyldinfo != nil { + // legacy export trie + start = int64(mc.dyldinfo.export_off) + size = int(mc.dyldinfo.export_size) + mc.file.WriteAt(make([]byte, size), start) + } else if mc.exports != nil { + // modern export trie + start = int64(mc.exports.dataoff) + size = int(mc.exports.datasize) + mc.file.WriteAt(make([]byte, size), start) + } else { + // no export trie (??) + // should never occur unless this binary is modified + } } diff --git a/macho-go/pkg/ios/macho/load_commands.go b/macho-go/pkg/ios/macho/load_commands.go index da3fb5f..799520b 100644 --- a/macho-go/pkg/ios/macho/load_commands.go +++ b/macho-go/pkg/ios/macho/load_commands.go @@ -397,13 +397,13 @@ func (lcmd *DyldInfo) Deserialize(mc *MachoContext, buf []byte) { } type Fixups struct { - fixups_version uint32 - starts_offset uint32 - imports_offset uint32 - symbols_offset uint32 + fixups_version uint32 + starts_offset uint32 + imports_offset uint32 + symbols_offset uint32 imports_count uint32 imports_format uint32 - symbols_format uint32 + symbols_format uint32 } func (lcmd *Fixups) Serialize(mc *MachoContext) []byte { @@ -516,25 +516,25 @@ func (lcmd *Symtab) Deserialize(mc *MachoContext, buf []byte) { } type DySymtab struct { - c LoadCmd - ilocalsym uint32 - nlocalsym uint32 - iextdefsym uint32 - nextdefsym uint32 - iundefsym uint32 - nundefsym uint32 - tocoff uint32 - ntoc uint32 - modtaboff uint32 - nmodtab uint32 - extrefsymoff uint32 - nextrefsyms uint32 - indirectsymoff uint32 - nindirectsyms uint32 - extreloff uint32 - nextrel uint32 - localrefoff uint32 - nlocref uint32 + c LoadCmd + ilocalsym uint32 + nlocalsym uint32 + iextdefsym uint32 + nextdefsym uint32 + iundefsym uint32 + nundefsym uint32 + tocoff uint32 + ntoc uint32 + modtaboff uint32 + nmodtab uint32 + extrefsymoff uint32 + nextrefsyms uint32 + indirectsymoff uint32 + nindirectsyms uint32 + extreloff uint32 + nextrel uint32 + localrefoff uint32 + nlocref uint32 } func (lcmd *DySymtab) Cmd() uint32 { @@ -558,20 +558,20 @@ func (lcmd *DySymtab) Serialize(mc *MachoContext) []byte { binary.Write(buf, mc.byteorder, lcmd.nlocalsym) binary.Write(buf, mc.byteorder, lcmd.iextdefsym) binary.Write(buf, mc.byteorder, lcmd.nextdefsym) - binary.Write(buf, mc.byteorder, lcmd.iundefsym) - binary.Write(buf, mc.byteorder, lcmd.nundefsym) - binary.Write(buf, mc.byteorder, lcmd.tocoff) - binary.Write(buf, mc.byteorder, lcmd.ntoc) - binary.Write(buf, mc.byteorder, lcmd.modtaboff) - binary.Write(buf, mc.byteorder, lcmd.nmodtab) - binary.Write(buf, mc.byteorder, lcmd.extrefsymoff) - binary.Write(buf, mc.byteorder, lcmd.nextrefsyms) - binary.Write(buf, mc.byteorder, lcmd.indirectsymoff) - binary.Write(buf, mc.byteorder, lcmd.nindirectsyms) - binary.Write(buf, mc.byteorder, lcmd.extreloff) - binary.Write(buf, mc.byteorder, lcmd.nextrel) - binary.Write(buf, mc.byteorder, lcmd.localrefoff) - binary.Write(buf, mc.byteorder, lcmd.nlocref) + binary.Write(buf, mc.byteorder, lcmd.iundefsym) + binary.Write(buf, mc.byteorder, lcmd.nundefsym) + binary.Write(buf, mc.byteorder, lcmd.tocoff) + binary.Write(buf, mc.byteorder, lcmd.ntoc) + binary.Write(buf, mc.byteorder, lcmd.modtaboff) + binary.Write(buf, mc.byteorder, lcmd.nmodtab) + binary.Write(buf, mc.byteorder, lcmd.extrefsymoff) + binary.Write(buf, mc.byteorder, lcmd.nextrefsyms) + binary.Write(buf, mc.byteorder, lcmd.indirectsymoff) + binary.Write(buf, mc.byteorder, lcmd.nindirectsyms) + binary.Write(buf, mc.byteorder, lcmd.extreloff) + binary.Write(buf, mc.byteorder, lcmd.nextrel) + binary.Write(buf, mc.byteorder, lcmd.localrefoff) + binary.Write(buf, mc.byteorder, lcmd.nlocref) return buf.Bytes() } @@ -583,18 +583,18 @@ func (lcmd *DySymtab) Deserialize(mc *MachoContext, buf []byte) { binary.Read(r, mc.byteorder, &lcmd.nlocalsym) binary.Read(r, mc.byteorder, &lcmd.iextdefsym) binary.Read(r, mc.byteorder, &lcmd.nextdefsym) - binary.Read(r, mc.byteorder, &lcmd.iundefsym) - binary.Read(r, mc.byteorder, &lcmd.nundefsym) - binary.Read(r, mc.byteorder, &lcmd.tocoff) - binary.Read(r, mc.byteorder, &lcmd.ntoc) - binary.Read(r, mc.byteorder, &lcmd.modtaboff) - binary.Read(r, mc.byteorder, &lcmd.nmodtab) - binary.Read(r, mc.byteorder, &lcmd.extrefsymoff) - binary.Read(r, mc.byteorder, &lcmd.nextrefsyms) - binary.Read(r, mc.byteorder, &lcmd.indirectsymoff) - binary.Read(r, mc.byteorder, &lcmd.nindirectsyms) - binary.Read(r, mc.byteorder, &lcmd.extreloff) - binary.Read(r, mc.byteorder, &lcmd.nextrel) - binary.Read(r, mc.byteorder, &lcmd.localrefoff) - binary.Read(r, mc.byteorder, &lcmd.nlocref) + binary.Read(r, mc.byteorder, &lcmd.iundefsym) + binary.Read(r, mc.byteorder, &lcmd.nundefsym) + binary.Read(r, mc.byteorder, &lcmd.tocoff) + binary.Read(r, mc.byteorder, &lcmd.ntoc) + binary.Read(r, mc.byteorder, &lcmd.modtaboff) + binary.Read(r, mc.byteorder, &lcmd.nmodtab) + binary.Read(r, mc.byteorder, &lcmd.extrefsymoff) + binary.Read(r, mc.byteorder, &lcmd.nextrefsyms) + binary.Read(r, mc.byteorder, &lcmd.indirectsymoff) + binary.Read(r, mc.byteorder, &lcmd.nindirectsyms) + binary.Read(r, mc.byteorder, &lcmd.extreloff) + binary.Read(r, mc.byteorder, &lcmd.nextrel) + binary.Read(r, mc.byteorder, &lcmd.localrefoff) + binary.Read(r, mc.byteorder, &lcmd.nlocref) } diff --git a/macho-go/pkg/ios/macho/macho.go b/macho-go/pkg/ios/macho/macho.go index c8fc09b..091d30e 100644 --- a/macho-go/pkg/ios/macho/macho.go +++ b/macho-go/pkg/ios/macho/macho.go @@ -29,11 +29,11 @@ type MachoContext struct { linkedits []*LinkEdit segments []Segment symtab *Symtab - dysymtab *DySymtab + dysymtab *DySymtab - dyldinfo *DyldInfo - fixups *LinkEdit - exports *LinkEdit + dyldinfo *DyldInfo + fixups *LinkEdit + exports *LinkEdit } func (mc *MachoContext) FileSize() uint32 { @@ -235,12 +235,12 @@ func (mc *MachoContext) Parse(r *bufio.Reader) error { lcmd.Deserialize(mc, command_buf) mc.commands = append(mc.commands, lcmd) mc.linkedits = append(mc.linkedits, lcmd) - if lcmd.Cmd() == LC_DYLD_CHAINED_FIXUPS { - mc.fixups = lcmd - } - if lcmd.Cmd() == LC_DYLD_EXPORTS_TRIE { - mc.exports = lcmd - } + if lcmd.Cmd() == LC_DYLD_CHAINED_FIXUPS { + mc.fixups = lcmd + } + if lcmd.Cmd() == LC_DYLD_EXPORTS_TRIE { + mc.exports = lcmd + } break case LC_SYMTAB: @@ -248,12 +248,14 @@ func (mc *MachoContext) Parse(r *bufio.Reader) error { lcmd.Deserialize(mc, command_buf) mc.commands = append(mc.commands, lcmd) mc.symtab = lcmd + break case LC_DYSYMTAB: lcmd := new(DySymtab) lcmd.Deserialize(mc, command_buf) mc.commands = append(mc.commands, lcmd) mc.dysymtab = lcmd + break default: lcmd := new(LoadCmd) diff --git a/macho-go/pkg/ios/macho/symtab.go b/macho-go/pkg/ios/macho/symtab.go index 04e96b0..fd21758 100644 --- a/macho-go/pkg/ios/macho/symtab.go +++ b/macho-go/pkg/ios/macho/symtab.go @@ -82,7 +82,7 @@ func (mc *MachoContext) CollectSymbols() []*Symbol { binary.Read(symtab_buffer, mc.byteorder, &value64) } else { // always use value64 - var value32 uint32 + var value32 uint32 binary.Read(symtab_buffer, mc.byteorder, &value32) value64 = uint64(value32) }