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()
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
}

View File

@ -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()))
}

View File

@ -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 {

View File

@ -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()

View File

@ -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
}
}