diff --git a/macho-go/internal/wrapper/action/save_imports.go b/macho-go/internal/wrapper/action/save_imports.go index efa7b58..fc87088 100644 --- a/macho-go/internal/wrapper/action/save_imports.go +++ b/macho-go/internal/wrapper/action/save_imports.go @@ -139,14 +139,14 @@ 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 + selectors_list := []*protomodel.MachoInfo_Selector{} + for _, sel := range mc.CollectSpecialSelectors() { + selectors_list = append(selectors_list, &protomodel.MachoInfo_Selector{ + Idx: uint32(sel.Idx()), + Name: sel.Name(), + }) + } + mf.Info().SpecialSelectors = selectors_list return nil } diff --git a/macho-go/internal/wrapper/cli.go b/macho-go/internal/wrapper/cli.go index 3e7efda..fffc048 100644 --- a/macho-go/internal/wrapper/cli.go +++ b/macho-go/internal/wrapper/cli.go @@ -302,16 +302,16 @@ func bcell2header(bfile string, header string) { 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) - } + 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) - } + 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())) } diff --git a/macho-go/pkg/ios/macho/dyld_info.go b/macho-go/pkg/ios/macho/dyld_info.go index 21dd92c..a616392 100644 --- a/macho-go/pkg/ios/macho/dyld_info.go +++ b/macho-go/pkg/ios/macho/dyld_info.go @@ -43,7 +43,7 @@ func (sym *ImportSymbol) Type() string { } func (sym *ImportSymbol) SafeForRemoval() bool { - return sym.typ == "lazy" || sym.typ == "fixups" + return sym.typ == "lazy" || sym.typ == "fixups" } func (sym *ImportSymbol) Dylib() string { diff --git a/macho-go/pkg/ios/macho/edit.go b/macho-go/pkg/ios/macho/edit.go index 67a2d8a..1d75c04 100644 --- a/macho-go/pkg/ios/macho/edit.go +++ b/macho-go/pkg/ios/macho/edit.go @@ -280,8 +280,8 @@ func (mc *MachoContext) RemoveBindSymbols() { rand.Seed(time.Now().UnixNano()) - isModernSymbol := mc.dyldinfo == nil - isLegacySymbol := !isModernSymbol + isModernSymbol := mc.dyldinfo == nil + isLegacySymbol := !isModernSymbol if isModernSymbol { mc.removeBindSymbolsModern() diff --git a/macho-go/pkg/ios/macho/objc.go b/macho-go/pkg/ios/macho/objc.go index ec01d8d..779ce27 100644 --- a/macho-go/pkg/ios/macho/objc.go +++ b/macho-go/pkg/ios/macho/objc.go @@ -1,27 +1,26 @@ package macho import ( - "fmt" - "bytes" - "encoding/binary" - "io" - "strings" + "bytes" + "encoding/binary" + "fmt" + "io" + "strings" . "ios-wrapper/pkg/ios" ) - type SpecialSelector struct { - idx uint - name string + idx uint + name string } func (sel *SpecialSelector) Idx() uint { - return sel.idx + return sel.idx } func (sel *SpecialSelector) Name() string { - return sel.name + return sel.name } // collect the index and the name in selector list of special method names @@ -33,9 +32,9 @@ func (sel *SpecialSelector) Name() string { // - retain func (mc *MachoContext) CollectSpecialSelectors() []*SpecialSelector { - var special_selectors []*SpecialSelector - var methods []byte - var methname_offset uint32 + var special_selectors []*SpecialSelector + var methods []byte + var methname_offset uint32 for _, cmd := range mc.commands { if cmd.Cmd() == LC_MAIN { @@ -49,50 +48,50 @@ func (mc *MachoContext) CollectSpecialSelectors() []*SpecialSelector { 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())) + 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())) + selectors_buffer := make([]byte, section.Size()) + mc.file.ReadAt(selectors_buffer, int64(section.Offset())) - buffer := bytes.NewReader(selectors_buffer) + 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 + 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, - }) - } + 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 - } + binary.Read(buffer, mc.byteorder, &offset) // ignore rebase arguments + } } } } } - return special_selectors + return special_selectors } func (mc *MachoContext) ReworkForObjc() { @@ -131,14 +130,14 @@ func (mc *MachoContext) ReworkForObjc() { 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" + // 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())) + mc.file.WriteAt(make([]byte, section.Size()), int64(section.Offset())) } section_ptr += 16*2 + 8*2 + 4*8 } @@ -167,7 +166,7 @@ func (mc *MachoContext) ReworkForObjc() { last := sections[len(sections)-1] data_end = int(last.Addr() - segment.Vmaddr() + segment.Fileoff() + last.Size()) - // do not register selector and see what happens + // 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 { @@ -196,24 +195,24 @@ func (mc *MachoContext) ReworkForObjc() { // 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 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 @@ -223,32 +222,32 @@ func (mc *MachoContext) ReworkForObjc() { 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 + // 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 + stp x30, x8, [sp], #-0x10 + stp x3, x2, [sp], #-0x10 + stp x1, x0, [sp], #-0x10 - # custom intializer - ldr x9, [x8] - blr x9 + # custom intializer + ldr x9, [x8] + blr x9 - ldp x1, x0, [sp, #0x10]! - ldp x3, x2, [sp, #0x10]! - ldp x30, x8, [sp, #0x10]! + 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 - */ + # 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) @@ -362,4 +361,3 @@ func (mc *MachoContext) ReworkForObjc() { offset += 4 } } -