This commit is contained in:
nganhkhoa 2024-01-10 15:56:32 +07:00
parent 9a8ab15d88
commit 41144ff0dc
5 changed files with 106 additions and 108 deletions

View File

@ -139,14 +139,14 @@ func (action *saveImports) saveToInfo(mf *MachoFile) error {
mf.Info().Main = mc.Main() mf.Info().Main = mc.Main()
selectors_list := []*protomodel.MachoInfo_Selector{} selectors_list := []*protomodel.MachoInfo_Selector{}
for _, sel := range mc.CollectSpecialSelectors() { for _, sel := range mc.CollectSpecialSelectors() {
selectors_list = append(selectors_list, &protomodel.MachoInfo_Selector{ selectors_list = append(selectors_list, &protomodel.MachoInfo_Selector{
Idx: uint32(sel.Idx()), Idx: uint32(sel.Idx()),
Name: sel.Name(), Name: sel.Name(),
}) })
} }
mf.Info().SpecialSelectors = selectors_list mf.Info().SpecialSelectors = selectors_list
return nil return nil
} }

View File

@ -302,16 +302,16 @@ func bcell2header(bfile string, header string) {
fmt.Fprintf(w, "__attribute__((section(\"__DATA,bshield\")))\n") fmt.Fprintf(w, "__attribute__((section(\"__DATA,bshield\")))\n")
fmt.Fprintf(w, "uint32_t special_selectors_idx[] = {\n") fmt.Fprintf(w, "uint32_t special_selectors_idx[] = {\n")
for _, selector := range info.GetSpecialSelectors() { for _, selector := range info.GetSpecialSelectors() {
fmt.Fprintf(w, "%x,\n", selector.Idx) fmt.Fprintf(w, "%x,\n", selector.Idx)
} }
fmt.Fprintf(w, "};\n") fmt.Fprintf(w, "};\n")
fmt.Fprintf(w, "__attribute__((section(\"__DATA,bshield\")))\n") fmt.Fprintf(w, "__attribute__((section(\"__DATA,bshield\")))\n")
fmt.Fprintf(w, "const char* special_selectors_name[] = {\n") fmt.Fprintf(w, "const char* special_selectors_name[] = {\n")
for _, selector := range info.GetSpecialSelectors() { for _, selector := range info.GetSpecialSelectors() {
fmt.Fprintf(w, "\"%s\",\n", selector.Name) fmt.Fprintf(w, "\"%s\",\n", selector.Name)
} }
fmt.Fprintf(w, "};\n") fmt.Fprintf(w, "};\n")
fmt.Fprintf(w, "uint32_t n_selectors = %d;\n", len(info.GetSpecialSelectors())) fmt.Fprintf(w, "uint32_t n_selectors = %d;\n", len(info.GetSpecialSelectors()))
} }

View File

@ -43,7 +43,7 @@ func (sym *ImportSymbol) Type() string {
} }
func (sym *ImportSymbol) SafeForRemoval() bool { func (sym *ImportSymbol) SafeForRemoval() bool {
return sym.typ == "lazy" || sym.typ == "fixups" return sym.typ == "lazy" || sym.typ == "fixups"
} }
func (sym *ImportSymbol) Dylib() string { func (sym *ImportSymbol) Dylib() string {

View File

@ -280,8 +280,8 @@ func (mc *MachoContext) RemoveBindSymbols() {
rand.Seed(time.Now().UnixNano()) rand.Seed(time.Now().UnixNano())
isModernSymbol := mc.dyldinfo == nil isModernSymbol := mc.dyldinfo == nil
isLegacySymbol := !isModernSymbol isLegacySymbol := !isModernSymbol
if isModernSymbol { if isModernSymbol {
mc.removeBindSymbolsModern() mc.removeBindSymbolsModern()

View File

@ -1,27 +1,26 @@
package macho package macho
import ( import (
"fmt" "bytes"
"bytes" "encoding/binary"
"encoding/binary" "fmt"
"io" "io"
"strings" "strings"
. "ios-wrapper/pkg/ios" . "ios-wrapper/pkg/ios"
) )
type SpecialSelector struct { type SpecialSelector struct {
idx uint idx uint
name string name string
} }
func (sel *SpecialSelector) Idx() uint { func (sel *SpecialSelector) Idx() uint {
return sel.idx return sel.idx
} }
func (sel *SpecialSelector) Name() string { func (sel *SpecialSelector) Name() string {
return sel.name return sel.name
} }
// collect the index and the name in selector list of special method names // collect the index and the name in selector list of special method names
@ -33,9 +32,9 @@ func (sel *SpecialSelector) Name() string {
// - retain // - retain
func (mc *MachoContext) CollectSpecialSelectors() []*SpecialSelector { func (mc *MachoContext) CollectSpecialSelectors() []*SpecialSelector {
var special_selectors []*SpecialSelector var special_selectors []*SpecialSelector
var methods []byte var methods []byte
var methname_offset uint32 var methname_offset uint32
for _, cmd := range mc.commands { for _, cmd := range mc.commands {
if cmd.Cmd() == LC_MAIN { 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 { if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__TEXT")) == 0 {
for _, section := range segment.Sections() { for _, section := range segment.Sections() {
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_methname")) == 0 { if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_methname")) == 0 {
methname_offset = section.Offset() methname_offset = section.Offset()
methods = make([]byte, section.Size()) methods = make([]byte, section.Size())
mc.file.ReadAt(methods, int64(section.Offset())) mc.file.ReadAt(methods, int64(section.Offset()))
} }
} }
} }
if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__DATA")) == 0 { if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__DATA")) == 0 {
for _, section := range segment.Sections() { for _, section := range segment.Sections() {
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_selrefs")) == 0 { if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_selrefs")) == 0 {
selectors_buffer := make([]byte, section.Size()) selectors_buffer := make([]byte, section.Size())
mc.file.ReadAt(selectors_buffer, int64(section.Offset())) 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++ { for i := uint(0); i < uint(section.Size())/8; i++ {
// this field is actually a Rebase // this field is actually a Rebase
// we assume that no rebase is needed // we assume that no rebase is needed
// so everything sticks to its file offset // so everything sticks to its file offset
var offset uint32 var offset uint32
binary.Read(buffer, mc.byteorder, &offset) // first 4 bytes is offset binary.Read(buffer, mc.byteorder, &offset) // first 4 bytes is offset
var name_builder strings.Builder var name_builder strings.Builder
for j := uint32(0); ; j++ { for j := uint32(0); ; j++ {
c := methods[offset - methname_offset + j] c := methods[offset-methname_offset+j]
if c == 0 { if c == 0 {
break break
} }
name_builder.WriteByte(c) name_builder.WriteByte(c)
} }
name := name_builder.String() name := name_builder.String()
if name == "load" { if name == "load" {
special_selectors = append(special_selectors, &SpecialSelector{ special_selectors = append(special_selectors, &SpecialSelector{
idx: i, idx: i,
name: name, 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() { func (mc *MachoContext) ReworkForObjc() {
@ -131,14 +130,14 @@ func (mc *MachoContext) ReworkForObjc() {
mc.file.WriteAt([]byte{0, 0, 0, 0}, section_ptr+0x40) mc.file.WriteAt([]byte{0, 0, 0, 0}, section_ptr+0x40)
} }
// erases all objc method names // erases all objc method names
// this should still works because the cache inserts the pointer value not string // 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 // 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 // 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" // 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 { if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_methname")) == 0 {
// mc.file.WriteAt([]byte("__objc_methbruh"), section_ptr) // 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 section_ptr += 16*2 + 8*2 + 4*8
} }
@ -167,7 +166,7 @@ func (mc *MachoContext) ReworkForObjc() {
last := sections[len(sections)-1] last := sections[len(sections)-1]
data_end = int(last.Addr() - segment.Vmaddr() + segment.Fileoff() + last.Size()) 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 section_ptr := ptr + 0x40 + 8
for _, section := range segment.Sections() { for _, section := range segment.Sections() {
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_selrefs")) == 0 { 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 stack to same value before calling main
// must recover link register before calling main // must recover link register before calling main
// ┌─────────────────┐ // ┌─────────────────┐
// │ │ // │ │
// shellcode starts ────┼─────────────────┼───── │ │instruction // shellcode starts ────┼─────────────────┼───── │ │instruction
// │ │ │ │fetch RIP size // │ │ │ │fetch RIP size
// RIP returns ────┼─────────────────┼───── ▲ │ │ // RIP returns ────┼─────────────────┼───── ▲ │ │
// │ │ │ │ // │ │ │ │
// │ │ │ │ shellcode length // │ │ │ │ shellcode length
// shellcode ends │ │ │ offset │ // shellcode ends │ │ │ offset │
// __text ────┼─────────────────┼───── │ range │ // __text ────┼─────────────────┼───── │ range │
// │ │ │ │ __DATA ends - __text // │ │ │ │ __DATA ends - __text
// │ │ │ │ // │ │ │ │
// __DATA ends ────┼─────────────────┼───── ▼ │ // __DATA ends ────┼─────────────────┼───── ▼ │
// │ │ // │ │
// │ │ // │ │
// │ │ // │ │
// │ │ // │ │
// │ │ // │ │
// └─────────────────┘ // └─────────────────┘
shellcode := []uint32{} shellcode := []uint32{}
ins_size_byte := 4 ins_size_byte := 4
@ -223,32 +222,32 @@ func (mc *MachoContext) ReworkForObjc() {
isArm := (mc.header.cputype & 0xff) == 12 isArm := (mc.header.cputype & 0xff) == 12
if isArm { if isArm {
// we use shorthand store/load multiple // we use shorthand store/load multiple
// arm also has different indexing instruction, so be careful // arm also has different indexing instruction, so be careful
// https://developer.arm.com/documentation/102374/0101/Loads-and-stores---addressing // https://developer.arm.com/documentation/102374/0101/Loads-and-stores---addressing
/* /*
adr x8, 0 adr x8, 0
# x9 = (offset end of __DATA) - (offset shellcode) # x9 = (offset end of __DATA) - (offset shellcode)
movz x9, #0x9999 movz x9, #0x9999
add x8, x8, x9 add x8, x8, x9
stp x30, x8, [sp], #-0x10 stp x30, x8, [sp], #-0x10
stp x3, x2, [sp], #-0x10 stp x3, x2, [sp], #-0x10
stp x1, x0, [sp], #-0x10 stp x1, x0, [sp], #-0x10
# custom intializer # custom intializer
ldr x9, [x8] ldr x9, [x8]
blr x9 blr x9
ldp x1, x0, [sp, #0x10]! ldp x1, x0, [sp, #0x10]!
ldp x3, x2, [sp, #0x10]! ldp x3, x2, [sp, #0x10]!
ldp x30, x8, [sp, #0x10]! ldp x30, x8, [sp, #0x10]!
# original main # original main
# link register is set so jump only # link register is set so jump only
ldr x9, [x8, #8] ldr x9, [x8, #8]
br x9 br x9
*/ */
shellcode = []uint32{ shellcode = []uint32{
0x10000008, 0x10000008,
0, // x9 = (offset end of __DATA) - (offset shellcode) 0, // x9 = (offset end of __DATA) - (offset shellcode)
@ -362,4 +361,3 @@ func (mc *MachoContext) ReworkForObjc() {
offset += 4 offset += 4
} }
} }