add keep imports action
This commit is contained in:
parent
557eed0254
commit
6815ea6556
26
macho-go/internal/wrapper/action/rewrite_imports.go
Normal file
26
macho-go/internal/wrapper/action/rewrite_imports.go
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,13 +3,16 @@ package action
|
|||||||
import (
|
import (
|
||||||
// "fmt"
|
// "fmt"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strings"
|
||||||
// log "github.com/sirupsen/logrus"
|
// log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
. "ios-wrapper/internal/wrapper/ofile"
|
. "ios-wrapper/internal/wrapper/ofile"
|
||||||
"ios-wrapper/pkg/protomodel"
|
"ios-wrapper/pkg/protomodel"
|
||||||
)
|
)
|
||||||
|
|
||||||
type saveImports struct{}
|
type saveImports struct{
|
||||||
|
keepSymbols []string
|
||||||
|
}
|
||||||
|
|
||||||
func (action *saveImports) withMacho(mf *MachoFile) error {
|
func (action *saveImports) withMacho(mf *MachoFile) error {
|
||||||
// calculateHash := func(name string) uint32 {
|
// calculateHash := func(name string) uint32 {
|
||||||
@ -51,6 +54,30 @@ func (action *saveImports) withMacho(mf *MachoFile) error {
|
|||||||
if symbol.Type() != "lazy" {
|
if symbol.Type() != "lazy" {
|
||||||
continue
|
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())
|
// dylib_hash := calculateHash(symbol.Dylib())
|
||||||
seg := mc.Segments()[symbol.Segment()]
|
seg := mc.Segments()[symbol.Segment()]
|
||||||
|
|
||||||
@ -113,6 +140,8 @@ func (action *saveImports) withFat(ff *FatFile) error {
|
|||||||
return defaultWithFat(action, ff)
|
return defaultWithFat(action, ff)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSaveImportsAction() *saveImports {
|
func NewSaveImportsAction(keepSymbols []string) *saveImports {
|
||||||
return &saveImports{}
|
return &saveImports{
|
||||||
|
keepSymbols,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,6 +128,7 @@ func Cli() {
|
|||||||
pc.rpath_to_add = arg.Rpath
|
pc.rpath_to_add = arg.Rpath
|
||||||
pc.outfile = arg.Out
|
pc.outfile = arg.Out
|
||||||
pc.bcellfile = arg.Bcell
|
pc.bcellfile = arg.Bcell
|
||||||
|
pc.symbols_keep = arg.KeepImports
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return
|
return
|
||||||
|
@ -71,6 +71,8 @@ type PepeArgument struct {
|
|||||||
RemoveObjCString bool `default:"false" negatable:"" help:"(TODO) Remove references, string litteral to Objctive-C strings"`
|
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"`
|
RebuildLinkEdit bool `default:"false" negatable:"" help:"(TODO) Rebuild the LINKEDIT section"`
|
||||||
FullRemoval bool `default:"false" help:"Apply every removal possible"`
|
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 {
|
type BcellToHeaderArgument struct {
|
||||||
|
@ -46,6 +46,7 @@ type ProgramContext struct {
|
|||||||
remove_symbol_table bool
|
remove_symbol_table bool
|
||||||
dylib_to_add []string
|
dylib_to_add []string
|
||||||
rpath_to_add []string
|
rpath_to_add []string
|
||||||
|
symbols_keep []string
|
||||||
|
|
||||||
outfile string
|
outfile string
|
||||||
|
|
||||||
@ -95,8 +96,9 @@ func (pc *ProgramContext) Process(ofile OFile) {
|
|||||||
pc.AddAction(NewRemoveInitPointerAction())
|
pc.AddAction(NewRemoveInitPointerAction())
|
||||||
}
|
}
|
||||||
if pc.remove_imports {
|
if pc.remove_imports {
|
||||||
pc.AddAction(NewSaveImportsAction())
|
pc.AddAction(NewSaveImportsAction(pc.symbols_keep))
|
||||||
pc.AddAction(NewRemoveImportsAction())
|
pc.AddAction(NewRemoveImportsAction())
|
||||||
|
pc.AddAction(NewRewriteImportsWithKeepSymbolsAction(pc.symbols_keep))
|
||||||
}
|
}
|
||||||
if pc.remove_symbol_table {
|
if pc.remove_symbol_table {
|
||||||
pc.AddAction(NewRemoveClassicSymbolAction())
|
pc.AddAction(NewRemoveClassicSymbolAction())
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"time"
|
"time"
|
||||||
|
"strings"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
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() {
|
func (mc *MachoContext) RemoveSymbolTable() {
|
||||||
// try to remove symtab and dysymtab
|
// try to remove symtab and dysymtab
|
||||||
mc.removeSymtabCommand()
|
mc.removeSymtabCommand()
|
||||||
|
@ -104,6 +104,28 @@ uint64_t MakeRebaseFixupOpcode(int next, uint64_t target, uint64_t high8) {
|
|||||||
return value;
|
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) {
|
void ParseFixUps(uint8_t* buffer) {
|
||||||
struct dyld_chained_fixups_header* header = (struct dyld_chained_fixups_header*)buffer;
|
struct dyld_chained_fixups_header* header = (struct dyld_chained_fixups_header*)buffer;
|
||||||
printf("starts=0x%x\n", header->starts_offset);
|
printf("starts=0x%x\n", header->starts_offset);
|
||||||
|
@ -31,4 +31,7 @@ struct ImportSymbol GetImportsAt(struct ImportTable* table, int i);
|
|||||||
int GetSegmentFixAt(uint8_t* buffer, uint32_t i, struct SegmentFix* fix);
|
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);
|
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 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
|
#endif
|
||||||
|
@ -37,6 +37,14 @@ func (h *Header) Cpusubtype() uint32 {
|
|||||||
return h.cpusubtype
|
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 {
|
func (h *Header) Serialize(mc *MachoContext) []byte {
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
binary.Write(buf, mc.byteorder, h.magic)
|
binary.Write(buf, mc.byteorder, h.magic)
|
||||||
@ -406,6 +414,14 @@ type Fixups struct {
|
|||||||
symbols_format uint32
|
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 {
|
func (lcmd *Fixups) Serialize(mc *MachoContext) []byte {
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
binary.Write(buf, mc.byteorder, lcmd.fixups_version)
|
binary.Write(buf, mc.byteorder, lcmd.fixups_version)
|
||||||
|
@ -68,6 +68,14 @@ func (mc *MachoContext) Main() uint64 {
|
|||||||
return mc.entryoff
|
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 {
|
func (mc *MachoContext) WriteEnabled() bool {
|
||||||
return mc.file != nil
|
return mc.file != nil
|
||||||
}
|
}
|
||||||
|
@ -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
|
clang -fobjc-arc -ObjC -mmacosx-version-min=$VERSION -o $OUT/a -L"./out" -lb a.mm
|
||||||
|
|
||||||
# extract symbols from a
|
# 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
|
../../macho-go/bin/ios-wrapper bcell2header -b $OUT/b.bcell -o $OUT/b.h
|
||||||
# build libb with symbols extracted from a
|
# 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
|
clang++ -mmacosx-version-min=$VERSION -o $OUT/libb.dylib -shared -Wl,-reexport_library out/libc.dylib b.cc
|
||||||
|
Loading…
Reference in New Issue
Block a user