format go code

This commit is contained in:
nganhkhoa 2023-06-26 15:28:16 +07:00
parent b8d8343835
commit 2eede8f9b2
12 changed files with 542 additions and 544 deletions

View File

@ -18,4 +18,3 @@ func (action *removeExports) withFat(ff *FatFile) error {
func NewRemoveExportsAction() *removeExports { func NewRemoveExportsAction() *removeExports {
return &removeExports{} return &removeExports{}
} }

View File

@ -20,4 +20,3 @@ func (action *removeImports) withFat(ff *FatFile) error {
func NewRemoveImportsAction() *removeImports { func NewRemoveImportsAction() *removeImports {
return &removeImports{} return &removeImports{}
} }

View File

@ -1,7 +1,7 @@
package action package action
import ( import (
"fmt" "fmt"
// log "github.com/sirupsen/logrus" // log "github.com/sirupsen/logrus"
. "ios-wrapper/internal/wrapper/ofile" . "ios-wrapper/internal/wrapper/ofile"
@ -11,52 +11,52 @@ import (
type saveImports struct{} type saveImports struct{}
func (action *saveImports) withMacho(mf *MachoFile) error { func (action *saveImports) withMacho(mf *MachoFile) error {
calculateHash := func(name string) uint32 { calculateHash := func(name string) uint32 {
var h uint32 = 0x811c9dc5 var h uint32 = 0x811c9dc5
for _, s := range name { for _, s := range name {
h ^= uint32(s) h ^= uint32(s)
h *= 0x01000193 h *= 0x01000193
} }
return h return h
} }
mc := mf.Context() mc := mf.Context()
symbols := []*protomodel.MachoInfo_BindSymbol{} 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("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("const char* lib_to_resolve = \"main\";")
fmt.Println("struct imported_symbol imported_table[] = {") fmt.Println("struct imported_symbol imported_table[] = {")
for _, symbol := range mc.CollectBindSymbols() { for _, symbol := range mc.CollectBindSymbols() {
if symbol.Type() != "lazy" { if symbol.Type() != "lazy" {
continue continue
} }
dylib_hash := calculateHash(symbol.Dylib()) dylib_hash := calculateHash(symbol.Dylib())
seg := mc.Segments()[symbol.Segment()] seg := mc.Segments()[symbol.Segment()]
var offset uint64 var offset uint64
if symbol.Address() >= seg.Vmaddr() { if symbol.Address() >= seg.Vmaddr() {
// this is virtual address // this is virtual address
offset = symbol.Address() - seg.Vmaddr() offset = symbol.Address() - seg.Vmaddr()
} else { } else {
// this is file address // this is file address
offset = symbol.Address() - seg.Fileoff() offset = symbol.Address() - seg.Fileoff()
} }
fmt.Printf("{\"%s\", \"%s\", 0x%x, 0x%x, 0x%x},\n", fmt.Printf("{\"%s\", \"%s\", 0x%x, 0x%x, 0x%x},\n",
symbol.Name(), symbol.Dylib(), dylib_hash, symbol.Segment(), offset); symbol.Name(), symbol.Dylib(), dylib_hash, symbol.Segment(), offset)
symbols = append(symbols, symbols = append(symbols,
&protomodel.MachoInfo_BindSymbol{ &protomodel.MachoInfo_BindSymbol{
Name: symbol.Name(), Name: symbol.Name(),
Libname: symbol.Dylib(), Libname: symbol.Dylib(),
Libhash: dylib_hash, Libhash: dylib_hash,
Segment: symbol.Segment(), Segment: symbol.Segment(),
Offset: offset, Offset: offset,
}) })
} }
fmt.Println("};") fmt.Println("};")
fmt.Printf("uint32_t nimports = %d;\n", len(symbols)); fmt.Printf("uint32_t nimports = %d;\n", len(symbols))
mf.Info().Symbols = symbols mf.Info().Symbols = symbols
return nil return nil
} }
@ -68,4 +68,3 @@ func (action *saveImports) withFat(ff *FatFile) error {
func NewSaveImportsAction() *saveImports { func NewSaveImportsAction() *saveImports {
return &saveImports{} return &saveImports{}
} }

View File

@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"strings" "strings"
"github.com/alecthomas/kong" "github.com/alecthomas/kong"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@ -65,10 +65,10 @@ func Cli() {
fat.FatJoin(arg.Macho, arg.Out) fat.FatJoin(arg.Macho, arg.Out)
return return
} else if command == "bcell2header" { } else if command == "bcell2header" {
arg := cli.BcellToHeader arg := cli.BcellToHeader
bcell2header(arg.Bcell, arg.Out) bcell2header(arg.Bcell, arg.Out)
return return
} }
var pc ProgramContext var pc ProgramContext
var ofile OFile = nil var ofile OFile = nil
@ -106,23 +106,23 @@ func Cli() {
pc.outfile = arg.Out pc.outfile = arg.Out
pc.bcellfile = arg.Bcell pc.bcellfile = arg.Bcell
case "pepe": case "pepe":
arg := cli.Pepe arg := cli.Pepe
ofile = NewOFile(arg.OFile) ofile = NewOFile(arg.OFile)
if arg.FullRemoval { if arg.FullRemoval {
pc.remove_exports = true pc.remove_exports = true
pc.remove_symbol_table = true pc.remove_symbol_table = true
pc.remove_imports = true pc.remove_imports = true
pc.remove_inits = true pc.remove_inits = true
pc.remove_codesign = true pc.remove_codesign = true
pc.remove_others = true pc.remove_others = true
} }
pc.remove_imports = arg.RemoveBindSymbols pc.remove_imports = arg.RemoveBindSymbols
pc.remove_codesign = arg.RemoveCodeSign pc.remove_codesign = arg.RemoveCodeSign
pc.remove_inits = arg.RemoveInitFunctions pc.remove_inits = arg.RemoveInitFunctions
pc.remove_others = arg.RemoveOthers pc.remove_others = arg.RemoveOthers
pc.remove_exports = arg.RemoveExports pc.remove_exports = arg.RemoveExports
pc.remove_symbol_table = arg.RemoveSymbolTable pc.remove_symbol_table = arg.RemoveSymbolTable
pc.dylib_to_add = arg.Dylibs pc.dylib_to_add = arg.Dylibs
pc.rpath_to_add = arg.Rpath pc.rpath_to_add = arg.Rpath
pc.outfile = arg.Out pc.outfile = arg.Out
@ -195,7 +195,7 @@ func displayBcell(bfile string) {
} }
fmt.Printf(" | Bind Symbols:\n") fmt.Printf(" | Bind Symbols:\n")
for _, symbol := range info.Symbols { 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(" | %s offset=0x%x segmentID=0x%x\n", symbol.Name, symbol.Offset, symbol.Segment)
fmt.Printf(" | from=%s\n", lib) fmt.Printf(" | from=%s\n", lib)
} }
@ -255,7 +255,7 @@ func bcell2header(bfile string, header string) {
} }
fmt.Printf(" | Bind Symbols:\n") fmt.Printf(" | Bind Symbols:\n")
for _, symbol := range info.Symbols { 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(" | %s offset=0x%x segmentID=0x%x\n", symbol.Name, symbol.Offset, symbol.Segment)
fmt.Printf(" | from=%s\n", lib) fmt.Printf(" | from=%s\n", lib)
} }

View File

@ -26,7 +26,7 @@ type RemoveCodesignArgument struct {
type RemoveImportsArgument struct { type RemoveImportsArgument struct {
Out string `short:"o" required name:"outfile" help:"Modified Mach-O/Fat binary output file" type:"path"` 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"` OFile string `arg help:"Path to Mach-O/Fat binary file" type:"existingfile"`
} }
@ -56,26 +56,26 @@ type LipoArgument struct {
} }
type PepeArgument struct { type PepeArgument struct {
Out string `short:"o" required name:"outfile" help:"Output file after transformation" type:"path"` 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"` 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"` OFile string `arg help:"Path to Mach-O/Fat binary file" type:"existingfile"`
Dylibs []string `short:"l" help:"Add more LC_DYLIB"` Dylibs []string `short:"l" help:"Add more LC_DYLIB"`
Rpath []string `short:"r" help:"Add more LC_RPATH"` Rpath []string `short:"r" help:"Add more LC_RPATH"`
RemoveCodeSign bool `default:"false" negatable:"" help:"Remove LC_CODE_SIGNATURE"` RemoveCodeSign bool `default:"false" negatable:"" help:"Remove LC_CODE_SIGNATURE"`
RemoveExports bool `default:"false" negatable:"" help:"Clear the export table/trie"` RemoveExports bool `default:"false" negatable:"" help:"Clear the export table/trie"`
RemoveSymbolTable bool `default:"true" negatable:"" help:"Remove LC_SYMTAB and LC_DYSYMTAB"` 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, ..."` 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"` 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"` 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"` 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"` 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"` RebuildLinkEdit bool `default:"false" negatable:"" help:"(TODO) Rebuild the LINKEDIT section"`
FullRemoval bool `default:"false" help:"Apply every removal possible"` FullRemoval bool `default:"false" help:"Apply every removal possible"`
} }
type BcellToHeaderArgument struct { type BcellToHeaderArgument struct {
Out string `short:"o" required name:"outfile" help:"Header file name to output to" type:"path"` 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"` Bcell string `short:"b" required help:"Input bcell.dat file" type:"existingfile"`
} }
type Argument struct { type Argument struct {
@ -89,13 +89,13 @@ type Argument struct {
Addr2Line Addr2LineArgument `cmd name:"addr2line" help:"Resolve crash address from DWARF file"` Addr2Line Addr2LineArgument `cmd name:"addr2line" help:"Resolve crash address from DWARF file"`
Lipo LipoArgument `cmd help:"split Fat binary or join Mach-O binares"` Lipo LipoArgument `cmd help:"split Fat binary or join Mach-O binares"`
Pepe PepeArgument `cmd help:"custom command"` Pepe PepeArgument `cmd help:"custom command"`
BcellToHeader BcellToHeaderArgument `cmd name:"bcell2header" help:"Build C header file from bcell file"` BcellToHeader BcellToHeaderArgument `cmd name:"bcell2header" help:"Build C header file from bcell file"`
AddSection struct { AddSection struct {
Out string `short:"o" required name:"outfile" help:"Output file after transformation"` 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"` 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"` OFile string `arg help:"Path to Mach-O/Fat binary file" type:"existingfile"`
Segment string `required help:"Segment name"` Segment string `required help:"Segment name"`
Section string `required help:"Section name"` Section string `required help:"Section name"`
Size int `required help:"Size of segment/section"` 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"` } `cmd:"" default:"false" help:"(TODO) Add a new segment with 1 section, segment starts at the end of last segment"`
} }

View File

@ -35,16 +35,16 @@ func (printer *InfoPrinter) Print() {
} }
symbols := mc.CollectBindSymbols() symbols := mc.CollectBindSymbols()
for _, sym := range symbols { for _, sym := range symbols {
fmt.Printf( fmt.Printf(
"%s (%s)\n\tStub=0x%x Address=0x%x\n\tDylib=%s\n", "%s (%s)\n\tStub=0x%x Address=0x%x\n\tDylib=%s\n",
sym.Name(), sym.Name(),
sym.Type(), sym.Type(),
sym.Stub(), sym.Stub(),
sym.Address(), sym.Address(),
sym.Dylib(), sym.Dylib(),
) )
} }
fmt.Println("======") fmt.Println("======")
} }

View File

@ -38,12 +38,12 @@ func (uc *UserConfig) Protomodel() *protomodel.Config {
} }
type ProgramContext struct { type ProgramContext struct {
remove_inits bool remove_inits bool
remove_codesign bool remove_codesign bool
remove_imports bool remove_imports bool
remove_others bool remove_others bool
remove_exports bool remove_exports bool
remove_symbol_table bool remove_symbol_table bool
dylib_to_add []string dylib_to_add []string
rpath_to_add []string rpath_to_add []string
@ -96,18 +96,18 @@ func (pc *ProgramContext) Process(ofile OFile) {
} }
if pc.remove_imports { if pc.remove_imports {
pc.AddAction(NewSaveImportsAction()) pc.AddAction(NewSaveImportsAction())
pc.AddAction(NewRemoveImportsAction()) pc.AddAction(NewRemoveImportsAction())
} }
if pc.remove_symbol_table { if pc.remove_symbol_table {
pc.AddAction(NewRemoveClassicSymbolAction()) pc.AddAction(NewRemoveClassicSymbolAction())
} }
if pc.remove_exports { if pc.remove_exports {
pc.AddAction(NewRemoveExportsAction()) pc.AddAction(NewRemoveExportsAction())
} }
ExperimentalFeature("Remove Unnecessary Info", func() { ExperimentalFeature("Remove Unnecessary Info", func() {
if pc.remove_others { if pc.remove_others {
pc.AddAction(NewRemoveUnnecessaryInfoAction()) pc.AddAction(NewRemoveUnnecessaryInfoAction())
} }
}) })
pc.AddAction(NewAddRpathAction(pc.rpath_to_add)) pc.AddAction(NewAddRpathAction(pc.rpath_to_add))
pc.AddAction(NewAddDylibAction(pc.dylib_to_add)) pc.AddAction(NewAddDylibAction(pc.dylib_to_add))

View File

@ -4,9 +4,9 @@ import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"unsafe" "unsafe"
// "bufio" // "bufio"
"io" "io"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@ -19,7 +19,7 @@ import "C"
type ImportSymbol struct { type ImportSymbol struct {
name string name string
typ string typ string
dylib string dylib string
segment uint32 segment uint32
segment_offset uint32 segment_offset uint32
@ -30,7 +30,7 @@ type ImportSymbol struct {
pnum uint32 pnum uint32
stub uint64 stub uint64
next int // only for LC_DYLD_CHAINED_FIXUPS next int // only for LC_DYLD_CHAINED_FIXUPS
} }
func (sym *ImportSymbol) Name() string { func (sym *ImportSymbol) Name() string {
@ -70,140 +70,140 @@ func (mc *MachoContext) CollectBindSymbols() []*ImportSymbol {
} }
func (mc *MachoContext) findSegmentIndexAt(address uint64) int { func (mc *MachoContext) findSegmentIndexAt(address uint64) int {
for i, segment := range mc.Segments() { for i, segment := range mc.Segments() {
if segment.Fileoff() <= address && segment.Fileoff() + segment.Filesize() > address { if segment.Fileoff() <= address && segment.Fileoff()+segment.Filesize() > address {
return i return i
} }
} }
return -1 return -1
} }
// New convention using LC_DYLD_CHAINED_FIXUPS // New convention using LC_DYLD_CHAINED_FIXUPS
func (mc *MachoContext) CollectBindSymbolsModern() []*ImportSymbol { func (mc *MachoContext) CollectBindSymbolsModern() []*ImportSymbol {
start := mc.fixups.dataoff start := mc.fixups.dataoff
size := mc.fixups.datasize size := mc.fixups.datasize
buf := mc.buf[start:start+size] buf := mc.buf[start : start+size]
// all pointers used are based from this **buf** // all pointers used are based from this **buf**
// until buf is freed, all pointers are valid // until buf is freed, all pointers are valid
// remember to copy before moving out // remember to copy before moving out
header := (*C.uchar)(unsafe.Pointer(&buf[0])) header := (*C.uchar)(unsafe.Pointer(&buf[0]))
imports_table := C.GetImportsTable(header); imports_table := C.GetImportsTable(header)
// for i := 0; i < int(imports_table.size); i++ { // for i := 0; i < int(imports_table.size); i++ {
// s := C.GetImportsAt(&imports_table, C.int(i)) // s := C.GetImportsAt(&imports_table, C.int(i))
// name := C.GoString(s.name) // name := C.GoString(s.name)
// symbol.dylib := string(mc.dylibs[int(s.lib_ordinal)-1].name[:]) // symbol.dylib := string(mc.dylibs[int(s.lib_ordinal)-1].name[:])
// symbol_table = append(symbol_table, symbol) // symbol_table = append(symbol_table, symbol)
// fmt.Printf("id=%d lib=%s name=%s\n", i, dylib, name) // fmt.Printf("id=%d lib=%s name=%s\n", i, dylib, name)
// } // }
var syms []*ImportSymbol var syms []*ImportSymbol
var sym ImportSymbol var sym ImportSymbol
segment_i := 0 segment_i := 0
for { for {
var fix C.struct_SegmentFix var fix C.struct_SegmentFix
fix_ptr := (*C.struct_SegmentFix)(unsafe.Pointer(&fix)) fix_ptr := (*C.struct_SegmentFix)(unsafe.Pointer(&fix))
status := int(C.GetSegmentFixAt(header, C.uint(segment_i), fix_ptr)) status := int(C.GetSegmentFixAt(header, C.uint(segment_i), fix_ptr))
segment_i += 1 segment_i += 1
if status == 2 { if status == 2 {
break; break
} }
if status == 3 { if status == 3 {
continue continue
} }
// fmt.Printf("segment=%x format=%x page_count=%d\n", fix.segment, fix.format, fix.page_count) // fmt.Printf("segment=%x format=%x page_count=%d\n", fix.segment, fix.format, fix.page_count)
// fmt.Printf("pages=%x\n", fix.pages) // fmt.Printf("pages=%x\n", fix.pages)
pages := ([]C.ushort)(unsafe.Slice(fix.pages, fix.page_count)) pages := ([]C.ushort)(unsafe.Slice(fix.pages, fix.page_count))
for page_i := 0; page_i < int(fix.page_count); page_i++ { for page_i := 0; page_i < int(fix.page_count); page_i++ {
// fmt.Printf(" page offset=%x\n", pages[page_i]) // fmt.Printf(" page offset=%x\n", pages[page_i])
address := int64(fix.segment) + int64(pages[page_i]) address := int64(fix.segment) + int64(pages[page_i])
mc.file.Seek(address, io.SeekStart) mc.file.Seek(address, io.SeekStart)
code := make([]byte, 8) code := make([]byte, 8)
for { for {
mc.file.Read(code) mc.file.Read(code)
v := mc.byteorder.Uint64(code) v := mc.byteorder.Uint64(code)
var bind C.int var bind C.int
var ret1 C.ulonglong var ret1 C.ulonglong
var ret2 C.ulonglong var ret2 C.ulonglong
next := C.ParseFixValue(C.int(fix.format), C.ulonglong(v), next := C.ParseFixValue(C.int(fix.format), C.ulonglong(v),
&bind, &ret1, &ret2) &bind, &ret1, &ret2)
if bind == 1 { if bind == 1 {
s := C.GetImportsAt(&imports_table, C.int(ret1)) s := C.GetImportsAt(&imports_table, C.int(ret1))
name := C.GoString(s.name) name := C.GoString(s.name)
dylib := string(mc.dylibs[int(s.lib_ordinal)-1].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.address = uint64(address)
sym.name = name sym.name = name
sym.dylib = dylib sym.dylib = dylib
sym.typ = "lazy" sym.typ = "lazy"
sym.segment = uint32(mc.findSegmentIndexAt(uint64(address))) sym.segment = uint32(mc.findSegmentIndexAt(uint64(address)))
sym.file_address = uint64(address) sym.file_address = uint64(address)
sym.next = int(next) sym.next = int(next)
new_sym := sym new_sym := sym
syms = append(syms, &new_sym) syms = append(syms, &new_sym)
} else { } else {
fmt.Printf("// 0x%x rebase=%d target=0x%x high8=0x%x\n", address, bind, ret1, ret2) fmt.Printf("// 0x%x rebase=%d target=0x%x high8=0x%x\n", address, bind, ret1, ret2)
} }
if int(next) == 0 { if int(next) == 0 {
break break
} }
// because the pointer move up 8 bytes already so we minus 8 // because the pointer move up 8 bytes already so we minus 8
address += int64(next * 4) address += int64(next * 4)
mc.file.Seek(int64(next * 4) - 8, io.SeekCurrent) mc.file.Seek(int64(next*4)-8, io.SeekCurrent)
} }
mc.file.Seek(0, io.SeekStart) mc.file.Seek(0, io.SeekStart)
} }
} }
return syms return syms
} }
// Old convention using LC_DYLD_INFO_ONLY section and bytecode runner // Old convention using LC_DYLD_INFO_ONLY section and bytecode runner
func (mc *MachoContext) CollectBindSymbolsLegacy() []*ImportSymbol { func (mc *MachoContext) CollectBindSymbolsLegacy() []*ImportSymbol {
noLazy := (func() []*ImportSymbol { noLazy := (func() []*ImportSymbol {
start := mc.dyldinfo.bind_off start := mc.dyldinfo.bind_off
size := mc.dyldinfo.bind_size size := mc.dyldinfo.bind_size
end := start + size end := start + size
buf := bytes.NewBuffer(mc.buf[start:end]) buf := bytes.NewBuffer(mc.buf[start:end])
return mc.readBindStream(buf, "no lazy") return mc.readBindStream(buf, "no lazy")
})() })()
lazy := (func() []*ImportSymbol { lazy := (func() []*ImportSymbol {
start := mc.dyldinfo.lazy_bind_off start := mc.dyldinfo.lazy_bind_off
size := mc.dyldinfo.lazy_bind_size size := mc.dyldinfo.lazy_bind_size
end := start + size end := start + size
buf := bytes.NewBuffer(mc.buf[start:end]) buf := bytes.NewBuffer(mc.buf[start:end])
return mc.readBindStream(buf, "lazy") return mc.readBindStream(buf, "lazy")
})() })()
weak := (func() []*ImportSymbol { weak := (func() []*ImportSymbol {
start := mc.dyldinfo.weak_bind_off start := mc.dyldinfo.weak_bind_off
size := mc.dyldinfo.weak_bind_size size := mc.dyldinfo.weak_bind_size
end := start + size end := start + size
buf := bytes.NewBuffer(mc.buf[start:end]) buf := bytes.NewBuffer(mc.buf[start:end])
return mc.readBindStream(buf, "weak") return mc.readBindStream(buf, "weak")
})() })()
var symbols []*ImportSymbol var symbols []*ImportSymbol
symbols = append(symbols, noLazy...) symbols = append(symbols, noLazy...)
symbols = append(symbols, lazy...) symbols = append(symbols, lazy...)
symbols = append(symbols, weak...) symbols = append(symbols, weak...)
return symbols return symbols
} }
func (mc *MachoContext) readBindStream(buf *bytes.Buffer, typ string) []*ImportSymbol { func (mc *MachoContext) readBindStream(buf *bytes.Buffer, typ string) []*ImportSymbol {
size := buf.Len() size := buf.Len()
if size == 0 { if size == 0 {
return []*ImportSymbol{} return []*ImportSymbol{}
} }
@ -237,7 +237,7 @@ func (mc *MachoContext) readBindStream(buf *bytes.Buffer, typ string) []*ImportS
case BIND_OPCODE_DO_BIND: case BIND_OPCODE_DO_BIND:
if sym.name != "" { if sym.name != "" {
new_sym := sym new_sym := sym
new_sym.typ = typ new_sym.typ = typ
syms = append(syms, &new_sym) syms = append(syms, &new_sym)
// fmt.Printf("Offset 0x%x: Symbol %+v\n", symoffset, 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, "symbol": sym.name,
}).Trace("Bind") }).Trace("Bind")
sym.name = "" sym.name = ""
sym.address += 8 sym.address += 8
} }
offset += 1 offset += 1
break break
@ -275,9 +275,9 @@ func (mc *MachoContext) readBindStream(buf *bytes.Buffer, typ string) []*ImportS
case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
sym.name, _ = buf.ReadString(0) sym.name, _ = buf.ReadString(0)
// ReadString input the 0x00 byte to buffer // ReadString input the 0x00 byte to buffer
// while we are string so we can remove that // while we are string so we can remove that
sym.name = sym.name[:len(sym.name)-1] sym.name = sym.name[:len(sym.name)-1]
offset += uint(len(sym.name)) offset += uint(len(sym.name))
break break
@ -301,12 +301,12 @@ func (mc *MachoContext) readBindStream(buf *bytes.Buffer, typ string) []*ImportS
offset += br offset += br
break break
case BIND_OPCODE_SET_TYPE_IMM: case BIND_OPCODE_SET_TYPE_IMM:
fmt.Println("// symbol type", imm) fmt.Println("// symbol type", imm)
break break
default: default:
fmt.Println("BIND OPCODE NOT SUPPORTED", op, imm) fmt.Println("BIND OPCODE NOT SUPPORTED", op, imm)
break break
} }
} }

View File

@ -1,11 +1,11 @@
package macho package macho
import ( import (
"bytes"
"fmt" "fmt"
"io" "io"
"math/rand" "math/rand"
"time" "time"
"bytes"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@ -272,93 +272,93 @@ func (mc *MachoContext) UpdateHeaderRemoveLcmd(size uint32) {
func (mc *MachoContext) RemoveBindSymbols() { func (mc *MachoContext) RemoveBindSymbols() {
if !mc.WriteEnabled() { if !mc.WriteEnabled() {
return return
} }
rand.Seed(time.Now().UnixNano()) rand.Seed(time.Now().UnixNano())
if mc.dyldinfo == nil { if mc.dyldinfo == nil {
mc.removeBindSymbolsModern() mc.removeBindSymbolsModern()
} else { } else {
mc.removeBindSymbolsLegacy() mc.removeBindSymbolsLegacy()
} }
mc.ReworkForObjc() mc.ReworkForObjc()
// due to some limitations when design this tool // due to some limitations when design this tool
// we write the c code to stdout lol // we write the c code to stdout lol
for _, symbol := range mc.CollectBindSymbols() { for _, symbol := range mc.CollectBindSymbols() {
if symbol.Type() != "lazy" { if symbol.Type() != "lazy" {
continue continue
} }
if mc.dyldinfo != nil { if mc.dyldinfo != nil {
// for legacy resolve the opcodes can be rewritten as 0x00 // for legacy resolve the opcodes can be rewritten as 0x00
mc.file.WriteAt(make([]byte, 8), int64(symbol.file_address)) mc.file.WriteAt(make([]byte, 8), int64(symbol.file_address))
} else { } else {
// for modern resolve the opcodes must not be rewritten as 0x00 // for modern resolve the opcodes must not be rewritten as 0x00
// because it contains 2 types of opcodes, BIND and REBASE // because it contains 2 types of opcodes, BIND and REBASE
// we only fix BIND and leave REBASE intact // we only fix BIND and leave REBASE intact
// However, each opcodes has a *next* field to the next opcode // However, each opcodes has a *next* field to the next opcode
// So if we want to leave the header intact (contains pointers, size) // So if we want to leave the header intact (contains pointers, size)
// We should rewrite this as REBASE opcode (so no symbol lookup happens) // We should rewrite this as REBASE opcode (so no symbol lookup happens)
// and it can continue // and it can continue
// we can write random values, because the loader just do // we can write random values, because the loader just do
// (high8 << 56 | target) - mach_header // (high8 << 56 | target) - mach_header
// or something, so no symbol lookup and no error at runtime // or something, so no symbol lookup and no error at runtime
target := rand.Int() target := rand.Int()
high8 := rand.Int() high8 := rand.Int()
value := C.MakeRebaseFixupOpcode(C.int(symbol.next), C.ulonglong(target), C.ulonglong(high8)) value := C.MakeRebaseFixupOpcode(C.int(symbol.next), C.ulonglong(target), C.ulonglong(high8))
v := make([]byte, 8) v := make([]byte, 8)
mc.byteorder.PutUint64(v, uint64(value)) mc.byteorder.PutUint64(v, uint64(value))
mc.file.WriteAt(v, int64(symbol.file_address)) mc.file.WriteAt(v, int64(symbol.file_address))
} }
} }
} }
func (mc *MachoContext) removeBindSymbolsModern() { func (mc *MachoContext) removeBindSymbolsModern() {
// we don't mess up the chain // we don't mess up the chain
// we clear the imports table, and the raw opcodes // we clear the imports table, and the raw opcodes
// clearing imports table disables static analysis // clearing imports table disables static analysis
// clearing opcodes forces runtime manual mapping // clearing opcodes forces runtime manual mapping
// imports item are defined by mc.fixups.imports_format // imports item are defined by mc.fixups.imports_format
// basic case is dyld_chained_import, 4 bytes // basic case is dyld_chained_import, 4 bytes
start := mc.fixups.dataoff start := mc.fixups.dataoff
size := mc.fixups.datasize size := mc.fixups.datasize
fixups := new(Fixups) fixups := new(Fixups)
fixups.Deserialize(mc, mc.buf[start:start+size]) fixups.Deserialize(mc, mc.buf[start:start+size])
start = mc.fixups.dataoff + fixups.imports_offset start = mc.fixups.dataoff + fixups.imports_offset
size = fixups.imports_count * 4 size = fixups.imports_count * 4
fmt.Printf("// Erase at=0x%x size=0x%x\n", start, size) fmt.Printf("// Erase at=0x%x size=0x%x\n", start, size)
mc.file.WriteAt(make([]byte, size), int64(start)) mc.file.WriteAt(make([]byte, size), int64(start))
// string reference are at the end of this section // string reference are at the end of this section
start = mc.fixups.dataoff + fixups.symbols_offset start = mc.fixups.dataoff + fixups.symbols_offset
size = mc.fixups.Datasize() - fixups.symbols_offset size = mc.fixups.Datasize() - fixups.symbols_offset
fmt.Printf("// Erase at=0x%x size=0x%x\n", start, size) fmt.Printf("// Erase at=0x%x size=0x%x\n", start, size)
mc.file.WriteAt(make([]byte, size), int64(start)) mc.file.WriteAt(make([]byte, size), int64(start))
fixups.imports_count = 0 fixups.imports_count = 0
mc.file.WriteAt(fixups.Serialize(mc), int64(mc.fixups.dataoff)) mc.file.WriteAt(fixups.Serialize(mc), int64(mc.fixups.dataoff))
} }
func (mc *MachoContext) removeBindSymbolsLegacy() { func (mc *MachoContext) removeBindSymbolsLegacy() {
start := mc.dyldinfo.lazy_bind_off start := mc.dyldinfo.lazy_bind_off
size := mc.dyldinfo.lazy_bind_size size := mc.dyldinfo.lazy_bind_size
// set lazy opcodes to 0x00 == DO_BIND // set lazy opcodes to 0x00 == DO_BIND
// but no symbol state to bind // but no symbol state to bind
mc.file.WriteAt(make([]byte, size), int64(start)) mc.file.WriteAt(make([]byte, size), int64(start))
} }
func (mc *MachoContext) ReworkForObjc() { func (mc *MachoContext) ReworkForObjc() {
text_start := 0 text_start := 0
data_end := 0 data_end := 0
lc_main_offset := int64(0) lc_main_offset := int64(0)
ptr := int64(0) ptr := int64(0)
if mc.Is64bit() { if mc.Is64bit() {
ptr, _ = mc.file.Seek(int64(Header_size_64), io.SeekStart) ptr, _ = mc.file.Seek(int64(Header_size_64), io.SeekStart)
} else { } else {
@ -366,218 +366,217 @@ func (mc *MachoContext) ReworkForObjc() {
} }
for _, cmd := range mc.commands { for _, cmd := range mc.commands {
if cmd.Cmd() == LC_MAIN { if cmd.Cmd() == LC_MAIN {
lc_main_offset = ptr + 8 lc_main_offset = ptr + 8
ptr += int64(cmd.Cmdsize()) ptr += int64(cmd.Cmdsize())
continue
}
if cmd.Cmd() != LC_SEGMENT_64 {
ptr += int64(cmd.Cmdsize())
continue 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 { if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__TEXT")) == 0 {
section_ptr := ptr + 0x40 + 8 section_ptr := ptr + 0x40 + 8
for _, section := range segment.Sections() { for _, section := range segment.Sections() {
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__text")) == 0 { if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__text")) == 0 {
text_start = int(section.Offset()) text_start = int(section.Offset())
} }
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__init_offsets")) == 0 { if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__init_offsets")) == 0 {
// mc.file.WriteAt([]byte("__init_offsetx"), section_ptr) // mc.file.WriteAt([]byte("__init_offsetx"), section_ptr)
// edit flags to not S_MOD_INIT_FUNC // edit flags to not S_MOD_INIT_FUNC
mc.file.WriteAt([]byte{0, 0, 0, 0}, section_ptr + 0x40) mc.file.WriteAt([]byte{0, 0, 0, 0}, section_ptr+0x40)
} }
section_ptr += 16 * 2 + 8 * 2 + 4 * 8 section_ptr += 16*2 + 8*2 + 4*8
} }
} }
if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__DATA_CONST")) == 0 { if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__DATA_CONST")) == 0 {
section_ptr := ptr + 0x40 + 8 section_ptr := ptr + 0x40 + 8
for _, section := range segment.Sections() { for _, section := range segment.Sections() {
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_classlist")) == 0 { if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_classlist")) == 0 {
mc.file.WriteAt([]byte("__objc_classbruh"), section_ptr) mc.file.WriteAt([]byte("__objc_classbruh"), section_ptr)
} }
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_nlclslist")) == 0 { if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_nlclslist")) == 0 {
mc.file.WriteAt([]byte("__objc_nlclsbruh"), section_ptr) mc.file.WriteAt([]byte("__objc_nlclsbruh"), section_ptr)
} }
section_ptr += 16 * 2 + 8 * 2 + 4 * 8 section_ptr += 16*2 + 8*2 + 4*8
} }
} }
if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__DATA")) == 0 { if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__DATA")) == 0 {
// end of __DATA segment, should have enough space for a pointer // end of __DATA segment, should have enough space for a pointer
// __bss section is dynamically allocated at the end to or something, hmmge // __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 // assume that it order correctly, which it should if compiled and not modified
sections := segment.Sections() sections := segment.Sections()
last := sections[len(sections) - 1] last := sections[len(sections)-1]
data_end = int(last.Offset()) + int(last.Size()) data_end = int(last.Offset()) + int(last.Size())
if (last.Offset() == 0) { if last.Offset() == 0 {
before_last := sections[len(sections) - 2] before_last := sections[len(sections)-2]
data_end += int(before_last.Offset()) + int(before_last.Size()) data_end += int(before_last.Offset()) + int(before_last.Size())
} }
} }
ptr += int64(cmd.Cmdsize()) 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), // dummy value past the end of __DATA segment (logical size),
// its physical size is still a page // its physical size is still a page
// mc.file.WriteAt([]byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7}, int64(0x81d8)) // mc.file.WriteAt([]byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7}, int64(0x81d8))
// we use 2 registers, x8 x9 // we use 2 registers, x8 x9
// stack values: // stack values:
// [ return address, header, argc, argv, env, apple ] // [ return address, header, argc, argv, env, apple ]
// we need to store the return address, and parameters passed to main // we need to store the return address, and parameters passed to main
// we also store our header address to not calculate many times // we also store our header address to not calculate many times
/* /*
adr x8, 0 adr x8, 0
sub sp, sp, #0x30 sub sp, sp, #0x30
str x30, [sp] str x30, [sp]
movz x9, #0x3d68 ; offset at this point movz x9, #0x3d68 ; offset at this point
sub x8, x8, x9 sub x8, x8, x9
str x8, [sp, #0x8] str x8, [sp, #0x8]
str x0, [sp, #0x10] str x0, [sp, #0x10]
str x1, [sp, #0x18] str x1, [sp, #0x18]
str x2, [sp, #0x20] str x2, [sp, #0x20]
str x3, [sp, #0x28] str x3, [sp, #0x28]
movz x9, #0x81d8 ; offset to end of __DATA movz x9, #0x81d8 ; offset to end of __DATA
add x9, x8, x9 add x9, x8, x9
ldr x9, [x9] ldr x9, [x9]
blr x9 blr x9
ldr x8, [sp, #0x8] ldr x8, [sp, #0x8]
ldr x0, [sp, #0x10] ldr x0, [sp, #0x10]
ldr x1, [sp, #0x18] ldr x1, [sp, #0x18]
ldr x2, [sp, #0x20] ldr x2, [sp, #0x20]
ldr x3, [sp, #0x28] ldr x3, [sp, #0x28]
movz x9, #0x3e3c ; offset to original main movz x9, #0x3e3c ; offset to original main
add x9, x8, x9 add x9, x8, x9
blr x9 blr x9
ldr x30, [sp] ldr x30, [sp]
add sp, sp, #0x10 add sp, sp, #0x10
ret ret
*/ */
// TODO: fix to work with offset larger than 0xffff // TODO: fix to work with offset larger than 0xffff
shellcode := []uint32{ shellcode := []uint32{
0x10000008, 0x10000008,
0xD100C3FF, 0xD100C3FF,
0xF90003FE, 0xF90003FE,
0, // movz_shellcode_offset, 0, // movz_shellcode_offset,
0xCB090108, 0xCB090108,
0xF90007E8, 0xF90007E8,
0xF9000BE0, 0xF9000BE0,
0xF9000FE1, 0xF9000FE1,
0xF90013E2, 0xF90013E2,
0xF90017E3, 0xF90017E3,
0, // movz_data_end_offset, 0, // movz_data_end_offset,
0x8B090109, 0x8B090109,
0xF9400129, 0xF9400129,
0xD63F0120, 0xD63F0120,
0xF94007E8, 0xF94007E8,
0xF9400BE0, 0xF9400BE0,
0xF9400FE1, 0xF9400FE1,
0xF94013E2, 0xF94013E2,
0xF94017E3, 0xF94017E3,
0, // movz_main_offset, 0, // movz_main_offset,
0x8B090109, 0x8B090109,
0xD63F0120, 0xD63F0120,
0xF94003FE, 0xF94003FE,
0x910043FF, 0x910043FF,
0xD65F03C0, 0xD65F03C0,
} }
ins_size_byte := 4 ins_size_byte := 4
shellcode_offset := text_start - (ins_size_byte * len(shellcode)) shellcode_offset := text_start - (ins_size_byte * len(shellcode))
main_offset := int(mc.entryoff) main_offset := int(mc.entryoff)
encode_movz := func(v int) uint32 { encode_movz := func(v int) uint32 {
return uint32(uint32(v)<<5 | uint32(0x694)<<21 | uint32(0x09)) return uint32(uint32(v)<<5 | uint32(0x694)<<21 | uint32(0x09))
} }
movz_shellcode_offset := encode_movz(shellcode_offset) movz_shellcode_offset := encode_movz(shellcode_offset)
movz_main_offset := encode_movz(main_offset) movz_main_offset := encode_movz(main_offset)
movz_data_end_offset := encode_movz(data_end) movz_data_end_offset := encode_movz(data_end)
shellcode[3] = movz_shellcode_offset shellcode[3] = movz_shellcode_offset
shellcode[10] = movz_data_end_offset shellcode[10] = movz_data_end_offset
shellcode[19] = movz_main_offset shellcode[19] = movz_main_offset
fmt.Printf("// shellcode_offset=%x\n", shellcode_offset) fmt.Printf("// shellcode_offset=%x\n", shellcode_offset)
fmt.Printf("// main_offset=%x\n", main_offset) fmt.Printf("// main_offset=%x\n", main_offset)
fmt.Printf("// data_end=%x\n", data_end) fmt.Printf("// data_end=%x\n", data_end)
fmt.Printf("// movz_shellcode_offset=%x\n", movz_shellcode_offset) fmt.Printf("// movz_shellcode_offset=%x\n", movz_shellcode_offset)
fmt.Printf("// movz_main_offset=%x\n", movz_main_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("// movz_data_end_offset=%x\n", movz_data_end_offset)
fmt.Printf("// lc_main_offset=%x\n", lc_main_offset) fmt.Printf("// lc_main_offset=%x\n", lc_main_offset)
offset := int64(shellcode_offset) offset := int64(shellcode_offset)
{ {
// fix main to point to our newly created shellcode // fix main to point to our newly created shellcode
bs := make([]byte, 8) bs := make([]byte, 8)
mc.byteorder.PutUint64(bs, uint64(offset)) mc.byteorder.PutUint64(bs, uint64(offset))
mc.file.WriteAt(bs, int64(lc_main_offset)) mc.file.WriteAt(bs, int64(lc_main_offset))
} }
bs := make([]byte, 4) bs := make([]byte, 4)
for _, ins := range shellcode { for _, ins := range shellcode {
mc.byteorder.PutUint32(bs, ins) mc.byteorder.PutUint32(bs, ins)
mc.file.WriteAt(bs, offset) mc.file.WriteAt(bs, offset)
offset += 4 offset += 4
} }
} }
func (mc *MachoContext) RemoveSymbolTable() { func (mc *MachoContext) RemoveSymbolTable() {
// try to remove symtab and dysymtab // try to remove symtab and dysymtab
mc.removeSymtabCommand() mc.removeSymtabCommand()
mc.removeDySymtabCommand() mc.removeDySymtabCommand()
} }
func (mc *MachoContext) removeSymtabCommand() { func (mc *MachoContext) removeSymtabCommand() {
ptr := int64(0) ptr := int64(0)
if mc.Is64bit() { if mc.Is64bit() {
ptr, _ = mc.file.Seek(int64(Header_size_64), io.SeekStart) ptr, _ = mc.file.Seek(int64(Header_size_64), io.SeekStart)
} else { } else {
ptr, _ = mc.file.Seek(int64(Header_size), io.SeekStart) ptr, _ = mc.file.Seek(int64(Header_size), io.SeekStart)
} }
var symtab_fix *Symtab var symtab_fix *Symtab
for _, cmd := range mc.commands { for _, cmd := range mc.commands {
if cmd.Cmd() != LC_SYMTAB { if cmd.Cmd() != LC_SYMTAB {
ptr += int64(cmd.Cmdsize()) ptr += int64(cmd.Cmdsize())
continue continue
} }
var symtab = cmd.(*Symtab) var symtab = cmd.(*Symtab)
symtab_fix = symtab symtab_fix = symtab
// erase strings referenced // erase strings referenced
start := int64(symtab_fix.stroff) start := int64(symtab_fix.stroff)
size := symtab_fix.strsize size := symtab_fix.strsize
fmt.Printf("// Erase at=0x%x size=0x%x\n", start, size) fmt.Printf("// Erase at=0x%x size=0x%x\n", start, size)
mc.file.WriteAt(make([]byte, size), start) mc.file.WriteAt(make([]byte, size), start)
// erase nlist64 symbol items // erase nlist64 symbol items
start = int64(symtab_fix.symoff) start = int64(symtab_fix.symoff)
size = symtab_fix.nsyms * 16 size = symtab_fix.nsyms * 16
fmt.Printf("// Erase at=0x%x size=0x%x\n", start, size) fmt.Printf("// Erase at=0x%x size=0x%x\n", start, size)
mc.file.WriteAt(make([]byte, size), start) mc.file.WriteAt(make([]byte, size), start)
symtab_fix.symoff = 0 symtab_fix.symoff = 0
symtab_fix.nsyms = 0 symtab_fix.nsyms = 0
symtab_fix.stroff = 0 symtab_fix.stroff = 0
symtab_fix.strsize = 0 symtab_fix.strsize = 0
mc.file.Seek(ptr, io.SeekStart) mc.file.Seek(ptr, io.SeekStart)
mc.file.Write(symtab_fix.Serialize(mc)) 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() { func (mc *MachoContext) removeDySymtabCommand() {
ptr := int64(0) ptr := int64(0)
if mc.Is64bit() { if mc.Is64bit() {
ptr, _ = mc.file.Seek(int64(Header_size_64), io.SeekStart) ptr, _ = mc.file.Seek(int64(Header_size_64), io.SeekStart)
} else { } else {
@ -585,33 +584,33 @@ func (mc *MachoContext) removeDySymtabCommand() {
} }
for _, cmd := range mc.commands { for _, cmd := range mc.commands {
if cmd.Cmd() != LC_DYSYMTAB { if cmd.Cmd() != LC_DYSYMTAB {
ptr += int64(cmd.Cmdsize()) ptr += int64(cmd.Cmdsize())
continue continue
} }
var dysymtab = cmd.(*DySymtab) var dysymtab = cmd.(*DySymtab)
dysymtab_fix := dysymtab dysymtab_fix := dysymtab
dysymtab_fix.indirectsymoff = 0 dysymtab_fix.indirectsymoff = 0
dysymtab_fix.nindirectsyms = 0 dysymtab_fix.nindirectsyms = 0
mc.file.Seek(ptr, io.SeekStart) mc.file.Seek(ptr, io.SeekStart)
mc.file.Write(dysymtab_fix.Serialize(mc)) mc.file.Write(dysymtab_fix.Serialize(mc))
} }
} }
func (mc *MachoContext) RemoveExportTrie() { func (mc *MachoContext) RemoveExportTrie() {
var start int64 var start int64
var size int var size int
if mc.dyldinfo != nil { if mc.dyldinfo != nil {
// legacy export trie // legacy export trie
start = int64(mc.dyldinfo.export_off) start = int64(mc.dyldinfo.export_off)
size = int(mc.dyldinfo.export_size) size = int(mc.dyldinfo.export_size)
mc.file.WriteAt(make([]byte, size), start) mc.file.WriteAt(make([]byte, size), start)
} else if mc.exports != nil { } else if mc.exports != nil {
// modern export trie // modern export trie
start = int64(mc.exports.dataoff) start = int64(mc.exports.dataoff)
size = int(mc.exports.datasize) size = int(mc.exports.datasize)
mc.file.WriteAt(make([]byte, size), start) mc.file.WriteAt(make([]byte, size), start)
} else { } else {
// no export trie (??) // no export trie (??)
// should never occur unless this binary is modified // should never occur unless this binary is modified
} }
} }

View File

@ -397,13 +397,13 @@ func (lcmd *DyldInfo) Deserialize(mc *MachoContext, buf []byte) {
} }
type Fixups struct { type Fixups struct {
fixups_version uint32 fixups_version uint32
starts_offset uint32 starts_offset uint32
imports_offset uint32 imports_offset uint32
symbols_offset uint32 symbols_offset uint32
imports_count uint32 imports_count uint32
imports_format uint32 imports_format uint32
symbols_format uint32 symbols_format uint32
} }
func (lcmd *Fixups) Serialize(mc *MachoContext) []byte { func (lcmd *Fixups) Serialize(mc *MachoContext) []byte {
@ -516,25 +516,25 @@ func (lcmd *Symtab) Deserialize(mc *MachoContext, buf []byte) {
} }
type DySymtab struct { type DySymtab struct {
c LoadCmd c LoadCmd
ilocalsym uint32 ilocalsym uint32
nlocalsym uint32 nlocalsym uint32
iextdefsym uint32 iextdefsym uint32
nextdefsym uint32 nextdefsym uint32
iundefsym uint32 iundefsym uint32
nundefsym uint32 nundefsym uint32
tocoff uint32 tocoff uint32
ntoc uint32 ntoc uint32
modtaboff uint32 modtaboff uint32
nmodtab uint32 nmodtab uint32
extrefsymoff uint32 extrefsymoff uint32
nextrefsyms uint32 nextrefsyms uint32
indirectsymoff uint32 indirectsymoff uint32
nindirectsyms uint32 nindirectsyms uint32
extreloff uint32 extreloff uint32
nextrel uint32 nextrel uint32
localrefoff uint32 localrefoff uint32
nlocref uint32 nlocref uint32
} }
func (lcmd *DySymtab) Cmd() 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.nlocalsym)
binary.Write(buf, mc.byteorder, lcmd.iextdefsym) binary.Write(buf, mc.byteorder, lcmd.iextdefsym)
binary.Write(buf, mc.byteorder, lcmd.nextdefsym) binary.Write(buf, mc.byteorder, lcmd.nextdefsym)
binary.Write(buf, mc.byteorder, lcmd.iundefsym) binary.Write(buf, mc.byteorder, lcmd.iundefsym)
binary.Write(buf, mc.byteorder, lcmd.nundefsym) binary.Write(buf, mc.byteorder, lcmd.nundefsym)
binary.Write(buf, mc.byteorder, lcmd.tocoff) binary.Write(buf, mc.byteorder, lcmd.tocoff)
binary.Write(buf, mc.byteorder, lcmd.ntoc) binary.Write(buf, mc.byteorder, lcmd.ntoc)
binary.Write(buf, mc.byteorder, lcmd.modtaboff) binary.Write(buf, mc.byteorder, lcmd.modtaboff)
binary.Write(buf, mc.byteorder, lcmd.nmodtab) binary.Write(buf, mc.byteorder, lcmd.nmodtab)
binary.Write(buf, mc.byteorder, lcmd.extrefsymoff) binary.Write(buf, mc.byteorder, lcmd.extrefsymoff)
binary.Write(buf, mc.byteorder, lcmd.nextrefsyms) binary.Write(buf, mc.byteorder, lcmd.nextrefsyms)
binary.Write(buf, mc.byteorder, lcmd.indirectsymoff) binary.Write(buf, mc.byteorder, lcmd.indirectsymoff)
binary.Write(buf, mc.byteorder, lcmd.nindirectsyms) binary.Write(buf, mc.byteorder, lcmd.nindirectsyms)
binary.Write(buf, mc.byteorder, lcmd.extreloff) binary.Write(buf, mc.byteorder, lcmd.extreloff)
binary.Write(buf, mc.byteorder, lcmd.nextrel) binary.Write(buf, mc.byteorder, lcmd.nextrel)
binary.Write(buf, mc.byteorder, lcmd.localrefoff) binary.Write(buf, mc.byteorder, lcmd.localrefoff)
binary.Write(buf, mc.byteorder, lcmd.nlocref) binary.Write(buf, mc.byteorder, lcmd.nlocref)
return buf.Bytes() 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.nlocalsym)
binary.Read(r, mc.byteorder, &lcmd.iextdefsym) binary.Read(r, mc.byteorder, &lcmd.iextdefsym)
binary.Read(r, mc.byteorder, &lcmd.nextdefsym) binary.Read(r, mc.byteorder, &lcmd.nextdefsym)
binary.Read(r, mc.byteorder, &lcmd.iundefsym) binary.Read(r, mc.byteorder, &lcmd.iundefsym)
binary.Read(r, mc.byteorder, &lcmd.nundefsym) binary.Read(r, mc.byteorder, &lcmd.nundefsym)
binary.Read(r, mc.byteorder, &lcmd.tocoff) binary.Read(r, mc.byteorder, &lcmd.tocoff)
binary.Read(r, mc.byteorder, &lcmd.ntoc) binary.Read(r, mc.byteorder, &lcmd.ntoc)
binary.Read(r, mc.byteorder, &lcmd.modtaboff) binary.Read(r, mc.byteorder, &lcmd.modtaboff)
binary.Read(r, mc.byteorder, &lcmd.nmodtab) binary.Read(r, mc.byteorder, &lcmd.nmodtab)
binary.Read(r, mc.byteorder, &lcmd.extrefsymoff) binary.Read(r, mc.byteorder, &lcmd.extrefsymoff)
binary.Read(r, mc.byteorder, &lcmd.nextrefsyms) binary.Read(r, mc.byteorder, &lcmd.nextrefsyms)
binary.Read(r, mc.byteorder, &lcmd.indirectsymoff) binary.Read(r, mc.byteorder, &lcmd.indirectsymoff)
binary.Read(r, mc.byteorder, &lcmd.nindirectsyms) binary.Read(r, mc.byteorder, &lcmd.nindirectsyms)
binary.Read(r, mc.byteorder, &lcmd.extreloff) binary.Read(r, mc.byteorder, &lcmd.extreloff)
binary.Read(r, mc.byteorder, &lcmd.nextrel) binary.Read(r, mc.byteorder, &lcmd.nextrel)
binary.Read(r, mc.byteorder, &lcmd.localrefoff) binary.Read(r, mc.byteorder, &lcmd.localrefoff)
binary.Read(r, mc.byteorder, &lcmd.nlocref) binary.Read(r, mc.byteorder, &lcmd.nlocref)
} }

View File

@ -29,11 +29,11 @@ type MachoContext struct {
linkedits []*LinkEdit linkedits []*LinkEdit
segments []Segment segments []Segment
symtab *Symtab symtab *Symtab
dysymtab *DySymtab dysymtab *DySymtab
dyldinfo *DyldInfo dyldinfo *DyldInfo
fixups *LinkEdit fixups *LinkEdit
exports *LinkEdit exports *LinkEdit
} }
func (mc *MachoContext) FileSize() uint32 { func (mc *MachoContext) FileSize() uint32 {
@ -235,12 +235,12 @@ func (mc *MachoContext) Parse(r *bufio.Reader) error {
lcmd.Deserialize(mc, command_buf) lcmd.Deserialize(mc, command_buf)
mc.commands = append(mc.commands, lcmd) mc.commands = append(mc.commands, lcmd)
mc.linkedits = append(mc.linkedits, lcmd) mc.linkedits = append(mc.linkedits, lcmd)
if lcmd.Cmd() == LC_DYLD_CHAINED_FIXUPS { if lcmd.Cmd() == LC_DYLD_CHAINED_FIXUPS {
mc.fixups = lcmd mc.fixups = lcmd
} }
if lcmd.Cmd() == LC_DYLD_EXPORTS_TRIE { if lcmd.Cmd() == LC_DYLD_EXPORTS_TRIE {
mc.exports = lcmd mc.exports = lcmd
} }
break break
case LC_SYMTAB: case LC_SYMTAB:
@ -248,12 +248,14 @@ func (mc *MachoContext) Parse(r *bufio.Reader) error {
lcmd.Deserialize(mc, command_buf) lcmd.Deserialize(mc, command_buf)
mc.commands = append(mc.commands, lcmd) mc.commands = append(mc.commands, lcmd)
mc.symtab = lcmd mc.symtab = lcmd
break
case LC_DYSYMTAB: case LC_DYSYMTAB:
lcmd := new(DySymtab) lcmd := new(DySymtab)
lcmd.Deserialize(mc, command_buf) lcmd.Deserialize(mc, command_buf)
mc.commands = append(mc.commands, lcmd) mc.commands = append(mc.commands, lcmd)
mc.dysymtab = lcmd mc.dysymtab = lcmd
break
default: default:
lcmd := new(LoadCmd) lcmd := new(LoadCmd)

View File

@ -82,7 +82,7 @@ func (mc *MachoContext) CollectSymbols() []*Symbol {
binary.Read(symtab_buffer, mc.byteorder, &value64) binary.Read(symtab_buffer, mc.byteorder, &value64)
} else { } else {
// always use value64 // always use value64
var value32 uint32 var value32 uint32
binary.Read(symtab_buffer, mc.byteorder, &value32) binary.Read(symtab_buffer, mc.byteorder, &value32)
value64 = uint64(value32) value64 = uint64(value32)
} }