nicer
This commit is contained in:
parent
ff58f88401
commit
9149062ebb
23
Makefile
23
Makefile
@ -1,31 +1,38 @@
|
|||||||
DATA = $(word 1,$(wildcard ./data ../data))
|
DATA = $(word 1,$(wildcard ./data ../data))
|
||||||
CFLAGS += -I$(DATA)
|
override CFLAGS += -I$(DATA)
|
||||||
include $(DATA)/Makefile.common
|
include $(DATA)/Makefile.common
|
||||||
|
|
||||||
BINS := $(OUTDIR)/check_sanity $(OUTDIR)/make_kernel_patchfile $(OUTDIR)/apply_patchfile $(OUTDIR)/dump_range $(OUTDIR)/nm $(OUTDIR)/grapher sandboxc.c
|
BINS := $(OUTDIR)/check_sanity $(OUTDIR)/make_kernel_patchfile $(OUTDIR)/apply_patchfile $(OUTDIR)/dump $(OUTDIR)/nm $(OUTDIR)/decrypt_kern sandboxc-armv6.c sandboxc-armv7.c
|
||||||
|
ifneq "$(GXX)" ""
|
||||||
|
BINS += $(OUTDIR)/grapher
|
||||||
|
endif
|
||||||
|
|
||||||
all: .data $(OUTDIR) $(BINS)
|
all: .data $(OUTDIR) $(BINS)
|
||||||
|
|
||||||
$(OUTDIR):
|
$(OUTDIR):
|
||||||
mkdir $(OUTDIR)
|
mkdir $(OUTDIR)
|
||||||
|
|
||||||
sandbox.o: sandbox.S
|
sandbox-armv6.o: sandbox.S
|
||||||
$(SDK_GCC) -arch armv6 -c -o $@ $<
|
$(SDK_GCC) -arch armv6 -c -o $@ $<
|
||||||
sandboxc.c: sandbox.o
|
sandbox-armv7.o: sandbox.S
|
||||||
xxd -i sandbox.o > sandboxc.c
|
$(SDK_GCC) -arch armv7 -c -o $@ $<
|
||||||
|
sandboxc-%.c: sandbox-%.o
|
||||||
|
xxd -i $< > $@
|
||||||
|
|
||||||
$(OUTDIR)/check_sanity: $(OUTDIR)/check_sanity.o $(DATA)/$(OUTDIR)/libdata.a
|
$(OUTDIR)/check_sanity: $(OUTDIR)/check_sanity.o $(DATA)/$(OUTDIR)/libdata.a
|
||||||
$(GCC) -o $@ $^
|
$(GCC) -o $@ $^
|
||||||
$(OUTDIR)/apply_patchfile: $(OUTDIR)/apply_patchfile.o $(DATA)/$(OUTDIR)/libdata.a
|
$(OUTDIR)/apply_patchfile: $(OUTDIR)/apply_patchfile.o $(DATA)/$(OUTDIR)/libdata.a
|
||||||
$(GCC) -o $@ $^
|
$(GCC) -o $@ $^
|
||||||
$(OUTDIR)/make_kernel_patchfile: $(OUTDIR)/make_kernel_patchfile.o $(OUTDIR)/sandboxc.o $(DATA)/$(OUTDIR)/libdata.a
|
$(OUTDIR)/make_kernel_patchfile: $(OUTDIR)/make_kernel_patchfile.o $(OUTDIR)/sandboxc-armv6.o $(OUTDIR)/sandboxc-armv7.o $(DATA)/$(OUTDIR)/libdata.a
|
||||||
$(GCC) -o $@ $^
|
$(GCC) -o $@ $^
|
||||||
$(OUTDIR)/dump_range: $(OUTDIR)/dump_range.o $(DATA)/$(OUTDIR)/libdata.a
|
$(OUTDIR)/dump: $(OUTDIR)/dump.o $(DATA)/$(OUTDIR)/libdata.a
|
||||||
$(GCC) -o $@ $^
|
$(GCC) -o $@ $^
|
||||||
$(OUTDIR)/nm: $(OUTDIR)/nm.o $(DATA)/$(OUTDIR)/libdata.a
|
$(OUTDIR)/nm: $(OUTDIR)/nm.o $(DATA)/$(OUTDIR)/libdata.a
|
||||||
$(GCC) -o $@ $^
|
$(GCC) -o $@ $^
|
||||||
$(OUTDIR)/grapher: $(OUTDIR)/grapher.o $(DATA)/$(OUTDIR)/libdata.a
|
$(OUTDIR)/grapher: $(OUTDIR)/grapher.o $(DATA)/$(OUTDIR)/libdata.a
|
||||||
$(GXX) -o $@ $^ -O3
|
$(GXX) -o $@ $^ -O3
|
||||||
|
$(OUTDIR)/decrypt_kern: $(OUTDIR)/decrypt_kern.o $(DATA)/$(OUTDIR)/libdata.a
|
||||||
|
$(GCC) -o $@ $^ -O3
|
||||||
|
|
||||||
clean: .clean
|
clean: .clean
|
||||||
rm -f sandbox.o sandboxc.c
|
rm -f sandboxc-{armv6,armv7}.c sandbox-{armv6,armv7}.o
|
||||||
|
15
decrypt_kern.c
Normal file
15
decrypt_kern.c
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#include <data/cc.h>
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
if(argc != 5) {
|
||||||
|
fprintf(stderr, "Usage: decrypt_kern <img3> <key> <iv> <outfile>\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
uint32_t key_bits;
|
||||||
|
char *kern_fn;
|
||||||
|
prange_t data = parse_img3_file(kern_fn = argv[1], &key_bits);
|
||||||
|
prange_t key = parse_hex_string(argv[2]);
|
||||||
|
prange_t iv = parse_hex_string(argv[3]);
|
||||||
|
prange_t decompressed = decrypt_and_decompress(key_bits, key, iv, data);
|
||||||
|
store_file(decompressed, argv[4], 0644);
|
||||||
|
return 0;
|
||||||
|
}
|
36
dump.c
Normal file
36
dump.c
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#include <data/mach-o/binary.h>
|
||||||
|
|
||||||
|
static void dump(range_t range) {
|
||||||
|
prange_t pr = rangeconv(range, MUST_FIND);
|
||||||
|
write(1, pr.start, pr.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
if(argc < 2) goto usage;
|
||||||
|
struct binary binary;
|
||||||
|
b_init(&binary);
|
||||||
|
b_load_macho(&binary, argv[1]);
|
||||||
|
char **arg = &argv[2];
|
||||||
|
while(*arg) {
|
||||||
|
if(!strcmp(*arg, "-a")) {
|
||||||
|
if(!arg[1] || !arg[2]) goto usage;
|
||||||
|
dump((range_t) {&binary, parse_hex_uint32(arg[1]), parse_hex_uint32(arg[2])});
|
||||||
|
arg += 3;
|
||||||
|
} else if(!strcmp(*arg, "-A")) {
|
||||||
|
if(!arg[1] || !arg[2]) goto usage;
|
||||||
|
uint32_t start = parse_hex_uint32(arg[1]);
|
||||||
|
dump((range_t) {&binary, start, parse_hex_uint32(arg[2]) - start});
|
||||||
|
arg += 3;
|
||||||
|
} else if(!strcmp(*arg, "-s")) {
|
||||||
|
if(!arg[1]) goto usage;
|
||||||
|
dump(b_macho_segrange(&binary, arg[1]));
|
||||||
|
arg += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
usage:
|
||||||
|
fprintf(stderr, "Usage: dump_range binary [-a start len] [-A start end] [-s segname]\n");
|
||||||
|
return 1;
|
||||||
|
}
|
14
dump_range.c
14
dump_range.c
@ -1,14 +0,0 @@
|
|||||||
#include <data/mach-o/binary.h>
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
|
||||||
if(argc != 4) {
|
|
||||||
fprintf(stderr, "Usage: dump_range binary start len\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
struct binary binary;
|
|
||||||
b_init(&binary);
|
|
||||||
b_load_macho(&binary, argv[1]);
|
|
||||||
prange_t pr = rangeconv((range_t) {&binary, parse_hex_uint32(argv[2]), parse_hex_uint32(argv[3])}, MUST_FIND);
|
|
||||||
write(1, pr.start, pr.size);
|
|
||||||
return 0;
|
|
||||||
}
|
|
363
grapher.cpp
363
grapher.cpp
@ -1,4 +1,5 @@
|
|||||||
#include <data/mach-o/binary.h>
|
#include <data/mach-o/binary.h>
|
||||||
|
#include <data/find.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
@ -14,7 +15,13 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
#define STRICT 1
|
enum {
|
||||||
|
FULL_HASH,
|
||||||
|
BEGINNING_HASH,
|
||||||
|
ENDING_HASH
|
||||||
|
};
|
||||||
|
|
||||||
|
static int hashMode = FULL_HASH;
|
||||||
|
|
||||||
struct Edge;
|
struct Edge;
|
||||||
|
|
||||||
@ -28,19 +35,6 @@ static bool b_in_vmrange(const struct binary *binary, addr_t addr) {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// wtf
|
|
||||||
namespace std {
|
|
||||||
template <typename A, typename B>
|
|
||||||
struct hash<pair<A, B>> : public unary_function<pair<A, B>, size_t> {
|
|
||||||
inline size_t operator()(const pair<A, B> p) const {
|
|
||||||
hash<A> hA;
|
|
||||||
hash<B> hB;
|
|
||||||
return hA(p.first) ^ hB(p.second);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t signExtend(uint32_t val, int bits) {
|
static uint32_t signExtend(uint32_t val, int bits) {
|
||||||
if(val & (1 << (bits - 1))) {
|
if(val & (1 << (bits - 1))) {
|
||||||
val |= ~((1 << bits) - 1);
|
val |= ~((1 << bits) - 1);
|
||||||
@ -49,7 +43,7 @@ static uint32_t signExtend(uint32_t val, int bits) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
INCOMPLETE_FUNC,
|
INCOMPLETE_FUNC = 0,
|
||||||
THUMB_FUNC,
|
THUMB_FUNC,
|
||||||
THUMB_VARARGS_FUNC,
|
THUMB_VARARGS_FUNC,
|
||||||
THUMB_ACCESSOR_FUNC
|
THUMB_ACCESSOR_FUNC
|
||||||
@ -64,7 +58,7 @@ struct Function {
|
|||||||
const char *name;
|
const char *name;
|
||||||
uint32_t hash;
|
uint32_t hash;
|
||||||
|
|
||||||
list<pair<addr_t, addr_t>> refs;
|
list<pair<pair<addr_t, addr_t>, bool>> refs;// the bool is whether it's a function
|
||||||
|
|
||||||
int type;
|
int type;
|
||||||
|
|
||||||
@ -84,27 +78,27 @@ struct Function {
|
|||||||
uint32_t jumpTarget = 0;
|
uint32_t jumpTarget = 0;
|
||||||
if((p[0] & 0xf000) == 0xd000) { // B1
|
if((p[0] & 0xf000) == 0xd000) { // B1
|
||||||
jumpTarget = signExtend(p[0] & 0xff, 8);
|
jumpTarget = signExtend(p[0] & 0xff, 8);
|
||||||
p[0] = 0;
|
p[0] = 0x42;
|
||||||
} else if((p[0] & 0xf800) == 0xe000) { // B2
|
} else if((p[0] & 0xf800) == 0xe000) { // B2
|
||||||
jumpTarget = signExtend(p[0] & 0x7ff, 11);
|
jumpTarget = signExtend(p[0] & 0x7ff, 11);
|
||||||
p[0] = 0;
|
p[0] = 0x43;
|
||||||
} else if((p[0] & 0xf800) == 0xf000 && ((p[1] & 0xd000) == 0x8000) && ((p[0] & 0x380) >> 7) != 7) { // B3
|
} else if((p[0] & 0xf800) == 0xf000 && ((p[1] & 0xd000) == 0x8000) && ((p[0] & 0x380) >> 7) != 7) { // B3
|
||||||
jumpTarget = signExtend(((p[0] & 0x400) << 9) | ((p[1] & 0x800) << 7) | ((p[1] & 0x2000) << 4) | ((p[0] & 0x3f) << 11) | (p[1] & 0x7ff), 20);
|
jumpTarget = signExtend(((p[0] & 0x400) << 9) | ((p[1] & 0x800) << 7) | ((p[1] & 0x2000) << 4) | ((p[0] & 0x3f) << 11) | (p[1] & 0x7ff), 20);
|
||||||
p[0] = p[1] = 0;
|
p[0] = p[1] = 0x44;
|
||||||
} else if((p[0] & 0xf500) == 0xb100) { // CB[N]Z
|
} else if((p[0] & 0xf500) == 0xb100) { // CB[N]Z
|
||||||
jumpTarget = ((p[0] & 0x200) >> 4) | ((p[0] & 0xf8) >> 3);
|
jumpTarget = ((p[0] & 0x200) >> 4) | ((p[0] & 0xf8) >> 3);
|
||||||
} else if((p[0] & 0xf800) == 0x4800) { // LDR literal
|
} else if((p[0] & 0xf800) == 0x4800) { // LDR literal
|
||||||
auto target = (uint32_t *) (p + ((addr & 2) ? 1 : 2) + 2*(p[0] & 0xff));
|
auto target = (uint32_t *) (p + ((addr & 2) ? 1 : 2) + 2*(p[0] & 0xff));
|
||||||
if(target < (uint32_t *) endOfWorld) {
|
if(target < (uint32_t *) endOfWorld) {
|
||||||
refs.push_back(make_pair(addr, *target));
|
refs.push_back(make_pair(make_pair(addr, *target), false));
|
||||||
}
|
}
|
||||||
p[0] = 0;
|
p[0] = 0x45;
|
||||||
} else if((p[0] & 0xff7f) == 0xf85f) { // LDR literal 2
|
} else if((p[0] & 0xff7f) == 0xf85f) { // LDR literal 2
|
||||||
auto target = (uint32_t *) ((uint8_t *) p + ((addr & 2) ? 2 : 4) + (p[1] & 0xfff));
|
auto target = (uint32_t *) ((uint8_t *) p + ((addr & 2) ? 2 : 4) + (p[1] & 0xfff));
|
||||||
if(target < (uint32_t *) endOfWorld) {
|
if(target < (uint32_t *) endOfWorld) {
|
||||||
refs.push_back(make_pair(addr, *target));
|
refs.push_back(make_pair(make_pair(addr, *target), false));
|
||||||
}
|
}
|
||||||
p[0] = p[1] = 0;
|
p[0] = p[1] = 0x46;
|
||||||
} else if((p[0] & 0xf800) == 0xf000 && (p[1] & 0xc000) == 0xc000) { // BL(X)
|
} else if((p[0] & 0xf800) == 0xf000 && (p[1] & 0xc000) == 0xc000) { // BL(X)
|
||||||
// gross
|
// gross
|
||||||
auto S = ((p[0] & 0x400) >> 10), J1 = (p[1] & 0x2000) >> 13, J2 = (p[1] & 0x800) >> 11;
|
auto S = ((p[0] & 0x400) >> 10), J1 = (p[1] & 0x2000) >> 13, J2 = (p[1] & 0x800) >> 11;
|
||||||
@ -118,12 +112,12 @@ struct Function {
|
|||||||
} else { // BLX
|
} else { // BLX
|
||||||
target &= ~2;
|
target &= ~2;
|
||||||
}
|
}
|
||||||
refs.push_back(make_pair(addr, target));
|
refs.push_back(make_pair(make_pair(addr, target), true));
|
||||||
|
|
||||||
p[0] = p[1] = 0;
|
p[0] = p[1] = 0x46;
|
||||||
} else if(
|
} else if(
|
||||||
(type == THUMB_FUNC && p[0] == (0xbd00 | (start[0] & 0xff))) ||
|
(type == THUMB_FUNC && p[0] == (0xbd00 | (start[0] & 0xff))) ||
|
||||||
(type == THUMB_VARARGS_FUNC && p[0] == 0xb004 && p[1] == 0x4770)) { // end of function
|
(type == THUMB_VARARGS_FUNC && (p[0] & 0xb000) == 0xb000 && p[1] == 0x4770)) { // end of function
|
||||||
jumpTarget = UINT32_MAX;
|
jumpTarget = UINT32_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,8 +141,23 @@ struct Function {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void setHash() {
|
void setHash() {
|
||||||
hash = 0;
|
auto hstart = start;
|
||||||
for(auto p = start; p + 1 <= end && (STRICT || p < start + 10); p++) {
|
auto hend = end;
|
||||||
|
switch(hashMode) {
|
||||||
|
case BEGINNING_HASH:
|
||||||
|
hstart = start;
|
||||||
|
hend = hstart + 7;
|
||||||
|
break;
|
||||||
|
case ENDING_HASH:
|
||||||
|
hend = end;
|
||||||
|
hstart = hend - 7;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(hstart < start) hstart = start;
|
||||||
|
if(hend > end) hend = end;
|
||||||
|
|
||||||
|
for(auto p = hstart; p + 1 <= hend; p++) {
|
||||||
hash += *p;
|
hash += *p;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -189,10 +198,12 @@ struct Edge {
|
|||||||
uint32_t hash;
|
uint32_t hash;
|
||||||
Edge(Function *source, Function *dest)
|
Edge(Function *source, Function *dest)
|
||||||
: source(source), dest(dest) {
|
: source(source), dest(dest) {
|
||||||
hash = source->hash ^ ((dest->hash >> 16) | (dest->hash << 16));
|
|
||||||
source->forward.push_back(this);
|
source->forward.push_back(this);
|
||||||
dest->backward.push_back(this);
|
dest->backward.push_back(this);
|
||||||
}
|
}
|
||||||
|
inline void setHash() {
|
||||||
|
hash = source->hash ^ ((dest->hash >> 16) | (dest->hash << 16));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -200,10 +211,10 @@ struct Binary {
|
|||||||
struct binary binary;
|
struct binary binary;
|
||||||
const char *filename;
|
const char *filename;
|
||||||
unordered_map<addr_t, Function *> funcs;
|
unordered_map<addr_t, Function *> funcs;
|
||||||
unordered_map<uint32_t, set<Function *>> funcsByHash;
|
unordered_map<uint32_t, vector<Function *>> funcsByHash;
|
||||||
map<string, Function *> funcsByName;
|
map<string, Function *> funcsByName;
|
||||||
list<Function *> funcsList;
|
vector<Function *> funcsList;
|
||||||
unordered_map<uint32_t, list<Edge *>> edgesByHash;
|
unordered_map<uint32_t, vector<Edge *>> edgesByHash;
|
||||||
|
|
||||||
unordered_map<addr_t, const char *> reverseSymbols;
|
unordered_map<addr_t, const char *> reverseSymbols;
|
||||||
|
|
||||||
@ -240,11 +251,6 @@ struct Binary {
|
|||||||
if(name) funcsByName[name] = func;
|
if(name) funcsByName[name] = func;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setFuncHash(Function *func, uint32_t hash) {
|
|
||||||
funcsByHash[func->hash].erase(func);
|
|
||||||
funcsByHash[func->hash = hash].insert(func);
|
|
||||||
}
|
|
||||||
|
|
||||||
Function *addFunc(uint16_t *start, uint16_t *end, addr_t addr, int type) {
|
Function *addFunc(uint16_t *start, uint16_t *end, addr_t addr, int type) {
|
||||||
Function *&func = funcs[addr];
|
Function *&func = funcs[addr];
|
||||||
if(!func) {
|
if(!func) {
|
||||||
@ -254,14 +260,16 @@ struct Binary {
|
|||||||
return func;
|
return func;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cut(const set<uint32_t>& cutPoints) {
|
void cut(const set<uint32_t>& cutPoints, bool explain) {
|
||||||
uint32_t x = 0;
|
uint32_t x = 0;
|
||||||
for(auto func : funcsList) {
|
for(auto func : funcsList) {
|
||||||
uint32_t hash = func->hash;
|
uint32_t hash = func->hash;
|
||||||
setFuncHash(func, hash ^ x);
|
func->hash ^= x;
|
||||||
|
//func->hash = x;
|
||||||
|
//printf("%08x: %x -> %x\n", func->startAddr, hash, func->hash);
|
||||||
if(cutPoints.find(hash) != cutPoints.end()) {
|
if(cutPoints.find(hash) != cutPoints.end()) {
|
||||||
//printf("CUT: %x\n", func->startAddr);
|
if(explain) printf("CUT: hash %x from %x\n", hash, func->startAddr);
|
||||||
x ^= (hash << 2);
|
x = (hash << 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -283,40 +291,66 @@ struct Binary {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for(auto func : funcsList) {
|
for(auto func : funcsList) {
|
||||||
setFuncHash(func, func->hash);
|
|
||||||
for(auto p : func->refs) {
|
for(auto p : func->refs) {
|
||||||
auto b = p.second;
|
auto b = p.first.second;
|
||||||
|
auto executable = p.second;
|
||||||
if(b_in_vmrange(&binary, b)) {
|
if(b_in_vmrange(&binary, b)) {
|
||||||
Function *&func2 = funcs[b];
|
Function *&func2 = funcs[b];
|
||||||
if(!func2) {
|
if(!func2) {
|
||||||
prange_t pr = rangeconv((range_t) {&binary, b, 4}, 0);
|
prange_t pr = rangeconv((range_t) {&binary, b, 4}, 0);
|
||||||
if(!pr.start || b_in_vmrange(&binary, *((uint32_t *) pr.start))) {
|
if(!pr.start || !executable) {
|
||||||
|
//value = *((uint32_t *) pr.start),
|
||||||
|
//(/* hack */ true || b_in_vmrange(&binary, value)))) {
|
||||||
// quick guess
|
// quick guess
|
||||||
pr.size = 0;
|
pr.size = 0;
|
||||||
}
|
}
|
||||||
func2 = addFunc((uint16_t *) pr.start, (uint16_t *) (pr.start + pr.size), b, INCOMPLETE_FUNC);
|
func2 = addFunc((uint16_t *) pr.start, (uint16_t *) (pr.start + pr.size), b, INCOMPLETE_FUNC);
|
||||||
}
|
}
|
||||||
|
new Edge(func, func2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for(auto func : funcsList) {
|
||||||
|
#define X(direction, port) \
|
||||||
|
if(hashMode == FULL_HASH && false) { \
|
||||||
|
for(auto edge : func->direction) { \
|
||||||
|
func->hash ^= ~(edge->port->hash); \
|
||||||
|
} \
|
||||||
|
} else { \
|
||||||
|
if(func->direction.size() == 1) { \
|
||||||
|
func->hash += ~(*func->direction.begin())->port->hash; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
X(forward, dest)
|
||||||
|
X(backward, source)
|
||||||
|
#undef X
|
||||||
|
}
|
||||||
|
|
||||||
|
sort(funcsList.begin(), funcsList.end(), [](Function *const& a, Function *const& b) { return a->startAddr < b->startAddr; });
|
||||||
}
|
}
|
||||||
|
|
||||||
void doEdges() {
|
void doHashes() {
|
||||||
if(edgesByHash.size()) return;
|
if(edgesByHash.size()) return;
|
||||||
for(auto func : funcsList) {
|
for(auto func : funcsList) {
|
||||||
for(auto p : func->refs) {
|
funcsByHash[func->hash].push_back(func);
|
||||||
auto it = funcs.find(p.second);
|
for(auto edge : func->forward) {
|
||||||
if(it != funcs.end()) {
|
edge->setHash();
|
||||||
auto edge = new Edge(func, it->second);
|
edgesByHash[edge->hash].push_back(edge);
|
||||||
edgesByHash[edge->hash].push_back(edge);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unordered_map<uint32_t, list<Function *>> getFuncsByHash() {
|
||||||
|
typeof(getFuncsByHash()) result;
|
||||||
|
for(auto func : funcsList) {
|
||||||
|
result[func->hash].push_back(func);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void identifyVtables(bool explain) {
|
void identifyVtables(bool explain) {
|
||||||
doEdges();
|
doHashes();
|
||||||
|
|
||||||
auto constructor = funcsByName["__ZN11OSMetaClassC2EPKcPKS_j"];
|
auto constructor = funcsByName["__ZN11OSMetaClassC2EPKcPKS_j"];
|
||||||
assert(constructor);
|
assert(constructor);
|
||||||
@ -412,22 +446,39 @@ struct Binary {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static void doCutPoints(Binary *ba, Binary *bb) {
|
static void doCutPoints(Binary *ba, Binary *bb, bool explain = false) {
|
||||||
|
auto funcsByHashA = ba->getFuncsByHash(), funcsByHashB = bb->getFuncsByHash();
|
||||||
|
|
||||||
set<uint32_t> cutPoints;
|
set<uint32_t> cutPoints;
|
||||||
for(auto p : ba->funcsByHash) {
|
for(auto p : funcsByHashA) {
|
||||||
if(p.second.size() == 1 &&
|
if(p.second.size() == 1 &&
|
||||||
bb->funcsByHash[p.first].size() == 1) {
|
funcsByHashB[p.first].size() == 1) {
|
||||||
cutPoints.insert(p.first);
|
cutPoints.insert(p.first);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ba->cut(cutPoints);
|
|
||||||
bb->cut(cutPoints);
|
if(explain) {
|
||||||
|
// verify (by hand) that cut points are actually in the same order between the binaries
|
||||||
|
auto it = ba->funcsList.begin(), it2 = bb->funcsList.begin();
|
||||||
|
while(it != ba->funcsList.end() && it2 != bb->funcsList.end()) {
|
||||||
|
while(cutPoints.find((*it)->hash) == cutPoints.end()) if(++it == ba->funcsList.end()) goto done;
|
||||||
|
while(cutPoints.find((*it2)->hash) == cutPoints.end()) if(++it2 == bb->funcsList.end()) goto done;
|
||||||
|
if((*it)->hash != (*it2)->hash) printf("XXX ");
|
||||||
|
printf("%08x:%08x %x:%x\n", (*it)->startAddr, (*it2)->startAddr, (*it)->hash, (*it2)->hash);
|
||||||
|
it++; it2++;
|
||||||
|
}
|
||||||
|
done:;
|
||||||
|
}
|
||||||
|
|
||||||
|
ba->cut(cutPoints, explain);
|
||||||
|
bb->cut(cutPoints, explain);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static list<pair<Function *, Function *>> doMatch(Binary *ba, Binary *bb) {
|
static list<pair<Function *, Function *>> doMatch(Binary *ba, Binary *bb, bool explain = false) {
|
||||||
doCutPoints(ba, bb);
|
doCutPoints(ba, bb);
|
||||||
ba->doEdges();
|
ba->doHashes();
|
||||||
bb->doEdges();
|
bb->doHashes();
|
||||||
|
|
||||||
// This is not the most efficient thing
|
// This is not the most efficient thing
|
||||||
unordered_map<Function *, unordered_map<Function *, double>> xs;
|
unordered_map<Function *, unordered_map<Function *, double>> xs;
|
||||||
@ -442,7 +493,75 @@ static list<pair<Function *, Function *>> doMatch(Binary *ba, Binary *bb) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct MetaEdge {
|
||||||
|
double *source;
|
||||||
|
double weight;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MetaVertex {
|
||||||
|
double *dest;
|
||||||
|
MetaEdge *edges;
|
||||||
|
};
|
||||||
|
|
||||||
|
vector<MetaVertex> mvs;
|
||||||
|
|
||||||
|
fprintf(stderr, "5.1\n");
|
||||||
|
// 5.1
|
||||||
|
for(auto group : ba->edgesByHash) {
|
||||||
|
for(auto edge1 : group.second) {
|
||||||
|
for(auto edge2 : bb->edgesByHash[edge1->hash]) {
|
||||||
|
MetaVertex mv;
|
||||||
|
mv.dest = &ys[edge1][edge2];
|
||||||
|
mv.edges = new MetaEdge[3];
|
||||||
|
mv.edges[0] = (MetaEdge) {&xs[edge1->source][edge2->source], 1};
|
||||||
|
mv.edges[1] = (MetaEdge) {&xs[edge1->dest][edge2->dest], 1};
|
||||||
|
mv.edges[2] = (MetaEdge) {NULL, 0};
|
||||||
|
mvs.push_back(mv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "5.2\n");
|
||||||
|
// 5.2, tweaked to account for order
|
||||||
|
// not perfect
|
||||||
|
// but that needs be divided by something
|
||||||
|
// oh, and we can't completely discard the original xs value because some functions neither call or are called by anyone we know; we still can use matching
|
||||||
|
for(auto a : ba->funcsList) {
|
||||||
|
//printf("%d %x\n", (int) bb->funcsByHash[a->hash].size(), a->startAddr);
|
||||||
|
for(auto b : bb->funcsByHash[a->hash]) {
|
||||||
|
//printf("welp\n");
|
||||||
|
MetaVertex mv;
|
||||||
|
mv.dest = &xs[a][b];
|
||||||
|
MetaEdge *ptr = mv.edges = new MetaEdge[a->forward.size() * b->forward.size() + a->backward.size() * b->backward.size() + 2];
|
||||||
|
#define X(direction) \
|
||||||
|
if(a->direction.size() == b->direction.size()) { \
|
||||||
|
for(auto it = a->direction.begin(), it2 = b->direction.begin(); \
|
||||||
|
it != a->direction.end(); \
|
||||||
|
it++, it2++) { \
|
||||||
|
*ptr++ = (MetaEdge) {&ys[*it][*it2], 1}; \
|
||||||
|
} \
|
||||||
|
} else { \
|
||||||
|
double multiplier = 1.0 / (a->direction.size() + b->direction.size()); /* not a mistake */ \
|
||||||
|
for(auto ar : a->direction) { \
|
||||||
|
for(auto br : b->direction) { \
|
||||||
|
*ptr++ = (MetaEdge) {&ys[ar][br], multiplier}; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
X(forward)
|
||||||
|
X(backward)
|
||||||
|
#undef X
|
||||||
|
*ptr++ = (MetaEdge) {mv.dest, 0.1};
|
||||||
|
*ptr++ = (MetaEdge) {NULL, 0};
|
||||||
|
mvs.push_back(mv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size = mvs.size();
|
||||||
|
MetaVertex *mvp = &mvs[0];
|
||||||
|
|
||||||
for(int iteration = 0; iteration < 6; iteration++) {
|
for(int iteration = 0; iteration < 6; iteration++) {
|
||||||
|
fprintf(stderr, "%d (%zd to go)\n", iteration, size);
|
||||||
if(0) {
|
if(0) {
|
||||||
// debug
|
// debug
|
||||||
printf("--\n");
|
printf("--\n");
|
||||||
@ -457,41 +576,15 @@ static list<pair<Function *, Function *>> doMatch(Binary *ba, Binary *bb) {
|
|||||||
}
|
}
|
||||||
F(0x80063890)
|
F(0x80063890)
|
||||||
}
|
}
|
||||||
// 5.1
|
MetaVertex *mymvp = mvp;
|
||||||
for(auto group : ba->edgesByHash) {
|
for(size_t i = 0; i < size; i++, mymvp++) {
|
||||||
for(auto edge1 : group.second) {
|
MetaEdge *edge = mymvp->edges;
|
||||||
for(auto edge2 : bb->edgesByHash[edge1->hash]) {
|
double result = 0;
|
||||||
ys[edge1][edge2] = xs[edge1->source][edge2->source] + xs[edge1->dest][edge2->dest];
|
while(edge->source) {
|
||||||
}
|
result += edge->weight * *edge->source;
|
||||||
}
|
edge++;
|
||||||
}
|
|
||||||
|
|
||||||
// 5.2, tweaked to account for order
|
|
||||||
// not perfect
|
|
||||||
// but that needs be divided by something
|
|
||||||
for(auto a : ba->funcsList) {
|
|
||||||
for(auto b : bb->funcsByHash[a->hash]) {
|
|
||||||
#define X(direction) \
|
|
||||||
if(a->direction.size() == b->direction.size()) { \
|
|
||||||
for(auto it = a->direction.begin(), it2 = b->direction.begin(); \
|
|
||||||
it != a->direction.end(); \
|
|
||||||
it++, it2++) { \
|
|
||||||
result += ys[*it][*it2]; \
|
|
||||||
} \
|
|
||||||
} else { \
|
|
||||||
double temp = 0; \
|
|
||||||
for(auto ar : a->direction) { \
|
|
||||||
for(auto br : b->direction) { \
|
|
||||||
temp += ys[ar][br]; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
result += temp / (a->direction.size() + b->direction.size()); /* not a mistake */ \
|
|
||||||
}
|
|
||||||
double result = 0;
|
|
||||||
X(forward)
|
|
||||||
X(backward)
|
|
||||||
xs[a][b] = result;
|
|
||||||
}
|
}
|
||||||
|
*mymvp->dest = result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -499,13 +592,16 @@ static list<pair<Function *, Function *>> doMatch(Binary *ba, Binary *bb) {
|
|||||||
|
|
||||||
for(auto p : xs) {
|
for(auto p : xs) {
|
||||||
Function *maxFunction = NULL;
|
Function *maxFunction = NULL;
|
||||||
|
if(explain) printf("%08x (%s):\n", p.first->startAddr, p.first->name);
|
||||||
double maxValue = -1;
|
double maxValue = -1;
|
||||||
for(auto p2 : p.second) {
|
for(auto p2 : p.second) {
|
||||||
|
if(explain) printf(" %x=%f (predict:%f,%f)\n", p2.first->startAddr, p2.second, p.first->predict(p2.first), p2.first->predict(p.first));
|
||||||
if(p2.second > maxValue) {
|
if(p2.second > maxValue) {
|
||||||
maxValue = p2.second;
|
maxValue = p2.second;
|
||||||
maxFunction = p2.first;
|
maxFunction = p2.first;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(explain) printf("Max: %x\n\n", maxFunction ? maxFunction->startAddr : 0);
|
||||||
if(maxFunction) {
|
if(maxFunction) {
|
||||||
result.push_back(make_pair(p.first, maxFunction));
|
result.push_back(make_pair(p.first, maxFunction));
|
||||||
}
|
}
|
||||||
@ -529,30 +625,41 @@ static list<pair<Function *, Function *>> doMatchTrivially(Binary *ba, Binary *b
|
|||||||
|
|
||||||
int main(__unused int argc, char **argv) {
|
int main(__unused int argc, char **argv) {
|
||||||
argv++;
|
argv++;
|
||||||
Binary ba(*argv++);
|
Binary *ba = NULL;
|
||||||
while(auto arg = *argv++)
|
while(auto arg = *argv++)
|
||||||
if(!strncmp(arg, "--", 2)) {
|
if(!strncmp(arg, "--", 2)) {
|
||||||
string mode = arg;
|
string mode = arg;
|
||||||
if(mode == "--list") {
|
if(mode.find("--hash=") == 0) {
|
||||||
|
string type = mode.substr(7);
|
||||||
|
if(type == "beginning") hashMode = BEGINNING_HASH;
|
||||||
|
else if(type == "ending") hashMode = ENDING_HASH;
|
||||||
|
else if(type == "full") hashMode = FULL_HASH;
|
||||||
|
} else if(mode == "--list") {
|
||||||
printf("List of funcs:\n");
|
printf("List of funcs:\n");
|
||||||
bool refs = false;
|
bool refs = false;
|
||||||
if(*argv && !strcmp(*argv, "--refs")) {
|
if(*argv && !strcmp(*argv, "--refs")) {
|
||||||
refs = true;
|
refs = true;
|
||||||
argv++;
|
argv++;
|
||||||
}
|
}
|
||||||
for(auto func : ba.funcsList) {
|
for(auto func : ba->funcsList) {
|
||||||
printf("%x-%x l=%ld h=%x n=%s f=%d b=%d t=%d\n", func->startAddr, (addr_t) (func->startAddr + 2*(func->end - func->start)), func->end - func->start, func->hash, func->name, (int) func->forward.size(), (int) func->backward.size(), func->type);
|
printf("%x-%x l=%ld h=%x n=%s f=%d b=%d t=%d\n", func->startAddr, (addr_t) (func->startAddr + 2*(func->end - func->start)), func->end - func->start, func->hash, func->name, (int) func->forward.size(), (int) func->backward.size(), func->type);
|
||||||
if(refs) for(auto ref : func->refs) {
|
if(refs) for(auto ref : func->refs) {
|
||||||
printf(" r:%x->%x\n", (int) ref.first, (int) ref.second);
|
printf(" r:%x->%x (%s)\n", (int) ref.first.first, (int) ref.first.second, ref.second ? "(code)" : "(data)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if(mode == "--cut") {
|
} else if(mode == "--cut") {
|
||||||
Binary bb(*argv++);
|
Binary bb(*argv++);
|
||||||
doCutPoints(&ba, &bb);
|
bool explain = false;
|
||||||
|
if(*argv && !strcmp(*argv, "--explain")) {
|
||||||
|
explain = true;
|
||||||
|
argv++;
|
||||||
|
}
|
||||||
|
doCutPoints(ba, &bb, explain);
|
||||||
} else if(mode == "--byHash") {
|
} else if(mode == "--byHash") {
|
||||||
printf("List of funcs by hash:\n");
|
printf("List of funcs by hash:\n");
|
||||||
|
ba->doHashes();
|
||||||
|
|
||||||
for(auto p : ba.funcsByHash) {
|
for(auto p : ba->funcsByHash) {
|
||||||
printf("%d - [%08x]:", (int) p.second.size(), p.first);
|
printf("%d - [%08x]:", (int) p.second.size(), p.first);
|
||||||
for(auto func : p.second) {
|
for(auto func : p.second) {
|
||||||
printf(" %x", func->startAddr);
|
printf(" %x", func->startAddr);
|
||||||
@ -562,9 +669,9 @@ int main(__unused int argc, char **argv) {
|
|||||||
|
|
||||||
} else if(mode == "--compare") {
|
} else if(mode == "--compare") {
|
||||||
Binary bb(*argv++);
|
Binary bb(*argv++);
|
||||||
for(auto p : ba.reverseSymbols) {
|
for(auto p : ba->reverseSymbols) {
|
||||||
auto myAddr = p.first, otherAddr = b_sym(&bb.binary, p.second, TO_EXECUTE);
|
auto myAddr = p.first, otherAddr = b_sym(&bb.binary, p.second, TO_EXECUTE);
|
||||||
auto first = ba.funcs[myAddr], second = bb.funcs[otherAddr];
|
auto first = ba->funcs[myAddr], second = bb.funcs[otherAddr];
|
||||||
if(first && second) {
|
if(first && second) {
|
||||||
double forward = first->predict(second), backward = second->predict(first);
|
double forward = first->predict(second), backward = second->predict(first);
|
||||||
printf("%.32s (%08x/%08x): %f\n", p.second, myAddr, otherAddr, (forward + backward) / 2);
|
printf("%.32s (%08x/%08x): %f\n", p.second, myAddr, otherAddr, (forward + backward) / 2);
|
||||||
@ -572,25 +679,30 @@ int main(__unused int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
} else if(mode == "--matchF" || mode == "--matchB" || mode == "--trivial") {
|
} else if(mode == "--matchF" || mode == "--matchB" || mode == "--trivial") {
|
||||||
Binary bb(*argv++);
|
Binary bb(*argv++);
|
||||||
|
bool explain = false;
|
||||||
|
if(*argv && !strcmp(*argv, "--explain")) {
|
||||||
|
explain = true;
|
||||||
|
argv++;
|
||||||
|
}
|
||||||
list<pair<Function *, Function *>> result;
|
list<pair<Function *, Function *>> result;
|
||||||
if(mode == "--matchF") {
|
if(mode == "--matchF") {
|
||||||
result = doMatch(&ba, &bb);
|
result = doMatch(ba, &bb, explain);
|
||||||
} else if(mode == "--matchB") {
|
} else if(mode == "--matchB") {
|
||||||
for(auto p : doMatch(&bb, &ba)) result.push_back(make_pair(p.second, p.first));
|
for(auto p : doMatch(&bb, ba, explain)) result.push_back(make_pair(p.second, p.first));
|
||||||
} else if(mode == "--trivial") {
|
} else if(mode == "--trivial") {
|
||||||
result = doMatchTrivially(&ba, &bb);
|
result = doMatchTrivially(ba, &bb);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!strcmp(*argv, "--audit")) {
|
if(*argv && !strcmp(*argv, "--audit")) {
|
||||||
for(auto p : result) {
|
for(auto p : result) {
|
||||||
const char *trueName = ba.reverseSymbols[p.first->startAddr];
|
const char *trueName = ba->reverseSymbols[p.first->startAddr];
|
||||||
const char *name = bb.reverseSymbols[p.second->startAddr];
|
const char *name = bb.reverseSymbols[p.second->startAddr];
|
||||||
if(name && trueName && strcmp(name, trueName)) {
|
if(name && trueName && strcmp(name, trueName)) {
|
||||||
printf("Wrong: %x=%x (%s = %s)\n", p.first->startAddr, p.second->startAddr, trueName, name);
|
printf("Wrong: %x=%x (%s = %s)\n", p.first->startAddr, p.second->startAddr, trueName, name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
argv++;
|
argv++;
|
||||||
} else if(!strcmp(*argv, "--explain")) {
|
} else if(*argv && !strcmp(*argv, "--show")) {
|
||||||
for(auto p : result) {
|
for(auto p : result) {
|
||||||
auto func1 = p.first, func2 = p.second;
|
auto func1 = p.first, func2 = p.second;
|
||||||
printf("%08x/%08x %f/%f %s/%s\n", func1->startAddr, func2->startAddr, func1->predict(func2), func2->predict(func1), func1->name, func2->name);
|
printf("%08x/%08x %f/%f %s/%s\n", func1->startAddr, func2->startAddr, func1->predict(func2), func2->predict(func1), func1->name, func2->name);
|
||||||
@ -599,13 +711,13 @@ int main(__unused int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for(auto p : result) {
|
for(auto p : result) {
|
||||||
p.first->name = p.second->name;
|
ba->setFuncName(p.first, p.second->name);
|
||||||
}
|
}
|
||||||
} else if(mode == "--clear") {
|
} else if(mode == "--clear") {
|
||||||
// HACK
|
// HACK
|
||||||
for(auto func : ba.funcsList) {
|
for(auto func : ba->funcsList) {
|
||||||
if(func->name && strcmp(func->name, "__ZN11OSMetaClassC2EPKcPKS_j") && strcmp(func->name, "__ZNK11OSMetaClass19instanceConstructedEv"))
|
if(func->name && strcmp(func->name, "__ZN11OSMetaClassC2EPKcPKS_j") && strcmp(func->name, "__ZNK11OSMetaClass19instanceConstructedEv"))
|
||||||
ba.setFuncName(func, NULL);
|
ba->setFuncName(func, NULL);
|
||||||
}
|
}
|
||||||
} else if(mode == "--vt") {
|
} else if(mode == "--vt") {
|
||||||
bool explain = false;
|
bool explain = false;
|
||||||
@ -613,14 +725,37 @@ int main(__unused int argc, char **argv) {
|
|||||||
explain = true;
|
explain = true;
|
||||||
argv++;
|
argv++;
|
||||||
}
|
}
|
||||||
ba.identifyVtables(explain);
|
ba->identifyVtables(explain);
|
||||||
|
} else if(mode == "--manual") {
|
||||||
|
const char *name = *argv++;
|
||||||
|
string mode = *argv++;
|
||||||
|
addr_t addr;
|
||||||
|
auto range = b_macho_segrange(&ba->binary, "__TEXT");
|
||||||
|
if(mode == "strref") {
|
||||||
|
addr = find_bof(range, find_int32(range, find_string(range, *argv++, 1, MUST_FIND), MUST_FIND), 2);
|
||||||
|
} else if(mode == "inline-strref") {
|
||||||
|
addr = find_bof(range, find_string(range, *argv++, 1, MUST_FIND), 2);
|
||||||
|
} else if(mode == "pattern") {
|
||||||
|
addr = find_data(range, *argv++, 0, MUST_FIND);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "? %s\n", mode.c_str());
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
auto func = ba->funcs[addr];
|
||||||
|
if(!func) {
|
||||||
|
fprintf(stderr, "not a Function: %x\n", addr);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
ba->setFuncName(func, name);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "? %s\n", mode.c_str());
|
fprintf(stderr, "? %s\n", mode.c_str());
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
} else if(!ba) {
|
||||||
|
ba = new Binary(arg);
|
||||||
} else {
|
} else {
|
||||||
// write back
|
// write back
|
||||||
ba.injectSymbols(arg);
|
ba->injectSymbols(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
#include <data/mach-o/link.h>
|
#include <data/mach-o/link.h>
|
||||||
#include "lambda.h"
|
#include "lambda.h"
|
||||||
|
|
||||||
extern unsigned char sandbox_o[];
|
extern unsigned char sandbox_armv6_o[], sandbox_armv7_o[];
|
||||||
extern unsigned int sandbox_o_len;
|
extern unsigned int sandbox_armv6_o_len, sandbox_armv7_o_len;
|
||||||
|
|
||||||
int patchfd;
|
int patchfd;
|
||||||
|
|
||||||
@ -111,7 +111,10 @@ void do_kernel(struct binary *binary, struct binary *sandbox) {
|
|||||||
DECL_LAMBDA(l, uint32_t, (const char *name), {
|
DECL_LAMBDA(l, uint32_t, (const char *name), {
|
||||||
if(!strcmp(name, "c_sb_evaluate_orig1")) return b_read32(binary, sb_evaluate);
|
if(!strcmp(name, "c_sb_evaluate_orig1")) return b_read32(binary, sb_evaluate);
|
||||||
if(!strcmp(name, "c_sb_evaluate_orig2")) return b_read32(binary, sb_evaluate + 4);
|
if(!strcmp(name, "c_sb_evaluate_orig2")) return b_read32(binary, sb_evaluate + 4);
|
||||||
if(!strcmp(name, "c_sb_evaluate_jumpto")) return sb_evaluate + (is_armv7 ? 9 : 8);
|
if(!strcmp(name, "c_sb_evaluate_orig3")) return b_read32(binary, sb_evaluate + 8);
|
||||||
|
if(!strcmp(name, "c_sb_evaluate_orig4")) return b_read32(binary, sb_evaluate + 12);
|
||||||
|
if(!strcmp(name, "c_sb_evaluate_jumpto")) return sb_evaluate + (is_armv7 ? 17 : 16);
|
||||||
|
|
||||||
if(!strcmp(name, "c_memcmp")) return _memcmp;
|
if(!strcmp(name, "c_memcmp")) return _memcmp;
|
||||||
if(!strcmp(name, "c_vn_getpath")) return _vn_getpath;
|
if(!strcmp(name, "c_vn_getpath")) return _vn_getpath;
|
||||||
//if(!strcmp(name, "c_dvp_struct_offset")) return spec2(0xde, 0xad, 0xbe);
|
//if(!strcmp(name, "c_dvp_struct_offset")) return spec2(0xde, 0xad, 0xbe);
|
||||||
@ -119,6 +122,7 @@ void do_kernel(struct binary *binary, struct binary *sandbox) {
|
|||||||
})
|
})
|
||||||
b_relocate(sandbox, (void *) l.arg, (void *) l.func, 0);
|
b_relocate(sandbox, (void *) l.arg, (void *) l.func, 0);
|
||||||
prange_t sandbox_pr = rangeconv_off(sandbox->segments[0].file_range, MUST_FIND);
|
prange_t sandbox_pr = rangeconv_off(sandbox->segments[0].file_range, MUST_FIND);
|
||||||
|
store_file(sandbox_pr, "/tmp/wtf.o", 0644);
|
||||||
patch_with_range("sb_evaluate hook",
|
patch_with_range("sb_evaluate hook",
|
||||||
scratch,
|
scratch,
|
||||||
sandbox_pr);
|
sandbox_pr);
|
||||||
@ -140,7 +144,7 @@ int main(int argc, char **argv) {
|
|||||||
b_init(&kernel);
|
b_init(&kernel);
|
||||||
b_init(&sandbox);
|
b_init(&sandbox);
|
||||||
b_load_macho(&kernel, argv[1]);
|
b_load_macho(&kernel, argv[1]);
|
||||||
b_prange_load_macho(&sandbox, (prange_t) {&sandbox_o, sandbox_o_len}, 0, "sandbox.o");
|
b_prange_load_macho(&sandbox, kernel.actual_cpusubtype == 9 ? (prange_t) {sandbox_armv7_o, sandbox_armv7_o_len} : (prange_t) {sandbox_armv6_o, sandbox_armv6_o_len}, 0, "sandbox.o");
|
||||||
|
|
||||||
patchfd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
patchfd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||||
if(patchfd == -1) {
|
if(patchfd == -1) {
|
||||||
|
18
nm.c
18
nm.c
@ -1,20 +1,24 @@
|
|||||||
#include <data/mach-o/binary.h>
|
#include <data/mach-o/binary.h>
|
||||||
|
#include <data/dyldcache/binary.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
static void usage() {
|
static void usage() {
|
||||||
fprintf(stderr, "Usage: nm [-exp] binary [symbol]\n");
|
fprintf(stderr, "Usage: nm [-exp] [-c subfile] binary [symbol]\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
|
|
||||||
|
const char *subfile = NULL;
|
||||||
|
|
||||||
int c;
|
int c;
|
||||||
while((c = getopt(argc, argv, "ixp")) != -1) switch(c) {
|
while((c = getopt(argc, argv, "ixpc:")) != -1) switch(c) {
|
||||||
case 'i': flags |= IMPORTED_SYM; break;
|
case 'i': flags |= IMPORTED_SYM; break;
|
||||||
case 'x': flags |= TO_EXECUTE; break;
|
case 'x': flags |= TO_EXECUTE; break;
|
||||||
case 'p': flags |= PRIVATE_SYM; break;
|
case 'p': flags |= PRIVATE_SYM; break;
|
||||||
|
case 'c': subfile = optarg; break;
|
||||||
default: usage();
|
default: usage();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -22,7 +26,15 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
struct binary binary;
|
struct binary binary;
|
||||||
b_init(&binary);
|
b_init(&binary);
|
||||||
b_load_macho(&binary, argv[optind]);
|
if(subfile) {
|
||||||
|
struct binary other;
|
||||||
|
b_init(&other);
|
||||||
|
b_load_dyldcache(&other, argv[optind]);
|
||||||
|
b_dyldcache_load_macho(&other, subfile, &binary);
|
||||||
|
} else {
|
||||||
|
b_load_macho(&binary, argv[optind]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if(argv[optind + 1]) {
|
if(argv[optind + 1]) {
|
||||||
printf("%8x\n", b_sym(&binary, argv[optind + 1], flags));
|
printf("%8x\n", b_sym(&binary, argv[optind + 1], flags));
|
||||||
|
16
sandbox.S
16
sandbox.S
@ -62,23 +62,19 @@ actually_eval:
|
|||||||
ldr r1, orig_addr
|
ldr r1, orig_addr
|
||||||
mov r9, r1
|
mov r9, r1
|
||||||
|
|
||||||
# XXX - this is really stupid; it should be handled at compile time
|
|
||||||
movs r2, #1
|
|
||||||
tst r1, r2
|
|
||||||
pop {r0-r4}
|
pop {r0-r4}
|
||||||
add sp, #4
|
add sp, #4
|
||||||
beq armlol
|
|
||||||
.long c_sb_evaluate_orig1
|
#ifndef __ARM_ARCH_7A__
|
||||||
.long c_sb_evaluate_orig2
|
|
||||||
bx r9
|
|
||||||
armlol:
|
|
||||||
bx pc
|
bx pc
|
||||||
|
.align 2
|
||||||
.arm
|
.arm
|
||||||
.align 2
|
#endif
|
||||||
.long c_sb_evaluate_orig1
|
.long c_sb_evaluate_orig1
|
||||||
.long c_sb_evaluate_orig2
|
.long c_sb_evaluate_orig2
|
||||||
|
.long c_sb_evaluate_orig3
|
||||||
|
.long c_sb_evaluate_orig4
|
||||||
bx r9
|
bx r9
|
||||||
|
|
||||||
|
|
||||||
.align 2
|
.align 2
|
||||||
var_mobile: .ascii "/private/var/mobile"
|
var_mobile: .ascii "/private/var/mobile"
|
||||||
|
Loading…
Reference in New Issue
Block a user