diff --git a/macho-go/cmd/extract-section/main.go b/macho-go/cmd/extract-section/main.go index 6f29aeb..d76216c 100644 --- a/macho-go/cmd/extract-section/main.go +++ b/macho-go/cmd/extract-section/main.go @@ -1,12 +1,12 @@ package main import ( - "ios-wrapper/pkg/ios/macho" "github.com/alecthomas/kong" + "ios-wrapper/pkg/ios/macho" - "os" - "fmt" - "bytes" + "bytes" + "fmt" + "os" ) type Argument struct { @@ -18,30 +18,30 @@ func main() { var cli Argument kong.Parse(&cli) - compare(cli.One, cli.Two) + compare(cli.One, cli.Two) } func compare(one string, two string) { f1, _ := os.OpenFile(one, os.O_RDONLY, 0644) f2, _ := os.OpenFile(two, os.O_RDONLY, 0644) - var mc1 macho.MachoContext - var mc2 macho.MachoContext + var mc1 macho.MachoContext + var mc2 macho.MachoContext mc1.ParseFile(f1, 0) mc2.ParseFile(f2, 0) - s1 := mc1.FindSection("__text") - s2 := mc2.FindSection("__text") + s1 := mc1.FindSection("__text") + s2 := mc2.FindSection("__text") - if (s1.Size() == s2.Size()) { - fmt.Println("Size is equal") - } else { - fmt.Printf("%x <> %x\n", s1.Size(), s2.Size()) - } + if s1.Size() == s2.Size() { + fmt.Println("Size is equal") + } else { + fmt.Printf("%x <> %x\n", s1.Size(), s2.Size()) + } - data1 := mc1.Cut(uint64(s1.Offset()), s1.Size()) - data2 := mc1.Cut(uint64(s2.Offset()), s2.Size()) - if (bytes.Compare(data1, data2) == 0) { - fmt.Println("Data is equal") - } + data1 := mc1.Cut(uint64(s1.Offset()), s1.Size()) + data2 := mc1.Cut(uint64(s2.Offset()), s2.Size()) + if bytes.Compare(data1, data2) == 0 { + fmt.Println("Data is equal") + } } diff --git a/macho-go/internal/wrapper/cli.go b/macho-go/internal/wrapper/cli.go index c1ad81d..8f1cd2b 100644 --- a/macho-go/internal/wrapper/cli.go +++ b/macho-go/internal/wrapper/cli.go @@ -57,13 +57,13 @@ func Cli() { return } else if command == "lipo split" { arg := cli.Lipo.Split - fat.FatSplit(arg.Fat) - return - } else if command == "lipo join" { + fat.FatSplit(arg.Fat) + return + } else if command == "lipo join" { arg := cli.Lipo.Join - fat.FatJoin(arg.Macho, arg.Out) - return - } + fat.FatJoin(arg.Macho, arg.Out) + return + } var pc ProgramContext var ofile OFile = nil @@ -81,7 +81,7 @@ func Cli() { pc.signed = arg.Signed pc.ReadUserConfig(arg.Config) - case "vltk": + case "vltk": arg := cli.Vltk ofile = NewOFile(arg.OFile) pc.remove_codesign = true diff --git a/macho-go/internal/wrapper/cli_parser.go b/macho-go/internal/wrapper/cli_parser.go index 54e7ef3..1b2c7c1 100644 --- a/macho-go/internal/wrapper/cli_parser.go +++ b/macho-go/internal/wrapper/cli_parser.go @@ -9,14 +9,14 @@ type WrapArgument struct { } type VltkArgument struct { - Out string `short:"o" required name:"outfile" help:"Modified Mach-O/Fat binary output file" type:"path"` - OFile string `arg help:"Path to Mach-O/Fat binary file" type:"existingfile"` + Out string `short:"o" required name:"outfile" help:"Modified Mach-O/Fat binary output file" type:"path"` + OFile string `arg help:"Path to Mach-O/Fat binary file" type:"existingfile"` } type InfoArgument struct { OFile string `arg help:"Path to Mach-O/Fat binary file" type:"existingfile"` - All bool `short:"a" help:"If print all information"` - Arch string `help:"Only print information in this arch"` + All bool `short:"a" help:"If print all information"` + Arch string `help:"Only print information in this arch"` } type RemoveCodesignArgument struct { @@ -40,17 +40,17 @@ type Addr2LineArgument struct { } type LipoArgument struct { - Join struct { - Out string `short:"o" required help:"Output Fat binary file" type:"path"` - Macho []string `arg help:"Macho binaries to join" type:"existingfile"` - } `cmd help:"Join Macho binaries into Fat binary"` - Split struct { - Fat string `arg help:"Fat binary to split" type:"existingfile"` - } `cmd help:"Split fat binary into files, named _"` + Join struct { + Out string `short:"o" required help:"Output Fat binary file" type:"path"` + Macho []string `arg help:"Macho binaries to join" type:"existingfile"` + } `cmd help:"Join Macho binaries into Fat binary"` + Split struct { + Fat string `arg help:"Fat binary to split" type:"existingfile"` + } `cmd help:"Split fat binary into files, named _"` } type PepeArgument struct { - OFile string `arg help:"Path to Mach-O/Fat binary file" type:"existingfile"` + OFile string `arg help:"Path to Mach-O/Fat binary file" type:"existingfile"` } type Argument struct { @@ -59,8 +59,8 @@ type Argument struct { Info InfoArgument `cmd help:"Show Mach-O/Fat binary information"` RemoveCodesign RemoveCodesignArgument `cmd aliases:"remove-signature" name:"remove-codesign" help:"Remove LC_CODE_SIGNATURE from Mach-O/Fat binary"` SignedBcell SignedBcellArgument `cmd name:"signed-bcell" help:"Change Protobuf into Protobuf"` - DisplayBcell DisplayBcellArgument `cmd name:"display-bcell" help:"Display Protobuf content"` - Addr2Line Addr2LineArgument `cmd name:"addr2line" help:"Resolve crash address from DWARF file"` - Lipo LipoArgument `cmd help:"split Fat binary or join Mach-O binares"` - Pepe PepeArgument `cmd help:"split Fat binary or join Mach-O binares"` + DisplayBcell DisplayBcellArgument `cmd name:"display-bcell" help:"Display Protobuf content"` + Addr2Line Addr2LineArgument `cmd name:"addr2line" help:"Resolve crash address from DWARF file"` + Lipo LipoArgument `cmd help:"split Fat binary or join Mach-O binares"` + Pepe PepeArgument `cmd help:"split Fat binary or join Mach-O binares"` } diff --git a/macho-go/internal/wrapper/info.go b/macho-go/internal/wrapper/info.go index 571b4a2..635f893 100644 --- a/macho-go/internal/wrapper/info.go +++ b/macho-go/internal/wrapper/info.go @@ -34,7 +34,6 @@ func (printer *InfoPrinter) Print() { fmt.Printf("Init functions at offset %s\n", &fun) } - symbols := mc.CollectLazyBindSymbols() if len(symbols) > 0 { fmt.Println("Lazy Symbols") diff --git a/macho-go/pkg/ios/const.go b/macho-go/pkg/ios/const.go index 290c892..a231095 100644 --- a/macho-go/pkg/ios/const.go +++ b/macho-go/pkg/ios/const.go @@ -92,8 +92,8 @@ const ( LC_VERSION_MIN_TVOS uint32 = 0x2F LC_VERSION_MIN_WATCHOS uint32 = 0x30 LC_BUILD_VERSION uint32 = 0x32 - LC_DYLD_EXPORTS_TRIE uint32 = 0x33 | 0x80000000 - LC_DYLD_CHAINED_FIXUPS uint32 = 0x34 | 0x80000000 + LC_DYLD_EXPORTS_TRIE uint32 = 0x33 | 0x80000000 + LC_DYLD_CHAINED_FIXUPS uint32 = 0x34 | 0x80000000 ) const ( diff --git a/macho-go/pkg/ios/fat/create-fat.go b/macho-go/pkg/ios/fat/create-fat.go index 3af875f..cf59eeb 100644 --- a/macho-go/pkg/ios/fat/create-fat.go +++ b/macho-go/pkg/ios/fat/create-fat.go @@ -1,8 +1,8 @@ -/// Contains the declaration of FatHeader and FatArch -/// These structs are always written using Big-Endian, -/// as documented in the mach-o/fat.h -/// This file also has a CreateFat function to generate -/// Fat file from a list of MachoContext +// / Contains the declaration of FatHeader and FatArch +// / These structs are always written using Big-Endian, +// / as documented in the mach-o/fat.h +// / This file also has a CreateFat function to generate +// / Fat file from a list of MachoContext package fat import ( @@ -16,8 +16,8 @@ import ( macho "ios-wrapper/pkg/ios/macho" ) -/// Get the alignment for the Mach-O in Fat binary -/// The returned value is the multiplier of 2 +// / Get the alignment for the Mach-O in Fat binary +// / The returned value is the multiplier of 2 func GetAlignment(h *macho.Header) uint32 { switch h.Cputype() { case CPU_TYPE_ARM, CPU_TYPE_ARM64: @@ -46,17 +46,17 @@ func MachosToFatArchs(machos []*macho.MachoContext) []*FatArch { return fa } -/// Create a Fat binary from MachoContext -/// Convert MachoContext to FatArch -/// Calculate the alignment, now using basic calculation -/// because iOS always has valid archs ARM -/// -/// Sort the Fat arch as per the cctools/lipo -/// Calculate the offset with each Mach-O -/// -/// Write the FatHeader -/// Write the FatArchs -/// Write the Mach-Os +// / Create a Fat binary from MachoContext +// / Convert MachoContext to FatArch +// / Calculate the alignment, now using basic calculation +// / because iOS always has valid archs ARM +// / +// / Sort the Fat arch as per the cctools/lipo +// / Calculate the offset with each Mach-O +// / +// / Write the FatHeader +// / Write the FatArchs +// / Write the Mach-Os func CreateFat(machos []*macho.MachoContext, outfilename string) error { archs := MachosToFatArchs(machos) sort.SliceStable(archs, func(i, j int) bool { @@ -139,9 +139,9 @@ func (fw *fatWriter) WriteFatArchs(w io.Writer, archs []*FatArch) { } } -/// for each fat arch sorted, we locate the MachoContext and -/// use it to Write to the buffer -/// locating the macho by its cputype and cpusubtype +// / for each fat arch sorted, we locate the MachoContext and +// / use it to Write to the buffer +// / locating the macho by its cputype and cpusubtype func (fw *fatWriter) WriteMachos( w io.WriteSeeker, archs []*FatArch, diff --git a/macho-go/pkg/ios/macho/dyld_info.go b/macho-go/pkg/ios/macho/dyld_info.go index a8183b8..bb24a91 100644 --- a/macho-go/pkg/ios/macho/dyld_info.go +++ b/macho-go/pkg/ios/macho/dyld_info.go @@ -46,41 +46,41 @@ func (sym *ImportSymbol) Stub() uint64 { } func (mc *MachoContext) CollectLazyBindSymbols() []*ImportSymbol { - if mc.dyldinfo == nil { - return mc.CollectLazyBindSymbolsModern() - } else { - return mc.CollectLazyBindSymbolsLegacy() - } + if mc.dyldinfo == nil { + return mc.CollectLazyBindSymbolsModern() + } else { + return mc.CollectLazyBindSymbolsLegacy() + } } // New convention using LC_DYLD_CHAINED_FIXUPS func (mc *MachoContext) CollectLazyBindSymbolsModern() []*ImportSymbol { - var buf []byte - for _, cmd := range mc.Linkedits() { - if (cmd.Cmd() != LC_DYLD_CHAINED_FIXUPS) { - continue - } + var buf []byte + for _, cmd := range mc.Linkedits() { + if cmd.Cmd() != LC_DYLD_CHAINED_FIXUPS { + continue + } - count_offset := int64(cmd.Dataoff()) + 16 - mc.file.WriteAt([]byte{0, 0, 0, 0}, count_offset) + count_offset := int64(cmd.Dataoff()) + 16 + mc.file.WriteAt([]byte{0, 0, 0, 0}, count_offset) - symbol_offset := int64(0x4000) - mc.file.WriteAt([]byte{0, 0, 0, 0, 0, 0, 0, 0}, symbol_offset) + symbol_offset := int64(0x4000) + mc.file.WriteAt([]byte{0, 0, 0, 0, 0, 0, 0, 0}, symbol_offset) - buf = mc.buf[cmd.Dataoff():cmd.Dataoff() + cmd.Datasize()] - break - } + buf = mc.buf[cmd.Dataoff() : cmd.Dataoff()+cmd.Datasize()] + break + } r := bytes.NewReader(buf) rr := bufio.NewReader(r) - var fixups_version int32 - var starts_offset int32 - var imports_offset int32 - var symbols_offset int32 - var imports_count int32 - var imports_format int32 - var symbols_format int32 + var fixups_version int32 + var starts_offset int32 + var imports_offset int32 + var symbols_offset int32 + var imports_count int32 + var imports_format int32 + var symbols_format int32 binary.Read(rr, mc.byteorder, &fixups_version) binary.Read(rr, mc.byteorder, &starts_offset) binary.Read(rr, mc.byteorder, &imports_offset) @@ -88,36 +88,36 @@ func (mc *MachoContext) CollectLazyBindSymbolsModern() []*ImportSymbol { binary.Read(rr, mc.byteorder, &imports_count) binary.Read(rr, mc.byteorder, &imports_format) binary.Read(rr, mc.byteorder, &symbols_format) - fmt.Printf( - "HMMGE %x %x\n", - imports_offset, - imports_count, - ) + fmt.Printf( + "HMMGE %x %x\n", + imports_offset, + imports_count, + ) - return []*ImportSymbol{} + return []*ImportSymbol{} } // Old convention using LC_DYLD_INFO_ONLY section and bytecode runner func (mc *MachoContext) CollectLazyBindSymbolsLegacy() []*ImportSymbol { start := mc.dyldinfo.lazy_bind_off - size := mc.dyldinfo.lazy_bind_size + size := mc.dyldinfo.lazy_bind_size end := start + size if size == 0 { return []*ImportSymbol{} } - // clear this whole section to 0x00 BIND_OPCODE_DONE - dummy := []byte{ - 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, - 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, - } - // make LINK EDIT section writable - // mc.file.WriteAt([]byte{0x03}, int64(0x3f8)) - // set number of symbols to 0 - mc.file.WriteAt([]byte{0, 0, 0, 0}, int64(0x444)) - mc.file.WriteAt([]byte{0, 0, 0, 0}, int64(0x44c)) - mc.file.WriteAt([]byte{0, 0, 0, 0}, int64(0x48c)) + // clear this whole section to 0x00 BIND_OPCODE_DONE + dummy := []byte{ + 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, + 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, + } + // make LINK EDIT section writable + // mc.file.WriteAt([]byte{0x03}, int64(0x3f8)) + // set number of symbols to 0 + mc.file.WriteAt([]byte{0, 0, 0, 0}, int64(0x444)) + mc.file.WriteAt([]byte{0, 0, 0, 0}, int64(0x44c)) + mc.file.WriteAt([]byte{0, 0, 0, 0}, int64(0x48c)) mc.file.WriteAt(dummy, int64(start)) buf := bytes.NewBuffer(mc.buf[start:end]) diff --git a/macho-go/pkg/ios/macho/edit.go b/macho-go/pkg/ios/macho/edit.go index 36de576..0e2c741 100644 --- a/macho-go/pkg/ios/macho/edit.go +++ b/macho-go/pkg/ios/macho/edit.go @@ -40,12 +40,13 @@ func rewriteLoadcommandsWithoutCodesignature(mc *MachoContext) { // CODE_SIGNATURE load commands points to the codesign data offset and size. // __LINKEDIT section points to data offset and size. // We have: -// linkedit = (section*) LC_SEGMENT.section[0] // name="__LINKEDIT" -// codesign = (linkedit_data_command*) LC_CODE_SIGNATURE -// BinarySize = { f.seek(0, SEEKEND); return f.tell() } // -// linkedit->fileoff + linkedit->filesize == codesign->dataOff + codesign->dataSize -// linkedit->fileoff + linkedit->filesize == BinarySize +// linkedit = (section*) LC_SEGMENT.section[0] // name="__LINKEDIT" +// codesign = (linkedit_data_command*) LC_CODE_SIGNATURE +// BinarySize = { f.seek(0, SEEKEND); return f.tell() } +// +// linkedit->fileoff + linkedit->filesize == codesign->dataOff + codesign->dataSize +// linkedit->fileoff + linkedit->filesize == BinarySize // // To remove the codesign data, we truncate the file to remove the codesign data. // Then we update the linkedit->filesize to linkedit->filesize - codesign->dataSize diff --git a/macho-go/pkg/ios/macho/load_commands.go b/macho-go/pkg/ios/macho/load_commands.go index 302da62..0105802 100644 --- a/macho-go/pkg/ios/macho/load_commands.go +++ b/macho-go/pkg/ios/macho/load_commands.go @@ -456,7 +456,7 @@ func (lcmd *Symtab) Cmdsize() uint32 { } func (lcmd *Symtab) Cmdname() string { - return fmt.Sprintf("%s symoff:0x%x nsyms:%d stroff:0x%x strsize:0x%x", + return fmt.Sprintf("%s symoff:0x%x nsyms:%d stroff:0x%x strsize:0x%x", lcmd.c.Cmdname(), lcmd.symoff, lcmd.nsyms, lcmd.stroff, lcmd.strsize) } diff --git a/macho-go/pkg/ios/macho/macho.go b/macho-go/pkg/ios/macho/macho.go index aab72f1..3d33fed 100644 --- a/macho-go/pkg/ios/macho/macho.go +++ b/macho-go/pkg/ios/macho/macho.go @@ -71,10 +71,12 @@ func (mc *MachoContext) WriteBufferTo(w io.Writer) (int, error) { // Parse the provided Mach-O binary from a file // The first 4 bytes of the file must be the MachO magic // That is: -// file.Seek(0, io.SeekStart) -// magic := make([]byte, 4) -// file.Read(magic) -// assert magic == []byte{macho magic bytes} +// +// file.Seek(0, io.SeekStart) +// magic := make([]byte, 4) +// file.Read(magic) +// assert magic == []byte{macho magic bytes} +// // or else, parsing error is panic func (mc *MachoContext) ParseFile(file *os.File, length int) error { file.Seek(0, io.SeekStart) diff --git a/macho-go/pkg/ios/macho/util.go b/macho-go/pkg/ios/macho/util.go index 6c73e72..b2704cb 100644 --- a/macho-go/pkg/ios/macho/util.go +++ b/macho-go/pkg/ios/macho/util.go @@ -83,8 +83,8 @@ func (mc *MachoContext) DylibExisted(name string) bool { // simple check // Advanced check requires expansion of @rpath for _, dylib := range mc.dylibs { - dylib_ := bytes.Trim(dylib.name, "\x00") - match := bytes.Compare(dylib_, []byte(name)) == 0 + dylib_ := bytes.Trim(dylib.name, "\x00") + match := bytes.Compare(dylib_, []byte(name)) == 0 log.WithFields(log.Fields{ "left": dylib_, "right": []byte(name), @@ -101,8 +101,8 @@ func (mc *MachoContext) RPathExisted(path string) bool { // simple check // Advanced check requires expansion of @rpath for _, rpath := range mc.rpaths { - rpath_ := bytes.Trim(rpath.path, "\x00") - match := bytes.Compare(rpath_, []byte(path)) == 0 + rpath_ := bytes.Trim(rpath.path, "\x00") + match := bytes.Compare(rpath_, []byte(path)) == 0 log.WithFields(log.Fields{ "left": rpath_, "right": []byte(path), @@ -138,7 +138,7 @@ func (mc *MachoContext) FindSegment(name string) Segment { } func (mc *MachoContext) Cut(offset uint64, size uint64) []byte { - return mc.buf[offset : offset + size]; + return mc.buf[offset : offset+size] } // INIT POINTER diff --git a/research/custom_loader/b.c b/research/custom_loader/b.c index 60f51ca..0a88e24 100644 --- a/research/custom_loader/b.c +++ b/research/custom_loader/b.c @@ -1,39 +1,40 @@ -#include -#include #include #include +#include +#include const uint32_t magic64 = 0xfeedfacf; const uint32_t magic32 = 0xfeedface; struct ProgramVars { - void* mh; // mach_header or mach_header64 - int* NXArgcPtr; - const char*** NXArgvPtr; - const char*** environPtr; - const char** __prognamePtr; + void *mh; // mach_header or mach_header64 + int *NXArgcPtr; + const char ***NXArgvPtr; + const char ***environPtr; + const char **__prognamePtr; }; -extern "C" uint32_t dyld_get_sdk_version(const mach_header* mh); +extern "C" uint32_t dyld_get_sdk_version(const mach_header *mh); -void decode_uleb128(char*& addr, uint32_t* ret) { +void decode_uleb128(char *&addr, uint32_t *ret) { uint32_t result = 0; int shift = 0; while (1) { - unsigned char byte = *(unsigned char*)(addr); + unsigned char byte = *(unsigned char *)(addr); addr++; result |= (byte & 0x7f) << shift; shift += 7; - if (!(byte & 0x80)) break; + if (!(byte & 0x80)) + break; } *ret = result; } -void* find_header(void* _func) { +void *find_header(void *_func) { // Approach 1: (not stable) // we assume that text section is small enough to fit on 1 page // so the header should stay at the top of the page due to allocation logic @@ -63,41 +64,41 @@ void* find_header(void* _func) { uint64_t func = (uint64_t)_func; uint64_t potential_head = func + (0x1000 - (func % page_size)); - void* head = 0; - uint32_t* x = (uint32_t*)(potential_head); + void *head = 0; + uint32_t *x = (uint32_t *)(potential_head); while (*x != magic64 && *x != magic32) { - x -= 0x1000/4; + x -= 0x1000 / 4; } - return (void*)x; + return (void *)x; } -void print_macho_summary(const void* header) { - const uint32_t magic = *(uint32_t*)header; - char* ptr = (char*)header; +void print_macho_summary(const void *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); + const uint32_t ncmds = *((uint32_t *)header + 4); printf("parsing macho at %p\n", header); printf("ncmds %x\n", ncmds); for (int i = 0; i < ncmds; i++) { - const uint32_t cmd = *((uint32_t*)ptr + 0); - const uint32_t cmdsize = *((uint32_t*)ptr + 1); + const uint32_t cmd = *((uint32_t *)ptr + 0); + const uint32_t cmdsize = *((uint32_t *)ptr + 1); printf(" cmd %x %x\n", cmd, cmdsize); if (cmd == LC_DYLD_EXPORTS_TRIE) { - const uint32_t offset = *((uint32_t*)ptr + 2); - const uint32_t size = *((uint32_t*)ptr + 3); + const uint32_t offset = *((uint32_t *)ptr + 2); + const uint32_t size = *((uint32_t *)ptr + 3); printf(" export trie: offset=0x%x size=0x%x\n", offset, size); } if (cmd == LC_SEGMENT_64) { - char* name = (char*)((uint64_t*)ptr + 1); - uint64_t vmaddr = *((uint64_t*)ptr + 3); - uint64_t vmsize = *((uint64_t*)ptr + 4); - uint64_t fileoffset = *((uint64_t*)ptr + 5); - uint64_t filesize = *((uint64_t*)ptr + 6); + char *name = (char *)((uint64_t *)ptr + 1); + uint64_t vmaddr = *((uint64_t *)ptr + 3); + uint64_t vmsize = *((uint64_t *)ptr + 4); + uint64_t fileoffset = *((uint64_t *)ptr + 5); + uint64_t filesize = *((uint64_t *)ptr + 6); if (strcmp(name, "__TEXT") == 0) { uint64_t slide = (uint64_t)header - vmaddr; printf(" --- slide=0x%llx ---\n", slide); @@ -110,9 +111,9 @@ void print_macho_summary(const void* header) { } } -void* get_export_trie(const void* header, uint32_t& size) { - const uint32_t magic = *(uint32_t*)header; - char* ptr = (char*)header; +void *get_export_trie(const void *header, uint32_t &size) { + const uint32_t magic = *(uint32_t *)header; + char *ptr = (char *)header; if (magic == magic64) { ptr += 0x20; } else { @@ -122,20 +123,20 @@ void* get_export_trie(const void* header, uint32_t& size) { uint64_t slice = 0; uint64_t linkedit_vmaddr = 0; uint64_t linkedit_fileoffset = 0; - const uint32_t ncmds = *((uint32_t*)header + 4); + const uint32_t ncmds = *((uint32_t *)header + 4); for (int i = 0; i < ncmds; i++) { - const uint32_t cmd = *((uint32_t*)ptr + 0); - const uint32_t cmdsize = *((uint32_t*)ptr + 1); + const uint32_t cmd = *((uint32_t *)ptr + 0); + const uint32_t cmdsize = *((uint32_t *)ptr + 1); if (cmd == LC_DYLD_EXPORTS_TRIE) { - const uint32_t offset = *((uint32_t*)ptr + 2); - size = *((uint32_t*)ptr + 3); + const uint32_t offset = *((uint32_t *)ptr + 2); + size = *((uint32_t *)ptr + 3); uint64_t offset_in_linkedit = (uint64_t)offset - linkedit_fileoffset; - return (void*)(linkedit_vmaddr + slice + offset_in_linkedit); + return (void *)(linkedit_vmaddr + slice + offset_in_linkedit); } 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); + char *name = (char *)((uint64_t *)ptr + 1); + uint64_t vmaddr = *((uint64_t *)ptr + 3); + uint64_t fileoffset = *((uint64_t *)ptr + 5); if (strcmp(name, "__TEXT") == 0) { slice = (uint64_t)header - vmaddr; } else if (strcmp(name, "__LINKEDIT") == 0) { @@ -148,9 +149,9 @@ void* get_export_trie(const void* header, uint32_t& size) { return 0; } -uint32_t should_follow_symbol(char*& buffer, char*& _find) { +uint32_t should_follow_symbol(char *&buffer, char *&_find) { // printf("follow check %s has prefix: %s\n", _find, buffer); - char* find = _find; + char *find = _find; char is_prefix = true; while (1) { int find_end = *find == 0; @@ -183,11 +184,11 @@ 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; - char* find = symbol; + char *ptr = (char *)trie; + char *find = symbol; while (1) { // terminal node will have data uint32_t data_count = 0; @@ -206,7 +207,7 @@ void* find_in_export_trie(const void* header, void* trie, char* symbol) { uint32_t follow_offset; decode_uleb128(ptr, &follow_offset); if (still_following) { - ptr = (char*)trie + follow_offset; + ptr = (char *)trie + follow_offset; break; } } @@ -221,10 +222,10 @@ void* find_in_export_trie(const void* header, void* trie, char* symbol) { ptr++; // flags // uleb128 offset decode_uleb128(ptr, &func); - return (void*)((char*)header + func); + return (void *)((char *)header + func); } -int hook_printf (const char * format, ... ) { +int hook_printf(const char *format, ...) { va_list args; va_start(args, format); @@ -236,16 +237,17 @@ int hook_printf (const char * format, ... ) { return status; } -__attribute__((constructor)) -static void bruh(int argc, const char* const argv[], const char* const envp[], const char* const apple[], const struct ProgramVars* vars) { +__attribute__((constructor)) static void +bruh(int argc, const char *const argv[], const char *const envp[], + const char *const apple[], const struct ProgramVars *vars) { // ProgramVars contains pointer to main executable (mapped) file - const void* main = (int*)(vars->mh); + const void *main = (int *)(vars->mh); // Find our lib (mapped) file - const void* thislib = find_header((void*)bruh); + const void *thislib = find_header((void *)bruh); // Find dyld lib (mapped) file using a no-sus function - const void* libdyld = find_header((void*)dyld_get_sdk_version); + const void *libdyld = find_header((void *)dyld_get_sdk_version); - const void* libc = find_header((void*)printf); + const void *libc = find_header((void *)printf); // From libdyld header, we can list exports table // to find all function we want to use @@ -273,16 +275,16 @@ static void bruh(int argc, const char* const argv[], const char* const envp[], c printf("libdyld header at %p\n", libdyld); for (int i = 0; i < _dyld_image_count(); i++) { - void* header = (void*)_dyld_get_image_header(i); - char* name = (char*)_dyld_get_image_name(i); + void *header = (void *)_dyld_get_image_header(i); + char *name = (char *)_dyld_get_image_name(i); int offset = _dyld_get_image_vmaddr_slide(i); printf("%p 0x%x name=%s\n", header, offset, name); } uint32_t trie_size; - void* thislib_export_trie = get_export_trie(thislib, trie_size); - void* libdyld_export_trie = get_export_trie(libdyld, trie_size); - void* libc_export_trie = get_export_trie(libc, trie_size); + void *thislib_export_trie = get_export_trie(thislib, trie_size); + void *libdyld_export_trie = get_export_trie(libdyld, trie_size); + void *libc_export_trie = get_export_trie(libc, trie_size); // printf("export this lib address %p\n", thislib_export_trie); // for (int i = 0; i < 136; i++) { @@ -291,7 +293,6 @@ static void bruh(int argc, const char* const argv[], const char* const envp[], c // } // printf("\n"); - // printf("export dyld lib address %llx\n", (uint64_t)libdyld_export_trie); // for (int i = 0; i < 0x11e0; i++) { // if (i % 0x10 == 0) printf("\n"); @@ -310,22 +311,24 @@ static void bruh(int argc, const char* const argv[], const char* const envp[], c // fwrite(system_export_trie, trie_size, 1, write_ptr); struct test_find_export { - const char* name; - const void* lib; - void* trie; - void* original; + const char *name; + const void *lib; + void *trie; + void *original; }; struct test_find_export find_export_testcases[] = { - {"__Z11find_headerPv", thislib, thislib_export_trie, (void*)find_header}, - {"__dyld_get_image_name", libdyld, libdyld_export_trie, (void*)_dyld_get_image_name}, - {"__dyld_image_count", libdyld, libdyld_export_trie, (void*)_dyld_image_count}, - {"_printf",libc, libc_export_trie, (void*)printf}, + {"__Z11find_headerPv", thislib, thislib_export_trie, (void *)find_header}, + {"__dyld_get_image_name", libdyld, libdyld_export_trie, + (void *)_dyld_get_image_name}, + {"__dyld_image_count", libdyld, libdyld_export_trie, + (void *)_dyld_image_count}, + {"_printf", libc, libc_export_trie, (void *)printf}, }; for (int i = 0; i < 4; i++) { struct test_find_export test = find_export_testcases[i]; - void* found = find_in_export_trie(test.lib, test.trie, (char*)test.name); + void *found = find_in_export_trie(test.lib, test.trie, (char *)test.name); printf("%s: Found=%p | Expect=%p\n", test.name, found, test.original); } @@ -334,11 +337,11 @@ static void bruh(int argc, const char* const argv[], const char* const envp[], c // modern symbol resolve // fix got - uint64_t* got = (uint64_t*)((char*)main + 0x4000); - + uint64_t *got = (uint64_t *)((char *)main + 0x4000); printf("BEFORE symbol bind code is %llx\n", *got); - vm_protect(mach_task_self(), (uint64_t)got, 0x4000, 0, VM_PROT_READ | VM_PROT_WRITE); + vm_protect(mach_task_self(), (uint64_t)got, 0x4000, 0, + VM_PROT_READ | VM_PROT_WRITE); // fix got table // *got = (uint64_t)find_in_export_trie(libc, libc_export_trie, "_printf");