hook绕过
一、环境及背景
pixel 2
某app (***企业版加固)
frida 15.1.28
二、hook绕过
启用frida并更改端口没有发现检测行为但是直接hook会闪退
打印so 调用堆栈
function hook_pthread(){
var pthread_create_addr = Module.findExportByName(null, 'pthread_create
var pthread_create = new NativeFunction(pthread_create_addr, "int", ["pointer", "pointer", "pointer", "pointer"]);
Interceptor.replace(pthread_create_addr, new NativeCallback(function (parg0, parg1, parg2, parg3) {
var so_name = Process.findModuleByAddress(parg2).name;
var so_path = Process.findModuleByAddress(parg2).path;
var so_base = Module.getBaseAddress(so_name);
var offset = parg2 - so_base;
var PC = 0;
if ((so_name.indexOf("libexec.so") > -1)) {
console.log("find thread func offset", so_name, offset);
} else {
PC = pthread_create(parg0, parg1, parg2, parg3);
}
return PC;
}, "int", ["pointer", "pointer", "pointer", "pointer"]))
}
hook_pthread();
找到了libexec.so开启pthread_create的偏移量,对其进行bypass,即
function hook_pthread() {
var pthread_create_addr = Module.findExportByName(null, 'pthread_create');
var pthread_create = new NativeFunction(pthread_create_addr, "int", ["pointer", "pointer", "pointer", "pointer"]);
Interceptor.replace(pthread_create_addr, new NativeCallback(function (parg0, parg1, parg2, parg3) {
var so_name = Process.findModuleByAddress(parg2).name;
var so_path = Process.findModuleByAddress(parg2).path;
var so_base = Module.getBaseAddress(so_name);
var offset = parg2 - so_base;
var PC = 0;
if ((so_name.indexOf("libexec.so") > -1)) {
console.log("find thread func offset", so_name, offset);
if ((207076 === offset)) {
console.log("anti bypass");
} else if (207308 === offset) {
console.log("anti bypass");
} else if (283820 === offset) {
console.log("anti bypass");
} else if (286488 === offset) {
console.log("anti bypass");
} else if (292416 === offset) {
console.log("anti bypass");
} else if (78136 === offset) {
console.log("anti bypass");
} else if (293768 === offset) {
console.log("anti bypass");
} else {
PC = pthread_create(parg0, parg1, parg2, parg3);
}
} else {
PC = pthread_create(parg0, parg1, parg2, parg3);
}
return PC;
}, "int", ["pointer", "pointer", "pointer", "pointer"]))
}
hook_pthread();
已经对其进行绕过frida的检测
class的遍历和hook
绕过frida的检测之后,开始对其加载的class以及class中的函数进行遍历
Java.enumerateLoadedClasses({
onMatch: function(className) {
console.log("found class >> " + className);
//遍历类中所有的方法和属性
var jClass = Java.use(className);
console.log(JSON.stringify({
_name: className,
_methods: Object.getOwnPropertyNames(jClass.__proto__).filter(function(m) {
return !m.startsWith('$') // filter out Frida related special properties
|| m == 'class' || m == 'constructor' // optional
}),
_fields: jClass.class.getFields().map(function(f) {
return f.toString()
})
}, null, 2));
//遍历类中所有的方法和属性
},
onComplete: function() {
console.log("[*] class enuemration complete");
}
});
class和函数大部分已经被遍历出来了,但是由于是加固的,部分函数并没有被加载出来(意料之中),利用常规的框架尝试去执行。
//框架为
if(Java.available) {
Java.perform(function(){
var application = Java.use("android.app.Application");
application.attach.overload('android.content.Context').implementation = function(context) {
var result = this.attach(context); // 先执行原来的attach方法
var classloader = context.getClassLoader(); // 获取classloader
Java.classFactory.loader = classloader;
var Hook_class = Java.classFactory.use("com.xxx.xxx"); // app的类
console.log("Hook_class: " + Hook_class);
// 下面代码和写正常的hook一样
Hook_class.函数.implementation = function() // 有参数填参数
{
}
return result;
}
});
}
发现会执行不成功,说明加固后的app没有用常规的classloader去加载函数。因此需要去遍历在加载app的时候,是哪些classloader被加载
1、可以通过重加载指定classloader去使得脱壳后的源码能在内存中被找到
2、可以一次性重加载所有调用的classloader去执行
//获取加固的classloader并hook函数
Java.enumerateClassLoaders({
onMatch: function(loader){
// 每次匹配到,都要把匹配到的赋值给java默认的loader
Java.classFactory.loader = loader;
var TryClass;
// console.log(loader); // 输出被加载的classloader
// 没报错就hook到了,报错了就hook下一个,如果全都报错了,没打印东西,那可能就是hook错了。
try{ // 每一次加载尝试是否可以找到想要的class
TryClass = Java.use("cn.xxx"); // 需要被加载之后查询的类
TryClass.xx.implementation = function(p1,p2){ // 类的函数
console.log('p1:'+p1)
console.log('p2:'+p2)
return this.xx(p1,p2)
}
}catch(error){
if(error.message.includes("ClassNotFoundException")){
console.log(" You are trying to load encrypted class, trying next loader");
}
else{
console.log(error.message);
}
}
},
onComplete: function(){
}
})
用2的方法被加载成功。
总结
最终成功实现在***企业版中去hook数据,当然这需要成功的脱壳之后查看原app存在哪些函数才行。依靠遍历出来的class。
作者:0x0101 ,文章转载于先知社区
END
• 往期精选
下方点击关注发现更多精彩
原文始发于微信公众号(银河护卫队super):某企业版加固app绕过hook