add selfbind functionality
This commit is contained in:
parent
6815ea6556
commit
4ee62a2d93
@ -15,6 +15,15 @@ type saveImports struct{
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (action *saveImports) withMacho(mf *MachoFile) error {
|
func (action *saveImports) withMacho(mf *MachoFile) error {
|
||||||
|
action.saveToInfo(mf)
|
||||||
|
mc := mf.Context()
|
||||||
|
if mc.Header().IsDylib() {
|
||||||
|
mc.WriteInfoToData(mf.Info())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (action *saveImports) saveToInfo(mf *MachoFile) error {
|
||||||
// calculateHash := func(name string) uint32 {
|
// calculateHash := func(name string) uint32 {
|
||||||
// var h uint32 = 0x811c9dc5
|
// var h uint32 = 0x811c9dc5
|
||||||
// for _, s := range name {
|
// for _, s := range name {
|
||||||
|
@ -7,9 +7,11 @@ import (
|
|||||||
"math/rand"
|
"math/rand"
|
||||||
"time"
|
"time"
|
||||||
"strings"
|
"strings"
|
||||||
|
"encoding/binary"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"ios-wrapper/pkg/protomodel"
|
||||||
. "ios-wrapper/pkg/ios"
|
. "ios-wrapper/pkg/ios"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -681,3 +683,130 @@ func (mc *MachoContext) RemoveExportTrie() {
|
|||||||
// should never occur unless this binary is modified
|
// should never occur unless this binary is modified
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mc *MachoContext) AddSection(segname string, name string, size int) Section {
|
||||||
|
// mc.file.WriteAt(mc.header.Serialize(mc), 0)
|
||||||
|
var ret Section
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
for _, command := range mc.commands {
|
||||||
|
switch command.(type) {
|
||||||
|
case *Segment64:
|
||||||
|
var virtualAddr uint64
|
||||||
|
var fileOffset uint64
|
||||||
|
|
||||||
|
var segment = command.(*Segment64)
|
||||||
|
if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte(segname)) != 0 {
|
||||||
|
buffer.Write(segment.Serialize(mc))
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
virtualAddr = segment.Vmaddr()
|
||||||
|
fileOffset = segment.Fileoff()
|
||||||
|
for _, section := range segment.Sections() {
|
||||||
|
virtualAddr += section.Size()
|
||||||
|
// if section.Offset() != 0 {
|
||||||
|
fileOffset += section.Size()
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
align := uint64(4)
|
||||||
|
alignment := align - (fileOffset % align)
|
||||||
|
fileOffset += alignment
|
||||||
|
virtualAddr += alignment
|
||||||
|
|
||||||
|
enoughSpace := segment.Fileoff() + segment.Filesize() >= fileOffset + uint64(size)
|
||||||
|
if !enoughSpace {
|
||||||
|
fmt.Println("Not enough space to store saved info in __DATA segment, need resize (not supported now)")
|
||||||
|
panic("Not enough space to store saved info in __DATA segment, need resize (not supported now)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var section Section64
|
||||||
|
section.sectname = make([]byte, 16)
|
||||||
|
copy(section.sectname, name)
|
||||||
|
section.segname = make([]byte, 16)
|
||||||
|
copy(section.segname, segname)
|
||||||
|
section.size = uint64(size)
|
||||||
|
section.reloff = 0
|
||||||
|
section.nreloc = 0
|
||||||
|
section.flags = 0
|
||||||
|
section.align = 3
|
||||||
|
section.reserved1 = 0
|
||||||
|
section.reserved2 = 0
|
||||||
|
section.reserved3 = 0
|
||||||
|
|
||||||
|
// addr will increment from the last section
|
||||||
|
// offset will increment from the last section + size
|
||||||
|
// be careful of Virtual section (bss)
|
||||||
|
section.addr = virtualAddr
|
||||||
|
section.offset = uint32(fileOffset)
|
||||||
|
segment.nsects += 1
|
||||||
|
buffer.Write(segment.Serialize(mc))
|
||||||
|
buffer.Write(section.Serialize(mc))
|
||||||
|
|
||||||
|
fmt.Printf("Add a new section with addr=0x%x, fileoffset=0x%x\n", section.addr, section.offset)
|
||||||
|
|
||||||
|
ret = §ion
|
||||||
|
continue
|
||||||
|
|
||||||
|
default:
|
||||||
|
buffer.Write(command.Serialize(mc))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mc.header.sizeofcmds = uint32(buffer.Len())
|
||||||
|
header := mc.header.Serialize(mc)
|
||||||
|
mc.file.WriteAt(header, 0)
|
||||||
|
mc.file.WriteAt(buffer.Bytes(), int64(len(header)))
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mc *MachoContext) WriteInfoToData(info *protomodel.MachoInfo) {
|
||||||
|
encode := func () []byte {
|
||||||
|
buffer := new(bytes.Buffer)
|
||||||
|
for _, table := range info.Symbols.Tables {
|
||||||
|
binary.Write(buffer, mc.byteorder, table.LibIndex)
|
||||||
|
binary.Write(buffer, mc.byteorder, table.Nsymbols)
|
||||||
|
for _, symbol := range table.Symbols {
|
||||||
|
binary.Write(buffer, mc.byteorder, (symbol.SymbolIndex<<8)|symbol.SegmentIndex)
|
||||||
|
binary.Write(buffer, mc.byteorder, symbol.Offset)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
instructions := buffer.Bytes()
|
||||||
|
|
||||||
|
buffer = new(bytes.Buffer)
|
||||||
|
for _, lib := range info.Symbols.Libs {
|
||||||
|
buffer.WriteString(lib)
|
||||||
|
buffer.WriteByte(0)
|
||||||
|
}
|
||||||
|
liblist := buffer.Bytes()
|
||||||
|
|
||||||
|
buffer = new(bytes.Buffer)
|
||||||
|
for _, symbol := range info.Symbols.Symbols {
|
||||||
|
buffer.WriteString(symbol)
|
||||||
|
buffer.WriteByte(0)
|
||||||
|
}
|
||||||
|
symbollist := buffer.Bytes()
|
||||||
|
|
||||||
|
buffer = new(bytes.Buffer)
|
||||||
|
// offset to liblist
|
||||||
|
binary.Write(buffer, mc.byteorder, uint32(len(instructions)))
|
||||||
|
// offset to symbollist
|
||||||
|
binary.Write(buffer, mc.byteorder, uint32(len(instructions) + len(liblist)))
|
||||||
|
buffer.Write(instructions)
|
||||||
|
buffer.Write(liblist)
|
||||||
|
buffer.Write(symbollist)
|
||||||
|
|
||||||
|
return buffer.Bytes()
|
||||||
|
}
|
||||||
|
encoded := encode()
|
||||||
|
// encoded := []byte{0x11,0x22,0x33, 0x44}
|
||||||
|
section := mc.AddSection("__DATA", "selfbind", len(encoded))
|
||||||
|
if mc.Is64bit() {
|
||||||
|
var s *Section64 = section.(*Section64)
|
||||||
|
mc.file.WriteAt(encoded, int64(s.Offset()))
|
||||||
|
} else {
|
||||||
|
var s *Section32 = section.(*Section32)
|
||||||
|
mc.file.WriteAt(encoded, int64(s.Offset()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -216,6 +216,51 @@ uint64_t get_slide(const void *header) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void* get_selfbind(const void *header) {
|
||||||
|
const uint32_t magic = *(uint32_t *)header;
|
||||||
|
char *ptr = (char *)header;
|
||||||
|
if (magic == magic64) {
|
||||||
|
ptr += 0x20;
|
||||||
|
} else {
|
||||||
|
ptr += 0x20 - 0x4;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t ncmds = *((uint32_t *)header + 4);
|
||||||
|
char* command_ptr = ptr;
|
||||||
|
|
||||||
|
uint64_t slide;
|
||||||
|
for (int i = 0; i < ncmds; i++) {
|
||||||
|
const uint32_t cmd = *((uint32_t *)ptr + 0);
|
||||||
|
const uint32_t cmdsize = *((uint32_t *)ptr + 1);
|
||||||
|
if (cmd == LC_SEGMENT_64) {
|
||||||
|
char *name = (char *)((uint64_t *)ptr + 1);
|
||||||
|
uint64_t vmaddr = *((uint64_t *)ptr + 3);
|
||||||
|
uint64_t fileoffset = *((uint64_t *)ptr + 5);
|
||||||
|
// this assumes that __TEXT comes before __DATA_CONST
|
||||||
|
if (custom_strcmp(name, "__TEXT") == 0) {
|
||||||
|
slide = (uint64_t)header - vmaddr;
|
||||||
|
} else if (custom_strcmp(name, "__DATA") == 0) {
|
||||||
|
uint64_t nsect = *((uint32_t *)ptr + 8*2);
|
||||||
|
char* sections_ptr = (char*)((uint32_t*)ptr + 18);
|
||||||
|
sections_ptr += (16 * 2 + 8 * 2 + 4 * 8) * (nsect - 1);
|
||||||
|
|
||||||
|
for (int sec = 0; sec < nsect; sec++) {
|
||||||
|
char* secname = sections_ptr;
|
||||||
|
if (custom_strcmp(secname, "selfbind") == 0) {
|
||||||
|
uint64_t addr = *((uint64_t*)sections_ptr + 4);
|
||||||
|
uint64_t size = *((uint64_t*)sections_ptr + 5);
|
||||||
|
uint32_t *data_ptr = (uint32_t*)(addr + slide);
|
||||||
|
return (void*)data_ptr;
|
||||||
|
}
|
||||||
|
sections_ptr += 16 * 2 + 8 * 2 + 4 * 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ptr += cmdsize;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void print_macho_summary(const void *header) {
|
void print_macho_summary(const void *header) {
|
||||||
const uint32_t magic = *(uint32_t *)header;
|
const uint32_t magic = *(uint32_t *)header;
|
||||||
char *ptr = (char *)header;
|
char *ptr = (char *)header;
|
||||||
@ -450,11 +495,11 @@ void *find_in_reexport(struct libcache *cache, struct libcache_item *lib,
|
|||||||
char *name = (char *)ptr + name_offset;
|
char *name = (char *)ptr + name_offset;
|
||||||
uint32_t hash = calculate_libname_hash(cache, name);
|
uint32_t hash = calculate_libname_hash(cache, name);
|
||||||
for (int j = 0; j < cache->size; j++) {
|
for (int j = 0; j < cache->size; j++) {
|
||||||
struct libcache_item reexport = cache->libs[j];
|
struct libcache_item* reexport = &cache->libs[j];
|
||||||
if (reexport.hash != hash) {
|
if (reexport->hash != hash) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
void *found = find_in_lib(cache, &reexport, symbol);
|
void *found = find_in_lib(cache, reexport, symbol);
|
||||||
if (found)
|
if (found)
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
@ -466,33 +511,27 @@ void *find_in_reexport(struct libcache *cache, struct libcache_item *lib,
|
|||||||
void *find_in_lib(struct libcache *cache, struct libcache_item *lib,
|
void *find_in_lib(struct libcache *cache, struct libcache_item *lib,
|
||||||
const char *symbol) {
|
const char *symbol) {
|
||||||
void *direct = find_in_export_trie(lib->header, lib->trie, symbol);
|
void *direct = find_in_export_trie(lib->header, lib->trie, symbol);
|
||||||
if (direct)
|
if (direct) {
|
||||||
return direct;
|
return direct;
|
||||||
|
}
|
||||||
// cannot find in directly exported trie, loop through all reexport libs
|
// cannot find in directly exported trie, loop through all reexport libs
|
||||||
return find_in_reexport(cache, lib, symbol);
|
return find_in_reexport(cache, lib, symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *custom_dlsym(struct libcache *cache, uint32_t hash, const char *symbol) {
|
||||||
|
for (size_t i = 0; i < cache->size; i++) {
|
||||||
|
struct libcache_item* cache_lib = &cache->libs[i];
|
||||||
|
if (cache_lib->hash == hash) {
|
||||||
|
return find_in_lib(cache, cache_lib, symbol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void *custom_dlsym(struct libcache *cache, const char *libname,
|
void *custom_dlsym(struct libcache *cache, const char *libname,
|
||||||
const char *symbol) {
|
const char *symbol) {
|
||||||
uint32_t hash = calculate_libname_hash(cache, libname);
|
uint32_t hash = calculate_libname_hash(cache, libname);
|
||||||
for (int i = 0; i < cache->size; i++) {
|
return custom_dlsym(cache, hash, symbol);
|
||||||
struct libcache_item cache_lib = cache->libs[i];
|
|
||||||
if (cache_lib.hash == hash) {
|
|
||||||
return find_in_lib(cache, &cache_lib, symbol);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf("cannot find lib with hash 0x%x\n", hash);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *custom_dlsym(struct libcache *cache, uint32_t hash, const char *symbol) {
|
|
||||||
for (int i = 0; i < cache->size; i++) {
|
|
||||||
struct libcache_item cache_lib = cache->libs[i];
|
|
||||||
if (cache_lib.hash == hash) {
|
|
||||||
return find_in_lib(cache, &cache_lib, symbol);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void bootstrap_libcache_item(struct libcache_item* item, const void* header, const char* name) {
|
void bootstrap_libcache_item(struct libcache_item* item, const void* header, const char* name) {
|
||||||
@ -536,7 +575,6 @@ void bootstrap_libcache_item(struct libcache_item* item, const void* header, con
|
|||||||
ptr += cmdsize;
|
ptr += cmdsize;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct libcache_item* get_libcache_with_name(struct libcache* cache, const char* name) {
|
struct libcache_item* get_libcache_with_name(struct libcache* cache, const char* name) {
|
||||||
@ -707,7 +745,7 @@ __attribute__((constructor)) static void
|
|||||||
bruh(int argc, const char *const argv[], const char *const envp[],
|
bruh(int argc, const char *const argv[], const char *const envp[],
|
||||||
const char *const apple[], const struct ProgramVars *vars) {
|
const char *const apple[], const struct ProgramVars *vars) {
|
||||||
printf("=== manual symbol bind starts ===\n");
|
printf("=== manual symbol bind starts ===\n");
|
||||||
set_cwd(envp);
|
// set_cwd(envp);
|
||||||
|
|
||||||
// ProgramVars contains pointer to main executable (mapped) file
|
// ProgramVars contains pointer to main executable (mapped) file
|
||||||
|
|
||||||
@ -817,6 +855,72 @@ void build_cache(struct libcache& cache, void* main) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void fix_binds(struct libcache_item* libfixing, struct libcache* cache,
|
||||||
|
int n_ins, uint32_t* instructions, char* libs, char* symbols) {
|
||||||
|
uint32_t libsystem_hash =
|
||||||
|
calculate_libname_hash(cache, "/usr/lib/libSystem.B.dylib");
|
||||||
|
|
||||||
|
typedef void *(*vm_protect_t)(void *, uint64_t, uint64_t, int, int);
|
||||||
|
typedef void *(*mach_task_self_t)();
|
||||||
|
mach_task_self_t mach_task_self_func =
|
||||||
|
(mach_task_self_t)custom_dlsym(cache, libsystem_hash, "_mach_task_self");
|
||||||
|
vm_protect_t vm_protect_func =
|
||||||
|
(vm_protect_t)custom_dlsym(cache, libsystem_hash, "_vm_protect");
|
||||||
|
|
||||||
|
int npage_rw_fixed = 0;
|
||||||
|
uint64_t page_rw_fixed[10]; // should be dynamic, but works for now
|
||||||
|
|
||||||
|
int pc = 0;
|
||||||
|
for (;pc != n_ins;) {
|
||||||
|
uint32_t libidx = instructions[pc];
|
||||||
|
uint32_t nsym = instructions[pc + 1];
|
||||||
|
pc += 2;
|
||||||
|
|
||||||
|
char* lib = libs + libidx;
|
||||||
|
for (int i = 0; i < nsym; i++) {
|
||||||
|
uint32_t op = instructions[pc];
|
||||||
|
uint32_t offset = instructions[pc + 1];
|
||||||
|
pc += 2;
|
||||||
|
|
||||||
|
uint32_t symidx = op >> 8;
|
||||||
|
uint32_t segment = op & 0xff;
|
||||||
|
char* sym = symbols + symidx;
|
||||||
|
|
||||||
|
uint64_t fix_at = offset + libfixing->segment[segment];
|
||||||
|
|
||||||
|
// enable WRITE protection for this data segment
|
||||||
|
int need_rw_fix = true;
|
||||||
|
for (int j = 0; j < npage_rw_fixed; j++) {
|
||||||
|
if (page_rw_fixed[j] <= fix_at &&
|
||||||
|
page_rw_fixed[j] + 0x1000 > fix_at) {
|
||||||
|
need_rw_fix = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (need_rw_fix) {
|
||||||
|
uint64_t start_page = fix_at - (fix_at % 0x1000);
|
||||||
|
vm_protect_func(mach_task_self_func(), start_page, 0x1000, 0,
|
||||||
|
VM_PROT_READ | VM_PROT_WRITE);
|
||||||
|
page_rw_fixed[npage_rw_fixed++] = start_page;
|
||||||
|
printf("modify page starts at 0x%llx to RW\n", start_page);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *resolved = 0;
|
||||||
|
// search with hash is faster
|
||||||
|
// resolved = custom_dlsym(&cache, symbol.hash, symbol.name);
|
||||||
|
if (resolved == 0) {
|
||||||
|
// but fuck apple they have relative path and rpath
|
||||||
|
resolved = custom_dlsym(cache, lib, sym);
|
||||||
|
}
|
||||||
|
*(uint64_t *)fix_at = (uint64_t)resolved;
|
||||||
|
|
||||||
|
printf("imports need to fix: %s at 0x%llx\n", sym, fix_at);
|
||||||
|
printf(" from=%s\n", lib);
|
||||||
|
printf(" segment id=%d; offset=0x%x;", segment, offset);
|
||||||
|
printf(" resolved=%llx(%p)\n", *(uint64_t*)fix_at, resolved);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void fix_objc(struct libcache_item* libfixing, struct libcache& cache);
|
void fix_objc(struct libcache_item* libfixing, struct libcache& cache);
|
||||||
void fix_initializer(struct libcache_item* libfixing, struct libcache& cache);
|
void fix_initializer(struct libcache_item* libfixing, struct libcache& cache);
|
||||||
@ -916,80 +1020,52 @@ void fix(struct libcache& cache) {
|
|||||||
// may need to look into why this happens so we can deal with this more
|
// may need to look into why this happens so we can deal with this more
|
||||||
// generic
|
// generic
|
||||||
|
|
||||||
uint32_t libsystem_hash =
|
// resolve selfbind if exist
|
||||||
calculate_libname_hash(&cache, "/usr/lib/libSystem.B.dylib");
|
{ // stored inside __DATA,selfbind
|
||||||
|
struct libcache_item* libfixing = get_libcache_with_name(&cache, "thislib");
|
||||||
|
struct selfbind_t {
|
||||||
|
uint32_t liblist_offset;
|
||||||
|
uint32_t symbollist_offset;
|
||||||
|
};
|
||||||
|
struct selfbind_t* selfbind = (struct selfbind_t*)get_selfbind(libfixing->header);
|
||||||
|
|
||||||
typedef void *(*vm_protect_t)(void *, uint64_t, uint64_t, int, int);
|
if (selfbind) {
|
||||||
typedef void *(*mach_task_self_t)();
|
char* libs = (char*)(selfbind+1) + selfbind->liblist_offset;
|
||||||
mach_task_self_t mach_task_self_func =
|
char* symbols = (char*)(selfbind+1) + selfbind->symbollist_offset;
|
||||||
(mach_task_self_t)custom_dlsym(&cache, libsystem_hash, "_mach_task_self");
|
uint64_t n_instructions = ((uint64_t)libs - (uint64_t)(selfbind + 1)) / 4;
|
||||||
vm_protect_t vm_protect_func =
|
uint32_t* encoded_table = (uint32_t*)(selfbind+1);
|
||||||
(vm_protect_t)custom_dlsym(&cache, libsystem_hash, "_vm_protect");
|
|
||||||
|
|
||||||
int npage_rw_fixed = 0;
|
printf("[*] performing selfbind (instructions=%p)\n", selfbind);
|
||||||
uint64_t page_rw_fixed[10]; // should be dynamic, but works for now
|
fix_binds(libfixing, &cache,
|
||||||
|
n_instructions, encoded_table,
|
||||||
// think of a way to get what binary to fix
|
libs, symbols);
|
||||||
// so we can iterate through them
|
|
||||||
char* lib_to_resolve = "main";
|
|
||||||
struct libcache_item* libfixing = get_libcache_with_name(&cache, lib_to_resolve);
|
|
||||||
|
|
||||||
int pc = 0;
|
|
||||||
for (;pc != bshield_data::n_instructions;) {
|
|
||||||
uint32_t libidx = bshield_data::encoded_table[pc];
|
|
||||||
uint32_t nsym = bshield_data::encoded_table[pc + 1];
|
|
||||||
pc += 2;
|
|
||||||
|
|
||||||
char* lib = bshield_data::libs + libidx;
|
|
||||||
for (int i = 0; i < nsym; i++) {
|
|
||||||
uint32_t op = bshield_data::encoded_table[pc];
|
|
||||||
uint32_t offset = bshield_data::encoded_table[pc + 1];
|
|
||||||
pc += 2;
|
|
||||||
|
|
||||||
uint32_t symidx = op >> 8;
|
|
||||||
uint32_t segment = op & 0xff;
|
|
||||||
char* sym = bshield_data::symbols + symidx;
|
|
||||||
|
|
||||||
uint64_t fix_at = offset + libfixing->segment[segment];
|
|
||||||
|
|
||||||
// enable WRITE protection for this data segment
|
|
||||||
int need_rw_fix = true;
|
|
||||||
for (int j = 0; j < npage_rw_fixed; j++) {
|
|
||||||
if (page_rw_fixed[j] <= fix_at &&
|
|
||||||
page_rw_fixed[j] + 0x1000 > fix_at) {
|
|
||||||
need_rw_fix = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (need_rw_fix) {
|
|
||||||
uint64_t start_page = fix_at - (fix_at % 0x1000);
|
|
||||||
vm_protect_func(mach_task_self_func(), start_page, 0x1000, 0,
|
|
||||||
VM_PROT_READ | VM_PROT_WRITE);
|
|
||||||
page_rw_fixed[npage_rw_fixed++] = start_page;
|
|
||||||
printf("modify page starts at 0x%llx to RW\n", start_page);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *resolved = 0;
|
|
||||||
// search with hash is faster
|
|
||||||
// resolved = custom_dlsym(&cache, symbol.hash, symbol.name);
|
|
||||||
if (resolved == 0) {
|
|
||||||
// but fuck apple they have relative path and rpath
|
|
||||||
resolved = custom_dlsym(&cache, lib, sym);
|
|
||||||
}
|
|
||||||
*(uint64_t *)fix_at = (uint64_t)resolved;
|
|
||||||
|
|
||||||
printf("imports need to fix: %s at 0x%llx\n", sym, fix_at);
|
|
||||||
printf(" from=%s\n", lib);
|
|
||||||
printf(" segment id=%d; offset=0x%llx;", segment, offset);
|
|
||||||
printf(" resolved=%llx(%p)\n", *(uint64_t*)fix_at, resolved);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the rest of the fixes are in main executable
|
||||||
|
printf("[*] performing bind for main executable\n");
|
||||||
|
struct libcache_item* libfixing = get_libcache_with_name(&cache, "main");
|
||||||
|
fix_binds(libfixing, &cache,
|
||||||
|
bshield_data::n_instructions, bshield_data::encoded_table,
|
||||||
|
bshield_data::libs, bshield_data::symbols);
|
||||||
|
|
||||||
// TODO: Reformat the region as per before, or leave as it
|
// TODO: Reformat the region as per before, or leave as it
|
||||||
// for (int j = 0; j < npage_rw_fixed; j++) {
|
// for (int j = 0; j < npage_rw_fixed; j++) {
|
||||||
// uint64_t start_page = page_rw_fixed[j];
|
// uint64_t start_page = page_rw_fixed[j];
|
||||||
// vm_protect_func(mach_task_self_func(), start_page, 0x4000, 0, VM_PROT_READ);
|
// vm_protect_func(mach_task_self_func(), start_page, 0x4000, 0, VM_PROT_READ);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
// Encrypted __TEXT segment
|
||||||
|
// char* text_start = (char*)libfixing->header + 0x3000;
|
||||||
|
// vm_protect_func(mach_task_self_func(), (uint64_t)text_start, 0x1000, 0,
|
||||||
|
// VM_PROT_READ | VM_PROT_WRITE);
|
||||||
|
// printf("text fix at %p\n", text_start + 0xb8c);
|
||||||
|
// for (int i = 0; i < 0x2ac; i++) {
|
||||||
|
// text_start[0xb8c + i] = text_start[0xb8c + i] ^ 0xcc;
|
||||||
|
// }
|
||||||
|
// vm_protect_func(mach_task_self_func(), (uint64_t)text_start, 0x1000, 0,
|
||||||
|
// VM_PROT_READ | VM_PROT_EXECUTE);
|
||||||
|
|
||||||
fix_objc(libfixing, cache);
|
fix_objc(libfixing, cache);
|
||||||
fix_initializer(libfixing, cache);
|
fix_initializer(libfixing, cache);
|
||||||
}
|
}
|
||||||
|
@ -64,12 +64,15 @@ clang -fobjc-arc -ObjC -mmacosx-version-min=$VERSION -o $OUT/a -L"./out" -lb a.m
|
|||||||
|
|
||||||
# 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 --keep-imports _printf $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 pepe -o $OUT/a-fixed -b $OUT/b.bcell --remove-imports --remove-exports $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
|
||||||
|
../../macho-go/bin/ios-wrapper pepe -o $OUT/libb.dylib -b $OUT/libb.bcell --remove-imports --remove-exports --keep-imports _dyld_get_sdk_version --keep-imports _malloc --keep-imports _printf --keep-imports ___stack_chk_guard $OUT/libb.dylib
|
||||||
|
|
||||||
|
# resign
|
||||||
codesign --force --deep -s - $OUT/a-fixed
|
codesign --force --deep -s - $OUT/a-fixed
|
||||||
|
codesign --force --deep -s - $OUT/libb.dylib
|
||||||
|
|
||||||
# export OBJC_PRINT_LOAD_METHODS=1
|
# export OBJC_PRINT_LOAD_METHODS=1
|
||||||
# export OBJC_PRINT_CLASS_SETUP=1
|
# export OBJC_PRINT_CLASS_SETUP=1
|
||||||
|
Loading…
Reference in New Issue
Block a user