一
解题情况
二
大概解题思路
三
具体解题过程
function WriteMemToFile(addr, size, file_path) {
Java.perform(function() {
var prefix = '/data/data/com.com.sec2023.rocketmouse.mouse/files/'var mkdir = Module.findExportByName('libc.so', 'mkdir');
var chmod = Module.findExportByName('libc.so', 'chmod');
var fopen = Module.findExportByName('libc.so', 'fopen');
var fwrite = Module.findExportByName('libc.so', 'fwrite');
var fclose = Module.findExportByName('libc.so', 'fclose');var call_mkdir = new NativeFunction(mkdir, 'int', ['pointer', 'int']);
var call_chmod = new NativeFunction(chmod, 'int', ['pointer', 'int']);
var call_fopen =
new NativeFunction(fopen, 'pointer', ['pointer', 'pointer']);
var call_fwrite =
new NativeFunction(fwrite, 'int', ['pointer', 'int', 'int', 'pointer']);
var call_fclose = new NativeFunction(fclose, 'int', ['pointer']);call_mkdir(Memory.allocUtf8String(prefix), 0x1FF);
call_chmod(Memory.allocUtf8String(prefix), 0x1FF);
var fp = call_fopen(
Memory.allocUtf8String(prefix + file_path),
Memory.allocUtf8String('wb'));
if (call_fwrite(addr, 1, size, fp)) {
console.log('[+] Write file success, file path: ' + prefix + file_path);
} else {
console.log('[x] Write file failed');
}call_fclose(fp);
});
}function HookLibWithCallback(name, callback) {
var dlopen = Module.findExportByName('libdl.so', 'dlopen');
var detach_listener = Interceptor.attach(dlopen, {
onEnter: function(args) {
var cur = args[0].readCString();
console.log('[+] dlopen called, name: ' + cur);
if (cur.indexOf(name) != -1) {
this.hook = true;
}
},
onLeave: function() {
if (this.hook) {
console.log('[+] Hook Lib success, name:', name);
callback();
detach_listener.detach();
}
}
});
}function DumpIL2CPP() {
var libil2cpp = TraverseModules('single', {name: 'libil2cpp.so'});
WriteMemToFile(libil2cpp.base, libil2cpp.size, 'libil2cpp.so');
}function main() {
HookLibWithCallback('libil2cpp.so', DumpIL2CPP);
}main();
function PatchIncrease() {
var libil2cpp = TraverseModules('single', {name: 'libil2cpp.so'});
var insn = libil2cpp.base.add(0x465674);
console.log('[+] Patching..');
Memory.protect(insn, 4, 'rwx');
insn.writeByteArray([0x01, 0xA0, 0x0F, 0x11]);
}
function HookSmallKeyboard$$parse_input_iI1Ii_4610736() {
var libil2cpp = TraverseModules('single', {name: 'libil2cpp.so'});
var HookSmallKeyboard$$parse_input_iI1Ii_4610736 =
libil2cpp.base.add(0x465AB4);
Interceptor.attach(HookSmallKeyboard$$parse_input_iI1Ii_4610736, {
onEnter: function(args) {
PrintNativeBackTraceFuzzy(this.context, TraverseModules('all', {}));
console.log('[+] HookSmallKeyboard$$parse_input_iI1Ii_4610736 called');
console.log('input_key: ', args[1]);
Dump_g_sec2023_o_array();
}
});
}
// 假设输入了1111,则key会变成0x7d8174410d817fa
// [+] HookSmallKeyboard$$parse_input_iI1Ii_4610736 called
// input_key: 0x7d8174410d817fa
function get_reg_code() {
var libil2cpp = TraverseModules('single', {name: 'libil2cpp.so'});
var ctor = libil2cpp.base.add(0x4660E8);
Interceptor.attach(ctor, {
onEnter: function(args) {
console.log('[+] vm ctor called');
console.log('ipt_enc_high: ', this.context.x22);
},
onLeave: function(retval) {
console.log('[+] vm ctor returned');
}
});var loc_465D34 = libil2cpp.base.add(0x465D34);
Interceptor.attach(loc_465D34, {
onEnter: function(args) {
console.log('[+] get_reg_code called');
console.log('key_array: ', parseSystemArrayObjectU32(this.context.x20));
console.log('ipt_enc_high: ', this.context.x22);
console.log('ipt_enc_low: ', this.context.x21);
console.log('reg_code_i32: ', this.context.x0);
}
});
}
uint32_t key[4] = {0x7B777C63, 0xC56F6BF2, 0x2B670130, 0x76ABD7FE};
void EncryptXTEA(uint32_t *msg, uint32_t *key, ssize_t round) {
uint32_t v0 = msg[0], v1 = msg[1];
uint32_t delta = DELTA, sum = 0xBEEFBEEF;
for (ssize_t idx = 0; idx < round; idx++) {
v0 += (((v1 << 7) ^ (v1 >> 8)) + v1) ^ (sum - key[sum & 3]);
sum += delta;
v1 += (((v0 << 8) ^ (v0 >> 7)) - v0) ^ (sum + key[(sum >> 13) & 3]);
}
msg[0] = v0;
msg[1] = v1;
}
from emu_utils import *
from unicorn import *
from unicorn.arm64_const import *
# from ida_bytes import *def trace_back_insn_with_target(insn_queue, target_reg):
for insn in insn_queue:
if (target_reg in insn.op_str):
if (insn.mnemonic == 'add'):
print(insn.mnemonic + '\t' + insn.op_str)
if (insn.mnemonic == 'ldr'):
print(insn.mnemonic + '\t' + insn.op_str)
if (insn.mnemonic == 'csel'):
print(insn.mnemonic + '\t' + insn.op_str)def log_hook(emu, addr, size, user_data):
disasm = get_disasm(emu, addr, size)print(hex(addr) + '\t' + disasm.mnemonic + '\t' + disasm.op_str)
def step_over_hook(emu, addr, size, none):
disasm = get_disasm(emu, addr, size)if (disasm.mnemonic == 'bl' or disasm.mnemonic == 'blr'):
emu.reg_write(UC_ARM64_REG_PC, addr + size)if (disasm.mnemonic == 'ret'):
print('function returned')
emu.emu_stop()if (addr == 0x3ac68):
emu.reg_write(UC_ARM64_REG_W10, 0xEECF7326)def normal_hook(emu, addr, size, insn_queue):
global const_value, offset_value, cond, cond_value, uncond_value
disasm = get_disasm(emu, addr, size)
reg_maps = get_reg_maps()insn_queue.insert(0, disasm)
if (len(insn_queue) > 8):
insn_queue.pop()if (disasm.mnemonic == 'csel'):
cond_value = emu.reg_read(reg_maps[disasm.op_str.split(', ')[1]])
uncond_value = emu.reg_read(reg_maps[disasm.op_str.split(', ')[2]])
cond = disasm.op_str.split(', ')[3]if (disasm.mnemonic == 'cset'):
cond_value = 1
uncond_value = 0
cond = disasm.op_str.split(', ')[1]if (disasm.mnemonic == 'ldr'):
if (len(disasm.op_str.split(', ')) == 3):
offset_value = emu.reg_read(
reg_maps[disasm.op_str.split(', ')[1].split('[')[1]])
elif (len(disasm.op_str.split(', ')) == 4):
offset_value = emu.reg_read(
reg_maps[disasm.op_str.split(', ')[1].split('[')[1]])
cond_value *= 8if (disasm.mnemonic == 'add' and '#' not in disasm.op_str and 'w' not in disasm.op_str):
const_value = emu.reg_read(reg_maps[disasm.op_str.split(', ')[2]])if (disasm.mnemonic == 'br'):
print('on br insn')target_reg = disasm.op_str
trace_back_insn_with_target(insn_queue, target_reg)print(hex(const_value), hex(offset_value),
cond, cond_value, uncond_value)cond_addr = emu.mem_read(offset_value + cond_value, 4)
cond_addr = (int.from_bytes(
cond_addr, byteorder='little') + const_value) & 0xffffffff
uncond_addr = emu.mem_read(offset_value + uncond_value, 4)
uncond_addr = (int.from_bytes(
uncond_addr, byteorder='little') + const_value) & 0xffffffffpatch_asm = b''
patch_asm += get_asm('b' + cond + ' ' + hex(cond_addr), addr - 4)
patch_asm += get_asm('b ' + hex(uncond_addr), addr)
# patch_bytes(addr - 4, patch_asm)emu.reg_write(UC_ARM64_REG_PC, addr + size)
def emulate_execution(filename, start_addr, hook_func, user_data):
emu = Uc(UC_ARCH_ARM64, UC_MODE_LITTLE_ENDIAN)textSec = get_section(filename, '.text')
dataSec = get_section(filename, '.data')textSec_entry = textSec.header['sh_addr']
textSec_size = textSec.header['sh_size']
textSec_raw = textSec.header['sh_offset']TEXT_BASE = textSec_entry >> 12 << 12
TEXT_SIZE = (textSec_size + 0x1000) >> 12 << 12
TEXT_RBASE = textSec_raw >> 12 << 12dataSec_entry = dataSec.header['sh_addr']
dataSec_size = dataSec.header['sh_size']
dataSec_raw = dataSec.header['sh_offset']DATA_BASE = dataSec_entry >> 12 << 12
DATA_SIZE = (dataSec_size + 0x1000) >> 12 << 12
DATA_RBASE = dataSec_raw >> 12 << 12VOID_1_BASE = 0x00000000
VOID_1_SIZE = TEXT_BASEVOID_2_BASE = TEXT_BASE + TEXT_SIZE
VOID_2_SIZE = DATA_BASE - VOID_2_BASESTACK_BASE = DATA_BASE + DATA_SIZE
STACK_SIZE = 0xFFFFFFFF - STACK_BASE >> 12 << 12emu.mem_map(VOID_1_BASE, VOID_1_SIZE)
emu.mem_map(TEXT_BASE, TEXT_SIZE)
emu.mem_map(DATA_BASE, DATA_SIZE)
emu.mem_map(VOID_2_BASE, VOID_2_SIZE)
emu.mem_map(STACK_BASE, STACK_SIZE)emu.mem_write(TEXT_BASE, read(filename)[TEXT_RBASE:TEXT_RBASE+TEXT_SIZE])
emu.mem_write(DATA_BASE, read(filename)[DATA_RBASE:DATA_RBASE+DATA_SIZE])
emu.reg_write(UC_ARM64_REG_FP, STACK_BASE + 0x1000)
emu.reg_write(UC_ARM64_REG_SP, STACK_BASE + STACK_SIZE // 2)emu.hook_add(UC_HOOK_CODE, log_hook)
emu.hook_add(UC_HOOK_CODE, step_over_hook, user_data)
emu.hook_add(UC_HOOK_CODE, hook_func, user_data)emu.emu_start(start_addr, 0x0)
if __name__ == '__main__':
filename = './libsec2023.so'
start_addr = 0x3ac68insn_queue = []
emulate_execution(filename, start_addr, normal_hook, insn_queue)
void EncryptObfusedRoundI(uint32_t ipt[]) {
for (ssize_t idx = 0; idx < 2; ++idx) {
uint8_t buf[4] = {0}, tmp[4] = {0};for (ssize_t i = 0; i < 4; i++) {
buf[i] = ((uint8_t *)&ipt[idx])[i] ^ i;
}buf[3] ^= 0x86;
buf[2] -= 0x5E;
buf[1] ^= 0xD3;
buf[0] -= 0x1C;for (ssize_t i = 0; i < 4; i++) {
tmp[i] = buf[i] - i * 8;
}ipt[idx] = *(uint32_t *)&tmp;
}
}
function HookGetStaticMethodID() {
var libart = TraverseModules('single', {name: 'libart.so'});
var GetStaticMethodID = libart.base.add(0x3A87B4);
Interceptor.attach(GetStaticMethodID, {
onEnter: function(args) {
var clazz = args[1];
var name = args[2].readUtf8String();
var sig = args[3].readUtf8String();// get clazz name
var clazz_name = Java.vm.getEnv().getClassName(clazz);console.log(`[*] GetStaticMethodID called: ${clazz_name} ${name} ${sig}`);
}
});
}
uint32_t EncryptObfusedRoundII(uint32_t ipt) {
uint32_t n1 = 0, n2 = 0;
uint8_t result[4] = {0}, *buf = (uint8_t *)&ipt;
uint8_t key[8] = {0x32, 0xCD, 0xFF, 0x98, 0x19, 0xB2, 0x7C, 0x9A};n1 = __builtin_bswap32(*(uint32_t *)buf);
n2 = (n1 >> 7) | (n1 << 25);*(uint32_t *)result = __builtin_bswap32(n2);
for (int idx = 0; idx < 8; idx++) {
result[idx] = (result[idx] ^ key[idx % 8]);
result[idx] = (result[idx] + idx);
}return *(uint32_t *)result;
}
function ParseVMClazz(thiz) {
var fields = thiz.add(0x10);
var opcode = fields.add(0x00);
var input = fields.add(0x08);
var buf = fields.add(0x10);
var x = fields.add(0x18);
var cnt = fields.add(0x1C)
var maybe_idx = fields.add(0x20);
var num = fields.add(0x24);
var opdict = fields.add(0x28);
var vm_context = {
opcode: opcode.readPointer(),
input: input.readPointer(),
buf: buf.readPointer(),
x: x.readS32(),
cnt: cnt.readS32(),
maybe_idx: maybe_idx.readS32(),
num: num.readS32(),
opdict: opdict.readPointer(),
};
return vm_context;
}
function VMparser() {
var libil2cpp = TraverseModules('single', {name: 'libil2cpp.so'});var array_op_1_O00O0000O0o = libil2cpp.base.add(0x46B480);
Interceptor.attach(array_op_1_O00O0000O0o, {
onEnter: function(args) {
var x = ParseVMClazz(args[0]).x;
// console.log('[*] array_op_1_O00O0000O0o called');
console.log(` input[buf${x}] = buf${x - 1};`);
}
});var array_op_2_O00O00000oo = libil2cpp.base.add(0x46B4E8);
Interceptor.attach(array_op_2_O00O00000oo, {
onEnter: function(args) {
var x = ParseVMClazz(args[0]).x;
var opcode = ParseVMClazz(args[0]).opcode.add(32);
var cnt = ParseVMClazz(args[0]).cnt;
// console.log('[*] array_op_2_O00O00000oo called');
console.log(` input[${opcode.add(cnt * 2).readU16()}] = buf${x};`);
}
});var array_op_3_O00O0000OO = libil2cpp.base.add(0x46B3F8);
Interceptor.attach(array_op_3_O00O0000OO, {
onEnter: function(args) {
var x = ParseVMClazz(args[0]).x;
var opcode = ParseVMClazz(args[0]).opcode.add(32);
var cnt = ParseVMClazz(args[0]).cnt;
// console.log('[*] array_op_3_O00O0000OO called');
console.log(` buf${x + 1} = input[${opcode.add(cnt * 2).readU16()}];`);
}
});var array_op_4_O0O0000Ooo = libil2cpp.base.add(0x46B28C);
Interceptor.attach(array_op_4_O0O0000Ooo, {
onEnter: function(args) {
var opcode = ParseVMClazz(args[0]).opcode.add(32);
var cnt = ParseVMClazz(args[0]).cnt;
// console.log('[*] array_op_4_O0O0000Ooo called');
console.log(` cnt = ${opcode.add(cnt * 2).readU16()};`);
}
});
.....
...
}
register uint32_t buf0, buf1, buf2, buf3, buf4, buf5, cnt;
uint32_t input[8] = {0};
input[0] = ipt[0];
input[1] = ipt[1];buf0 = 24;
input[2] = buf0;
buf0 = input[0];
buf1 = input[2];
buf0 = ((~(buf0 + 0x100) | 0xFFFFFEFF) + 2 * buf0 +
(~(buf0 + 0x100) & 0xFFFFFEFF) + 0x202) >>
buf1;
buf1 = 255;
buf0 = (buf1 + (buf1 ^ ~buf0) + (~buf0 & ~buf1) + (buf0 & ~buf1) + 1) & buf0;
buf1 = input[2];
buf2 = 8;
buf1 = buf1 - buf2 + (buf1 ^ buf2) + (buf1 & buf2) - (buf1 | buf2);
input[2] = buf1;
buf1 = input[2];
buf2 = 0;
buf1 = buf1 < buf2;
if (buf1) {
cnt = 26;
} else {
cnt = 4;
}
.....
...
四
梳理加密过程,开整注册机
void DecryptXTEA(uint32_t *msg, uint32_t *key, ssize_t round) {
uint32_t v0 = msg[0], v1 = msg[1];
uint32_t delta = DELTA, sum = 0xBEEFBEEF + delta * round;
for (ssize_t idx = 0; idx < round; idx++) {
v1 -= (((v0 << 8) ^ (v0 >> 7)) - v0) ^ (sum + key[(sum >> 13) & 3]);
sum -= delta;
v0 -= (((v1 << 7) ^ (v1 >> 8)) + v1) ^ (sum - key[sum & 3]);
}
msg[0] = v0;
msg[1] = v1;
}
uint32_t DecryptObfusedRoundII(uint32_t enc) {
uint32_t n1 = 0, n2 = 0;
uint8_t result[4] = {0}, *buf = (uint8_t *)&enc;
uint8_t key[8] = {0x32, 0xCD, 0xFF, 0x98, 0x19, 0xB2, 0x7C, 0x9A};for (int idx = 0; idx < 8; idx++) {
result[idx] = (buf[idx] - idx);
result[idx] = (result[idx] ^ key[idx % 8]);
}n2 = __builtin_bswap32(*(uint32_t *)result);
n1 = (n2 << 7) | (n2 >> 25);return __builtin_bswap32(n1);
}
void DecryptObfusedRoundI(uint32_t enc[]) {
for (ssize_t idx = 0; idx < 2; ++idx) {
uint8_t buf[4] = {0}, tmp[4] = {0};*(uint32_t *)&tmp = enc[idx];
for (ssize_t i = 0; i < 4; i++) {
buf[i] = tmp[i] + i * 8;
}buf[3] ^= 0x86;
buf[2] += 0x5E;
buf[1] ^= 0xD3;
buf[0] += 0x1C;for (ssize_t i = 0; i < 4; i++) {
tmp[i] = buf[i] ^ i;
}enc[idx] = *(uint32_t *)&tmp;
}
}
看雪ID:fallw1nd
https://bbs.kanxue.com/user-home-887676.htm
# 往期推荐
3、安卓加固脱壳分享
球分享
球点赞
球在看