浅谈Mac应用逆向破解
视频讲解:https://www.youtube.com/watch?v=WcgTJhmloMk
0x01 Mac应用分类
- 文件格式
- 解释器脚本格式
- 通用二进制格式
- Mach-O 格式
- 常见编写方式
- 原生Object-C、Swift
- 其他编程语言
- Electron
0x02 Mac逆向常用工具
- 反汇编
- Hopper Disassembler
- IDA Pro
- hook工具
- Frida
- 头文件提取
- class-dump
0x03 破解的切入点
- 关键词搜索
- 根据提示找判断点
- 根据激活找校验
0x04 小技巧
dump 头文件
class-dump -S -s -H -o ./Headers filename
快速获取方法在进程中的调用
frida-trace -m "-[* methodname*]" 进程
文件中查询字符串
grep -r -i "string" ./
frida 脚本
- hook方法调用信息
const targetClass = ObjC.classes.%s;
let methodName = "%s";
Interceptor.attach(targetClass[methodName].implementation, {
onEnter(args) {
console.log("\n================================");
const reciver = ObjC.Object(args[0]);
console.log("Target class: " + reciver);
console.log("Target class address: " + ptr(args[0]));
let ivars = reciver.$ivars;
for(let k in ivars){
let v = ivars[k];
console.log(`ivars:[${k}] -> [${v}]`);
}
console.log("Target superClass: " + reciver.$superClass);
const sel = ObjC.selectorAsString(args[1]);
console.log("Hooked the target method: " + sel);
let index = 0;
let arg_num = methodName.split(":").length - 1;
if(arg_num > 0){
while(index < arg_num){
index = index + 1;
let obj = ObjC.Object(args[index + 1]);
console.log("Argument" + String(index) + ": " + obj.toString());
}
}
},
onLeave(retval) {
const ob1 = ObjC.Object(retval);
console.log("Retval: " + retval);
console.log("ObjC Retval: " + ob1.toString());
console.log("Type: " + ob1.$className);
console.log("SuperClass: " + ob1.$superClass);
console.log("");
}
});
- 枚举类所拥有的方法
const className = "%s";
const info = {}
const hookOwnMethods = ObjC.classes[className].$ownMethods;
const hookAllMethods = ObjC.classes[className].$methods;
const hookClasses = ObjC.classes;
info["ownMethods"] = hookOwnMethods;
//info["methods"] = hookAllMethods;
//info["allClasses"] = hookClasses;
console.log(JSON.stringify(info))
- 枚举进程所拥有的模块
var modules = Process.enumerateModules();
for(var i=0;i<modules.length;i++){
console.log(`== Name: ${modules[i].name} <${modules[i].base}>`);
}
- 根据模块和偏移获取方法
/**
* 根据module名字和目标方法的偏移地址获得方法的绝对地址
*/
function get_func_addr(module, offset) {
// 根据名字获取module地址
var base_addr = Module.findBaseAddress(module);
console.log("base_addr: " + base_addr);
console.log(hexdump(ptr(base_addr), {
length: 16,
header: true,
ansi: true
}));
var func_addr = base_addr.add(offset);
var return_addr;
if (Process.arch == 'arm')
return_addr = func_addr.add(1); //如果是32位地址+1
else
return_addr = func_addr;
console.log('func_addr: ' + return_addr);
console.log(hexdump(ptr(return_addr), {
length: 16,
header: true,
ansi: true
}));
return return_addr;
}
let moduleName = "%s";
let offset = %s
// 获取目标函数的绝对地址
var func_addr = get_func_addr(moduleName, offset);
Interceptor.attach(ptr(func_addr), {
onEnter: function(args) {
console.log("====onEnter=====");
let index = 0;
for(let arg of args){
console.log("arg" + String(index)+ ": " + arg);
}
// console.log("arg0: " + args[0]);
// console.log(hexdump(ptr(args[0]), {
// length: 64,
// header: false,
// ansi: false
// }))
// console.log("arg1: " + args[1]);
// console.log("arg2: " + args[2]);
},
onLeave: function(retval) {
console.log("====onLeave=====");
console.log("retval: " + retval);
// console.log(hexdump(ptr(retval), {
// length: 64,
// header: true,
// ansi: true
// }))
}
});
- json转换为Object-C
var NSString = ObjC.classes.NSString;
var NSJSONSerialization = ObjC.classes.NSJSONSerialization;
function json_to_objc(data){
let strData = NSString.stringWithString_(data).dataUsingEncoding_(0x4);
return NSJSONSerialization.JSONObjectWithData_options_error_(strData,0x1,ptr(0x0));
}
console.log(json_to_objc('%s'));
0x05 Typora Crack
- 关键词
- license/License
- hasLicense
- 提示
- 未激活
- UNREGISTERED
- 激活api
- api/client/activate
0x06 Reference
Mach-O 文件格式探索 · GitBook (desgard.com)
MacOS逆向 - 『脱壳破解区』 (52pojie.cn)
https://frida.re/docs/examples/macos/
https://developer.apple.com/cn/search/?type=Documentation&q=
ios逆向工具Hopper Disassembler的基本使用功能整理(持续更新)_小手琴师的博客-CSDN博客_hopper disassembler