Compare commits
53 Commits
0.1.0-alph
...
benchmark
Author | SHA1 | Date | |
---|---|---|---|
465aed7ba1 | |||
998d5844e7 | |||
78a8ca45d5 | |||
3e99eff22d | |||
8be97742c9 | |||
06525b8a5e | |||
57b0ae26a7 | |||
f795e9b99d | |||
792316f4ea | |||
62fa58f039 | |||
62daeb1c52 | |||
37c2f93383 | |||
901f1ed819 | |||
41144ff0dc | |||
9a8ab15d88 | |||
a8ffae5202 | |||
9ec2a301b4 | |||
a68bbf2b8f | |||
07f361d8ac | |||
263596b1a1 | |||
7a6a41b4d8 | |||
0a070941b1 | |||
4dea12dd9e | |||
011abfd8db | |||
67157c91ef | |||
26d002cdb1 | |||
c805fc56b3 | |||
1b3eb467a7 | |||
54f61f36ab | |||
f88861a87e | |||
4016abf40d | |||
4ee62a2d93 | |||
6815ea6556 | |||
557eed0254 | |||
eccd0bf845 | |||
ed2f09348e | |||
2eede8f9b2 | |||
b8d8343835 | |||
e15d1e8d6f | |||
a2f9ca82e7 | |||
693c2b6c95 | |||
7eb43a35fb | |||
f5144fec4f | |||
ebd52d9acb | |||
3aaa85520e | |||
ed793b1df6 | |||
9f54720e7b | |||
fdccdca8a0 | |||
e2c75bf718 | |||
a257286d2e | |||
91e5b1f6b3 | |||
887c53ed44 | |||
88bb0aa09d |
6
.gitmodules
vendored
Normal file
6
.gitmodules
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
[submodule "apple/dyld"]
|
||||
path = apple/dyld
|
||||
url = git@github.com:apple-oss-distributions/dyld.git
|
||||
[submodule "apple/objc4"]
|
||||
path = apple/objc4
|
||||
url = git@github.com:apple-oss-distributions/objc4.git
|
1
apple/dyld
Submodule
1
apple/dyld
Submodule
Submodule apple/dyld added at c8a445f88f
1
apple/objc4
Submodule
1
apple/objc4
Submodule
Submodule apple/objc4 added at 689525d556
29
docs/links.md
Normal file
29
docs/links.md
Normal file
@ -0,0 +1,29 @@
|
||||
## Direct References in Apple
|
||||
|
||||
[dyld_info](https://github.com/apple-oss-distributions/dyld/blob/main/other-tools/dyld_info.cpp)
|
||||
|
||||
[macho layout](https://github.com/apple-oss-distributions/dyld/blob/main/common/MachOLayout.cpp#L714)
|
||||
|
||||
[mod init func](https://github.com/apple-oss-distributions/dyld/blob/c8a445f88f9fc1713db34674e79b00e30723e79d/dyld/Loader.cpp#L1879)
|
||||
|
||||
[dlsym](https://github.com/apple-oss-distributions/dyld/blob/c8a445f88f9fc1713db34674e79b00e30723e79d/common/MachOLoaded.cpp#L263)
|
||||
|
||||
[dyld_all_image_infos](https://opensource.apple.com/source/dyld/dyld-195.6/include/mach-o/dyld_images.h.auto.html)
|
||||
|
||||
[dyld env vars](https://stackoverflow.com/questions/51504439/what-environment-variables-control-dyld)
|
||||
|
||||
## Blogposts
|
||||
|
||||
[Basic Mach-O (Old)](https://www.m4b.io/reverse/engineering/mach/binaries/2015/03/29/mach-binaries.html)
|
||||
|
||||
[Basic Mach-O memory loader](https://blog.xpnsec.com/building-a-mach-o-memory-loader-part-1/)
|
||||
|
||||
[My Mach-O posts](https://blog.efiens.com/post/luibo/osx/)
|
||||
|
||||
## Tools
|
||||
|
||||
[llios](https://github.com/qyang-nj/llios)
|
||||
|
||||
[fishhook](https://github.com/facebook/fishhook/blob/main/fishhook.c)
|
||||
|
||||
[blacktop/go-macho](https://github.com/blacktop/go-macho)
|
@ -9,3 +9,6 @@ build-linux:
|
||||
|
||||
module:
|
||||
go get -u google.golang.org/protobuf/cmd/protoc-gen-go
|
||||
|
||||
format:
|
||||
go fmt ./...
|
||||
|
@ -5,10 +5,11 @@ go 1.17
|
||||
require (
|
||||
github.com/alecthomas/kong v0.2.16
|
||||
github.com/sirupsen/logrus v1.8.0
|
||||
google.golang.org/protobuf v1.26.0
|
||||
google.golang.org/protobuf v1.31.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/magefile/mage v1.10.0 // indirect
|
||||
github.com/pkg/errors v0.8.1 // indirect
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 // indirect
|
||||
|
@ -3,6 +3,8 @@ github.com/alecthomas/kong v0.2.16/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QL
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/magefile/mage v1.10.0 h1:3HiXzCUY12kh9bIuyXShaVe529fJfyqoVM42o/uom2g=
|
||||
@ -22,3 +24,5 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
|
@ -7,7 +7,7 @@ import (
|
||||
type removeClassicSymbol struct{}
|
||||
|
||||
func (action *removeClassicSymbol) withMacho(mf *MachoFile) error {
|
||||
mf.Context().RemoveClassicSymbol()
|
||||
mf.Context().RemoveSymbolTable()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
20
macho-go/internal/wrapper/action/remove_exports.go
Normal file
20
macho-go/internal/wrapper/action/remove_exports.go
Normal file
@ -0,0 +1,20 @@
|
||||
package action
|
||||
|
||||
import (
|
||||
. "ios-wrapper/internal/wrapper/ofile"
|
||||
)
|
||||
|
||||
type removeExports struct{}
|
||||
|
||||
func (action *removeExports) withMacho(mf *MachoFile) error {
|
||||
mf.Context().RemoveExportTrie()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (action *removeExports) withFat(ff *FatFile) error {
|
||||
return defaultWithFat(action, ff)
|
||||
}
|
||||
|
||||
func NewRemoveExportsAction() *removeExports {
|
||||
return &removeExports{}
|
||||
}
|
@ -8,8 +8,6 @@ type removeImports struct{}
|
||||
|
||||
func (action *removeImports) withMacho(mf *MachoFile) error {
|
||||
mf.Context().RemoveBindSymbols()
|
||||
mf.Context().RemoveSymbolTable()
|
||||
mf.Context().RemoveExportTrie()
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -20,4 +18,3 @@ func (action *removeImports) withFat(ff *FatFile) error {
|
||||
func NewRemoveImportsAction() *removeImports {
|
||||
return &removeImports{}
|
||||
}
|
||||
|
||||
|
25
macho-go/internal/wrapper/action/rewrite_imports.go
Normal file
25
macho-go/internal/wrapper/action/rewrite_imports.go
Normal file
@ -0,0 +1,25 @@
|
||||
package action
|
||||
|
||||
import (
|
||||
. "ios-wrapper/internal/wrapper/ofile"
|
||||
)
|
||||
|
||||
type rewriteImports struct {
|
||||
symbols []string
|
||||
}
|
||||
|
||||
func (action *rewriteImports) withMacho(mf *MachoFile) error {
|
||||
mc := mf.Context()
|
||||
mc.RewriteImportsTable(action.symbols)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (action *rewriteImports) withFat(ff *FatFile) error {
|
||||
return defaultWithFat(action, ff)
|
||||
}
|
||||
|
||||
func NewRewriteImportsWithKeepSymbolsAction(symbols []string) *rewriteImports {
|
||||
return &rewriteImports{
|
||||
symbols,
|
||||
}
|
||||
}
|
162
macho-go/internal/wrapper/action/save_imports.go
Normal file
162
macho-go/internal/wrapper/action/save_imports.go
Normal file
@ -0,0 +1,162 @@
|
||||
package action
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
// log "github.com/sirupsen/logrus"
|
||||
|
||||
. "ios-wrapper/internal/wrapper/ofile"
|
||||
"ios-wrapper/pkg/protomodel"
|
||||
)
|
||||
|
||||
type saveImports struct {
|
||||
keepSymbols []string
|
||||
}
|
||||
|
||||
func (action *saveImports) withMacho(mf *MachoFile) error {
|
||||
action.saveToInfo(mf)
|
||||
mc := mf.Context()
|
||||
if mc.Header().IsDylib() {
|
||||
mc.WriteInfoToData(mf.Info())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (action *saveImports) saveToInfo(mf *MachoFile) error {
|
||||
// calculateHash := func(name string) uint32 {
|
||||
// var h uint32 = 0x811c9dc5
|
||||
// for _, s := range name {
|
||||
// h ^= uint32(s)
|
||||
// h *= 0x01000193
|
||||
// }
|
||||
// return h
|
||||
// }
|
||||
|
||||
mc := mf.Context()
|
||||
// symbols_storage := []*protomodel.MachoInfo_AllImportedSymbols{}
|
||||
symbols_raw := mc.CollectBindSymbols()
|
||||
sort.Slice(symbols_raw, func(i, j int) bool {
|
||||
orderedByLibrary := symbols_raw[i].Dylib() < symbols_raw[j].Dylib()
|
||||
if symbols_raw[i].Dylib() == symbols_raw[j].Dylib() {
|
||||
orderedBySymbol := symbols_raw[i].Name() < symbols_raw[j].Name()
|
||||
return orderedBySymbol
|
||||
}
|
||||
return orderedByLibrary
|
||||
})
|
||||
|
||||
libs := []string{}
|
||||
symbols := []string{}
|
||||
tables := []*protomodel.MachoInfo_LibraryImportedSymbols{}
|
||||
|
||||
var current_table *protomodel.MachoInfo_LibraryImportedSymbols
|
||||
|
||||
current_lib := ""
|
||||
current_symbol := ""
|
||||
|
||||
current_lib_idx := -1
|
||||
current_symbol_idx := -1
|
||||
|
||||
intlSymbols := []string{}
|
||||
for _, symbol := range symbols_raw {
|
||||
if symbol.Dylib() == "/usr/local/opt/gettext/lib/libintl.8.dylib" {
|
||||
intlSymbols = append(intlSymbols, symbol.Name())
|
||||
}
|
||||
}
|
||||
action.keepSymbols = append(action.keepSymbols, intlSymbols...)
|
||||
|
||||
// now we expect everything is sorted and easier to build strings tables
|
||||
// this is not fully optimized, there can be repeated symbol name in different libraries
|
||||
for _, symbol := range symbols_raw {
|
||||
if !symbol.SafeForRemoval() {
|
||||
continue
|
||||
}
|
||||
|
||||
skip := false
|
||||
for _, keep := range action.keepSymbols {
|
||||
name := keep
|
||||
lib := ""
|
||||
parts := strings.Split(keep, ",")
|
||||
if len(parts) == 2 {
|
||||
name = parts[0]
|
||||
lib = parts[1]
|
||||
}
|
||||
|
||||
if symbol.Name() != name {
|
||||
continue
|
||||
}
|
||||
if lib == "" || lib == symbol.Dylib() {
|
||||
skip = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if skip {
|
||||
continue
|
||||
}
|
||||
|
||||
// dylib_hash := calculateHash(symbol.Dylib())
|
||||
seg := mc.Segments()[symbol.Segment()]
|
||||
|
||||
var offset uint64
|
||||
|
||||
if symbol.Address() >= seg.Vmaddr() {
|
||||
// this is virtual address
|
||||
offset = symbol.Address() - seg.Vmaddr()
|
||||
} else {
|
||||
// this is file address
|
||||
offset = symbol.Address() - seg.Fileoff()
|
||||
}
|
||||
|
||||
if current_lib != symbol.Dylib() {
|
||||
current_lib_idx += len(current_lib) + 1
|
||||
current_lib = symbol.Dylib()
|
||||
libs = append(libs, symbol.Dylib())
|
||||
tables = append(tables, &protomodel.MachoInfo_LibraryImportedSymbols{
|
||||
LibIndex: uint32(current_lib_idx),
|
||||
Nsymbols: 0,
|
||||
Symbols: []*protomodel.MachoInfo_SymbolTable{},
|
||||
})
|
||||
current_table = tables[len(tables)-1]
|
||||
}
|
||||
if current_symbol != symbol.Name() {
|
||||
current_symbol_idx += len(current_symbol) + 1
|
||||
current_symbol = symbol.Name()
|
||||
symbols = append(symbols, symbol.Name())
|
||||
}
|
||||
current_table.Nsymbols += 1
|
||||
current_table.Symbols = append(current_table.Symbols, &protomodel.MachoInfo_SymbolTable{
|
||||
SymbolIndex: uint32(current_symbol_idx),
|
||||
SegmentIndex: symbol.Segment(),
|
||||
Offset: uint32(offset),
|
||||
})
|
||||
}
|
||||
mf.Info().Symbols = &protomodel.MachoInfo_AllImportedSymbols{
|
||||
Libs: libs,
|
||||
Symbols: symbols,
|
||||
Tables: tables,
|
||||
}
|
||||
|
||||
mf.Info().Main = mc.Main()
|
||||
|
||||
selectors_list := []*protomodel.MachoInfo_Selector{}
|
||||
for _, sel := range mc.CollectSpecialSelectors() {
|
||||
selectors_list = append(selectors_list, &protomodel.MachoInfo_Selector{
|
||||
Idx: uint32(sel.Idx()),
|
||||
Name: sel.Name(),
|
||||
})
|
||||
}
|
||||
mf.Info().SpecialSelectors = selectors_list
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (action *saveImports) withFat(ff *FatFile) error {
|
||||
return defaultWithFat(action, ff)
|
||||
}
|
||||
|
||||
func NewSaveImportsAction(keepSymbols []string) *saveImports {
|
||||
return &saveImports{
|
||||
keepSymbols,
|
||||
}
|
||||
}
|
@ -1,9 +1,11 @@
|
||||
package wrapper
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
// "strings"
|
||||
|
||||
"github.com/alecthomas/kong"
|
||||
log "github.com/sirupsen/logrus"
|
||||
@ -63,6 +65,10 @@ func Cli() {
|
||||
arg := cli.Lipo.Join
|
||||
fat.FatJoin(arg.Macho, arg.Out)
|
||||
return
|
||||
} else if command == "bcell2header" {
|
||||
arg := cli.BcellToHeader
|
||||
bcell2header(arg.Bcell, arg.Out)
|
||||
return
|
||||
}
|
||||
|
||||
var pc ProgramContext
|
||||
@ -73,7 +79,7 @@ func Cli() {
|
||||
arg := cli.Wrap
|
||||
ofile = NewOFile(arg.OFile)
|
||||
pc.remove_codesign = true
|
||||
pc.strip_init_pointers = true
|
||||
pc.remove_inits = true
|
||||
pc.dylib_to_add = []string{"@rpath/bcell.framework/bcell"}
|
||||
pc.rpath_to_add = []string{"@executable_path/Frameworks"}
|
||||
pc.outfile = arg.Out
|
||||
@ -99,6 +105,30 @@ func Cli() {
|
||||
ofile = NewOFile(arg.OFile)
|
||||
pc.remove_imports = true
|
||||
pc.outfile = arg.Out
|
||||
pc.bcellfile = arg.Bcell
|
||||
|
||||
case "pepe":
|
||||
arg := cli.Pepe
|
||||
ofile = NewOFile(arg.OFile)
|
||||
if arg.FullRemoval {
|
||||
pc.remove_exports = true
|
||||
pc.remove_symbol_table = true
|
||||
pc.remove_imports = true
|
||||
pc.remove_inits = true
|
||||
pc.remove_codesign = true
|
||||
pc.remove_others = true
|
||||
}
|
||||
pc.remove_imports = arg.RemoveBindSymbols
|
||||
pc.remove_codesign = arg.RemoveCodeSign
|
||||
pc.remove_inits = arg.RemoveInitFunctions
|
||||
pc.remove_others = arg.RemoveOthers
|
||||
pc.remove_exports = arg.RemoveExports
|
||||
pc.remove_symbol_table = arg.RemoveSymbolTable
|
||||
pc.dylib_to_add = arg.Dylibs
|
||||
pc.rpath_to_add = arg.Rpath
|
||||
pc.outfile = arg.Out
|
||||
pc.bcellfile = arg.Bcell
|
||||
pc.symbols_keep = arg.KeepImports
|
||||
|
||||
default:
|
||||
return
|
||||
@ -165,6 +195,12 @@ func displayBcell(bfile string) {
|
||||
init_ptr.Value,
|
||||
)
|
||||
}
|
||||
fmt.Printf(" | Bind Symbols:\n")
|
||||
// for _, symbol := range info.Symbols {
|
||||
// lib := strings.Replace(symbol.Libname, "/System/Library/Frameworks/", "", 1)
|
||||
// fmt.Printf(" | %s offset=0x%x segmentID=0x%x\n", symbol.Name, symbol.Offset, symbol.Segment)
|
||||
// fmt.Printf(" | from=%s\n", lib)
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@ -194,3 +230,91 @@ func resolveAddresses(dwarf string, load string, addresses []string) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func bcell2header(bfile string, header string) {
|
||||
raw_data, err := ioutil.ReadFile(bfile)
|
||||
data := &protomodel.BcellFile{}
|
||||
err = proto.Unmarshal(raw_data, data)
|
||||
if err != nil {
|
||||
log.Panic("Invalid Protobuf<BcellFile> bcell.dat")
|
||||
}
|
||||
|
||||
f, err := os.Create(header)
|
||||
if err != nil {
|
||||
log.Panic("Cannot open header file for writing")
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
w := bufio.NewWriter(f)
|
||||
|
||||
// fmt.Printf("[+] User Config: %+v\n", data.BcellConfig)
|
||||
fmt.Fprintf(w, "#include<stdint.h>\n")
|
||||
fmt.Fprintf(w, "namespace bshield_data{\n")
|
||||
for arch, info := range data.MachoInfos {
|
||||
fmt.Fprintf(w, "const char* arch = \"%s\";\n", arch)
|
||||
fmt.Fprintf(w, "unsigned int pointer_size = %d;\n", info.PointerSize)
|
||||
fmt.Fprintf(w, "uint64_t image_base = 0x%x;\n", info.ImageBase)
|
||||
fmt.Fprintf(w, "uint64_t main = 0x%x;\n", info.Main)
|
||||
|
||||
fmt.Fprintf(w, "struct init_pointer {uint64_t offset; uint64_t value;};\n")
|
||||
fmt.Fprintf(w, "int num_init_pointers = %d;\n", len(info.InitPointers))
|
||||
fmt.Fprintf(w, "struct init_pointer init_pointers_offsets[] = {\n")
|
||||
for _, init_ptr := range info.InitPointers {
|
||||
fmt.Fprintf(w, " {0x%x, 0x%x},\n", init_ptr.Offset, init_ptr.Value)
|
||||
}
|
||||
fmt.Fprintf(w, "};\n")
|
||||
|
||||
fmt.Fprintf(w, "__attribute__((section(\"__DATA,bshield\")))\n")
|
||||
fmt.Fprintf(w, "char libs[] =\n")
|
||||
for _, lib := range info.Symbols.Libs {
|
||||
fmt.Fprintf(w, " \"%s\\0\"\n", lib)
|
||||
}
|
||||
fmt.Fprintf(w, ";\n")
|
||||
|
||||
fmt.Fprintf(w, "__attribute__((section(\"__DATA,bshield\")))\n")
|
||||
fmt.Fprintf(w, "char symbols[] =\n")
|
||||
for _, symbol := range info.Symbols.Symbols {
|
||||
fmt.Fprintf(w, " \"%s\\0\"\n", symbol)
|
||||
}
|
||||
fmt.Fprintf(w, ";\n")
|
||||
|
||||
fmt.Fprintf(w, "// very compact symbol table,\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, "// 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, "uint32_t encoded_table[] = {\n")
|
||||
n_instructions := 0
|
||||
for i, table := range info.Symbols.Tables {
|
||||
fmt.Fprintf(w, " // %s\n", info.Symbols.Libs[i])
|
||||
fmt.Fprintf(w, " %d/*lib offset*/,\n", table.LibIndex)
|
||||
fmt.Fprintf(w, " %d/*nsymbols*/,\n", table.Nsymbols)
|
||||
n_instructions += 2
|
||||
for _, symbol := range table.Symbols {
|
||||
fmt.Fprintf(w, " %d, 0x%x,\n", (symbol.SymbolIndex<<8)|symbol.SegmentIndex, symbol.Offset)
|
||||
n_instructions += 2
|
||||
}
|
||||
fmt.Fprintf(w, "\n")
|
||||
}
|
||||
fmt.Fprintf(w, "};\n")
|
||||
fmt.Fprintf(w, "uint32_t n_instructions = %d;\n", n_instructions)
|
||||
|
||||
fmt.Fprintf(w, "__attribute__((section(\"__DATA,bshield\")))\n")
|
||||
fmt.Fprintf(w, "uint32_t special_selectors_idx[] = {\n")
|
||||
for _, selector := range info.GetSpecialSelectors() {
|
||||
fmt.Fprintf(w, "%x,\n", selector.Idx)
|
||||
}
|
||||
fmt.Fprintf(w, "};\n")
|
||||
|
||||
fmt.Fprintf(w, "__attribute__((section(\"__DATA,bshield\")))\n")
|
||||
fmt.Fprintf(w, "const char* special_selectors_name[] = {\n")
|
||||
for _, selector := range info.GetSpecialSelectors() {
|
||||
fmt.Fprintf(w, "\"%s\",\n", selector.Name)
|
||||
}
|
||||
fmt.Fprintf(w, "};\n")
|
||||
fmt.Fprintf(w, "uint32_t n_selectors = %d;\n", len(info.GetSpecialSelectors()))
|
||||
}
|
||||
fmt.Fprintf(w, "}// namespace bshield_data\n")
|
||||
w.Flush()
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ type RemoveCodesignArgument struct {
|
||||
|
||||
type RemoveImportsArgument struct {
|
||||
Out string `short:"o" required name:"outfile" help:"Modified Mach-O/Fat binary output file" type:"path"`
|
||||
Bcell string `short:"b" required help:"bcell.dat output file" type:"path"`
|
||||
OFile string `arg help:"Path to Mach-O/Fat binary file" type:"existingfile"`
|
||||
}
|
||||
|
||||
@ -55,7 +56,28 @@ type LipoArgument struct {
|
||||
}
|
||||
|
||||
type PepeArgument struct {
|
||||
OFile string `arg help:"Path to Mach-O/Fat binary file" type:"existingfile"`
|
||||
Out string `short:"o" required name:"outfile" help:"Output file after transformation" type:"path"`
|
||||
Bcell string `short:"b" required help:"bcell.dat output file" type:"path"`
|
||||
OFile string `arg help:"Path to Mach-O/Fat binary file" type:"existingfile"`
|
||||
Dylibs []string `short:"l" help:"Add more LC_DYLIB"`
|
||||
Rpath []string `short:"r" help:"Add more LC_RPATH"`
|
||||
RemoveCodeSign bool `default:"false" negatable:"" help:"Remove LC_CODE_SIGNATURE"`
|
||||
RemoveExports bool `default:"false" negatable:"" help:"Clear the export table/trie"`
|
||||
RemoveSymbolTable bool `default:"false" negatable:"" help:"Remove LC_SYMTAB and LC_DYSYMTAB"`
|
||||
RemoveOthers bool `default:"false" negatable:"" help:"Remove LC_FUNCTION_STARTS, LC_DATA_IN_CODE, ..."`
|
||||
RemoveID bool `default:"false" negatable:"" help:"(TODO) Remove LC_ID_DYLIB"`
|
||||
RemoveInitFunctions bool `default:"false" name:"remove-inits" negatable:"" help:"Clear MOD_INIT_FUNC section"`
|
||||
RemoveBindSymbols bool `default:"false" name:"remove-imports" negatable:"" help:"Remove all bind symbols information"`
|
||||
RemoveObjCString bool `default:"false" negatable:"" help:"(TODO) Remove references, string litteral to Objctive-C strings"`
|
||||
RebuildLinkEdit bool `default:"false" negatable:"" help:"(TODO) Rebuild the LINKEDIT section"`
|
||||
FullRemoval bool `default:"false" help:"Apply every removal possible"`
|
||||
|
||||
KeepImports []string `short:"keep" help:"Do not remove import symbols and allow dyld resolve. If symbols is found with more than 1 occurrances, specify the library with a comma or else all occurrances will be kept. e.g., _symbol,libLIB.dylib"`
|
||||
}
|
||||
|
||||
type BcellToHeaderArgument struct {
|
||||
Out string `short:"o" required name:"outfile" help:"Header file name to output to" type:"path"`
|
||||
Bcell string `short:"b" required help:"Input bcell.dat file" type:"existingfile"`
|
||||
}
|
||||
|
||||
type Argument struct {
|
||||
@ -68,5 +90,14 @@ type Argument struct {
|
||||
DisplayBcell DisplayBcellArgument `cmd name:"display-bcell" help:"Display Protobuf<BcellFile> content"`
|
||||
Addr2Line Addr2LineArgument `cmd name:"addr2line" help:"Resolve crash address from DWARF file"`
|
||||
Lipo LipoArgument `cmd help:"split Fat binary or join Mach-O binares"`
|
||||
Pepe PepeArgument `cmd help:"split Fat binary or join Mach-O binares"`
|
||||
Pepe PepeArgument `cmd help:"custom command"`
|
||||
BcellToHeader BcellToHeaderArgument `cmd name:"bcell2header" help:"Build C header file from bcell file"`
|
||||
AddSection struct {
|
||||
Out string `short:"o" required name:"outfile" help:"Output file after transformation"`
|
||||
Data string `arg help:"Input data file to fill in this section, or null if not provided" type:"existingfile"`
|
||||
OFile string `arg help:"Path to Mach-O/Fat binary file" type:"existingfile"`
|
||||
Segment string `required help:"Segment name"`
|
||||
Section string `required help:"Section name"`
|
||||
Size int `required help:"Size of segment/section"`
|
||||
} `cmd:"" default:"false" help:"(TODO) Add a new segment with 1 section, segment starts at the end of last segment"`
|
||||
}
|
||||
|
@ -35,16 +35,18 @@ func (printer *InfoPrinter) Print() {
|
||||
}
|
||||
|
||||
symbols := mc.CollectBindSymbols()
|
||||
for _, sym := range symbols {
|
||||
fmt.Printf(
|
||||
"%s (%s)\n\tStub=0x%x Address=0x%x\n\tDylib=%s\n",
|
||||
sym.Name(),
|
||||
sym.Type(),
|
||||
sym.Stub(),
|
||||
sym.Address(),
|
||||
sym.Dylib(),
|
||||
)
|
||||
}
|
||||
for _, sym := range symbols {
|
||||
fmt.Printf(
|
||||
"%s (%s)\n\tStub=0x%x Address=0x%x\n\tDylib=%s\n",
|
||||
sym.Name(),
|
||||
sym.Type(),
|
||||
sym.Stub(),
|
||||
sym.Address(),
|
||||
sym.Dylib(),
|
||||
)
|
||||
}
|
||||
|
||||
mc.CollectObjectiveCClasses()
|
||||
|
||||
fmt.Println("======")
|
||||
}
|
||||
|
@ -38,11 +38,15 @@ func (uc *UserConfig) Protomodel() *protomodel.Config {
|
||||
}
|
||||
|
||||
type ProgramContext struct {
|
||||
strip_init_pointers bool
|
||||
remove_inits bool
|
||||
remove_codesign bool
|
||||
remove_imports bool
|
||||
remove_others bool
|
||||
remove_exports bool
|
||||
remove_symbol_table bool
|
||||
dylib_to_add []string
|
||||
rpath_to_add []string
|
||||
symbols_keep []string
|
||||
|
||||
outfile string
|
||||
|
||||
@ -84,24 +88,28 @@ func (pc *ProgramContext) dispatchActions(ofile OFile) {
|
||||
}
|
||||
|
||||
func (pc *ProgramContext) Process(ofile OFile) {
|
||||
if pc.remove_imports {
|
||||
pc.AddAction(NewRemoveImportsAction())
|
||||
pc.AddAction(NewWriteFileAction(pc.outfile))
|
||||
pc.dispatchActions(ofile)
|
||||
return
|
||||
}
|
||||
if pc.remove_codesign {
|
||||
pc.AddAction(NewRemoveCodeSignatureAction())
|
||||
}
|
||||
if pc.strip_init_pointers {
|
||||
if pc.remove_inits {
|
||||
pc.AddAction(NewSaveInitPointerAction())
|
||||
pc.AddAction(NewRemoveInitPointerAction())
|
||||
}
|
||||
ExperimentalFeature("Remove Unnecessary Info", func() {
|
||||
pc.AddAction(NewRemoveUnnecessaryInfoAction())
|
||||
})
|
||||
ExperimentalFeature("Remove Classic Symbol", func() {
|
||||
if pc.remove_imports {
|
||||
pc.AddAction(NewSaveImportsAction(pc.symbols_keep))
|
||||
pc.AddAction(NewRemoveImportsAction())
|
||||
pc.AddAction(NewRewriteImportsWithKeepSymbolsAction(pc.symbols_keep))
|
||||
}
|
||||
if pc.remove_symbol_table {
|
||||
pc.AddAction(NewRemoveClassicSymbolAction())
|
||||
}
|
||||
if pc.remove_exports {
|
||||
pc.AddAction(NewRemoveExportsAction())
|
||||
}
|
||||
ExperimentalFeature("Remove Unnecessary Info", func() {
|
||||
if pc.remove_others {
|
||||
pc.AddAction(NewRemoveUnnecessaryInfoAction())
|
||||
}
|
||||
})
|
||||
pc.AddAction(NewAddRpathAction(pc.rpath_to_add))
|
||||
pc.AddAction(NewAddDylibAction(pc.dylib_to_add))
|
||||
|
@ -4,9 +4,9 @@ import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"unsafe"
|
||||
"unsafe"
|
||||
// "bufio"
|
||||
"io"
|
||||
"io"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
@ -19,16 +19,19 @@ import "C"
|
||||
|
||||
type ImportSymbol struct {
|
||||
name string
|
||||
typ string
|
||||
typ string
|
||||
dylib string
|
||||
segment uint32
|
||||
segment_offset uint32
|
||||
address uint64
|
||||
file_address uint64
|
||||
lib_ordinal uint32
|
||||
|
||||
// push number
|
||||
pnum uint32
|
||||
stub uint64
|
||||
|
||||
next int // only for LC_DYLD_CHAINED_FIXUPS
|
||||
}
|
||||
|
||||
func (sym *ImportSymbol) Name() string {
|
||||
@ -39,10 +42,18 @@ func (sym *ImportSymbol) Type() string {
|
||||
return sym.typ
|
||||
}
|
||||
|
||||
func (sym *ImportSymbol) SafeForRemoval() bool {
|
||||
return sym.typ == "lazy" || sym.typ == "fixups"
|
||||
}
|
||||
|
||||
func (sym *ImportSymbol) Dylib() string {
|
||||
return sym.dylib
|
||||
}
|
||||
|
||||
func (sym *ImportSymbol) LibOrdinal() uint32 {
|
||||
return sym.lib_ordinal
|
||||
}
|
||||
|
||||
func (sym *ImportSymbol) Address() uint64 {
|
||||
return sym.address
|
||||
}
|
||||
@ -55,6 +66,10 @@ func (sym *ImportSymbol) Stub() uint64 {
|
||||
return sym.stub
|
||||
}
|
||||
|
||||
func (sym *ImportSymbol) Segment() uint32 {
|
||||
return sym.segment
|
||||
}
|
||||
|
||||
func (mc *MachoContext) CollectBindSymbols() []*ImportSymbol {
|
||||
if mc.dyldinfo == nil {
|
||||
return mc.CollectBindSymbolsModern()
|
||||
@ -64,135 +79,142 @@ func (mc *MachoContext) CollectBindSymbols() []*ImportSymbol {
|
||||
}
|
||||
|
||||
func (mc *MachoContext) findSegmentIndexAt(address uint64) int {
|
||||
for i, segment := range mc.Segments() {
|
||||
if segment.Fileoff() <= address && segment.Fileoff() + segment.Filesize() > address {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
for i, segment := range mc.Segments() {
|
||||
if segment.Fileoff() <= address && segment.Fileoff()+segment.Filesize() > address {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// New convention using LC_DYLD_CHAINED_FIXUPS
|
||||
func (mc *MachoContext) CollectBindSymbolsModern() []*ImportSymbol {
|
||||
start := mc.fixups.dataoff
|
||||
size := mc.fixups.datasize
|
||||
buf := mc.buf[start:start+size]
|
||||
start := mc.fixups.dataoff
|
||||
size := mc.fixups.datasize
|
||||
buf := mc.buf[start : start+size]
|
||||
|
||||
// all pointers used are based from this **buf**
|
||||
// until buf is freed, all pointers are valid
|
||||
// remember to copy before moving out
|
||||
header := (*C.uchar)(unsafe.Pointer(&buf[0]))
|
||||
imports_table := C.GetImportsTable(header);
|
||||
// all pointers used are based from this **buf**
|
||||
// until buf is freed, all pointers are valid
|
||||
// remember to copy before moving out
|
||||
header := (*C.uchar)(unsafe.Pointer(&buf[0]))
|
||||
imports_table := C.GetImportsTable(header)
|
||||
|
||||
// for i := 0; i < int(imports_table.size); i++ {
|
||||
// s := C.GetImportsAt(&imports_table, C.int(i))
|
||||
// name := C.GoString(s.name)
|
||||
// symbol.dylib := string(mc.dylibs[int(s.lib_ordinal)-1].name[:])
|
||||
// symbol_table = append(symbol_table, symbol)
|
||||
// fmt.Printf("id=%d lib=%s name=%s\n", i, dylib, name)
|
||||
// }
|
||||
// for i := 0; i < int(imports_table.size); i++ {
|
||||
// s := C.GetImportsAt(&imports_table, C.int(i))
|
||||
// name := C.GoString(s.name)
|
||||
// symbol.dylib := string(mc.dylibs[int(s.lib_ordinal)-1].name[:])
|
||||
// symbol_table = append(symbol_table, symbol)
|
||||
// fmt.Printf("id=%d lib=%s name=%s\n", i, dylib, name)
|
||||
// }
|
||||
|
||||
var syms []*ImportSymbol
|
||||
var sym ImportSymbol
|
||||
|
||||
segment_i := 0
|
||||
for {
|
||||
var fix C.struct_SegmentFix
|
||||
fix_ptr := (*C.struct_SegmentFix)(unsafe.Pointer(&fix))
|
||||
status := int(C.GetSegmentFixAt(header, C.uint(segment_i), fix_ptr))
|
||||
segment_i += 1
|
||||
if status == 2 {
|
||||
break;
|
||||
}
|
||||
if status == 3 {
|
||||
continue
|
||||
}
|
||||
// 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))
|
||||
for page_i := 0; page_i < int(fix.page_count); page_i++ {
|
||||
// fmt.Printf(" page offset=%x\n", pages[page_i])
|
||||
segment_i := 0
|
||||
for {
|
||||
var fix C.struct_SegmentFix
|
||||
fix_ptr := (*C.struct_SegmentFix)(unsafe.Pointer(&fix))
|
||||
status := int(C.GetSegmentFixAt(header, C.uint(segment_i), fix_ptr))
|
||||
segment_i += 1
|
||||
if status == 2 {
|
||||
break
|
||||
}
|
||||
if status == 3 {
|
||||
continue
|
||||
}
|
||||
// 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)
|
||||
for page_i := 0; page_i < int(fix.page_count); page_i++ {
|
||||
// fmt.Printf(" page offset=%x\n", pages[page_i])
|
||||
|
||||
address := int64(fix.segment) + int64(pages[page_i])
|
||||
mc.file.Seek(address, io.SeekStart)
|
||||
address := int64(fix.segment) + int64(pages[page_i])
|
||||
reader.Seek(address, io.SeekStart)
|
||||
|
||||
code := make([]byte, 8)
|
||||
code := make([]byte, 8)
|
||||
|
||||
for {
|
||||
mc.file.Read(code)
|
||||
v := binary.LittleEndian.Uint64(code)
|
||||
for {
|
||||
reader.Read(code)
|
||||
v := mc.byteorder.Uint64(code)
|
||||
|
||||
var bind C.int
|
||||
var ret1 C.ulonglong
|
||||
var ret2 C.ulonglong
|
||||
next := C.ParseFixValue(C.int(fix.format), C.ulonglong(v),
|
||||
&bind, &ret1, &ret2)
|
||||
var bind C.int
|
||||
var ret1 C.ulonglong
|
||||
var ret2 C.ulonglong
|
||||
next := C.ParseFixValue(C.int(fix.format), C.ulonglong(v),
|
||||
&bind, &ret1, &ret2)
|
||||
|
||||
if bind == 1 {
|
||||
s := C.GetImportsAt(&imports_table, C.int(ret1))
|
||||
name := C.GoString(s.name)
|
||||
dylib := string(mc.dylibs[int(s.lib_ordinal)-1].name[:])
|
||||
if bind == 1 {
|
||||
s := C.GetImportsAt(&imports_table, C.int(ret1))
|
||||
name := C.GoString(s.name)
|
||||
dylib := string(mc.dylibs[int(s.lib_ordinal)-1].name[:])
|
||||
|
||||
// fmt.Printf("%x bind=%d (%s)%s\n", address, bind, dylib, name)
|
||||
fmt.Printf("// 0x%x bind=%d (%s)%s\n", address, bind, dylib, name)
|
||||
|
||||
sym.address = uint64(address)
|
||||
sym.name = name
|
||||
sym.dylib = dylib
|
||||
sym.typ = "lazy"
|
||||
sym.address = uint64(address)
|
||||
sym.name = name
|
||||
sym.dylib = dylib
|
||||
sym.typ = "fixups"
|
||||
sym.lib_ordinal = uint32(s.lib_ordinal)
|
||||
|
||||
sym.segment = uint32(mc.findSegmentIndexAt(uint64(address)))
|
||||
sym.file_address = uint64(address)
|
||||
new_sym := sym
|
||||
syms = append(syms, &new_sym)
|
||||
}
|
||||
sym.segment = uint32(mc.findSegmentIndexAt(uint64(address)))
|
||||
sym.file_address = uint64(address)
|
||||
sym.next = int(next)
|
||||
new_sym := sym
|
||||
syms = append(syms, &new_sym)
|
||||
} else {
|
||||
fmt.Printf("// 0x%x rebase=%d target=0x%x high8=0x%x\n", address, bind, ret1, ret2)
|
||||
}
|
||||
|
||||
address += 8
|
||||
if int(next) == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
mc.file.Seek(0, io.SeekStart)
|
||||
}
|
||||
}
|
||||
if int(next) == 0 {
|
||||
break
|
||||
}
|
||||
// because the pointer move up 8 bytes already so we minus 8
|
||||
address += int64(next * 4)
|
||||
reader.Seek(int64(next*4)-8, io.SeekCurrent)
|
||||
}
|
||||
reader.Seek(0, io.SeekStart)
|
||||
}
|
||||
}
|
||||
return syms
|
||||
}
|
||||
|
||||
// Old convention using LC_DYLD_INFO_ONLY section and bytecode runner
|
||||
func (mc *MachoContext) CollectBindSymbolsLegacy() []*ImportSymbol {
|
||||
noLazy := (func() []*ImportSymbol {
|
||||
start := mc.dyldinfo.bind_off
|
||||
size := mc.dyldinfo.bind_size
|
||||
end := start + size
|
||||
buf := bytes.NewBuffer(mc.buf[start:end])
|
||||
return mc.readBindStream(buf, "no lazy")
|
||||
})()
|
||||
noLazy := (func() []*ImportSymbol {
|
||||
start := mc.dyldinfo.bind_off
|
||||
size := mc.dyldinfo.bind_size
|
||||
end := start + size
|
||||
buf := bytes.NewBuffer(mc.buf[start:end])
|
||||
return mc.readBindStream(buf, "no lazy")
|
||||
})()
|
||||
|
||||
lazy := (func() []*ImportSymbol {
|
||||
start := mc.dyldinfo.lazy_bind_off
|
||||
size := mc.dyldinfo.lazy_bind_size
|
||||
end := start + size
|
||||
buf := bytes.NewBuffer(mc.buf[start:end])
|
||||
return mc.readBindStream(buf, "lazy")
|
||||
})()
|
||||
lazy := (func() []*ImportSymbol {
|
||||
start := mc.dyldinfo.lazy_bind_off
|
||||
size := mc.dyldinfo.lazy_bind_size
|
||||
end := start + size
|
||||
buf := bytes.NewBuffer(mc.buf[start:end])
|
||||
return mc.readBindStream(buf, "lazy")
|
||||
})()
|
||||
|
||||
weak := (func() []*ImportSymbol {
|
||||
start := mc.dyldinfo.weak_bind_off
|
||||
size := mc.dyldinfo.weak_bind_size
|
||||
end := start + size
|
||||
buf := bytes.NewBuffer(mc.buf[start:end])
|
||||
return mc.readBindStream(buf, "weak")
|
||||
})()
|
||||
weak := (func() []*ImportSymbol {
|
||||
start := mc.dyldinfo.weak_bind_off
|
||||
size := mc.dyldinfo.weak_bind_size
|
||||
end := start + size
|
||||
buf := bytes.NewBuffer(mc.buf[start:end])
|
||||
return mc.readBindStream(buf, "weak")
|
||||
})()
|
||||
|
||||
var symbols []*ImportSymbol
|
||||
symbols = append(symbols, noLazy...)
|
||||
symbols = append(symbols, lazy...)
|
||||
symbols = append(symbols, weak...)
|
||||
var symbols []*ImportSymbol
|
||||
symbols = append(symbols, noLazy...)
|
||||
symbols = append(symbols, lazy...)
|
||||
symbols = append(symbols, weak...)
|
||||
|
||||
return symbols
|
||||
return symbols
|
||||
}
|
||||
|
||||
func (mc *MachoContext) readBindStream(buf *bytes.Buffer, typ string) []*ImportSymbol {
|
||||
size := buf.Len()
|
||||
size := buf.Len()
|
||||
if size == 0 {
|
||||
return []*ImportSymbol{}
|
||||
}
|
||||
@ -226,7 +248,7 @@ func (mc *MachoContext) readBindStream(buf *bytes.Buffer, typ string) []*ImportS
|
||||
case BIND_OPCODE_DO_BIND:
|
||||
if sym.name != "" {
|
||||
new_sym := sym
|
||||
new_sym.typ = typ
|
||||
new_sym.typ = typ
|
||||
syms = append(syms, &new_sym)
|
||||
// fmt.Printf("Offset 0x%x: Symbol %+v\n", symoffset, sym)
|
||||
|
||||
@ -235,7 +257,7 @@ func (mc *MachoContext) readBindStream(buf *bytes.Buffer, typ string) []*ImportS
|
||||
"symbol": sym.name,
|
||||
}).Trace("Bind")
|
||||
sym.name = ""
|
||||
sym.address += 8
|
||||
sym.address += 8
|
||||
}
|
||||
offset += 1
|
||||
break
|
||||
@ -264,9 +286,9 @@ func (mc *MachoContext) readBindStream(buf *bytes.Buffer, typ string) []*ImportS
|
||||
|
||||
case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
|
||||
sym.name, _ = buf.ReadString(0)
|
||||
// ReadString input the 0x00 byte to buffer
|
||||
// while we are string so we can remove that
|
||||
sym.name = sym.name[:len(sym.name)-1]
|
||||
// ReadString input the 0x00 byte to buffer
|
||||
// while we are string so we can remove that
|
||||
sym.name = sym.name[:len(sym.name)-1]
|
||||
offset += uint(len(sym.name))
|
||||
break
|
||||
|
||||
@ -290,12 +312,12 @@ func (mc *MachoContext) readBindStream(buf *bytes.Buffer, typ string) []*ImportS
|
||||
offset += br
|
||||
break
|
||||
|
||||
case BIND_OPCODE_SET_TYPE_IMM:
|
||||
fmt.Println("// symbol type", imm)
|
||||
break
|
||||
case BIND_OPCODE_SET_TYPE_IMM:
|
||||
fmt.Println("// symbol type", imm)
|
||||
break
|
||||
|
||||
default:
|
||||
fmt.Println("BIND OPCODE NOT SUPPORTED", op, imm)
|
||||
fmt.Println("BIND OPCODE NOT SUPPORTED", op, imm)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,23 @@
|
||||
package macho
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
. "ios-wrapper/pkg/ios"
|
||||
"ios-wrapper/pkg/protomodel"
|
||||
)
|
||||
|
||||
// #include "fixups.h"
|
||||
import "C"
|
||||
|
||||
func rewriteLoadcommandsWithoutCodesignature(mc *MachoContext) {
|
||||
if mc.Is64bit() {
|
||||
mc.file.Seek(int64(Header_size_64), io.SeekStart)
|
||||
@ -185,10 +194,6 @@ func (mc *MachoContext) RemoveUnnecessaryInfo() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (mc *MachoContext) RemoveClassicSymbol() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (mc *MachoContext) AddLoadCmd(lcmd LoadCommand) {
|
||||
var offset uint64
|
||||
payload := lcmd.Serialize(mc)
|
||||
@ -270,140 +275,227 @@ func (mc *MachoContext) UpdateHeaderRemoveLcmd(size uint32) {
|
||||
|
||||
func (mc *MachoContext) RemoveBindSymbols() {
|
||||
if !mc.WriteEnabled() {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if mc.dyldinfo == nil {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
|
||||
isModernSymbol := mc.dyldinfo == nil
|
||||
isLegacySymbol := !isModernSymbol
|
||||
|
||||
if isModernSymbol {
|
||||
mc.removeBindSymbolsModern()
|
||||
} else {
|
||||
mc.removeBindSymbolsLegacy()
|
||||
}
|
||||
// Objective-C stub replaces main which can only appears in executable
|
||||
if mc.Header().IsExecutable() {
|
||||
mc.ReworkForObjc()
|
||||
}
|
||||
|
||||
calculateHash := func(name string) uint32 {
|
||||
var h uint32 = 0x811c9dc5
|
||||
for _, s := range name {
|
||||
h ^= uint32(s)
|
||||
h *= 0x01000193
|
||||
}
|
||||
return h
|
||||
}
|
||||
for _, symbol := range mc.CollectBindSymbols() {
|
||||
if !symbol.SafeForRemoval() {
|
||||
continue
|
||||
}
|
||||
|
||||
// due to some limitations when design this tool
|
||||
// we write the c code to stdout lol
|
||||
fmt.Println("struct imported_symbol {const char* name; const char* lib; uint32_t hash; int segment_i; uint64_t offset;};")
|
||||
fmt.Println("struct imported_symbol imported_table[] = {")
|
||||
count := 0
|
||||
for _, symbol := range mc.CollectBindSymbols() {
|
||||
if symbol.Type() != "lazy" {
|
||||
continue
|
||||
}
|
||||
count += 1
|
||||
dylib_hash := calculateHash(symbol.Dylib())
|
||||
seg := mc.segments[symbol.segment]
|
||||
if isLegacySymbol {
|
||||
// for legacy resolve the opcodes can be rewritten as 0x00
|
||||
mc.file.WriteAt(make([]byte, 8), int64(symbol.file_address))
|
||||
} else {
|
||||
// for modern resolve the opcodes must not be rewritten as 0x00
|
||||
// because it contains 2 types of opcodes, BIND and REBASE
|
||||
// we only fix BIND and leave REBASE intact
|
||||
// However, each opcodes has a *next* field to the next opcode
|
||||
// So if we want to leave the header intact (contains pointers, size)
|
||||
// We should rewrite this as REBASE opcode (so no symbol lookup happens)
|
||||
// and it can continue
|
||||
|
||||
var offset uint64
|
||||
|
||||
if symbol.address >= seg.Vmaddr() {
|
||||
// this is virtual address
|
||||
offset = symbol.address - seg.Vmaddr()
|
||||
} else {
|
||||
// this is file address
|
||||
offset = symbol.address - seg.Fileoff()
|
||||
}
|
||||
|
||||
fmt.Printf("{\"%s\", \"%s\", 0x%x, 0x%x, 0x%x},\n",
|
||||
symbol.Name(), symbol.Dylib(), dylib_hash, symbol.segment, offset);
|
||||
mc.file.WriteAt(make([]byte, 8), int64(symbol.file_address))
|
||||
}
|
||||
fmt.Println("};")
|
||||
fmt.Printf("uint32_t nimports = %d;\n", count);
|
||||
// we can write random values, because the loader just do
|
||||
// (high8 << 56 | target) - mach_header
|
||||
// or something, so no symbol lookup and no error at runtime
|
||||
target := rand.Int()
|
||||
high8 := rand.Int()
|
||||
value := C.MakeRebaseFixupOpcode(C.int(symbol.next), C.ulonglong(target), C.ulonglong(high8))
|
||||
v := make([]byte, 8)
|
||||
mc.byteorder.PutUint64(v, uint64(value))
|
||||
mc.file.WriteAt(v, int64(symbol.file_address))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (mc *MachoContext) removeBindSymbolsModern() {
|
||||
// we don't mess up the chain
|
||||
// we clear the imports table, and the raw opcodes
|
||||
// clearing imports table disables static analysis
|
||||
// clearing opcodes forces runtime manual mapping
|
||||
// we don't mess up the chain
|
||||
// we clear the imports table, and the raw opcodes
|
||||
// clearing imports table disables static analysis
|
||||
// clearing opcodes forces runtime manual mapping
|
||||
|
||||
// imports item are defined by mc.fixups.imports_format
|
||||
// basic case is dyld_chained_import, 4 bytes
|
||||
// imports item are defined by mc.fixups.imports_format
|
||||
// basic case is dyld_chained_import, 4 bytes
|
||||
|
||||
start := mc.fixups.dataoff
|
||||
size := mc.fixups.datasize
|
||||
fixups := new(Fixups)
|
||||
fixups.Deserialize(mc, mc.buf[start:start+size])
|
||||
start := mc.fixups.dataoff
|
||||
size := mc.fixups.datasize
|
||||
fixups := new(Fixups)
|
||||
fixups.Deserialize(mc, mc.buf[start:start+size])
|
||||
|
||||
start = mc.fixups.dataoff + fixups.imports_offset
|
||||
size = fixups.imports_count * 4
|
||||
fmt.Printf("// Erase at=0x%x size=0x%x\n", start, size)
|
||||
mc.file.WriteAt(make([]byte, size), int64(start))
|
||||
start = mc.fixups.dataoff + fixups.imports_offset
|
||||
size = fixups.imports_count * 4
|
||||
fmt.Printf("// Erase at=0x%x size=0x%x\n", start, size)
|
||||
mc.file.WriteAt(make([]byte, size), int64(start))
|
||||
|
||||
// string reference are at the end of this section
|
||||
start = mc.fixups.dataoff + fixups.symbols_offset
|
||||
size = mc.fixups.Datasize() - fixups.symbols_offset
|
||||
fmt.Printf("// Erase at=0x%x size=0x%x\n", start, size)
|
||||
mc.file.WriteAt(make([]byte, size), int64(start))
|
||||
// string reference are at the end of this section
|
||||
start = mc.fixups.dataoff + fixups.symbols_offset
|
||||
size = mc.fixups.Datasize() - fixups.symbols_offset
|
||||
fmt.Printf("// Erase at=0x%x size=0x%x\n", start, size)
|
||||
mc.file.WriteAt(make([]byte, size), int64(start))
|
||||
|
||||
fixups.imports_count = 0
|
||||
mc.file.WriteAt(fixups.Serialize(mc), int64(mc.fixups.dataoff))
|
||||
fixups.imports_count = 0
|
||||
mc.file.WriteAt(fixups.Serialize(mc), int64(mc.fixups.dataoff))
|
||||
}
|
||||
|
||||
func (mc *MachoContext) removeBindSymbolsLegacy() {
|
||||
start := mc.dyldinfo.lazy_bind_off
|
||||
size := mc.dyldinfo.lazy_bind_size
|
||||
// set lazy opcodes to 0x00 == DO_BIND
|
||||
// but no symbol state to bind
|
||||
mc.file.WriteAt(make([]byte, size), int64(start))
|
||||
start := mc.dyldinfo.lazy_bind_off
|
||||
size := mc.dyldinfo.lazy_bind_size
|
||||
// set lazy opcodes to 0x00 == DO_BIND
|
||||
// but no symbol state to bind
|
||||
mc.file.WriteAt(make([]byte, size), int64(start))
|
||||
}
|
||||
|
||||
func (mc *MachoContext) RewriteImportsTable(keepSymbols []string) {
|
||||
allSymbols := mc.CollectBindSymbols()
|
||||
fixups, fixupsOffset := mc.Fixups()
|
||||
|
||||
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
|
||||
|
||||
// some symbols are annoyingly distributed by another library
|
||||
// dispite the name asking for X, the dyld loads a Y library
|
||||
// LC_DYLD_ID of Y is equal to X and dyld can resolve these symbols
|
||||
// because we do not search for library using LC_DYLD_ID,
|
||||
// paths are mistaken and will not resolve symbols
|
||||
//
|
||||
// the most common library that has this behavior is libintl
|
||||
// and fixing the resolver takes time, we temporarily ignore this library
|
||||
// and so we keep symbols referenced by libintl
|
||||
intlSymbols := []string{}
|
||||
for _, symbol := range allSymbols {
|
||||
if symbol.Dylib() == "/usr/local/opt/gettext/lib/libintl.8.dylib" {
|
||||
intlSymbols = append(intlSymbols, symbol.Name())
|
||||
}
|
||||
}
|
||||
keepSymbols = append(keepSymbols, intlSymbols...)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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))
|
||||
|
||||
{
|
||||
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
|
||||
}
|
||||
|
||||
fixups.imports_count = keepCount
|
||||
mc.file.WriteAt(fixups.Serialize(mc), int64(mc.fixups.dataoff))
|
||||
}
|
||||
|
||||
func (mc *MachoContext) RemoveSymbolTable() {
|
||||
// try to remove symtab and dysymtab
|
||||
mc.removeSymtabCommand()
|
||||
mc.removeDySymtabCommand()
|
||||
// try to remove symtab and dysymtab
|
||||
mc.removeSymtabCommand()
|
||||
mc.removeDySymtabCommand()
|
||||
}
|
||||
|
||||
func (mc *MachoContext) removeSymtabCommand() {
|
||||
ptr := 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)
|
||||
}
|
||||
|
||||
var symtab_fix *Symtab
|
||||
var symtab_fix *Symtab
|
||||
for _, cmd := range mc.commands {
|
||||
if cmd.Cmd() != LC_SYMTAB {
|
||||
ptr += int64(cmd.Cmdsize())
|
||||
ptr += int64(cmd.Cmdsize())
|
||||
continue
|
||||
}
|
||||
var symtab = cmd.(*Symtab)
|
||||
symtab_fix = symtab
|
||||
var symtab = cmd.(*Symtab)
|
||||
symtab_fix = symtab
|
||||
|
||||
// erase strings referenced
|
||||
start := int64(symtab_fix.stroff)
|
||||
size := symtab_fix.strsize
|
||||
fmt.Printf("// Erase at=0x%x size=0x%x\n", start, size)
|
||||
mc.file.WriteAt(make([]byte, size), start)
|
||||
// erase strings referenced
|
||||
start := int64(symtab_fix.stroff)
|
||||
size := symtab_fix.strsize
|
||||
fmt.Printf("// Erase at=0x%x size=0x%x\n", start, size)
|
||||
mc.file.WriteAt(make([]byte, size), start)
|
||||
|
||||
// erase nlist64 symbol items
|
||||
start = int64(symtab_fix.symoff)
|
||||
size = symtab_fix.nsyms * 16
|
||||
fmt.Printf("// Erase at=0x%x size=0x%x\n", start, size)
|
||||
mc.file.WriteAt(make([]byte, size), start)
|
||||
// erase nlist64 symbol items
|
||||
start = int64(symtab_fix.symoff)
|
||||
size = symtab_fix.nsyms * 16
|
||||
fmt.Printf("// Erase at=0x%x size=0x%x\n", start, size)
|
||||
mc.file.WriteAt(make([]byte, size), start)
|
||||
|
||||
symtab_fix.symoff = 0
|
||||
symtab_fix.nsyms = 0
|
||||
symtab_fix.stroff = 0
|
||||
symtab_fix.strsize = 0
|
||||
// symtab_fix.symoff = 0
|
||||
// symtab_fix.nsyms = 0
|
||||
// symtab_fix.stroff = 0
|
||||
// symtab_fix.strsize = 0
|
||||
mc.file.Seek(ptr, io.SeekStart)
|
||||
mc.file.Write(symtab_fix.Serialize(mc))
|
||||
break
|
||||
break
|
||||
}
|
||||
mc.file.Seek(0, io.SeekStart)
|
||||
mc.file.Seek(0, io.SeekStart)
|
||||
}
|
||||
|
||||
func (mc *MachoContext) removeDySymtabCommand() {
|
||||
ptr := int64(0)
|
||||
ptr := int64(0)
|
||||
if mc.Is64bit() {
|
||||
ptr, _ = mc.file.Seek(int64(Header_size_64), io.SeekStart)
|
||||
} else {
|
||||
@ -411,33 +503,160 @@ func (mc *MachoContext) removeDySymtabCommand() {
|
||||
}
|
||||
for _, cmd := range mc.commands {
|
||||
if cmd.Cmd() != LC_DYSYMTAB {
|
||||
ptr += int64(cmd.Cmdsize())
|
||||
ptr += int64(cmd.Cmdsize())
|
||||
continue
|
||||
}
|
||||
var dysymtab = cmd.(*DySymtab)
|
||||
dysymtab_fix := dysymtab
|
||||
dysymtab_fix.indirectsymoff = 0
|
||||
dysymtab_fix.nindirectsyms = 0
|
||||
var dysymtab = cmd.(*DySymtab)
|
||||
dysymtab_fix := dysymtab
|
||||
dysymtab_fix.indirectsymoff = 0
|
||||
dysymtab_fix.nindirectsyms = 0
|
||||
mc.file.Seek(ptr, io.SeekStart)
|
||||
mc.file.Write(dysymtab_fix.Serialize(mc))
|
||||
}
|
||||
}
|
||||
|
||||
func (mc *MachoContext) RemoveExportTrie() {
|
||||
var start int64
|
||||
var size int
|
||||
if mc.dyldinfo != nil {
|
||||
// legacy export trie
|
||||
start = int64(mc.dyldinfo.export_off)
|
||||
size = int(mc.dyldinfo.export_size)
|
||||
mc.file.WriteAt(make([]byte, size), start)
|
||||
} else if mc.exports != nil {
|
||||
// modern export trie
|
||||
start = int64(mc.exports.dataoff)
|
||||
size = int(mc.exports.datasize)
|
||||
mc.file.WriteAt(make([]byte, size), start)
|
||||
} else {
|
||||
// no export trie (??)
|
||||
// should never occur unless this binary is modified
|
||||
}
|
||||
var start int64
|
||||
var size int
|
||||
if mc.dyldinfo != nil {
|
||||
// legacy export trie
|
||||
start = int64(mc.dyldinfo.export_off)
|
||||
size = int(mc.dyldinfo.export_size)
|
||||
mc.file.WriteAt(make([]byte, size), start)
|
||||
} else if mc.exports != nil {
|
||||
// modern export trie
|
||||
start = int64(mc.exports.dataoff)
|
||||
size = int(mc.exports.datasize)
|
||||
mc.file.WriteAt(make([]byte, size), start)
|
||||
} else {
|
||||
// no export trie (??)
|
||||
// should never occur unless this binary is modified
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
for _, command := range mc.commands {
|
||||
switch command.(type) {
|
||||
case *Segment64:
|
||||
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()
|
||||
// }
|
||||
}
|
||||
|
||||
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)")
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
|
||||
fmt.Printf("Add a new section with addr=0x%x, fileoffset=0x%x\n", section.addr, section.offset)
|
||||
|
||||
ret = §ion
|
||||
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
|
||||
}
|
||||
|
||||
func (mc *MachoContext) WriteInfoToData(info *protomodel.MachoInfo) {
|
||||
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)
|
||||
for _, symbol := range table.Symbols {
|
||||
binary.Write(buffer, mc.byteorder, (symbol.SymbolIndex<<8)|symbol.SegmentIndex)
|
||||
binary.Write(buffer, mc.byteorder, symbol.Offset)
|
||||
}
|
||||
}
|
||||
instructions := buffer.Bytes()
|
||||
|
||||
buffer = new(bytes.Buffer)
|
||||
for _, lib := range info.Symbols.Libs {
|
||||
buffer.WriteString(lib)
|
||||
buffer.WriteByte(0)
|
||||
}
|
||||
liblist := buffer.Bytes()
|
||||
|
||||
buffer = new(bytes.Buffer)
|
||||
for _, symbol := range info.Symbols.Symbols {
|
||||
buffer.WriteString(symbol)
|
||||
buffer.WriteByte(0)
|
||||
}
|
||||
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)
|
||||
|
||||
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()))
|
||||
}
|
||||
}
|
||||
|
@ -94,6 +94,38 @@ int ParseFixValue(int format, uint64_t value, int* bind, uint64_t* ret1, uint64_
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t MakeRebaseFixupOpcode(int next, uint64_t target, uint64_t high8) {
|
||||
uint64_t value;
|
||||
struct dyld_chained_ptr_64_rebase* b = (struct dyld_chained_ptr_64_rebase*)&value;
|
||||
b->bind = 0;
|
||||
b->next = next;
|
||||
b->target = target;
|
||||
b->high8 = high8;
|
||||
return value;
|
||||
}
|
||||
|
||||
uint64_t MakeBindFixupOpcodeFromRebase(uint64_t rebaseOpcode, uint32_t ordinal) {
|
||||
printf("fix bind value\n");
|
||||
uint64_t ret;
|
||||
struct dyld_chained_ptr_64_bind* b = (struct dyld_chained_ptr_64_bind*)&ret;
|
||||
b->next = ((struct dyld_chained_ptr_64_rebase*)&rebaseOpcode)->next;
|
||||
b->bind = 1;
|
||||
b->ordinal = ordinal;
|
||||
b->addend = 0;
|
||||
b->reserved = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t MakeImportTableEntry(uint32_t lib_ordinal, uint32_t name_offset) {
|
||||
printf("append import table\n");
|
||||
uint32_t ret;
|
||||
struct dyld_chained_import* import = (struct dyld_chained_import*)&ret;
|
||||
import->lib_ordinal = lib_ordinal;
|
||||
import->name_offset = name_offset;
|
||||
import->weak_import = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ParseFixUps(uint8_t* buffer) {
|
||||
struct dyld_chained_fixups_header* header = (struct dyld_chained_fixups_header*)buffer;
|
||||
printf("starts=0x%x\n", header->starts_offset);
|
||||
|
@ -30,4 +30,8 @@ struct ImportTable GetImportsTable(uint8_t* header_ptr);
|
||||
struct ImportSymbol GetImportsAt(struct ImportTable* table, int i);
|
||||
int GetSegmentFixAt(uint8_t* buffer, uint32_t i, struct SegmentFix* fix);
|
||||
int ParseFixValue(int format, uint64_t value, int* bind, uint64_t* ret1, uint64_t* ret2);
|
||||
uint64_t MakeRebaseFixupOpcode(int next, uint64_t target, uint64_t high8);
|
||||
|
||||
uint64_t MakeBindFixupOpcodeFromRebase(uint64_t rebaseOpcode, uint32_t ordinal);
|
||||
uint32_t MakeImportTableEntry(uint32_t lib_ordinal, uint32_t name_offset);
|
||||
#endif
|
||||
|
@ -37,6 +37,14 @@ func (h *Header) Cpusubtype() uint32 {
|
||||
return h.cpusubtype
|
||||
}
|
||||
|
||||
func (h *Header) IsExecutable() bool {
|
||||
return h.filetype == 0x2
|
||||
}
|
||||
|
||||
func (h *Header) IsDylib() bool {
|
||||
return h.filetype == 0x6
|
||||
}
|
||||
|
||||
func (h *Header) Serialize(mc *MachoContext) []byte {
|
||||
buf := new(bytes.Buffer)
|
||||
binary.Write(buf, mc.byteorder, h.magic)
|
||||
@ -127,6 +135,16 @@ func (lcmd *LoadCmd) Cmdname() string {
|
||||
return "LC_DATA_IN_CODE"
|
||||
case LC_SYMTAB:
|
||||
return "LC_SYMTAB"
|
||||
case LC_BUILD_VERSION:
|
||||
return "LC_BUILD_VERSION"
|
||||
case LC_UUID:
|
||||
return "LC_UUID"
|
||||
case LC_SOURCE_VERSION:
|
||||
return "LC_SOURCE_VERSION"
|
||||
case LC_DYLD_CHAINED_FIXUPS:
|
||||
return "LC_DYLD_CHAINED_FIXUPS"
|
||||
case LC_DYLD_EXPORTS_TRIE:
|
||||
return "LC_DYLD_EXPORTS_TRIE"
|
||||
default:
|
||||
// TODO: Update
|
||||
return fmt.Sprintf("LC_DONT_KNOW_0x%x", lcmd.Cmd())
|
||||
@ -397,13 +415,21 @@ func (lcmd *DyldInfo) Deserialize(mc *MachoContext, buf []byte) {
|
||||
}
|
||||
|
||||
type Fixups struct {
|
||||
fixups_version uint32
|
||||
starts_offset uint32
|
||||
imports_offset uint32
|
||||
symbols_offset uint32
|
||||
fixups_version uint32
|
||||
starts_offset uint32
|
||||
imports_offset uint32
|
||||
symbols_offset uint32
|
||||
imports_count uint32
|
||||
imports_format uint32
|
||||
symbols_format uint32
|
||||
symbols_format uint32
|
||||
}
|
||||
|
||||
func (lcmd *Fixups) ImportsOffset(fixups_offset uint32) uint32 {
|
||||
return lcmd.imports_offset + fixups_offset
|
||||
}
|
||||
|
||||
func (lcmd *Fixups) SymbolsOffset(fixups_offset uint32) uint32 {
|
||||
return lcmd.symbols_offset + fixups_offset
|
||||
}
|
||||
|
||||
func (lcmd *Fixups) Serialize(mc *MachoContext) []byte {
|
||||
@ -516,25 +542,25 @@ func (lcmd *Symtab) Deserialize(mc *MachoContext, buf []byte) {
|
||||
}
|
||||
|
||||
type DySymtab struct {
|
||||
c LoadCmd
|
||||
ilocalsym uint32
|
||||
nlocalsym uint32
|
||||
iextdefsym uint32
|
||||
nextdefsym uint32
|
||||
iundefsym uint32
|
||||
nundefsym uint32
|
||||
tocoff uint32
|
||||
ntoc uint32
|
||||
modtaboff uint32
|
||||
nmodtab uint32
|
||||
extrefsymoff uint32
|
||||
nextrefsyms uint32
|
||||
indirectsymoff uint32
|
||||
nindirectsyms uint32
|
||||
extreloff uint32
|
||||
nextrel uint32
|
||||
localrefoff uint32
|
||||
nlocref uint32
|
||||
c LoadCmd
|
||||
ilocalsym uint32
|
||||
nlocalsym uint32
|
||||
iextdefsym uint32
|
||||
nextdefsym uint32
|
||||
iundefsym uint32
|
||||
nundefsym uint32
|
||||
tocoff uint32
|
||||
ntoc uint32
|
||||
modtaboff uint32
|
||||
nmodtab uint32
|
||||
extrefsymoff uint32
|
||||
nextrefsyms uint32
|
||||
indirectsymoff uint32
|
||||
nindirectsyms uint32
|
||||
extreloff uint32
|
||||
nextrel uint32
|
||||
localrefoff uint32
|
||||
nlocref uint32
|
||||
}
|
||||
|
||||
func (lcmd *DySymtab) Cmd() uint32 {
|
||||
@ -558,20 +584,20 @@ func (lcmd *DySymtab) Serialize(mc *MachoContext) []byte {
|
||||
binary.Write(buf, mc.byteorder, lcmd.nlocalsym)
|
||||
binary.Write(buf, mc.byteorder, lcmd.iextdefsym)
|
||||
binary.Write(buf, mc.byteorder, lcmd.nextdefsym)
|
||||
binary.Write(buf, mc.byteorder, lcmd.iundefsym)
|
||||
binary.Write(buf, mc.byteorder, lcmd.nundefsym)
|
||||
binary.Write(buf, mc.byteorder, lcmd.tocoff)
|
||||
binary.Write(buf, mc.byteorder, lcmd.ntoc)
|
||||
binary.Write(buf, mc.byteorder, lcmd.modtaboff)
|
||||
binary.Write(buf, mc.byteorder, lcmd.nmodtab)
|
||||
binary.Write(buf, mc.byteorder, lcmd.extrefsymoff)
|
||||
binary.Write(buf, mc.byteorder, lcmd.nextrefsyms)
|
||||
binary.Write(buf, mc.byteorder, lcmd.indirectsymoff)
|
||||
binary.Write(buf, mc.byteorder, lcmd.nindirectsyms)
|
||||
binary.Write(buf, mc.byteorder, lcmd.extreloff)
|
||||
binary.Write(buf, mc.byteorder, lcmd.nextrel)
|
||||
binary.Write(buf, mc.byteorder, lcmd.localrefoff)
|
||||
binary.Write(buf, mc.byteorder, lcmd.nlocref)
|
||||
binary.Write(buf, mc.byteorder, lcmd.iundefsym)
|
||||
binary.Write(buf, mc.byteorder, lcmd.nundefsym)
|
||||
binary.Write(buf, mc.byteorder, lcmd.tocoff)
|
||||
binary.Write(buf, mc.byteorder, lcmd.ntoc)
|
||||
binary.Write(buf, mc.byteorder, lcmd.modtaboff)
|
||||
binary.Write(buf, mc.byteorder, lcmd.nmodtab)
|
||||
binary.Write(buf, mc.byteorder, lcmd.extrefsymoff)
|
||||
binary.Write(buf, mc.byteorder, lcmd.nextrefsyms)
|
||||
binary.Write(buf, mc.byteorder, lcmd.indirectsymoff)
|
||||
binary.Write(buf, mc.byteorder, lcmd.nindirectsyms)
|
||||
binary.Write(buf, mc.byteorder, lcmd.extreloff)
|
||||
binary.Write(buf, mc.byteorder, lcmd.nextrel)
|
||||
binary.Write(buf, mc.byteorder, lcmd.localrefoff)
|
||||
binary.Write(buf, mc.byteorder, lcmd.nlocref)
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
@ -583,18 +609,18 @@ func (lcmd *DySymtab) Deserialize(mc *MachoContext, buf []byte) {
|
||||
binary.Read(r, mc.byteorder, &lcmd.nlocalsym)
|
||||
binary.Read(r, mc.byteorder, &lcmd.iextdefsym)
|
||||
binary.Read(r, mc.byteorder, &lcmd.nextdefsym)
|
||||
binary.Read(r, mc.byteorder, &lcmd.iundefsym)
|
||||
binary.Read(r, mc.byteorder, &lcmd.nundefsym)
|
||||
binary.Read(r, mc.byteorder, &lcmd.tocoff)
|
||||
binary.Read(r, mc.byteorder, &lcmd.ntoc)
|
||||
binary.Read(r, mc.byteorder, &lcmd.modtaboff)
|
||||
binary.Read(r, mc.byteorder, &lcmd.nmodtab)
|
||||
binary.Read(r, mc.byteorder, &lcmd.extrefsymoff)
|
||||
binary.Read(r, mc.byteorder, &lcmd.nextrefsyms)
|
||||
binary.Read(r, mc.byteorder, &lcmd.indirectsymoff)
|
||||
binary.Read(r, mc.byteorder, &lcmd.nindirectsyms)
|
||||
binary.Read(r, mc.byteorder, &lcmd.extreloff)
|
||||
binary.Read(r, mc.byteorder, &lcmd.nextrel)
|
||||
binary.Read(r, mc.byteorder, &lcmd.localrefoff)
|
||||
binary.Read(r, mc.byteorder, &lcmd.nlocref)
|
||||
binary.Read(r, mc.byteorder, &lcmd.iundefsym)
|
||||
binary.Read(r, mc.byteorder, &lcmd.nundefsym)
|
||||
binary.Read(r, mc.byteorder, &lcmd.tocoff)
|
||||
binary.Read(r, mc.byteorder, &lcmd.ntoc)
|
||||
binary.Read(r, mc.byteorder, &lcmd.modtaboff)
|
||||
binary.Read(r, mc.byteorder, &lcmd.nmodtab)
|
||||
binary.Read(r, mc.byteorder, &lcmd.extrefsymoff)
|
||||
binary.Read(r, mc.byteorder, &lcmd.nextrefsyms)
|
||||
binary.Read(r, mc.byteorder, &lcmd.indirectsymoff)
|
||||
binary.Read(r, mc.byteorder, &lcmd.nindirectsyms)
|
||||
binary.Read(r, mc.byteorder, &lcmd.extreloff)
|
||||
binary.Read(r, mc.byteorder, &lcmd.nextrel)
|
||||
binary.Read(r, mc.byteorder, &lcmd.localrefoff)
|
||||
binary.Read(r, mc.byteorder, &lcmd.nlocref)
|
||||
}
|
||||
|
@ -29,11 +29,11 @@ type MachoContext struct {
|
||||
linkedits []*LinkEdit
|
||||
segments []Segment
|
||||
symtab *Symtab
|
||||
dysymtab *DySymtab
|
||||
dysymtab *DySymtab
|
||||
|
||||
dyldinfo *DyldInfo
|
||||
fixups *LinkEdit
|
||||
exports *LinkEdit
|
||||
dyldinfo *DyldInfo
|
||||
fixups *LinkEdit
|
||||
exports *LinkEdit
|
||||
}
|
||||
|
||||
func (mc *MachoContext) FileSize() uint32 {
|
||||
@ -64,6 +64,18 @@ func (mc *MachoContext) Segments() []Segment {
|
||||
return mc.segments
|
||||
}
|
||||
|
||||
func (mc *MachoContext) Main() uint64 {
|
||||
return mc.entryoff
|
||||
}
|
||||
|
||||
func (mc *MachoContext) Fixups() (*Fixups, uint64) {
|
||||
start := mc.fixups.dataoff
|
||||
size := mc.fixups.datasize
|
||||
fixups := new(Fixups)
|
||||
fixups.Deserialize(mc, mc.buf[start:start+size])
|
||||
return fixups, uint64(mc.fixups.dataoff)
|
||||
}
|
||||
|
||||
func (mc *MachoContext) WriteEnabled() bool {
|
||||
return mc.file != nil
|
||||
}
|
||||
@ -235,12 +247,12 @@ func (mc *MachoContext) Parse(r *bufio.Reader) error {
|
||||
lcmd.Deserialize(mc, command_buf)
|
||||
mc.commands = append(mc.commands, lcmd)
|
||||
mc.linkedits = append(mc.linkedits, lcmd)
|
||||
if lcmd.Cmd() == LC_DYLD_CHAINED_FIXUPS {
|
||||
mc.fixups = lcmd
|
||||
}
|
||||
if lcmd.Cmd() == LC_DYLD_EXPORTS_TRIE {
|
||||
mc.exports = lcmd
|
||||
}
|
||||
if lcmd.Cmd() == LC_DYLD_CHAINED_FIXUPS {
|
||||
mc.fixups = lcmd
|
||||
}
|
||||
if lcmd.Cmd() == LC_DYLD_EXPORTS_TRIE {
|
||||
mc.exports = lcmd
|
||||
}
|
||||
break
|
||||
|
||||
case LC_SYMTAB:
|
||||
@ -248,12 +260,14 @@ func (mc *MachoContext) Parse(r *bufio.Reader) error {
|
||||
lcmd.Deserialize(mc, command_buf)
|
||||
mc.commands = append(mc.commands, lcmd)
|
||||
mc.symtab = lcmd
|
||||
break
|
||||
|
||||
case LC_DYSYMTAB:
|
||||
lcmd := new(DySymtab)
|
||||
lcmd.Deserialize(mc, command_buf)
|
||||
mc.commands = append(mc.commands, lcmd)
|
||||
mc.dysymtab = lcmd
|
||||
break
|
||||
|
||||
default:
|
||||
lcmd := new(LoadCmd)
|
||||
|
524
macho-go/pkg/ios/macho/objc.go
Normal file
524
macho-go/pkg/ios/macho/objc.go
Normal file
@ -0,0 +1,524 @@
|
||||
package macho
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
. "ios-wrapper/pkg/ios"
|
||||
)
|
||||
|
||||
// #include "fixups.h"
|
||||
import "C"
|
||||
|
||||
func (mc *MachoContext) CollectObjectiveCClasses() {
|
||||
var objc_const *bytes.Reader
|
||||
var objc_const_start uint64
|
||||
var objc_const_end uint64
|
||||
// var objc_methname []byte
|
||||
|
||||
for _, cmd := range mc.commands {
|
||||
if cmd.Cmd() == LC_MAIN {
|
||||
continue
|
||||
}
|
||||
if cmd.Cmd() != LC_SEGMENT_64 {
|
||||
continue
|
||||
}
|
||||
var segment = cmd.(*Segment64)
|
||||
|
||||
// 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 {
|
||||
for _, section := range segment.Sections() {
|
||||
buffer := make([]byte, section.Size())
|
||||
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_methlist")) == 0 {
|
||||
}
|
||||
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_methname")) == 0 {
|
||||
// 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_methtype")) == 0 {
|
||||
}
|
||||
}
|
||||
}
|
||||
if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__DATA_CONST")) == 0 {
|
||||
for _, section := range segment.Sections() {
|
||||
buffer := make([]byte, section.Size())
|
||||
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_nlclslist")) == 0 {
|
||||
}
|
||||
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_imageinfo")) == 0 {
|
||||
}
|
||||
}
|
||||
}
|
||||
if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__DATA")) == 0 {
|
||||
for _, section := range segment.Sections() {
|
||||
buffer := make([]byte, section.Size())
|
||||
mc.file.ReadAt(buffer, int64(section.Offset()))
|
||||
reader := bytes.NewReader(buffer)
|
||||
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_const")) == 0 {
|
||||
objc_const = reader
|
||||
objc_const_start = uint64(section.Offset())
|
||||
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_classrefs")) == 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 {
|
||||
// this section contains a series of class_t
|
||||
// struct _class_t {
|
||||
// struct _class_t *isa;
|
||||
// struct _class_t * const superclass;
|
||||
// void *cache;
|
||||
// IMP *vtable;
|
||||
// struct class_ro_t *ro;
|
||||
// };
|
||||
|
||||
for i := uint64(0); i < (section.Size() / uint64(mc.pointersize*5)); i++ {
|
||||
var isa uint64
|
||||
var superclass uint64
|
||||
var cache uint64
|
||||
var vtable uint64
|
||||
var ro uint64
|
||||
binary.Read(reader, mc.byteorder, &isa)
|
||||
binary.Read(reader, mc.byteorder, &superclass)
|
||||
binary.Read(reader, mc.byteorder, &cache)
|
||||
binary.Read(reader, mc.byteorder, &vtable)
|
||||
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)
|
||||
|
||||
var bind int
|
||||
var ret1 uint64
|
||||
var ret2 uint64
|
||||
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)),
|
||||
)
|
||||
|
||||
// is rebase, because ro points to objc_const
|
||||
// and address is in range
|
||||
if bind != 1 && ret1 >= objc_const_start && ret1 < objc_const_end {
|
||||
offset := ret1 - objc_const_start
|
||||
objc_const.Seek(int64(offset), 0)
|
||||
|
||||
// struct _class_ro_t {
|
||||
// uint32_t const flags;
|
||||
// uint32_t const instanceStart;
|
||||
// uint32_t const instanceSize;
|
||||
// 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;
|
||||
// };
|
||||
|
||||
var tmp uint32
|
||||
var ivarLayout uint64 // ptr
|
||||
var name uint64 // ptr
|
||||
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")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type SpecialSelector struct {
|
||||
idx uint
|
||||
name string
|
||||
}
|
||||
|
||||
func (sel *SpecialSelector) Idx() uint {
|
||||
return sel.idx
|
||||
}
|
||||
|
||||
func (sel *SpecialSelector) Name() string {
|
||||
return sel.name
|
||||
}
|
||||
|
||||
// collect the index and the name in selector list of special method names
|
||||
// these names are resolved by the dyld objc cache
|
||||
// through __dyld_get_objc_selector
|
||||
//
|
||||
// we currently have the following symbols guaranteed to be in this list:
|
||||
// - load
|
||||
// - retain
|
||||
//
|
||||
// besides special selectors, selectors of outside classes must also be
|
||||
// registered through the cache
|
||||
// selectors of outside classes are defined as not being referenced by
|
||||
// internal classes in __objc_data
|
||||
func (mc *MachoContext) CollectSpecialSelectors() []*SpecialSelector {
|
||||
var special_selectors []*SpecialSelector
|
||||
var methods []byte
|
||||
var methname_offset uint32
|
||||
|
||||
for _, cmd := range mc.commands {
|
||||
if cmd.Cmd() == LC_MAIN {
|
||||
continue
|
||||
}
|
||||
if cmd.Cmd() != LC_SEGMENT_64 {
|
||||
continue
|
||||
}
|
||||
var segment = cmd.(*Segment64)
|
||||
|
||||
if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__TEXT")) == 0 {
|
||||
for _, section := range segment.Sections() {
|
||||
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_methname")) == 0 {
|
||||
methname_offset = section.Offset()
|
||||
methods = make([]byte, section.Size())
|
||||
mc.file.ReadAt(methods, int64(section.Offset()))
|
||||
}
|
||||
}
|
||||
}
|
||||
if bytes.Compare(bytes.Trim(segment.SegName(), "\x00"), []byte("__DATA")) == 0 {
|
||||
for _, section := range segment.Sections() {
|
||||
if bytes.Compare(bytes.Trim(section.SectName(), "\x00"), []byte("__objc_selrefs")) == 0 {
|
||||
selectors_buffer := make([]byte, section.Size())
|
||||
mc.file.ReadAt(selectors_buffer, int64(section.Offset()))
|
||||
|
||||
buffer := bytes.NewReader(selectors_buffer)
|
||||
|
||||
for i := uint(0); i < uint(section.Size())/8; i++ {
|
||||
// this field is actually a Rebase
|
||||
// we assume that no rebase is needed
|
||||
// so everything sticks to its file offset
|
||||
var offset uint32
|
||||
binary.Read(buffer, mc.byteorder, &offset) // first 4 bytes is offset
|
||||
|
||||
var name_builder strings.Builder
|
||||
for j := uint32(0); ; j++ {
|
||||
c := methods[offset-methname_offset+j]
|
||||
if c == 0 {
|
||||
break
|
||||
}
|
||||
name_builder.WriteByte(c)
|
||||
}
|
||||
name := name_builder.String()
|
||||
if name == "load" {
|
||||
special_selectors = append(special_selectors, &SpecialSelector{
|
||||
idx: i,
|
||||
name: name,
|
||||
})
|
||||
}
|
||||
|
||||
binary.Read(buffer, mc.byteorder, &offset) // ignore rebase arguments
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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)) + 3)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// make __TEXT writable lol
|
||||
mc.file.Seek(0, 0)
|
||||
mc.file.WriteAt([]byte{0x7}, 0xa0)
|
||||
}
|
@ -72,7 +72,6 @@ func (mc *MachoContext) CollectSymbols() []*Symbol {
|
||||
var flags uint8
|
||||
var sect uint8
|
||||
var desc uint16
|
||||
var value32 uint32
|
||||
var value64 uint64
|
||||
|
||||
binary.Read(symtab_buffer, mc.byteorder, &strx)
|
||||
@ -83,6 +82,7 @@ func (mc *MachoContext) CollectSymbols() []*Symbol {
|
||||
binary.Read(symtab_buffer, mc.byteorder, &value64)
|
||||
} else {
|
||||
// always use value64
|
||||
var value32 uint32
|
||||
binary.Read(symtab_buffer, mc.byteorder, &value32)
|
||||
value64 = uint64(value32)
|
||||
}
|
||||
|
@ -17,18 +17,42 @@ message MachoInfo {
|
||||
uint64 value = 2; // address of the init function
|
||||
}
|
||||
|
||||
// iOS library rewrite these as opcodes and dyld processes
|
||||
// message LazySymbol {
|
||||
// string name = 1;
|
||||
// int32 dylib_ordinal = 2; // could be -1 -2
|
||||
// uint32 segment = 3;
|
||||
// uint32 segment_offset = 4;
|
||||
// }
|
||||
// right now we waste memory to store name/hash for all symbols
|
||||
// should consider compress them, dyld stores the index in list of LC_DYLIB
|
||||
message BindSymbol {
|
||||
string name = 1;
|
||||
string libname = 2;
|
||||
uint32 libhash = 3;
|
||||
uint32 segment = 4; // segment index
|
||||
uint64 offset = 5; // offset in segment
|
||||
}
|
||||
|
||||
message SymbolTable {
|
||||
uint32 symbolIndex = 1;
|
||||
uint32 segmentIndex = 2;
|
||||
uint32 offset = 3;
|
||||
}
|
||||
message LibraryImportedSymbols {
|
||||
uint32 libIndex = 1;
|
||||
uint32 nsymbols = 2;
|
||||
repeated SymbolTable symbols = 3;
|
||||
}
|
||||
|
||||
message AllImportedSymbols {
|
||||
repeated string libs = 1;
|
||||
repeated string symbols = 2;
|
||||
repeated LibraryImportedSymbols tables = 3;
|
||||
}
|
||||
|
||||
message Selector {
|
||||
uint32 idx = 1;
|
||||
string name = 2;
|
||||
}
|
||||
|
||||
PointerSize pointer_size = 1;
|
||||
uint64 image_base = 2;
|
||||
repeated InitPointer init_pointers = 3;
|
||||
// saved or read from header -> dyld_info -> lazyoff
|
||||
// uint64 lazy_symbol_address = 4;
|
||||
// repeated LazySymbol lazy_symbols = 5;
|
||||
uint64 main = 3;
|
||||
repeated InitPointer init_pointers = 4;
|
||||
AllImportedSymbols symbols = 5;
|
||||
repeated Selector special_selectors = 6;
|
||||
}
|
||||
|
2
research/custom_loader/.gitignore
vendored
2
research/custom_loader/.gitignore
vendored
@ -1 +1,3 @@
|
||||
out/
|
||||
coreutils-9.1/
|
||||
*.tar.xz
|
||||
|
123
research/custom_loader/a.mm
Normal file
123
research/custom_loader/a.mm
Normal file
@ -0,0 +1,123 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#include <objc/message.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void* sel_lookUpByName(const char* name);
|
||||
|
||||
|
||||
@interface Foo : NSObject
|
||||
@end
|
||||
|
||||
@implementation Foo
|
||||
- (void)bar {
|
||||
NSLog(@"Invoke instance method original bar in Foo");
|
||||
}
|
||||
|
||||
- (void)tobehijacked:(NSString*)input {
|
||||
NSLog(@"Invoke tobehijacked method %@ from Foo", input);
|
||||
}
|
||||
@end
|
||||
|
||||
@interface Bar : NSObject
|
||||
@end
|
||||
|
||||
@implementation Bar
|
||||
static int x;
|
||||
|
||||
+ (void)load {
|
||||
x = 1;
|
||||
printf("Invoke +load method\n");
|
||||
}
|
||||
|
||||
- (void)dummy {
|
||||
NSLog(@"Static value check after +load should be 1: x=%d", x);
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@interface FakeNSDateFormatter : NSDateFormatter {
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation FakeNSDateFormatter
|
||||
- (NSDate*)dateFromString:(NSString*)dateString {
|
||||
NSLog(@"Hijacked the NSDateFormatter");
|
||||
return [super dateFromString:dateString];
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
__attribute__((constructor)) static void
|
||||
hmmge(int argc, char** argv) {
|
||||
printf("Invoke C constructor\n");
|
||||
printf("Checking for arguments to be passed correctly\n");
|
||||
printf(" argc=%d\n", argc);
|
||||
for (int i = 0; i < argc; i++) {
|
||||
printf(" argv[%d]=%s\n", i, argv[i]);
|
||||
}
|
||||
NSLog(@"Using Objective-C in C constructor");
|
||||
NSLog(@"Test static Objective-C class is initialized and +load completed");
|
||||
Bar *bar = [[Bar alloc] init];
|
||||
[bar dummy];
|
||||
}
|
||||
|
||||
int main(int argc, const char * argv[], char* envp[]) {
|
||||
@autoreleasepool {
|
||||
NSLog(@"Invoke main()");
|
||||
|
||||
// Foo bar using Objective-C syntax
|
||||
Foo *foo = [[Foo alloc] init];
|
||||
[foo bar];
|
||||
|
||||
// Foo bar with selector and msgSend
|
||||
NSLog(@"Directly call \"bar\" %p through objc_msgSend %p with object foo %p", @selector(bar), objc_msgSend, foo);
|
||||
typedef void (*barfunc)(id, SEL);
|
||||
barfunc bar_ = (barfunc)&objc_msgSend;
|
||||
bar_(foo, @selector(bar));
|
||||
|
||||
NSString *dummyinput = @"dummy input";
|
||||
[foo tobehijacked:dummyinput];
|
||||
NSLog(@"The above invocation should be hijacked with input at %p", dummyinput);
|
||||
|
||||
NSString *dateString = @"2024-01-01T00:00:00.000Z";
|
||||
|
||||
// NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
|
||||
// [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZ"];
|
||||
// NSDate *date = [dateFormatter dateFromString:dateString];
|
||||
|
||||
// this is to test the idea for hooking,
|
||||
// basically, we create a middle-class inherits the class to be used
|
||||
//
|
||||
// example using NSDateFormatter:
|
||||
// - Create a FakeNSDateFormatter inherits NSDateFormatter
|
||||
// - Have an overloaded function that calls [super inherited]
|
||||
// - The internal struct class_t has superclass points to NSDateFormatter
|
||||
// FakeNSDateFormatter *dateFormatter = [[FakeNSDateFormatter alloc] init];
|
||||
// [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZ"];
|
||||
// NSDate *date = [dateFormatter dateFromString:dateString];
|
||||
// NSLog(@"Test hijacked/hooked Objective-C result %@", date);
|
||||
|
||||
NSLog(@"Selector \"dateFromString:\" using @selector %p", @selector(dateFromString:));
|
||||
NSLog(@"Selector \"bar:\" using @selector %p", @selector(bar:));
|
||||
NSLog(@"Selector \"dummy\" using @selector %p", @selector(dummy));
|
||||
|
||||
NSLog(@"[Bar dummy] implementation is at %p\n", [foo methodForSelector:@selector(bar:)]);
|
||||
}
|
||||
|
||||
printf("Selector lookup 'dateFromString:' addr: %p\n", sel_lookUpByName("dateFromString:"));
|
||||
printf("Selector lookup 'bar:' addr: %p\n", sel_lookUpByName("bar:"));
|
||||
printf("Selector lookup 'dummy' addr: %p\n", sel_lookUpByName("dummy"));
|
||||
|
||||
printf("Test if arguments are passed correctly to main(argc, argv, env)\n");
|
||||
printf(" argc=%d\n", argc);
|
||||
for (int i = 0; i < argc; i++) {
|
||||
printf(" argv[%d]=%s\n", i, argv[i]);
|
||||
}
|
||||
|
||||
while (*envp) {
|
||||
printf(" env[]=%s\n", *envp);
|
||||
envp++;
|
||||
}
|
||||
return 0;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
220
research/custom_loader/benchmark.py
Normal file
220
research/custom_loader/benchmark.py
Normal file
@ -0,0 +1,220 @@
|
||||
# import unittest
|
||||
import subprocess, resource
|
||||
import lief
|
||||
import os
|
||||
# import time
|
||||
import re
|
||||
|
||||
PATH = "./coreutils-9.1/src"
|
||||
|
||||
class Line:
|
||||
file = None
|
||||
@classmethod
|
||||
def init(cls):
|
||||
cls.file = open("out.csv", "w")
|
||||
cls.file.write("Name,File size(KiB),Number of symbols,Number of imports,Restoration time(s),Execution time(s),File size(KiB),Number of symbols,Number of imports,Restoration time(s),Execution time(s)\n")
|
||||
|
||||
def write(self):
|
||||
out = f"{self.name},{self.norm_size},{self.norm_symbols},{self.norm_imports},0,{self.norm_exe:.3f},{self.obf_size},{self.obf_symbols},{self.obf_imports},{self.restore:.3f},{self.obf_exe:.3f}\n"
|
||||
self.file.write(out)
|
||||
|
||||
def __init__(self, name: str) -> None:
|
||||
self.name = name
|
||||
self.norm_path = f"{PATH}/{name}"
|
||||
self.obf_path = f"{PATH}/{name}-dir/out/{name}-fixed"
|
||||
|
||||
def numOfSymbols(sym: list) -> int:
|
||||
count = 0
|
||||
for i in sym:
|
||||
if i.type != 0:
|
||||
count += 1
|
||||
return count
|
||||
|
||||
def numOfImports(imp: list) -> int:
|
||||
count = 0
|
||||
for i in imp:
|
||||
if i.name != "":
|
||||
count += 1
|
||||
return count
|
||||
|
||||
def setup(binpath: str, libpath: str = None):
|
||||
if os.path.isdir("/tmp/test"):
|
||||
os.system("rm -rf /tmp/test")
|
||||
os.mkdir("/tmp/test")
|
||||
# if libpath:
|
||||
# os.system(f"cp {binpath} {libpath} ./test_file.txt /tmp/test")
|
||||
# else:
|
||||
# os.system(f"cp {binpath} ./test_file.txt /tmp/test")
|
||||
os.system("cp ./test_file.txt /tmp/test")
|
||||
|
||||
|
||||
# class Benchmark(unittest.TestCase):
|
||||
def info(l: Line):
|
||||
l.norm_size = int(os.path.getsize(l.norm_path) / 1024)
|
||||
l.obf_size = int(os.path.getsize(l.obf_path) / 1024)
|
||||
|
||||
norm = lief.parse(l.norm_path)
|
||||
obf = lief.parse(l.obf_path)
|
||||
|
||||
l.norm_symbols = numOfSymbols(norm.symbols)
|
||||
l.obf_symbols = numOfSymbols(obf.symbols)
|
||||
l.norm_imports = numOfImports(norm.imported_functions)
|
||||
l.obf_imports = numOfImports(obf.imported_functions)
|
||||
|
||||
def run(l, cmd):
|
||||
print(f"[+] Running benchmark for {l.name} with command \"{cmd}\"")
|
||||
cmd = cmd.split(" ")
|
||||
setup(l.norm_path)
|
||||
start = resource.getrusage(resource.RUSAGE_CHILDREN).ru_utime
|
||||
p1 = subprocess.run([l.norm_path] + cmd, capture_output=True)
|
||||
end = resource.getrusage(resource.RUSAGE_CHILDREN).ru_utime
|
||||
l.norm_exe = end - start
|
||||
|
||||
setup(l.obf_path)
|
||||
start = resource.getrusage(resource.RUSAGE_CHILDREN).ru_utime
|
||||
p2 = subprocess.run([l.obf_path] + cmd, capture_output=True)
|
||||
end = resource.getrusage(resource.RUSAGE_CHILDREN).ru_utime
|
||||
if p2.returncode == -11:
|
||||
print(f"\033[91m[!] Error in {l.name} (segfault)\033[0m")
|
||||
Line.file.write(f"{l.name},segfault\n")
|
||||
return
|
||||
# print(p2.stdout)
|
||||
match = re.search(b"restoration library time: ([0-9.]+)", p2.stdout)
|
||||
l.restore = float(match.group(1))
|
||||
l.obf_exe = end - start
|
||||
if p2.returncode != p1.returncode:
|
||||
print(f"\033[91m[!] Error in {l.name} (diff exit code)\033[0m")
|
||||
Line.file.write(f"{l.name},exit code diff\n")
|
||||
return
|
||||
l.write()
|
||||
# if p1.stdout in p2.stdout:
|
||||
# l.write()
|
||||
# else:
|
||||
# print(f"\033[91m[!] Error in {l.name} (stdout diff)\033[0m")
|
||||
# print(p1.stdout)
|
||||
# print("-"*20)
|
||||
# print(p2.stdout)
|
||||
|
||||
# Line.file.write(f"{l.name},stdout diff\n")
|
||||
|
||||
|
||||
def test_basic(name, cmd):
|
||||
l = Line(name)
|
||||
info(l)
|
||||
run(l, cmd)
|
||||
|
||||
test_data = [
|
||||
("md5sum", "/tmp/test/test_file.txt"),
|
||||
("split", "/tmp/test/test_file.txt /tmp/test/out"),
|
||||
("cat", "/tmp/test/test_file.txt"),
|
||||
("mkfifo", "/tmp/test/a"),
|
||||
("shuf", "--random-source=/tmp/test/test_file.txt /tmp/test/test_file.txt"),
|
||||
("pathchk", "/tmp/test/test_file.txt"),
|
||||
("expand", "/tmp/test/test_file.txt"),
|
||||
("tty", ""),
|
||||
("basename", "/tmp/test/test_file.txt"),
|
||||
("nice", ""),
|
||||
("truncate", "-s 0 /tmp/test/test_file.txt"),
|
||||
("echo", "hello"),
|
||||
("du", "-h /tmp"),
|
||||
("ptx", "/tmp/test/test_file.txt"),
|
||||
("join", "/tmp/test/test_file.txt /tmp/test/test_file.txt"),
|
||||
("df", "--help"),
|
||||
("pwd", ""),
|
||||
("test", "-f /tmp/test_file.txt"),
|
||||
("csplit", "/tmp/test_file.txt 1"),
|
||||
("sort", "/tmp/test_file.txt"),
|
||||
("whoami", ""),
|
||||
("touch", "/tmp/test/a"),
|
||||
("unlink", "/tmp/test/test_file.txt"),
|
||||
("b2sum", "/tmp/test/test_file.txt"),
|
||||
("sleep", "1"),
|
||||
("fmt", "/tmp/test/test_file.txt"),
|
||||
("stty", ""),
|
||||
("logname", ""),
|
||||
("chgrp", "root /tmp/test/test_file.txt"),
|
||||
("printenv", ""),
|
||||
("seq", "1 10"),
|
||||
("uname", ""),
|
||||
("sha224sum", "/tmp/test/test_file.txt"),
|
||||
("od", "/tmp/test/test_file.txt"),
|
||||
("date", ""),
|
||||
("base64", "/tmp/test/test_file.txt"),
|
||||
("realpath", "/tmp/test/test_file.txt"),
|
||||
("readlink", "/tmp/test/test_file.txt"),
|
||||
("dircolors", ""),
|
||||
("timeout", "1s sleep 2"),
|
||||
("tac", "/tmp/test/test_file.txt"),
|
||||
("numfmt", "1000"),
|
||||
("wc", "/tmp/test/test_file.txt"),
|
||||
("basenc", "/tmp/test/test_file.txt"),
|
||||
("comm", "/tmp/test/test_file.txt /tmp/test/test_file.txt"),
|
||||
("nproc", ""),
|
||||
("expr", "1"),
|
||||
("cksum", "/tmp/test/test_file.txt"),
|
||||
("printf", "hello"),
|
||||
("groups", ""),
|
||||
("chcon", "-t s0 /tmp/test/test_file.txt"),
|
||||
("factor", "10"),
|
||||
("tail", "-n 1 /tmp/test/test_file.txt"),
|
||||
("env", ""),
|
||||
("pr", "/tmp/test/test_file.txt"),
|
||||
("head", "-n 1 /tmp/test/test_file.txt"),
|
||||
("kill", "$$"),
|
||||
("uniq", "/tmp/test/test_file.txt"),
|
||||
("stat", "-f /tmp/test/test_file.txt"),
|
||||
("link", "/tmp/test/test_file.txt /tmp/test/test_file.txt"),
|
||||
# ("make-prime-list", "10"), # build fail
|
||||
("sum", "/tmp/test/test_file.txt"),
|
||||
("tsort", "/tmp/test/test_file.txt"),
|
||||
# ("extract-magic", "/tmp/test/test_file.txt"), build fail
|
||||
("mknod", "/tmp/test/test_file.txt"),
|
||||
("users", ""),
|
||||
("dd", "--help"),
|
||||
("who", ""),
|
||||
("sha1sum", "/tmp/test/test_file.txt"),
|
||||
("mktemp", ""),
|
||||
("cut", "-c 1 /tmp/test/test_file.txt"),
|
||||
("sha256sum", "/tmp/test/test_file.txt"),
|
||||
("dir", "/tmp/test/test_file.txt"),
|
||||
("mkdir", "/tmp/test/a"),
|
||||
("nl", "/tmp/test/test_file.txt"),
|
||||
("ginstall", "/tmp/test/test_file.txt /tmp/test/test_file.txt"),
|
||||
("shred", "-u /tmp/test/test_file.txt"),
|
||||
("fold", "-w 10 /tmp/test/test_file.txt"),
|
||||
("rmdir", "/tmp/test/a"),
|
||||
("sha384sum", "/tmp/test/test_file.txt"),
|
||||
("mv", "/tmp/test/test_file.txt /tmp/test/test_file.txt"),
|
||||
("dirname", "/tmp/test/test_file.txt"),
|
||||
("id", ""),
|
||||
("base32", "/tmp/test/test_file.txt"),
|
||||
("pinky", ""),
|
||||
("ln", "/tmp/test/test_file.txt /tmp/test/test_file.txt"),
|
||||
("hostid", ""),
|
||||
("chroot", "/tmp/test /tmp/test/test_file.txt"),
|
||||
("ls", "/tmp/test"),
|
||||
("true", ""),
|
||||
("cp", "/tmp/test/test_file.txt /tmp/test/test_file.txt"),
|
||||
("sync", ""),
|
||||
("yes", "--help"),
|
||||
("unexpand", "/tmp/test/test_file.txt"),
|
||||
("chown", "root /tmp/test/test_file.txt"),
|
||||
("getlimits", ""),
|
||||
("chmod", "777 /tmp/test/test_file.txt"),
|
||||
("uptime", ""),
|
||||
("rm", "/tmp/test/test_file.txt"),
|
||||
("vdir", "/tmp/test"),
|
||||
("false", ""),
|
||||
("sha512sum", "/tmp/test/test_file.txt"),
|
||||
("tr", "a b /tmp/test/test_file.txt"),
|
||||
("paste", "/tmp/test/test_file.txt /tmp/test/test_file.txt"),
|
||||
("nohup", "sleep 1")
|
||||
]
|
||||
|
||||
# core="tee md5sum split cat shuf mkfifo pathchk runcon expand tty basename nice truncate echo du ptx join df pwd test csplit sort whoami touch dcgen unlink b2sum sleep fmt stty logname chgrp printenv seq uname sha224sum od date base64 realpath readlink dircolors timeout tac numfmt wc basenc comm nproc expr stdbuf cksum printf groups chcon factor tail env pr head kill uniq stat link make-prime-list sum tsort extract-magic mknod users dd who sha1sum mktemp cut sha256sum dir mkdir nl ginstall shred fold rmdir sha384sum mv dirname id base32 pinky ln hostid chroot ls true cp sync yes unexpand chown getlimits chmod uptime rm vdir false sha512sum tr paste nohup"
|
||||
|
||||
if __name__ == "__main__":
|
||||
Line.init()
|
||||
for name, cmd in test_data:
|
||||
test_basic(name, cmd)
|
||||
# unittest.main()
|
@ -1,9 +1,10 @@
|
||||
# set -ex
|
||||
|
||||
set -e
|
||||
clear
|
||||
VERSION=${1:-14}
|
||||
METH=${2}
|
||||
OUT=./out
|
||||
LOGIC=2
|
||||
|
||||
LOGIC=3
|
||||
make -C ../../macho-go
|
||||
mkdir -p $OUT
|
||||
|
||||
echo "using mach-o version $VERSION"
|
||||
@ -14,6 +15,21 @@ else
|
||||
echo "Resulting binary uses LEGACY symbol resolver"
|
||||
fi
|
||||
|
||||
cat <<'fly'
|
||||
______
|
||||
_\ _~-\___
|
||||
= = ==(____AA____D
|
||||
\_____\___________________,-~~~~~~~`-.._
|
||||
/ o O o o o o O O o o o o o o O o |\_
|
||||
`~-.__ ___..----.. )
|
||||
`---~~\___________/------------`````
|
||||
= ===(_________D
|
||||
fly
|
||||
|
||||
# this is a joke for those who knows
|
||||
# https://www.blackhat.com/presentations/bh-dc-09/Iozzo/BlackHat-DC-09-Iozzo-let-your-mach0-fly-whitepaper.pdf
|
||||
echo "make your Mach-O fly"
|
||||
|
||||
if [[ $LOGIC -eq 0 ]]
|
||||
then
|
||||
|
||||
@ -39,21 +55,88 @@ clang++ -mmacosx-version-min=$VERSION -o $OUT/libc.dylib -shared c.cc
|
||||
# create our dummy lib first
|
||||
clang++ -mmacosx-version-min=$VERSION -o $OUT/libb.dylib -shared -Wl,-reexport_library out/libc.dylib dummy.cc
|
||||
# build a references libb
|
||||
clang++ -mmacosx-version-min=$VERSION -o $OUT/a -L"./out" -lb a.cc
|
||||
clang++ -mmacosx-version-min=$VERSION -o $OUT/a -L"./out" -Xlinker -no_data_const -lb a.cc
|
||||
|
||||
# extract symbols from a
|
||||
../../macho-go/bin/ios-wrapper remove-imports $OUT/a -o $OUT/a > $OUT/b.h
|
||||
../../macho-go/bin/ios-wrapper pepe -o $OUT/a-fixed -b $OUT/b.bcell --remove-imports --remove-exports --remove-symbol-table $OUT/a
|
||||
../../macho-go/bin/ios-wrapper bcell2header -b $OUT/b.bcell -o $OUT/b.h
|
||||
# build libb with symbols extracted from a
|
||||
clang++ -mmacosx-version-min=$VERSION -o $OUT/libb.dylib -shared -Wl,-reexport_library out/libc.dylib b.cc
|
||||
|
||||
out/a
|
||||
codesign --force --deep -s - $OUT/a-fixed
|
||||
$OUT/a-fixed
|
||||
|
||||
elif [[ $LOGIC -eq 3 ]]
|
||||
then
|
||||
# remove imports test
|
||||
|
||||
# libc to test reexport custom lib
|
||||
clang++ -mmacosx-version-min=$VERSION -o $OUT/libc.dylib -shared c.cc
|
||||
|
||||
# create our dummy lib first
|
||||
clang++ -mmacosx-version-min=$VERSION -o $OUT/libb.dylib -shared -Wl,-reexport_library out/libc.dylib dummy.cc
|
||||
# build a references libb
|
||||
clang -fobjc-arc -ObjC -mmacosx-version-min=$VERSION -o $OUT/a a.mm
|
||||
|
||||
# extract symbols from a
|
||||
# ../../macho-go/bin/ios-wrapper pepe -o $OUT/a-fixed -b $OUT/b.bcell --remove-imports --remove-exports --remove-symbol-table --keep-imports _printf $OUT/a
|
||||
../../macho-go/bin/ios-wrapper pepe -o $OUT/a-fixed -b $OUT/b.bcell --dylibs=./out/libb.dylib --remove-imports --remove-exports --remove-symbol-table --remove-others $OUT/a
|
||||
../../macho-go/bin/ios-wrapper bcell2header -b $OUT/b.bcell -o $OUT/b.h
|
||||
|
||||
if [ "$METH" = "METH1" ]; then
|
||||
# build libb with symbols extracted from a
|
||||
clang++ -D $METH -mmacosx-version-min=$VERSION -o $OUT/libb.dylib -shared -Wl,-reexport_library out/libc.dylib b.cc
|
||||
# ../../macho-go/bin/ios-wrapper pepe -o $OUT/libb.dylib -b $OUT/libb.bcell --remove-imports --remove-exports --remove-symbol-table --remove-others --keep-imports _dyld_get_sdk_version --keep-imports _malloc --keep-imports ___stack_chk_guard --keep-imports _printf $OUT/libb.dylib
|
||||
|
||||
elif [ "$METH" = "METH3" ]; then
|
||||
clang -mmacosx-version-min=$VERSION -fobjc-arc -ObjC -c -o $OUT/hooking.o hooking.mm
|
||||
clang++ -mmacosx-version-min=$VERSION -D $METH -c -o $OUT/b.o b.cc
|
||||
clang++ -fobjc-arc -ObjC -shared -Wl,-reexport_library -o $OUT/libb.dylib $OUT/b.o $OUT/hooking.o
|
||||
fi
|
||||
|
||||
# resign
|
||||
codesign --force --deep -s - $OUT/a-fixed
|
||||
codesign --force --deep -s - $OUT/libb.dylib
|
||||
|
||||
# export OBJC_PRINT_LOAD_METHODS=1
|
||||
# export OBJC_PRINT_CLASS_SETUP=1
|
||||
$OUT/a-fixed
|
||||
# unset OBJC_PRINT_LOAD_METHODS
|
||||
# unset OBJC_PRINT_CLASS_SETUP
|
||||
|
||||
else
|
||||
|
||||
# dummy test build
|
||||
# remove imports test
|
||||
|
||||
clang++ -mmacosx-version-min=$VERSION -o $OUT/libc.dylib -shared c.cc
|
||||
clang++ -mmacosx-version-min=$VERSION -o $OUT/libb.dylib -shared -Wl,-reexport_library out/libc.dylib b.cc
|
||||
clang++ -mmacosx-version-min=$VERSION -o $OUT/a -L"./out" -lb a.cc
|
||||
# test rpath
|
||||
clang++ -mmacosx-version-min=$VERSION -o $OUT/libc.dylib -install_name @rpath/libc.dylib -shared c.cc
|
||||
# linked with libd
|
||||
# with rpath = $OUT
|
||||
clang++ -mmacosx-version-min=$VERSION -Xlinker -no_data_const -o $OUT/a \
|
||||
-rpath ./heheeeekkkkkkk \
|
||||
-rpath $OUT \
|
||||
-rpath ./hehe \
|
||||
-rpath ./haha \
|
||||
$OUT/libc.dylib a.cc \
|
||||
|
||||
|
||||
# extract symbols from a
|
||||
../../macho-go/bin/ios-wrapper pepe -o $OUT/a-fixed -b $OUT/b.bcell -l out/libb.dylib --remove-imports --remove-exports $OUT/a
|
||||
|
||||
# build restoration libb with symbols extracted from a
|
||||
../../macho-go/bin/ios-wrapper bcell2header -b $OUT/b.bcell -o $OUT/b.h
|
||||
clang++ -mmacosx-version-min=$VERSION -o $OUT/libb.dylib -shared b.cc
|
||||
|
||||
# obfuscate libb (bugged)
|
||||
# ../../macho-go/bin/ios-wrapper pepe -o $OUT/libb.dylib -b $OUT/libb.bcell --remove-imports --remove-exports --keep-imports _dyld_get_sdk_version --keep-imports _malloc --keep-imports _printf --keep-imports ___stack_chk_guard $OUT/libb.dylib
|
||||
|
||||
# resign
|
||||
codesign --force --deep -s - $OUT/a-fixed
|
||||
codesign --force --deep -s - $OUT/libb.dylib
|
||||
|
||||
# export OBJC_PRINT_LOAD_METHODS=1
|
||||
# export OBJC_PRINT_CLASS_SETUP=1
|
||||
$OUT/a-fixed
|
||||
# unset OBJC_PRINT_LOAD_METHODS
|
||||
# unset OBJC_PRINT_CLASS_SETUP
|
||||
fi
|
||||
|
31
research/custom_loader/hooking.mm
Normal file
31
research/custom_loader/hooking.mm
Normal file
@ -0,0 +1,31 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#include <objc/message.h>
|
||||
#include <stdio.h>
|
||||
|
||||
@interface Hehe : NSObject
|
||||
- (void)bar;
|
||||
- (void)tobehijacked:(NSString*)input;
|
||||
@end
|
||||
|
||||
@interface Hooker : Hehe
|
||||
@end
|
||||
|
||||
@implementation Hehe
|
||||
- (void)bar {
|
||||
NSLog(@"Invoke instance method %@", self);
|
||||
}
|
||||
- (void)tobehijacked:(NSString*)input {
|
||||
NSLog(@"Invoke tobehijacked method %@", input);
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation Hooker
|
||||
- (void)tobehijacked:(NSString*)input {
|
||||
NSLog(@"Hijacked tobehijacked method %@ from Hooker", input);
|
||||
}
|
||||
|
||||
- (void)bar {
|
||||
[super bar];
|
||||
}
|
||||
|
||||
@end
|
11
research/custom_loader/install.sh
Normal file
11
research/custom_loader/install.sh
Normal file
@ -0,0 +1,11 @@
|
||||
curl -LO https://ftp.gnu.org/gnu/coreutils/coreutils-9.1.tar.xz
|
||||
|
||||
tar -xvf coreutils-9.1.tar.xz
|
||||
|
||||
cd coreutils-9.1
|
||||
|
||||
./configure
|
||||
make
|
||||
|
||||
rm coreutils-9.1.tar.xz
|
||||
|
27
research/custom_loader/obfuscate.sh
Executable file
27
research/custom_loader/obfuscate.sh
Executable file
@ -0,0 +1,27 @@
|
||||
rm -r coreutils-9.1/src/*-dir
|
||||
|
||||
core="tee md5sum split cat shuf mkfifo pathchk runcon expand tty basename nice truncate echo du ptx join df pwd test csplit sort whoami touch dcgen unlink b2sum sleep fmt stty logname chgrp printenv seq uname sha224sum od date base64 realpath readlink dircolors timeout tac numfmt wc basenc comm nproc expr stdbuf cksum printf groups chcon factor tail env pr head kill uniq stat link make-prime-list sum tsort extract-magic mknod users dd who sha1sum mktemp cut sha256sum dir mkdir nl ginstall shred fold rmdir sha384sum mv dirname id base32 pinky ln hostid chroot ls true cp sync yes unexpand chown getlimits chmod uptime rm vdir false sha512sum tr paste nohup"
|
||||
for i in $core; do
|
||||
echo "[+] $i"
|
||||
WD=coreutils-9.1/src/${i}-dir
|
||||
OUT=$WD/out
|
||||
mkdir -p $WD
|
||||
mkdir -p $OUT
|
||||
|
||||
cp b.cc $WD
|
||||
|
||||
{
|
||||
clang++ -mmacosx-version-min=14 -o $OUT/libb.dylib -shared dummy.cc
|
||||
|
||||
../../macho-go/bin/ios-wrapper pepe -o $OUT/${i}-fixed -b $OUT/b.bcell --dylibs=./$OUT/libb.dylib --remove-imports --remove-exports --remove-symbol-table --remove-others coreutils-9.1/src/${i}
|
||||
../../macho-go/bin/ios-wrapper bcell2header -b $OUT/b.bcell -o $OUT/b.h
|
||||
|
||||
clang++ -mmacosx-version-min=14 -o $OUT/libb.dylib -shared -Wl,-reexport_library out/libc.dylib $WD/b.cc
|
||||
|
||||
codesign --force --deep -s - $OUT/${i}-fixed
|
||||
codesign --force --deep -s - $OUT/libb.dylib
|
||||
chmod +x $OUT/${i}-fixed
|
||||
} > /dev/null 2>&1
|
||||
done
|
||||
|
||||
|
1375
research/custom_loader/objc-symtab.txt
Normal file
1375
research/custom_loader/objc-symtab.txt
Normal file
File diff suppressed because it is too large
Load Diff
104
research/custom_loader/out_x86_64.csv
Normal file
104
research/custom_loader/out_x86_64.csv
Normal file
@ -0,0 +1,104 @@
|
||||
Name,File size(KiB),Number of symbols,Number of imports,Restoration time(s),Execution time(s),File size(KiB),Number of symbols,Number of imports,Restoration time(s),Execution time(s)
|
||||
md5sum,segfault
|
||||
split,150,1321,101,0,0.003,169,0,4,0.002,0.005
|
||||
cat,124,916,84,0,0.003,143,0,4,0.002,0.005
|
||||
mkfifo,121,819,78,0,0.003,140,0,4,0.002,0.004
|
||||
shuf,149,1255,91,0,0.004,168,0,4,0.002,0.005
|
||||
pathchk,121,791,79,0,0.003,139,0,4,0.001,0.004
|
||||
expand,123,904,82,0,0.003,142,0,4,0.002,0.005
|
||||
tty,120,773,77,0,0.003,139,0,4,0.001,0.004
|
||||
basename,121,805,74,0,0.003,140,0,4,0.001,0.004
|
||||
nice,121,802,79,0,0.003,139,0,4,0.002,0.004
|
||||
truncate,123,868,81,0,0.003,141,0,4,0.002,0.005
|
||||
echo,118,710,67,0,0.003,137,0,4,0.001,0.004
|
||||
du,321,2323,130,0,0.003,341,0,4,0.003,0.005
|
||||
ptx,257,1763,111,0,0.031,277,0,4,0.002,0.038
|
||||
join,146,1164,90,0,0.013,165,0,4,0.002,0.018
|
||||
df,197,1797,102,0,0.003,217,0,4,0.002,0.005
|
||||
pwd,122,861,86,0,0.003,141,0,4,0.002,0.004
|
||||
test,121,826,71,0,0.003,140,0,4,0.002,0.004
|
||||
csplit,235,1559,106,0,0.003,255,0,4,0.002,0.005
|
||||
sort,239,2154,146,0,0.004,258,0,5,0.003,0.007
|
||||
whoami,120,790,77,0,0.003,139,0,4,0.002,0.004
|
||||
touch,187,1406,108,0,0.003,206,0,4,0.003,0.006
|
||||
unlink,121,817,77,0,0.003,140,0,4,0.002,0.004
|
||||
b2sum,141,956,88,0,0.004,160,0,5,0.002,0.005
|
||||
sleep,123,848,79,0,0.003,141,0,4,0.002,0.005
|
||||
fmt,139,908,81,0,0.007,158,0,4,0.003,0.010
|
||||
stty,158,1023,89,0,0.003,177,0,4,0.002,0.005
|
||||
logname,120,789,76,0,0.003,139,0,4,0.002,0.004
|
||||
chgrp,171,1433,105,0,0.003,190,0,4,0.003,0.006
|
||||
printenv,120,769,75,0,0.003,138,0,4,0.001,0.004
|
||||
seq,139,887,83,0,0.003,158,0,4,0.002,0.004
|
||||
uname,120,786,76,0,0.003,139,0,4,0.001,0.004
|
||||
sha224sum,segfault
|
||||
od,161,1156,90,0,0.022,181,0,4,0.002,0.023
|
||||
date,195,1178,95,0,0.003,215,0,4,0.002,0.005
|
||||
base64,122,856,81,0,0.003,141,0,4,0.002,0.005
|
||||
realpath,145,1078,81,0,0.003,164,0,4,0.002,0.005
|
||||
readlink,144,1042,81,0,0.003,163,0,4,0.002,0.005
|
||||
dircolors,159,1012,96,0,0.003,178,0,4,0.002,0.004
|
||||
timeout,124,888,95,0,0.006,142,0,4,0.002,0.007
|
||||
tac,216,1387,97,0,0.003,235,0,4,0.002,0.005
|
||||
numfmt,160,1079,92,0,0.003,179,0,4,0.002,0.005
|
||||
wc,146,1104,95,0,0.004,165,0,4,0.002,0.006
|
||||
basenc,145,1163,81,0,0.003,164,0,4,0.003,0.005
|
||||
comm,126,948,84,0,0.004,144,0,4,0.002,0.006
|
||||
nproc,121,817,79,0,0.003,140,0,4,0.002,0.004
|
||||
expr,232,1436,102,0,0.003,252,0,4,0.002,0.004
|
||||
cksum,187,1436,115,0,0.004,206,0,5,0.002,0.006
|
||||
printf,122,853,74,0,0.003,141,0,4,0.001,0.004
|
||||
groups,122,843,82,0,0.003,141,0,4,0.002,0.005
|
||||
chcon,169,1380,96,0,0.003,188,0,4,0.002,0.005
|
||||
factor,183,1284,115,0,0.003,202,0,4,0.003,0.006
|
||||
tail,165,1192,95,0,0.003,184,0,4,0.003,0.006
|
||||
env,142,1007,92,0,0.003,161,0,4,0.002,0.004
|
||||
pr,185,1370,101,0,0.005,204,0,4,0.002,0.007
|
||||
head,142,994,81,0,0.003,161,0,4,0.002,0.004
|
||||
kill,121,802,81,0,0.003,140,0,4,0.002,0.004
|
||||
uniq,142,987,86,0,0.003,161,0,4,0.002,0.006
|
||||
stat,209,1561,108,0,0.003,228,0,4,0.002,0.005
|
||||
link,121,818,78,0,0.003,140,0,4,0.002,0.005
|
||||
sum,140,923,86,0,0.003,159,0,4,0.002,0.005
|
||||
tsort,123,891,83,0,0.008,142,0,4,0.003,0.015
|
||||
mknod,123,875,81,0,0.003,142,0,4,0.002,0.005
|
||||
users,121,818,81,0,0.003,140,0,4,0.002,0.004
|
||||
dd,165,1284,101,0,0.003,184,0,5,0.002,0.005
|
||||
who,142,972,97,0,0.003,161,0,4,0.002,0.004
|
||||
sha1sum,segfault
|
||||
mktemp,126,960,86,0,0.003,145,0,4,0.002,0.004
|
||||
cut,140,903,88,0,0.003,159,0,4,0.002,0.005
|
||||
sha256sum,segfault
|
||||
dir,281,2551,148,0,0.003,301,0,5,0.003,0.005
|
||||
mkdir,144,1019,92,0,0.003,163,0,4,0.002,0.005
|
||||
nl,214,1377,92,0,0.004,233,0,4,0.002,0.006
|
||||
ginstall,239,2490,161,0,0.003,259,0,4,0.004,0.006
|
||||
shred,151,1215,109,0,0.003,170,0,4,0.002,0.005
|
||||
fold,122,843,80,0,0.004,141,0,4,0.002,0.005
|
||||
rmdir,123,863,83,0,0.003,142,0,4,0.002,0.005
|
||||
sha384sum,segfault
|
||||
mv,238,2461,149,0,0.003,258,0,4,0.004,0.007
|
||||
dirname,121,798,74,0,0.003,139,0,4,0.001,0.004
|
||||
id,141,940,88,0,0.003,160,0,4,0.002,0.005
|
||||
base32,122,861,81,0,0.003,141,0,4,0.002,0.005
|
||||
pinky,125,929,98,0,0.003,144,0,4,0.002,0.005
|
||||
ln,179,1589,111,0,0.003,198,0,4,0.003,0.006
|
||||
hostid,120,783,75,0,0.003,139,0,4,0.001,0.004
|
||||
chroot,148,1170,99,0,0.003,167,0,4,0.003,0.006
|
||||
ls,281,2551,148,0,0.003,301,0,5,0.003,0.006
|
||||
true,118,708,65,0,0.003,137,0,4,0.001,0.004
|
||||
cp,233,2273,148,0,0.003,253,0,4,0.003,0.006
|
||||
sync,121,809,80,0,0.003,140,0,4,0.002,0.004
|
||||
yes,121,801,75,0,0.003,140,0,4,0.003,0.008
|
||||
unexpand,123,907,82,0,0.003,142,0,4,0.003,0.009
|
||||
chown,172,1449,107,0,0.003,191,0,4,0.003,0.006
|
||||
getlimits,137,808,78,0,0.004,156,0,4,0.003,0.008
|
||||
chmod,165,1245,92,0,0.003,184,0,4,0.002,0.004
|
||||
uptime,140,924,93,0,0.003,159,0,5,0.003,0.009
|
||||
rm,171,1417,98,0,0.003,190,0,5,0.003,0.008
|
||||
vdir,281,2551,148,0,0.003,301,0,5,0.005,0.011
|
||||
false,118,708,65,0,0.003,137,0,4,0.003,0.008
|
||||
sha512sum,segfault
|
||||
tr,142,1049,83,0,0.003,161,0,4,0.003,0.009
|
||||
paste,122,880,77,0,0.004,141,0,4,0.003,0.009
|
||||
nohup,123,856,82,0,0.005,142,0,4,0.003,0.012
|
|
@ -0,0 +1,57 @@
|
||||
struct class {
|
||||
class* isa;
|
||||
class* super;
|
||||
struct {
|
||||
void* bucket;
|
||||
void* preoptimize;
|
||||
} cache;
|
||||
uint64_t cache_bits;
|
||||
}
|
||||
|
||||
realizeClassWithoutSwift(class* cls, class* previous) {
|
||||
// x0 = cls
|
||||
// x1 = previous
|
||||
|
||||
x19 = x0
|
||||
if (!x0) {
|
||||
return
|
||||
}
|
||||
|
||||
x28 = x1
|
||||
x8 = *x19 - 1
|
||||
|
||||
if (x8 < 0xf) {
|
||||
} else {
|
||||
x8 = x19
|
||||
x16 = *(x8 + 0x20)
|
||||
x9 = x16
|
||||
// strip pointer auth x9
|
||||
x9 = x9 & 0x7ffffffffff8
|
||||
w9 = *x9
|
||||
|
||||
if (w9 & 0x1f) {
|
||||
x17 = x8
|
||||
x17 = 0xc93a << 48
|
||||
// authenticate x16 x17
|
||||
x17 = x16
|
||||
// strip pointer auth x17
|
||||
if (x16 != x17) {
|
||||
throw
|
||||
}
|
||||
x20 = x16 & 0x7ffffffffff8
|
||||
x0 = x20
|
||||
x0 = malloc_size(x0)
|
||||
if (x0 > 0x1f) {
|
||||
return
|
||||
}
|
||||
|
||||
} else {
|
||||
w20 = -0x7ff80000
|
||||
x21 = x19 + w20
|
||||
x0 = x21
|
||||
x0 = safe_ro(x0)
|
||||
x8 = *x0 & 0x1
|
||||
}
|
||||
|
||||
}
|
||||
}
|
657
research/custom_loader/realizeClassWithoutSwift.txt
Normal file
657
research/custom_loader/realizeClassWithoutSwift.txt
Normal file
@ -0,0 +1,657 @@
|
||||
libobjc.A.dylib`realizeClassWithoutSwift:
|
||||
0x193755cac <+0>: pacibsp
|
||||
0x193755cb0 <+4>: sub sp, sp, #0xc0
|
||||
0x193755cb4 <+8>: stp x28, x27, [sp, #0x60]
|
||||
0x193755cb8 <+12>: stp x26, x25, [sp, #0x70]
|
||||
0x193755cbc <+16>: stp x24, x23, [sp, #0x80]
|
||||
0x193755cc0 <+20>: stp x22, x21, [sp, #0x90]
|
||||
0x193755cc4 <+24>: stp x20, x19, [sp, #0xa0]
|
||||
0x193755cc8 <+28>: stp x29, x30, [sp, #0xb0]
|
||||
0x193755ccc <+32>: add x29, sp, #0xb0
|
||||
0x193755cd0 <+36>: mov x19, x0
|
||||
0x193755cd4 <+40>: cbz x0, 0x193756550 ; <+2212>
|
||||
0x193755cd8 <+44>: mov x28, x1
|
||||
0x193755cdc <+48>: ldr x8, [x19]
|
||||
0x193755ce0 <+52>: sub x8, x8, #0x1
|
||||
0x193755ce4 <+56>: cmp x8, #0xf
|
||||
0x193755ce8 <+60>: b.lo 0x193755d08 ; <+92>
|
||||
0x193755cec <+64>: mov x8, x19
|
||||
0x193755cf0 <+68>: ldr x16, [x8, #0x20]!
|
||||
0x193755cf4 <+72>: mov x9, x16
|
||||
0x193755cf8 <+76>: xpacd x9
|
||||
0x193755cfc <+80>: and x9, x9, #0x7ffffffffff8
|
||||
0x193755d00 <+84>: ldr w9, [x9]
|
||||
0x193755d04 <+88>: tbnz w9, #0x1f, 0x1937560e8 ; <+1084>
|
||||
0x193755d08 <+92>: mov w20, #-0x7ff80000
|
||||
0x193755d0c <+96>: add x21, x19, #0x20
|
||||
0x193755d10 <+100>: mov x0, x21
|
||||
0x193755d14 <+104>: bl 0x1937753cc ; class_ro_t const* class_data_bits_t::safe_ro<(Authentication)0>() const
|
||||
0x193755d18 <+108>: ldr w8, [x0]
|
||||
0x193755d1c <+112>: and w26, w8, #0x1
|
||||
0x193755d20 <+116>: tbnz w8, #0x1e, 0x193755d58 ; <+172>
|
||||
0x193755d24 <+120>: mov x23, x0
|
||||
0x193755d28 <+124>: mov w0, #0x20
|
||||
0x193755d2c <+128>: mov w1, #0x1
|
||||
0x193755d30 <+132>: bl 0x193786a90 ; symbol stub for: calloc
|
||||
0x193755d34 <+136>: mov x22, x0
|
||||
0x193755d38 <+140>: add x8, x0, #0x8
|
||||
0x193755d3c <+144>: ldr x9, [x0, #0x8]
|
||||
0x193755d40 <+148>: tbnz w9, #0x0, 0x193755dd8 ; <+300>
|
||||
0x193755d44 <+152>: mov x9, x8
|
||||
0x193755d48 <+156>: movk x9, #0x949b, lsl #48
|
||||
0x193755d4c <+160>: mov x17, x23
|
||||
0x193755d50 <+164>: mov x16, x9
|
||||
0x193755d54 <+168>: b 0x193755e08 ; <+348>
|
||||
0x193755d58 <+172>: ldr x16, [x21]
|
||||
0x193755d5c <+176>: mov x17, x21
|
||||
0x193755d60 <+180>: movk x17, #0xc93a, lsl #48
|
||||
0x193755d64 <+184>: autdb x16, x17
|
||||
0x193755d68 <+188>: mov x17, x16
|
||||
0x193755d6c <+192>: xpacd x17
|
||||
0x193755d70 <+196>: cmp x16, x17
|
||||
0x193755d74 <+200>: b.eq 0x193755d7c ; <+208>
|
||||
0x193755d78 <+204>: brk #0xc473
|
||||
0x193755d7c <+208>: and x22, x16, #0x7ffffffffff8
|
||||
0x193755d80 <+212>: mov x0, x22
|
||||
0x193755d84 <+216>: bl 0x193772238 ; class_rw_t::ro() const
|
||||
0x193755d88 <+220>: mov x23, x0
|
||||
0x193755d8c <+224>: ldr x16, [x21]
|
||||
0x193755d90 <+228>: mov x17, x21
|
||||
0x193755d94 <+232>: movk x17, #0xc93a, lsl #48
|
||||
0x193755d98 <+236>: autdb x16, x17
|
||||
0x193755d9c <+240>: mov x17, x16
|
||||
0x193755da0 <+244>: xpacd x17
|
||||
0x193755da4 <+248>: cmp x16, x17
|
||||
0x193755da8 <+252>: b.eq 0x193755db0 ; <+260>
|
||||
0x193755dac <+256>: brk #0xc473
|
||||
0x193755db0 <+260>: and x8, x16, #0x7ffffffffff8
|
||||
0x193755db4 <+264>: mov w9, #0x3ff7ffff
|
||||
0x193755db8 <+268>: ldr w10, [x8]
|
||||
0x193755dbc <+272>: and w11, w10, w9
|
||||
0x193755dc0 <+276>: orr w11, w11, w20
|
||||
0x193755dc4 <+280>: mov x12, x10
|
||||
0x193755dc8 <+284>: casal w12, w11, [x8]
|
||||
0x193755dcc <+288>: cmp w12, w10
|
||||
0x193755dd0 <+292>: b.ne 0x193755db8 ; <+268>
|
||||
0x193755dd4 <+296>: b 0x193755e24 ; <+376>
|
||||
0x193755dd8 <+300>: and x16, x9, #0xfffffffffffffffe
|
||||
0x193755ddc <+304>: mov x17, x8
|
||||
0x193755de0 <+308>: movk x17, #0xe4f, lsl #48
|
||||
0x193755de4 <+312>: autdb x16, x17
|
||||
0x193755de8 <+316>: mov x17, x16
|
||||
0x193755dec <+320>: xpacd x17
|
||||
0x193755df0 <+324>: cmp x16, x17
|
||||
0x193755df4 <+328>: b.eq 0x193755dfc ; <+336>
|
||||
0x193755df8 <+332>: brk #0xc473
|
||||
0x193755dfc <+336>: mov x8, x16
|
||||
0x193755e00 <+340>: movk x16, #0xa0d3, lsl #48
|
||||
0x193755e04 <+344>: mov x17, x23
|
||||
0x193755e08 <+348>: pacdb x17, x16
|
||||
0x193755e0c <+352>: str x17, [x8]
|
||||
0x193755e10 <+356>: orr w8, w26, w20
|
||||
0x193755e14 <+360>: str w8, [x22]
|
||||
0x193755e18 <+364>: mov x0, x21
|
||||
0x193755e1c <+368>: mov x1, x22
|
||||
0x193755e20 <+372>: bl 0x19377576c ; class_data_bits_t::setData(class_rw_t*)
|
||||
0x193755e24 <+376>: adrp x8, 50
|
||||
0x193755e28 <+380>: add x8, x8, #0x5c0 ; _objc_empty_cache
|
||||
0x193755e2c <+384>: str x8, [x19, #0x10]
|
||||
0x193755e30 <+388>: str xzr, [x19, #0x18]
|
||||
0x193755e34 <+392>: cbz w26, 0x193755e44 ; <+408>
|
||||
0x193755e38 <+396>: add x8, x19, #0x1e
|
||||
0x193755e3c <+400>: mov w9, #0x4
|
||||
0x193755e40 <+404>: ldseth w9, w8, [x8]
|
||||
0x193755e44 <+408>: adrp x8, 363074
|
||||
0x193755e48 <+412>: ldr w8, [x8, #0x4f0]
|
||||
0x193755e4c <+416>: cbnz w8, 0x193756574 ; <+2248>
|
||||
0x193755e50 <+420>: mov x27, x19
|
||||
0x193755e54 <+424>: ldr x16, [x27, #0x8]!
|
||||
0x193755e58 <+428>: str x22, [sp, #0x40]
|
||||
0x193755e5c <+432>: cbz x16, 0x193755e88 ; <+476>
|
||||
0x193755e60 <+436>: mov x17, x27
|
||||
0x193755e64 <+440>: movk x17, #0xb5ab, lsl #48
|
||||
0x193755e68 <+444>: autda x16, x17
|
||||
0x193755e6c <+448>: mov x17, x16
|
||||
0x193755e70 <+452>: xpacd x17
|
||||
0x193755e74 <+456>: cmp x16, x17
|
||||
0x193755e78 <+460>: b.eq 0x193755e80 ; <+468>
|
||||
0x193755e7c <+464>: brk #0xc472
|
||||
0x193755e80 <+468>: mov x0, x16
|
||||
0x193755e84 <+472>: b 0x193755e8c ; <+480>
|
||||
0x193755e88 <+476>: mov x0, #0x0
|
||||
0x193755e8c <+480>: bl 0x19375573c ; remapClass(objc_class*)
|
||||
0x193755e90 <+484>: mov x24, x0
|
||||
0x193755e94 <+488>: mov x1, #0x0
|
||||
0x193755e98 <+492>: bl 0x193755cac ; <+0>
|
||||
0x193755e9c <+496>: ldr x8, [x19]
|
||||
0x193755ea0 <+500>: and x0, x8, #0x7ffffffffff8
|
||||
0x193755ea4 <+504>: bl 0x19375573c ; remapClass(objc_class*)
|
||||
0x193755ea8 <+508>: mov x25, x0
|
||||
0x193755eac <+512>: mov x1, #0x0
|
||||
0x193755eb0 <+516>: bl 0x193755cac ; <+0>
|
||||
0x193755eb4 <+520>: adrp x20, 373658
|
||||
0x193755eb8 <+524>: cbz w26, 0x193755ecc ; <+544>
|
||||
0x193755ebc <+528>: add x8, x19, #0x1e
|
||||
0x193755ec0 <+532>: mov w9, #0x2000
|
||||
0x193755ec4 <+536>: ldseth w9, w8, [x8]
|
||||
0x193755ec8 <+540>: b 0x193755ee0 ; <+564>
|
||||
0x193755ecc <+544>: ldr w8, [x20, #0xa64]
|
||||
0x193755ed0 <+548>: cbz w8, 0x193756130 ; <+1156>
|
||||
0x193755ed4 <+552>: mov w1, #0x0
|
||||
0x193755ed8 <+556>: mov x0, x19
|
||||
0x193755edc <+560>: bl 0x193757828 ; objc_class::setInstancesRequireRawIsaRecursively(bool)
|
||||
0x193755ee0 <+564>: mov x17, x24
|
||||
0x193755ee4 <+568>: mov x8, x27
|
||||
0x193755ee8 <+572>: movk x8, #0xb5ab, lsl #48
|
||||
0x193755eec <+576>: mov x16, x8
|
||||
0x193755ef0 <+580>: pacda x17, x16
|
||||
0x193755ef4 <+584>: str x17, [x27]
|
||||
0x193755ef8 <+588>: ldr w8, [x20, #0xa64]
|
||||
0x193755efc <+592>: mov x16, x19
|
||||
0x193755f00 <+596>: movk x16, #0x6ae1, lsl #48
|
||||
0x193755f04 <+600>: cbnz w8, 0x193755f2c ; <+640>
|
||||
0x193755f08 <+604>: ldrh w8, [x25, #0x1e]
|
||||
0x193755f0c <+608>: tbnz w8, #0xd, 0x193755f2c ; <+640>
|
||||
0x193755f10 <+612>: mov x17, x25
|
||||
0x193755f14 <+616>: pacda x17, x16
|
||||
0x193755f18 <+620>: and x8, x17, #0x7ffffffffffff8
|
||||
0x193755f1c <+624>: mov x9, #0x1
|
||||
0x193755f20 <+628>: movk x9, #0x100, lsl #48
|
||||
0x193755f24 <+632>: orr x8, x8, x9
|
||||
0x193755f28 <+636>: b 0x193755f38 ; <+652>
|
||||
0x193755f2c <+640>: mov x17, x25
|
||||
0x193755f30 <+644>: pacda x17, x16
|
||||
0x193755f34 <+648>: and x8, x17, #0x7ffffffffffff8
|
||||
0x193755f38 <+652>: str x8, [x19]
|
||||
0x193755f3c <+656>: cbz x24, 0x193756280 ; <+1492>
|
||||
0x193755f40 <+660>: cbnz w26, 0x193756280 ; <+1492>
|
||||
0x193755f44 <+664>: ldr x16, [x21]
|
||||
0x193755f48 <+668>: mov x17, x21
|
||||
0x193755f4c <+672>: movk x17, #0xc93a, lsl #48
|
||||
0x193755f50 <+676>: autdb x16, x17
|
||||
0x193755f54 <+680>: mov x17, x16
|
||||
0x193755f58 <+684>: xpacd x17
|
||||
0x193755f5c <+688>: cmp x16, x17
|
||||
0x193755f60 <+692>: b.eq 0x193755f68 ; <+700>
|
||||
0x193755f64 <+696>: brk #0xc473
|
||||
0x193755f68 <+700>: and x25, x16, #0x7ffffffffff8
|
||||
0x193755f6c <+704>: mov x8, x24
|
||||
0x193755f70 <+708>: ldr x16, [x8, #0x20]!
|
||||
0x193755f74 <+712>: mov x17, x8
|
||||
0x193755f78 <+716>: movk x17, #0xc93a, lsl #48
|
||||
0x193755f7c <+720>: autdb x16, x17
|
||||
0x193755f80 <+724>: mov x17, x16
|
||||
0x193755f84 <+728>: xpacd x17
|
||||
0x193755f88 <+732>: cmp x16, x17
|
||||
0x193755f8c <+736>: b.eq 0x193755f94 ; <+744>
|
||||
0x193755f90 <+740>: brk #0xc473
|
||||
0x193755f94 <+744>: and x0, x16, #0x7ffffffffff8
|
||||
0x193755f98 <+748>: bl 0x193772238 ; class_rw_t::ro() const
|
||||
0x193755f9c <+752>: mov x26, x0
|
||||
0x193755fa0 <+756>: adrp x8, 363071
|
||||
0x193755fa4 <+760>: ldr w8, [x8, #0x3c4]
|
||||
0x193755fa8 <+764>: cbz w8, 0x193755fc8 ; <+796>
|
||||
0x193755fac <+768>: mov x0, x19
|
||||
0x193755fb0 <+772>: bl 0x193775830 ; objc_class::mangledName()
|
||||
0x193755fb4 <+776>: mov x27, x0
|
||||
0x193755fb8 <+780>: adrp x1, 60
|
||||
0x193755fbc <+784>: add x1, x1, #0x660 ; "NSCF"
|
||||
0x193755fc0 <+788>: bl 0x193786fb0 ; symbol stub for: strstr
|
||||
0x193755fc4 <+792>: cbz x0, 0x1937561b0 ; <+1284>
|
||||
0x193755fc8 <+796>: ldr w8, [x23, #0x4]
|
||||
0x193755fcc <+800>: ldr w9, [x26, #0x8]
|
||||
0x193755fd0 <+804>: cmp w8, w9
|
||||
0x193755fd4 <+808>: b.hs 0x193756280 ; <+1492>
|
||||
0x193755fd8 <+812>: adrp x8, 363071
|
||||
0x193755fdc <+816>: ldr w8, [x8, #0x380]
|
||||
0x193755fe0 <+820>: cbnz w8, 0x193756688 ; <+2524>
|
||||
0x193755fe4 <+824>: mov x0, x25
|
||||
0x193755fe8 <+828>: bl 0x193770194 ; make_ro_writeable(class_rw_t*)
|
||||
0x193755fec <+832>: mov x27, x0
|
||||
0x193755ff0 <+836>: mov x0, x25
|
||||
0x193755ff4 <+840>: bl 0x193772238 ; class_rw_t::ro() const
|
||||
0x193755ff8 <+844>: mov x23, x0
|
||||
0x193755ffc <+848>: ldr w9, [x26, #0x8]
|
||||
0x193756000 <+852>: ldr w8, [x27, #0x4]
|
||||
0x193756004 <+856>: sub w26, w9, w8
|
||||
0x193756008 <+860>: ldr x25, [x27, #0x30]
|
||||
0x19375600c <+864>: cbz x25, 0x193756264 ; <+1464>
|
||||
0x193756010 <+868>: ldp w20, w9, [x25]
|
||||
0x193756014 <+872>: mul w22, w9, w20
|
||||
0x193756018 <+876>: cbz w22, 0x193756264 ; <+1464>
|
||||
0x19375601c <+880>: mov x8, #0x0
|
||||
0x193756020 <+884>: mov w9, #0x1
|
||||
0x193756024 <+888>: mov w11, #0x8
|
||||
0x193756028 <+892>: mov w10, #0x1
|
||||
0x19375602c <+896>: add x12, x25, x8
|
||||
0x193756030 <+900>: ldr x13, [x12, #0x8]
|
||||
0x193756034 <+904>: cbz x13, 0x193756050 ; <+932>
|
||||
0x193756038 <+908>: ldr w12, [x12, #0x20]
|
||||
0x19375603c <+912>: lsl w13, w9, w12
|
||||
0x193756040 <+916>: cmn w12, #0x1
|
||||
0x193756044 <+920>: csel w12, w11, w13, eq
|
||||
0x193756048 <+924>: cmp w12, w10
|
||||
0x19375604c <+928>: csel w10, w12, w10, hi
|
||||
0x193756050 <+932>: add x8, x8, x20
|
||||
0x193756054 <+936>: cmp x22, x8
|
||||
0x193756058 <+940>: b.ne 0x19375602c ; <+896>
|
||||
0x19375605c <+944>: str x28, [sp, #0x38]
|
||||
0x193756060 <+948>: mov x28, #0x0
|
||||
0x193756064 <+952>: add w8, w26, w10
|
||||
0x193756068 <+956>: sub w8, w8, #0x1
|
||||
0x19375606c <+960>: neg w9, w10
|
||||
0x193756070 <+964>: and w26, w8, w9
|
||||
0x193756074 <+968>: adrp x11, 363070
|
||||
0x193756078 <+972>: add x8, x25, x28
|
||||
0x19375607c <+976>: ldr x10, [x8, #0x8]
|
||||
0x193756080 <+980>: cbz x10, 0x193756098 ; <+1004>
|
||||
0x193756084 <+984>: ldr w8, [x10]
|
||||
0x193756088 <+988>: add w9, w8, w26
|
||||
0x19375608c <+992>: str w9, [x10]
|
||||
0x193756090 <+996>: ldr w10, [x11, #0x380]
|
||||
0x193756094 <+1000>: cbnz w10, 0x1937560a8 ; <+1020>
|
||||
0x193756098 <+1004>: add x28, x28, x20
|
||||
0x19375609c <+1008>: cmp x22, x28
|
||||
0x1937560a0 <+1012>: b.ne 0x193756078 ; <+972>
|
||||
0x1937560a4 <+1016>: b 0x19375625c ; <+1456>
|
||||
0x1937560a8 <+1020>: add x10, x25, x28
|
||||
0x1937560ac <+1024>: ldr x11, [x10, #0x10]
|
||||
0x1937560b0 <+1028>: ldp w12, w10, [x10, #0x20]
|
||||
0x1937560b4 <+1032>: mov w13, #0x1
|
||||
0x1937560b8 <+1036>: lsl w13, w13, w12
|
||||
0x1937560bc <+1040>: cmn w12, #0x1
|
||||
0x1937560c0 <+1044>: mov w12, #0x8
|
||||
0x1937560c4 <+1048>: csel w12, w12, w13, eq
|
||||
0x1937560c8 <+1052>: stp x11, x10, [sp, #0x10]
|
||||
0x1937560cc <+1056>: stp x8, x9, [sp]
|
||||
0x1937560d0 <+1060>: str x12, [sp, #0x20]
|
||||
0x1937560d4 <+1064>: adrp x0, 59
|
||||
0x1937560d8 <+1068>: add x0, x0, #0x71e ; "IVARS: offset %u -> %u for %s (size %u, align %u)"
|
||||
0x1937560dc <+1072>: bl 0x19376dd58 ; _objc_inform
|
||||
0x1937560e0 <+1076>: adrp x11, 363070
|
||||
0x1937560e4 <+1080>: b 0x193756098 ; <+1004>
|
||||
0x1937560e8 <+1084>: mov x17, x8
|
||||
0x1937560ec <+1088>: movk x17, #0xc93a, lsl #48
|
||||
0x1937560f0 <+1092>: autdb x16, x17
|
||||
0x1937560f4 <+1096>: mov x17, x16
|
||||
0x1937560f8 <+1100>: xpacd x17
|
||||
0x1937560fc <+1104>: cmp x16, x17
|
||||
0x193756100 <+1108>: b.eq 0x193756108 ; <+1116>
|
||||
0x193756104 <+1112>: brk #0xc473
|
||||
0x193756108 <+1116>: and x20, x16, #0x7ffffffffff8
|
||||
0x19375610c <+1120>: mov x0, x20
|
||||
0x193756110 <+1124>: bl 0x193786c70 ; symbol stub for: malloc_size
|
||||
0x193756114 <+1128>: cmp x0, #0x1f
|
||||
0x193756118 <+1132>: b.hi 0x193756550 ; <+2212>
|
||||
0x19375611c <+1136>: stp x20, x0, [sp, #0x8]
|
||||
0x193756120 <+1140>: str x19, [sp]
|
||||
0x193756124 <+1144>: adrp x0, 59
|
||||
0x193756128 <+1148>: add x0, x0, #0x61e ; "realized class %p has corrupt data pointer: malloc_size(%p) = %zu"
|
||||
0x19375612c <+1152>: bl 0x193785458 ; _objc_fatal(char const*, ...)
|
||||
0x193756130 <+1156>: ldrh w22, [x19, #0x1e]
|
||||
0x193756134 <+1160>: adrp x8, 373657
|
||||
0x193756138 <+1164>: ldrb w8, [x8, #0xa48]
|
||||
0x19375613c <+1168>: tbnz w8, #0x0, 0x193756160 ; <+1204>
|
||||
0x193756140 <+1172>: add x8, x23, #0x18
|
||||
0x193756144 <+1176>: ldapr x0, [x8]
|
||||
0x193756148 <+1180>: cbz x0, 0x193756160 ; <+1204>
|
||||
0x19375614c <+1184>: adrp x1, 59
|
||||
0x193756150 <+1188>: add x1, x1, #0x614 ; "OS_object"
|
||||
0x193756154 <+1192>: bl 0x193786f30 ; symbol stub for: strcmp
|
||||
0x193756158 <+1196>: adrp x9, 373657
|
||||
0x19375615c <+1200>: cbz w0, 0x193756610 ; <+2404>
|
||||
0x193756160 <+1204>: cbz x24, 0x1937561a8 ; <+1276>
|
||||
0x193756164 <+1208>: mov x8, x24
|
||||
0x193756168 <+1212>: ldr x16, [x8, #0x8]!
|
||||
0x19375616c <+1216>: cbz x16, 0x1937561a8 ; <+1276>
|
||||
0x193756170 <+1220>: mov x17, x8
|
||||
0x193756174 <+1224>: movk x17, #0xb5ab, lsl #48
|
||||
0x193756178 <+1228>: autda x16, x17
|
||||
0x19375617c <+1232>: mov x17, x16
|
||||
0x193756180 <+1236>: xpacd x17
|
||||
0x193756184 <+1240>: cmp x16, x17
|
||||
0x193756188 <+1244>: b.eq 0x193756190 ; <+1252>
|
||||
0x19375618c <+1248>: brk #0xc472
|
||||
0x193756190 <+1252>: cbz x16, 0x1937561a8 ; <+1276>
|
||||
0x193756194 <+1256>: ldrh w8, [x24, #0x1e]
|
||||
0x193756198 <+1260>: orr w9, w8, w22
|
||||
0x19375619c <+1264>: tbz w9, #0xd, 0x193755ee0 ; <+564>
|
||||
0x1937561a0 <+1268>: ubfx w1, w8, #13, #1
|
||||
0x1937561a4 <+1272>: b 0x193755ed8 ; <+556>
|
||||
0x1937561a8 <+1276>: tbnz w22, #0xd, 0x193755ed4 ; <+552>
|
||||
0x1937561ac <+1280>: b 0x193755ee0 ; <+564>
|
||||
0x1937561b0 <+1284>: adrp x1, 59
|
||||
0x1937561b4 <+1288>: add x1, x1, #0x665 ; "__CF"
|
||||
0x1937561b8 <+1292>: mov x0, x27
|
||||
0x1937561bc <+1296>: mov w2, #0x4
|
||||
0x1937561c0 <+1300>: bl 0x193786f90 ; symbol stub for: strncmp
|
||||
0x1937561c4 <+1304>: cbz w0, 0x193755fc8 ; <+796>
|
||||
0x1937561c8 <+1308>: adrp x1, 59
|
||||
0x1937561cc <+1312>: add x1, x1, #0x66a ; "NSConstantString"
|
||||
0x1937561d0 <+1316>: mov x0, x27
|
||||
0x1937561d4 <+1320>: bl 0x193786f30 ; symbol stub for: strcmp
|
||||
0x1937561d8 <+1324>: cbz w0, 0x193755fc8 ; <+796>
|
||||
0x1937561dc <+1328>: adrp x1, 59
|
||||
0x1937561e0 <+1332>: add x1, x1, #0x67b ; "NSSimpleCString"
|
||||
0x1937561e4 <+1336>: mov x0, x27
|
||||
0x1937561e8 <+1340>: bl 0x193786f30 ; symbol stub for: strcmp
|
||||
0x1937561ec <+1344>: cbz w0, 0x193755fc8 ; <+796>
|
||||
0x1937561f0 <+1348>: ldr w20, [x23, #0x4]
|
||||
0x1937561f4 <+1352>: mov x0, x25
|
||||
0x1937561f8 <+1356>: bl 0x193770194 ; make_ro_writeable(class_rw_t*)
|
||||
0x1937561fc <+1360>: mov x27, x0
|
||||
0x193756200 <+1364>: mov x0, x25
|
||||
0x193756204 <+1368>: bl 0x193772238 ; class_rw_t::ro() const
|
||||
0x193756208 <+1372>: mov x23, x0
|
||||
0x19375620c <+1376>: ldr x8, [x0, #0x30]
|
||||
0x193756210 <+1380>: cbz x8, 0x193756620 ; <+2420>
|
||||
0x193756214 <+1384>: ldp w9, w10, [x8]
|
||||
0x193756218 <+1388>: mul w10, w10, w9
|
||||
0x19375621c <+1392>: mov w11, #0x8
|
||||
0x193756220 <+1396>: cbz w10, 0x193756620 ; <+2420>
|
||||
0x193756224 <+1400>: mov x13, #0x0
|
||||
0x193756228 <+1404>: add x14, x8, #0x20
|
||||
0x19375622c <+1408>: mov w15, #0x1
|
||||
0x193756230 <+1412>: mov w12, #0x8
|
||||
0x193756234 <+1416>: ldr w16, [x14, x13]
|
||||
0x193756238 <+1420>: lsl w17, w15, w16
|
||||
0x19375623c <+1424>: cmn w16, #0x1
|
||||
0x193756240 <+1428>: csel w16, w11, w17, eq
|
||||
0x193756244 <+1432>: cmp w16, w12
|
||||
0x193756248 <+1436>: csel w12, w16, w12, hi
|
||||
0x19375624c <+1440>: add x13, x13, x9
|
||||
0x193756250 <+1444>: cmp x10, x13
|
||||
0x193756254 <+1448>: b.ne 0x193756234 ; <+1416>
|
||||
0x193756258 <+1452>: b 0x193756624 ; <+2424>
|
||||
0x19375625c <+1456>: ldr w8, [x27, #0x4]
|
||||
0x193756260 <+1460>: ldr x28, [sp, #0x38]
|
||||
0x193756264 <+1464>: add w8, w26, w8
|
||||
0x193756268 <+1468>: ldr w9, [x27, #0x8]
|
||||
0x19375626c <+1472>: add w9, w9, w26
|
||||
0x193756270 <+1476>: stp w8, w9, [x27, #0x4]
|
||||
0x193756274 <+1480>: add x8, x23, #0x18
|
||||
0x193756278 <+1484>: ldapr xzr, [x8]
|
||||
0x19375627c <+1488>: bl 0x1937650d8 ; gdb_objc_class_changed
|
||||
0x193756280 <+1492>: ldr w1, [x23, #0x8]
|
||||
0x193756284 <+1496>: mov x0, x19
|
||||
0x193756288 <+1500>: bl 0x193775884 ; objc_class::setInstanceSize(unsigned int)
|
||||
0x19375628c <+1504>: ldr w8, [x23]
|
||||
0x193756290 <+1508>: tbz w8, #0x2, 0x1937562b4 ; <+1544>
|
||||
0x193756294 <+1512>: add x9, x19, #0x1e
|
||||
0x193756298 <+1516>: mov w8, #0x1
|
||||
0x19375629c <+1520>: ldseth w8, w8, [x9]
|
||||
0x1937562a0 <+1524>: ldr w8, [x23]
|
||||
0x1937562a4 <+1528>: tbnz w8, #0x8, 0x1937562b4 ; <+1544>
|
||||
0x1937562a8 <+1532>: mov w8, #0x2
|
||||
0x1937562ac <+1536>: ldseth w8, w8, [x9]
|
||||
0x1937562b0 <+1540>: ldr w8, [x23]
|
||||
0x1937562b4 <+1544>: tbnz w8, #0xa, 0x193756304 ; <+1624>
|
||||
0x1937562b8 <+1548>: cbz x24, 0x193756358 ; <+1708>
|
||||
0x1937562bc <+1552>: mov x8, x24
|
||||
0x1937562c0 <+1556>: ldr x16, [x8, #0x20]!
|
||||
0x1937562c4 <+1560>: mov x17, x8
|
||||
0x1937562c8 <+1564>: movk x17, #0xc93a, lsl #48
|
||||
0x1937562cc <+1568>: autdb x16, x17
|
||||
0x1937562d0 <+1572>: mov x17, x16
|
||||
0x1937562d4 <+1576>: xpacd x17
|
||||
0x1937562d8 <+1580>: cmp x16, x17
|
||||
0x1937562dc <+1584>: b.eq 0x1937562e4 ; <+1592>
|
||||
0x1937562e0 <+1588>: brk #0xc473
|
||||
0x1937562e4 <+1592>: and x8, x16, #0x7ffffffffff8
|
||||
0x1937562e8 <+1596>: ldrb w8, [x8, #0x2]
|
||||
0x1937562ec <+1600>: tbz w8, #0x4, 0x193756318 ; <+1644>
|
||||
0x1937562f0 <+1604>: ldr x9, [sp, #0x40]
|
||||
0x1937562f4 <+1608>: ldr w8, [x9]
|
||||
0x1937562f8 <+1612>: orr w8, w8, #0x100000
|
||||
0x1937562fc <+1616>: str w8, [x9]
|
||||
0x193756300 <+1620>: b 0x193756318 ; <+1644>
|
||||
0x193756304 <+1624>: ldr x9, [sp, #0x40]
|
||||
0x193756308 <+1628>: ldr w8, [x9]
|
||||
0x19375630c <+1632>: orr w8, w8, #0x100000
|
||||
0x193756310 <+1636>: str w8, [x9]
|
||||
0x193756314 <+1640>: cbz x24, 0x193756358 ; <+1708>
|
||||
0x193756318 <+1644>: mov x0, x24
|
||||
0x19375631c <+1648>: mov x1, x19
|
||||
0x193756320 <+1652>: bl 0x1937566e8 ; addSubclass(objc_class*, objc_class*)
|
||||
0x193756324 <+1656>: ldr x16, [x19, #0x20]
|
||||
0x193756328 <+1660>: mov x20, x21
|
||||
0x19375632c <+1664>: movk x20, #0xc93a, lsl #48
|
||||
0x193756330 <+1668>: mov x17, x21
|
||||
0x193756334 <+1672>: movk x17, #0xc93a, lsl #48
|
||||
0x193756338 <+1676>: autdb x16, x17
|
||||
0x19375633c <+1680>: mov x17, x16
|
||||
0x193756340 <+1684>: xpacd x17
|
||||
0x193756344 <+1688>: cmp x16, x17
|
||||
0x193756348 <+1692>: b.eq 0x193756350 ; <+1700>
|
||||
0x19375634c <+1696>: brk #0xc473
|
||||
0x193756350 <+1700>: and x22, x16, #0x7ffffffffff8
|
||||
0x193756354 <+1704>: b 0x1937563a8 ; <+1788>
|
||||
0x193756358 <+1708>: adrp x8, 373657
|
||||
0x19375635c <+1712>: ldr x9, [x8, #0x868]
|
||||
0x193756360 <+1716>: add x9, x9, #0x1
|
||||
0x193756364 <+1720>: str x9, [x8, #0x868]
|
||||
0x193756368 <+1724>: adrp x8, 373657
|
||||
0x19375636c <+1728>: ldr x9, [x8, #0xa50]
|
||||
0x193756370 <+1732>: ldr x16, [x19, #0x20]
|
||||
0x193756374 <+1736>: mov x20, x21
|
||||
0x193756378 <+1740>: movk x20, #0xc93a, lsl #48
|
||||
0x19375637c <+1744>: mov x17, x21
|
||||
0x193756380 <+1748>: movk x17, #0xc93a, lsl #48
|
||||
0x193756384 <+1752>: autdb x16, x17
|
||||
0x193756388 <+1756>: mov x17, x16
|
||||
0x19375638c <+1760>: xpacd x17
|
||||
0x193756390 <+1764>: cmp x16, x17
|
||||
0x193756394 <+1768>: b.eq 0x19375639c ; <+1776>
|
||||
0x193756398 <+1772>: brk #0xc473
|
||||
0x19375639c <+1776>: and x22, x16, #0x7ffffffffff8
|
||||
0x1937563a0 <+1780>: str x9, [x22, #0x18]
|
||||
0x1937563a4 <+1784>: str x19, [x8, #0xa50]
|
||||
0x1937563a8 <+1788>: ldrh w23, [x19, #0x1e]
|
||||
0x1937563ac <+1792>: mov x0, x22
|
||||
0x1937563b0 <+1796>: bl 0x193772238 ; class_rw_t::ro() const
|
||||
0x1937563b4 <+1800>: mov x21, x0
|
||||
0x1937563b8 <+1804>: ldr x8, [x22, #0x8]
|
||||
0x1937563bc <+1808>: tbz w8, #0x0, 0x1937563f4 ; <+1864>
|
||||
0x1937563c0 <+1812>: ands x16, x8, #0xfffffffffffffffe
|
||||
0x1937563c4 <+1816>: b.eq 0x1937563f4 ; <+1864>
|
||||
0x1937563c8 <+1820>: add x8, x22, #0x8
|
||||
0x1937563cc <+1824>: mov x17, x8
|
||||
0x1937563d0 <+1828>: movk x17, #0xe4f, lsl #48
|
||||
0x1937563d4 <+1832>: autdb x16, x17
|
||||
0x1937563d8 <+1836>: mov x17, x16
|
||||
0x1937563dc <+1840>: xpacd x17
|
||||
0x1937563e0 <+1844>: cmp x16, x17
|
||||
0x1937563e4 <+1848>: b.eq 0x1937563ec ; <+1856>
|
||||
0x1937563e8 <+1852>: brk #0xc473
|
||||
0x1937563ec <+1856>: mov x22, x16
|
||||
0x1937563f0 <+1860>: b 0x1937563f8 ; <+1868>
|
||||
0x1937563f4 <+1864>: mov x22, #0x0
|
||||
0x1937563f8 <+1868>: adrp x8, 363073
|
||||
0x1937563fc <+1872>: ldr w8, [x8, #0x4f0]
|
||||
0x193756400 <+1876>: cbnz w8, 0x1937565dc ; <+2352>
|
||||
0x193756404 <+1880>: mov x8, x21
|
||||
0x193756408 <+1884>: ldr x16, [x8, #0x20]!
|
||||
0x19375640c <+1888>: cbz x16, 0x19375648c ; <+2016>
|
||||
0x193756410 <+1892>: mov x17, x8
|
||||
0x193756414 <+1896>: movk x17, #0xc310, lsl #48
|
||||
0x193756418 <+1900>: autda x16, x17
|
||||
0x19375641c <+1904>: mov x17, x16
|
||||
0x193756420 <+1908>: xpacd x17
|
||||
0x193756424 <+1912>: cmp x16, x17
|
||||
0x193756428 <+1916>: b.eq 0x193756430 ; <+1924>
|
||||
0x19375642c <+1920>: brk #0xc472
|
||||
0x193756430 <+1924>: str x16, [sp, #0x58]
|
||||
0x193756434 <+1928>: cbz x16, 0x193756490 ; <+2020>
|
||||
0x193756438 <+1932>: ldr x16, [x19, #0x20]
|
||||
0x19375643c <+1936>: autdb x16, x20
|
||||
0x193756440 <+1940>: mov x17, x16
|
||||
0x193756444 <+1944>: xpacd x17
|
||||
0x193756448 <+1948>: cmp x16, x17
|
||||
0x19375644c <+1952>: b.eq 0x193756454 ; <+1960>
|
||||
0x193756450 <+1956>: brk #0xc473
|
||||
0x193756454 <+1960>: and x0, x16, #0x7ffffffffff8
|
||||
0x193756458 <+1964>: bl 0x193772238 ; class_rw_t::ro() const
|
||||
0x19375645c <+1968>: ldr w8, [x0]
|
||||
0x193756460 <+1972>: ubfx w3, w8, #29, #1
|
||||
0x193756464 <+1976>: add x1, sp, #0x58
|
||||
0x193756468 <+1980>: mov x0, x19
|
||||
0x19375646c <+1984>: mov w2, #0x1
|
||||
0x193756470 <+1988>: bl 0x193775914 ; prepareMethodLists(objc_class*, method_list_t**, int, bool, bool, char const*)
|
||||
0x193756474 <+1992>: cbz x22, 0x1937564dc ; <+2096>
|
||||
0x193756478 <+1996>: add x0, x22, #0x8
|
||||
0x19375647c <+2000>: add x1, sp, #0x58
|
||||
0x193756480 <+2004>: mov w2, #0x1
|
||||
0x193756484 <+2008>: bl 0x1937749ac ; list_array_tt<method_t, method_list_t, method_list_t_authed_ptr>::attachLists(method_list_t* const*, unsigned int)
|
||||
0x193756488 <+2012>: b 0x193756490 ; <+2020>
|
||||
0x19375648c <+2016>: str xzr, [sp, #0x58]
|
||||
0x193756490 <+2020>: ldr x8, [x21, #0x40]
|
||||
0x193756494 <+2024>: str x8, [sp, #0x50]
|
||||
0x193756498 <+2028>: cmp x22, #0x0
|
||||
0x19375649c <+2032>: cset w20, ne
|
||||
0x1937564a0 <+2036>: cbz x22, 0x1937564bc ; <+2064>
|
||||
0x1937564a4 <+2040>: cbz x8, 0x1937564bc ; <+2064>
|
||||
0x1937564a8 <+2044>: add x0, x22, #0x10
|
||||
0x1937564ac <+2048>: mov w20, #0x1
|
||||
0x1937564b0 <+2052>: add x1, sp, #0x50
|
||||
0x1937564b4 <+2056>: mov w2, #0x1
|
||||
0x1937564b8 <+2060>: bl 0x193774c28 ; list_array_tt<property_t, property_list_t, RawPtr>::attachLists(property_list_t* const*, unsigned int)
|
||||
0x1937564bc <+2064>: ldr x8, [x21, #0x28]
|
||||
0x1937564c0 <+2068>: str x8, [sp, #0x48]
|
||||
0x1937564c4 <+2072>: cbz w20, 0x1937564dc ; <+2096>
|
||||
0x1937564c8 <+2076>: cbz x8, 0x1937564dc ; <+2096>
|
||||
0x1937564cc <+2080>: add x0, x22, #0x18
|
||||
0x1937564d0 <+2084>: add x1, sp, #0x48
|
||||
0x1937564d4 <+2088>: mov w2, #0x1
|
||||
0x1937564d8 <+2092>: bl 0x193774d78 ; list_array_tt<unsigned long, protocol_list_t, RawPtr>::attachLists(protocol_list_t* const*, unsigned int)
|
||||
0x1937564dc <+2096>: ldr x8, [x19]
|
||||
0x1937564e0 <+2100>: and x8, x8, #0x7ffffffffff8
|
||||
0x1937564e4 <+2104>: cmp x8, x19
|
||||
0x1937564e8 <+2108>: b.ne 0x193756518 ; <+2156>
|
||||
0x1937564ec <+2112>: adrp x8, 326768
|
||||
0x1937564f0 <+2116>: add x1, x8, #0x2f
|
||||
0x1937564f4 <+2120>: adrp x3, 61
|
||||
0x1937564f8 <+2124>: add x3, x3, #0xbf3 ; ""
|
||||
0x1937564fc <+2128>: adrp x16, 42
|
||||
0x193756500 <+2132>: add x16, x16, #0xb74 ; objc_noop_imp
|
||||
0x193756504 <+2136>: paciza x16
|
||||
0x193756508 <+2140>: mov x2, x16
|
||||
0x19375650c <+2144>: mov x0, x19
|
||||
0x193756510 <+2148>: mov w4, #0x0
|
||||
0x193756514 <+2152>: bl 0x1937568a8 ; addMethod(objc_class*, objc_selector*, void (*)(), char const*, bool)
|
||||
0x193756518 <+2156>: cbz x28, 0x193756538 ; <+2188>
|
||||
0x19375651c <+2160>: tst w23, #0x4
|
||||
0x193756520 <+2164>: mov w8, #0x2
|
||||
0x193756524 <+2168>: mov w9, #0x4
|
||||
0x193756528 <+2172>: csel w2, w9, w8, eq
|
||||
0x19375652c <+2176>: mov x0, x19
|
||||
0x193756530 <+2180>: mov x1, x28
|
||||
0x193756534 <+2184>: bl 0x19375714c ; objc::UnattachedCategories::attachToClass(objc_class*, objc_class*, int)
|
||||
0x193756538 <+2188>: tst w23, #0x4
|
||||
0x19375653c <+2192>: mov w8, #0x1
|
||||
0x193756540 <+2196>: cinc w2, w8, ne
|
||||
0x193756544 <+2200>: mov x0, x19
|
||||
0x193756548 <+2204>: mov x1, x19
|
||||
0x19375654c <+2208>: bl 0x19375714c ; objc::UnattachedCategories::attachToClass(objc_class*, objc_class*, int)
|
||||
0x193756550 <+2212>: mov x0, x19
|
||||
0x193756554 <+2216>: ldp x29, x30, [sp, #0xb0]
|
||||
0x193756558 <+2220>: ldp x20, x19, [sp, #0xa0]
|
||||
0x19375655c <+2224>: ldp x22, x21, [sp, #0x90]
|
||||
0x193756560 <+2228>: ldp x24, x23, [sp, #0x80]
|
||||
0x193756564 <+2232>: ldp x26, x25, [sp, #0x70]
|
||||
0x193756568 <+2236>: ldp x28, x27, [sp, #0x60]
|
||||
0x19375656c <+2240>: add sp, sp, #0xc0
|
||||
-> 0x193756570 <+2244>: retab
|
||||
0x193756574 <+2248>: mov x0, x19
|
||||
0x193756578 <+2252>: bl 0x193775470 ; objc_class::nameForLogging()
|
||||
0x19375657c <+2256>: adrp x8, 61
|
||||
0x193756580 <+2260>: add x8, x8, #0xbf3 ; ""
|
||||
0x193756584 <+2264>: adrp x9, 59
|
||||
0x193756588 <+2268>: add x9, x9, #0x111 ; " (meta)"
|
||||
0x19375658c <+2272>: cmp w26, #0x0
|
||||
0x193756590 <+2276>: csel x9, x9, x8, ne
|
||||
0x193756594 <+2280>: ldr x10, [x19, #0x20]
|
||||
0x193756598 <+2284>: adrp x11, 59
|
||||
0x19375659c <+2288>: add x11, x11, #0x5f9 ; "(swift)"
|
||||
0x1937565a0 <+2292>: tst x10, #0x2
|
||||
0x1937565a4 <+2296>: csel x11, x8, x11, eq
|
||||
0x1937565a8 <+2300>: adrp x12, 59
|
||||
0x1937565ac <+2304>: add x12, x12, #0x601 ; "(pre-stable swift)"
|
||||
0x1937565b0 <+2308>: tst x10, #0x1
|
||||
0x1937565b4 <+2312>: csel x8, x8, x12, eq
|
||||
0x1937565b8 <+2316>: stp x11, x8, [sp, #0x28]
|
||||
0x1937565bc <+2320>: stp x23, xzr, [sp, #0x18]
|
||||
0x1937565c0 <+2324>: stp x9, x19, [sp, #0x8]
|
||||
0x1937565c4 <+2328>: adrp x8, 59
|
||||
0x1937565c8 <+2332>: add x8, x8, #0x5cc ; "CLASS: realizing class '%s'%s %p %p #%u %s%s"
|
||||
0x1937565cc <+2336>: str x0, [sp]
|
||||
0x1937565d0 <+2340>: mov x0, x8
|
||||
0x1937565d4 <+2344>: bl 0x19376dd58 ; _objc_inform
|
||||
0x1937565d8 <+2348>: b 0x193755e50 ; <+420>
|
||||
0x1937565dc <+2352>: mov x0, x19
|
||||
0x1937565e0 <+2356>: bl 0x193775470 ; objc_class::nameForLogging()
|
||||
0x1937565e4 <+2360>: adrp x8, 59
|
||||
0x1937565e8 <+2364>: add x8, x8, #0x774 ; "(meta)"
|
||||
0x1937565ec <+2368>: adrp x9, 61
|
||||
0x1937565f0 <+2372>: add x9, x9, #0xbf3 ; ""
|
||||
0x1937565f4 <+2376>: tst w23, #0x4
|
||||
0x1937565f8 <+2380>: csel x8, x9, x8, eq
|
||||
0x1937565fc <+2384>: stp x0, x8, [sp]
|
||||
0x193756600 <+2388>: adrp x0, 59
|
||||
0x193756604 <+2392>: add x0, x0, #0x753 ; "CLASS: methodizing class '%s' %s"
|
||||
0x193756608 <+2396>: bl 0x19376dd58 ; _objc_inform
|
||||
0x19375660c <+2400>: b 0x193756404 ; <+1880>
|
||||
0x193756610 <+2404>: mov w1, #0x0
|
||||
0x193756614 <+2408>: mov w8, #0x1
|
||||
0x193756618 <+2412>: strb w8, [x9, #0xa48]
|
||||
0x19375661c <+2416>: b 0x193755ed8 ; <+556>
|
||||
0x193756620 <+2420>: mov w12, #0x8
|
||||
0x193756624 <+2424>: ldr w9, [x23, #0x4]
|
||||
0x193756628 <+2428>: udiv w10, w9, w12
|
||||
0x19375662c <+2432>: mul w22, w10, w12
|
||||
0x193756630 <+2436>: sub w9, w9, w22
|
||||
0x193756634 <+2440>: ldr w10, [x27, #0x8]
|
||||
0x193756638 <+2444>: sub w10, w10, w22
|
||||
0x19375663c <+2448>: stp w9, w10, [x27, #0x4]
|
||||
0x193756640 <+2452>: adrp x9, 363070
|
||||
0x193756644 <+2456>: ldr w9, [x9, #0x380]
|
||||
0x193756648 <+2460>: cbnz w9, 0x1937566b0 ; <+2564>
|
||||
0x19375664c <+2464>: cbz x8, 0x193755fc8 ; <+796>
|
||||
0x193756650 <+2468>: ldp w9, w10, [x8]
|
||||
0x193756654 <+2472>: mul w10, w10, w9
|
||||
0x193756658 <+2476>: cbz w10, 0x193755fc8 ; <+796>
|
||||
0x19375665c <+2480>: mov x11, #0x0
|
||||
0x193756660 <+2484>: add x8, x8, #0x8
|
||||
0x193756664 <+2488>: ldr x12, [x8, x11]
|
||||
0x193756668 <+2492>: cbz x12, 0x193756678 ; <+2508>
|
||||
0x19375666c <+2496>: ldr w13, [x12]
|
||||
0x193756670 <+2500>: sub w13, w13, w22
|
||||
0x193756674 <+2504>: str w13, [x12]
|
||||
0x193756678 <+2508>: add x11, x11, x9
|
||||
0x19375667c <+2512>: cmp x10, x11
|
||||
0x193756680 <+2516>: b.ne 0x193756664 ; <+2488>
|
||||
0x193756684 <+2520>: b 0x193755fc8 ; <+796>
|
||||
0x193756688 <+2524>: mov x0, x19
|
||||
0x19375668c <+2528>: bl 0x193775470 ; objc_class::nameForLogging()
|
||||
0x193756690 <+2532>: ldr w8, [x23, #0x4]
|
||||
0x193756694 <+2536>: ldr w9, [x26, #0x8]
|
||||
0x193756698 <+2540>: stp x8, x9, [sp, #0x8]
|
||||
0x19375669c <+2544>: str x0, [sp]
|
||||
0x1937566a0 <+2548>: adrp x0, 59
|
||||
0x1937566a4 <+2552>: add x0, x0, #0x6da ; "IVARS: sliding ivars for class %s (superclass was %u bytes, now %u)"
|
||||
0x1937566a8 <+2556>: bl 0x19376dd58 ; _objc_inform
|
||||
0x1937566ac <+2560>: b 0x193755fe4 ; <+824>
|
||||
0x1937566b0 <+2564>: mov x0, x19
|
||||
0x1937566b4 <+2568>: bl 0x193775470 ; objc_class::nameForLogging()
|
||||
0x1937566b8 <+2572>: ldr w8, [x23, #0x4]
|
||||
0x1937566bc <+2576>: stp x20, x8, [sp, #0x8]
|
||||
0x1937566c0 <+2580>: str x0, [sp]
|
||||
0x1937566c4 <+2584>: adrp x0, 59
|
||||
0x1937566c8 <+2588>: add x0, x0, #0x68b ; "IVARS: DEBUG: forcing ivars for class '%s' to slide (instanceStart %zu -> %zu)"
|
||||
0x1937566cc <+2592>: bl 0x19376dd58 ; _objc_inform
|
||||
0x1937566d0 <+2596>: ldr x8, [x23, #0x30]
|
||||
0x1937566d4 <+2600>: cbnz x8, 0x193756650 ; <+2468>
|
||||
0x1937566d8 <+2604>: b 0x193755fc8 ; <+796>
|
||||
0x1937566dc <+2608>: udf #0x0
|
||||
0x1937566e0 <+2612>: udf #0x0
|
||||
0x1937566e4 <+2616>: udf #0x0
|
||||
|
93
research/custom_loader/schedule_class_load.txt
Normal file
93
research/custom_loader/schedule_class_load.txt
Normal file
@ -0,0 +1,93 @@
|
||||
libobjc.A.dylib`schedule_class_load:
|
||||
libobjc.A.dylib[0x1800687c8] <+0>: pacibsp
|
||||
libobjc.A.dylib[0x1800687cc] <+4>: sub sp, sp, #0x50
|
||||
libobjc.A.dylib[0x1800687d0] <+8>: stp x24, x23, [sp, #0x10]
|
||||
libobjc.A.dylib[0x1800687d4] <+12>: stp x22, x21, [sp, #0x20]
|
||||
libobjc.A.dylib[0x1800687d8] <+16>: stp x20, x19, [sp, #0x30]
|
||||
libobjc.A.dylib[0x1800687dc] <+20>: stp x29, x30, [sp, #0x40]
|
||||
libobjc.A.dylib[0x1800687e0] <+24>: add x29, sp, #0x40
|
||||
libobjc.A.dylib[0x1800687e4] <+28>: cbz x0, 0x1800688fc ; <+308>
|
||||
libobjc.A.dylib[0x1800687e8] <+32>: mov x19, x0
|
||||
libobjc.A.dylib[0x1800687ec] <+36>: mov x21, x0
|
||||
libobjc.A.dylib[0x1800687f0] <+40>: ldr x16, [x21, #0x20]!
|
||||
libobjc.A.dylib[0x1800687f4] <+44>: mov x17, x21
|
||||
libobjc.A.dylib[0x1800687f8] <+48>: movk x17, #0xc93a, lsl #48
|
||||
libobjc.A.dylib[0x1800687fc] <+52>: autdb x16, x17
|
||||
libobjc.A.dylib[0x180068800] <+56>: mov x17, x16
|
||||
libobjc.A.dylib[0x180068804] <+60>: xpacd x17
|
||||
libobjc.A.dylib[0x180068808] <+64>: cmp x16, x17
|
||||
libobjc.A.dylib[0x18006880c] <+68>: b.eq 0x180068814 ; <+76>
|
||||
libobjc.A.dylib[0x180068810] <+72>: brk #0xc473
|
||||
libobjc.A.dylib[0x180068814] <+76>: and x8, x16, #0x7ffffffffff8
|
||||
libobjc.A.dylib[0x180068818] <+80>: ldrb w8, [x8, #0x2]
|
||||
libobjc.A.dylib[0x18006881c] <+84>: tbnz w8, #0x7, 0x1800688fc ; <+308>
|
||||
libobjc.A.dylib[0x180068820] <+88>: mov x8, x19
|
||||
libobjc.A.dylib[0x180068824] <+92>: ldr x16, [x8, #0x8]!
|
||||
libobjc.A.dylib[0x180068828] <+96>: cbz x16, 0x180068854 ; <+140>
|
||||
libobjc.A.dylib[0x18006882c] <+100>: mov x17, x8
|
||||
libobjc.A.dylib[0x180068830] <+104>: movk x17, #0xb5ab, lsl #48
|
||||
libobjc.A.dylib[0x180068834] <+108>: autda x16, x17
|
||||
libobjc.A.dylib[0x180068838] <+112>: mov x17, x16
|
||||
libobjc.A.dylib[0x18006883c] <+116>: xpacd x17
|
||||
libobjc.A.dylib[0x180068840] <+120>: cmp x16, x17
|
||||
libobjc.A.dylib[0x180068844] <+124>: b.eq 0x18006884c ; <+132>
|
||||
libobjc.A.dylib[0x180068848] <+128>: brk #0xc472
|
||||
libobjc.A.dylib[0x18006884c] <+132>: mov x0, x16
|
||||
libobjc.A.dylib[0x180068850] <+136>: b 0x180068858 ; <+144>
|
||||
libobjc.A.dylib[0x180068854] <+140>: mov x0, #0x0
|
||||
libobjc.A.dylib[0x180068858] <+144>: bl 0x1800687c8 ; <+0>
|
||||
libobjc.A.dylib[0x18006885c] <+148>: ldr x0, [x19]
|
||||
libobjc.A.dylib[0x180068860] <+152>: bl 0x18007b0d8 ; objc_class::getLoadMethod()
|
||||
libobjc.A.dylib[0x180068864] <+156>: cbz x0, 0x1800688cc ; <+260>
|
||||
libobjc.A.dylib[0x180068868] <+160>: mov x20, x0
|
||||
libobjc.A.dylib[0x18006886c] <+164>: adrp x8, 363064
|
||||
libobjc.A.dylib[0x180068870] <+168>: ldr w8, [x8, #0x374]
|
||||
libobjc.A.dylib[0x180068874] <+172>: cbnz w8, 0x180068914 ; <+332>
|
||||
libobjc.A.dylib[0x180068878] <+176>: adrp x22, 363064
|
||||
libobjc.A.dylib[0x18006887c] <+180>: ldrsw x23, [x22, #0x220]
|
||||
libobjc.A.dylib[0x180068880] <+184>: adrp x8, 363064
|
||||
libobjc.A.dylib[0x180068884] <+188>: ldr w9, [x8, #0x224]
|
||||
libobjc.A.dylib[0x180068888] <+192>: cmp w23, w9
|
||||
libobjc.A.dylib[0x18006888c] <+196>: b.ne 0x1800688b4 ; <+236>
|
||||
libobjc.A.dylib[0x180068890] <+200>: lsl w9, w23, #1
|
||||
libobjc.A.dylib[0x180068894] <+204>: add w9, w9, #0x10
|
||||
libobjc.A.dylib[0x180068898] <+208>: str w9, [x8, #0x224]
|
||||
libobjc.A.dylib[0x18006889c] <+212>: adrp x24, 363064
|
||||
libobjc.A.dylib[0x1800688a0] <+216>: ldr x0, [x24, #0x228]
|
||||
libobjc.A.dylib[0x1800688a4] <+220>: sbfiz x1, x9, #4, #32
|
||||
libobjc.A.dylib[0x1800688a8] <+224>: bl 0x180092ec0 ; symbol stub for: realloc
|
||||
libobjc.A.dylib[0x1800688ac] <+228>: str x0, [x24, #0x228]
|
||||
libobjc.A.dylib[0x1800688b0] <+232>: b 0x1800688bc ; <+244>
|
||||
libobjc.A.dylib[0x1800688b4] <+236>: adrp x8, 363064
|
||||
libobjc.A.dylib[0x1800688b8] <+240>: ldr x0, [x8, #0x228]
|
||||
libobjc.A.dylib[0x1800688bc] <+244>: add x8, x0, x23, lsl #4
|
||||
libobjc.A.dylib[0x1800688c0] <+248>: stp x19, x20, [x8]
|
||||
libobjc.A.dylib[0x1800688c4] <+252>: add w8, w23, #0x1
|
||||
libobjc.A.dylib[0x1800688c8] <+256>: str w8, [x22, #0x220]
|
||||
libobjc.A.dylib[0x1800688cc] <+260>: ldr x16, [x21]
|
||||
libobjc.A.dylib[0x1800688d0] <+264>: mov x17, x21
|
||||
libobjc.A.dylib[0x1800688d4] <+268>: movk x17, #0xc93a, lsl #48
|
||||
libobjc.A.dylib[0x1800688d8] <+272>: autdb x16, x17
|
||||
libobjc.A.dylib[0x1800688dc] <+276>: mov x17, x16
|
||||
libobjc.A.dylib[0x1800688e0] <+280>: xpacd x17
|
||||
libobjc.A.dylib[0x1800688e4] <+284>: cmp x16, x17
|
||||
libobjc.A.dylib[0x1800688e8] <+288>: b.eq 0x1800688f0 ; <+296>
|
||||
libobjc.A.dylib[0x1800688ec] <+292>: brk #0xc473
|
||||
libobjc.A.dylib[0x1800688f0] <+296>: and x8, x16, #0x7ffffffffff8
|
||||
libobjc.A.dylib[0x1800688f4] <+300>: mov w9, #0x800000
|
||||
libobjc.A.dylib[0x1800688f8] <+304>: ldset w9, w8, [x8]
|
||||
libobjc.A.dylib[0x1800688fc] <+308>: ldp x29, x30, [sp, #0x40]
|
||||
libobjc.A.dylib[0x180068900] <+312>: ldp x20, x19, [sp, #0x30]
|
||||
libobjc.A.dylib[0x180068904] <+316>: ldp x22, x21, [sp, #0x20]
|
||||
libobjc.A.dylib[0x180068908] <+320>: ldp x24, x23, [sp, #0x10]
|
||||
libobjc.A.dylib[0x18006890c] <+324>: add sp, sp, #0x50
|
||||
libobjc.A.dylib[0x180068910] <+328>: retab
|
||||
libobjc.A.dylib[0x180068914] <+332>: mov x0, x19
|
||||
libobjc.A.dylib[0x180068918] <+336>: bl 0x180081470 ; objc_class::nameForLogging()
|
||||
libobjc.A.dylib[0x18006891c] <+340>: str x0, [sp]
|
||||
libobjc.A.dylib[0x180068920] <+344>: adrp x0, 52
|
||||
libobjc.A.dylib[0x180068924] <+348>: add x0, x0, #0x7e6 ; "LOAD: class '%s' scheduled for +load"
|
||||
libobjc.A.dylib[0x180068928] <+352>: bl 0x180079d58 ; _objc_inform
|
||||
libobjc.A.dylib[0x18006892c] <+356>: b 0x180068878 ; <+176>
|
||||
libobjc.A.dylib[0x180068930] <+360>: udf #0x0
|
||||
|
3384
research/custom_loader/test_file.txt
Normal file
3384
research/custom_loader/test_file.txt
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user