fix fixups chain rewrite stops at first entry

This commit is contained in:
nganhkhoa 2023-06-07 10:49:05 +07:00
parent 1b7da037bb
commit 88bb0aa09d
4 changed files with 49 additions and 3 deletions

View File

@ -29,6 +29,8 @@ type ImportSymbol struct {
// push number
pnum uint32
stub uint64
next int // only for LC_DYLD_CHAINED_FIXUPS
}
func (sym *ImportSymbol) Name() string {
@ -120,7 +122,7 @@ func (mc *MachoContext) CollectBindSymbolsModern() []*ImportSymbol {
for {
mc.file.Read(code)
v := binary.LittleEndian.Uint64(code)
v := mc.byteorder.Uint64(code)
var bind C.int
var ret1 C.ulonglong
@ -133,7 +135,7 @@ func (mc *MachoContext) CollectBindSymbolsModern() []*ImportSymbol {
name := C.GoString(s.name)
dylib := string(mc.dylibs[int(s.lib_ordinal)-1].name[:])
// fmt.Printf("%x bind=%d (%s)%s\n", address, bind, dylib, name)
fmt.Printf("// 0x%x bind=%d (%s)%s\n", address, bind, dylib, name)
sym.address = uint64(address)
sym.name = name
@ -142,14 +144,19 @@ func (mc *MachoContext) CollectBindSymbolsModern() []*ImportSymbol {
sym.segment = uint32(mc.findSegmentIndexAt(uint64(address)))
sym.file_address = uint64(address)
sym.next = int(next)
new_sym := sym
syms = append(syms, &new_sym)
} else {
fmt.Printf("// 0x%x rebase=%d target=0x%x high8=0x%x\n", address, bind, ret1, ret2)
}
address += 8
if int(next) == 0 {
break
}
// because the pointer move up 8 bytes already so we minus 8
mc.file.Seek(int64(next * 4) - 8, io.SeekCurrent)
}
mc.file.Seek(0, io.SeekStart)
}

View File

@ -3,12 +3,17 @@ package macho
import (
"fmt"
"io"
"math/rand"
"time"
log "github.com/sirupsen/logrus"
. "ios-wrapper/pkg/ios"
)
// #include "fixups.h"
import "C"
func rewriteLoadcommandsWithoutCodesignature(mc *MachoContext) {
if mc.Is64bit() {
mc.file.Seek(int64(Header_size_64), io.SeekStart)
@ -273,6 +278,8 @@ func (mc *MachoContext) RemoveBindSymbols() {
return
}
rand.Seed(time.Now().UnixNano())
if mc.dyldinfo == nil {
mc.removeBindSymbolsModern()
} else {
@ -291,6 +298,7 @@ func (mc *MachoContext) RemoveBindSymbols() {
// due to some limitations when design this tool
// we write the c code to stdout lol
fmt.Println("struct imported_symbol {const char* name; const char* lib; uint32_t hash; int segment_i; uint64_t offset;};")
fmt.Println("const char* lib_to_resolve = \"main\";")
fmt.Println("struct imported_symbol imported_table[] = {")
count := 0
for _, symbol := range mc.CollectBindSymbols() {
@ -313,7 +321,28 @@ func (mc *MachoContext) RemoveBindSymbols() {
fmt.Printf("{\"%s\", \"%s\", 0x%x, 0x%x, 0x%x},\n",
symbol.Name(), symbol.Dylib(), dylib_hash, symbol.segment, offset);
mc.file.WriteAt(make([]byte, 8), int64(symbol.file_address))
if mc.dyldinfo != nil {
// for legacy resolve the opcodes can be rewritten as 0x00
mc.file.WriteAt(make([]byte, 8), int64(symbol.file_address))
} else {
// for modern resolve the opcodes must not be rewritten as 0x00
// because it contains 2 types of opcodes, BIND and REBASE
// we only fix BIND and leave REBASE intact
// However, each opcodes has a *next* field to the next opcode
// So if we want to leave the header intact (contains pointers, size)
// We should rewrite this as REBASE opcode (so no symbol lookup happens)
// and it can continue
// we can write random values, because the loader just do
// (high8 << 56 | target) - mach_header
// or something, so no symbol lookup and no error at runtime
target := rand.Int()
high8 := rand.Int()
value := C.MakeRebaseFixupOpcode(C.int(symbol.next), C.ulonglong(target), C.ulonglong(high8))
v := make([]byte, 8)
mc.byteorder.PutUint64(v, uint64(value))
mc.file.WriteAt(v, int64(symbol.file_address))
}
}
fmt.Println("};")
fmt.Printf("uint32_t nimports = %d;\n", count);

View File

@ -94,6 +94,15 @@ int ParseFixValue(int format, uint64_t value, int* bind, uint64_t* ret1, uint64_
}
}
uint64_t MakeRebaseFixupOpcode(int next, uint64_t target, uint64_t high8) {
uint64_t value;
struct dyld_chained_ptr_64_rebase* b = (struct dyld_chained_ptr_64_rebase*)&value;
b->next = next;
b->target = target;
b->high8 = high8;
return value;
}
void ParseFixUps(uint8_t* buffer) {
struct dyld_chained_fixups_header* header = (struct dyld_chained_fixups_header*)buffer;
printf("starts=0x%x\n", header->starts_offset);

View File

@ -30,4 +30,5 @@ struct ImportTable GetImportsTable(uint8_t* header_ptr);
struct ImportSymbol GetImportsAt(struct ImportTable* table, int i);
int GetSegmentFixAt(uint8_t* buffer, uint32_t i, struct SegmentFix* fix);
int ParseFixValue(int format, uint64_t value, int* bind, uint64_t* ret1, uint64_t* ret2);
uint64_t MakeRebaseFixupOpcode(int next, uint64_t target, uint64_t high8);
#endif