go fmt
This commit is contained in:
parent
1c495989d4
commit
06bbde2612
@ -18,4 +18,3 @@ func (action *removeStrings) withFat(ff *FatFile) error {
|
|||||||
func NewRemoveStringsAction() *removeStrings {
|
func NewRemoveStringsAction() *removeStrings {
|
||||||
return &removeStrings{}
|
return &removeStrings{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ func Cli() {
|
|||||||
pc.remove_inits = true
|
pc.remove_inits = true
|
||||||
pc.remove_codesign = true
|
pc.remove_codesign = true
|
||||||
pc.remove_others = true
|
pc.remove_others = true
|
||||||
pc.remove_string = true
|
pc.remove_string = true
|
||||||
}
|
}
|
||||||
pc.remove_imports = arg.RemoveBindSymbols
|
pc.remove_imports = arg.RemoveBindSymbols
|
||||||
pc.remove_codesign = arg.RemoveCodeSign
|
pc.remove_codesign = arg.RemoveCodeSign
|
||||||
@ -125,7 +125,7 @@ func Cli() {
|
|||||||
pc.remove_others = arg.RemoveOthers
|
pc.remove_others = arg.RemoveOthers
|
||||||
pc.remove_exports = arg.RemoveExports
|
pc.remove_exports = arg.RemoveExports
|
||||||
pc.remove_symbol_table = arg.RemoveSymbolTable
|
pc.remove_symbol_table = arg.RemoveSymbolTable
|
||||||
pc.remove_string = arg.RemoveStrings
|
pc.remove_string = arg.RemoveStrings
|
||||||
pc.dylib_to_add = arg.Dylibs
|
pc.dylib_to_add = arg.Dylibs
|
||||||
pc.rpath_to_add = arg.Rpath
|
pc.rpath_to_add = arg.Rpath
|
||||||
pc.outfile = arg.Out
|
pc.outfile = arg.Out
|
||||||
@ -266,54 +266,54 @@ func bcell2header(bfile string, header string) {
|
|||||||
}
|
}
|
||||||
fmt.Fprintf(w, "};\n")
|
fmt.Fprintf(w, "};\n")
|
||||||
|
|
||||||
if info.Symbols != nil {
|
if info.Symbols != nil {
|
||||||
fmt.Fprintf(w, "__attribute__((section(\"__DATA,bshield\")))\n")
|
fmt.Fprintf(w, "__attribute__((section(\"__DATA,bshield\")))\n")
|
||||||
fmt.Fprintf(w, "char libs[] =\n")
|
fmt.Fprintf(w, "char libs[] =\n")
|
||||||
for _, lib := range info.Symbols.Libs {
|
for _, lib := range info.Symbols.Libs {
|
||||||
fmt.Fprintf(w, " \"%s\\0\"\n", lib)
|
fmt.Fprintf(w, " \"%s\\0\"\n", lib)
|
||||||
}
|
}
|
||||||
fmt.Fprintf(w, ";\n")
|
fmt.Fprintf(w, ";\n")
|
||||||
|
|
||||||
fmt.Fprintf(w, "__attribute__((section(\"__DATA,bshield\")))\n")
|
fmt.Fprintf(w, "__attribute__((section(\"__DATA,bshield\")))\n")
|
||||||
fmt.Fprintf(w, "char symbols[] =\n")
|
fmt.Fprintf(w, "char symbols[] =\n")
|
||||||
for _, symbol := range info.Symbols.Symbols {
|
for _, symbol := range info.Symbols.Symbols {
|
||||||
fmt.Fprintf(w, " \"%s\\0\"\n", symbol)
|
fmt.Fprintf(w, " \"%s\\0\"\n", symbol)
|
||||||
}
|
}
|
||||||
fmt.Fprintf(w, ";\n")
|
fmt.Fprintf(w, ";\n")
|
||||||
|
|
||||||
fmt.Fprintf(w, "// very compact symbol table,\n")
|
fmt.Fprintf(w, "// very compact symbol table,\n")
|
||||||
fmt.Fprintf(w, "// [lib idx/*4 bytes*/, nsymbol/*4 byte*/]\n")
|
fmt.Fprintf(w, "// [lib idx/*4 bytes*/, nsymbol/*4 byte*/]\n")
|
||||||
fmt.Fprintf(w, "// repeat nsymbol times [name offset/*3 bytes*/, segment idx/**/, offset /*4 btyes*/]\n")
|
fmt.Fprintf(w, "// repeat nsymbol times [name offset/*3 bytes*/, segment idx/**/, offset /*4 btyes*/]\n")
|
||||||
fmt.Fprintf(w, "// name offset is 3 bytes because we don't think we should have a table size > 2^(3 * 8)\n")
|
fmt.Fprintf(w, "// name offset is 3 bytes because we don't think we should have a table size > 2^(3 * 8)\n")
|
||||||
|
|
||||||
fmt.Fprintf(w, "__attribute__((section(\"__DATA,bshield\")))\n")
|
fmt.Fprintf(w, "__attribute__((section(\"__DATA,bshield\")))\n")
|
||||||
fmt.Fprintf(w, "uint32_t encoded_table[] = {\n")
|
fmt.Fprintf(w, "uint32_t encoded_table[] = {\n")
|
||||||
n_instructions := 0
|
n_instructions := 0
|
||||||
for i, table := range info.Symbols.Tables {
|
for i, table := range info.Symbols.Tables {
|
||||||
fmt.Fprintf(w, " // %s\n", info.Symbols.Libs[i])
|
fmt.Fprintf(w, " // %s\n", info.Symbols.Libs[i])
|
||||||
fmt.Fprintf(w, " %d/*lib offset*/,\n", table.LibIndex)
|
fmt.Fprintf(w, " %d/*lib offset*/,\n", table.LibIndex)
|
||||||
fmt.Fprintf(w, " %d/*nsymbols*/,\n", table.Nsymbols)
|
fmt.Fprintf(w, " %d/*nsymbols*/,\n", table.Nsymbols)
|
||||||
n_instructions += 2
|
n_instructions += 2
|
||||||
for _, symbol := range table.Symbols {
|
for _, symbol := range table.Symbols {
|
||||||
fmt.Fprintf(w, " %d, 0x%x,\n", (symbol.SymbolIndex<<8)|symbol.SegmentIndex, symbol.Offset)
|
fmt.Fprintf(w, " %d, 0x%x,\n", (symbol.SymbolIndex<<8)|symbol.SegmentIndex, symbol.Offset)
|
||||||
n_instructions += 2
|
n_instructions += 2
|
||||||
}
|
}
|
||||||
fmt.Fprintf(w, "\n")
|
fmt.Fprintf(w, "\n")
|
||||||
}
|
}
|
||||||
fmt.Fprintf(w, "};\n")
|
fmt.Fprintf(w, "};\n")
|
||||||
fmt.Fprintf(w, "uint32_t n_instructions = %d;\n", n_instructions)
|
fmt.Fprintf(w, "uint32_t n_instructions = %d;\n", n_instructions)
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(w, "__attribute__((section(\"__DATA,bshield\")))\n")
|
fmt.Fprintf(w, "__attribute__((section(\"__DATA,bshield\")))\n")
|
||||||
fmt.Fprintf(w, "char libs[] = {};\n")
|
fmt.Fprintf(w, "char libs[] = {};\n")
|
||||||
|
|
||||||
fmt.Fprintf(w, "__attribute__((section(\"__DATA,bshield\")))\n")
|
fmt.Fprintf(w, "__attribute__((section(\"__DATA,bshield\")))\n")
|
||||||
fmt.Fprintf(w, "char symbols[] = {};\n")
|
fmt.Fprintf(w, "char symbols[] = {};\n")
|
||||||
|
|
||||||
fmt.Fprintf(w, "__attribute__((section(\"__DATA,bshield\")))\n")
|
fmt.Fprintf(w, "__attribute__((section(\"__DATA,bshield\")))\n")
|
||||||
fmt.Fprintf(w, "uint32_t encoded_table[] = {};\n")
|
fmt.Fprintf(w, "uint32_t encoded_table[] = {};\n")
|
||||||
|
|
||||||
fmt.Fprintf(w, "uint32_t n_instructions = %d;\n", 0)
|
fmt.Fprintf(w, "uint32_t n_instructions = %d;\n", 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(w, "__attribute__((section(\"__DATA,bshield\")))\n")
|
fmt.Fprintf(w, "__attribute__((section(\"__DATA,bshield\")))\n")
|
||||||
fmt.Fprintf(w, "uint32_t special_selectors_idx[] = {\n")
|
fmt.Fprintf(w, "uint32_t special_selectors_idx[] = {\n")
|
||||||
|
@ -46,7 +46,7 @@ func (printer *InfoPrinter) Print() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
mc.CollectObjectiveCClasses()
|
mc.CollectObjectiveCClasses()
|
||||||
|
|
||||||
fmt.Println("======")
|
fmt.Println("======")
|
||||||
}
|
}
|
||||||
|
@ -107,9 +107,9 @@ func (pc *ProgramContext) Process(ofile OFile) {
|
|||||||
if pc.remove_exports {
|
if pc.remove_exports {
|
||||||
pc.AddAction(NewRemoveExportsAction())
|
pc.AddAction(NewRemoveExportsAction())
|
||||||
}
|
}
|
||||||
if pc.remove_string {
|
if pc.remove_string {
|
||||||
pc.AddAction(NewRemoveStringsAction())
|
pc.AddAction(NewRemoveStringsAction())
|
||||||
}
|
}
|
||||||
ExperimentalFeature("Remove Unnecessary Info", func() {
|
ExperimentalFeature("Remove Unnecessary Info", func() {
|
||||||
if pc.remove_others {
|
if pc.remove_others {
|
||||||
pc.AddAction(NewRemoveUnnecessaryInfoAction())
|
pc.AddAction(NewRemoveUnnecessaryInfoAction())
|
||||||
|
@ -27,8 +27,8 @@ type ImportSymbol struct {
|
|||||||
file_address uint64
|
file_address uint64
|
||||||
lib_ordinal uint32
|
lib_ordinal uint32
|
||||||
|
|
||||||
target uint32
|
target uint32
|
||||||
high8 uint32
|
high8 uint32
|
||||||
|
|
||||||
// push number
|
// push number
|
||||||
pnum uint32
|
pnum uint32
|
||||||
@ -131,9 +131,9 @@ func (mc *MachoContext) CollectBindSymbolsModern() []*ImportSymbol {
|
|||||||
pages := ([]C.ushort)(unsafe.Slice(fix.pages, fix.page_count))
|
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++ {
|
for page_i := 0; page_i < int(fix.page_count); page_i++ {
|
||||||
// loop through each page in segment, each page has size fix.page_size
|
// loop through each page in segment, each page has size fix.page_size
|
||||||
// the first item in page is offset through pages[page_i]
|
// the first item in page is offset through pages[page_i]
|
||||||
address := int64(fix.segment) + int64(page_i) * int64(fix.page_size) + int64(pages[page_i])
|
address := int64(fix.segment) + int64(page_i)*int64(fix.page_size) + int64(pages[page_i])
|
||||||
reader.Seek(address, io.SeekStart)
|
reader.Seek(address, io.SeekStart)
|
||||||
|
|
||||||
fmt.Printf(" page %d offset=%x\n", page_i, address)
|
fmt.Printf(" page %d offset=%x\n", page_i, address)
|
||||||
@ -147,9 +147,9 @@ func (mc *MachoContext) CollectBindSymbolsModern() []*ImportSymbol {
|
|||||||
var bind C.int
|
var bind C.int
|
||||||
var ret1 C.ulonglong
|
var ret1 C.ulonglong
|
||||||
var ret2 C.ulonglong
|
var ret2 C.ulonglong
|
||||||
if (fix.format != 2 && fix.format != 6) {
|
if fix.format != 2 && fix.format != 6 {
|
||||||
fmt.Printf("format is %d\n", fix.format)
|
fmt.Printf("format is %d\n", fix.format)
|
||||||
}
|
}
|
||||||
|
|
||||||
next := C.ParseFixValue(C.int(fix.format), C.ulonglong(v),
|
next := C.ParseFixValue(C.int(fix.format), C.ulonglong(v),
|
||||||
&bind, &ret1, &ret2)
|
&bind, &ret1, &ret2)
|
||||||
@ -175,8 +175,8 @@ func (mc *MachoContext) CollectBindSymbolsModern() []*ImportSymbol {
|
|||||||
} else {
|
} else {
|
||||||
fmt.Printf("// 0x%x rebase=%d target=0x%x high8=0x%x\n", address, bind, ret1, ret2)
|
fmt.Printf("// 0x%x rebase=%d target=0x%x high8=0x%x\n", address, bind, ret1, ret2)
|
||||||
sym.typ = "rebase"
|
sym.typ = "rebase"
|
||||||
sym.target = uint32(ret1)
|
sym.target = uint32(ret1)
|
||||||
sym.high8 = uint32(ret2)
|
sym.high8 = uint32(ret2)
|
||||||
sym.segment = uint32(mc.findSegmentIndexAt(uint64(address)))
|
sym.segment = uint32(mc.findSegmentIndexAt(uint64(address)))
|
||||||
sym.file_address = uint64(address)
|
sym.file_address = uint64(address)
|
||||||
sym.next = int(next)
|
sym.next = int(next)
|
||||||
@ -194,7 +194,7 @@ func (mc *MachoContext) CollectBindSymbolsModern() []*ImportSymbol {
|
|||||||
reader.Seek(0, io.SeekStart)
|
reader.Seek(0, io.SeekStart)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt.Printf("number of imports %d\n", len(syms))
|
fmt.Printf("number of imports %d\n", len(syms))
|
||||||
return syms
|
return syms
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,12 +5,12 @@ import (
|
|||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
@ -199,8 +199,8 @@ func (mc *MachoContext) RemoveUnnecessaryInfo() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (mc *MachoContext) RewriteHeader() {
|
func (mc *MachoContext) RewriteHeader() {
|
||||||
var offset uint64
|
var offset uint64
|
||||||
var start uint64
|
var start uint64
|
||||||
|
|
||||||
if mc.Is64bit() {
|
if mc.Is64bit() {
|
||||||
start = Header_size_64
|
start = Header_size_64
|
||||||
@ -208,17 +208,17 @@ func (mc *MachoContext) RewriteHeader() {
|
|||||||
start = Header_size
|
start = Header_size
|
||||||
}
|
}
|
||||||
|
|
||||||
mc.file.Seek(0, io.SeekStart)
|
mc.file.Seek(0, io.SeekStart)
|
||||||
|
|
||||||
offset = start
|
offset = start
|
||||||
for _, cmd := range mc.commands {
|
for _, cmd := range mc.commands {
|
||||||
nwrite, _ := mc.file.WriteAt(cmd.Serialize(mc), int64(offset))
|
nwrite, _ := mc.file.WriteAt(cmd.Serialize(mc), int64(offset))
|
||||||
offset += uint64(nwrite)
|
offset += uint64(nwrite)
|
||||||
}
|
}
|
||||||
|
|
||||||
mc.header.ncmds = uint32(len(mc.commands))
|
mc.header.ncmds = uint32(len(mc.commands))
|
||||||
mc.header.sizeofcmds = uint32(offset - start)
|
mc.header.sizeofcmds = uint32(offset - start)
|
||||||
mc.file.WriteAt(mc.header.Serialize(mc), 0)
|
mc.file.WriteAt(mc.header.Serialize(mc), 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mc *MachoContext) AddLoadCmd(lcmd LoadCommand) {
|
func (mc *MachoContext) AddLoadCmd(lcmd LoadCommand) {
|
||||||
@ -345,7 +345,7 @@ func (mc *MachoContext) RemoveBindSymbols() {
|
|||||||
value := C.MakeRebaseFixupOpcode(C.int(symbol.next), C.ulonglong(target), C.ulonglong(high8))
|
value := C.MakeRebaseFixupOpcode(C.int(symbol.next), C.ulonglong(target), C.ulonglong(high8))
|
||||||
v := make([]byte, 8)
|
v := make([]byte, 8)
|
||||||
mc.byteorder.PutUint64(v, uint64(value))
|
mc.byteorder.PutUint64(v, uint64(value))
|
||||||
fmt.Printf("change to rebase at %x\n", symbol.file_address)
|
fmt.Printf("change to rebase at %x\n", symbol.file_address)
|
||||||
mc.file.WriteAt(v, int64(symbol.file_address))
|
mc.file.WriteAt(v, int64(symbol.file_address))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -565,39 +565,39 @@ func (mc *MachoContext) RemoveExportTrie() {
|
|||||||
// this function breaks the file by adding another segment at
|
// this function breaks the file by adding another segment at
|
||||||
// the end of the file
|
// the end of the file
|
||||||
func (mc *MachoContext) RemoveStrings() {
|
func (mc *MachoContext) RemoveStrings() {
|
||||||
// add a new writable segment with a section
|
// add a new writable segment with a section
|
||||||
// loop over the instructions for adrp,add instructions
|
// loop over the instructions for adrp,add instructions
|
||||||
// if the access points to old cstring section, update
|
// if the access points to old cstring section, update
|
||||||
// with new values from the new segment and section.
|
// with new values from the new segment and section.
|
||||||
|
|
||||||
// data references, e.g., pointer to string, are compiled
|
// data references, e.g., pointer to string, are compiled
|
||||||
// into Rebase symbol, so actively check for rebase and
|
// into Rebase symbol, so actively check for rebase and
|
||||||
// rewrite the rebase value to new segment, section offset.
|
// rewrite the rebase value to new segment, section offset.
|
||||||
|
|
||||||
// save the strings into a file for recovery. should keep linear
|
// save the strings into a file for recovery. should keep linear
|
||||||
// format as before, or customized order, if want complex.
|
// format as before, or customized order, if want complex.
|
||||||
|
|
||||||
// __LINKEDIT must be at the end of the section for the binary
|
// __LINKEDIT must be at the end of the section for the binary
|
||||||
// to be able to resign, so we have to move __LINKEDIT down
|
// to be able to resign, so we have to move __LINKEDIT down
|
||||||
// by how much? by the page aligned size of the added segment
|
// by how much? by the page aligned size of the added segment
|
||||||
|
|
||||||
// but __LINKEDIT also contains data for link time data
|
// but __LINKEDIT also contains data for link time data
|
||||||
// (fixed ups and bytecode chain) so have to modify
|
// (fixed ups and bytecode chain) so have to modify
|
||||||
// their reference down too,
|
// their reference down too,
|
||||||
// symtab and dysymtab can be ignored, by removing them lmao
|
// symtab and dysymtab can be ignored, by removing them lmao
|
||||||
|
|
||||||
var cstring *Section64;
|
var cstring *Section64
|
||||||
for _, command := range mc.commands {
|
for _, command := range mc.commands {
|
||||||
switch command.(type) {
|
switch command.(type) {
|
||||||
case *Segment64:
|
case *Segment64:
|
||||||
var segment = command.(*Segment64)
|
var segment = command.(*Segment64)
|
||||||
if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__TEXT")) == 0 {
|
if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__TEXT")) == 0 {
|
||||||
for _, section := range segment.Sections() {
|
for _, section := range segment.Sections() {
|
||||||
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__cstring")) == 0 {
|
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__cstring")) == 0 {
|
||||||
cstring = section.(*Section64)
|
cstring = section.(*Section64)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -605,259 +605,257 @@ func (mc *MachoContext) RemoveStrings() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if cstring == nil {
|
if cstring == nil {
|
||||||
return
|
return
|
||||||
}
|
|
||||||
|
|
||||||
// get last segment, as the start point we extend from
|
|
||||||
// this assumes that the segment are ordered correctly,
|
|
||||||
// first segment offset is lower then second segment offset,
|
|
||||||
// and so on, yielding last segment is the last part of the
|
|
||||||
// binary. Our new segment add another part to the binary
|
|
||||||
// at the end.
|
|
||||||
|
|
||||||
// last segment is always the linkedits
|
|
||||||
last_segment := mc.Segments()[len(mc.Segments()) - 1]
|
|
||||||
fmt.Printf("last segment %v %s\n", last_segment, string(last_segment.SegName()))
|
|
||||||
|
|
||||||
// all data must be inside the segment (or in header)
|
|
||||||
|
|
||||||
// occupy the segment of linkedit and move linkedit down
|
|
||||||
|
|
||||||
segstart := last_segment.Vmaddr()
|
|
||||||
|
|
||||||
// segment must be page aligned, and the size is based on
|
|
||||||
// the section size
|
|
||||||
secstart := segstart
|
|
||||||
secsize := cstring.Size()
|
|
||||||
|
|
||||||
filestart := last_segment.Fileoff()
|
|
||||||
// align to page address, not sure if neccessary, because the
|
|
||||||
// loader can pick up from anywhere and load in memory (mmap)
|
|
||||||
if filestart % 0x4000 != 0 {
|
|
||||||
filestart += 0x4000 - (filestart % 0x4000)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("section size %x\n", secsize)
|
|
||||||
secsize_aligned := uint64(0)
|
|
||||||
if secsize % 0x4000 == 0 {
|
|
||||||
// very rare, but possible, it occupies whole pages
|
|
||||||
secsize_aligned = secsize
|
|
||||||
} else {
|
|
||||||
secsize_aligned = secsize + (0x4000 - (secsize % 0x4000))
|
|
||||||
}
|
|
||||||
filesize := secsize_aligned
|
|
||||||
|
|
||||||
segname := make([]byte, 16)
|
|
||||||
copy(segname, []byte("__BSHIELD"))
|
|
||||||
secname := make([]byte, 16)
|
|
||||||
copy(secname, []byte("__secrets"))
|
|
||||||
|
|
||||||
|
|
||||||
fmt.Printf("segstart %x\n", segstart)
|
|
||||||
fmt.Printf("file_start %x\n", filestart)
|
|
||||||
|
|
||||||
// size of the section and segment is defined by the total
|
|
||||||
// space for strings required
|
|
||||||
|
|
||||||
new_cstring_section := Section64{
|
|
||||||
sectname: secname,
|
|
||||||
segname: segname,
|
|
||||||
addr: secstart,
|
|
||||||
size: secsize,
|
|
||||||
offset: uint32(filestart),
|
|
||||||
align: 3, // idk, see AddSection
|
|
||||||
reloff: 0,
|
|
||||||
nreloc: 0,
|
|
||||||
flags: 0,
|
|
||||||
reserved1: 0,
|
|
||||||
reserved2: 0,
|
|
||||||
reserved3: 0,
|
|
||||||
}
|
|
||||||
string_segment := Segment64{
|
|
||||||
c: LoadCmd{cmd: LC_SEGMENT_64, cmdsize: 0},
|
|
||||||
segname: segname,
|
|
||||||
vmaddr: segstart,
|
|
||||||
vmsize: secsize_aligned,
|
|
||||||
fileoff: filestart,
|
|
||||||
filesize: filesize,
|
|
||||||
maxprot: 3, // read/write
|
|
||||||
initprot: 3, // read/write
|
|
||||||
nsects: 1,
|
|
||||||
flags: 0,
|
|
||||||
sections: []*Section64{&new_cstring_section},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// rewrite the header to be correct
|
// get last segment, as the start point we extend from
|
||||||
|
// this assumes that the segment are ordered correctly,
|
||||||
|
// first segment offset is lower then second segment offset,
|
||||||
|
// and so on, yielding last segment is the last part of the
|
||||||
|
// binary. Our new segment add another part to the binary
|
||||||
|
// at the end.
|
||||||
|
|
||||||
|
// last segment is always the linkedits
|
||||||
|
last_segment := mc.Segments()[len(mc.Segments())-1]
|
||||||
|
fmt.Printf("last segment %v %s\n", last_segment, string(last_segment.SegName()))
|
||||||
|
|
||||||
|
// all data must be inside the segment (or in header)
|
||||||
|
|
||||||
|
// occupy the segment of linkedit and move linkedit down
|
||||||
|
|
||||||
|
segstart := last_segment.Vmaddr()
|
||||||
|
|
||||||
|
// segment must be page aligned, and the size is based on
|
||||||
|
// the section size
|
||||||
|
secstart := segstart
|
||||||
|
secsize := cstring.Size()
|
||||||
|
|
||||||
|
filestart := last_segment.Fileoff()
|
||||||
|
// align to page address, not sure if neccessary, because the
|
||||||
|
// loader can pick up from anywhere and load in memory (mmap)
|
||||||
|
if filestart%0x4000 != 0 {
|
||||||
|
filestart += 0x4000 - (filestart % 0x4000)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("section size %x\n", secsize)
|
||||||
|
secsize_aligned := uint64(0)
|
||||||
|
if secsize%0x4000 == 0 {
|
||||||
|
// very rare, but possible, it occupies whole pages
|
||||||
|
secsize_aligned = secsize
|
||||||
|
} else {
|
||||||
|
secsize_aligned = secsize + (0x4000 - (secsize % 0x4000))
|
||||||
|
}
|
||||||
|
filesize := secsize_aligned
|
||||||
|
|
||||||
|
segname := make([]byte, 16)
|
||||||
|
copy(segname, []byte("__BSHIELD"))
|
||||||
|
secname := make([]byte, 16)
|
||||||
|
copy(secname, []byte("__secrets"))
|
||||||
|
|
||||||
|
fmt.Printf("segstart %x\n", segstart)
|
||||||
|
fmt.Printf("file_start %x\n", filestart)
|
||||||
|
|
||||||
|
// size of the section and segment is defined by the total
|
||||||
|
// space for strings required
|
||||||
|
|
||||||
|
new_cstring_section := Section64{
|
||||||
|
sectname: secname,
|
||||||
|
segname: segname,
|
||||||
|
addr: secstart,
|
||||||
|
size: secsize,
|
||||||
|
offset: uint32(filestart),
|
||||||
|
align: 3, // idk, see AddSection
|
||||||
|
reloff: 0,
|
||||||
|
nreloc: 0,
|
||||||
|
flags: 0,
|
||||||
|
reserved1: 0,
|
||||||
|
reserved2: 0,
|
||||||
|
reserved3: 0,
|
||||||
|
}
|
||||||
|
string_segment := Segment64{
|
||||||
|
c: LoadCmd{cmd: LC_SEGMENT_64, cmdsize: 0},
|
||||||
|
segname: segname,
|
||||||
|
vmaddr: segstart,
|
||||||
|
vmsize: secsize_aligned,
|
||||||
|
fileoff: filestart,
|
||||||
|
filesize: filesize,
|
||||||
|
maxprot: 3, // read/write
|
||||||
|
initprot: 3, // read/write
|
||||||
|
nsects: 1,
|
||||||
|
flags: 0,
|
||||||
|
sections: []*Section64{&new_cstring_section},
|
||||||
|
}
|
||||||
|
|
||||||
|
// rewrite the header to be correct
|
||||||
// mc.AddLoadCmd(&string_segment)
|
// mc.AddLoadCmd(&string_segment)
|
||||||
|
|
||||||
edit_segname := make([]byte, 16)
|
edit_segname := make([]byte, 16)
|
||||||
copy(edit_segname, []byte("__LINKEDIT"))
|
copy(edit_segname, []byte("__LINKEDIT"))
|
||||||
edit_segment := Segment64{
|
edit_segment := Segment64{
|
||||||
c: LoadCmd{cmd: LC_SEGMENT_64, cmdsize: 0},
|
c: LoadCmd{cmd: LC_SEGMENT_64, cmdsize: 0},
|
||||||
segname: edit_segname,
|
segname: edit_segname,
|
||||||
vmaddr: segstart + secsize_aligned, // move down
|
vmaddr: segstart + secsize_aligned, // move down
|
||||||
vmsize: last_segment.Vmsize(),
|
vmsize: last_segment.Vmsize(),
|
||||||
fileoff: filestart + filesize,
|
fileoff: filestart + filesize,
|
||||||
filesize: last_segment.Filesize(),
|
filesize: last_segment.Filesize(),
|
||||||
maxprot: 1, // read/write
|
maxprot: 1, // read/write
|
||||||
initprot: 1, // read/write
|
initprot: 1, // read/write
|
||||||
nsects: 0,
|
nsects: 0,
|
||||||
flags: 0,
|
flags: 0,
|
||||||
sections: []*Section64{},
|
sections: []*Section64{},
|
||||||
}
|
}
|
||||||
|
|
||||||
// modify the segment list
|
// modify the segment list
|
||||||
mc.segments[len(mc.segments) - 1] = &string_segment
|
mc.segments[len(mc.segments)-1] = &string_segment
|
||||||
mc.segments = append(mc.segments, &edit_segment)
|
mc.segments = append(mc.segments, &edit_segment)
|
||||||
|
|
||||||
// modify the command list
|
// modify the command list
|
||||||
for i, cmd := range mc.commands {
|
for i, cmd := range mc.commands {
|
||||||
if cmd.(*Segment64) == last_segment.(*Segment64) {
|
if cmd.(*Segment64) == last_segment.(*Segment64) {
|
||||||
mc.commands = append(mc.commands[:i + 1], mc.commands[i:]...)
|
mc.commands = append(mc.commands[:i+1], mc.commands[i:]...)
|
||||||
mc.commands[i] = &string_segment
|
mc.commands[i] = &string_segment
|
||||||
mc.commands[i + 1] = &edit_segment
|
mc.commands[i+1] = &edit_segment
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// modify offset in other commands to use new link edit offset
|
// modify offset in other commands to use new link edit offset
|
||||||
|
|
||||||
edit_offset_migrate := func (file_offset uint64) uint64 {
|
edit_offset_migrate := func(file_offset uint64) uint64 {
|
||||||
// they should keep the old offset,
|
// they should keep the old offset,
|
||||||
// but the base related to linkedit is modified
|
// but the base related to linkedit is modified
|
||||||
relative_offset := file_offset - last_segment.Fileoff()
|
relative_offset := file_offset - last_segment.Fileoff()
|
||||||
return relative_offset + edit_segment.Fileoff()
|
return relative_offset + edit_segment.Fileoff()
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, cmd := range mc.commands {
|
for _, cmd := range mc.commands {
|
||||||
if lcmd, ok := cmd.(*LinkEdit); ok {
|
if lcmd, ok := cmd.(*LinkEdit); ok {
|
||||||
lcmd.dataoff = uint32(edit_offset_migrate(uint64(lcmd.dataoff)))
|
lcmd.dataoff = uint32(edit_offset_migrate(uint64(lcmd.dataoff)))
|
||||||
}
|
}
|
||||||
if lcmd, ok := cmd.(*Symtab); ok {
|
if lcmd, ok := cmd.(*Symtab); ok {
|
||||||
lcmd.stroff = uint32(edit_offset_migrate(uint64(lcmd.stroff)))
|
lcmd.stroff = uint32(edit_offset_migrate(uint64(lcmd.stroff)))
|
||||||
lcmd.symoff = uint32(edit_offset_migrate(uint64(lcmd.symoff)))
|
lcmd.symoff = uint32(edit_offset_migrate(uint64(lcmd.symoff)))
|
||||||
}
|
}
|
||||||
if lcmd, ok := cmd.(*DySymtab); ok {
|
if lcmd, ok := cmd.(*DySymtab); ok {
|
||||||
lcmd.indirectsymoff = uint32(edit_offset_migrate(uint64(lcmd.indirectsymoff)))
|
lcmd.indirectsymoff = uint32(edit_offset_migrate(uint64(lcmd.indirectsymoff)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mc.RewriteHeader()
|
mc.RewriteHeader()
|
||||||
|
|
||||||
|
tmp_file := mc.file.Name()
|
||||||
|
|
||||||
tmp_file := mc.file.Name()
|
// has to reopen file as append
|
||||||
|
mc.file.Close()
|
||||||
|
mc.file, _ = os.OpenFile(tmp_file, os.O_RDWR|os.O_APPEND, 0644)
|
||||||
|
|
||||||
// has to reopen file as append
|
// make extra space
|
||||||
mc.file.Close()
|
expected_end := edit_segment.Fileoff() + edit_segment.Filesize()
|
||||||
mc.file, _ = os.OpenFile(tmp_file, os.O_RDWR | os.O_APPEND, 0644)
|
end, _ := mc.file.Seek(0, io.SeekEnd)
|
||||||
|
if end < int64(expected_end) {
|
||||||
|
mc.file.WriteAt(make([]byte, expected_end-uint64(end)), end)
|
||||||
|
}
|
||||||
|
|
||||||
// make extra space
|
// close and reopen as read/write, the buffer at the end is now empty
|
||||||
expected_end := edit_segment.Fileoff() + edit_segment.Filesize()
|
mc.file.Close()
|
||||||
end, _ := mc.file.Seek(0, io.SeekEnd)
|
|
||||||
if end < int64(expected_end) {
|
|
||||||
mc.file.WriteAt(make([]byte, expected_end - uint64(end)), end)
|
|
||||||
}
|
|
||||||
|
|
||||||
// close and reopen as read/write, the buffer at the end is now empty
|
|
||||||
mc.file.Close()
|
|
||||||
mc.file, _ = os.OpenFile(tmp_file, os.O_RDWR, 0644)
|
mc.file, _ = os.OpenFile(tmp_file, os.O_RDWR, 0644)
|
||||||
|
|
||||||
// peek at old link edit and move down
|
// peek at old link edit and move down
|
||||||
old_linkedit := make([]byte, last_segment.Filesize())
|
old_linkedit := make([]byte, last_segment.Filesize())
|
||||||
mc.file.ReadAt(old_linkedit, int64(last_segment.Fileoff()))
|
mc.file.ReadAt(old_linkedit, int64(last_segment.Fileoff()))
|
||||||
mc.file.WriteAt(old_linkedit, int64(edit_segment.Fileoff()))
|
mc.file.WriteAt(old_linkedit, int64(edit_segment.Fileoff()))
|
||||||
|
|
||||||
// prepare dummy bytes into new string segment, 0 for now
|
// prepare dummy bytes into new string segment, 0 for now
|
||||||
// this is a way to divert their effort, writing fake strings
|
// this is a way to divert their effort, writing fake strings
|
||||||
// will be written again at runtime
|
// will be written again at runtime
|
||||||
dummy := make([]byte, edit_segment.Fileoff() - string_segment.Fileoff())
|
dummy := make([]byte, edit_segment.Fileoff()-string_segment.Fileoff())
|
||||||
mc.file.ReadAt(dummy, int64(cstring.Offset()))
|
mc.file.ReadAt(dummy, int64(cstring.Offset()))
|
||||||
// copy(dummy, []byte("We R BShield\n"))
|
// copy(dummy, []byte("We R BShield\n"))
|
||||||
for i := 0; i < len(dummy); i++ {
|
for i := 0; i < len(dummy); i++ {
|
||||||
dummy[i] = dummy[i] ^ 0x4f
|
dummy[i] = dummy[i] ^ 0x4f
|
||||||
}
|
}
|
||||||
mc.file.WriteAt(dummy, int64(string_segment.Fileoff()))
|
mc.file.WriteAt(dummy, int64(string_segment.Fileoff()))
|
||||||
|
|
||||||
// TODO: erase old strings
|
// TODO: erase old strings
|
||||||
cstring_start := uint64(cstring.Offset())
|
cstring_start := uint64(cstring.Offset())
|
||||||
random := make([]byte, cstring.Size())
|
random := make([]byte, cstring.Size())
|
||||||
rand.Read(random)
|
rand.Read(random)
|
||||||
mc.file.WriteAt(random, int64(cstring_start))
|
mc.file.WriteAt(random, int64(cstring_start))
|
||||||
|
|
||||||
// re-read internal buffer
|
// re-read internal buffer
|
||||||
last, _ := mc.file.Seek(0, io.SeekEnd)
|
last, _ := mc.file.Seek(0, io.SeekEnd)
|
||||||
mc.buf = make([]byte, last)
|
mc.buf = make([]byte, last)
|
||||||
mc.file.Seek(0, io.SeekStart)
|
mc.file.Seek(0, io.SeekStart)
|
||||||
if _, err := io.ReadFull(mc.file, mc.buf); err != nil {
|
if _, err := io.ReadFull(mc.file, mc.buf); err != nil {
|
||||||
// panic?
|
// panic?
|
||||||
}
|
}
|
||||||
|
|
||||||
// loop over __TEXT,__text and find all occurances of (adrp, add)
|
// loop over __TEXT,__text and find all occurances of (adrp, add)
|
||||||
// edit the offset to points to new region
|
// edit the offset to points to new region
|
||||||
// because adrp sets the register to the address page at its address
|
// because adrp sets the register to the address page at its address
|
||||||
// (for page align 0x4000), e.g.,
|
// (for page align 0x4000), e.g.,
|
||||||
// `adrp x0` instruction at 0x100003f70, yields x0 = 0x100003000
|
// `adrp x0` instruction at 0x100003f70, yields x0 = 0x100003000
|
||||||
// technically, adrp can offset as far as 33-bit, roughly 4GB memory
|
// technically, adrp can offset as far as 33-bit, roughly 4GB memory
|
||||||
// so we should be very free, because very few program goes this far
|
// so we should be very free, because very few program goes this far
|
||||||
// but if this happens, god bless you
|
// but if this happens, god bless you
|
||||||
|
|
||||||
// encoding ADRP is actually hard hmmge?
|
// encoding ADRP is actually hard hmmge?
|
||||||
|
|
||||||
// this part uses file offsets for calculations
|
// this part uses file offsets for calculations
|
||||||
|
|
||||||
in_cstring := func (offset uint64) bool {
|
in_cstring := func(offset uint64) bool {
|
||||||
cstring_start := uint64(cstring.Offset())
|
cstring_start := uint64(cstring.Offset())
|
||||||
cstring_end := cstring_start + cstring.Size()
|
cstring_end := cstring_start + cstring.Size()
|
||||||
return (offset >= cstring_start) && (offset < cstring_end)
|
return (offset >= cstring_start) && (offset < cstring_end)
|
||||||
}
|
}
|
||||||
|
|
||||||
text := mc.segments[1]
|
text := mc.segments[1]
|
||||||
text_start := text.Fileoff()
|
text_start := text.Fileoff()
|
||||||
text_end := text_start + text.Filesize()
|
text_end := text_start + text.Filesize()
|
||||||
|
|
||||||
inst := make([]byte, 4)
|
inst := make([]byte, 4)
|
||||||
for addr := text_start; addr < text_end; addr = addr + 4 {
|
for addr := text_start; addr < text_end; addr = addr + 4 {
|
||||||
mc.file.ReadAt(inst, int64(addr))
|
mc.file.ReadAt(inst, int64(addr))
|
||||||
inst_adrp := binary.LittleEndian.Uint32(inst)
|
inst_adrp := binary.LittleEndian.Uint32(inst)
|
||||||
mc.file.ReadAt(inst, int64(addr + 4))
|
mc.file.ReadAt(inst, int64(addr+4))
|
||||||
inst_add := binary.LittleEndian.Uint32(inst)
|
inst_add := binary.LittleEndian.Uint32(inst)
|
||||||
|
|
||||||
if !(C.is_adrp(C.uint(inst_adrp)) != 0 && C.is_add(C.uint(inst_add)) != 0) {
|
if !(C.is_adrp(C.uint(inst_adrp)) != 0 && C.is_add(C.uint(inst_add)) != 0) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
base := (addr >> 12) << 12
|
base := (addr >> 12) << 12
|
||||||
|
|
||||||
// calculate the old string reference
|
// calculate the old string reference
|
||||||
ref_base := C.adrp_imm_get(C.uint(inst_adrp))
|
ref_base := C.adrp_imm_get(C.uint(inst_adrp))
|
||||||
ref_offset := C.add_imm_get(C.uint(inst_add))
|
ref_offset := C.add_imm_get(C.uint(inst_add))
|
||||||
ref := base + uint64(ref_base + ref_offset)
|
ref := base + uint64(ref_base+ref_offset)
|
||||||
|
|
||||||
if (!in_cstring(ref)) {
|
if !in_cstring(ref) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
oldstr := uint64(ref)
|
oldstr := uint64(ref)
|
||||||
oldstr_relative := oldstr - uint64(cstring.Offset())
|
oldstr_relative := oldstr - uint64(cstring.Offset())
|
||||||
|
|
||||||
// find the new string address
|
// find the new string address
|
||||||
// using oldstr relative address to cstring section
|
// using oldstr relative address to cstring section
|
||||||
newstr := uint64(new_cstring_section.Offset()) + oldstr_relative
|
newstr := uint64(new_cstring_section.Offset()) + oldstr_relative
|
||||||
newstr_base := (newstr >> 12) << 12 // to calculate new offset in adrp
|
newstr_base := (newstr >> 12) << 12 // to calculate new offset in adrp
|
||||||
newstr_offset := newstr - newstr_base // to calculate new offset in add
|
newstr_offset := newstr - newstr_base // to calculate new offset in add
|
||||||
|
|
||||||
C.adrp_imm_set((*C.uint32_t)(unsafe.Pointer(&inst_adrp)), C.uint(newstr_base - base))
|
C.adrp_imm_set((*C.uint32_t)(unsafe.Pointer(&inst_adrp)), C.uint(newstr_base-base))
|
||||||
C.add_imm_set((*C.uint32_t)(unsafe.Pointer(&inst_add)), C.uint(newstr_offset))
|
C.add_imm_set((*C.uint32_t)(unsafe.Pointer(&inst_add)), C.uint(newstr_offset))
|
||||||
|
|
||||||
binary.LittleEndian.PutUint32(inst, inst_adrp)
|
binary.LittleEndian.PutUint32(inst, inst_adrp)
|
||||||
mc.file.WriteAt(inst, int64(addr))
|
mc.file.WriteAt(inst, int64(addr))
|
||||||
binary.LittleEndian.PutUint32(inst, inst_add)
|
binary.LittleEndian.PutUint32(inst, inst_add)
|
||||||
mc.file.WriteAt(inst, int64(addr + 4))
|
mc.file.WriteAt(inst, int64(addr+4))
|
||||||
}
|
}
|
||||||
|
|
||||||
// modify the rebase table (for both opcode and fixups chain versions)
|
// modify the rebase table (for both opcode and fixups chain versions)
|
||||||
// this is for pointer references
|
// this is for pointer references
|
||||||
|
|
||||||
isModernSymbol := mc.dyldinfo == nil
|
isModernSymbol := mc.dyldinfo == nil
|
||||||
isLegacySymbol := !isModernSymbol
|
isLegacySymbol := !isModernSymbol
|
||||||
@ -866,21 +864,21 @@ func (mc *MachoContext) RemoveStrings() {
|
|||||||
} else {
|
} else {
|
||||||
// (high8 << 56 | target) - mach_header
|
// (high8 << 56 | target) - mach_header
|
||||||
|
|
||||||
ref := uint64(symbol.high8 << 56 | symbol.target)
|
ref := uint64(symbol.high8<<56 | symbol.target)
|
||||||
if (!in_cstring(ref)) {
|
if !in_cstring(ref) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
oldstr := ref
|
oldstr := ref
|
||||||
oldstr_relative := oldstr - uint64(cstring.Offset())
|
oldstr_relative := oldstr - uint64(cstring.Offset())
|
||||||
newstr := uint64(new_cstring_section.Offset()) + oldstr_relative
|
newstr := uint64(new_cstring_section.Offset()) + oldstr_relative
|
||||||
|
|
||||||
target := newstr & 0x00FFFFFFFFFFFFFF
|
target := newstr & 0x00FFFFFFFFFFFFFF
|
||||||
high8 := newstr >> 56
|
high8 := newstr >> 56
|
||||||
value := C.MakeRebaseFixupOpcode(C.int(symbol.next), C.ulonglong(target), C.ulonglong(high8))
|
value := C.MakeRebaseFixupOpcode(C.int(symbol.next), C.ulonglong(target), C.ulonglong(high8))
|
||||||
v := make([]byte, 8)
|
v := make([]byte, 8)
|
||||||
mc.byteorder.PutUint64(v, uint64(value))
|
mc.byteorder.PutUint64(v, uint64(value))
|
||||||
fmt.Printf("string rebase change at %x\n", symbol.file_address)
|
fmt.Printf("string rebase change at %x\n", symbol.file_address)
|
||||||
mc.file.WriteAt(v, int64(symbol.file_address))
|
mc.file.WriteAt(v, int64(symbol.file_address))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
. "ios-wrapper/pkg/ios"
|
. "ios-wrapper/pkg/ios"
|
||||||
)
|
)
|
||||||
@ -15,10 +15,10 @@ import (
|
|||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
func (mc *MachoContext) CollectObjectiveCClasses() {
|
func (mc *MachoContext) CollectObjectiveCClasses() {
|
||||||
var objc_const *bytes.Reader
|
var objc_const *bytes.Reader
|
||||||
var objc_const_start uint64
|
var objc_const_start uint64
|
||||||
var objc_const_end uint64
|
var objc_const_end uint64
|
||||||
// var objc_methname []byte
|
// var objc_methname []byte
|
||||||
|
|
||||||
for _, cmd := range mc.commands {
|
for _, cmd := range mc.commands {
|
||||||
if cmd.Cmd() == LC_MAIN {
|
if cmd.Cmd() == LC_MAIN {
|
||||||
@ -29,18 +29,18 @@ func (mc *MachoContext) CollectObjectiveCClasses() {
|
|||||||
}
|
}
|
||||||
var segment = cmd.(*Segment64)
|
var segment = cmd.(*Segment64)
|
||||||
|
|
||||||
// we assume the binary comes in perfect ordering, that is as laid out below
|
// we assume the binary comes in perfect ordering, that is as laid out below
|
||||||
|
|
||||||
if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__TEXT")) == 0 {
|
if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__TEXT")) == 0 {
|
||||||
for _, section := range segment.Sections() {
|
for _, section := range segment.Sections() {
|
||||||
buffer := make([]byte, section.Size())
|
buffer := make([]byte, section.Size())
|
||||||
mc.file.ReadAt(buffer, int64(section.Offset()))
|
mc.file.ReadAt(buffer, int64(section.Offset()))
|
||||||
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_stubs")) == 0 {
|
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_stubs")) == 0 {
|
||||||
}
|
}
|
||||||
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_methlist")) == 0 {
|
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_methlist")) == 0 {
|
||||||
}
|
}
|
||||||
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_methname")) == 0 {
|
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_methname")) == 0 {
|
||||||
// objc_methname := buffer
|
// objc_methname := buffer
|
||||||
}
|
}
|
||||||
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_classname")) == 0 {
|
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_classname")) == 0 {
|
||||||
}
|
}
|
||||||
@ -50,8 +50,8 @@ func (mc *MachoContext) CollectObjectiveCClasses() {
|
|||||||
}
|
}
|
||||||
if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__DATA_CONST")) == 0 {
|
if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__DATA_CONST")) == 0 {
|
||||||
for _, section := range segment.Sections() {
|
for _, section := range segment.Sections() {
|
||||||
buffer := make([]byte, section.Size())
|
buffer := make([]byte, section.Size())
|
||||||
mc.file.ReadAt(buffer, int64(section.Offset()))
|
mc.file.ReadAt(buffer, int64(section.Offset()))
|
||||||
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_classlist")) == 0 {
|
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_classlist")) == 0 {
|
||||||
}
|
}
|
||||||
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_nlclslist")) == 0 {
|
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_nlclslist")) == 0 {
|
||||||
@ -59,16 +59,16 @@ func (mc *MachoContext) CollectObjectiveCClasses() {
|
|||||||
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_imageinfo")) == 0 {
|
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_imageinfo")) == 0 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__DATA")) == 0 {
|
if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__DATA")) == 0 {
|
||||||
for _, section := range segment.Sections() {
|
for _, section := range segment.Sections() {
|
||||||
buffer := make([]byte, section.Size())
|
buffer := make([]byte, section.Size())
|
||||||
mc.file.ReadAt(buffer, int64(section.Offset()))
|
mc.file.ReadAt(buffer, int64(section.Offset()))
|
||||||
reader := bytes.NewReader(buffer)
|
reader := bytes.NewReader(buffer)
|
||||||
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_const")) == 0 {
|
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_const")) == 0 {
|
||||||
objc_const = reader
|
objc_const = reader
|
||||||
objc_const_start = uint64(section.Offset())
|
objc_const_start = uint64(section.Offset())
|
||||||
objc_const_end = objc_const_start + section.Size()
|
objc_const_end = objc_const_start + section.Size()
|
||||||
}
|
}
|
||||||
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_selrefs")) == 0 {
|
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_selrefs")) == 0 {
|
||||||
}
|
}
|
||||||
@ -77,90 +77,89 @@ func (mc *MachoContext) CollectObjectiveCClasses() {
|
|||||||
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_superrefs")) == 0 {
|
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_superrefs")) == 0 {
|
||||||
}
|
}
|
||||||
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_data")) == 0 {
|
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_data")) == 0 {
|
||||||
// this section contains a series of class_t
|
// this section contains a series of class_t
|
||||||
// struct _class_t {
|
// struct _class_t {
|
||||||
// struct _class_t *isa;
|
// struct _class_t *isa;
|
||||||
// struct _class_t * const superclass;
|
// struct _class_t * const superclass;
|
||||||
// void *cache;
|
// void *cache;
|
||||||
// IMP *vtable;
|
// IMP *vtable;
|
||||||
// struct class_ro_t *ro;
|
// struct class_ro_t *ro;
|
||||||
// };
|
// };
|
||||||
|
|
||||||
for i := uint64(0); i < (section.Size() / uint64(mc.pointersize * 5)); i++ {
|
for i := uint64(0); i < (section.Size() / uint64(mc.pointersize*5)); i++ {
|
||||||
var isa uint64
|
var isa uint64
|
||||||
var superclass uint64
|
var superclass uint64
|
||||||
var cache uint64
|
var cache uint64
|
||||||
var vtable uint64
|
var vtable uint64
|
||||||
var ro uint64
|
var ro uint64
|
||||||
binary.Read(reader, mc.byteorder, &isa)
|
binary.Read(reader, mc.byteorder, &isa)
|
||||||
binary.Read(reader, mc.byteorder, &superclass)
|
binary.Read(reader, mc.byteorder, &superclass)
|
||||||
binary.Read(reader, mc.byteorder, &cache)
|
binary.Read(reader, mc.byteorder, &cache)
|
||||||
binary.Read(reader, mc.byteorder, &vtable)
|
binary.Read(reader, mc.byteorder, &vtable)
|
||||||
binary.Read(reader, mc.byteorder, &ro)
|
binary.Read(reader, mc.byteorder, &ro)
|
||||||
|
|
||||||
|
fmt.Printf("at=0x%x\n", section.Offset()+uint32(i)*mc.pointersize*5)
|
||||||
|
fmt.Printf("isa=0x%x superclass=0x%x\n", isa, superclass)
|
||||||
|
fmt.Printf("cache=0x%x vtable=0x%x\n", cache, vtable)
|
||||||
|
fmt.Printf("ro=0x%x\n", ro)
|
||||||
|
|
||||||
fmt.Printf("at=0x%x\n", section.Offset() + uint32(i) * mc.pointersize * 5)
|
var bind int
|
||||||
fmt.Printf("isa=0x%x superclass=0x%x\n", isa, superclass)
|
var ret1 uint64
|
||||||
fmt.Printf("cache=0x%x vtable=0x%x\n", cache, vtable)
|
var ret2 uint64
|
||||||
fmt.Printf("ro=0x%x\n", ro)
|
C.ParseFixValue(C.int(2), C.uint64_t(ro),
|
||||||
|
(*C.int)(unsafe.Pointer(&bind)),
|
||||||
|
(*C.uint64_t)(unsafe.Pointer(&ret1)),
|
||||||
|
(*C.uint64_t)(unsafe.Pointer(&ret2)),
|
||||||
|
)
|
||||||
|
|
||||||
var bind int
|
// is rebase, because ro points to objc_const
|
||||||
var ret1 uint64
|
// and address is in range
|
||||||
var ret2 uint64
|
if bind != 1 && ret1 >= objc_const_start && ret1 < objc_const_end {
|
||||||
C.ParseFixValue(C.int(2), C.uint64_t(ro),
|
offset := ret1 - objc_const_start
|
||||||
(*C.int)(unsafe.Pointer(&bind)),
|
objc_const.Seek(int64(offset), 0)
|
||||||
(*C.uint64_t)(unsafe.Pointer(&ret1)),
|
|
||||||
(*C.uint64_t)(unsafe.Pointer(&ret2)),
|
|
||||||
)
|
|
||||||
|
|
||||||
// is rebase, because ro points to objc_const
|
// struct _class_ro_t {
|
||||||
// and address is in range
|
// uint32_t const flags;
|
||||||
if (bind != 1 && ret1 >= objc_const_start && ret1 < objc_const_end) {
|
// uint32_t const instanceStart;
|
||||||
offset := ret1 - objc_const_start
|
// uint32_t const instanceSize;
|
||||||
objc_const.Seek(int64(offset), 0)
|
// uint32_t const reserved; // only when building for 64bit targets
|
||||||
|
// const uint8_t * const ivarLayout;
|
||||||
|
// const char *const name;
|
||||||
|
// const struct _method_list_t * const baseMethods;
|
||||||
|
// const struct _protocol_list_t *const baseProtocols;
|
||||||
|
// const struct _ivar_list_t *const ivars;
|
||||||
|
// const uint8_t * const weakIvarLayout;
|
||||||
|
// const struct _prop_list_t * const properties;
|
||||||
|
// };
|
||||||
|
|
||||||
// struct _class_ro_t {
|
var tmp uint32
|
||||||
// uint32_t const flags;
|
var ivarLayout uint64 // ptr
|
||||||
// uint32_t const instanceStart;
|
var name uint64 // ptr
|
||||||
// uint32_t const instanceSize;
|
var baseMethods uint64 // ptr
|
||||||
// uint32_t const reserved; // only when building for 64bit targets
|
var baseProtocols uint64 // ptr
|
||||||
// const uint8_t * const ivarLayout;
|
var ivars uint64 // ptr
|
||||||
// const char *const name;
|
var weakIvarLayout uint64 // ptr
|
||||||
// const struct _method_list_t * const baseMethods;
|
var properties uint64 // ptr
|
||||||
// const struct _protocol_list_t *const baseProtocols;
|
binary.Read(objc_const, mc.byteorder, &tmp)
|
||||||
// const struct _ivar_list_t *const ivars;
|
binary.Read(objc_const, mc.byteorder, &tmp)
|
||||||
// const uint8_t * const weakIvarLayout;
|
binary.Read(objc_const, mc.byteorder, &tmp)
|
||||||
// const struct _prop_list_t * const properties;
|
binary.Read(objc_const, mc.byteorder, &tmp)
|
||||||
// };
|
binary.Read(objc_const, mc.byteorder, &ivarLayout)
|
||||||
|
binary.Read(objc_const, mc.byteorder, &name)
|
||||||
|
binary.Read(objc_const, mc.byteorder, &baseMethods)
|
||||||
|
binary.Read(objc_const, mc.byteorder, &baseProtocols)
|
||||||
|
binary.Read(objc_const, mc.byteorder, &ivars)
|
||||||
|
binary.Read(objc_const, mc.byteorder, &weakIvarLayout)
|
||||||
|
binary.Read(objc_const, mc.byteorder, &properties)
|
||||||
|
|
||||||
var tmp uint32
|
fmt.Printf("method list: %x\n", baseMethods)
|
||||||
var ivarLayout uint64 // ptr
|
}
|
||||||
var name uint64 // ptr
|
fmt.Printf("========\n")
|
||||||
var baseMethods uint64 // ptr
|
}
|
||||||
var baseProtocols uint64 // ptr
|
|
||||||
var ivars uint64 // ptr
|
|
||||||
var weakIvarLayout uint64 // ptr
|
|
||||||
var properties uint64 // ptr
|
|
||||||
binary.Read(objc_const, mc.byteorder, &tmp)
|
|
||||||
binary.Read(objc_const, mc.byteorder, &tmp)
|
|
||||||
binary.Read(objc_const, mc.byteorder, &tmp)
|
|
||||||
binary.Read(objc_const, mc.byteorder, &tmp)
|
|
||||||
binary.Read(objc_const, mc.byteorder, &ivarLayout)
|
|
||||||
binary.Read(objc_const, mc.byteorder, &name)
|
|
||||||
binary.Read(objc_const, mc.byteorder, &baseMethods)
|
|
||||||
binary.Read(objc_const, mc.byteorder, &baseProtocols)
|
|
||||||
binary.Read(objc_const, mc.byteorder, &ivars)
|
|
||||||
binary.Read(objc_const, mc.byteorder, &weakIvarLayout)
|
|
||||||
binary.Read(objc_const, mc.byteorder, &properties)
|
|
||||||
|
|
||||||
fmt.Printf("method list: %x\n", baseMethods)
|
|
||||||
}
|
|
||||||
fmt.Printf("========\n")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -482,7 +481,7 @@ func (mc *MachoContext) ReworkForObjc() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
encode_movz((data_end - text_start) + (shellcode_size - len(shellcode_start))+3)
|
encode_movz((data_end - text_start) + (shellcode_size - len(shellcode_start)) + 3)
|
||||||
|
|
||||||
shellcode_offset = text_start - shellcode_size
|
shellcode_offset = text_start - shellcode_size
|
||||||
shellcode_bytes := append(shellcode_start, offset...)
|
shellcode_bytes := append(shellcode_start, offset...)
|
||||||
@ -519,7 +518,7 @@ func (mc *MachoContext) ReworkForObjc() {
|
|||||||
offset += 4
|
offset += 4
|
||||||
}
|
}
|
||||||
|
|
||||||
// make __TEXT writable lol
|
// make __TEXT writable lol
|
||||||
mc.file.Seek(0, 0)
|
mc.file.Seek(0, 0)
|
||||||
mc.file.WriteAt([]byte{0x7}, 0xa0)
|
mc.file.WriteAt([]byte{0x7}, 0xa0)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user