format code

This commit is contained in:
nganhkhoa 2023-05-31 16:31:52 +07:00
parent e3453ae127
commit 841a50f8e1
12 changed files with 201 additions and 196 deletions

View File

@ -1,12 +1,12 @@
package main package main
import ( import (
"ios-wrapper/pkg/ios/macho"
"github.com/alecthomas/kong" "github.com/alecthomas/kong"
"ios-wrapper/pkg/ios/macho"
"os"
"fmt"
"bytes" "bytes"
"fmt"
"os"
) )
type Argument struct { type Argument struct {
@ -33,7 +33,7 @@ func compare(one string, two string) {
s1 := mc1.FindSection("__text") s1 := mc1.FindSection("__text")
s2 := mc2.FindSection("__text") s2 := mc2.FindSection("__text")
if (s1.Size() == s2.Size()) { if s1.Size() == s2.Size() {
fmt.Println("Size is equal") fmt.Println("Size is equal")
} else { } else {
fmt.Printf("%x <> %x\n", s1.Size(), s2.Size()) fmt.Printf("%x <> %x\n", s1.Size(), s2.Size())
@ -41,7 +41,7 @@ func compare(one string, two string) {
data1 := mc1.Cut(uint64(s1.Offset()), s1.Size()) data1 := mc1.Cut(uint64(s1.Offset()), s1.Size())
data2 := mc1.Cut(uint64(s2.Offset()), s2.Size()) data2 := mc1.Cut(uint64(s2.Offset()), s2.Size())
if (bytes.Compare(data1, data2) == 0) { if bytes.Compare(data1, data2) == 0 {
fmt.Println("Data is equal") fmt.Println("Data is equal")
} }
} }

View File

@ -34,7 +34,6 @@ func (printer *InfoPrinter) Print() {
fmt.Printf("Init functions at offset %s\n", &fun) fmt.Printf("Init functions at offset %s\n", &fun)
} }
symbols := mc.CollectLazyBindSymbols() symbols := mc.CollectLazyBindSymbols()
if len(symbols) > 0 { if len(symbols) > 0 {
fmt.Println("Lazy Symbols") fmt.Println("Lazy Symbols")

View File

@ -1,8 +1,8 @@
/// Contains the declaration of FatHeader and FatArch // / Contains the declaration of FatHeader and FatArch
/// These structs are always written using Big-Endian, // / These structs are always written using Big-Endian,
/// as documented in the mach-o/fat.h // / as documented in the mach-o/fat.h
/// This file also has a CreateFat function to generate // / This file also has a CreateFat function to generate
/// Fat file from a list of MachoContext // / Fat file from a list of MachoContext
package fat package fat
import ( import (
@ -16,8 +16,8 @@ import (
macho "ios-wrapper/pkg/ios/macho" macho "ios-wrapper/pkg/ios/macho"
) )
/// Get the alignment for the Mach-O in Fat binary // / Get the alignment for the Mach-O in Fat binary
/// The returned value is the multiplier of 2 // / The returned value is the multiplier of 2
func GetAlignment(h *macho.Header) uint32 { func GetAlignment(h *macho.Header) uint32 {
switch h.Cputype() { switch h.Cputype() {
case CPU_TYPE_ARM, CPU_TYPE_ARM64: case CPU_TYPE_ARM, CPU_TYPE_ARM64:
@ -46,17 +46,17 @@ func MachosToFatArchs(machos []*macho.MachoContext) []*FatArch {
return fa return fa
} }
/// Create a Fat binary from MachoContext // / Create a Fat binary from MachoContext
/// Convert MachoContext to FatArch // / Convert MachoContext to FatArch
/// Calculate the alignment, now using basic calculation // / Calculate the alignment, now using basic calculation
/// because iOS always has valid archs ARM // / because iOS always has valid archs ARM
/// // /
/// Sort the Fat arch as per the cctools/lipo // / Sort the Fat arch as per the cctools/lipo
/// Calculate the offset with each Mach-O // / Calculate the offset with each Mach-O
/// // /
/// Write the FatHeader // / Write the FatHeader
/// Write the FatArchs // / Write the FatArchs
/// Write the Mach-Os // / Write the Mach-Os
func CreateFat(machos []*macho.MachoContext, outfilename string) error { func CreateFat(machos []*macho.MachoContext, outfilename string) error {
archs := MachosToFatArchs(machos) archs := MachosToFatArchs(machos)
sort.SliceStable(archs, func(i, j int) bool { sort.SliceStable(archs, func(i, j int) bool {
@ -139,9 +139,9 @@ func (fw *fatWriter) WriteFatArchs(w io.Writer, archs []*FatArch) {
} }
} }
/// for each fat arch sorted, we locate the MachoContext and // / for each fat arch sorted, we locate the MachoContext and
/// use it to Write to the buffer // / use it to Write to the buffer
/// locating the macho by its cputype and cpusubtype // / locating the macho by its cputype and cpusubtype
func (fw *fatWriter) WriteMachos( func (fw *fatWriter) WriteMachos(
w io.WriteSeeker, w io.WriteSeeker,
archs []*FatArch, archs []*FatArch,

View File

@ -57,7 +57,7 @@ func (mc *MachoContext) CollectLazyBindSymbols() []*ImportSymbol {
func (mc *MachoContext) CollectLazyBindSymbolsModern() []*ImportSymbol { func (mc *MachoContext) CollectLazyBindSymbolsModern() []*ImportSymbol {
var buf []byte var buf []byte
for _, cmd := range mc.Linkedits() { for _, cmd := range mc.Linkedits() {
if (cmd.Cmd() != LC_DYLD_CHAINED_FIXUPS) { if cmd.Cmd() != LC_DYLD_CHAINED_FIXUPS {
continue continue
} }
@ -67,7 +67,7 @@ func (mc *MachoContext) CollectLazyBindSymbolsModern() []*ImportSymbol {
symbol_offset := int64(0x4000) symbol_offset := int64(0x4000)
mc.file.WriteAt([]byte{0, 0, 0, 0, 0, 0, 0, 0}, symbol_offset) mc.file.WriteAt([]byte{0, 0, 0, 0, 0, 0, 0, 0}, symbol_offset)
buf = mc.buf[cmd.Dataoff():cmd.Dataoff() + cmd.Datasize()] buf = mc.buf[cmd.Dataoff() : cmd.Dataoff()+cmd.Datasize()]
break break
} }

View File

@ -40,6 +40,7 @@ func rewriteLoadcommandsWithoutCodesignature(mc *MachoContext) {
// CODE_SIGNATURE load commands points to the codesign data offset and size. // CODE_SIGNATURE load commands points to the codesign data offset and size.
// __LINKEDIT section points to data offset and size. // __LINKEDIT section points to data offset and size.
// We have: // We have:
//
// linkedit = (section*) LC_SEGMENT.section[0] // name="__LINKEDIT" // linkedit = (section*) LC_SEGMENT.section[0] // name="__LINKEDIT"
// codesign = (linkedit_data_command*) LC_CODE_SIGNATURE // codesign = (linkedit_data_command*) LC_CODE_SIGNATURE
// BinarySize = { f.seek(0, SEEKEND); return f.tell() } // BinarySize = { f.seek(0, SEEKEND); return f.tell() }

View File

@ -71,10 +71,12 @@ func (mc *MachoContext) WriteBufferTo(w io.Writer) (int, error) {
// Parse the provided Mach-O binary from a file // Parse the provided Mach-O binary from a file
// The first 4 bytes of the file must be the MachO magic // The first 4 bytes of the file must be the MachO magic
// That is: // That is:
//
// file.Seek(0, io.SeekStart) // file.Seek(0, io.SeekStart)
// magic := make([]byte, 4) // magic := make([]byte, 4)
// file.Read(magic) // file.Read(magic)
// assert magic == []byte{macho magic bytes} // assert magic == []byte{macho magic bytes}
//
// or else, parsing error is panic // or else, parsing error is panic
func (mc *MachoContext) ParseFile(file *os.File, length int) error { func (mc *MachoContext) ParseFile(file *os.File, length int) error {
file.Seek(0, io.SeekStart) file.Seek(0, io.SeekStart)

View File

@ -138,7 +138,7 @@ func (mc *MachoContext) FindSegment(name string) Segment {
} }
func (mc *MachoContext) Cut(offset uint64, size uint64) []byte { func (mc *MachoContext) Cut(offset uint64, size uint64) []byte {
return mc.buf[offset : offset + size]; return mc.buf[offset : offset+size]
} }
// INIT POINTER // INIT POINTER

View File

@ -1,39 +1,40 @@
#include <stdio.h>
#include <stdint.h>
#include <mach-o/dyld.h> #include <mach-o/dyld.h>
#include <mach/mach.h> #include <mach/mach.h>
#include <stdint.h>
#include <stdio.h>
const uint32_t magic64 = 0xfeedfacf; const uint32_t magic64 = 0xfeedfacf;
const uint32_t magic32 = 0xfeedface; const uint32_t magic32 = 0xfeedface;
struct ProgramVars { struct ProgramVars {
void* mh; // mach_header or mach_header64 void *mh; // mach_header or mach_header64
int* NXArgcPtr; int *NXArgcPtr;
const char*** NXArgvPtr; const char ***NXArgvPtr;
const char*** environPtr; const char ***environPtr;
const char** __prognamePtr; const char **__prognamePtr;
}; };
extern "C" uint32_t dyld_get_sdk_version(const mach_header* mh); extern "C" uint32_t dyld_get_sdk_version(const mach_header *mh);
void decode_uleb128(char*& addr, uint32_t* ret) { void decode_uleb128(char *&addr, uint32_t *ret) {
uint32_t result = 0; uint32_t result = 0;
int shift = 0; int shift = 0;
while (1) { while (1) {
unsigned char byte = *(unsigned char*)(addr); unsigned char byte = *(unsigned char *)(addr);
addr++; addr++;
result |= (byte & 0x7f) << shift; result |= (byte & 0x7f) << shift;
shift += 7; shift += 7;
if (!(byte & 0x80)) break; if (!(byte & 0x80))
break;
} }
*ret = result; *ret = result;
} }
void* find_header(void* _func) { void *find_header(void *_func) {
// Approach 1: (not stable) // Approach 1: (not stable)
// we assume that text section is small enough to fit on 1 page // we assume that text section is small enough to fit on 1 page
// so the header should stay at the top of the page due to allocation logic // so the header should stay at the top of the page due to allocation logic
@ -63,41 +64,41 @@ void* find_header(void* _func) {
uint64_t func = (uint64_t)_func; uint64_t func = (uint64_t)_func;
uint64_t potential_head = func + (0x1000 - (func % page_size)); uint64_t potential_head = func + (0x1000 - (func % page_size));
void* head = 0; void *head = 0;
uint32_t* x = (uint32_t*)(potential_head); uint32_t *x = (uint32_t *)(potential_head);
while (*x != magic64 && *x != magic32) { while (*x != magic64 && *x != magic32) {
x -= 0x1000/4; x -= 0x1000 / 4;
} }
return (void*)x; return (void *)x;
} }
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;
if (magic == magic64) { if (magic == magic64) {
ptr += 0x20; ptr += 0x20;
} else { } else {
ptr += 0x20 - 0x4; ptr += 0x20 - 0x4;
} }
const uint32_t ncmds = *((uint32_t*)header + 4); const uint32_t ncmds = *((uint32_t *)header + 4);
printf("parsing macho at %p\n", header); printf("parsing macho at %p\n", header);
printf("ncmds %x\n", ncmds); printf("ncmds %x\n", ncmds);
for (int i = 0; i < ncmds; i++) { for (int i = 0; i < ncmds; i++) {
const uint32_t cmd = *((uint32_t*)ptr + 0); const uint32_t cmd = *((uint32_t *)ptr + 0);
const uint32_t cmdsize = *((uint32_t*)ptr + 1); const uint32_t cmdsize = *((uint32_t *)ptr + 1);
printf(" cmd %x %x\n", cmd, cmdsize); printf(" cmd %x %x\n", cmd, cmdsize);
if (cmd == LC_DYLD_EXPORTS_TRIE) { if (cmd == LC_DYLD_EXPORTS_TRIE) {
const uint32_t offset = *((uint32_t*)ptr + 2); const uint32_t offset = *((uint32_t *)ptr + 2);
const uint32_t size = *((uint32_t*)ptr + 3); const uint32_t size = *((uint32_t *)ptr + 3);
printf(" export trie: offset=0x%x size=0x%x\n", offset, size); printf(" export trie: offset=0x%x size=0x%x\n", offset, size);
} }
if (cmd == LC_SEGMENT_64) { if (cmd == LC_SEGMENT_64) {
char* name = (char*)((uint64_t*)ptr + 1); char *name = (char *)((uint64_t *)ptr + 1);
uint64_t vmaddr = *((uint64_t*)ptr + 3); uint64_t vmaddr = *((uint64_t *)ptr + 3);
uint64_t vmsize = *((uint64_t*)ptr + 4); uint64_t vmsize = *((uint64_t *)ptr + 4);
uint64_t fileoffset = *((uint64_t*)ptr + 5); uint64_t fileoffset = *((uint64_t *)ptr + 5);
uint64_t filesize = *((uint64_t*)ptr + 6); uint64_t filesize = *((uint64_t *)ptr + 6);
if (strcmp(name, "__TEXT") == 0) { if (strcmp(name, "__TEXT") == 0) {
uint64_t slide = (uint64_t)header - vmaddr; uint64_t slide = (uint64_t)header - vmaddr;
printf(" --- slide=0x%llx ---\n", slide); printf(" --- slide=0x%llx ---\n", slide);
@ -110,9 +111,9 @@ void print_macho_summary(const void* header) {
} }
} }
void* get_export_trie(const void* header, uint32_t& size) { void *get_export_trie(const void *header, uint32_t &size) {
const uint32_t magic = *(uint32_t*)header; const uint32_t magic = *(uint32_t *)header;
char* ptr = (char*)header; char *ptr = (char *)header;
if (magic == magic64) { if (magic == magic64) {
ptr += 0x20; ptr += 0x20;
} else { } else {
@ -122,20 +123,20 @@ void* get_export_trie(const void* header, uint32_t& size) {
uint64_t slice = 0; uint64_t slice = 0;
uint64_t linkedit_vmaddr = 0; uint64_t linkedit_vmaddr = 0;
uint64_t linkedit_fileoffset = 0; uint64_t linkedit_fileoffset = 0;
const uint32_t ncmds = *((uint32_t*)header + 4); const uint32_t ncmds = *((uint32_t *)header + 4);
for (int i = 0; i < ncmds; i++) { for (int i = 0; i < ncmds; i++) {
const uint32_t cmd = *((uint32_t*)ptr + 0); const uint32_t cmd = *((uint32_t *)ptr + 0);
const uint32_t cmdsize = *((uint32_t*)ptr + 1); const uint32_t cmdsize = *((uint32_t *)ptr + 1);
if (cmd == LC_DYLD_EXPORTS_TRIE) { if (cmd == LC_DYLD_EXPORTS_TRIE) {
const uint32_t offset = *((uint32_t*)ptr + 2); const uint32_t offset = *((uint32_t *)ptr + 2);
size = *((uint32_t*)ptr + 3); size = *((uint32_t *)ptr + 3);
uint64_t offset_in_linkedit = (uint64_t)offset - linkedit_fileoffset; uint64_t offset_in_linkedit = (uint64_t)offset - linkedit_fileoffset;
return (void*)(linkedit_vmaddr + slice + offset_in_linkedit); return (void *)(linkedit_vmaddr + slice + offset_in_linkedit);
} }
if (cmd == LC_SEGMENT_64) { if (cmd == LC_SEGMENT_64) {
char* name = (char*)((uint64_t*)ptr + 1); char *name = (char *)((uint64_t *)ptr + 1);
uint64_t vmaddr = *((uint64_t*)ptr + 3); uint64_t vmaddr = *((uint64_t *)ptr + 3);
uint64_t fileoffset = *((uint64_t*)ptr + 5); uint64_t fileoffset = *((uint64_t *)ptr + 5);
if (strcmp(name, "__TEXT") == 0) { if (strcmp(name, "__TEXT") == 0) {
slice = (uint64_t)header - vmaddr; slice = (uint64_t)header - vmaddr;
} else if (strcmp(name, "__LINKEDIT") == 0) { } else if (strcmp(name, "__LINKEDIT") == 0) {
@ -148,9 +149,9 @@ void* get_export_trie(const void* header, uint32_t& size) {
return 0; return 0;
} }
uint32_t should_follow_symbol(char*& buffer, char*& _find) { uint32_t should_follow_symbol(char *&buffer, char *&_find) {
// printf("follow check %s has prefix: %s\n", _find, buffer); // printf("follow check %s has prefix: %s\n", _find, buffer);
char* find = _find; char *find = _find;
char is_prefix = true; char is_prefix = true;
while (1) { while (1) {
int find_end = *find == 0; int find_end = *find == 0;
@ -183,11 +184,11 @@ uint32_t should_follow_symbol(char*& buffer, char*& _find) {
return is_prefix; return is_prefix;
} }
void* find_in_export_trie(const void* header, void* trie, char* symbol) { void *find_in_export_trie(const void *header, void *trie, char *symbol) {
uint32_t func = 0; uint32_t func = 0;
char* ptr = (char*)trie; char *ptr = (char *)trie;
char* find = symbol; char *find = symbol;
while (1) { while (1) {
// terminal node will have data // terminal node will have data
uint32_t data_count = 0; uint32_t data_count = 0;
@ -206,7 +207,7 @@ void* find_in_export_trie(const void* header, void* trie, char* symbol) {
uint32_t follow_offset; uint32_t follow_offset;
decode_uleb128(ptr, &follow_offset); decode_uleb128(ptr, &follow_offset);
if (still_following) { if (still_following) {
ptr = (char*)trie + follow_offset; ptr = (char *)trie + follow_offset;
break; break;
} }
} }
@ -221,10 +222,10 @@ void* find_in_export_trie(const void* header, void* trie, char* symbol) {
ptr++; // flags ptr++; // flags
// uleb128 offset // uleb128 offset
decode_uleb128(ptr, &func); decode_uleb128(ptr, &func);
return (void*)((char*)header + func); return (void *)((char *)header + func);
} }
int hook_printf (const char * format, ... ) { int hook_printf(const char *format, ...) {
va_list args; va_list args;
va_start(args, format); va_start(args, format);
@ -236,16 +237,17 @@ int hook_printf (const char * format, ... ) {
return status; return status;
} }
__attribute__((constructor)) __attribute__((constructor)) static void
static void bruh(int argc, const char* const argv[], const char* const envp[], const char* const apple[], const struct ProgramVars* vars) { bruh(int argc, const char *const argv[], const char *const envp[],
const char *const apple[], const struct ProgramVars *vars) {
// ProgramVars contains pointer to main executable (mapped) file // ProgramVars contains pointer to main executable (mapped) file
const void* main = (int*)(vars->mh); const void *main = (int *)(vars->mh);
// Find our lib (mapped) file // Find our lib (mapped) file
const void* thislib = find_header((void*)bruh); const void *thislib = find_header((void *)bruh);
// Find dyld lib (mapped) file using a no-sus function // Find dyld lib (mapped) file using a no-sus function
const void* libdyld = find_header((void*)dyld_get_sdk_version); const void *libdyld = find_header((void *)dyld_get_sdk_version);
const void* libc = find_header((void*)printf); const void *libc = find_header((void *)printf);
// From libdyld header, we can list exports table // From libdyld header, we can list exports table
// to find all function we want to use // to find all function we want to use
@ -273,16 +275,16 @@ static void bruh(int argc, const char* const argv[], const char* const envp[], c
printf("libdyld header at %p\n", libdyld); printf("libdyld header at %p\n", libdyld);
for (int i = 0; i < _dyld_image_count(); i++) { for (int i = 0; i < _dyld_image_count(); i++) {
void* header = (void*)_dyld_get_image_header(i); void *header = (void *)_dyld_get_image_header(i);
char* name = (char*)_dyld_get_image_name(i); char *name = (char *)_dyld_get_image_name(i);
int offset = _dyld_get_image_vmaddr_slide(i); int offset = _dyld_get_image_vmaddr_slide(i);
printf("%p 0x%x name=%s\n", header, offset, name); printf("%p 0x%x name=%s\n", header, offset, name);
} }
uint32_t trie_size; uint32_t trie_size;
void* thislib_export_trie = get_export_trie(thislib, trie_size); void *thislib_export_trie = get_export_trie(thislib, trie_size);
void* libdyld_export_trie = get_export_trie(libdyld, trie_size); void *libdyld_export_trie = get_export_trie(libdyld, trie_size);
void* libc_export_trie = get_export_trie(libc, trie_size); void *libc_export_trie = get_export_trie(libc, trie_size);
// printf("export this lib address %p\n", thislib_export_trie); // printf("export this lib address %p\n", thislib_export_trie);
// for (int i = 0; i < 136; i++) { // for (int i = 0; i < 136; i++) {
@ -291,7 +293,6 @@ static void bruh(int argc, const char* const argv[], const char* const envp[], c
// } // }
// printf("\n"); // printf("\n");
// printf("export dyld lib address %llx\n", (uint64_t)libdyld_export_trie); // printf("export dyld lib address %llx\n", (uint64_t)libdyld_export_trie);
// for (int i = 0; i < 0x11e0; i++) { // for (int i = 0; i < 0x11e0; i++) {
// if (i % 0x10 == 0) printf("\n"); // if (i % 0x10 == 0) printf("\n");
@ -310,22 +311,24 @@ static void bruh(int argc, const char* const argv[], const char* const envp[], c
// fwrite(system_export_trie, trie_size, 1, write_ptr); // fwrite(system_export_trie, trie_size, 1, write_ptr);
struct test_find_export { struct test_find_export {
const char* name; const char *name;
const void* lib; const void *lib;
void* trie; void *trie;
void* original; void *original;
}; };
struct test_find_export find_export_testcases[] = { struct test_find_export find_export_testcases[] = {
{"__Z11find_headerPv", thislib, thislib_export_trie, (void*)find_header}, {"__Z11find_headerPv", thislib, thislib_export_trie, (void *)find_header},
{"__dyld_get_image_name", libdyld, libdyld_export_trie, (void*)_dyld_get_image_name}, {"__dyld_get_image_name", libdyld, libdyld_export_trie,
{"__dyld_image_count", libdyld, libdyld_export_trie, (void*)_dyld_image_count}, (void *)_dyld_get_image_name},
{"_printf",libc, libc_export_trie, (void*)printf}, {"__dyld_image_count", libdyld, libdyld_export_trie,
(void *)_dyld_image_count},
{"_printf", libc, libc_export_trie, (void *)printf},
}; };
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
struct test_find_export test = find_export_testcases[i]; struct test_find_export test = find_export_testcases[i];
void* found = find_in_export_trie(test.lib, test.trie, (char*)test.name); void *found = find_in_export_trie(test.lib, test.trie, (char *)test.name);
printf("%s: Found=%p | Expect=%p\n", test.name, found, test.original); printf("%s: Found=%p | Expect=%p\n", test.name, found, test.original);
} }
@ -334,11 +337,11 @@ static void bruh(int argc, const char* const argv[], const char* const envp[], c
// modern symbol resolve // modern symbol resolve
// fix got // fix got
uint64_t* got = (uint64_t*)((char*)main + 0x4000); uint64_t *got = (uint64_t *)((char *)main + 0x4000);
printf("BEFORE symbol bind code is %llx\n", *got); printf("BEFORE symbol bind code is %llx\n", *got);
vm_protect(mach_task_self(), (uint64_t)got, 0x4000, 0, VM_PROT_READ | VM_PROT_WRITE); vm_protect(mach_task_self(), (uint64_t)got, 0x4000, 0,
VM_PROT_READ | VM_PROT_WRITE);
// fix got table // fix got table
// *got = (uint64_t)find_in_export_trie(libc, libc_export_trie, "_printf"); // *got = (uint64_t)find_in_export_trie(libc, libc_export_trie, "_printf");