add remove imports command

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

View File

@ -0,0 +1,21 @@
package action
import (
. "ios-wrapper/internal/wrapper/ofile"
)
type removeImports struct{}
func (action *removeImports) withMacho(mf *MachoFile) error {
mf.Context().RemoveBindSymbols()
return nil
}
func (action *removeImports) withFat(ff *FatFile) error {
return defaultWithFat(action, ff)
}
func NewRemoveImportsAction() *removeImports {
return &removeImports{}
}

View File

@ -94,6 +94,12 @@ func Cli() {
pc.remove_codesign = true
pc.outfile = arg.Out
case "remove-imports":
arg := cli.RemoveImports
ofile = NewOFile(arg.OFile)
pc.remove_imports = true
pc.outfile = arg.Out
default:
return
}

View File

@ -24,6 +24,11 @@ type RemoveCodesignArgument struct {
OFile string `arg help:"Path to Mach-O/Fat binary file" type:"existingfile"`
}
type RemoveImportsArgument struct {
Out string `short:"o" required name:"outfile" help:"Modified Mach-O/Fat binary output file" type:"path"`
OFile string `arg help:"Path to Mach-O/Fat binary file" type:"existingfile"`
}
type SignedBcellArgument struct {
Out string `short:"o" required name:"outfile" help:"bcell.dat.signed output file" type:"existingfile"`
Bcell string `arg short:"b" required help:"bcell.dat input file" type:"existingfile"`
@ -57,6 +62,7 @@ type Argument struct {
Wrap WrapArgument `cmd help:"Modifies Mach-O/Fat binary"`
Vltk VltkArgument `cmd help:"Modifies Mach-O/Fat binary"`
Info InfoArgument `cmd help:"Show Mach-O/Fat binary information"`
RemoveImports RemoveImportsArgument `cmd aliases:"remove-imports" name:"remove-imports" help:"Remove imports"`
RemoveCodesign RemoveCodesignArgument `cmd aliases:"remove-signature" name:"remove-codesign" help:"Remove LC_CODE_SIGNATURE from Mach-O/Fat binary"`
SignedBcell SignedBcellArgument `cmd name:"signed-bcell" help:"Change Protobuf<BcellFile> into Protobuf<SignedData>"`
DisplayBcell DisplayBcellArgument `cmd name:"display-bcell" help:"Display Protobuf<BcellFile> content"`

View File

@ -34,21 +34,17 @@ func (printer *InfoPrinter) Print() {
fmt.Printf("Init functions at offset %s\n", &fun)
}
symbols := mc.CollectLazyBindSymbols()
if len(symbols) > 0 {
fmt.Println("Lazy Symbols")
for _, sym := range symbols {
fmt.Printf(
"%s\n\tStub=0x%x Address=0x%x\n\tDylib=%s\n",
sym.Name(),
sym.Stub(),
sym.Address(),
sym.Dylib(),
)
}
} else {
fmt.Println("No lazy symbols")
}
symbols := mc.CollectBindSymbols()
for _, sym := range symbols {
fmt.Printf(
"%s (%s)\n\tStub=0x%x Address=0x%x\n\tDylib=%s\n",
sym.Name(),
sym.Type(),
sym.Stub(),
sym.Address(),
sym.Dylib(),
)
}
fmt.Println("======")
}

View File

@ -40,6 +40,7 @@ func (uc *UserConfig) Protomodel() *protomodel.Config {
type ProgramContext struct {
strip_init_pointers bool
remove_codesign bool
remove_imports bool
dylib_to_add []string
rpath_to_add []string
@ -83,6 +84,12 @@ func (pc *ProgramContext) dispatchActions(ofile OFile) {
}
func (pc *ProgramContext) Process(ofile OFile) {
if pc.remove_imports {
pc.AddAction(NewRemoveImportsAction())
pc.AddAction(NewWriteFileAction(pc.outfile))
pc.dispatchActions(ofile)
return
}
if pc.remove_codesign {
pc.AddAction(NewRemoveCodeSignatureAction())
}

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