update shellcode

- shellcode correctly passes arguments to main
- shellcode deals with __bss section in __DATA
- remove hardcoded values
This commit is contained in:
nganhkhoa 2023-06-26 15:13:15 +07:00
parent 693c2b6c95
commit a2f9ca82e7

View File

@ -355,6 +355,8 @@ func (mc *MachoContext) removeBindSymbolsLegacy() {
func (mc *MachoContext) ReworkForObjc() { func (mc *MachoContext) ReworkForObjc() {
text_start := 0 text_start := 0
data_end := 0
lc_main_offset := int64(0)
ptr := int64(0) ptr := int64(0)
if mc.Is64bit() { if mc.Is64bit() {
@ -364,6 +366,11 @@ func (mc *MachoContext) ReworkForObjc() {
} }
for _, cmd := range mc.commands { 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 { if cmd.Cmd() != LC_SEGMENT_64 {
ptr += int64(cmd.Cmdsize()) ptr += int64(cmd.Cmdsize())
continue continue
@ -371,11 +378,17 @@ func (mc *MachoContext) ReworkForObjc() {
var segment = cmd.(*Segment64) var segment = cmd.(*Segment64)
if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__TEXT")) == 0 { if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__TEXT")) == 0 {
section_ptr := ptr + 0x40 + 8
for _, section := range segment.Sections() { for _, section := range segment.Sections() {
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__text")) == 0 { if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__text")) == 0 {
text_start = int(section.Offset()) 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 { 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 { 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 // 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()) ptr += int64(cmd.Cmdsize())
} }
@ -405,50 +425,63 @@ func (mc *MachoContext) ReworkForObjc() {
// its physical size is still a page // its physical size is still a page
// mc.file.WriteAt([]byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7}, int64(0x81d8)) // mc.file.WriteAt([]byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7}, int64(0x81d8))
ins_size_byte := 4 // we use 2 registers, x8 x9
x8_value_offset := text_start - (ins_size_byte * 17) + (ins_size_byte * 2) // stack values:
main_offset := mc.entryoff // [ 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) movz x9, #0x81d8 ; offset to end of __DATA
fmt.Printf("// main_offset=%x\n", main_offset) add x9, x8, x9
fmt.Printf("// x8_value_offset=%x\n", movz_x8_value_offset) ldr x9, [x9]
fmt.Printf("// main_offset=%x\n", movz_main_offset) blr x9
ldr x8, [sp, #0x8]
// sub sp, sp, #0x10 ldr x0, [sp, #0x10]
// str x30, [sp] ldr x1, [sp, #0x18]
// adr x8, 0 ldr x2, [sp, #0x20]
// movz x9, #0x3d68 ; offset at this point ldr x3, [sp, #0x28]
// sub x8, x8, x9 movz x9, #0x3e3c ; offset to original main
// str x8, [sp, #8] add x9, x8, x9
// movz x9, #0x81d8 blr x9
// add x9, x8, x9 ldr x30, [sp]
// ldr x9, [x9] add sp, sp, #0x10
// blr x9 ret
// 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
// TODO: fix to work with offset larger than 0xffff // TODO: fix to work with offset larger than 0xffff
shellcode := []uint32{ shellcode := []uint32{
0xD10043FF,
0xF90003FE,
0x10000008, 0x10000008,
movz_x8_value_offset, 0xD100C3FF,
0xF90003FE,
0, // movz_shellcode_offset,
0xCB090108, 0xCB090108,
0xF90007E8, 0xF90007E8,
0xD2903B09, 0xF9000BE0,
0xF9000FE1,
0xF90013E2,
0xF90017E3,
0, // movz_data_end_offset,
0x8B090109, 0x8B090109,
0xF9400129, 0xF9400129,
0xD63F0120, 0xD63F0120,
0xF94007E8, 0xF94007E8,
movz_main_offset, 0xF9400BE0,
0xF9400FE1,
0xF94013E2,
0xF94017E3,
0, // movz_main_offset,
0x8B090109, 0x8B090109,
0xD63F0120, 0xD63F0120,
0xF94003FE, 0xF94003FE,
@ -456,12 +489,36 @@ func (mc *MachoContext) ReworkForObjc() {
0xD65F03C0, 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 // fix main to point to our newly created shellcode
bs := make([]byte, 8) bs := make([]byte, 8)
mc.byteorder.PutUint64(bs, uint64(offset)) mc.byteorder.PutUint64(bs, uint64(offset))
mc.file.WriteAt(bs, int64(0x870)) mc.file.WriteAt(bs, int64(lc_main_offset))
} }
bs := make([]byte, 4) bs := make([]byte, 4)