add remove imports command

This commit is contained in:
2023-06-01 17:29:23 +07:00
parent 9d94dd5494
commit b5ee7124ab
7 changed files with 161 additions and 46 deletions

View File

@ -14,6 +14,7 @@ import (
type ImportSymbol struct {
name string
typ string
dylib string
segment uint32
segment_offset uint32
@ -29,6 +30,10 @@ func (sym *ImportSymbol) Name() string {
return sym.name
}
func (sym *ImportSymbol) Type() string {
return sym.typ
}
func (sym *ImportSymbol) Dylib() string {
return sym.dylib
}
@ -45,28 +50,22 @@ func (sym *ImportSymbol) Stub() uint64 {
return sym.stub
}
func (mc *MachoContext) CollectLazyBindSymbols() []*ImportSymbol {
func (mc *MachoContext) CollectBindSymbols() []*ImportSymbol {
if mc.dyldinfo == nil {
return mc.CollectLazyBindSymbolsModern()
return mc.CollectBindSymbolsModern()
} else {
return mc.CollectLazyBindSymbolsLegacy()
return mc.CollectBindSymbolsLegacy()
}
}
// New convention using LC_DYLD_CHAINED_FIXUPS
func (mc *MachoContext) CollectLazyBindSymbolsModern() []*ImportSymbol {
func (mc *MachoContext) CollectBindSymbolsModern() []*ImportSymbol {
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)
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
}
@ -98,34 +97,62 @@ func (mc *MachoContext) CollectLazyBindSymbolsModern() []*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
end := start + size
func (mc *MachoContext) CollectBindSymbolsLegacy() []*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))
// mc.file.WriteAt(dummy, int64(start))
noLazy := (func() []*ImportSymbol {
start := mc.dyldinfo.bind_off
size := mc.dyldinfo.bind_size
end := start + size
buf := bytes.NewBuffer(mc.buf[start:end])
return mc.readBindStream(buf, "no lazy")
})()
lazy := (func() []*ImportSymbol {
start := mc.dyldinfo.lazy_bind_off
size := mc.dyldinfo.lazy_bind_size
end := start + size
buf := bytes.NewBuffer(mc.buf[start:end])
return mc.readBindStream(buf, "lazy")
})()
weak := (func() []*ImportSymbol {
start := mc.dyldinfo.weak_bind_off
size := mc.dyldinfo.weak_bind_size
end := start + size
buf := bytes.NewBuffer(mc.buf[start:end])
return mc.readBindStream(buf, "weak")
})()
var symbols []*ImportSymbol
symbols = append(symbols, noLazy...)
symbols = append(symbols, lazy...)
symbols = append(symbols, weak...)
return symbols
}
func (mc *MachoContext) readBindStream(buf *bytes.Buffer, typ string) []*ImportSymbol {
size := buf.Len()
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))
mc.file.WriteAt(dummy, int64(start))
buf := bytes.NewBuffer(mc.buf[start:end])
offset := uint(0)
var syms []*ImportSymbol
var sym ImportSymbol
// symoffset := offset
offset := uint(0)
lastop_done := false
for offset < uint(size) {
d, _ := buf.ReadByte()
@ -151,6 +178,7 @@ func (mc *MachoContext) CollectLazyBindSymbolsLegacy() []*ImportSymbol {
case BIND_OPCODE_DO_BIND:
if sym.name != "" {
new_sym := sym
new_sym.typ = typ
syms = append(syms, &new_sym)
// fmt.Printf("Offset 0x%x: Symbol %+v\n", symoffset, sym)
@ -187,6 +215,9 @@ func (mc *MachoContext) CollectLazyBindSymbolsLegacy() []*ImportSymbol {
case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
sym.name, _ = buf.ReadString(0)
// ReadString input the 0x00 byte to buffer
// while we are string so we can remove that
sym.name = sym.name[:len(sym.name)-1]
offset += uint(len(sym.name))
break

View File

@ -267,3 +267,51 @@ func (mc *MachoContext) UpdateHeaderRemoveLcmd(size uint32) {
mc.file.WriteAt(mc.header.Serialize(mc), 0)
}
}
func (mc *MachoContext) RemoveBindSymbols() {
if !mc.WriteEnabled() {
return
}
if mc.dyldinfo == nil {
mc.removeBindSymbolsModern()
} else {
mc.removeBindSymbolsLegacy()
}
}
func (mc *MachoContext) removeBindSymbolsModern() {}
func (mc *MachoContext) removeBindSymbolsLegacy() {
start := mc.dyldinfo.lazy_bind_off
size := mc.dyldinfo.lazy_bind_size
// set lazy opcodes to 0x00 == DO_BIND
// but no symbol state to bind
mc.file.WriteAt(make([]byte, size), int64(start))
calculateHash := func(name string) uint32 {
var h uint32 = 0x811c9dc5
for _, s := range name {
h ^= uint32(s)
h *= 0x01000193
}
return h
}
// 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; uint64_t address;};")
fmt.Println("struct imported_symbol imported_table[] = {")
count := 0
for _, symbol := range mc.CollectBindSymbols() {
if symbol.Type() != "lazy" {
continue
}
count += 1
dylib_hash := calculateHash(symbol.Dylib())
fmt.Printf("{\"%s\", \"%s\", 0x%x, 0x%x},\n",
symbol.Name(), symbol.Dylib(), dylib_hash, symbol.Address());
}
fmt.Println("};")
fmt.Printf("uint32_t nimports = %d;\n", count);
}