Compare commits
18 Commits
Author | SHA1 | Date | |
---|---|---|---|
465aed7ba1 | |||
998d5844e7 | |||
78a8ca45d5 | |||
3e99eff22d | |||
8be97742c9 | |||
06525b8a5e | |||
57b0ae26a7 | |||
f795e9b99d | |||
792316f4ea | |||
62fa58f039 | |||
62daeb1c52 | |||
37c2f93383 | |||
901f1ed819 | |||
41144ff0dc | |||
9a8ab15d88 | |||
a8ffae5202 | |||
9ec2a301b4 | |||
a68bbf2b8f |
@ -9,3 +9,6 @@ build-linux:
|
||||
|
||||
module:
|
||||
go get -u google.golang.org/protobuf/cmd/protoc-gen-go
|
||||
|
||||
format:
|
||||
go fmt ./...
|
||||
|
@ -68,7 +68,7 @@ func (action *saveImports) saveToInfo(mf *MachoFile) error {
|
||||
// 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
|
||||
}
|
||||
|
||||
@ -138,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
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
@ -46,6 +46,8 @@ func (printer *InfoPrinter) Print() {
|
||||
)
|
||||
}
|
||||
|
||||
mc.CollectObjectiveCClasses()
|
||||
|
||||
fmt.Println("======")
|
||||
}
|
||||
}
|
||||
|
@ -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)))
|
||||
|
@ -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,254 +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
|
||||
*/
|
||||
shellcode := []uint32{}
|
||||
ins_size_byte := 4
|
||||
main_offset := int(mc.entryoff)
|
||||
var shellcode_offset int
|
||||
|
||||
isArm := (mc.header.cputype & 0xff) == 12
|
||||
if isArm {
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ┌─────────────────┐
|
||||
// │ │
|
||||
// shellcode starts ────┼─────────────────┼───── │ │instruction
|
||||
// │ │ │ │fetch RIP size
|
||||
// RIP returns ────┼─────────────────┼───── ▲ │ │
|
||||
// │ │ │ │
|
||||
// │ │ │ │ shellcode length
|
||||
// shellcode ends │ │ │ offset │
|
||||
// __text ────┼─────────────────┼───── │ range │
|
||||
// │ │ │ │ __DATA ends - __text
|
||||
// │ │ │ │
|
||||
// __DATA ends ────┼─────────────────┼───── ▼ │
|
||||
// │ │
|
||||
// │ │
|
||||
// │ │
|
||||
// │ │
|
||||
// │ │
|
||||
// └─────────────────┘
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
func (mc *MachoContext) RewriteImportsTable(keepSymbols []string) {
|
||||
allSymbols := mc.CollectBindSymbols()
|
||||
fixups, fixupsOffset := mc.Fixups()
|
||||
@ -730,10 +483,10 @@ func (mc *MachoContext) removeSymtabCommand() {
|
||||
fmt.Printf("// Erase at=0x%x size=0x%x\n", start, size)
|
||||
mc.file.WriteAt(make([]byte, size), start)
|
||||
|
||||
symtab_fix.symoff = 0
|
||||
symtab_fix.nsyms = 0
|
||||
symtab_fix.stroff = 0
|
||||
symtab_fix.strsize = 0
|
||||
// symtab_fix.symoff = 0
|
||||
// symtab_fix.nsyms = 0
|
||||
// symtab_fix.stroff = 0
|
||||
// symtab_fix.strsize = 0
|
||||
mc.file.Seek(ptr, io.SeekStart)
|
||||
mc.file.Write(symtab_fix.Serialize(mc))
|
||||
break
|
||||
|
524
macho-go/pkg/ios/macho/objc.go
Normal file
524
macho-go/pkg/ios/macho/objc.go
Normal file
@ -0,0 +1,524 @@
|
||||
package macho
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
. "ios-wrapper/pkg/ios"
|
||||
)
|
||||
|
||||
// #include "fixups.h"
|
||||
import "C"
|
||||
|
||||
func (mc *MachoContext) CollectObjectiveCClasses() {
|
||||
var objc_const *bytes.Reader
|
||||
var objc_const_start uint64
|
||||
var objc_const_end uint64
|
||||
// var objc_methname []byte
|
||||
|
||||
for _, cmd := range mc.commands {
|
||||
if cmd.Cmd() == LC_MAIN {
|
||||
continue
|
||||
}
|
||||
if cmd.Cmd() != LC_SEGMENT_64 {
|
||||
continue
|
||||
}
|
||||
var segment = cmd.(*Segment64)
|
||||
|
||||
// we assume the binary comes in perfect ordering, that is as laid out below
|
||||
|
||||
if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__TEXT")) == 0 {
|
||||
for _, section := range segment.Sections() {
|
||||
buffer := make([]byte, section.Size())
|
||||
mc.file.ReadAt(buffer, int64(section.Offset()))
|
||||
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_stubs")) == 0 {
|
||||
}
|
||||
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_methlist")) == 0 {
|
||||
}
|
||||
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_methname")) == 0 {
|
||||
// objc_methname := buffer
|
||||
}
|
||||
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_classname")) == 0 {
|
||||
}
|
||||
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_methtype")) == 0 {
|
||||
}
|
||||
}
|
||||
}
|
||||
if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__DATA_CONST")) == 0 {
|
||||
for _, section := range segment.Sections() {
|
||||
buffer := make([]byte, section.Size())
|
||||
mc.file.ReadAt(buffer, int64(section.Offset()))
|
||||
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_classlist")) == 0 {
|
||||
}
|
||||
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_nlclslist")) == 0 {
|
||||
}
|
||||
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_imageinfo")) == 0 {
|
||||
}
|
||||
}
|
||||
}
|
||||
if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__DATA")) == 0 {
|
||||
for _, section := range segment.Sections() {
|
||||
buffer := make([]byte, section.Size())
|
||||
mc.file.ReadAt(buffer, int64(section.Offset()))
|
||||
reader := bytes.NewReader(buffer)
|
||||
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_const")) == 0 {
|
||||
objc_const = reader
|
||||
objc_const_start = uint64(section.Offset())
|
||||
objc_const_end = objc_const_start + section.Size()
|
||||
}
|
||||
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_selrefs")) == 0 {
|
||||
}
|
||||
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_classrefs")) == 0 {
|
||||
}
|
||||
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_superrefs")) == 0 {
|
||||
}
|
||||
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_data")) == 0 {
|
||||
// this section contains a series of class_t
|
||||
// struct _class_t {
|
||||
// struct _class_t *isa;
|
||||
// struct _class_t * const superclass;
|
||||
// void *cache;
|
||||
// IMP *vtable;
|
||||
// struct class_ro_t *ro;
|
||||
// };
|
||||
|
||||
for i := uint64(0); i < (section.Size() / uint64(mc.pointersize*5)); i++ {
|
||||
var isa uint64
|
||||
var superclass uint64
|
||||
var cache uint64
|
||||
var vtable uint64
|
||||
var ro uint64
|
||||
binary.Read(reader, mc.byteorder, &isa)
|
||||
binary.Read(reader, mc.byteorder, &superclass)
|
||||
binary.Read(reader, mc.byteorder, &cache)
|
||||
binary.Read(reader, mc.byteorder, &vtable)
|
||||
binary.Read(reader, mc.byteorder, &ro)
|
||||
|
||||
fmt.Printf("at=0x%x\n", section.Offset()+uint32(i)*mc.pointersize*5)
|
||||
fmt.Printf("isa=0x%x superclass=0x%x\n", isa, superclass)
|
||||
fmt.Printf("cache=0x%x vtable=0x%x\n", cache, vtable)
|
||||
fmt.Printf("ro=0x%x\n", ro)
|
||||
|
||||
var bind int
|
||||
var ret1 uint64
|
||||
var ret2 uint64
|
||||
C.ParseFixValue(C.int(2), C.uint64_t(ro),
|
||||
(*C.int)(unsafe.Pointer(&bind)),
|
||||
(*C.uint64_t)(unsafe.Pointer(&ret1)),
|
||||
(*C.uint64_t)(unsafe.Pointer(&ret2)),
|
||||
)
|
||||
|
||||
// is rebase, because ro points to objc_const
|
||||
// and address is in range
|
||||
if bind != 1 && ret1 >= objc_const_start && ret1 < objc_const_end {
|
||||
offset := ret1 - objc_const_start
|
||||
objc_const.Seek(int64(offset), 0)
|
||||
|
||||
// struct _class_ro_t {
|
||||
// uint32_t const flags;
|
||||
// uint32_t const instanceStart;
|
||||
// uint32_t const instanceSize;
|
||||
// uint32_t const reserved; // only when building for 64bit targets
|
||||
// const uint8_t * const ivarLayout;
|
||||
// const char *const name;
|
||||
// const struct _method_list_t * const baseMethods;
|
||||
// const struct _protocol_list_t *const baseProtocols;
|
||||
// const struct _ivar_list_t *const ivars;
|
||||
// const uint8_t * const weakIvarLayout;
|
||||
// const struct _prop_list_t * const properties;
|
||||
// };
|
||||
|
||||
var tmp uint32
|
||||
var ivarLayout uint64 // ptr
|
||||
var name uint64 // ptr
|
||||
var baseMethods uint64 // ptr
|
||||
var baseProtocols uint64 // ptr
|
||||
var ivars uint64 // ptr
|
||||
var weakIvarLayout uint64 // ptr
|
||||
var properties uint64 // ptr
|
||||
binary.Read(objc_const, mc.byteorder, &tmp)
|
||||
binary.Read(objc_const, mc.byteorder, &tmp)
|
||||
binary.Read(objc_const, mc.byteorder, &tmp)
|
||||
binary.Read(objc_const, mc.byteorder, &tmp)
|
||||
binary.Read(objc_const, mc.byteorder, &ivarLayout)
|
||||
binary.Read(objc_const, mc.byteorder, &name)
|
||||
binary.Read(objc_const, mc.byteorder, &baseMethods)
|
||||
binary.Read(objc_const, mc.byteorder, &baseProtocols)
|
||||
binary.Read(objc_const, mc.byteorder, &ivars)
|
||||
binary.Read(objc_const, mc.byteorder, &weakIvarLayout)
|
||||
binary.Read(objc_const, mc.byteorder, &properties)
|
||||
|
||||
fmt.Printf("method list: %x\n", baseMethods)
|
||||
}
|
||||
fmt.Printf("========\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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
|
||||
//
|
||||
// besides special selectors, selectors of outside classes must also be
|
||||
// registered through the cache
|
||||
// selectors of outside classes are defined as not being referenced by
|
||||
// internal classes in __objc_data
|
||||
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)) + 3)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// make __TEXT writable lol
|
||||
mc.file.Seek(0, 0)
|
||||
mc.file.WriteAt([]byte{0x7}, 0xa0)
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
2
research/custom_loader/.gitignore
vendored
2
research/custom_loader/.gitignore
vendored
@ -1 +1,3 @@
|
||||
out/
|
||||
coreutils-9.1/
|
||||
*.tar.xz
|
||||
|
@ -1,12 +1,20 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#include <objc/message.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void* sel_lookUpByName(const char* name);
|
||||
|
||||
|
||||
@interface Foo : NSObject
|
||||
@end
|
||||
|
||||
@implementation Foo
|
||||
- (void)bar {
|
||||
NSLog(@"%@", self);
|
||||
NSLog(@"Invoke instance method original bar in Foo");
|
||||
}
|
||||
|
||||
- (void)tobehijacked:(NSString*)input {
|
||||
NSLog(@"Invoke tobehijacked method %@ from Foo", input);
|
||||
}
|
||||
@end
|
||||
|
||||
@ -17,41 +25,99 @@
|
||||
static int x;
|
||||
|
||||
+ (void)load {
|
||||
NSLog(@"%@", self);
|
||||
// NSLog(@"x=%d", x)
|
||||
printf("printf in [Bar load]\n");
|
||||
x = 1;
|
||||
printf("Invoke +load method\n");
|
||||
}
|
||||
|
||||
- (void)dummy {
|
||||
NSLog(@"dummy bar x=%d", x);
|
||||
NSLog(@"Static value check after +load should be 1: x=%d", x);
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@interface FakeNSDateFormatter : NSDateFormatter {
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation FakeNSDateFormatter
|
||||
- (NSDate*)dateFromString:(NSString*)dateString {
|
||||
NSLog(@"Hijacked the NSDateFormatter");
|
||||
return [super dateFromString:dateString];
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
__attribute__((constructor)) static void
|
||||
hmmge(int argc, char** argv) {
|
||||
// create a dummy blank function to be replaced to call OBJC load
|
||||
printf("hmmge=%p\n", hmmge);
|
||||
printf("hmmge argc=%d\n", argc);
|
||||
printf("Invoke C constructor\n");
|
||||
printf("Checking for arguments to be passed correctly\n");
|
||||
printf(" argc=%d\n", argc);
|
||||
for (int i = 0; i < argc; i++) {
|
||||
printf(" hmmge argv[%d]=%s\n", i, argv[i]);
|
||||
printf(" argv[%d]=%s\n", i, argv[i]);
|
||||
}
|
||||
NSLog(@"hmmge in objc-c");
|
||||
NSLog(@"Using Objective-C in C constructor");
|
||||
NSLog(@"Test static Objective-C class is initialized and +load completed");
|
||||
Bar *bar = [[Bar alloc] init];
|
||||
[bar dummy];
|
||||
}
|
||||
|
||||
int main(int argc, const char * argv[]) {
|
||||
int main(int argc, const char * argv[], char* envp[]) {
|
||||
@autoreleasepool {
|
||||
NSLog(@"Hello, World!");
|
||||
NSLog(@"Invoke main()");
|
||||
|
||||
// Foo bar using Objective-C syntax
|
||||
Foo *foo = [[Foo alloc] init];
|
||||
[foo bar];
|
||||
|
||||
// Foo bar with selector and msgSend
|
||||
NSLog(@"Directly call \"bar\" %p through objc_msgSend %p with object foo %p", @selector(bar), objc_msgSend, foo);
|
||||
typedef void (*barfunc)(id, SEL);
|
||||
barfunc bar_ = (barfunc)&objc_msgSend;
|
||||
bar_(foo, @selector(bar));
|
||||
|
||||
NSString *dummyinput = @"dummy input";
|
||||
[foo tobehijacked:dummyinput];
|
||||
NSLog(@"The above invocation should be hijacked with input at %p", dummyinput);
|
||||
|
||||
NSString *dateString = @"2024-01-01T00:00:00.000Z";
|
||||
|
||||
// NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
|
||||
// [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZ"];
|
||||
// NSDate *date = [dateFormatter dateFromString:dateString];
|
||||
|
||||
// this is to test the idea for hooking,
|
||||
// basically, we create a middle-class inherits the class to be used
|
||||
//
|
||||
// example using NSDateFormatter:
|
||||
// - Create a FakeNSDateFormatter inherits NSDateFormatter
|
||||
// - Have an overloaded function that calls [super inherited]
|
||||
// - The internal struct class_t has superclass points to NSDateFormatter
|
||||
// FakeNSDateFormatter *dateFormatter = [[FakeNSDateFormatter alloc] init];
|
||||
// [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZ"];
|
||||
// NSDate *date = [dateFormatter dateFromString:dateString];
|
||||
// NSLog(@"Test hijacked/hooked Objective-C result %@", date);
|
||||
|
||||
NSLog(@"Selector \"dateFromString:\" using @selector %p", @selector(dateFromString:));
|
||||
NSLog(@"Selector \"bar:\" using @selector %p", @selector(bar:));
|
||||
NSLog(@"Selector \"dummy\" using @selector %p", @selector(dummy));
|
||||
|
||||
NSLog(@"[Bar dummy] implementation is at %p\n", [foo methodForSelector:@selector(bar:)]);
|
||||
}
|
||||
|
||||
printf("argc=%d\n", argc);
|
||||
printf("Selector lookup 'dateFromString:' addr: %p\n", sel_lookUpByName("dateFromString:"));
|
||||
printf("Selector lookup 'bar:' addr: %p\n", sel_lookUpByName("bar:"));
|
||||
printf("Selector lookup 'dummy' addr: %p\n", sel_lookUpByName("dummy"));
|
||||
|
||||
printf("Test if arguments are passed correctly to main(argc, argv, env)\n");
|
||||
printf(" argc=%d\n", argc);
|
||||
for (int i = 0; i < argc; i++) {
|
||||
printf(" argv[%d]=%s\n", i, argv[i]);
|
||||
printf(" argv[%d]=%s\n", i, argv[i]);
|
||||
}
|
||||
|
||||
while (*envp) {
|
||||
printf(" env[]=%s\n", *envp);
|
||||
envp++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -3,11 +3,17 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
// #include <Foundation/Foundation.h>
|
||||
#include <objc/objc.h>
|
||||
|
||||
#include "out/b.h"
|
||||
|
||||
char *pwd;
|
||||
uint32_t pwd_len;
|
||||
clock_t start, end;
|
||||
#define ISARM(header) ((*((uint32_t *)(header)+1) & 0xff) == 0xc)
|
||||
|
||||
int custom_strcmp(const char *p1, const char *p2) {
|
||||
const unsigned char *s1 = (const unsigned char *)p1;
|
||||
@ -74,7 +80,7 @@ struct libcache {
|
||||
void *libdyld;
|
||||
|
||||
int nrpath;
|
||||
char** rpaths;
|
||||
char **rpaths;
|
||||
};
|
||||
|
||||
uint32_t fnv_hash_extend(const char *str, uint32_t h) {
|
||||
@ -93,9 +99,7 @@ uint32_t fnv_hash_extend(const char *str, uint32_t h) {
|
||||
|
||||
return h;
|
||||
}
|
||||
uint32_t fnv_hash(const char* str) {
|
||||
return fnv_hash_extend(str, 0x811c9dc5);
|
||||
}
|
||||
uint32_t fnv_hash(const char *str) { return fnv_hash_extend(str, 0x811c9dc5); }
|
||||
|
||||
// try these hashes
|
||||
// https://gist.github.com/sgsfak/9ba382a0049f6ee885f68621ae86079b
|
||||
@ -122,9 +126,9 @@ 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
|
||||
for (int i = 0; i < cache->nrpath; i++){
|
||||
char* rpath = cache->rpaths[i];
|
||||
char* p = realpath(rpath, 0);
|
||||
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++) {
|
||||
@ -448,7 +452,7 @@ uint32_t should_follow_symbol(char *&buffer, char *&_find) {
|
||||
return is_prefix;
|
||||
}
|
||||
|
||||
void *find_in_export_trie(const void *header, void *trie, char *& symbol) {
|
||||
void *find_in_export_trie(const void *header, void *trie, char *&symbol) {
|
||||
uint32_t func = 0;
|
||||
|
||||
char *ptr = (char *)trie;
|
||||
@ -512,10 +516,10 @@ void *find_in_export_trie(const void *header, void *trie, char *& symbol) {
|
||||
}
|
||||
|
||||
void *find_in_lib(struct libcache *cache, struct libcache_item *lib,
|
||||
char *& symbol);
|
||||
char *&symbol);
|
||||
|
||||
void *find_in_reexport(struct libcache *cache, struct libcache_item *lib,
|
||||
char *& symbol) {
|
||||
char *&symbol) {
|
||||
void *header = lib->header;
|
||||
const uint32_t magic = *(uint32_t *)header;
|
||||
char *ptr = (char *)header;
|
||||
@ -551,7 +555,7 @@ void *find_in_reexport(struct libcache *cache, struct libcache_item *lib,
|
||||
}
|
||||
|
||||
void *find_in_lib(struct libcache *cache, struct libcache_item *lib,
|
||||
char *& symbol) {
|
||||
char *&symbol) {
|
||||
void *direct = find_in_export_trie(lib->header, lib->trie, symbol);
|
||||
if (direct) {
|
||||
return direct;
|
||||
@ -582,8 +586,8 @@ void *custom_dlsym(struct libcache *cache, uint32_t hash, const char *symbol) {
|
||||
// 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);
|
||||
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);
|
||||
}
|
||||
@ -815,6 +819,7 @@ void test(struct libcache &cache);
|
||||
__attribute__((constructor)) static void
|
||||
bruh(int argc, const char *const argv[], const char *const envp[],
|
||||
const char *const apple[], const struct ProgramVars *vars) {
|
||||
start = clock();
|
||||
printf("=== manual symbol bind starts ===\n");
|
||||
// set_cwd(envp);
|
||||
|
||||
@ -896,7 +901,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);
|
||||
find_all_rpath(cache, main);
|
||||
uint32_t trie_size;
|
||||
void *libdyld_export_trie = get_export_trie(libdyld, trie_size);
|
||||
|
||||
@ -908,16 +913,16 @@ void build_cache(struct libcache &cache, void *main) {
|
||||
typedef char *(*dyld_get_image_name_t)(int);
|
||||
typedef void *(*dyld_get_image_header_t)(int);
|
||||
|
||||
char* dyld_image_count_s = "__dyld_image_count";
|
||||
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_s);
|
||||
|
||||
char* dyld_get_image_header_s = "__dyld_get_image_header";
|
||||
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_s);
|
||||
|
||||
char* dyld_get_image_name_s = "__dyld_get_image_name";
|
||||
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_s);
|
||||
@ -930,7 +935,7 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -950,7 +955,8 @@ void find_all_rpath(struct libcache &cache, void *header) {
|
||||
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++;
|
||||
if (cmd == LC_RPATH)
|
||||
cache.nrpath++;
|
||||
ptr += cmdsize;
|
||||
}
|
||||
uint32_t idx = 0;
|
||||
@ -1182,11 +1188,13 @@ void fix(struct libcache &cache) {
|
||||
// for (int i = 0; i < 0x2ac; i++) {
|
||||
// text_start[0xb8c + i] = text_start[0xb8c + i] ^ 0xcc;
|
||||
// }
|
||||
// vm_protect_func(mach_task_self_func(), (uint64_t)text_start, 0x1000, 0,
|
||||
// VM_PROT_READ | VM_PROT_EXECUTE);
|
||||
|
||||
fix_objc(libfixing, cache);
|
||||
fix_initializer(libfixing, cache);
|
||||
|
||||
// _TEXT must be RX or RW no RWX
|
||||
// vm_protect_func(mach_task_self_func(), (uint64_t)text_start, 0x1000, 0,
|
||||
// VM_PROT_READ | VM_PROT_EXECUTE);
|
||||
}
|
||||
|
||||
void volatile custom_initializer(int argc, const char *const argv[],
|
||||
@ -1263,9 +1271,341 @@ void volatile custom_initializer(int argc, const char *const argv[],
|
||||
|
||||
printf("[+] initializers completed\n");
|
||||
free(custom_initializer_i);
|
||||
end = clock();
|
||||
double cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC;
|
||||
printf("restoration library time: %lf\n", cpu_time_used);
|
||||
}
|
||||
|
||||
void fix_objc_classdata(struct libcache_item *libfixing, struct libcache &cache);
|
||||
void fix_class_refs(struct libcache_item *libfixing, struct libcache &cache);
|
||||
void run_objc_readclass(struct libcache_item *libfixing, struct libcache &cache);
|
||||
|
||||
// method are splited into 3 kinds, but for simplicity, we think of it as
|
||||
// 2 kinds: big and small
|
||||
// our example are small method list, which all pointers are relative and 32-bit
|
||||
// the size should be 0xc == 12 but we have padding 4-byte 0x0 for some reason?
|
||||
union _objc_method{
|
||||
struct {
|
||||
const char* name;
|
||||
const char* types;
|
||||
void* imp;
|
||||
};
|
||||
struct {
|
||||
int32_t sel_offset;
|
||||
int32_t typ_offset;
|
||||
int32_t imp_offset;
|
||||
};
|
||||
};
|
||||
|
||||
struct method_t {
|
||||
const char* name; /* Pointer to name (or selector reference?) */
|
||||
const char* types; /* Pointer to type info */
|
||||
void* imp; /* Pointer to implementation (code) */
|
||||
};
|
||||
|
||||
// entsize & 0x80000000 is small method kind
|
||||
// entsize = kind | sizeof(_objc_method)
|
||||
struct _method_list_t {
|
||||
uint32_t entsize; // sizeof(struct _objc_method)
|
||||
uint32_t method_count;
|
||||
union _objc_method method_list[];
|
||||
};
|
||||
|
||||
struct _class_ro_t {
|
||||
uint32_t flags;
|
||||
uint32_t const instanceStart;
|
||||
uint32_t const instanceSize;
|
||||
uint32_t const reserved; // only when building for 64bit targets
|
||||
const uint8_t * const ivarLayout;
|
||||
const char *const name;
|
||||
struct _method_list_t * baseMethods;
|
||||
const /*struct _protocol_list_t*/void *const baseProtocols;
|
||||
const /*struct _ivar_list_t*/void *const ivars;
|
||||
const uint8_t * const weakIvarLayout;
|
||||
const /*struct _prop_list_t*/void *const properties;
|
||||
};
|
||||
|
||||
struct _class_t {
|
||||
struct _class_t *isa;
|
||||
struct _class_t * superclass;
|
||||
void *cache;
|
||||
void *vtable;
|
||||
struct _class_ro_t *ro;
|
||||
};
|
||||
void fix_objc(struct libcache_item *libfixing, struct libcache &cache) {
|
||||
printf("[+] dealing with Objective-C\n");
|
||||
#ifdef METH1
|
||||
fix_objc_classdata(libfixing, cache);
|
||||
#endif
|
||||
#ifdef METH3
|
||||
printf("METH3\n");
|
||||
fix_class_refs(libfixing, cache);
|
||||
#endif
|
||||
run_objc_readclass(libfixing, cache);
|
||||
}
|
||||
|
||||
void test_objc_hijack(void* self, void* selector, void* input) {
|
||||
printf("[Foo tobehijacked] function is HIJACKED\n");
|
||||
printf("arg1=%p arg2=%p arg3=%p\n", self, selector, input);
|
||||
}
|
||||
|
||||
// a subroutine to perform hooking of fixed-binary classes
|
||||
// by iterating in the __objc_classref which internally points to
|
||||
// __objc_data for a list of _class_t structs
|
||||
// each _classt_t has a _class_ro_t containing pointers to
|
||||
// the components of an instance, including methods, properties, ivars, ...
|
||||
//
|
||||
// in this function, we only work on hooking/hijacking of class methods
|
||||
// by fixing the method list which to be read by Objective-C runtime during readClass
|
||||
// the method list is a list of {selector, type, implementation} (all pointers)
|
||||
// by fixing the implementation (should point to a function) the readClass
|
||||
// thinks that it is the function associated with the method name/selector
|
||||
//
|
||||
// by now, all rebases have been rebased and pointers should be pointing correctly
|
||||
// however, selectors are to be constructed, unless erased
|
||||
void fix_objc_classdata(struct libcache_item *libfixing, struct libcache &cache) {
|
||||
void *header = libfixing->header;
|
||||
const uint32_t magic = *(uint32_t *)header;
|
||||
char *ptr = (char *)header;
|
||||
if (magic == magic64) {
|
||||
ptr += 0x20;
|
||||
} else {
|
||||
ptr += 0x20 - 0x4;
|
||||
}
|
||||
|
||||
const uint32_t ncmds = *((uint32_t *)header + 4);
|
||||
char *command_ptr = ptr;
|
||||
|
||||
uint64_t linkedit_vmaddr;
|
||||
uint64_t linkedit_fileoffset;
|
||||
uint64_t slide;
|
||||
|
||||
uint64_t methlist_start;
|
||||
uint64_t methlist_size;
|
||||
|
||||
uint32_t libsystem_hash =
|
||||
calculate_libname_hash(&cache, "/usr/lib/libSystem.B.dylib");
|
||||
typedef void *(*vm_protect_t)(void *, uint64_t, uint64_t, int, int);
|
||||
typedef void *(*mach_task_self_t)();
|
||||
mach_task_self_t mach_task_self_func =
|
||||
(mach_task_self_t)custom_dlsym(&cache, libsystem_hash, "_mach_task_self");
|
||||
vm_protect_t vm_protect_func =
|
||||
(vm_protect_t)custom_dlsym(&cache, libsystem_hash, "_vm_protect");
|
||||
|
||||
for (int i = 0; i < ncmds; i++) {
|
||||
const uint32_t cmd = *((uint32_t *)ptr + 0);
|
||||
const uint32_t cmdsize = *((uint32_t *)ptr + 1);
|
||||
if (cmd == LC_SEGMENT_64) {
|
||||
char *name = (char *)((uint64_t *)ptr + 1);
|
||||
uint64_t vmaddr = *((uint64_t *)ptr + 3);
|
||||
uint64_t fileoffset = *((uint64_t *)ptr + 5);
|
||||
// this assumes that __TEXT comes before __DATA_CONST
|
||||
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;
|
||||
// to be able to fix method list for hooking, we need this section
|
||||
// to be writable
|
||||
if (custom_strncmp(secname, "__objc_methlist", 16) == 0) {
|
||||
uint64_t addr = *((uint64_t *)sections_ptr + 4);
|
||||
uint64_t size = *((uint64_t *)sections_ptr + 5);
|
||||
|
||||
methlist_start = addr + slide;
|
||||
methlist_size = size;
|
||||
|
||||
printf("setting __objc_methlist to RW: addr=%p size=%x\n", addr + slide, size);
|
||||
vm_protect_func(mach_task_self_func(), methlist_start, methlist_size, 0, VM_PROT_READ | VM_PROT_WRITE);
|
||||
}
|
||||
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;
|
||||
// we can iterate in the __objc_data rather than __objc_classref
|
||||
// classref can also point to outside classes that are imported
|
||||
if (custom_strncmp(secname, "__objc_data", 16) == 0) {
|
||||
|
||||
uint64_t addr = *((uint64_t *)sections_ptr + 4);
|
||||
uint64_t size = *((uint64_t *)sections_ptr + 5);
|
||||
struct _class_t *data_ptr = (struct _class_t *)(addr + slide);
|
||||
|
||||
for (int nclass = 0; nclass < size / sizeof(struct _class_t); nclass++, data_ptr++) {
|
||||
// ro can be null for some reasons
|
||||
// baseMethods is null if the class is a metaclass
|
||||
if (!(data_ptr->ro && data_ptr->ro->baseMethods)) {
|
||||
continue;
|
||||
}
|
||||
const char* class_name = data_ptr->ro->name;
|
||||
struct _method_list_t* methods = data_ptr->ro->baseMethods;
|
||||
for (int i_method = 0; i_method < methods->method_count; i_method++) {
|
||||
// have to use reference because the relative offset is calculated with the variable address
|
||||
// if not using reference, then the variable will be a COPY value and the address is localized
|
||||
union _objc_method* method = &methods->method_list[i_method];
|
||||
if (methods->entsize & 0x80000000) {
|
||||
const char* imp = *(char**)((char*)(&method->sel_offset) + method->sel_offset);
|
||||
if (custom_strcmp(class_name, "Foo") == 0 && custom_strcmp(imp, "tobehijacked:") == 0) {
|
||||
// char* current_imp = (char*)(&method->imp_offset) + method->imp_offset;
|
||||
|
||||
// encode the relative pointer
|
||||
uint64_t replace = (uint64_t)test_objc_hijack;
|
||||
uint64_t original = (uint64_t)&method->imp_offset;
|
||||
printf("modify the Objective-C method at %p\n", &method->imp_offset);
|
||||
if (replace > original) {
|
||||
method->imp_offset = (int32_t)(replace - original);
|
||||
} else {
|
||||
method->imp_offset = -(int32_t)(original - replace);
|
||||
}
|
||||
}
|
||||
|
||||
printf(" method=%p\n", method);
|
||||
printf(" sel=%x --> %p\n", method->sel_offset, (char*)(&method->sel_offset) + method->sel_offset);
|
||||
printf(" %s\n", name);
|
||||
printf(" typ=%x --> %s\n", method->typ_offset, (char*)&method->typ_offset + method->typ_offset);
|
||||
printf(" fun=%x --> %p\n", method->imp_offset, (char*)(&method->imp_offset) + method->imp_offset);
|
||||
}
|
||||
else {
|
||||
const char* imp = method->name;
|
||||
if (custom_strcmp(class_name, "Foo") == 0 && custom_strcmp(imp, "tobehijacked:") == 0) {
|
||||
void* replace = (void*)test_objc_hijack;
|
||||
printf("modify the Objective-C method at %p with legacy format.\n", &method->imp);
|
||||
method->imp = replace;
|
||||
}
|
||||
printf(" method=%p\n", method);
|
||||
printf(" sel=%s\n", method->name);
|
||||
printf(" typ=%p\n", method->types);
|
||||
printf(" fun=%p\n", method->imp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sections_ptr += 16 * 2 + 8 * 2 + 4 * 8;
|
||||
}
|
||||
} else if (custom_strcmp(name, "__LINKEDIT") == 0) {
|
||||
linkedit_vmaddr = vmaddr;
|
||||
linkedit_fileoffset = fileoffset;
|
||||
}
|
||||
}
|
||||
ptr += cmdsize;
|
||||
}
|
||||
|
||||
// _TEXT must be RX or RW no RWX
|
||||
vm_protect_func(mach_task_self_func(), methlist_start, methlist_size, 0,
|
||||
VM_PROT_READ | VM_PROT_EXECUTE);
|
||||
}
|
||||
|
||||
uint64_t find_replace_cls_refs(struct libcache cache) {
|
||||
void *header = cache.thislib;
|
||||
const uint32_t magic = *(uint32_t *)header;
|
||||
char *ptr = (char *)header;
|
||||
if (magic == magic64) {
|
||||
ptr += 0x20;
|
||||
} else {
|
||||
ptr += 0x20 - 0x4;
|
||||
}
|
||||
|
||||
const uint32_t ncmds = *((uint32_t *)header + 4);
|
||||
char *command_ptr = ptr;
|
||||
uint64_t slide;
|
||||
for (int i = 0; i < ncmds; i++){
|
||||
const uint32_t cmd = *((uint32_t *)ptr + 0);
|
||||
const uint32_t cmdsize = *((uint32_t *)ptr + 1);
|
||||
if (cmd == LC_SEGMENT_64){
|
||||
char* name = (char*)((uint64_t*)ptr + 1);
|
||||
uint64_t vmaddr = *((uint64_t*)ptr + 3);
|
||||
if (custom_strcmp(name, "__TEXT") == 0)
|
||||
slide = (uint64_t)header - vmaddr;
|
||||
|
||||
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;
|
||||
if (custom_strncmp(secname, "__objc_data", 11) == 0){
|
||||
uint64_t addr = *((uint64_t *)sections_ptr + 4);
|
||||
uint64_t size = *((uint64_t *)sections_ptr + 5);
|
||||
struct _class_t *data_ptr = (struct _class_t *)(addr + slide);
|
||||
for (int nclass = 0; nclass < size / sizeof(struct _class_t); nclass++, data_ptr++) {
|
||||
if (!data_ptr->ro)
|
||||
continue;
|
||||
if (data_ptr->ro->flags & 0x01/*if meta class*/) { continue; }
|
||||
if (custom_strcmp(data_ptr->ro->name, "Hooker") == 0){
|
||||
printf("Found Hooker @ %p\n", data_ptr);
|
||||
return (uint64_t)data_ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
sections_ptr += 16 * 2 + 8 * 2 + 4 * 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
ptr += cmdsize;
|
||||
}
|
||||
}
|
||||
|
||||
void fix_class_refs(struct libcache_item *libfixing, struct libcache &cache) {
|
||||
uint64_t replace = find_replace_cls_refs(cache);
|
||||
void *header = libfixing->header;
|
||||
const uint32_t magic = *(uint32_t *)header;
|
||||
char *ptr = (char *)header;
|
||||
if (magic == magic64) {
|
||||
ptr += 0x20;
|
||||
} else {
|
||||
ptr += 0x20 - 0x4;
|
||||
}
|
||||
|
||||
const uint32_t ncmds = *((uint32_t *)header + 4);
|
||||
char *command_ptr = ptr;
|
||||
uint64_t slide;
|
||||
for (int i = 0; i < ncmds; i++){
|
||||
const uint32_t cmd = *((uint32_t *)ptr + 0);
|
||||
const uint32_t cmdsize = *((uint32_t *)ptr + 1);
|
||||
if (cmd == LC_SEGMENT_64){
|
||||
char* name = (char*)((uint64_t*)ptr + 1);
|
||||
uint64_t vmaddr = *((uint64_t*)ptr + 3);
|
||||
if (custom_strcmp(name, "__TEXT") == 0)
|
||||
slide = (uint64_t)header - vmaddr;
|
||||
|
||||
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;
|
||||
if (custom_strncmp(secname, "__objc_classrefs", 16) == 0){
|
||||
uint64_t addr = *((uint64_t*)sections_ptr + 4) + slide;
|
||||
uint64_t size = *((uint64_t*)sections_ptr + 5);
|
||||
struct _class_t* target_clsref = NULL;
|
||||
for (int nclass = 0; nclass < size / sizeof(uint64_t*); nclass++){
|
||||
target_clsref = (_class_t*)(*((uint64_t *)addr + nclass));
|
||||
// printf("Target clasref @ %p: %p\n", (uint64_t *)addr + nclass, target_clsref);
|
||||
if (custom_strcmp(target_clsref->ro->name, "Foo") == 0){
|
||||
// TODO
|
||||
printf("Target clasref @ %p: %p\n", (uint64_t *)addr + nclass, target_clsref);
|
||||
*((uint64_t *)addr + nclass) = replace;
|
||||
printf("New clasref @ %p: %p\n", (uint64_t *)addr + nclass, *((uint64_t *)addr + nclass));
|
||||
struct _class_t* hooker = (struct _class_t*)replace;
|
||||
printf("superclass hooker: %p\n", target_clsref->superclass);
|
||||
hooker->superclass = target_clsref;
|
||||
printf("New superclass hooker: %p\n", hooker->superclass);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
sections_ptr += 16 * 2 + 8 * 2 + 4 * 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
ptr += cmdsize;
|
||||
}
|
||||
}
|
||||
|
||||
void run_objc_readclass(struct libcache_item *libfixing, struct libcache &cache) {
|
||||
// Manually run the Objective-C runtime for each class
|
||||
//
|
||||
|
||||
@ -1279,6 +1619,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;
|
||||
@ -1305,6 +1646,57 @@ 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);
|
||||
}
|
||||
|
||||
typedef void *(*sel_lookUpByName_t)(const char *);
|
||||
sel_lookUpByName_t sel_lookUpByName =
|
||||
(sel_lookUpByName_t)custom_dlsym(
|
||||
&cache, "/usr/lib/libobjc.A.dylib", "_sel_lookUpByName");
|
||||
printf("selector gogogo: %p\n",
|
||||
sel_lookUpByName("dateFromString:"));
|
||||
}
|
||||
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);
|
||||
|
220
research/custom_loader/benchmark.py
Normal file
220
research/custom_loader/benchmark.py
Normal file
@ -0,0 +1,220 @@
|
||||
# import unittest
|
||||
import subprocess, resource
|
||||
import lief
|
||||
import os
|
||||
# import time
|
||||
import re
|
||||
|
||||
PATH = "./coreutils-9.1/src"
|
||||
|
||||
class Line:
|
||||
file = None
|
||||
@classmethod
|
||||
def init(cls):
|
||||
cls.file = open("out.csv", "w")
|
||||
cls.file.write("Name,File size(KiB),Number of symbols,Number of imports,Restoration time(s),Execution time(s),File size(KiB),Number of symbols,Number of imports,Restoration time(s),Execution time(s)\n")
|
||||
|
||||
def write(self):
|
||||
out = f"{self.name},{self.norm_size},{self.norm_symbols},{self.norm_imports},0,{self.norm_exe:.3f},{self.obf_size},{self.obf_symbols},{self.obf_imports},{self.restore:.3f},{self.obf_exe:.3f}\n"
|
||||
self.file.write(out)
|
||||
|
||||
def __init__(self, name: str) -> None:
|
||||
self.name = name
|
||||
self.norm_path = f"{PATH}/{name}"
|
||||
self.obf_path = f"{PATH}/{name}-dir/out/{name}-fixed"
|
||||
|
||||
def numOfSymbols(sym: list) -> int:
|
||||
count = 0
|
||||
for i in sym:
|
||||
if i.type != 0:
|
||||
count += 1
|
||||
return count
|
||||
|
||||
def numOfImports(imp: list) -> int:
|
||||
count = 0
|
||||
for i in imp:
|
||||
if i.name != "":
|
||||
count += 1
|
||||
return count
|
||||
|
||||
def setup(binpath: str, libpath: str = None):
|
||||
if os.path.isdir("/tmp/test"):
|
||||
os.system("rm -rf /tmp/test")
|
||||
os.mkdir("/tmp/test")
|
||||
# if libpath:
|
||||
# os.system(f"cp {binpath} {libpath} ./test_file.txt /tmp/test")
|
||||
# else:
|
||||
# os.system(f"cp {binpath} ./test_file.txt /tmp/test")
|
||||
os.system("cp ./test_file.txt /tmp/test")
|
||||
|
||||
|
||||
# class Benchmark(unittest.TestCase):
|
||||
def info(l: Line):
|
||||
l.norm_size = int(os.path.getsize(l.norm_path) / 1024)
|
||||
l.obf_size = int(os.path.getsize(l.obf_path) / 1024)
|
||||
|
||||
norm = lief.parse(l.norm_path)
|
||||
obf = lief.parse(l.obf_path)
|
||||
|
||||
l.norm_symbols = numOfSymbols(norm.symbols)
|
||||
l.obf_symbols = numOfSymbols(obf.symbols)
|
||||
l.norm_imports = numOfImports(norm.imported_functions)
|
||||
l.obf_imports = numOfImports(obf.imported_functions)
|
||||
|
||||
def run(l, cmd):
|
||||
print(f"[+] Running benchmark for {l.name} with command \"{cmd}\"")
|
||||
cmd = cmd.split(" ")
|
||||
setup(l.norm_path)
|
||||
start = resource.getrusage(resource.RUSAGE_CHILDREN).ru_utime
|
||||
p1 = subprocess.run([l.norm_path] + cmd, capture_output=True)
|
||||
end = resource.getrusage(resource.RUSAGE_CHILDREN).ru_utime
|
||||
l.norm_exe = end - start
|
||||
|
||||
setup(l.obf_path)
|
||||
start = resource.getrusage(resource.RUSAGE_CHILDREN).ru_utime
|
||||
p2 = subprocess.run([l.obf_path] + cmd, capture_output=True)
|
||||
end = resource.getrusage(resource.RUSAGE_CHILDREN).ru_utime
|
||||
if p2.returncode == -11:
|
||||
print(f"\033[91m[!] Error in {l.name} (segfault)\033[0m")
|
||||
Line.file.write(f"{l.name},segfault\n")
|
||||
return
|
||||
# print(p2.stdout)
|
||||
match = re.search(b"restoration library time: ([0-9.]+)", p2.stdout)
|
||||
l.restore = float(match.group(1))
|
||||
l.obf_exe = end - start
|
||||
if p2.returncode != p1.returncode:
|
||||
print(f"\033[91m[!] Error in {l.name} (diff exit code)\033[0m")
|
||||
Line.file.write(f"{l.name},exit code diff\n")
|
||||
return
|
||||
l.write()
|
||||
# if p1.stdout in p2.stdout:
|
||||
# l.write()
|
||||
# else:
|
||||
# print(f"\033[91m[!] Error in {l.name} (stdout diff)\033[0m")
|
||||
# print(p1.stdout)
|
||||
# print("-"*20)
|
||||
# print(p2.stdout)
|
||||
|
||||
# Line.file.write(f"{l.name},stdout diff\n")
|
||||
|
||||
|
||||
def test_basic(name, cmd):
|
||||
l = Line(name)
|
||||
info(l)
|
||||
run(l, cmd)
|
||||
|
||||
test_data = [
|
||||
("md5sum", "/tmp/test/test_file.txt"),
|
||||
("split", "/tmp/test/test_file.txt /tmp/test/out"),
|
||||
("cat", "/tmp/test/test_file.txt"),
|
||||
("mkfifo", "/tmp/test/a"),
|
||||
("shuf", "--random-source=/tmp/test/test_file.txt /tmp/test/test_file.txt"),
|
||||
("pathchk", "/tmp/test/test_file.txt"),
|
||||
("expand", "/tmp/test/test_file.txt"),
|
||||
("tty", ""),
|
||||
("basename", "/tmp/test/test_file.txt"),
|
||||
("nice", ""),
|
||||
("truncate", "-s 0 /tmp/test/test_file.txt"),
|
||||
("echo", "hello"),
|
||||
("du", "-h /tmp"),
|
||||
("ptx", "/tmp/test/test_file.txt"),
|
||||
("join", "/tmp/test/test_file.txt /tmp/test/test_file.txt"),
|
||||
("df", "--help"),
|
||||
("pwd", ""),
|
||||
("test", "-f /tmp/test_file.txt"),
|
||||
("csplit", "/tmp/test_file.txt 1"),
|
||||
("sort", "/tmp/test_file.txt"),
|
||||
("whoami", ""),
|
||||
("touch", "/tmp/test/a"),
|
||||
("unlink", "/tmp/test/test_file.txt"),
|
||||
("b2sum", "/tmp/test/test_file.txt"),
|
||||
("sleep", "1"),
|
||||
("fmt", "/tmp/test/test_file.txt"),
|
||||
("stty", ""),
|
||||
("logname", ""),
|
||||
("chgrp", "root /tmp/test/test_file.txt"),
|
||||
("printenv", ""),
|
||||
("seq", "1 10"),
|
||||
("uname", ""),
|
||||
("sha224sum", "/tmp/test/test_file.txt"),
|
||||
("od", "/tmp/test/test_file.txt"),
|
||||
("date", ""),
|
||||
("base64", "/tmp/test/test_file.txt"),
|
||||
("realpath", "/tmp/test/test_file.txt"),
|
||||
("readlink", "/tmp/test/test_file.txt"),
|
||||
("dircolors", ""),
|
||||
("timeout", "1s sleep 2"),
|
||||
("tac", "/tmp/test/test_file.txt"),
|
||||
("numfmt", "1000"),
|
||||
("wc", "/tmp/test/test_file.txt"),
|
||||
("basenc", "/tmp/test/test_file.txt"),
|
||||
("comm", "/tmp/test/test_file.txt /tmp/test/test_file.txt"),
|
||||
("nproc", ""),
|
||||
("expr", "1"),
|
||||
("cksum", "/tmp/test/test_file.txt"),
|
||||
("printf", "hello"),
|
||||
("groups", ""),
|
||||
("chcon", "-t s0 /tmp/test/test_file.txt"),
|
||||
("factor", "10"),
|
||||
("tail", "-n 1 /tmp/test/test_file.txt"),
|
||||
("env", ""),
|
||||
("pr", "/tmp/test/test_file.txt"),
|
||||
("head", "-n 1 /tmp/test/test_file.txt"),
|
||||
("kill", "$$"),
|
||||
("uniq", "/tmp/test/test_file.txt"),
|
||||
("stat", "-f /tmp/test/test_file.txt"),
|
||||
("link", "/tmp/test/test_file.txt /tmp/test/test_file.txt"),
|
||||
# ("make-prime-list", "10"), # build fail
|
||||
("sum", "/tmp/test/test_file.txt"),
|
||||
("tsort", "/tmp/test/test_file.txt"),
|
||||
# ("extract-magic", "/tmp/test/test_file.txt"), build fail
|
||||
("mknod", "/tmp/test/test_file.txt"),
|
||||
("users", ""),
|
||||
("dd", "--help"),
|
||||
("who", ""),
|
||||
("sha1sum", "/tmp/test/test_file.txt"),
|
||||
("mktemp", ""),
|
||||
("cut", "-c 1 /tmp/test/test_file.txt"),
|
||||
("sha256sum", "/tmp/test/test_file.txt"),
|
||||
("dir", "/tmp/test/test_file.txt"),
|
||||
("mkdir", "/tmp/test/a"),
|
||||
("nl", "/tmp/test/test_file.txt"),
|
||||
("ginstall", "/tmp/test/test_file.txt /tmp/test/test_file.txt"),
|
||||
("shred", "-u /tmp/test/test_file.txt"),
|
||||
("fold", "-w 10 /tmp/test/test_file.txt"),
|
||||
("rmdir", "/tmp/test/a"),
|
||||
("sha384sum", "/tmp/test/test_file.txt"),
|
||||
("mv", "/tmp/test/test_file.txt /tmp/test/test_file.txt"),
|
||||
("dirname", "/tmp/test/test_file.txt"),
|
||||
("id", ""),
|
||||
("base32", "/tmp/test/test_file.txt"),
|
||||
("pinky", ""),
|
||||
("ln", "/tmp/test/test_file.txt /tmp/test/test_file.txt"),
|
||||
("hostid", ""),
|
||||
("chroot", "/tmp/test /tmp/test/test_file.txt"),
|
||||
("ls", "/tmp/test"),
|
||||
("true", ""),
|
||||
("cp", "/tmp/test/test_file.txt /tmp/test/test_file.txt"),
|
||||
("sync", ""),
|
||||
("yes", "--help"),
|
||||
("unexpand", "/tmp/test/test_file.txt"),
|
||||
("chown", "root /tmp/test/test_file.txt"),
|
||||
("getlimits", ""),
|
||||
("chmod", "777 /tmp/test/test_file.txt"),
|
||||
("uptime", ""),
|
||||
("rm", "/tmp/test/test_file.txt"),
|
||||
("vdir", "/tmp/test"),
|
||||
("false", ""),
|
||||
("sha512sum", "/tmp/test/test_file.txt"),
|
||||
("tr", "a b /tmp/test/test_file.txt"),
|
||||
("paste", "/tmp/test/test_file.txt /tmp/test/test_file.txt"),
|
||||
("nohup", "sleep 1")
|
||||
]
|
||||
|
||||
# core="tee md5sum split cat shuf mkfifo pathchk runcon expand tty basename nice truncate echo du ptx join df pwd test csplit sort whoami touch dcgen unlink b2sum sleep fmt stty logname chgrp printenv seq uname sha224sum od date base64 realpath readlink dircolors timeout tac numfmt wc basenc comm nproc expr stdbuf cksum printf groups chcon factor tail env pr head kill uniq stat link make-prime-list sum tsort extract-magic mknod users dd who sha1sum mktemp cut sha256sum dir mkdir nl ginstall shred fold rmdir sha384sum mv dirname id base32 pinky ln hostid chroot ls true cp sync yes unexpand chown getlimits chmod uptime rm vdir false sha512sum tr paste nohup"
|
||||
|
||||
if __name__ == "__main__":
|
||||
Line.init()
|
||||
for name, cmd in test_data:
|
||||
test_basic(name, cmd)
|
||||
# unittest.main()
|
@ -1,9 +1,10 @@
|
||||
# set -ex
|
||||
|
||||
set -e
|
||||
clear
|
||||
VERSION=${1:-14}
|
||||
METH=${2}
|
||||
OUT=./out
|
||||
LOGIC=${2}
|
||||
|
||||
LOGIC=3
|
||||
make -C ../../macho-go
|
||||
mkdir -p $OUT
|
||||
|
||||
echo "using mach-o version $VERSION"
|
||||
@ -14,6 +15,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
|
||||
|
||||
@ -60,15 +76,23 @@ 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 -fobjc-arc -ObjC -mmacosx-version-min=$VERSION -o $OUT/a -L"./out" -lb a.mm
|
||||
clang -fobjc-arc -ObjC -mmacosx-version-min=$VERSION -o $OUT/a a.mm
|
||||
|
||||
# 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 --dylibs=./out/libb.dylib --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
|
||||
|
||||
if [ "$METH" = "METH1" ]; then
|
||||
# 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
|
||||
clang++ -D $METH -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 --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
|
||||
|
||||
elif [ "$METH" = "METH3" ]; then
|
||||
clang -mmacosx-version-min=$VERSION -fobjc-arc -ObjC -c -o $OUT/hooking.o hooking.mm
|
||||
clang++ -mmacosx-version-min=$VERSION -D $METH -c -o $OUT/b.o b.cc
|
||||
clang++ -fobjc-arc -ObjC -shared -Wl,-reexport_library -o $OUT/libb.dylib $OUT/b.o $OUT/hooking.o
|
||||
fi
|
||||
|
||||
# resign
|
||||
codesign --force --deep -s - $OUT/a-fixed
|
||||
|
31
research/custom_loader/hooking.mm
Normal file
31
research/custom_loader/hooking.mm
Normal file
@ -0,0 +1,31 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#include <objc/message.h>
|
||||
#include <stdio.h>
|
||||
|
||||
@interface Hehe : NSObject
|
||||
- (void)bar;
|
||||
- (void)tobehijacked:(NSString*)input;
|
||||
@end
|
||||
|
||||
@interface Hooker : Hehe
|
||||
@end
|
||||
|
||||
@implementation Hehe
|
||||
- (void)bar {
|
||||
NSLog(@"Invoke instance method %@", self);
|
||||
}
|
||||
- (void)tobehijacked:(NSString*)input {
|
||||
NSLog(@"Invoke tobehijacked method %@", input);
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation Hooker
|
||||
- (void)tobehijacked:(NSString*)input {
|
||||
NSLog(@"Hijacked tobehijacked method %@ from Hooker", input);
|
||||
}
|
||||
|
||||
- (void)bar {
|
||||
[super bar];
|
||||
}
|
||||
|
||||
@end
|
11
research/custom_loader/install.sh
Normal file
11
research/custom_loader/install.sh
Normal file
@ -0,0 +1,11 @@
|
||||
curl -LO https://ftp.gnu.org/gnu/coreutils/coreutils-9.1.tar.xz
|
||||
|
||||
tar -xvf coreutils-9.1.tar.xz
|
||||
|
||||
cd coreutils-9.1
|
||||
|
||||
./configure
|
||||
make
|
||||
|
||||
rm coreutils-9.1.tar.xz
|
||||
|
27
research/custom_loader/obfuscate.sh
Executable file
27
research/custom_loader/obfuscate.sh
Executable file
@ -0,0 +1,27 @@
|
||||
rm -r coreutils-9.1/src/*-dir
|
||||
|
||||
core="tee md5sum split cat shuf mkfifo pathchk runcon expand tty basename nice truncate echo du ptx join df pwd test csplit sort whoami touch dcgen unlink b2sum sleep fmt stty logname chgrp printenv seq uname sha224sum od date base64 realpath readlink dircolors timeout tac numfmt wc basenc comm nproc expr stdbuf cksum printf groups chcon factor tail env pr head kill uniq stat link make-prime-list sum tsort extract-magic mknod users dd who sha1sum mktemp cut sha256sum dir mkdir nl ginstall shred fold rmdir sha384sum mv dirname id base32 pinky ln hostid chroot ls true cp sync yes unexpand chown getlimits chmod uptime rm vdir false sha512sum tr paste nohup"
|
||||
for i in $core; do
|
||||
echo "[+] $i"
|
||||
WD=coreutils-9.1/src/${i}-dir
|
||||
OUT=$WD/out
|
||||
mkdir -p $WD
|
||||
mkdir -p $OUT
|
||||
|
||||
cp b.cc $WD
|
||||
|
||||
{
|
||||
clang++ -mmacosx-version-min=14 -o $OUT/libb.dylib -shared dummy.cc
|
||||
|
||||
../../macho-go/bin/ios-wrapper pepe -o $OUT/${i}-fixed -b $OUT/b.bcell --dylibs=./$OUT/libb.dylib --remove-imports --remove-exports --remove-symbol-table --remove-others coreutils-9.1/src/${i}
|
||||
../../macho-go/bin/ios-wrapper bcell2header -b $OUT/b.bcell -o $OUT/b.h
|
||||
|
||||
clang++ -mmacosx-version-min=14 -o $OUT/libb.dylib -shared -Wl,-reexport_library out/libc.dylib $WD/b.cc
|
||||
|
||||
codesign --force --deep -s - $OUT/${i}-fixed
|
||||
codesign --force --deep -s - $OUT/libb.dylib
|
||||
chmod +x $OUT/${i}-fixed
|
||||
} > /dev/null 2>&1
|
||||
done
|
||||
|
||||
|
104
research/custom_loader/out_x86_64.csv
Normal file
104
research/custom_loader/out_x86_64.csv
Normal file
@ -0,0 +1,104 @@
|
||||
Name,File size(KiB),Number of symbols,Number of imports,Restoration time(s),Execution time(s),File size(KiB),Number of symbols,Number of imports,Restoration time(s),Execution time(s)
|
||||
md5sum,segfault
|
||||
split,150,1321,101,0,0.003,169,0,4,0.002,0.005
|
||||
cat,124,916,84,0,0.003,143,0,4,0.002,0.005
|
||||
mkfifo,121,819,78,0,0.003,140,0,4,0.002,0.004
|
||||
shuf,149,1255,91,0,0.004,168,0,4,0.002,0.005
|
||||
pathchk,121,791,79,0,0.003,139,0,4,0.001,0.004
|
||||
expand,123,904,82,0,0.003,142,0,4,0.002,0.005
|
||||
tty,120,773,77,0,0.003,139,0,4,0.001,0.004
|
||||
basename,121,805,74,0,0.003,140,0,4,0.001,0.004
|
||||
nice,121,802,79,0,0.003,139,0,4,0.002,0.004
|
||||
truncate,123,868,81,0,0.003,141,0,4,0.002,0.005
|
||||
echo,118,710,67,0,0.003,137,0,4,0.001,0.004
|
||||
du,321,2323,130,0,0.003,341,0,4,0.003,0.005
|
||||
ptx,257,1763,111,0,0.031,277,0,4,0.002,0.038
|
||||
join,146,1164,90,0,0.013,165,0,4,0.002,0.018
|
||||
df,197,1797,102,0,0.003,217,0,4,0.002,0.005
|
||||
pwd,122,861,86,0,0.003,141,0,4,0.002,0.004
|
||||
test,121,826,71,0,0.003,140,0,4,0.002,0.004
|
||||
csplit,235,1559,106,0,0.003,255,0,4,0.002,0.005
|
||||
sort,239,2154,146,0,0.004,258,0,5,0.003,0.007
|
||||
whoami,120,790,77,0,0.003,139,0,4,0.002,0.004
|
||||
touch,187,1406,108,0,0.003,206,0,4,0.003,0.006
|
||||
unlink,121,817,77,0,0.003,140,0,4,0.002,0.004
|
||||
b2sum,141,956,88,0,0.004,160,0,5,0.002,0.005
|
||||
sleep,123,848,79,0,0.003,141,0,4,0.002,0.005
|
||||
fmt,139,908,81,0,0.007,158,0,4,0.003,0.010
|
||||
stty,158,1023,89,0,0.003,177,0,4,0.002,0.005
|
||||
logname,120,789,76,0,0.003,139,0,4,0.002,0.004
|
||||
chgrp,171,1433,105,0,0.003,190,0,4,0.003,0.006
|
||||
printenv,120,769,75,0,0.003,138,0,4,0.001,0.004
|
||||
seq,139,887,83,0,0.003,158,0,4,0.002,0.004
|
||||
uname,120,786,76,0,0.003,139,0,4,0.001,0.004
|
||||
sha224sum,segfault
|
||||
od,161,1156,90,0,0.022,181,0,4,0.002,0.023
|
||||
date,195,1178,95,0,0.003,215,0,4,0.002,0.005
|
||||
base64,122,856,81,0,0.003,141,0,4,0.002,0.005
|
||||
realpath,145,1078,81,0,0.003,164,0,4,0.002,0.005
|
||||
readlink,144,1042,81,0,0.003,163,0,4,0.002,0.005
|
||||
dircolors,159,1012,96,0,0.003,178,0,4,0.002,0.004
|
||||
timeout,124,888,95,0,0.006,142,0,4,0.002,0.007
|
||||
tac,216,1387,97,0,0.003,235,0,4,0.002,0.005
|
||||
numfmt,160,1079,92,0,0.003,179,0,4,0.002,0.005
|
||||
wc,146,1104,95,0,0.004,165,0,4,0.002,0.006
|
||||
basenc,145,1163,81,0,0.003,164,0,4,0.003,0.005
|
||||
comm,126,948,84,0,0.004,144,0,4,0.002,0.006
|
||||
nproc,121,817,79,0,0.003,140,0,4,0.002,0.004
|
||||
expr,232,1436,102,0,0.003,252,0,4,0.002,0.004
|
||||
cksum,187,1436,115,0,0.004,206,0,5,0.002,0.006
|
||||
printf,122,853,74,0,0.003,141,0,4,0.001,0.004
|
||||
groups,122,843,82,0,0.003,141,0,4,0.002,0.005
|
||||
chcon,169,1380,96,0,0.003,188,0,4,0.002,0.005
|
||||
factor,183,1284,115,0,0.003,202,0,4,0.003,0.006
|
||||
tail,165,1192,95,0,0.003,184,0,4,0.003,0.006
|
||||
env,142,1007,92,0,0.003,161,0,4,0.002,0.004
|
||||
pr,185,1370,101,0,0.005,204,0,4,0.002,0.007
|
||||
head,142,994,81,0,0.003,161,0,4,0.002,0.004
|
||||
kill,121,802,81,0,0.003,140,0,4,0.002,0.004
|
||||
uniq,142,987,86,0,0.003,161,0,4,0.002,0.006
|
||||
stat,209,1561,108,0,0.003,228,0,4,0.002,0.005
|
||||
link,121,818,78,0,0.003,140,0,4,0.002,0.005
|
||||
sum,140,923,86,0,0.003,159,0,4,0.002,0.005
|
||||
tsort,123,891,83,0,0.008,142,0,4,0.003,0.015
|
||||
mknod,123,875,81,0,0.003,142,0,4,0.002,0.005
|
||||
users,121,818,81,0,0.003,140,0,4,0.002,0.004
|
||||
dd,165,1284,101,0,0.003,184,0,5,0.002,0.005
|
||||
who,142,972,97,0,0.003,161,0,4,0.002,0.004
|
||||
sha1sum,segfault
|
||||
mktemp,126,960,86,0,0.003,145,0,4,0.002,0.004
|
||||
cut,140,903,88,0,0.003,159,0,4,0.002,0.005
|
||||
sha256sum,segfault
|
||||
dir,281,2551,148,0,0.003,301,0,5,0.003,0.005
|
||||
mkdir,144,1019,92,0,0.003,163,0,4,0.002,0.005
|
||||
nl,214,1377,92,0,0.004,233,0,4,0.002,0.006
|
||||
ginstall,239,2490,161,0,0.003,259,0,4,0.004,0.006
|
||||
shred,151,1215,109,0,0.003,170,0,4,0.002,0.005
|
||||
fold,122,843,80,0,0.004,141,0,4,0.002,0.005
|
||||
rmdir,123,863,83,0,0.003,142,0,4,0.002,0.005
|
||||
sha384sum,segfault
|
||||
mv,238,2461,149,0,0.003,258,0,4,0.004,0.007
|
||||
dirname,121,798,74,0,0.003,139,0,4,0.001,0.004
|
||||
id,141,940,88,0,0.003,160,0,4,0.002,0.005
|
||||
base32,122,861,81,0,0.003,141,0,4,0.002,0.005
|
||||
pinky,125,929,98,0,0.003,144,0,4,0.002,0.005
|
||||
ln,179,1589,111,0,0.003,198,0,4,0.003,0.006
|
||||
hostid,120,783,75,0,0.003,139,0,4,0.001,0.004
|
||||
chroot,148,1170,99,0,0.003,167,0,4,0.003,0.006
|
||||
ls,281,2551,148,0,0.003,301,0,5,0.003,0.006
|
||||
true,118,708,65,0,0.003,137,0,4,0.001,0.004
|
||||
cp,233,2273,148,0,0.003,253,0,4,0.003,0.006
|
||||
sync,121,809,80,0,0.003,140,0,4,0.002,0.004
|
||||
yes,121,801,75,0,0.003,140,0,4,0.003,0.008
|
||||
unexpand,123,907,82,0,0.003,142,0,4,0.003,0.009
|
||||
chown,172,1449,107,0,0.003,191,0,4,0.003,0.006
|
||||
getlimits,137,808,78,0,0.004,156,0,4,0.003,0.008
|
||||
chmod,165,1245,92,0,0.003,184,0,4,0.002,0.004
|
||||
uptime,140,924,93,0,0.003,159,0,5,0.003,0.009
|
||||
rm,171,1417,98,0,0.003,190,0,5,0.003,0.008
|
||||
vdir,281,2551,148,0,0.003,301,0,5,0.005,0.011
|
||||
false,118,708,65,0,0.003,137,0,4,0.003,0.008
|
||||
sha512sum,segfault
|
||||
tr,142,1049,83,0,0.003,161,0,4,0.003,0.009
|
||||
paste,122,880,77,0,0.004,141,0,4,0.003,0.009
|
||||
nohup,123,856,82,0,0.005,142,0,4,0.003,0.012
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
}
|
657
research/custom_loader/realizeClassWithoutSwift.txt
Normal file
657
research/custom_loader/realizeClassWithoutSwift.txt
Normal file
@ -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<method_t, method_list_t, method_list_t_authed_ptr>::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<property_t, property_list_t, RawPtr>::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<unsigned long, protocol_list_t, RawPtr>::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
|
||||
|
93
research/custom_loader/schedule_class_load.txt
Normal file
93
research/custom_loader/schedule_class_load.txt
Normal file
@ -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
|
||||
|
3384
research/custom_loader/test_file.txt
Normal file
3384
research/custom_loader/test_file.txt
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user