move everything objc to objc.go
This commit is contained in:
parent
9ec2a301b4
commit
a8ffae5202
@ -360,273 +360,6 @@ func (mc *MachoContext) removeBindSymbolsLegacy() {
|
|||||||
mc.file.WriteAt(make([]byte, size), int64(start))
|
mc.file.WriteAt(make([]byte, size), int64(start))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mc *MachoContext) ReworkForObjc() {
|
|
||||||
text_start := 0
|
|
||||||
data_end := 0
|
|
||||||
lc_main_offset := int64(0)
|
|
||||||
|
|
||||||
ptr := int64(0)
|
|
||||||
if mc.Is64bit() {
|
|
||||||
ptr, _ = mc.file.Seek(int64(Header_size_64), io.SeekStart)
|
|
||||||
} else {
|
|
||||||
ptr, _ = mc.file.Seek(int64(Header_size), io.SeekStart)
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
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())
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
// erases all objc method names
|
|
||||||
// this should still works because the cache inserts the pointer value not string
|
|
||||||
// but some symbols relies on pre-defined implementations, such as **load** method
|
|
||||||
// load method is the same across all classes and so objc define an implementation
|
|
||||||
// selector should points to this load selector to make objc thinks that it's "load"
|
|
||||||
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_methname")) == 0 {
|
|
||||||
// mc.file.WriteAt([]byte("__objc_methbruh"), section_ptr)
|
|
||||||
mc.file.WriteAt(make([]byte, section.Size()), int64(section.Offset()))
|
|
||||||
}
|
|
||||||
section_ptr += 16*2 + 8*2 + 4*8
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__DATA_CONST")) == 0 {
|
|
||||||
section_ptr := ptr + 0x40 + 8
|
|
||||||
for _, section := range segment.Sections() {
|
|
||||||
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_classlist")) == 0 {
|
|
||||||
mc.file.WriteAt([]byte("__objc_classbruh"), section_ptr)
|
|
||||||
}
|
|
||||||
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_nlclslist")) == 0 {
|
|
||||||
mc.file.WriteAt([]byte("__objc_nlclsbruh"), section_ptr)
|
|
||||||
}
|
|
||||||
section_ptr += 16*2 + 8*2 + 4*8
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__DATA")) == 0 {
|
|
||||||
// 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
|
|
||||||
// each section has their addr field which we can use that with segment virtual address
|
|
||||||
// to calculate the offset of the last section from segment starts
|
|
||||||
// then use the size of section to calculate the end of segment in file
|
|
||||||
sections := segment.Sections()
|
|
||||||
last := sections[len(sections)-1]
|
|
||||||
data_end = int(last.Addr() - segment.Vmaddr() + segment.Fileoff() + last.Size())
|
|
||||||
|
|
||||||
// do not register selector and see what happens
|
|
||||||
section_ptr := ptr + 0x40 + 8
|
|
||||||
for _, section := range segment.Sections() {
|
|
||||||
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_selrefs")) == 0 {
|
|
||||||
// mc.file.WriteAt([]byte("__objc_selbruh"), section_ptr)
|
|
||||||
}
|
|
||||||
section_ptr += 16*2 + 8*2 + 4*8
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ptr += int64(cmd.Cmdsize())
|
|
||||||
}
|
|
||||||
mc.file.Seek(0, io.SeekStart)
|
|
||||||
|
|
||||||
// dummy value past the end of __DATA segment (logical size),
|
|
||||||
// its physical size is still a page
|
|
||||||
// mc.file.WriteAt([]byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7}, int64(0x81d8))
|
|
||||||
|
|
||||||
// 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
|
|
||||||
|
|
||||||
// must expand stack to store arguments passed
|
|
||||||
// must use newly allocated stack region
|
|
||||||
// must save return address
|
|
||||||
// must recover stack to same value before calling main
|
|
||||||
// must recover link register before calling main
|
|
||||||
|
|
||||||
// we use shorthand store/load multiple
|
|
||||||
// arm also has different indexing instruction, so be careful
|
|
||||||
// https://developer.arm.com/documentation/102374/0101/Loads-and-stores---addressing
|
|
||||||
/*
|
|
||||||
adr x8, 0
|
|
||||||
# x9 = (offset end of __DATA) - (offset shellcode)
|
|
||||||
movz x9, #0x9999
|
|
||||||
add x8, x8, x9
|
|
||||||
|
|
||||||
stp x30, x8, [sp], #-0x10
|
|
||||||
stp x3, x2, [sp], #-0x10
|
|
||||||
stp x1, x0, [sp], #-0x10
|
|
||||||
|
|
||||||
# custom intializer
|
|
||||||
ldr x9, [x8]
|
|
||||||
blr x9
|
|
||||||
|
|
||||||
ldp x1, x0, [sp, #0x10]!
|
|
||||||
ldp x3, x2, [sp, #0x10]!
|
|
||||||
ldp x30, x8, [sp, #0x10]!
|
|
||||||
|
|
||||||
# original main
|
|
||||||
# link register is set so jump only
|
|
||||||
ldr x9, [x8, #8]
|
|
||||||
br x9
|
|
||||||
*/
|
|
||||||
shellcode := []uint32{}
|
|
||||||
ins_size_byte := 4
|
|
||||||
main_offset := int(mc.entryoff)
|
|
||||||
var shellcode_offset int
|
|
||||||
|
|
||||||
isArm := (mc.header.cputype & 0xff) == 12
|
|
||||||
if isArm {
|
|
||||||
shellcode = []uint32{
|
|
||||||
0x10000008,
|
|
||||||
0, // x9 = (offset end of __DATA) - (offset shellcode)
|
|
||||||
0x8B090108,
|
|
||||||
0xA8BF23FE,
|
|
||||||
0xA8BF0BE3,
|
|
||||||
0xA8BF03E1,
|
|
||||||
0xF9400109,
|
|
||||||
0xD63F0120,
|
|
||||||
0xA9C103E1,
|
|
||||||
0xA9C10BE3,
|
|
||||||
0xA9C123FE,
|
|
||||||
0xF9400509,
|
|
||||||
0xD61F0120,
|
|
||||||
}
|
|
||||||
|
|
||||||
shellcode_offset = text_start - (ins_size_byte * len(shellcode))
|
|
||||||
|
|
||||||
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)
|
|
||||||
movz_calculate_offset := encode_movz(data_end - shellcode_offset)
|
|
||||||
|
|
||||||
shellcode[1] = movz_calculate_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_calculate_offset=%x\n", movz_calculate_offset)
|
|
||||||
// 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)
|
|
||||||
} else {
|
|
||||||
shellcode_start := []uint8{
|
|
||||||
0x4c, 0x8d, 0x05, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x49, 0xC7, 0xC1,
|
|
||||||
}
|
|
||||||
|
|
||||||
shellcode_end := []uint8{
|
|
||||||
0x4d, 0x01, 0xc8,
|
|
||||||
0x57,
|
|
||||||
0x56,
|
|
||||||
0x52,
|
|
||||||
0x51,
|
|
||||||
0x41, 0x50,
|
|
||||||
0x4d, 0x8b, 0x08,
|
|
||||||
0x41, 0xff, 0xd1,
|
|
||||||
0x41,
|
|
||||||
0x58,
|
|
||||||
0x59,
|
|
||||||
0x5a,
|
|
||||||
0x5e,
|
|
||||||
0x5f, 0x4d, 0x8b, 0x48, 0x08,
|
|
||||||
0x41, 0xff, 0xe1,
|
|
||||||
// pad to %4
|
|
||||||
0x00, 0x00,
|
|
||||||
}
|
|
||||||
|
|
||||||
offset := []uint8{0x00, 0x00, 0x00, 0x00} // offset
|
|
||||||
shellcode_size := len(shellcode_start) + len(offset) + len(shellcode_end)
|
|
||||||
|
|
||||||
// could use buffer encoding, but for correctness,
|
|
||||||
// we do this by hand
|
|
||||||
encode_movz := func(v int) {
|
|
||||||
for i := 0; i < 4; i++ {
|
|
||||||
offset[i] = uint8(v >> (i * 8))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ┌─────────────────┐
|
|
||||||
// │ │
|
|
||||||
// shellcode starts ────┼─────────────────┼───── │ │instruction
|
|
||||||
// │ │ │ │fetch RIP size
|
|
||||||
// RIP returns ────┼─────────────────┼───── ▲ │ │
|
|
||||||
// │ │ │ │
|
|
||||||
// │ │ │ │ shellcode length
|
|
||||||
// shellcode ends │ │ │ offset │
|
|
||||||
// __text ────┼─────────────────┼───── │ range │
|
|
||||||
// │ │ │ │ __DATA ends - __text
|
|
||||||
// │ │ │ │
|
|
||||||
// __DATA ends ────┼─────────────────┼───── ▼ │
|
|
||||||
// │ │
|
|
||||||
// │ │
|
|
||||||
// │ │
|
|
||||||
// │ │
|
|
||||||
// │ │
|
|
||||||
// └─────────────────┘
|
|
||||||
encode_movz((data_end - text_start) + (shellcode_size - len(shellcode_start)))
|
|
||||||
|
|
||||||
shellcode_offset = text_start - shellcode_size
|
|
||||||
shellcode_bytes := append(shellcode_start, offset...)
|
|
||||||
shellcode_bytes = append(shellcode_bytes, shellcode_end...)
|
|
||||||
|
|
||||||
for i := 0; i < len(shellcode_bytes); i += 4 {
|
|
||||||
val := 0
|
|
||||||
// little endian
|
|
||||||
val |= int(shellcode_bytes[i+0]) << 0
|
|
||||||
val |= int(shellcode_bytes[i+1]) << 8
|
|
||||||
val |= int(shellcode_bytes[i+2]) << 16
|
|
||||||
val |= int(shellcode_bytes[i+3]) << 24
|
|
||||||
shellcode = append(shellcode, uint32(val))
|
|
||||||
}
|
|
||||||
|
|
||||||
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("// 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(lc_main_offset))
|
|
||||||
}
|
|
||||||
|
|
||||||
bs := make([]byte, 4)
|
|
||||||
for _, ins := range shellcode {
|
|
||||||
mc.byteorder.PutUint32(bs, ins)
|
|
||||||
mc.file.WriteAt(bs, offset)
|
|
||||||
offset += 4
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mc *MachoContext) RewriteImportsTable(keepSymbols []string) {
|
func (mc *MachoContext) RewriteImportsTable(keepSymbols []string) {
|
||||||
allSymbols := mc.CollectBindSymbols()
|
allSymbols := mc.CollectBindSymbols()
|
||||||
fixups, fixupsOffset := mc.Fixups()
|
fixups, fixupsOffset := mc.Fixups()
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
package macho
|
package macho
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
. "ios-wrapper/pkg/ios"
|
. "ios-wrapper/pkg/ios"
|
||||||
@ -93,3 +95,271 @@ func (mc *MachoContext) CollectSpecialSelectors() []*SpecialSelector {
|
|||||||
return special_selectors
|
return special_selectors
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mc *MachoContext) ReworkForObjc() {
|
||||||
|
text_start := 0
|
||||||
|
data_end := 0
|
||||||
|
lc_main_offset := int64(0)
|
||||||
|
|
||||||
|
ptr := int64(0)
|
||||||
|
if mc.Is64bit() {
|
||||||
|
ptr, _ = mc.file.Seek(int64(Header_size_64), io.SeekStart)
|
||||||
|
} else {
|
||||||
|
ptr, _ = mc.file.Seek(int64(Header_size), io.SeekStart)
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// erases all objc method names
|
||||||
|
// this should still works because the cache inserts the pointer value not string
|
||||||
|
// but some symbols relies on pre-defined implementations, such as **load** method
|
||||||
|
// load method is the same across all classes and so objc define an implementation
|
||||||
|
// selector should points to this load selector to make objc thinks that it's "load"
|
||||||
|
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_methname")) == 0 {
|
||||||
|
// mc.file.WriteAt([]byte("__objc_methbruh"), section_ptr)
|
||||||
|
mc.file.WriteAt(make([]byte, section.Size()), int64(section.Offset()))
|
||||||
|
}
|
||||||
|
section_ptr += 16*2 + 8*2 + 4*8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__DATA_CONST")) == 0 {
|
||||||
|
section_ptr := ptr + 0x40 + 8
|
||||||
|
for _, section := range segment.Sections() {
|
||||||
|
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_classlist")) == 0 {
|
||||||
|
mc.file.WriteAt([]byte("__objc_classbruh"), section_ptr)
|
||||||
|
}
|
||||||
|
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_nlclslist")) == 0 {
|
||||||
|
mc.file.WriteAt([]byte("__objc_nlclsbruh"), section_ptr)
|
||||||
|
}
|
||||||
|
section_ptr += 16*2 + 8*2 + 4*8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__DATA")) == 0 {
|
||||||
|
// 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
|
||||||
|
// each section has their addr field which we can use that with segment virtual address
|
||||||
|
// to calculate the offset of the last section from segment starts
|
||||||
|
// then use the size of section to calculate the end of segment in file
|
||||||
|
sections := segment.Sections()
|
||||||
|
last := sections[len(sections)-1]
|
||||||
|
data_end = int(last.Addr() - segment.Vmaddr() + segment.Fileoff() + last.Size())
|
||||||
|
|
||||||
|
// do not register selector and see what happens
|
||||||
|
section_ptr := ptr + 0x40 + 8
|
||||||
|
for _, section := range segment.Sections() {
|
||||||
|
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_selrefs")) == 0 {
|
||||||
|
// mc.file.WriteAt([]byte("__objc_selbruh"), section_ptr)
|
||||||
|
}
|
||||||
|
section_ptr += 16*2 + 8*2 + 4*8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ptr += int64(cmd.Cmdsize())
|
||||||
|
}
|
||||||
|
mc.file.Seek(0, io.SeekStart)
|
||||||
|
|
||||||
|
// dummy value past the end of __DATA segment (logical size),
|
||||||
|
// its physical size is still a page
|
||||||
|
// mc.file.WriteAt([]byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7}, int64(0x81d8))
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
// must expand stack to store arguments passed
|
||||||
|
// must use newly allocated stack region
|
||||||
|
// must save return address
|
||||||
|
// must recover stack to same value before calling main
|
||||||
|
// must recover link register before calling main
|
||||||
|
|
||||||
|
// ┌─────────────────┐
|
||||||
|
// │ │
|
||||||
|
// shellcode starts ────┼─────────────────┼───── │ │instruction
|
||||||
|
// │ │ │ │fetch RIP size
|
||||||
|
// RIP returns ────┼─────────────────┼───── ▲ │ │
|
||||||
|
// │ │ │ │
|
||||||
|
// │ │ │ │ shellcode length
|
||||||
|
// shellcode ends │ │ │ offset │
|
||||||
|
// __text ────┼─────────────────┼───── │ range │
|
||||||
|
// │ │ │ │ __DATA ends - __text
|
||||||
|
// │ │ │ │
|
||||||
|
// __DATA ends ────┼─────────────────┼───── ▼ │
|
||||||
|
// │ │
|
||||||
|
// │ │
|
||||||
|
// │ │
|
||||||
|
// │ │
|
||||||
|
// │ │
|
||||||
|
// └─────────────────┘
|
||||||
|
|
||||||
|
shellcode := []uint32{}
|
||||||
|
ins_size_byte := 4
|
||||||
|
main_offset := int(mc.entryoff)
|
||||||
|
var shellcode_offset int
|
||||||
|
|
||||||
|
isArm := (mc.header.cputype & 0xff) == 12
|
||||||
|
if isArm {
|
||||||
|
|
||||||
|
// we use shorthand store/load multiple
|
||||||
|
// arm also has different indexing instruction, so be careful
|
||||||
|
// https://developer.arm.com/documentation/102374/0101/Loads-and-stores---addressing
|
||||||
|
/*
|
||||||
|
adr x8, 0
|
||||||
|
# x9 = (offset end of __DATA) - (offset shellcode)
|
||||||
|
movz x9, #0x9999
|
||||||
|
add x8, x8, x9
|
||||||
|
|
||||||
|
stp x30, x8, [sp], #-0x10
|
||||||
|
stp x3, x2, [sp], #-0x10
|
||||||
|
stp x1, x0, [sp], #-0x10
|
||||||
|
|
||||||
|
# custom intializer
|
||||||
|
ldr x9, [x8]
|
||||||
|
blr x9
|
||||||
|
|
||||||
|
ldp x1, x0, [sp, #0x10]!
|
||||||
|
ldp x3, x2, [sp, #0x10]!
|
||||||
|
ldp x30, x8, [sp, #0x10]!
|
||||||
|
|
||||||
|
# original main
|
||||||
|
# link register is set so jump only
|
||||||
|
ldr x9, [x8, #8]
|
||||||
|
br x9
|
||||||
|
*/
|
||||||
|
shellcode = []uint32{
|
||||||
|
0x10000008,
|
||||||
|
0, // x9 = (offset end of __DATA) - (offset shellcode)
|
||||||
|
0x8B090108,
|
||||||
|
0xA8BF23FE,
|
||||||
|
0xA8BF0BE3,
|
||||||
|
0xA8BF03E1,
|
||||||
|
0xF9400109,
|
||||||
|
0xD63F0120,
|
||||||
|
0xA9C103E1,
|
||||||
|
0xA9C10BE3,
|
||||||
|
0xA9C123FE,
|
||||||
|
0xF9400509,
|
||||||
|
0xD61F0120,
|
||||||
|
}
|
||||||
|
|
||||||
|
shellcode_offset = text_start - (ins_size_byte * len(shellcode))
|
||||||
|
|
||||||
|
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)
|
||||||
|
movz_calculate_offset := encode_movz(data_end - shellcode_offset)
|
||||||
|
|
||||||
|
shellcode[1] = movz_calculate_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_calculate_offset=%x\n", movz_calculate_offset)
|
||||||
|
// 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)
|
||||||
|
} else {
|
||||||
|
shellcode_start := []uint8{
|
||||||
|
0x4c, 0x8d, 0x05, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x49, 0xC7, 0xC1,
|
||||||
|
}
|
||||||
|
|
||||||
|
shellcode_end := []uint8{
|
||||||
|
0x4d, 0x01, 0xc8,
|
||||||
|
0x57,
|
||||||
|
0x56,
|
||||||
|
0x52,
|
||||||
|
0x51,
|
||||||
|
0x41, 0x50,
|
||||||
|
0x4d, 0x8b, 0x08,
|
||||||
|
0x41, 0xff, 0xd1,
|
||||||
|
0x41,
|
||||||
|
0x58,
|
||||||
|
0x59,
|
||||||
|
0x5a,
|
||||||
|
0x5e,
|
||||||
|
0x5f, 0x4d, 0x8b, 0x48, 0x08,
|
||||||
|
0x41, 0xff, 0xe1,
|
||||||
|
// pad to %4
|
||||||
|
0x00, 0x00,
|
||||||
|
}
|
||||||
|
|
||||||
|
offset := []uint8{0x00, 0x00, 0x00, 0x00} // offset
|
||||||
|
shellcode_size := len(shellcode_start) + len(offset) + len(shellcode_end)
|
||||||
|
|
||||||
|
// could use buffer encoding, but for correctness,
|
||||||
|
// we do this by hand
|
||||||
|
encode_movz := func(v int) {
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
offset[i] = uint8(v >> (i * 8))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
encode_movz((data_end - text_start) + (shellcode_size - len(shellcode_start)))
|
||||||
|
|
||||||
|
shellcode_offset = text_start - shellcode_size
|
||||||
|
shellcode_bytes := append(shellcode_start, offset...)
|
||||||
|
shellcode_bytes = append(shellcode_bytes, shellcode_end...)
|
||||||
|
|
||||||
|
for i := 0; i < len(shellcode_bytes); i += 4 {
|
||||||
|
val := 0
|
||||||
|
// little endian
|
||||||
|
val |= int(shellcode_bytes[i+0]) << 0
|
||||||
|
val |= int(shellcode_bytes[i+1]) << 8
|
||||||
|
val |= int(shellcode_bytes[i+2]) << 16
|
||||||
|
val |= int(shellcode_bytes[i+3]) << 24
|
||||||
|
shellcode = append(shellcode, uint32(val))
|
||||||
|
}
|
||||||
|
|
||||||
|
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("// 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(lc_main_offset))
|
||||||
|
}
|
||||||
|
|
||||||
|
bs := make([]byte, 4)
|
||||||
|
for _, ins := range shellcode {
|
||||||
|
mc.byteorder.PutUint32(bs, ins)
|
||||||
|
mc.file.WriteAt(bs, offset)
|
||||||
|
offset += 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user