From a2f9ca82e75c77283b37fbb31fe696e2a6edb25b Mon Sep 17 00:00:00 2001 From: nganhkhoa Date: Mon, 26 Jun 2023 15:13:15 +0700 Subject: [PATCH] update shellcode - shellcode correctly passes arguments to main - shellcode deals with __bss section in __DATA - remove hardcoded values --- macho-go/pkg/ios/macho/edit.go | 135 +++++++++++++++++++++++---------- 1 file changed, 96 insertions(+), 39 deletions(-) diff --git a/macho-go/pkg/ios/macho/edit.go b/macho-go/pkg/ios/macho/edit.go index a6f810f..79c5b00 100644 --- a/macho-go/pkg/ios/macho/edit.go +++ b/macho-go/pkg/ios/macho/edit.go @@ -355,6 +355,8 @@ func (mc *MachoContext) removeBindSymbolsLegacy() { func (mc *MachoContext) ReworkForObjc() { text_start := 0 + data_end := 0 + lc_main_offset := int64(0) ptr := int64(0) if mc.Is64bit() { @@ -364,6 +366,11 @@ func (mc *MachoContext) ReworkForObjc() { } for _, cmd := range mc.commands { + if cmd.Cmd() == LC_MAIN { + lc_main_offset = ptr + 8 + ptr += int64(cmd.Cmdsize()) + continue + } if cmd.Cmd() != LC_SEGMENT_64 { ptr += int64(cmd.Cmdsize()) continue @@ -371,11 +378,17 @@ func (mc *MachoContext) ReworkForObjc() { var segment = cmd.(*Segment64) if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__TEXT")) == 0 { + section_ptr := ptr + 0x40 + 8 for _, section := range segment.Sections() { if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__text")) == 0 { text_start = int(section.Offset()) - break } + if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__init_offsets")) == 0 { + // mc.file.WriteAt([]byte("__init_offsetx"), section_ptr) + // edit flags to not S_MOD_INIT_FUNC + mc.file.WriteAt([]byte{0, 0, 0, 0}, section_ptr + 0x40) + } + section_ptr += 16 * 2 + 8 * 2 + 4 * 8 } } if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__DATA_CONST")) == 0 { @@ -391,11 +404,18 @@ func (mc *MachoContext) ReworkForObjc() { } } if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__DATA")) == 0 { - // section_ptr := ptr + 0x40 + 8 - // for _, section := range segment.Sections() { - // section_ptr += 16 * 2 + 8 * 2 + 4 * 8 - // } // end of __DATA segment, should have enough space for a pointer + + // __bss section is dynamically allocated at the end to or something, hmmge + // assume that it order correctly, which it should if compiled and not modified + sections := segment.Sections() + last := sections[len(sections) - 1] + data_end = int(last.Offset()) + int(last.Size()) + + if (last.Offset() == 0) { + before_last := sections[len(sections) - 2] + data_end += int(before_last.Offset()) + int(before_last.Size()) + } } ptr += int64(cmd.Cmdsize()) } @@ -405,50 +425,63 @@ func (mc *MachoContext) ReworkForObjc() { // its physical size is still a page // mc.file.WriteAt([]byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7}, int64(0x81d8)) - ins_size_byte := 4 - x8_value_offset := text_start - (ins_size_byte * 17) + (ins_size_byte * 2) - main_offset := mc.entryoff + // we use 2 registers, x8 x9 + // stack values: + // [ return address, header, argc, argv, env, apple ] + // we need to store the return address, and parameters passed to main + // we also store our header address to not calculate many times - movz_x8_value_offset := uint32(uint32(x8_value_offset)<<5 | uint32(0x694)<<21 | uint32(0x09)) - movz_main_offset := uint32(uint32(main_offset)<<5 | uint32(0x694)<<21 | uint32(0x09)) + /* + adr x8, 0 + sub sp, sp, #0x30 + str x30, [sp] + movz x9, #0x3d68 ; offset at this point + sub x8, x8, x9 + str x8, [sp, #0x8] + str x0, [sp, #0x10] + str x1, [sp, #0x18] + str x2, [sp, #0x20] + str x3, [sp, #0x28] - fmt.Printf("// x8_value_offset=%x\n", x8_value_offset) - fmt.Printf("// main_offset=%x\n", main_offset) - fmt.Printf("// x8_value_offset=%x\n", movz_x8_value_offset) - fmt.Printf("// main_offset=%x\n", movz_main_offset) - - // sub sp, sp, #0x10 - // str x30, [sp] - // adr x8, 0 - // movz x9, #0x3d68 ; offset at this point - // sub x8, x8, x9 - // str x8, [sp, #8] - // movz x9, #0x81d8 - // add x9, x8, x9 - // ldr x9, [x9] - // blr x9 - // ldr x8, [sp, #8] - // movz x9, #0x3e3c ; offset to original main - // add x9, x8, x9 - // blr x9 - // ldr x30, [sp] - // add sp, sp, #0x10 - // ret + movz x9, #0x81d8 ; offset to end of __DATA + add x9, x8, x9 + ldr x9, [x9] + blr x9 + ldr x8, [sp, #0x8] + ldr x0, [sp, #0x10] + ldr x1, [sp, #0x18] + ldr x2, [sp, #0x20] + ldr x3, [sp, #0x28] + movz x9, #0x3e3c ; offset to original main + add x9, x8, x9 + blr x9 + ldr x30, [sp] + add sp, sp, #0x10 + ret + */ // TODO: fix to work with offset larger than 0xffff shellcode := []uint32{ - 0xD10043FF, - 0xF90003FE, 0x10000008, - movz_x8_value_offset, + 0xD100C3FF, + 0xF90003FE, + 0, // movz_shellcode_offset, 0xCB090108, 0xF90007E8, - 0xD2903B09, + 0xF9000BE0, + 0xF9000FE1, + 0xF90013E2, + 0xF90017E3, + 0, // movz_data_end_offset, 0x8B090109, 0xF9400129, 0xD63F0120, 0xF94007E8, - movz_main_offset, + 0xF9400BE0, + 0xF9400FE1, + 0xF94013E2, + 0xF94017E3, + 0, // movz_main_offset, 0x8B090109, 0xD63F0120, 0xF94003FE, @@ -456,12 +489,36 @@ func (mc *MachoContext) ReworkForObjc() { 0xD65F03C0, } - offset := int64(0x3da4 - len(shellcode) * 4) + ins_size_byte := 4 + shellcode_offset := text_start - (ins_size_byte * len(shellcode)) + main_offset := int(mc.entryoff) + + encode_movz := func(v int) uint32 { + return uint32(uint32(v)<<5 | uint32(0x694)<<21 | uint32(0x09)) + } + + movz_shellcode_offset := encode_movz(shellcode_offset) + movz_main_offset := encode_movz(main_offset) + movz_data_end_offset := encode_movz(data_end) + + shellcode[3] = movz_shellcode_offset + shellcode[10] = movz_data_end_offset + shellcode[19] = movz_main_offset + + fmt.Printf("// shellcode_offset=%x\n", shellcode_offset) + fmt.Printf("// main_offset=%x\n", main_offset) + fmt.Printf("// data_end=%x\n", data_end) + fmt.Printf("// movz_shellcode_offset=%x\n", movz_shellcode_offset) + fmt.Printf("// movz_main_offset=%x\n", movz_main_offset) + fmt.Printf("// movz_data_end_offset=%x\n", movz_data_end_offset) + fmt.Printf("// lc_main_offset=%x\n", lc_main_offset) + + offset := int64(shellcode_offset) { // fix main to point to our newly created shellcode bs := make([]byte, 8) mc.byteorder.PutUint64(bs, uint64(offset)) - mc.file.WriteAt(bs, int64(0x870)) + mc.file.WriteAt(bs, int64(lc_main_offset)) } bs := make([]byte, 4)