add keep imports action

This commit is contained in:
nganhkhoa 2023-07-11 10:06:59 +07:00
parent 557eed0254
commit 6815ea6556
11 changed files with 187 additions and 5 deletions

View File

@ -0,0 +1,26 @@
package action
import (
. "ios-wrapper/internal/wrapper/ofile"
)
type rewriteImports struct{
symbols []string
}
func (action *rewriteImports) withMacho(mf *MachoFile) error {
mc := mf.Context()
mc.RewriteImportsTable(action.symbols)
return nil
}
func (action *rewriteImports) withFat(ff *FatFile) error {
return defaultWithFat(action, ff)
}
func NewRewriteImportsWithKeepSymbolsAction(symbols []string) *rewriteImports {
return &rewriteImports{
symbols,
}
}

View File

@ -3,13 +3,16 @@ package action
import (
// "fmt"
"sort"
"strings"
// log "github.com/sirupsen/logrus"
. "ios-wrapper/internal/wrapper/ofile"
"ios-wrapper/pkg/protomodel"
)
type saveImports struct{}
type saveImports struct{
keepSymbols []string
}
func (action *saveImports) withMacho(mf *MachoFile) error {
// calculateHash := func(name string) uint32 {
@ -51,6 +54,30 @@ func (action *saveImports) withMacho(mf *MachoFile) error {
if symbol.Type() != "lazy" {
continue
}
skip := false
for _, keep := range action.keepSymbols {
name := keep
lib := ""
parts := strings.Split(keep, ",")
if len(parts) == 2 {
name = parts[0]
lib = parts[1]
}
if symbol.Name() != name {
continue
}
if lib == "" || lib == symbol.Dylib() {
skip = true
break
}
}
if skip {
continue
}
// dylib_hash := calculateHash(symbol.Dylib())
seg := mc.Segments()[symbol.Segment()]
@ -113,6 +140,8 @@ func (action *saveImports) withFat(ff *FatFile) error {
return defaultWithFat(action, ff)
}
func NewSaveImportsAction() *saveImports {
return &saveImports{}
func NewSaveImportsAction(keepSymbols []string) *saveImports {
return &saveImports{
keepSymbols,
}
}

View File

@ -128,6 +128,7 @@ func Cli() {
pc.rpath_to_add = arg.Rpath
pc.outfile = arg.Out
pc.bcellfile = arg.Bcell
pc.symbols_keep = arg.KeepImports
default:
return

View File

@ -71,6 +71,8 @@ type PepeArgument struct {
RemoveObjCString bool `default:"false" negatable:"" help:"(TODO) Remove references, string litteral to Objctive-C strings"`
RebuildLinkEdit bool `default:"false" negatable:"" help:"(TODO) Rebuild the LINKEDIT section"`
FullRemoval bool `default:"false" help:"Apply every removal possible"`
KeepImports []string `short:"keep" help:"Do not remove import symbols and allow dyld resolve. If symbols is found with more than 1 occurrances, specify the library with a comma or else all occurrances will be kept. e.g., _symbol,libLIB.dylib"`
}
type BcellToHeaderArgument struct {

View File

@ -46,6 +46,7 @@ type ProgramContext struct {
remove_symbol_table bool
dylib_to_add []string
rpath_to_add []string
symbols_keep []string
outfile string
@ -95,8 +96,9 @@ func (pc *ProgramContext) Process(ofile OFile) {
pc.AddAction(NewRemoveInitPointerAction())
}
if pc.remove_imports {
pc.AddAction(NewSaveImportsAction())
pc.AddAction(NewSaveImportsAction(pc.symbols_keep))
pc.AddAction(NewRemoveImportsAction())
pc.AddAction(NewRewriteImportsWithKeepSymbolsAction(pc.symbols_keep))
}
if pc.remove_symbol_table {
pc.AddAction(NewRemoveClassicSymbolAction())

View File

@ -6,6 +6,7 @@ import (
"io"
"math/rand"
"time"
"strings"
log "github.com/sirupsen/logrus"
@ -524,6 +525,77 @@ func (mc *MachoContext) ReworkForObjc() {
}
}
func (mc *MachoContext) RewriteImportsTable(keepSymbols []string) {
allSymbols := mc.CollectBindSymbols()
fixups, fixupsOffset := mc.Fixups()
importTable := fixups.ImportsOffset(uint32(fixupsOffset))
symbolTable := fixups.SymbolsOffset(uint32(fixupsOffset))
symbolTablePtr := symbolTable
// in removeBindSymbolsModern, we erase these pointers in file
// but because we keep a few symbols, we need to rewrite the pointers
// as well as rebuild the import table and strings table, and bind values
keepCount := uint32(0)
for _, symbol := range keepSymbols {
name := symbol
lib := ""
parts := strings.Split(symbol, ",")
if len(parts) == 2 {
name = parts[0]
lib = parts[1]
}
symbolInfo := (*ImportSymbol)(nil)
for _, s := range allSymbols {
if s.Name() != name {
continue
}
if lib == "" || lib == s.Dylib() {
symbolInfo = s
break
}
}
if symbolInfo == nil {
// symbol not found
continue
}
fmt.Printf("keep symbol %s\n", name)
fmt.Printf("importTable at 0x%x; stringTable at 0x%x\n", importTable, symbolTablePtr)
fmt.Printf("bind value at 0x%x\n", symbolInfo.file_address)
// write string to string table
mc.file.WriteAt([]byte(name), int64(symbolTablePtr))
// fix bind value
rebaseOpcodeBytes := make([]byte, 8)
mc.file.ReadAt(rebaseOpcodeBytes, int64(symbolInfo.file_address))
rebaseOpcode := mc.byteorder.Uint64(rebaseOpcodeBytes)
bindOpcode := C.MakeBindFixupOpcodeFromRebase(C.uint64_t(rebaseOpcode), C.uint(keepCount))
{
v := make([]byte, 8)
mc.byteorder.PutUint64(v, uint64(bindOpcode))
mc.file.WriteAt(v, int64(symbolInfo.file_address))
}
// write import data to import table
entry := C.MakeImportTableEntry(C.uint(symbolInfo.LibOrdinal()), C.uint(symbolTablePtr - symbolTable))
{
v := make([]byte, 4)
mc.byteorder.PutUint32(v, uint32(entry))
mc.file.WriteAt(v, int64(importTable))
}
keepCount += 1
importTable += 4
symbolTablePtr += uint32(len(name)) + 1
}
fixups.imports_count = keepCount
mc.file.WriteAt(fixups.Serialize(mc), int64(mc.fixups.dataoff))
}
func (mc *MachoContext) RemoveSymbolTable() {
// try to remove symtab and dysymtab
mc.removeSymtabCommand()

View File

@ -104,6 +104,28 @@ uint64_t MakeRebaseFixupOpcode(int next, uint64_t target, uint64_t high8) {
return value;
}
uint64_t MakeBindFixupOpcodeFromRebase(uint64_t rebaseOpcode, uint32_t ordinal) {
printf("fix bind value\n");
uint64_t ret;
struct dyld_chained_ptr_64_bind* b = (struct dyld_chained_ptr_64_bind*)&ret;
b->next = ((struct dyld_chained_ptr_64_rebase*)&rebaseOpcode)->next;
b->bind = 1;
b->ordinal = ordinal;
b->addend = 0;
b->reserved = 0;
return ret;
}
uint32_t MakeImportTableEntry(uint32_t lib_ordinal, uint32_t name_offset) {
printf("append import table\n");
uint32_t ret;
struct dyld_chained_import* import = (struct dyld_chained_import*)&ret;
import->lib_ordinal = lib_ordinal;
import->name_offset = name_offset;
import->weak_import = 0;
return ret;
}
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

@ -31,4 +31,7 @@ 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);
uint64_t MakeBindFixupOpcodeFromRebase(uint64_t rebaseOpcode, uint32_t ordinal);
uint32_t MakeImportTableEntry(uint32_t lib_ordinal, uint32_t name_offset);
#endif

View File

@ -37,6 +37,14 @@ func (h *Header) Cpusubtype() uint32 {
return h.cpusubtype
}
func (h *Header) IsExecutable() bool {
return h.filetype == 0x2
}
func (h *Header) IsDylib() bool {
return h.filetype == 0x6
}
func (h *Header) Serialize(mc *MachoContext) []byte {
buf := new(bytes.Buffer)
binary.Write(buf, mc.byteorder, h.magic)
@ -406,6 +414,14 @@ type Fixups struct {
symbols_format uint32
}
func (lcmd *Fixups) ImportsOffset(fixups_offset uint32) uint32 {
return lcmd.imports_offset + fixups_offset
}
func (lcmd *Fixups) SymbolsOffset(fixups_offset uint32) uint32 {
return lcmd.symbols_offset + fixups_offset
}
func (lcmd *Fixups) Serialize(mc *MachoContext) []byte {
buf := new(bytes.Buffer)
binary.Write(buf, mc.byteorder, lcmd.fixups_version)

View File

@ -68,6 +68,14 @@ func (mc *MachoContext) Main() uint64 {
return mc.entryoff
}
func (mc *MachoContext) Fixups() (*Fixups, uint64) {
start := mc.fixups.dataoff
size := mc.fixups.datasize
fixups := new(Fixups)
fixups.Deserialize(mc, mc.buf[start:start+size])
return fixups, uint64(mc.fixups.dataoff)
}
func (mc *MachoContext) WriteEnabled() bool {
return mc.file != nil
}

View File

@ -63,7 +63,8 @@ clang++ -mmacosx-version-min=$VERSION -o $OUT/libb.dylib -shared -Wl,-reexport_l
clang -fobjc-arc -ObjC -mmacosx-version-min=$VERSION -o $OUT/a -L"./out" -lb a.mm
# extract symbols from a
../../macho-go/bin/ios-wrapper pepe -o $OUT/a-fixed -b $OUT/b.bcell --remove-imports --remove-exports --remove-symbol-table $OUT/a
# ../../macho-go/bin/ios-wrapper pepe -o $OUT/a-fixed -b $OUT/b.bcell --remove-imports --remove-exports --remove-symbol-table --keep-imports _printf $OUT/a
../../macho-go/bin/ios-wrapper pepe -o $OUT/a-fixed -b $OUT/b.bcell --remove-imports --remove-exports --keep-imports _printf $OUT/a
../../macho-go/bin/ios-wrapper bcell2header -b $OUT/b.bcell -o $OUT/b.h
# build libb with symbols extracted from a
clang++ -mmacosx-version-min=$VERSION -o $OUT/libb.dylib -shared -Wl,-reexport_library out/libc.dylib b.cc