format code

This commit is contained in:
2023-07-12 13:37:54 +07:00
parent 4016abf40d
commit f88861a87e
10 changed files with 505 additions and 452 deletions

View File

@ -25,7 +25,7 @@ type ImportSymbol struct {
segment_offset uint32
address uint64
file_address uint64
lib_ordinal uint32
lib_ordinal uint32
// push number
pnum uint32
@ -121,7 +121,7 @@ func (mc *MachoContext) CollectBindSymbolsModern() []*ImportSymbol {
// fmt.Printf("segment=%x format=%x page_count=%d\n", fix.segment, fix.format, fix.page_count)
// fmt.Printf("pages=%x\n", fix.pages)
pages := ([]C.ushort)(unsafe.Slice(fix.pages, fix.page_count))
reader := bytes.NewReader(mc.buf)
reader := bytes.NewReader(mc.buf)
for page_i := 0; page_i < int(fix.page_count); page_i++ {
// fmt.Printf(" page offset=%x\n", pages[page_i])
@ -151,7 +151,7 @@ func (mc *MachoContext) CollectBindSymbolsModern() []*ImportSymbol {
sym.name = name
sym.dylib = dylib
sym.typ = "lazy"
sym.lib_ordinal = uint32(s.lib_ordinal)
sym.lib_ordinal = uint32(s.lib_ordinal)
sym.segment = uint32(mc.findSegmentIndexAt(uint64(address)))
sym.file_address = uint64(address)

View File

@ -2,17 +2,17 @@ package macho
import (
"bytes"
"encoding/binary"
"fmt"
"io"
"math/rand"
"strings"
"time"
"strings"
"encoding/binary"
log "github.com/sirupsen/logrus"
"ios-wrapper/pkg/protomodel"
. "ios-wrapper/pkg/ios"
"ios-wrapper/pkg/protomodel"
)
// #include "fixups.h"
@ -285,10 +285,10 @@ func (mc *MachoContext) RemoveBindSymbols() {
} else {
mc.removeBindSymbolsLegacy()
}
// Objective-C stub replaces main which can only appears in executable
if mc.Header().IsExecutable() {
mc.ReworkForObjc()
}
// Objective-C stub replaces main which can only appears in executable
if mc.Header().IsExecutable() {
mc.ReworkForObjc()
}
// due to some limitations when design this tool
// we write the c code to stdout lol
@ -445,27 +445,27 @@ func (mc *MachoContext) ReworkForObjc() {
// 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
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
stp x30, x8, [sp], #-0x10
stp x3, x2, [sp], #-0x10
stp x1, x0, [sp], #-0x10
# custom intializer
ldr x9, [x8]
blr x9
# custom intializer
ldr x9, [x8]
blr x9
ldp x1, x0, [sp, #0x10]!
ldp x3, x2, [sp, #0x10]!
ldp x30, x8, [sp, #0x10]!
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
# original main
# link register is set so jump only
ldr x9, [x8, #8]
br x9
*/
// TODO: fix to work with offset larger than 0xffff
@ -529,72 +529,72 @@ func (mc *MachoContext) ReworkForObjc() {
func (mc *MachoContext) RewriteImportsTable(keepSymbols []string) {
allSymbols := mc.CollectBindSymbols()
fixups, fixupsOffset := mc.Fixups()
fixups, fixupsOffset := mc.Fixups()
importTable := fixups.ImportsOffset(uint32(fixupsOffset))
symbolTable := fixups.SymbolsOffset(uint32(fixupsOffset))
symbolTablePtr := symbolTable
importTable := fixups.ImportsOffset(uint32(fixupsOffset))
symbolTable := fixups.SymbolsOffset(uint32(fixupsOffset))
symbolTablePtr := symbolTable
// in removeBindSymbolsModern, we erase these pointers in file
// but because we keep a few symbols, we need to rewrite the pointers
// as well as rebuild the import table and strings table, and bind values
// in removeBindSymbolsModern, we erase these pointers in file
// but because we keep a few symbols, we need to rewrite the pointers
// as well as rebuild the import table and strings table, and bind values
keepCount := uint32(0)
for _, symbol := range keepSymbols {
name := symbol
lib := ""
parts := strings.Split(symbol, ",")
if len(parts) == 2 {
name = parts[0]
lib = parts[1]
}
keepCount := uint32(0)
for _, symbol := range keepSymbols {
name := symbol
lib := ""
parts := strings.Split(symbol, ",")
if len(parts) == 2 {
name = parts[0]
lib = parts[1]
}
symbolInfo := (*ImportSymbol)(nil)
for _, s := range allSymbols {
if s.Name() != name {
continue
}
if lib == "" || lib == s.Dylib() {
symbolInfo = s
break
}
}
if symbolInfo == nil {
// symbol not found
continue
}
symbolInfo := (*ImportSymbol)(nil)
for _, s := range allSymbols {
if s.Name() != name {
continue
}
if lib == "" || lib == s.Dylib() {
symbolInfo = s
break
}
}
if symbolInfo == nil {
// symbol not found
continue
}
fmt.Printf("keep symbol %s\n", name)
fmt.Printf("importTable at 0x%x; stringTable at 0x%x\n", importTable, symbolTablePtr)
fmt.Printf("bind value at 0x%x\n", symbolInfo.file_address)
fmt.Printf("keep symbol %s\n", name)
fmt.Printf("importTable at 0x%x; stringTable at 0x%x\n", importTable, symbolTablePtr)
fmt.Printf("bind value at 0x%x\n", symbolInfo.file_address)
// write string to string table
mc.file.WriteAt([]byte(name), int64(symbolTablePtr))
// fix bind value
rebaseOpcodeBytes := make([]byte, 8)
mc.file.ReadAt(rebaseOpcodeBytes, int64(symbolInfo.file_address))
rebaseOpcode := mc.byteorder.Uint64(rebaseOpcodeBytes)
bindOpcode := C.MakeBindFixupOpcodeFromRebase(C.uint64_t(rebaseOpcode), C.uint(keepCount))
// write string to string table
mc.file.WriteAt([]byte(name), int64(symbolTablePtr))
// fix bind value
rebaseOpcodeBytes := make([]byte, 8)
mc.file.ReadAt(rebaseOpcodeBytes, int64(symbolInfo.file_address))
rebaseOpcode := mc.byteorder.Uint64(rebaseOpcodeBytes)
bindOpcode := C.MakeBindFixupOpcodeFromRebase(C.uint64_t(rebaseOpcode), C.uint(keepCount))
{
v := make([]byte, 8)
mc.byteorder.PutUint64(v, uint64(bindOpcode))
mc.file.WriteAt(v, int64(symbolInfo.file_address))
}
// write import data to import table
entry := C.MakeImportTableEntry(C.uint(symbolInfo.LibOrdinal()), C.uint(symbolTablePtr - symbolTable))
{
v := make([]byte, 4)
mc.byteorder.PutUint32(v, uint32(entry))
mc.file.WriteAt(v, int64(importTable))
}
{
v := make([]byte, 8)
mc.byteorder.PutUint64(v, uint64(bindOpcode))
mc.file.WriteAt(v, int64(symbolInfo.file_address))
}
// write import data to import table
entry := C.MakeImportTableEntry(C.uint(symbolInfo.LibOrdinal()), C.uint(symbolTablePtr-symbolTable))
{
v := make([]byte, 4)
mc.byteorder.PutUint32(v, uint32(entry))
mc.file.WriteAt(v, int64(importTable))
}
keepCount += 1
importTable += 4
symbolTablePtr += uint32(len(name)) + 1
}
keepCount += 1
importTable += 4
symbolTablePtr += uint32(len(name)) + 1
}
fixups.imports_count = keepCount
fixups.imports_count = keepCount
mc.file.WriteAt(fixups.Serialize(mc), int64(mc.fixups.dataoff))
}
@ -685,128 +685,128 @@ func (mc *MachoContext) RemoveExportTrie() {
}
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
// 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 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()
// }
}
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
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)")
}
}
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
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))
// 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)
fmt.Printf("Add a new section with addr=0x%x, fileoffset=0x%x\n", section.addr, section.offset)
ret = &section
continue
ret = &section
continue
default:
buffer.Write(command.Serialize(mc))
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
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)
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)
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)
binary.Write(buffer, mc.byteorder, (symbol.SymbolIndex<<8)|symbol.SegmentIndex)
binary.Write(buffer, mc.byteorder, symbol.Offset)
}
}
instructions := buffer.Bytes()
instructions := buffer.Bytes()
buffer = new(bytes.Buffer)
buffer = new(bytes.Buffer)
for _, lib := range info.Symbols.Libs {
buffer.WriteString(lib)
buffer.WriteByte(0)
buffer.WriteString(lib)
buffer.WriteByte(0)
}
liblist := buffer.Bytes()
liblist := buffer.Bytes()
buffer = new(bytes.Buffer)
buffer = new(bytes.Buffer)
for _, symbol := range info.Symbols.Symbols {
buffer.WriteString(symbol)
buffer.WriteByte(0)
buffer.WriteString(symbol)
buffer.WriteByte(0)
}
symbollist := buffer.Bytes()
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)
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()))
}
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()))
}
}

View File

@ -38,11 +38,11 @@ func (h *Header) Cpusubtype() uint32 {
}
func (h *Header) IsExecutable() bool {
return h.filetype == 0x2
return h.filetype == 0x2
}
func (h *Header) IsDylib() bool {
return h.filetype == 0x6
return h.filetype == 0x6
}
func (h *Header) Serialize(mc *MachoContext) []byte {
@ -135,7 +135,7 @@ func (lcmd *LoadCmd) Cmdname() string {
return "LC_DATA_IN_CODE"
case LC_SYMTAB:
return "LC_SYMTAB"
case LC_BUILD_VERSION:
case LC_BUILD_VERSION:
return "LC_BUILD_VERSION"
case LC_UUID:
return "LC_UUID"
@ -425,11 +425,11 @@ type Fixups struct {
}
func (lcmd *Fixups) ImportsOffset(fixups_offset uint32) uint32 {
return lcmd.imports_offset + fixups_offset
return lcmd.imports_offset + fixups_offset
}
func (lcmd *Fixups) SymbolsOffset(fixups_offset uint32) uint32 {
return lcmd.symbols_offset + fixups_offset
return lcmd.symbols_offset + fixups_offset
}
func (lcmd *Fixups) Serialize(mc *MachoContext) []byte {

View File

@ -73,7 +73,7 @@ func (mc *MachoContext) Fixups() (*Fixups, uint64) {
size := mc.fixups.datasize
fixups := new(Fixups)
fixups.Deserialize(mc, mc.buf[start:start+size])
return fixups, uint64(mc.fixups.dataoff)
return fixups, uint64(mc.fixups.dataoff)
}
func (mc *MachoContext) WriteEnabled() bool {