diff --git a/macho-go/go.mod b/macho-go/go.mod index 95ff2b8..fca52f3 100644 --- a/macho-go/go.mod +++ b/macho-go/go.mod @@ -5,10 +5,11 @@ go 1.17 require ( github.com/alecthomas/kong v0.2.16 github.com/sirupsen/logrus v1.8.0 - google.golang.org/protobuf v1.26.0 + google.golang.org/protobuf v1.31.0 ) require ( + github.com/golang/protobuf v1.5.3 // indirect github.com/magefile/mage v1.10.0 // indirect github.com/pkg/errors v0.8.1 // indirect golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 // indirect diff --git a/macho-go/go.sum b/macho-go/go.sum index 4bb6da4..5915ac3 100644 --- a/macho-go/go.sum +++ b/macho-go/go.sum @@ -3,6 +3,8 @@ github.com/alecthomas/kong v0.2.16/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QL github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/magefile/mage v1.10.0 h1:3HiXzCUY12kh9bIuyXShaVe529fJfyqoVM42o/uom2g= @@ -22,3 +24,5 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= diff --git a/macho-go/internal/wrapper/action/save_imports.go b/macho-go/internal/wrapper/action/save_imports.go index 2d80397..efa7b58 100644 --- a/macho-go/internal/wrapper/action/save_imports.go +++ b/macho-go/internal/wrapper/action/save_imports.go @@ -1,9 +1,9 @@ package action import ( - // "fmt" "sort" "strings" + // log "github.com/sirupsen/logrus" . "ios-wrapper/internal/wrapper/ofile" @@ -57,10 +57,18 @@ func (action *saveImports) saveToInfo(mf *MachoFile) error { current_lib_idx := -1 current_symbol_idx := -1 + intlSymbols := []string{} + for _, symbol := range symbols_raw { + if symbol.Dylib() == "/usr/local/opt/gettext/lib/libintl.8.dylib" { + intlSymbols = append(intlSymbols, symbol.Name()) + } + } + action.keepSymbols = append(action.keepSymbols, intlSymbols...) + // now we expect everything is sorted and easier to build strings tables // this is not fully optimized, there can be repeated symbol name in different libraries for _, symbol := range symbols_raw { - if symbol.Type() != "lazy" { + if !symbol.SafeForRemoval() { continue } @@ -130,6 +138,16 @@ func (action *saveImports) saveToInfo(mf *MachoFile) error { } mf.Info().Main = mc.Main() + + selectors_list := []*protomodel.MachoInfo_Selector{} + for _, sel := range mc.CollectSpecialSelectors() { + selectors_list = append(selectors_list, &protomodel.MachoInfo_Selector{ + Idx: uint32(sel.Idx()), + Name: sel.Name(), + }) + } + mf.Info().SpecialSelectors = selectors_list + return nil } diff --git a/macho-go/internal/wrapper/cli.go b/macho-go/internal/wrapper/cli.go index ca198ae..3e7efda 100644 --- a/macho-go/internal/wrapper/cli.go +++ b/macho-go/internal/wrapper/cli.go @@ -299,6 +299,21 @@ func bcell2header(bfile string, header string) { } fmt.Fprintf(w, "};\n") fmt.Fprintf(w, "uint32_t n_instructions = %d;\n", n_instructions) + + fmt.Fprintf(w, "__attribute__((section(\"__DATA,bshield\")))\n") + fmt.Fprintf(w, "uint32_t special_selectors_idx[] = {\n") + for _, selector := range info.GetSpecialSelectors() { + fmt.Fprintf(w, "%x,\n", selector.Idx) + } + fmt.Fprintf(w, "};\n") + + fmt.Fprintf(w, "__attribute__((section(\"__DATA,bshield\")))\n") + fmt.Fprintf(w, "const char* special_selectors_name[] = {\n") + for _, selector := range info.GetSpecialSelectors() { + fmt.Fprintf(w, "\"%s\",\n", selector.Name) + } + fmt.Fprintf(w, "};\n") + fmt.Fprintf(w, "uint32_t n_selectors = %d;\n", len(info.GetSpecialSelectors())) } fmt.Fprintf(w, "}// namespace bshield_data\n") w.Flush() diff --git a/macho-go/internal/wrapper/cli_parser.go b/macho-go/internal/wrapper/cli_parser.go index 31ea0e4..2f2ed25 100644 --- a/macho-go/internal/wrapper/cli_parser.go +++ b/macho-go/internal/wrapper/cli_parser.go @@ -63,7 +63,7 @@ type PepeArgument struct { 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"` + RemoveSymbolTable bool `default:"false" 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"` diff --git a/macho-go/pkg/ios/macho/dyld_info.go b/macho-go/pkg/ios/macho/dyld_info.go index 423afa5..21dd92c 100644 --- a/macho-go/pkg/ios/macho/dyld_info.go +++ b/macho-go/pkg/ios/macho/dyld_info.go @@ -42,6 +42,10 @@ func (sym *ImportSymbol) Type() string { return sym.typ } +func (sym *ImportSymbol) SafeForRemoval() bool { + return sym.typ == "lazy" || sym.typ == "fixups" +} + func (sym *ImportSymbol) Dylib() string { return sym.dylib } @@ -150,7 +154,7 @@ func (mc *MachoContext) CollectBindSymbolsModern() []*ImportSymbol { sym.address = uint64(address) sym.name = name sym.dylib = dylib - sym.typ = "lazy" + sym.typ = "fixups" sym.lib_ordinal = uint32(s.lib_ordinal) sym.segment = uint32(mc.findSegmentIndexAt(uint64(address))) diff --git a/macho-go/pkg/ios/macho/edit.go b/macho-go/pkg/ios/macho/edit.go index 4900e18..67a2d8a 100644 --- a/macho-go/pkg/ios/macho/edit.go +++ b/macho-go/pkg/ios/macho/edit.go @@ -280,7 +280,10 @@ func (mc *MachoContext) RemoveBindSymbols() { rand.Seed(time.Now().UnixNano()) - if mc.dyldinfo == nil { + isModernSymbol := mc.dyldinfo == nil + isLegacySymbol := !isModernSymbol + + if isModernSymbol { mc.removeBindSymbolsModern() } else { mc.removeBindSymbolsLegacy() @@ -290,14 +293,12 @@ func (mc *MachoContext) RemoveBindSymbols() { 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" { + if !symbol.SafeForRemoval() { continue } - if mc.dyldinfo != nil { + if isLegacySymbol { // for legacy resolve the opcodes can be rewritten as 0x00 mc.file.WriteAt(make([]byte, 8), int64(symbol.file_address)) } else { @@ -359,174 +360,6 @@ func (mc *MachoContext) removeBindSymbolsLegacy() { mc.file.WriteAt(make([]byte, size), int64(start)) } -func (mc *MachoContext) ReworkForObjc() { - text_start := 0 - data_end := 0 - lc_main_offset := 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) - } - - 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()) - 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 - - // __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 - // each section has their addr field which we can use that with segment virtual address - // to calculate the offset of the last section from segment starts - // then use the size of section to calculate the end of segment in file - sections := segment.Sections() - last := sections[len(sections)-1] - data_end = int(last.Addr() - segment.Vmaddr() + segment.Fileoff() + last.Size()) - } - ptr += int64(cmd.Cmdsize()) - } - 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)) - - // 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 - - // must expand stack to store arguments passed - // must use newly allocated stack region - // must save return address - // must recover stack to same value before calling main - // must recover link register before calling main - - // we use shorthand store/load multiple - // arm also has different indexing instruction, so be careful - // https://developer.arm.com/documentation/102374/0101/Loads-and-stores---addressing - /* - adr x8, 0 - # x9 = (offset end of __DATA) - (offset shellcode) - movz x9, #0x9999 - add x8, x8, x9 - - stp x30, x8, [sp], #-0x10 - stp x3, x2, [sp], #-0x10 - stp x1, x0, [sp], #-0x10 - - # custom intializer - ldr x9, [x8] - blr x9 - - ldp x1, x0, [sp, #0x10]! - ldp x3, x2, [sp, #0x10]! - ldp x30, x8, [sp, #0x10]! - - # original main - # link register is set so jump only - ldr x9, [x8, #8] - br x9 - */ - - // TODO: fix to work with offset larger than 0xffff - shellcode := []uint32{ - 0x10000008, - 0, // x9 = (offset end of __DATA) - (offset shellcode) - 0x8B090108, - 0xA8BF23FE, - 0xA8BF0BE3, - 0xA8BF03E1, - 0xF9400109, - 0xD63F0120, - 0xA9C103E1, - 0xA9C10BE3, - 0xA9C123FE, - 0xF9400509, - 0xD61F0120, - } - - 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)) - } - - // movz_shellcode_offset := encode_movz(shellcode_offset) - // movz_main_offset := encode_movz(main_offset) - // movz_data_end_offset := encode_movz(data_end) - movz_calculate_offset := encode_movz(data_end - shellcode_offset) - - shellcode[1] = movz_calculate_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_calculate_offset=%x\n", movz_calculate_offset) - // 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)) - } - - bs := make([]byte, 4) - for _, ins := range shellcode { - mc.byteorder.PutUint32(bs, ins) - mc.file.WriteAt(bs, offset) - offset += 4 - } -} - func (mc *MachoContext) RewriteImportsTable(keepSymbols []string) { allSymbols := mc.CollectBindSymbols() fixups, fixupsOffset := mc.Fixups() @@ -539,6 +372,23 @@ func (mc *MachoContext) RewriteImportsTable(keepSymbols []string) { // but because we keep a few symbols, we need to rewrite the pointers // as well as rebuild the import table and strings table, and bind values + // some symbols are annoyingly distributed by another library + // dispite the name asking for X, the dyld loads a Y library + // LC_DYLD_ID of Y is equal to X and dyld can resolve these symbols + // because we do not search for library using LC_DYLD_ID, + // paths are mistaken and will not resolve symbols + // + // the most common library that has this behavior is libintl + // and fixing the resolver takes time, we temporarily ignore this library + // and so we keep symbols referenced by libintl + intlSymbols := []string{} + for _, symbol := range allSymbols { + if symbol.Dylib() == "/usr/local/opt/gettext/lib/libintl.8.dylib" { + intlSymbols = append(intlSymbols, symbol.Name()) + } + } + keepSymbols = append(keepSymbols, intlSymbols...) + keepCount := uint32(0) for _, symbol := range keepSymbols { name := symbol diff --git a/macho-go/pkg/ios/macho/objc.go b/macho-go/pkg/ios/macho/objc.go new file mode 100644 index 0000000..ec01d8d --- /dev/null +++ b/macho-go/pkg/ios/macho/objc.go @@ -0,0 +1,365 @@ +package macho + +import ( + "fmt" + "bytes" + "encoding/binary" + "io" + "strings" + + . "ios-wrapper/pkg/ios" +) + + +type SpecialSelector struct { + idx uint + name string +} + +func (sel *SpecialSelector) Idx() uint { + return sel.idx +} + +func (sel *SpecialSelector) Name() string { + return sel.name +} + +// collect the index and the name in selector list of special method names +// these names are resolved by the dyld objc cache +// through __dyld_get_objc_selector +// +// we currently have the following symbols guaranteed to be in this list: +// - load +// - retain +func (mc *MachoContext) CollectSpecialSelectors() []*SpecialSelector { + + var special_selectors []*SpecialSelector + var methods []byte + var methname_offset uint32 + + for _, cmd := range mc.commands { + if cmd.Cmd() == LC_MAIN { + continue + } + if cmd.Cmd() != LC_SEGMENT_64 { + continue + } + var segment = cmd.(*Segment64) + + if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__TEXT")) == 0 { + for _, section := range segment.Sections() { + if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_methname")) == 0 { + methname_offset = section.Offset() + methods = make([]byte, section.Size()) + mc.file.ReadAt(methods, int64(section.Offset())) + } + } + } + if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__DATA")) == 0 { + for _, section := range segment.Sections() { + if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_selrefs")) == 0 { + selectors_buffer := make([]byte, section.Size()) + mc.file.ReadAt(selectors_buffer, int64(section.Offset())) + + buffer := bytes.NewReader(selectors_buffer) + + for i := uint(0); i < uint(section.Size()) / 8; i++ { + // this field is actually a Rebase + // we assume that no rebase is needed + // so everything sticks to its file offset + var offset uint32 + binary.Read(buffer, mc.byteorder, &offset) // first 4 bytes is offset + + var name_builder strings.Builder + for j := uint32(0); ; j++ { + c := methods[offset - methname_offset + j] + if c == 0 { + break + } + name_builder.WriteByte(c) + } + name := name_builder.String() + if name == "load" { + special_selectors = append(special_selectors, &SpecialSelector{ + idx: i, + name: name, + }) + } + + binary.Read(buffer, mc.byteorder, &offset) // ignore rebase arguments + } + } + } + } + } + return special_selectors +} + +func (mc *MachoContext) ReworkForObjc() { + text_start := 0 + data_end := 0 + lc_main_offset := 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) + } + + 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()) + 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) + } + + // erases all objc method names + // this should still works because the cache inserts the pointer value not string + // but some symbols relies on pre-defined implementations, such as **load** method + // load method is the same across all classes and so objc define an implementation + // selector should points to this load selector to make objc thinks that it's "load" + if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_methname")) == 0 { + // mc.file.WriteAt([]byte("__objc_methbruh"), section_ptr) + mc.file.WriteAt(make([]byte, section.Size()), int64(section.Offset())) + } + 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 + // each section has their addr field which we can use that with segment virtual address + // to calculate the offset of the last section from segment starts + // then use the size of section to calculate the end of segment in file + sections := segment.Sections() + last := sections[len(sections)-1] + data_end = int(last.Addr() - segment.Vmaddr() + segment.Fileoff() + last.Size()) + + // do not register selector and see what happens + section_ptr := ptr + 0x40 + 8 + for _, section := range segment.Sections() { + if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_selrefs")) == 0 { + // mc.file.WriteAt([]byte("__objc_selbruh"), section_ptr) + } + section_ptr += 16*2 + 8*2 + 4*8 + } + } + ptr += int64(cmd.Cmdsize()) + } + 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)) + + // 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 + + // must expand stack to store arguments passed + // must use newly allocated stack region + // must save return address + // must recover stack to same value before calling main + // must recover link register before calling main + + // ┌─────────────────┐ + // │ │ + // shellcode starts ────┼─────────────────┼───── │ │instruction + // │ │ │ │fetch RIP size + // RIP returns ────┼─────────────────┼───── ▲ │ │ + // │ │ │ │ + // │ │ │ │ shellcode length + // shellcode ends │ │ │ offset │ + // __text ────┼─────────────────┼───── │ range │ + // │ │ │ │ __DATA ends - __text + // │ │ │ │ + // __DATA ends ────┼─────────────────┼───── ▼ │ + // │ │ + // │ │ + // │ │ + // │ │ + // │ │ + // └─────────────────┘ + + shellcode := []uint32{} + ins_size_byte := 4 + main_offset := int(mc.entryoff) + var shellcode_offset int + + isArm := (mc.header.cputype & 0xff) == 12 + if isArm { + + // we use shorthand store/load multiple + // arm also has different indexing instruction, so be careful + // https://developer.arm.com/documentation/102374/0101/Loads-and-stores---addressing + /* + adr x8, 0 + # x9 = (offset end of __DATA) - (offset shellcode) + movz x9, #0x9999 + add x8, x8, x9 + + stp x30, x8, [sp], #-0x10 + stp x3, x2, [sp], #-0x10 + stp x1, x0, [sp], #-0x10 + + # custom intializer + ldr x9, [x8] + blr x9 + + ldp x1, x0, [sp, #0x10]! + ldp x3, x2, [sp, #0x10]! + ldp x30, x8, [sp, #0x10]! + + # original main + # link register is set so jump only + ldr x9, [x8, #8] + br x9 + */ + shellcode = []uint32{ + 0x10000008, + 0, // x9 = (offset end of __DATA) - (offset shellcode) + 0x8B090108, + 0xA8BF23FE, + 0xA8BF0BE3, + 0xA8BF03E1, + 0xF9400109, + 0xD63F0120, + 0xA9C103E1, + 0xA9C10BE3, + 0xA9C123FE, + 0xF9400509, + 0xD61F0120, + } + + shellcode_offset = text_start - (ins_size_byte * len(shellcode)) + + 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_calculate_offset := encode_movz(data_end - shellcode_offset) + + shellcode[1] = movz_calculate_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_calculate_offset=%x\n", movz_calculate_offset) + // 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) + } else { + shellcode_start := []uint8{ + 0x4c, 0x8d, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x49, 0xC7, 0xC1, + } + + shellcode_end := []uint8{ + 0x4d, 0x01, 0xc8, + 0x57, + 0x56, + 0x52, + 0x51, + 0x41, 0x50, + 0x4d, 0x8b, 0x08, + 0x41, 0xff, 0xd1, + 0x41, + 0x58, + 0x59, + 0x5a, + 0x5e, + 0x5f, 0x4d, 0x8b, 0x48, 0x08, + 0x41, 0xff, 0xe1, + // pad to %4 + 0x00, 0x00, + } + + offset := []uint8{0x00, 0x00, 0x00, 0x00} // offset + shellcode_size := len(shellcode_start) + len(offset) + len(shellcode_end) + + // could use buffer encoding, but for correctness, + // we do this by hand + encode_movz := func(v int) { + for i := 0; i < 4; i++ { + offset[i] = uint8(v >> (i * 8)) + } + } + + encode_movz((data_end - text_start) + (shellcode_size - len(shellcode_start))) + + shellcode_offset = text_start - shellcode_size + shellcode_bytes := append(shellcode_start, offset...) + shellcode_bytes = append(shellcode_bytes, shellcode_end...) + + for i := 0; i < len(shellcode_bytes); i += 4 { + val := 0 + // little endian + val |= int(shellcode_bytes[i+0]) << 0 + val |= int(shellcode_bytes[i+1]) << 8 + val |= int(shellcode_bytes[i+2]) << 16 + val |= int(shellcode_bytes[i+3]) << 24 + shellcode = append(shellcode, uint32(val)) + } + + 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("// 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)) + } + + bs := make([]byte, 4) + for _, ins := range shellcode { + mc.byteorder.PutUint32(bs, ins) + mc.file.WriteAt(bs, offset) + offset += 4 + } +} + diff --git a/macho-go/proto/macho_info.proto b/macho-go/proto/macho_info.proto index a2aecdb..dac9955 100644 --- a/macho-go/proto/macho_info.proto +++ b/macho-go/proto/macho_info.proto @@ -44,11 +44,15 @@ message MachoInfo { repeated LibraryImportedSymbols tables = 3; } + message Selector { + uint32 idx = 1; + string name = 2; + } + PointerSize pointer_size = 1; uint64 image_base = 2; uint64 main = 3; repeated InitPointer init_pointers = 4; - // repeated BindSymbol symbols = 5; AllImportedSymbols symbols = 5; - + repeated Selector special_selectors = 6; } diff --git a/research/custom_loader/a.mm b/research/custom_loader/a.mm index a594fd5..5eb730e 100644 --- a/research/custom_loader/a.mm +++ b/research/custom_loader/a.mm @@ -1,4 +1,5 @@ #import +#include #include @interface Foo : NSObject @@ -6,7 +7,7 @@ @implementation Foo - (void)bar { - NSLog(@"%@", self); + NSLog(@"[Foo bar]: %@", self); } @end @@ -44,9 +45,16 @@ hmmge(int argc, char** argv) { int main(int argc, const char * argv[]) { @autoreleasepool { - NSLog(@"Hello, World!"); + NSLog(@"main()"); + NSLog(@"selector for \"bar:\" %p", @selector(bar:)); + Foo *foo = [[Foo alloc] init]; [foo bar]; + + NSLog(@"directly call \"bar\" %p through objc_msgSend %p with object foo %p\n", @selector(bar), objc_msgSend, foo); + typedef void (*barfunc)(id, SEL); + barfunc bar_ = (barfunc)&objc_msgSend; + bar_(foo, @selector(bar)); } printf("argc=%d\n", argc); diff --git a/research/custom_loader/b.cc b/research/custom_loader/b.cc index 679b626..c6a4e83 100644 --- a/research/custom_loader/b.cc +++ b/research/custom_loader/b.cc @@ -72,17 +72,18 @@ struct libcache { void *main; void *thislib; void *libdyld; + + int nrpath; + char **rpaths; }; -// try these hashes -// https://gist.github.com/sgsfak/9ba382a0049f6ee885f68621ae86079b -uint32_t fnv_hash(const char *str) { +uint32_t fnv_hash_extend(const char *str, uint32_t h) { unsigned char *s = (unsigned char *)str; /* unsigned string */ /* See the FNV parameters at www.isthe.com/chongo/tech/comp/fnv/#FNV-param */ const uint32_t FNV_32_PRIME = 0x01000193; /* 16777619 */ - uint32_t h = 0x811c9dc5; /* 2166136261 */ + // uint32_t h = 0x811c9dc5; /* 2166136261 */x while (*s != 0) { /* xor the bottom with the current octet */ h ^= *s++; @@ -92,6 +93,10 @@ uint32_t fnv_hash(const char *str) { return h; } +uint32_t fnv_hash(const char *str) { return fnv_hash_extend(str, 0x811c9dc5); } + +// try these hashes +// https://gist.github.com/sgsfak/9ba382a0049f6ee885f68621ae86079b // calculate the hash to search // _dyld_get_image_name returns the full path to the library @@ -115,7 +120,20 @@ uint32_t calculate_libname_hash(const libcache *cache, const char *name) { // then resolve the full path for all rpath // // which rpath is correct can be done by checking if the cache has that hash - printf("resolver for @rpath is not supported yet\n"); + for (int i = 0; i < cache->nrpath; i++) { + char *rpath = cache->rpaths[i]; + char *p = realpath(rpath, 0); + hash = hash_func(p); + hash = fnv_hash_extend(&name[6], hash); + for (size_t j = 0; j < cache->size; j++) { + if (cache->libs[j].hash == hash) { + free(p); + return hash; + } + } + free(p); + } + // printf("resolver for @rpath is not supported yet\n"); } else { hash = hash_func(name); } @@ -428,7 +446,7 @@ uint32_t should_follow_symbol(char *&buffer, char *&_find) { return is_prefix; } -void *find_in_export_trie(const void *header, void *trie, const char *symbol) { +void *find_in_export_trie(const void *header, void *trie, char *&symbol) { uint32_t func = 0; char *ptr = (char *)trie; @@ -465,17 +483,37 @@ void *find_in_export_trie(const void *header, void *trie, const char *symbol) { } char count = *(ptr - 1); - ptr++; // flags + uint8_t flag = *ptr++; // flags // uleb128 offset decode_uleb128(ptr, &func); + + if (flag == 0x8 /*re-export*/) { + // this hits a re-export symbol but with another name + // usually, the re-export is the same name on another library + // but somehow, for system libraries, a lot of symbols are + // renamed and re-exported from another library + // probably this was to build wrappers and + // have custom platform optimizations + // + // example of these is _strlen in libsystem_c.dylib + // is re-exported from __platform_strlen in libplatform + // + // The purpose of using char*& is to change the symbol searching + // to another symbols and do it quickly using references (pointer) + // + // we return 0 so the dlsym continues to search, + // but with another symbol name because the symbol points to another string + symbol = ptr; + return 0; + } return (void *)((char *)header + func); } void *find_in_lib(struct libcache *cache, struct libcache_item *lib, - const char *symbol); + char *&symbol); void *find_in_reexport(struct libcache *cache, struct libcache_item *lib, - const char *symbol) { + char *&symbol) { void *header = lib->header; const uint32_t magic = *(uint32_t *)header; char *ptr = (char *)header; @@ -511,7 +549,7 @@ void *find_in_reexport(struct libcache *cache, struct libcache_item *lib, } void *find_in_lib(struct libcache *cache, struct libcache_item *lib, - const char *symbol) { + char *&symbol) { void *direct = find_in_export_trie(lib->header, lib->trie, symbol); if (direct) { return direct; @@ -520,11 +558,34 @@ void *find_in_lib(struct libcache *cache, struct libcache_item *lib, return find_in_reexport(cache, lib, symbol); } +// the current logic of dlsym is not correct, but it works for PoC +// +// dlsym searchs and match libraries based on the LC_DYLD_ID load command +// while for our PoC, we use the paths of libraries to search for them +// +// for performance reasons, we do not compare the paths as strings +// we instead use a simple hash to carry out comparision +// using hashes allows us to compare integers and would be faster void *custom_dlsym(struct libcache *cache, uint32_t hash, const char *symbol) { for (size_t i = 0; i < cache->size; i++) { struct libcache_item *cache_lib = &cache->libs[i]; if (cache_lib->hash == hash) { - return find_in_lib(cache, cache_lib, symbol); + // read find_in_export_trie comments to know the use of char*& + // + // this code is for when the symbol searching references + // a previous item in search chain + // + // For example: + // searching for X in [A, B, C], + // C has X but it is a re-export from B with the name Y + // then we have to perform a search again from the top + // but with symbol Y + char **symbol_copy = (char **)&symbol; + void *func = find_in_lib(cache, cache_lib, *symbol_copy); + if (*symbol_copy != symbol) { + func = find_in_lib(cache, cache_lib, *symbol_copy); + } + return func; } } return 0; @@ -745,6 +806,7 @@ struct ProgramVars { void build_cache(struct libcache &cache, void *main); void fix(struct libcache &cache); +void find_all_rpath(struct libcache &cache, void *main); void test(struct libcache &cache); @@ -832,6 +894,7 @@ void build_cache(struct libcache &cache, void *main) { printf("lib header at %p\n", thislib); printf("libdyld header at %p\n", libdyld); + find_all_rpath(cache, main); uint32_t trie_size; void *libdyld_export_trie = get_export_trie(libdyld, trie_size); @@ -842,14 +905,20 @@ void build_cache(struct libcache &cache, void *main) { typedef int (*dyld_image_count_t)(void); typedef char *(*dyld_get_image_name_t)(int); typedef void *(*dyld_get_image_header_t)(int); + + char *dyld_image_count_s = (char*)"__dyld_image_count"; int (*dyld_image_count_func)(void) = (dyld_image_count_t)find_in_export_trie( - libdyld, libdyld_export_trie, "__dyld_image_count"); + libdyld, libdyld_export_trie, dyld_image_count_s); + + char *dyld_get_image_header_s = (char*)"__dyld_get_image_header"; void *(*dyld_get_image_header_func)(int) = (dyld_get_image_header_t)find_in_export_trie(libdyld, libdyld_export_trie, - "__dyld_get_image_header"); + dyld_get_image_header_s); + + char *dyld_get_image_name_s = (char*)"__dyld_get_image_name"; char *(*dyld_get_image_name_func)(int) = (dyld_get_image_name_t)find_in_export_trie(libdyld, libdyld_export_trie, - "__dyld_get_image_name"); + dyld_get_image_name_s); cache.size = dyld_image_count_func(); cache.libs = @@ -859,10 +928,46 @@ void build_cache(struct libcache &cache, void *main) { char *name = dyld_get_image_name_func(i); bootstrap_libcache_item(&cache.libs[i], header, name); cache.libs[i].hash = calculate_libname_hash(&cache, name); - // printf("%p %s\n", header, name); + printf("%p %s\n", header, name); } } +// Function to find all rpath entries of the main executable +void find_all_rpath(struct libcache &cache, void *header) { + const uint32_t magic = *(uint32_t *)header; + char *ptr = (char *)header; + if (magic == magic64) { + ptr += 0x20; + } else { + ptr += 0x20 - 0x4; + } + printf("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"); + const uint32_t ncmds = *((uint32_t *)header + 4); + printf("RPATHS:\n"); + cache.nrpath = 0; + for (uint32_t i = 0; i < ncmds; i++) { + const uint32_t cmd = *((uint32_t *)ptr + 0); + const uint32_t cmdsize = *((uint32_t *)ptr + 1); + if (cmd == LC_RPATH) + cache.nrpath++; + ptr += cmdsize; + } + uint32_t idx = 0; + ptr = (char *)header; + ptr += (magic == magic64) ? 0x20 : 0x20 - 0x4; + cache.rpaths = (char **)malloc(sizeof(char *) * cache.nrpath); + for (uint32_t i = 0; i < ncmds; i++) { + const uint32_t cmd = *((uint32_t *)ptr + 0); + const uint32_t cmdsize = *((uint32_t *)ptr + 1); + if (cmd == LC_RPATH) { + cache.rpaths[idx++] = (char *)ptr + 12; + printf("%s\n", cache.rpaths[idx - 1]); + } + ptr += cmdsize; + } + printf("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"); +} + void fix_binds(struct libcache_item *libfixing, struct libcache *cache, int n_ins, uint32_t *instructions, char *libs, char *symbols) { uint32_t libsystem_hash = @@ -1086,7 +1191,7 @@ void fix(struct libcache &cache) { void volatile custom_initializer(int argc, const char *const argv[], const char *const envp[], const char *const apple[]) { - printf("run custom initializers %p\n", custom_initializer_i); + printf("[+] run custom initializers\n"); if (custom_initializer_i->cls != 0) { // for Objective-C load @@ -1155,6 +1260,7 @@ void volatile custom_initializer(int argc, const char *const argv[], free(custom_initializer_i->constructors); } + printf("[+] initializers completed\n"); free(custom_initializer_i); } @@ -1172,6 +1278,7 @@ void fix_objc(struct libcache_item *libfixing, struct libcache &cache) { // "mov rcx, 123;" // "call r12;"); + printf("fixing objective-c\n"); void *header = libfixing->header; const uint32_t magic = *(uint32_t *)header; char *ptr = (char *)header; @@ -1198,6 +1305,50 @@ void fix_objc(struct libcache_item *libfixing, struct libcache &cache) { printf("segment %s\n", name); if (custom_strcmp(name, "__TEXT") == 0) { slide = (uint64_t)header - vmaddr; + + uint64_t nsect = *((uint32_t *)ptr + 8 * 2); + char *sections_ptr = (char *)((uint32_t *)ptr + 18); + for (int sec = 0; sec < nsect; sec++) { + char *secname = sections_ptr; + printf("section %s\n", secname); + if (custom_strncmp(secname, "__objc_methname", 16) == 0) { + uint64_t addr = *((uint64_t *)sections_ptr + 4); + uint64_t size = *((uint64_t *)sections_ptr + 5); + uint64_t *data_ptr = (uint64_t *)(addr + slide); + // printf("methname addr %p : %s\n", data_ptr, (char*)data_ptr); + break; + } + sections_ptr += 16 * 2 + 8 * 2 + 4 * 8; + } + } else if (custom_strcmp(name, "__DATA") == 0) { + uint64_t nsect = *((uint32_t *)ptr + 8 * 2); + char *sections_ptr = (char *)((uint32_t *)ptr + 18); + for (int sec = 0; sec < nsect; sec++) { + char *secname = sections_ptr; + printf("section %s\n", secname); + if (custom_strncmp(secname, "__objc_selrefs", 16) == 0) { + uint64_t addr = *((uint64_t *)sections_ptr + 4); + uint64_t size = *((uint64_t *)sections_ptr + 5); + uint64_t *data_ptr = (uint64_t *)(addr + slide); + + uint32_t trie_size; + char* symbol = (char*)"__dyld_get_objc_selector"; + void *libdyld = cache.libdyld; + void *libdyld_export_trie = get_export_trie(libdyld, trie_size); + typedef void *(*dyld_get_objc_selector_t)(const char *); + dyld_get_objc_selector_t dyld_get_objc_selector_func = + (dyld_get_objc_selector_t)find_in_export_trie( + libdyld, libdyld_export_trie, symbol); + + // resolve method names that cached in the dyld + for (int i = 0; i < bshield_data::n_selectors; i++) { + uint32_t idx = bshield_data::special_selectors_idx[i]; + const char *name = bshield_data::special_selectors_name[i]; + data_ptr[idx] = (uint64_t)dyld_get_objc_selector_func(name); + } + } + sections_ptr += 16 * 2 + 8 * 2 + 4 * 8; + } } else if (custom_strcmp(name, "__DATA_CONST") == 0) { uint64_t nsect = *((uint32_t *)ptr + 8 * 2); char *sections_ptr = (char *)((uint32_t *)ptr + 18); @@ -1355,30 +1506,18 @@ void fix_initializer(struct libcache_item *libfixing, struct libcache &cache) { // (note: __TEXT segment is aligned to the end of the page, free space in the // middle) // - // Below is the shellcode. - /* - adr x8, 0 - # x9 = (offset end of __DATA) - (offset shellcode) - movz x9, #0x9999 - add x8, x8, x9 - - stp x30, x8, [sp], #-0x10 - stp x3, x2, [sp], #-0x10 - stp x1, x0, [sp], #-0x10 - - # custom intializer - ldr x9, [x8] - blr x9 - - ldp x1, x0, [sp, #0x10]! - ldp x3, x2, [sp, #0x10]! - ldp x30, x8, [sp, #0x10]! - - # original main - # link register is set so jump only - ldr x9, [x8, #8] - br x9 - */ + // The shellcode is built using the ios-wrapper tool + // The idea is: + // + // push main arguments + // r8 = shellcode location + // r9 = offset from shellcode to __DATA end + // r8 = r8 + r9 -- get __DATA end address + // r9 = *r8 -- the first pointer is custom_initializer + // call r9 + // r9 = *(r8 + 4) -- the second pointer is main function + // pop main arguments + // jump r9 -- do not call, return to dyld void *header = libfixing->header; const uint32_t magic = *(uint32_t *)header; @@ -1445,7 +1584,9 @@ void fix_initializer(struct libcache_item *libfixing, struct libcache &cache) { uint64_t *dummy = (uint64_t *)(addr + slide + size); dummy[0] = (uint64_t)custom_initializer; dummy[1] = (uint64_t)(header) + bshield_data::main; - printf("add custom main-peg at %p\n", dummy); + printf("-- add custom main-peg at %p\n", dummy); + printf("-- custom initializer at %llx\n", dummy[0]); + printf("-- main function at %llx\n", dummy[1]); } else if (custom_strcmp(name, "__LINKEDIT") == 0) { linkedit_vmaddr = vmaddr; linkedit_fileoffset = fileoffset; diff --git a/research/custom_loader/build.sh b/research/custom_loader/build.sh index b3f84c1..491460b 100755 --- a/research/custom_loader/build.sh +++ b/research/custom_loader/build.sh @@ -2,7 +2,7 @@ VERSION=${1:-14} OUT=./out -LOGIC=3 +LOGIC=${2} mkdir -p $OUT @@ -14,6 +14,21 @@ else echo "Resulting binary uses LEGACY symbol resolver" fi +cat <<'fly' + ______ + _\ _~-\___ + = = ==(____AA____D + \_____\___________________,-~~~~~~~`-.._ + / o O o o o o O O o o o o o o O o |\_ + `~-.__ ___..----.. ) + `---~~\___________/------------````` + = ===(_________D +fly + +# this is a joke for those who knows +# https://www.blackhat.com/presentations/bh-dc-09/Iozzo/BlackHat-DC-09-Iozzo-let-your-mach0-fly-whitepaper.pdf +echo "make your Mach-O fly" + if [[ $LOGIC -eq 0 ]] then @@ -39,7 +54,7 @@ clang++ -mmacosx-version-min=$VERSION -o $OUT/libc.dylib -shared c.cc # create our dummy lib first clang++ -mmacosx-version-min=$VERSION -o $OUT/libb.dylib -shared -Wl,-reexport_library out/libc.dylib dummy.cc # build a references libb -clang++ -mmacosx-version-min=$VERSION -o $OUT/a -L"./out" -lb a.cc +clang++ -mmacosx-version-min=$VERSION -o $OUT/a -L"./out" -Xlinker -no_data_const -lb a.cc # extract symbols from a ../../macho-go/bin/ios-wrapper pepe -o $OUT/a-fixed -b $OUT/b.bcell --remove-imports --remove-exports --remove-symbol-table $OUT/a @@ -64,11 +79,11 @@ clang -fobjc-arc -ObjC -mmacosx-version-min=$VERSION -o $OUT/a -L"./out" -lb a.m # extract symbols from a # ../../macho-go/bin/ios-wrapper pepe -o $OUT/a-fixed -b $OUT/b.bcell --remove-imports --remove-exports --remove-symbol-table --keep-imports _printf $OUT/a -../../macho-go/bin/ios-wrapper pepe -o $OUT/a-fixed -b $OUT/b.bcell --remove-imports --remove-exports $OUT/a +../../macho-go/bin/ios-wrapper pepe -o $OUT/a-fixed -b $OUT/b.bcell --remove-imports --remove-exports --remove-symbol-table --remove-others $OUT/a ../../macho-go/bin/ios-wrapper bcell2header -b $OUT/b.bcell -o $OUT/b.h # build libb with symbols extracted from a clang++ -mmacosx-version-min=$VERSION -o $OUT/libb.dylib -shared -Wl,-reexport_library out/libc.dylib b.cc -../../macho-go/bin/ios-wrapper pepe -o $OUT/libb.dylib -b $OUT/libb.bcell --remove-imports --remove-exports --keep-imports _dyld_get_sdk_version --keep-imports _malloc --keep-imports _printf --keep-imports ___stack_chk_guard $OUT/libb.dylib +../../macho-go/bin/ios-wrapper pepe -o $OUT/libb.dylib -b $OUT/libb.bcell --remove-imports --remove-exports --remove-symbol-table --remove-others --keep-imports _dyld_get_sdk_version --keep-imports _malloc --keep-imports ___stack_chk_guard --keep-imports _printf $OUT/libb.dylib # resign codesign --force --deep -s - $OUT/a-fixed @@ -82,10 +97,37 @@ $OUT/a-fixed else -# dummy test build +# remove imports test -clang++ -mmacosx-version-min=$VERSION -o $OUT/libc.dylib -shared c.cc -clang++ -mmacosx-version-min=$VERSION -o $OUT/libb.dylib -shared -Wl,-reexport_library out/libc.dylib b.cc -clang++ -mmacosx-version-min=$VERSION -o $OUT/a -L"./out" -lb a.cc +# test rpath +clang++ -mmacosx-version-min=$VERSION -o $OUT/libc.dylib -install_name @rpath/libc.dylib -shared c.cc +# linked with libd +# with rpath = $OUT +clang++ -mmacosx-version-min=$VERSION -Xlinker -no_data_const -o $OUT/a \ + -rpath ./heheeeekkkkkkk \ + -rpath $OUT \ + -rpath ./hehe \ + -rpath ./haha \ + $OUT/libc.dylib a.cc \ + +# extract symbols from a +../../macho-go/bin/ios-wrapper pepe -o $OUT/a-fixed -b $OUT/b.bcell -l out/libb.dylib --remove-imports --remove-exports $OUT/a + +# build restoration libb with symbols extracted from a +../../macho-go/bin/ios-wrapper bcell2header -b $OUT/b.bcell -o $OUT/b.h +clang++ -mmacosx-version-min=$VERSION -o $OUT/libb.dylib -shared b.cc + +# obfuscate libb (bugged) +# ../../macho-go/bin/ios-wrapper pepe -o $OUT/libb.dylib -b $OUT/libb.bcell --remove-imports --remove-exports --keep-imports _dyld_get_sdk_version --keep-imports _malloc --keep-imports _printf --keep-imports ___stack_chk_guard $OUT/libb.dylib + +# resign +codesign --force --deep -s - $OUT/a-fixed +codesign --force --deep -s - $OUT/libb.dylib + +# export OBJC_PRINT_LOAD_METHODS=1 +# export OBJC_PRINT_CLASS_SETUP=1 +$OUT/a-fixed +# unset OBJC_PRINT_LOAD_METHODS +# unset OBJC_PRINT_CLASS_SETUP fi diff --git a/research/custom_loader/realizeClassWithoutSwift-decompiled.txt b/research/custom_loader/realizeClassWithoutSwift-decompiled.txt new file mode 100644 index 0000000..efb62b1 --- /dev/null +++ b/research/custom_loader/realizeClassWithoutSwift-decompiled.txt @@ -0,0 +1,57 @@ +struct class { + class* isa; + class* super; + struct { + void* bucket; + void* preoptimize; + } cache; + uint64_t cache_bits; +} + +realizeClassWithoutSwift(class* cls, class* previous) { +// x0 = cls +// x1 = previous + +x19 = x0 +if (!x0) { +return +} + +x28 = x1 +x8 = *x19 - 1 + +if (x8 < 0xf) { +} else { + x8 = x19 + x16 = *(x8 + 0x20) + x9 = x16 + // strip pointer auth x9 + x9 = x9 & 0x7ffffffffff8 + w9 = *x9 + + if (w9 & 0x1f) { + x17 = x8 + x17 = 0xc93a << 48 + // authenticate x16 x17 + x17 = x16 + // strip pointer auth x17 + if (x16 != x17) { + throw + } + x20 = x16 & 0x7ffffffffff8 + x0 = x20 + x0 = malloc_size(x0) + if (x0 > 0x1f) { + return + } + + } else { + w20 = -0x7ff80000 + x21 = x19 + w20 + x0 = x21 + x0 = safe_ro(x0) + x8 = *x0 & 0x1 + } + +} +} diff --git a/research/custom_loader/realizeClassWithoutSwift.txt b/research/custom_loader/realizeClassWithoutSwift.txt new file mode 100644 index 0000000..e31dd98 --- /dev/null +++ b/research/custom_loader/realizeClassWithoutSwift.txt @@ -0,0 +1,657 @@ +libobjc.A.dylib`realizeClassWithoutSwift: + 0x193755cac <+0>: pacibsp + 0x193755cb0 <+4>: sub sp, sp, #0xc0 + 0x193755cb4 <+8>: stp x28, x27, [sp, #0x60] + 0x193755cb8 <+12>: stp x26, x25, [sp, #0x70] + 0x193755cbc <+16>: stp x24, x23, [sp, #0x80] + 0x193755cc0 <+20>: stp x22, x21, [sp, #0x90] + 0x193755cc4 <+24>: stp x20, x19, [sp, #0xa0] + 0x193755cc8 <+28>: stp x29, x30, [sp, #0xb0] + 0x193755ccc <+32>: add x29, sp, #0xb0 + 0x193755cd0 <+36>: mov x19, x0 + 0x193755cd4 <+40>: cbz x0, 0x193756550 ; <+2212> + 0x193755cd8 <+44>: mov x28, x1 + 0x193755cdc <+48>: ldr x8, [x19] + 0x193755ce0 <+52>: sub x8, x8, #0x1 + 0x193755ce4 <+56>: cmp x8, #0xf + 0x193755ce8 <+60>: b.lo 0x193755d08 ; <+92> + 0x193755cec <+64>: mov x8, x19 + 0x193755cf0 <+68>: ldr x16, [x8, #0x20]! + 0x193755cf4 <+72>: mov x9, x16 + 0x193755cf8 <+76>: xpacd x9 + 0x193755cfc <+80>: and x9, x9, #0x7ffffffffff8 + 0x193755d00 <+84>: ldr w9, [x9] + 0x193755d04 <+88>: tbnz w9, #0x1f, 0x1937560e8 ; <+1084> + 0x193755d08 <+92>: mov w20, #-0x7ff80000 + 0x193755d0c <+96>: add x21, x19, #0x20 + 0x193755d10 <+100>: mov x0, x21 + 0x193755d14 <+104>: bl 0x1937753cc ; class_ro_t const* class_data_bits_t::safe_ro<(Authentication)0>() const + 0x193755d18 <+108>: ldr w8, [x0] + 0x193755d1c <+112>: and w26, w8, #0x1 + 0x193755d20 <+116>: tbnz w8, #0x1e, 0x193755d58 ; <+172> + 0x193755d24 <+120>: mov x23, x0 + 0x193755d28 <+124>: mov w0, #0x20 + 0x193755d2c <+128>: mov w1, #0x1 + 0x193755d30 <+132>: bl 0x193786a90 ; symbol stub for: calloc + 0x193755d34 <+136>: mov x22, x0 + 0x193755d38 <+140>: add x8, x0, #0x8 + 0x193755d3c <+144>: ldr x9, [x0, #0x8] + 0x193755d40 <+148>: tbnz w9, #0x0, 0x193755dd8 ; <+300> + 0x193755d44 <+152>: mov x9, x8 + 0x193755d48 <+156>: movk x9, #0x949b, lsl #48 + 0x193755d4c <+160>: mov x17, x23 + 0x193755d50 <+164>: mov x16, x9 + 0x193755d54 <+168>: b 0x193755e08 ; <+348> + 0x193755d58 <+172>: ldr x16, [x21] + 0x193755d5c <+176>: mov x17, x21 + 0x193755d60 <+180>: movk x17, #0xc93a, lsl #48 + 0x193755d64 <+184>: autdb x16, x17 + 0x193755d68 <+188>: mov x17, x16 + 0x193755d6c <+192>: xpacd x17 + 0x193755d70 <+196>: cmp x16, x17 + 0x193755d74 <+200>: b.eq 0x193755d7c ; <+208> + 0x193755d78 <+204>: brk #0xc473 + 0x193755d7c <+208>: and x22, x16, #0x7ffffffffff8 + 0x193755d80 <+212>: mov x0, x22 + 0x193755d84 <+216>: bl 0x193772238 ; class_rw_t::ro() const + 0x193755d88 <+220>: mov x23, x0 + 0x193755d8c <+224>: ldr x16, [x21] + 0x193755d90 <+228>: mov x17, x21 + 0x193755d94 <+232>: movk x17, #0xc93a, lsl #48 + 0x193755d98 <+236>: autdb x16, x17 + 0x193755d9c <+240>: mov x17, x16 + 0x193755da0 <+244>: xpacd x17 + 0x193755da4 <+248>: cmp x16, x17 + 0x193755da8 <+252>: b.eq 0x193755db0 ; <+260> + 0x193755dac <+256>: brk #0xc473 + 0x193755db0 <+260>: and x8, x16, #0x7ffffffffff8 + 0x193755db4 <+264>: mov w9, #0x3ff7ffff + 0x193755db8 <+268>: ldr w10, [x8] + 0x193755dbc <+272>: and w11, w10, w9 + 0x193755dc0 <+276>: orr w11, w11, w20 + 0x193755dc4 <+280>: mov x12, x10 + 0x193755dc8 <+284>: casal w12, w11, [x8] + 0x193755dcc <+288>: cmp w12, w10 + 0x193755dd0 <+292>: b.ne 0x193755db8 ; <+268> + 0x193755dd4 <+296>: b 0x193755e24 ; <+376> + 0x193755dd8 <+300>: and x16, x9, #0xfffffffffffffffe + 0x193755ddc <+304>: mov x17, x8 + 0x193755de0 <+308>: movk x17, #0xe4f, lsl #48 + 0x193755de4 <+312>: autdb x16, x17 + 0x193755de8 <+316>: mov x17, x16 + 0x193755dec <+320>: xpacd x17 + 0x193755df0 <+324>: cmp x16, x17 + 0x193755df4 <+328>: b.eq 0x193755dfc ; <+336> + 0x193755df8 <+332>: brk #0xc473 + 0x193755dfc <+336>: mov x8, x16 + 0x193755e00 <+340>: movk x16, #0xa0d3, lsl #48 + 0x193755e04 <+344>: mov x17, x23 + 0x193755e08 <+348>: pacdb x17, x16 + 0x193755e0c <+352>: str x17, [x8] + 0x193755e10 <+356>: orr w8, w26, w20 + 0x193755e14 <+360>: str w8, [x22] + 0x193755e18 <+364>: mov x0, x21 + 0x193755e1c <+368>: mov x1, x22 + 0x193755e20 <+372>: bl 0x19377576c ; class_data_bits_t::setData(class_rw_t*) + 0x193755e24 <+376>: adrp x8, 50 + 0x193755e28 <+380>: add x8, x8, #0x5c0 ; _objc_empty_cache + 0x193755e2c <+384>: str x8, [x19, #0x10] + 0x193755e30 <+388>: str xzr, [x19, #0x18] + 0x193755e34 <+392>: cbz w26, 0x193755e44 ; <+408> + 0x193755e38 <+396>: add x8, x19, #0x1e + 0x193755e3c <+400>: mov w9, #0x4 + 0x193755e40 <+404>: ldseth w9, w8, [x8] + 0x193755e44 <+408>: adrp x8, 363074 + 0x193755e48 <+412>: ldr w8, [x8, #0x4f0] + 0x193755e4c <+416>: cbnz w8, 0x193756574 ; <+2248> + 0x193755e50 <+420>: mov x27, x19 + 0x193755e54 <+424>: ldr x16, [x27, #0x8]! + 0x193755e58 <+428>: str x22, [sp, #0x40] + 0x193755e5c <+432>: cbz x16, 0x193755e88 ; <+476> + 0x193755e60 <+436>: mov x17, x27 + 0x193755e64 <+440>: movk x17, #0xb5ab, lsl #48 + 0x193755e68 <+444>: autda x16, x17 + 0x193755e6c <+448>: mov x17, x16 + 0x193755e70 <+452>: xpacd x17 + 0x193755e74 <+456>: cmp x16, x17 + 0x193755e78 <+460>: b.eq 0x193755e80 ; <+468> + 0x193755e7c <+464>: brk #0xc472 + 0x193755e80 <+468>: mov x0, x16 + 0x193755e84 <+472>: b 0x193755e8c ; <+480> + 0x193755e88 <+476>: mov x0, #0x0 + 0x193755e8c <+480>: bl 0x19375573c ; remapClass(objc_class*) + 0x193755e90 <+484>: mov x24, x0 + 0x193755e94 <+488>: mov x1, #0x0 + 0x193755e98 <+492>: bl 0x193755cac ; <+0> + 0x193755e9c <+496>: ldr x8, [x19] + 0x193755ea0 <+500>: and x0, x8, #0x7ffffffffff8 + 0x193755ea4 <+504>: bl 0x19375573c ; remapClass(objc_class*) + 0x193755ea8 <+508>: mov x25, x0 + 0x193755eac <+512>: mov x1, #0x0 + 0x193755eb0 <+516>: bl 0x193755cac ; <+0> + 0x193755eb4 <+520>: adrp x20, 373658 + 0x193755eb8 <+524>: cbz w26, 0x193755ecc ; <+544> + 0x193755ebc <+528>: add x8, x19, #0x1e + 0x193755ec0 <+532>: mov w9, #0x2000 + 0x193755ec4 <+536>: ldseth w9, w8, [x8] + 0x193755ec8 <+540>: b 0x193755ee0 ; <+564> + 0x193755ecc <+544>: ldr w8, [x20, #0xa64] + 0x193755ed0 <+548>: cbz w8, 0x193756130 ; <+1156> + 0x193755ed4 <+552>: mov w1, #0x0 + 0x193755ed8 <+556>: mov x0, x19 + 0x193755edc <+560>: bl 0x193757828 ; objc_class::setInstancesRequireRawIsaRecursively(bool) + 0x193755ee0 <+564>: mov x17, x24 + 0x193755ee4 <+568>: mov x8, x27 + 0x193755ee8 <+572>: movk x8, #0xb5ab, lsl #48 + 0x193755eec <+576>: mov x16, x8 + 0x193755ef0 <+580>: pacda x17, x16 + 0x193755ef4 <+584>: str x17, [x27] + 0x193755ef8 <+588>: ldr w8, [x20, #0xa64] + 0x193755efc <+592>: mov x16, x19 + 0x193755f00 <+596>: movk x16, #0x6ae1, lsl #48 + 0x193755f04 <+600>: cbnz w8, 0x193755f2c ; <+640> + 0x193755f08 <+604>: ldrh w8, [x25, #0x1e] + 0x193755f0c <+608>: tbnz w8, #0xd, 0x193755f2c ; <+640> + 0x193755f10 <+612>: mov x17, x25 + 0x193755f14 <+616>: pacda x17, x16 + 0x193755f18 <+620>: and x8, x17, #0x7ffffffffffff8 + 0x193755f1c <+624>: mov x9, #0x1 + 0x193755f20 <+628>: movk x9, #0x100, lsl #48 + 0x193755f24 <+632>: orr x8, x8, x9 + 0x193755f28 <+636>: b 0x193755f38 ; <+652> + 0x193755f2c <+640>: mov x17, x25 + 0x193755f30 <+644>: pacda x17, x16 + 0x193755f34 <+648>: and x8, x17, #0x7ffffffffffff8 + 0x193755f38 <+652>: str x8, [x19] + 0x193755f3c <+656>: cbz x24, 0x193756280 ; <+1492> + 0x193755f40 <+660>: cbnz w26, 0x193756280 ; <+1492> + 0x193755f44 <+664>: ldr x16, [x21] + 0x193755f48 <+668>: mov x17, x21 + 0x193755f4c <+672>: movk x17, #0xc93a, lsl #48 + 0x193755f50 <+676>: autdb x16, x17 + 0x193755f54 <+680>: mov x17, x16 + 0x193755f58 <+684>: xpacd x17 + 0x193755f5c <+688>: cmp x16, x17 + 0x193755f60 <+692>: b.eq 0x193755f68 ; <+700> + 0x193755f64 <+696>: brk #0xc473 + 0x193755f68 <+700>: and x25, x16, #0x7ffffffffff8 + 0x193755f6c <+704>: mov x8, x24 + 0x193755f70 <+708>: ldr x16, [x8, #0x20]! + 0x193755f74 <+712>: mov x17, x8 + 0x193755f78 <+716>: movk x17, #0xc93a, lsl #48 + 0x193755f7c <+720>: autdb x16, x17 + 0x193755f80 <+724>: mov x17, x16 + 0x193755f84 <+728>: xpacd x17 + 0x193755f88 <+732>: cmp x16, x17 + 0x193755f8c <+736>: b.eq 0x193755f94 ; <+744> + 0x193755f90 <+740>: brk #0xc473 + 0x193755f94 <+744>: and x0, x16, #0x7ffffffffff8 + 0x193755f98 <+748>: bl 0x193772238 ; class_rw_t::ro() const + 0x193755f9c <+752>: mov x26, x0 + 0x193755fa0 <+756>: adrp x8, 363071 + 0x193755fa4 <+760>: ldr w8, [x8, #0x3c4] + 0x193755fa8 <+764>: cbz w8, 0x193755fc8 ; <+796> + 0x193755fac <+768>: mov x0, x19 + 0x193755fb0 <+772>: bl 0x193775830 ; objc_class::mangledName() + 0x193755fb4 <+776>: mov x27, x0 + 0x193755fb8 <+780>: adrp x1, 60 + 0x193755fbc <+784>: add x1, x1, #0x660 ; "NSCF" + 0x193755fc0 <+788>: bl 0x193786fb0 ; symbol stub for: strstr + 0x193755fc4 <+792>: cbz x0, 0x1937561b0 ; <+1284> + 0x193755fc8 <+796>: ldr w8, [x23, #0x4] + 0x193755fcc <+800>: ldr w9, [x26, #0x8] + 0x193755fd0 <+804>: cmp w8, w9 + 0x193755fd4 <+808>: b.hs 0x193756280 ; <+1492> + 0x193755fd8 <+812>: adrp x8, 363071 + 0x193755fdc <+816>: ldr w8, [x8, #0x380] + 0x193755fe0 <+820>: cbnz w8, 0x193756688 ; <+2524> + 0x193755fe4 <+824>: mov x0, x25 + 0x193755fe8 <+828>: bl 0x193770194 ; make_ro_writeable(class_rw_t*) + 0x193755fec <+832>: mov x27, x0 + 0x193755ff0 <+836>: mov x0, x25 + 0x193755ff4 <+840>: bl 0x193772238 ; class_rw_t::ro() const + 0x193755ff8 <+844>: mov x23, x0 + 0x193755ffc <+848>: ldr w9, [x26, #0x8] + 0x193756000 <+852>: ldr w8, [x27, #0x4] + 0x193756004 <+856>: sub w26, w9, w8 + 0x193756008 <+860>: ldr x25, [x27, #0x30] + 0x19375600c <+864>: cbz x25, 0x193756264 ; <+1464> + 0x193756010 <+868>: ldp w20, w9, [x25] + 0x193756014 <+872>: mul w22, w9, w20 + 0x193756018 <+876>: cbz w22, 0x193756264 ; <+1464> + 0x19375601c <+880>: mov x8, #0x0 + 0x193756020 <+884>: mov w9, #0x1 + 0x193756024 <+888>: mov w11, #0x8 + 0x193756028 <+892>: mov w10, #0x1 + 0x19375602c <+896>: add x12, x25, x8 + 0x193756030 <+900>: ldr x13, [x12, #0x8] + 0x193756034 <+904>: cbz x13, 0x193756050 ; <+932> + 0x193756038 <+908>: ldr w12, [x12, #0x20] + 0x19375603c <+912>: lsl w13, w9, w12 + 0x193756040 <+916>: cmn w12, #0x1 + 0x193756044 <+920>: csel w12, w11, w13, eq + 0x193756048 <+924>: cmp w12, w10 + 0x19375604c <+928>: csel w10, w12, w10, hi + 0x193756050 <+932>: add x8, x8, x20 + 0x193756054 <+936>: cmp x22, x8 + 0x193756058 <+940>: b.ne 0x19375602c ; <+896> + 0x19375605c <+944>: str x28, [sp, #0x38] + 0x193756060 <+948>: mov x28, #0x0 + 0x193756064 <+952>: add w8, w26, w10 + 0x193756068 <+956>: sub w8, w8, #0x1 + 0x19375606c <+960>: neg w9, w10 + 0x193756070 <+964>: and w26, w8, w9 + 0x193756074 <+968>: adrp x11, 363070 + 0x193756078 <+972>: add x8, x25, x28 + 0x19375607c <+976>: ldr x10, [x8, #0x8] + 0x193756080 <+980>: cbz x10, 0x193756098 ; <+1004> + 0x193756084 <+984>: ldr w8, [x10] + 0x193756088 <+988>: add w9, w8, w26 + 0x19375608c <+992>: str w9, [x10] + 0x193756090 <+996>: ldr w10, [x11, #0x380] + 0x193756094 <+1000>: cbnz w10, 0x1937560a8 ; <+1020> + 0x193756098 <+1004>: add x28, x28, x20 + 0x19375609c <+1008>: cmp x22, x28 + 0x1937560a0 <+1012>: b.ne 0x193756078 ; <+972> + 0x1937560a4 <+1016>: b 0x19375625c ; <+1456> + 0x1937560a8 <+1020>: add x10, x25, x28 + 0x1937560ac <+1024>: ldr x11, [x10, #0x10] + 0x1937560b0 <+1028>: ldp w12, w10, [x10, #0x20] + 0x1937560b4 <+1032>: mov w13, #0x1 + 0x1937560b8 <+1036>: lsl w13, w13, w12 + 0x1937560bc <+1040>: cmn w12, #0x1 + 0x1937560c0 <+1044>: mov w12, #0x8 + 0x1937560c4 <+1048>: csel w12, w12, w13, eq + 0x1937560c8 <+1052>: stp x11, x10, [sp, #0x10] + 0x1937560cc <+1056>: stp x8, x9, [sp] + 0x1937560d0 <+1060>: str x12, [sp, #0x20] + 0x1937560d4 <+1064>: adrp x0, 59 + 0x1937560d8 <+1068>: add x0, x0, #0x71e ; "IVARS: offset %u -> %u for %s (size %u, align %u)" + 0x1937560dc <+1072>: bl 0x19376dd58 ; _objc_inform + 0x1937560e0 <+1076>: adrp x11, 363070 + 0x1937560e4 <+1080>: b 0x193756098 ; <+1004> + 0x1937560e8 <+1084>: mov x17, x8 + 0x1937560ec <+1088>: movk x17, #0xc93a, lsl #48 + 0x1937560f0 <+1092>: autdb x16, x17 + 0x1937560f4 <+1096>: mov x17, x16 + 0x1937560f8 <+1100>: xpacd x17 + 0x1937560fc <+1104>: cmp x16, x17 + 0x193756100 <+1108>: b.eq 0x193756108 ; <+1116> + 0x193756104 <+1112>: brk #0xc473 + 0x193756108 <+1116>: and x20, x16, #0x7ffffffffff8 + 0x19375610c <+1120>: mov x0, x20 + 0x193756110 <+1124>: bl 0x193786c70 ; symbol stub for: malloc_size + 0x193756114 <+1128>: cmp x0, #0x1f + 0x193756118 <+1132>: b.hi 0x193756550 ; <+2212> + 0x19375611c <+1136>: stp x20, x0, [sp, #0x8] + 0x193756120 <+1140>: str x19, [sp] + 0x193756124 <+1144>: adrp x0, 59 + 0x193756128 <+1148>: add x0, x0, #0x61e ; "realized class %p has corrupt data pointer: malloc_size(%p) = %zu" + 0x19375612c <+1152>: bl 0x193785458 ; _objc_fatal(char const*, ...) + 0x193756130 <+1156>: ldrh w22, [x19, #0x1e] + 0x193756134 <+1160>: adrp x8, 373657 + 0x193756138 <+1164>: ldrb w8, [x8, #0xa48] + 0x19375613c <+1168>: tbnz w8, #0x0, 0x193756160 ; <+1204> + 0x193756140 <+1172>: add x8, x23, #0x18 + 0x193756144 <+1176>: ldapr x0, [x8] + 0x193756148 <+1180>: cbz x0, 0x193756160 ; <+1204> + 0x19375614c <+1184>: adrp x1, 59 + 0x193756150 <+1188>: add x1, x1, #0x614 ; "OS_object" + 0x193756154 <+1192>: bl 0x193786f30 ; symbol stub for: strcmp + 0x193756158 <+1196>: adrp x9, 373657 + 0x19375615c <+1200>: cbz w0, 0x193756610 ; <+2404> + 0x193756160 <+1204>: cbz x24, 0x1937561a8 ; <+1276> + 0x193756164 <+1208>: mov x8, x24 + 0x193756168 <+1212>: ldr x16, [x8, #0x8]! + 0x19375616c <+1216>: cbz x16, 0x1937561a8 ; <+1276> + 0x193756170 <+1220>: mov x17, x8 + 0x193756174 <+1224>: movk x17, #0xb5ab, lsl #48 + 0x193756178 <+1228>: autda x16, x17 + 0x19375617c <+1232>: mov x17, x16 + 0x193756180 <+1236>: xpacd x17 + 0x193756184 <+1240>: cmp x16, x17 + 0x193756188 <+1244>: b.eq 0x193756190 ; <+1252> + 0x19375618c <+1248>: brk #0xc472 + 0x193756190 <+1252>: cbz x16, 0x1937561a8 ; <+1276> + 0x193756194 <+1256>: ldrh w8, [x24, #0x1e] + 0x193756198 <+1260>: orr w9, w8, w22 + 0x19375619c <+1264>: tbz w9, #0xd, 0x193755ee0 ; <+564> + 0x1937561a0 <+1268>: ubfx w1, w8, #13, #1 + 0x1937561a4 <+1272>: b 0x193755ed8 ; <+556> + 0x1937561a8 <+1276>: tbnz w22, #0xd, 0x193755ed4 ; <+552> + 0x1937561ac <+1280>: b 0x193755ee0 ; <+564> + 0x1937561b0 <+1284>: adrp x1, 59 + 0x1937561b4 <+1288>: add x1, x1, #0x665 ; "__CF" + 0x1937561b8 <+1292>: mov x0, x27 + 0x1937561bc <+1296>: mov w2, #0x4 + 0x1937561c0 <+1300>: bl 0x193786f90 ; symbol stub for: strncmp + 0x1937561c4 <+1304>: cbz w0, 0x193755fc8 ; <+796> + 0x1937561c8 <+1308>: adrp x1, 59 + 0x1937561cc <+1312>: add x1, x1, #0x66a ; "NSConstantString" + 0x1937561d0 <+1316>: mov x0, x27 + 0x1937561d4 <+1320>: bl 0x193786f30 ; symbol stub for: strcmp + 0x1937561d8 <+1324>: cbz w0, 0x193755fc8 ; <+796> + 0x1937561dc <+1328>: adrp x1, 59 + 0x1937561e0 <+1332>: add x1, x1, #0x67b ; "NSSimpleCString" + 0x1937561e4 <+1336>: mov x0, x27 + 0x1937561e8 <+1340>: bl 0x193786f30 ; symbol stub for: strcmp + 0x1937561ec <+1344>: cbz w0, 0x193755fc8 ; <+796> + 0x1937561f0 <+1348>: ldr w20, [x23, #0x4] + 0x1937561f4 <+1352>: mov x0, x25 + 0x1937561f8 <+1356>: bl 0x193770194 ; make_ro_writeable(class_rw_t*) + 0x1937561fc <+1360>: mov x27, x0 + 0x193756200 <+1364>: mov x0, x25 + 0x193756204 <+1368>: bl 0x193772238 ; class_rw_t::ro() const + 0x193756208 <+1372>: mov x23, x0 + 0x19375620c <+1376>: ldr x8, [x0, #0x30] + 0x193756210 <+1380>: cbz x8, 0x193756620 ; <+2420> + 0x193756214 <+1384>: ldp w9, w10, [x8] + 0x193756218 <+1388>: mul w10, w10, w9 + 0x19375621c <+1392>: mov w11, #0x8 + 0x193756220 <+1396>: cbz w10, 0x193756620 ; <+2420> + 0x193756224 <+1400>: mov x13, #0x0 + 0x193756228 <+1404>: add x14, x8, #0x20 + 0x19375622c <+1408>: mov w15, #0x1 + 0x193756230 <+1412>: mov w12, #0x8 + 0x193756234 <+1416>: ldr w16, [x14, x13] + 0x193756238 <+1420>: lsl w17, w15, w16 + 0x19375623c <+1424>: cmn w16, #0x1 + 0x193756240 <+1428>: csel w16, w11, w17, eq + 0x193756244 <+1432>: cmp w16, w12 + 0x193756248 <+1436>: csel w12, w16, w12, hi + 0x19375624c <+1440>: add x13, x13, x9 + 0x193756250 <+1444>: cmp x10, x13 + 0x193756254 <+1448>: b.ne 0x193756234 ; <+1416> + 0x193756258 <+1452>: b 0x193756624 ; <+2424> + 0x19375625c <+1456>: ldr w8, [x27, #0x4] + 0x193756260 <+1460>: ldr x28, [sp, #0x38] + 0x193756264 <+1464>: add w8, w26, w8 + 0x193756268 <+1468>: ldr w9, [x27, #0x8] + 0x19375626c <+1472>: add w9, w9, w26 + 0x193756270 <+1476>: stp w8, w9, [x27, #0x4] + 0x193756274 <+1480>: add x8, x23, #0x18 + 0x193756278 <+1484>: ldapr xzr, [x8] + 0x19375627c <+1488>: bl 0x1937650d8 ; gdb_objc_class_changed + 0x193756280 <+1492>: ldr w1, [x23, #0x8] + 0x193756284 <+1496>: mov x0, x19 + 0x193756288 <+1500>: bl 0x193775884 ; objc_class::setInstanceSize(unsigned int) + 0x19375628c <+1504>: ldr w8, [x23] + 0x193756290 <+1508>: tbz w8, #0x2, 0x1937562b4 ; <+1544> + 0x193756294 <+1512>: add x9, x19, #0x1e + 0x193756298 <+1516>: mov w8, #0x1 + 0x19375629c <+1520>: ldseth w8, w8, [x9] + 0x1937562a0 <+1524>: ldr w8, [x23] + 0x1937562a4 <+1528>: tbnz w8, #0x8, 0x1937562b4 ; <+1544> + 0x1937562a8 <+1532>: mov w8, #0x2 + 0x1937562ac <+1536>: ldseth w8, w8, [x9] + 0x1937562b0 <+1540>: ldr w8, [x23] + 0x1937562b4 <+1544>: tbnz w8, #0xa, 0x193756304 ; <+1624> + 0x1937562b8 <+1548>: cbz x24, 0x193756358 ; <+1708> + 0x1937562bc <+1552>: mov x8, x24 + 0x1937562c0 <+1556>: ldr x16, [x8, #0x20]! + 0x1937562c4 <+1560>: mov x17, x8 + 0x1937562c8 <+1564>: movk x17, #0xc93a, lsl #48 + 0x1937562cc <+1568>: autdb x16, x17 + 0x1937562d0 <+1572>: mov x17, x16 + 0x1937562d4 <+1576>: xpacd x17 + 0x1937562d8 <+1580>: cmp x16, x17 + 0x1937562dc <+1584>: b.eq 0x1937562e4 ; <+1592> + 0x1937562e0 <+1588>: brk #0xc473 + 0x1937562e4 <+1592>: and x8, x16, #0x7ffffffffff8 + 0x1937562e8 <+1596>: ldrb w8, [x8, #0x2] + 0x1937562ec <+1600>: tbz w8, #0x4, 0x193756318 ; <+1644> + 0x1937562f0 <+1604>: ldr x9, [sp, #0x40] + 0x1937562f4 <+1608>: ldr w8, [x9] + 0x1937562f8 <+1612>: orr w8, w8, #0x100000 + 0x1937562fc <+1616>: str w8, [x9] + 0x193756300 <+1620>: b 0x193756318 ; <+1644> + 0x193756304 <+1624>: ldr x9, [sp, #0x40] + 0x193756308 <+1628>: ldr w8, [x9] + 0x19375630c <+1632>: orr w8, w8, #0x100000 + 0x193756310 <+1636>: str w8, [x9] + 0x193756314 <+1640>: cbz x24, 0x193756358 ; <+1708> + 0x193756318 <+1644>: mov x0, x24 + 0x19375631c <+1648>: mov x1, x19 + 0x193756320 <+1652>: bl 0x1937566e8 ; addSubclass(objc_class*, objc_class*) + 0x193756324 <+1656>: ldr x16, [x19, #0x20] + 0x193756328 <+1660>: mov x20, x21 + 0x19375632c <+1664>: movk x20, #0xc93a, lsl #48 + 0x193756330 <+1668>: mov x17, x21 + 0x193756334 <+1672>: movk x17, #0xc93a, lsl #48 + 0x193756338 <+1676>: autdb x16, x17 + 0x19375633c <+1680>: mov x17, x16 + 0x193756340 <+1684>: xpacd x17 + 0x193756344 <+1688>: cmp x16, x17 + 0x193756348 <+1692>: b.eq 0x193756350 ; <+1700> + 0x19375634c <+1696>: brk #0xc473 + 0x193756350 <+1700>: and x22, x16, #0x7ffffffffff8 + 0x193756354 <+1704>: b 0x1937563a8 ; <+1788> + 0x193756358 <+1708>: adrp x8, 373657 + 0x19375635c <+1712>: ldr x9, [x8, #0x868] + 0x193756360 <+1716>: add x9, x9, #0x1 + 0x193756364 <+1720>: str x9, [x8, #0x868] + 0x193756368 <+1724>: adrp x8, 373657 + 0x19375636c <+1728>: ldr x9, [x8, #0xa50] + 0x193756370 <+1732>: ldr x16, [x19, #0x20] + 0x193756374 <+1736>: mov x20, x21 + 0x193756378 <+1740>: movk x20, #0xc93a, lsl #48 + 0x19375637c <+1744>: mov x17, x21 + 0x193756380 <+1748>: movk x17, #0xc93a, lsl #48 + 0x193756384 <+1752>: autdb x16, x17 + 0x193756388 <+1756>: mov x17, x16 + 0x19375638c <+1760>: xpacd x17 + 0x193756390 <+1764>: cmp x16, x17 + 0x193756394 <+1768>: b.eq 0x19375639c ; <+1776> + 0x193756398 <+1772>: brk #0xc473 + 0x19375639c <+1776>: and x22, x16, #0x7ffffffffff8 + 0x1937563a0 <+1780>: str x9, [x22, #0x18] + 0x1937563a4 <+1784>: str x19, [x8, #0xa50] + 0x1937563a8 <+1788>: ldrh w23, [x19, #0x1e] + 0x1937563ac <+1792>: mov x0, x22 + 0x1937563b0 <+1796>: bl 0x193772238 ; class_rw_t::ro() const + 0x1937563b4 <+1800>: mov x21, x0 + 0x1937563b8 <+1804>: ldr x8, [x22, #0x8] + 0x1937563bc <+1808>: tbz w8, #0x0, 0x1937563f4 ; <+1864> + 0x1937563c0 <+1812>: ands x16, x8, #0xfffffffffffffffe + 0x1937563c4 <+1816>: b.eq 0x1937563f4 ; <+1864> + 0x1937563c8 <+1820>: add x8, x22, #0x8 + 0x1937563cc <+1824>: mov x17, x8 + 0x1937563d0 <+1828>: movk x17, #0xe4f, lsl #48 + 0x1937563d4 <+1832>: autdb x16, x17 + 0x1937563d8 <+1836>: mov x17, x16 + 0x1937563dc <+1840>: xpacd x17 + 0x1937563e0 <+1844>: cmp x16, x17 + 0x1937563e4 <+1848>: b.eq 0x1937563ec ; <+1856> + 0x1937563e8 <+1852>: brk #0xc473 + 0x1937563ec <+1856>: mov x22, x16 + 0x1937563f0 <+1860>: b 0x1937563f8 ; <+1868> + 0x1937563f4 <+1864>: mov x22, #0x0 + 0x1937563f8 <+1868>: adrp x8, 363073 + 0x1937563fc <+1872>: ldr w8, [x8, #0x4f0] + 0x193756400 <+1876>: cbnz w8, 0x1937565dc ; <+2352> + 0x193756404 <+1880>: mov x8, x21 + 0x193756408 <+1884>: ldr x16, [x8, #0x20]! + 0x19375640c <+1888>: cbz x16, 0x19375648c ; <+2016> + 0x193756410 <+1892>: mov x17, x8 + 0x193756414 <+1896>: movk x17, #0xc310, lsl #48 + 0x193756418 <+1900>: autda x16, x17 + 0x19375641c <+1904>: mov x17, x16 + 0x193756420 <+1908>: xpacd x17 + 0x193756424 <+1912>: cmp x16, x17 + 0x193756428 <+1916>: b.eq 0x193756430 ; <+1924> + 0x19375642c <+1920>: brk #0xc472 + 0x193756430 <+1924>: str x16, [sp, #0x58] + 0x193756434 <+1928>: cbz x16, 0x193756490 ; <+2020> + 0x193756438 <+1932>: ldr x16, [x19, #0x20] + 0x19375643c <+1936>: autdb x16, x20 + 0x193756440 <+1940>: mov x17, x16 + 0x193756444 <+1944>: xpacd x17 + 0x193756448 <+1948>: cmp x16, x17 + 0x19375644c <+1952>: b.eq 0x193756454 ; <+1960> + 0x193756450 <+1956>: brk #0xc473 + 0x193756454 <+1960>: and x0, x16, #0x7ffffffffff8 + 0x193756458 <+1964>: bl 0x193772238 ; class_rw_t::ro() const + 0x19375645c <+1968>: ldr w8, [x0] + 0x193756460 <+1972>: ubfx w3, w8, #29, #1 + 0x193756464 <+1976>: add x1, sp, #0x58 + 0x193756468 <+1980>: mov x0, x19 + 0x19375646c <+1984>: mov w2, #0x1 + 0x193756470 <+1988>: bl 0x193775914 ; prepareMethodLists(objc_class*, method_list_t**, int, bool, bool, char const*) + 0x193756474 <+1992>: cbz x22, 0x1937564dc ; <+2096> + 0x193756478 <+1996>: add x0, x22, #0x8 + 0x19375647c <+2000>: add x1, sp, #0x58 + 0x193756480 <+2004>: mov w2, #0x1 + 0x193756484 <+2008>: bl 0x1937749ac ; list_array_tt::attachLists(method_list_t* const*, unsigned int) + 0x193756488 <+2012>: b 0x193756490 ; <+2020> + 0x19375648c <+2016>: str xzr, [sp, #0x58] + 0x193756490 <+2020>: ldr x8, [x21, #0x40] + 0x193756494 <+2024>: str x8, [sp, #0x50] + 0x193756498 <+2028>: cmp x22, #0x0 + 0x19375649c <+2032>: cset w20, ne + 0x1937564a0 <+2036>: cbz x22, 0x1937564bc ; <+2064> + 0x1937564a4 <+2040>: cbz x8, 0x1937564bc ; <+2064> + 0x1937564a8 <+2044>: add x0, x22, #0x10 + 0x1937564ac <+2048>: mov w20, #0x1 + 0x1937564b0 <+2052>: add x1, sp, #0x50 + 0x1937564b4 <+2056>: mov w2, #0x1 + 0x1937564b8 <+2060>: bl 0x193774c28 ; list_array_tt::attachLists(property_list_t* const*, unsigned int) + 0x1937564bc <+2064>: ldr x8, [x21, #0x28] + 0x1937564c0 <+2068>: str x8, [sp, #0x48] + 0x1937564c4 <+2072>: cbz w20, 0x1937564dc ; <+2096> + 0x1937564c8 <+2076>: cbz x8, 0x1937564dc ; <+2096> + 0x1937564cc <+2080>: add x0, x22, #0x18 + 0x1937564d0 <+2084>: add x1, sp, #0x48 + 0x1937564d4 <+2088>: mov w2, #0x1 + 0x1937564d8 <+2092>: bl 0x193774d78 ; list_array_tt::attachLists(protocol_list_t* const*, unsigned int) + 0x1937564dc <+2096>: ldr x8, [x19] + 0x1937564e0 <+2100>: and x8, x8, #0x7ffffffffff8 + 0x1937564e4 <+2104>: cmp x8, x19 + 0x1937564e8 <+2108>: b.ne 0x193756518 ; <+2156> + 0x1937564ec <+2112>: adrp x8, 326768 + 0x1937564f0 <+2116>: add x1, x8, #0x2f + 0x1937564f4 <+2120>: adrp x3, 61 + 0x1937564f8 <+2124>: add x3, x3, #0xbf3 ; "" + 0x1937564fc <+2128>: adrp x16, 42 + 0x193756500 <+2132>: add x16, x16, #0xb74 ; objc_noop_imp + 0x193756504 <+2136>: paciza x16 + 0x193756508 <+2140>: mov x2, x16 + 0x19375650c <+2144>: mov x0, x19 + 0x193756510 <+2148>: mov w4, #0x0 + 0x193756514 <+2152>: bl 0x1937568a8 ; addMethod(objc_class*, objc_selector*, void (*)(), char const*, bool) + 0x193756518 <+2156>: cbz x28, 0x193756538 ; <+2188> + 0x19375651c <+2160>: tst w23, #0x4 + 0x193756520 <+2164>: mov w8, #0x2 + 0x193756524 <+2168>: mov w9, #0x4 + 0x193756528 <+2172>: csel w2, w9, w8, eq + 0x19375652c <+2176>: mov x0, x19 + 0x193756530 <+2180>: mov x1, x28 + 0x193756534 <+2184>: bl 0x19375714c ; objc::UnattachedCategories::attachToClass(objc_class*, objc_class*, int) + 0x193756538 <+2188>: tst w23, #0x4 + 0x19375653c <+2192>: mov w8, #0x1 + 0x193756540 <+2196>: cinc w2, w8, ne + 0x193756544 <+2200>: mov x0, x19 + 0x193756548 <+2204>: mov x1, x19 + 0x19375654c <+2208>: bl 0x19375714c ; objc::UnattachedCategories::attachToClass(objc_class*, objc_class*, int) + 0x193756550 <+2212>: mov x0, x19 + 0x193756554 <+2216>: ldp x29, x30, [sp, #0xb0] + 0x193756558 <+2220>: ldp x20, x19, [sp, #0xa0] + 0x19375655c <+2224>: ldp x22, x21, [sp, #0x90] + 0x193756560 <+2228>: ldp x24, x23, [sp, #0x80] + 0x193756564 <+2232>: ldp x26, x25, [sp, #0x70] + 0x193756568 <+2236>: ldp x28, x27, [sp, #0x60] + 0x19375656c <+2240>: add sp, sp, #0xc0 +-> 0x193756570 <+2244>: retab + 0x193756574 <+2248>: mov x0, x19 + 0x193756578 <+2252>: bl 0x193775470 ; objc_class::nameForLogging() + 0x19375657c <+2256>: adrp x8, 61 + 0x193756580 <+2260>: add x8, x8, #0xbf3 ; "" + 0x193756584 <+2264>: adrp x9, 59 + 0x193756588 <+2268>: add x9, x9, #0x111 ; " (meta)" + 0x19375658c <+2272>: cmp w26, #0x0 + 0x193756590 <+2276>: csel x9, x9, x8, ne + 0x193756594 <+2280>: ldr x10, [x19, #0x20] + 0x193756598 <+2284>: adrp x11, 59 + 0x19375659c <+2288>: add x11, x11, #0x5f9 ; "(swift)" + 0x1937565a0 <+2292>: tst x10, #0x2 + 0x1937565a4 <+2296>: csel x11, x8, x11, eq + 0x1937565a8 <+2300>: adrp x12, 59 + 0x1937565ac <+2304>: add x12, x12, #0x601 ; "(pre-stable swift)" + 0x1937565b0 <+2308>: tst x10, #0x1 + 0x1937565b4 <+2312>: csel x8, x8, x12, eq + 0x1937565b8 <+2316>: stp x11, x8, [sp, #0x28] + 0x1937565bc <+2320>: stp x23, xzr, [sp, #0x18] + 0x1937565c0 <+2324>: stp x9, x19, [sp, #0x8] + 0x1937565c4 <+2328>: adrp x8, 59 + 0x1937565c8 <+2332>: add x8, x8, #0x5cc ; "CLASS: realizing class '%s'%s %p %p #%u %s%s" + 0x1937565cc <+2336>: str x0, [sp] + 0x1937565d0 <+2340>: mov x0, x8 + 0x1937565d4 <+2344>: bl 0x19376dd58 ; _objc_inform + 0x1937565d8 <+2348>: b 0x193755e50 ; <+420> + 0x1937565dc <+2352>: mov x0, x19 + 0x1937565e0 <+2356>: bl 0x193775470 ; objc_class::nameForLogging() + 0x1937565e4 <+2360>: adrp x8, 59 + 0x1937565e8 <+2364>: add x8, x8, #0x774 ; "(meta)" + 0x1937565ec <+2368>: adrp x9, 61 + 0x1937565f0 <+2372>: add x9, x9, #0xbf3 ; "" + 0x1937565f4 <+2376>: tst w23, #0x4 + 0x1937565f8 <+2380>: csel x8, x9, x8, eq + 0x1937565fc <+2384>: stp x0, x8, [sp] + 0x193756600 <+2388>: adrp x0, 59 + 0x193756604 <+2392>: add x0, x0, #0x753 ; "CLASS: methodizing class '%s' %s" + 0x193756608 <+2396>: bl 0x19376dd58 ; _objc_inform + 0x19375660c <+2400>: b 0x193756404 ; <+1880> + 0x193756610 <+2404>: mov w1, #0x0 + 0x193756614 <+2408>: mov w8, #0x1 + 0x193756618 <+2412>: strb w8, [x9, #0xa48] + 0x19375661c <+2416>: b 0x193755ed8 ; <+556> + 0x193756620 <+2420>: mov w12, #0x8 + 0x193756624 <+2424>: ldr w9, [x23, #0x4] + 0x193756628 <+2428>: udiv w10, w9, w12 + 0x19375662c <+2432>: mul w22, w10, w12 + 0x193756630 <+2436>: sub w9, w9, w22 + 0x193756634 <+2440>: ldr w10, [x27, #0x8] + 0x193756638 <+2444>: sub w10, w10, w22 + 0x19375663c <+2448>: stp w9, w10, [x27, #0x4] + 0x193756640 <+2452>: adrp x9, 363070 + 0x193756644 <+2456>: ldr w9, [x9, #0x380] + 0x193756648 <+2460>: cbnz w9, 0x1937566b0 ; <+2564> + 0x19375664c <+2464>: cbz x8, 0x193755fc8 ; <+796> + 0x193756650 <+2468>: ldp w9, w10, [x8] + 0x193756654 <+2472>: mul w10, w10, w9 + 0x193756658 <+2476>: cbz w10, 0x193755fc8 ; <+796> + 0x19375665c <+2480>: mov x11, #0x0 + 0x193756660 <+2484>: add x8, x8, #0x8 + 0x193756664 <+2488>: ldr x12, [x8, x11] + 0x193756668 <+2492>: cbz x12, 0x193756678 ; <+2508> + 0x19375666c <+2496>: ldr w13, [x12] + 0x193756670 <+2500>: sub w13, w13, w22 + 0x193756674 <+2504>: str w13, [x12] + 0x193756678 <+2508>: add x11, x11, x9 + 0x19375667c <+2512>: cmp x10, x11 + 0x193756680 <+2516>: b.ne 0x193756664 ; <+2488> + 0x193756684 <+2520>: b 0x193755fc8 ; <+796> + 0x193756688 <+2524>: mov x0, x19 + 0x19375668c <+2528>: bl 0x193775470 ; objc_class::nameForLogging() + 0x193756690 <+2532>: ldr w8, [x23, #0x4] + 0x193756694 <+2536>: ldr w9, [x26, #0x8] + 0x193756698 <+2540>: stp x8, x9, [sp, #0x8] + 0x19375669c <+2544>: str x0, [sp] + 0x1937566a0 <+2548>: adrp x0, 59 + 0x1937566a4 <+2552>: add x0, x0, #0x6da ; "IVARS: sliding ivars for class %s (superclass was %u bytes, now %u)" + 0x1937566a8 <+2556>: bl 0x19376dd58 ; _objc_inform + 0x1937566ac <+2560>: b 0x193755fe4 ; <+824> + 0x1937566b0 <+2564>: mov x0, x19 + 0x1937566b4 <+2568>: bl 0x193775470 ; objc_class::nameForLogging() + 0x1937566b8 <+2572>: ldr w8, [x23, #0x4] + 0x1937566bc <+2576>: stp x20, x8, [sp, #0x8] + 0x1937566c0 <+2580>: str x0, [sp] + 0x1937566c4 <+2584>: adrp x0, 59 + 0x1937566c8 <+2588>: add x0, x0, #0x68b ; "IVARS: DEBUG: forcing ivars for class '%s' to slide (instanceStart %zu -> %zu)" + 0x1937566cc <+2592>: bl 0x19376dd58 ; _objc_inform + 0x1937566d0 <+2596>: ldr x8, [x23, #0x30] + 0x1937566d4 <+2600>: cbnz x8, 0x193756650 ; <+2468> + 0x1937566d8 <+2604>: b 0x193755fc8 ; <+796> + 0x1937566dc <+2608>: udf #0x0 + 0x1937566e0 <+2612>: udf #0x0 + 0x1937566e4 <+2616>: udf #0x0 + diff --git a/research/custom_loader/schedule_class_load.txt b/research/custom_loader/schedule_class_load.txt new file mode 100644 index 0000000..39d2ca5 --- /dev/null +++ b/research/custom_loader/schedule_class_load.txt @@ -0,0 +1,93 @@ +libobjc.A.dylib`schedule_class_load: +libobjc.A.dylib[0x1800687c8] <+0>: pacibsp +libobjc.A.dylib[0x1800687cc] <+4>: sub sp, sp, #0x50 +libobjc.A.dylib[0x1800687d0] <+8>: stp x24, x23, [sp, #0x10] +libobjc.A.dylib[0x1800687d4] <+12>: stp x22, x21, [sp, #0x20] +libobjc.A.dylib[0x1800687d8] <+16>: stp x20, x19, [sp, #0x30] +libobjc.A.dylib[0x1800687dc] <+20>: stp x29, x30, [sp, #0x40] +libobjc.A.dylib[0x1800687e0] <+24>: add x29, sp, #0x40 +libobjc.A.dylib[0x1800687e4] <+28>: cbz x0, 0x1800688fc ; <+308> +libobjc.A.dylib[0x1800687e8] <+32>: mov x19, x0 +libobjc.A.dylib[0x1800687ec] <+36>: mov x21, x0 +libobjc.A.dylib[0x1800687f0] <+40>: ldr x16, [x21, #0x20]! +libobjc.A.dylib[0x1800687f4] <+44>: mov x17, x21 +libobjc.A.dylib[0x1800687f8] <+48>: movk x17, #0xc93a, lsl #48 +libobjc.A.dylib[0x1800687fc] <+52>: autdb x16, x17 +libobjc.A.dylib[0x180068800] <+56>: mov x17, x16 +libobjc.A.dylib[0x180068804] <+60>: xpacd x17 +libobjc.A.dylib[0x180068808] <+64>: cmp x16, x17 +libobjc.A.dylib[0x18006880c] <+68>: b.eq 0x180068814 ; <+76> +libobjc.A.dylib[0x180068810] <+72>: brk #0xc473 +libobjc.A.dylib[0x180068814] <+76>: and x8, x16, #0x7ffffffffff8 +libobjc.A.dylib[0x180068818] <+80>: ldrb w8, [x8, #0x2] +libobjc.A.dylib[0x18006881c] <+84>: tbnz w8, #0x7, 0x1800688fc ; <+308> +libobjc.A.dylib[0x180068820] <+88>: mov x8, x19 +libobjc.A.dylib[0x180068824] <+92>: ldr x16, [x8, #0x8]! +libobjc.A.dylib[0x180068828] <+96>: cbz x16, 0x180068854 ; <+140> +libobjc.A.dylib[0x18006882c] <+100>: mov x17, x8 +libobjc.A.dylib[0x180068830] <+104>: movk x17, #0xb5ab, lsl #48 +libobjc.A.dylib[0x180068834] <+108>: autda x16, x17 +libobjc.A.dylib[0x180068838] <+112>: mov x17, x16 +libobjc.A.dylib[0x18006883c] <+116>: xpacd x17 +libobjc.A.dylib[0x180068840] <+120>: cmp x16, x17 +libobjc.A.dylib[0x180068844] <+124>: b.eq 0x18006884c ; <+132> +libobjc.A.dylib[0x180068848] <+128>: brk #0xc472 +libobjc.A.dylib[0x18006884c] <+132>: mov x0, x16 +libobjc.A.dylib[0x180068850] <+136>: b 0x180068858 ; <+144> +libobjc.A.dylib[0x180068854] <+140>: mov x0, #0x0 +libobjc.A.dylib[0x180068858] <+144>: bl 0x1800687c8 ; <+0> +libobjc.A.dylib[0x18006885c] <+148>: ldr x0, [x19] +libobjc.A.dylib[0x180068860] <+152>: bl 0x18007b0d8 ; objc_class::getLoadMethod() +libobjc.A.dylib[0x180068864] <+156>: cbz x0, 0x1800688cc ; <+260> +libobjc.A.dylib[0x180068868] <+160>: mov x20, x0 +libobjc.A.dylib[0x18006886c] <+164>: adrp x8, 363064 +libobjc.A.dylib[0x180068870] <+168>: ldr w8, [x8, #0x374] +libobjc.A.dylib[0x180068874] <+172>: cbnz w8, 0x180068914 ; <+332> +libobjc.A.dylib[0x180068878] <+176>: adrp x22, 363064 +libobjc.A.dylib[0x18006887c] <+180>: ldrsw x23, [x22, #0x220] +libobjc.A.dylib[0x180068880] <+184>: adrp x8, 363064 +libobjc.A.dylib[0x180068884] <+188>: ldr w9, [x8, #0x224] +libobjc.A.dylib[0x180068888] <+192>: cmp w23, w9 +libobjc.A.dylib[0x18006888c] <+196>: b.ne 0x1800688b4 ; <+236> +libobjc.A.dylib[0x180068890] <+200>: lsl w9, w23, #1 +libobjc.A.dylib[0x180068894] <+204>: add w9, w9, #0x10 +libobjc.A.dylib[0x180068898] <+208>: str w9, [x8, #0x224] +libobjc.A.dylib[0x18006889c] <+212>: adrp x24, 363064 +libobjc.A.dylib[0x1800688a0] <+216>: ldr x0, [x24, #0x228] +libobjc.A.dylib[0x1800688a4] <+220>: sbfiz x1, x9, #4, #32 +libobjc.A.dylib[0x1800688a8] <+224>: bl 0x180092ec0 ; symbol stub for: realloc +libobjc.A.dylib[0x1800688ac] <+228>: str x0, [x24, #0x228] +libobjc.A.dylib[0x1800688b0] <+232>: b 0x1800688bc ; <+244> +libobjc.A.dylib[0x1800688b4] <+236>: adrp x8, 363064 +libobjc.A.dylib[0x1800688b8] <+240>: ldr x0, [x8, #0x228] +libobjc.A.dylib[0x1800688bc] <+244>: add x8, x0, x23, lsl #4 +libobjc.A.dylib[0x1800688c0] <+248>: stp x19, x20, [x8] +libobjc.A.dylib[0x1800688c4] <+252>: add w8, w23, #0x1 +libobjc.A.dylib[0x1800688c8] <+256>: str w8, [x22, #0x220] +libobjc.A.dylib[0x1800688cc] <+260>: ldr x16, [x21] +libobjc.A.dylib[0x1800688d0] <+264>: mov x17, x21 +libobjc.A.dylib[0x1800688d4] <+268>: movk x17, #0xc93a, lsl #48 +libobjc.A.dylib[0x1800688d8] <+272>: autdb x16, x17 +libobjc.A.dylib[0x1800688dc] <+276>: mov x17, x16 +libobjc.A.dylib[0x1800688e0] <+280>: xpacd x17 +libobjc.A.dylib[0x1800688e4] <+284>: cmp x16, x17 +libobjc.A.dylib[0x1800688e8] <+288>: b.eq 0x1800688f0 ; <+296> +libobjc.A.dylib[0x1800688ec] <+292>: brk #0xc473 +libobjc.A.dylib[0x1800688f0] <+296>: and x8, x16, #0x7ffffffffff8 +libobjc.A.dylib[0x1800688f4] <+300>: mov w9, #0x800000 +libobjc.A.dylib[0x1800688f8] <+304>: ldset w9, w8, [x8] +libobjc.A.dylib[0x1800688fc] <+308>: ldp x29, x30, [sp, #0x40] +libobjc.A.dylib[0x180068900] <+312>: ldp x20, x19, [sp, #0x30] +libobjc.A.dylib[0x180068904] <+316>: ldp x22, x21, [sp, #0x20] +libobjc.A.dylib[0x180068908] <+320>: ldp x24, x23, [sp, #0x10] +libobjc.A.dylib[0x18006890c] <+324>: add sp, sp, #0x50 +libobjc.A.dylib[0x180068910] <+328>: retab +libobjc.A.dylib[0x180068914] <+332>: mov x0, x19 +libobjc.A.dylib[0x180068918] <+336>: bl 0x180081470 ; objc_class::nameForLogging() +libobjc.A.dylib[0x18006891c] <+340>: str x0, [sp] +libobjc.A.dylib[0x180068920] <+344>: adrp x0, 52 +libobjc.A.dylib[0x180068924] <+348>: add x0, x0, #0x7e6 ; "LOAD: class '%s' scheduled for +load" +libobjc.A.dylib[0x180068928] <+352>: bl 0x180079d58 ; _objc_inform +libobjc.A.dylib[0x18006892c] <+356>: b 0x180068878 ; <+176> +libobjc.A.dylib[0x180068930] <+360>: udf #0x0 +