Android逆向(反调,脱壳,过ssl证书脚本)

总结

暑假做了两个月的Android逆向,记录一下自己学到的东西。对于app渗透有了一些思路。
这两个月主要做的是代码分析,对于分析完后的持久化等没有学习。主要是如何反编译源码,如何找到关键函数。
在这里插入图片描述

基础

Android基础

开始学习Android逆向,需要先掌握一些Android开发常见的知识点:

1、需要了解一个apk的目录架构,什么文件放在什么位置,将apk当作zip解压可以看到xml文件(声明入口,权限,服务等)、lib文件(so文件)、asserts文件等
2、知道一些常见的函数,(请求的url函数,处理json的函数等),便于后续hook,可以边学边记录,

工具

jadx:反编译工具,得到的java代码较清晰,但是可能会有部分反编译不了
GDA:反编译工具,相对于jadx可能稍微不太好读,但是该工具编译快,且能够直接调用frida,更加方便
frida:编写hook脚本,相对于xpose更加方便调试,但是持久化比xpose麻烦。
模拟器,或者是root的手机。

定位关键代码

在反编译完代码需要的是找到我们需要分析的功能点。

页面activity定位

首先打开我们功能点所在的页面,比如我想查看我的个人记录处的代码逻辑,我就需要打开对应的页面,然后使用下面的命令,查看表层的activity名称,然后去源代码中寻找对应的activity。

查看表层activity的名称
adb shell "dumpsys activity top | grep --color=always ACTIVITY"

在这里插入图片描述

数据包参数定位

找到对应功能的数据包,然后根据里面的参数去代码中搜索
比如:这里我想要找这个app是如何触发升级的,于是我拦截他的数据包,然后看到其中的参数app_version,于是我去代码中搜索app_version,如果太多,也可以换参数vm。
在这里插入图片描述

堆栈追踪

假如我们需要找的功能,调用了一处函数,但是我们又不知道在哪里调用的,这个时候我们可以打印堆栈。frida脚本放结尾。
我们找到了tostring函数,然后打印堆栈发现a方法调用了tostring

============================= 调用堆栈开始 =======================

com.netease.commonupgrade.CommonUpgradeResponse.toString(Native Method)
com.netease.commonupgrade.CommonUpgradeResponse.a(Native Method)
com.netease.commonupgrade.CommonUpgradeImpl.a(SourceFile:114)
com.netease.commonupgrade.CommonUpgradeImpl.a(SourceFile:49)
com.netease.service.pris.v4.CheckUpdateTransaction.a(SourceFile:158)
com.netease.framework.task.AsyncTransaction.run(SourceFile:52)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
java.lang.Thread.run(Thread.java:919)
============================= 调用堆栈结束 ==========================

编写

编写frida脚本,刚开始的时候我们可以多看看其他人的脚本,然后去frida官网查询相关的函数。
对于一些简单的分析,直接用GDA就可以,选中对应的函数,右键hook方法,或者自定义脚本然后将代码复制出来。

//GDA复制的代码可以直接使用:
Java.perform(function() {
	var targetClass='com.netease.commonupgrade.CommonUpgradeResponse';
	var methodName='a';
	var gclass = Java.use(targetClass);
	gclass[methodName].overload('int').implementation = function(arg0) {
		console.log('\nGDA[Hook a(int)]'+'\n\targ0 = '+arg0);
		var i=this[methodName](arg0);
		console.log('\treturn '+i);
		printStack();
		return i;
	}
})

反调

对于反调试,一些常见的手段就是检测相关的特征。

检测文件:检测在/data/local/tmp文件夹下是否存在名称为frida,ida的调试文件等。检测文件的权限是否为x(第二个较少)。
端口检查: 检测常用的调试端口是否打开
ptrace占用: 检测父进程
TracePid:检测调试的变量

常用的绕过手段。

将检测的文件重定向
改名称,端口
将相关代码nop

一些检测的路径。

“/data/data/” + ProName + “/maps”;
“/data/data/” + ProName + “/fmaps”;
“/data/data/” + ProName + “/task”;
“/data/data/” + ProName + “/exe”;
“/data/data/” + ProName + “/mounts”;
"/data/data/ + ProName + /status;

脱壳

这个工具脱壳比较好,一些企业壳也可以脱,如爱加密,360的企业壳。脱的不是完整的但是分析代码已经差不多了。

https://www.52pojie.cn/thread-1781276-1-1.html

踩坑:
1.Android14的手机有问题,读取不到脚本文件
2.一个脚本不行,换其它的试试,(上次虽然是360的壳,但是我没有脱成功,用通用的脚本脱成功了)

好用的脚本

过ssl证书校验抓包

做渗透需要抓包,但是一些app有证书校验,可以采用下面的脚本+burp抓包:
将证书放到脚本里面的路径,然后有反调的需要先过反调


setTimeout(function(){
    Java.perform(function (){
        console.log("");
        console.log("[.] Cert Pinning Bypass/Re-Pinning");

        var CertificateFactory = Java.use("java.security.cert.CertificateFactory");
        var FileInputStream = Java.use("java.io.FileInputStream");
        var BufferedInputStream = Java.use("java.io.BufferedInputStream");
        var X509Certificate = Java.use("java.security.cert.X509Certificate");
        var KeyStore = Java.use("java.security.KeyStore");
        var TrustManagerFactory = Java.use("javax.net.ssl.TrustManagerFactory");
        var SSLContext = Java.use("javax.net.ssl.SSLContext");

        // Load CAs from an InputStream
        console.log("[+] Loading our CA...")
        var cf = CertificateFactory.getInstance("X.509");
       
        try {
            var fileInputStream = FileInputStream.$new("/data/local/tmp/cert-der.crt");
            //***********************证书路径*******************************
        }
        catch(err) {
            console.log("[o] " + err);
        }
       
        var bufferedInputStream = BufferedInputStream.$new(fileInputStream);
        var ca = cf.generateCertificate(bufferedInputStream);
        bufferedInputStream.close();

        var certInfo = Java.cast(ca, X509Certificate);
        console.log("[o] Our CA Info: " + certInfo.getSubjectDN());

        // Create a KeyStore containing our trusted CAs
        console.log("[+] Creating a KeyStore for our CA...");
        var keyStoreType = KeyStore.getDefaultType();
        var keyStore = KeyStore.getInstance(keyStoreType);
        keyStore.load(null, null);
        keyStore.setCertificateEntry("ca", ca);
       
        // Create a TrustManager that trusts the CAs in our KeyStore
        console.log("[+] Creating a TrustManager that trusts the CA in our KeyStore...");
        var tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
        var tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
        tmf.init(keyStore);
        console.log("[+] Our TrustManager is ready...");

        console.log("[+] Hijacking SSLContext methods now...")
        console.log("[-] Waiting for the app to invoke SSLContext.init()...")

        SSLContext.init.overload("[Ljavax.net.ssl.KeyManager;", "[Ljavax.net.ssl.TrustManager;", "java.security.SecureRandom").implementation = function(a,b,c) {
            console.log("[o] App invoked javax.net.ssl.SSLContext.init...");
            SSLContext.init.overload("[Ljavax.net.ssl.KeyManager;", "[Ljavax.net.ssl.TrustManager;", "java.security.SecureRandom").call(this, a, tmf.getTrustManagers(), c);
            console.log("[+] SSLContext initialized with our custom TrustManager!");
        }
    });

},0);

反调的脚本

这个是我在github上找到的,然后加了很多注释,根据需要修改。

//检测: 
//    /proc/25896/maps
//    /proc/25896/status    TracerPID Check
//
//
var ProName = ProcessName();
const currentPid = Process.id;
console.log(currentPid);
function ProcessName() {
    //libc.so是系统的文件,里面加载着打开,读取,关闭等操作文件的c函数,jni在调用so层时会用到打开,读取等。(下面还用到了pthread_creeate)
    var openPtr = Module.getExportByName('libc.so', 'open');
    var open = new NativeFunction(openPtr, 'int', ['pointer', 'int']);
    var readPtr = Module.getExportByName('libc.so', 'read');
    var read = new NativeFunction(readPtr, 'int', ['int', 'pointer', 'int']);
    var closePtr = Module.getExportByName('libc.so', 'close');
    var close = new NativeFunction(closePtr, 'int', ['int']);
    var path = Memory.allocUtf8String('/proc/self/cmdline');
    //父进程名检测
    var fd = open(path, 0);
    if (fd != -1) {
        var buffer = Memory.alloc(0x1000);
        var result = read(fd, buffer, 0x1000);
        close(fd);
        result = ptr(buffer).readCString();
        return result;
    }
    return -1;
}
//假设一个libxyz.so文件,追踪libxyz.so库,自己修改
//var ourlib = "libexec.so";
//获取pthread_create函数的地址
//var p_pthread_create = Module.findExportByName("libc.so", "pthread_create");
//var pthread_create = new NativeFunction(p_pthread_create, "int", ["pointer", "pointer", "pointer", "pointer"]);
//拦截和替换 pthread_create 函数
/*
Interceptor.replace(p_pthread_create, new NativeCallback(function(ptr0, ptr1, ptr2, ptr3) {
    //函数原型
    //int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
    //thread:一个指向 pthread_t 类型的指针,用于存储新创建线程的标识符。
    //attr:一个指向 pthread_attr_t 类型的指针,用于指定新线程的属性(例如堆栈大小、调度策略等),通常可以传入 NULL 使用默认属性。
    //start_routine:一个函数指针,指向新线程将要执行的函数,该函数必须具有 void * 类型的参数并返回 void * 类型的指针。
    //arg:传递给 start_routine 函数的参数。

    var ret = ptr(0);
    if (gmn(ptr0) == ourlib) {
        console.log("Thread Created ptr0 : ", gmn(ptr0), Mod, ptr0.sub(Mod));
    }
    
    if (gmn(ptr1) == ourlib) {
        var Mod = Module.findBaseAddress(ourlib)
        console.log("Thread Created ptr1 : ", gmn(ptr1), Mod, ptr1.sub(Mod));
        Interceptor.attach(Mod.add(ptr1.sub(Mod)), {
            onEnter: function(args) {
                console.log("New Thread Func", ptr1.sub(Mod), "arg : ", args[0], args[1]);
            },
            onLeave: function(retval) {
                console.log("New Thread Func Return : ", retval);
            }
        });
    }
    if (gmn(ptr2) == ourlib) {
        var Mod = Module.findBaseAddress(ourlib)
        console.log("Thread Created ptr2 : ", gmn(ptr2), Mod, ptr2.sub(Mod));
        Interceptor.attach(Mod.add(ptr2.sub(Mod)), {
            onEnter: function(args) {
                console.log("New Thread Func", ptr2.sub(Mod), "arg : ", args[0], args[1]);
            },
            onLeave: function(retval) {
                console.log("New Thread Func Return : ", retval);
            }
        });
    }
    if (gmn(ptr3) == ourlib) {
        var Mod = Module.findBaseAddress(ourlib)
        console.log("Thread Created ptr3 : ", gmn(ptr3), Mod, ptr3.sub(Mod));
        Interceptor.attach(Mod.add(ptr3.sub(Mod)), {
            onEnter: function(args) {
                console.log("New Thread Func", ptr3.sub(Mod), "arg : ", args[0], args[1]);
            },
            onLeave: function(retval) {
                console.log("New Thread Func Return : ", retval);
            }
        });
    }
    if (ptr1.isNull() && ptr3.isNull()) {
        console.warn("loading fake pthread_create");
        // return -1 if you not want to create that thread 
        return pthread_create(ptr0, ptr1, ptr2, ptr3);
        // return -1;
    } else {       
        return pthread_create(ptr0, ptr1, ptr2, ptr3);;
    }
    
}, "int", ["pointer", "pointer", "pointer", "pointer"]));

function gmn(fnPtr) {
     if (fnPtr != null) {
        try {
            //获取函数所在模块的名字          
            return Process.getModuleByAddress(fnPtr).name;          
        } catch (e) {console.error(e);}            
    }
}*/

// 检测frida
/*
inet_aton
作用: 将一个 IPv4 地址的字符串表示转换为网络字节序的整数表示。
参数: addrs 是 IPv4 地址的字符串指针;structure 是一个 in_addr 结构体的指针,用于存放转换后的结果。
返回值: 成功返回 1,失败返回 0。
popen
作用: 打开一个管道,通过调用 shell 命令来执行一个进程,并返回一个标准 I/O 流。
参数: path 是要执行的 shell 命令的字符串;type 是打开模式(如 "r" 或 "w")。
返回值: 成功返回指向文件流的指针,失败返回 NULL。
symlink
作用: 创建一个符号链接。
参数: target 是要链接到的目标路径;path 是要创建的符号链接路径。
返回值: 成功返回 0,失败返回 -1。
symlinkat
作用: 在指定的文件描述符(目录)下创建一个符号链接。
参数: target 是要链接到的目标路径;fd 是目录文件描述符;path 是要创建的符号链接路径。
返回值: 成功返回 0,失败返回 -1。
inet_addr
作用: 将一个点分十进制的 IPv4 地址转换为网络字节序的整数表示。
参数: path 是点分十进制 IPv4 地址的字符串。
返回值: 成功返回一个无符号 32 位整数表示的 IP 地址,失败返回 INADDR_NONE。
socket
作用: 创建一个套接字。
参数: domain 是地址族(如 AF_INET 表示 IPv4);type 是套接字类型(如 SOCK_STREAM 表示流套接字);proto 是协议(如 0 表示自动选择合适的协议)。
返回值: 成功返回一个文件描述符,表示创建的套接字;失败返回 -1。
connect
作用: 建立与远程套接字的连接。
参数: fd 是套接字的文件描述符;addr 是指向目标地址结构的指针;len 是地址结构的长度。
返回值: 成功返回 0,失败返回 -1。
send
作用: 发送数据到套接字。
参数: socksfd 是套接字的文件描述符;msg 是指向要发送数据的缓冲区的指针;slen 是要发送的数据的长度;flag 是附加标志。
返回值: 成功返回发送的字节数,失败返回 -1。
sendto
作用: 发送数据到指定的套接字地址。
参数: socksfd 是套接字的文件描述符;msg 是指向要发送数据的缓冲区的指针;slen 是要发送的数据的长度;flag 是附加标志;daddr 是目标地址的指针;dlen 是目标地址的长度。
返回值: 成功返回发送的字节数,失败返回 -1。
open
作用: 打开或创建一个文件或其他资源。
参数: pathname 是要打开的文件路径;flag 是打开标志(如 O_RDONLY 表示只读)。
返回值: 成功返回文件描述符,失败返回 -1。
read
作用: 从文件描述符读取数据。
参数: fd 是文件描述符;buffer 是用于接收数据的缓冲区的指针;count 是要读取的最大字节数。
返回值: 成功返回实际读取的字节数,可能会少于请求的字节数;失败返回 -1。
*/

var inet_atonPtr = Module.findExportByName(null, "inet_aton");
console.log(`inet_atonPtr: ${inet_atonPtr}`);
var inet_aton = new NativeFunction(inet_atonPtr, 'int', ['pointer', 'pointer']);

Interceptor.replace(inet_atonPtr, new NativeCallback(function(addrs, structure) {
    var retval = inet_aton(addrs, structure);
    //console.log(1);
    //console.log("inet_aton : ", addrs.readCString())
    return retval;
}, 'int', ['pointer', 'pointer']))

var popenPtr = Module.findExportByName("libc.so", "popen");
var popen = new NativeFunction(popenPtr, 'pointer', ['pointer', 'pointer']);
Interceptor.replace(popenPtr, new NativeCallback(function(path, type) {
    var retval = popen(path, type);
    //console.log(2);
    //console.log("popen : ", path.readCString());
    return retval;
}, 'pointer', ['pointer', 'pointer']))

var symlinkPtr = Module.findExportByName("libc.so", "symlink");
var symlink = new NativeFunction(symlinkPtr, 'int', ['pointer', 'pointer']);
Interceptor.replace(symlinkPtr, new NativeCallback(function(target, path) {
    var retval = symlink(target, path);
    //console.log(3);
    //console.log("symlink: ", target.readCString(), path.readCString());
    return retval;
}, 'int', ['pointer', 'pointer']))

var symlinkatPtr = Module.findExportByName("libc.so", "symlinkat");
var symlinkat = new NativeFunction(symlinkatPtr, 'int', ['pointer', 'int', 'pointer']);
Interceptor.replace(symlinkatPtr, new NativeCallback(function(target, fd, path) {
    var retval = symlinkat(target, fd, path);
    //console.log(4);
    //console.log("symlinkat : ", target.readCString(), path.readCString());
    return retval;
}, 'int', ['pointer', 'int', 'pointer']))

var inet_addrPtr = Module.findExportByName("libc.so", "inet_addr");
var inet_addr = new NativeFunction(inet_addrPtr, 'int', ['int']);
Interceptor.replace(inet_addrPtr, new NativeCallback(function(path) {
    var retval = inet_addr(path);
    //console.log(5);
    //console.log("inet_addr : ", path.readCString())
    return retval;
}, 'int', ['int']))

var socketPtr = Module.findExportByName("libc.so", "socket");
var socket = new NativeFunction(socketPtr, 'int', ['int', 'int', 'int']);
Interceptor.replace(socketPtr, new NativeCallback(function(domain, type, proto) {
    var retval = socket(domain, type, proto);
    //console.log(6);
    //console.warn("socket  : ", domain, type, proto, "Return : ", retval)
    return retval;
}, 'int', ['int', 'int', 'int']))

var connectPtr = Module.findExportByName("libc.so", "connect");
var connect = new NativeFunction(connectPtr, 'int', ['int', 'pointer', 'int']);
Interceptor.replace(connectPtr, new NativeCallback(function(fd, addr, len) {
    var retval = connect(fd, addr, len);
    var family = addr.readU16();
    var port = addr.add(2).readU16();
    //port = ((port & 0xff) << 8) | (port >> 8);
    //console.log(7);
    //console.warn("Connect : ", family, "Port : ", port, "Return : ", retval);
    return retval;
}, 'int', ['int', 'pointer', 'int']))

var sendPtr = Module.findExportByName("libc.so", "send");
var send2 = new NativeFunction(sendPtr, 'int', ['int', 'pointer', 'int', 'int']);
Interceptor.replace(sendPtr, new NativeCallback(function(socksfd, msg, slen, flag, daddr, dlen) {
    var retval = send2(socksfd, msg, slen, flag);
    //console.log(8);
    //console.log("send : ", socksfd, msg.readCString(), slen, flag);
    return retval;
}, 'int', ['int', 'pointer', 'int', 'int']))

var sendtoPtr = Module.findExportByName("libc.so", "sendto");
var sendto = new NativeFunction(sendtoPtr, 'int', ['int', 'pointer', 'int', 'int', 'pointer', 'int']);
Interceptor.replace(sendtoPtr, new NativeCallback(function(socksfd, msg, slen, flag, daddr, dlen) {
    var retval = sendto(socksfd, msg, slen, flag, daddr, dlen);
    //console.log(9);
      //console.log("sendto : ",socksfd,msg.readCString(),slen,flag,daddr,dlen);                                       
    return retval;
}, 'int', ['int', 'pointer', 'int', 'int', 'pointer', 'int']))

const openPtr = Module.getExportByName('libc.so', 'open');
const open = new NativeFunction(openPtr, 'int', ['pointer', 'int']);
var readPtr = Module.findExportByName("libc.so", "read");
var read = new NativeFunction(readPtr, 'int', ['int', 'pointer', "int"]);

//这一段就是hookopen函数,将记录了文件是否被调试的文件进行了重定向
//ProName:进程名
var FakeMaps = "/data/data/" + ProName + "/maps";
var FOpenMaps = "/data/data/" + ProName + "/fmaps";
var FakeTask = "/data/data/" + ProName + "/task";
var FakeExE = "/data/data/" + ProName + "/exe";
var FakeMounts = "/data/data/" + ProName + "/mounts";
var FakeStatus = "/data/data/" + ProName + "/status";
var MapsFile = new File(FakeMaps, "w");
var TaskFile = new File(FakeTask, "w");
var ExEFile = new File(FakeExE, "w");
var FMapsFile = new File(FOpenMaps, "w");
var FMountFile = new File(FakeMounts, "w");
var StatusFile = new File(FakeStatus, "w");
var MapsBuffer = Memory.alloc(512);
var TaskBuffer = Memory.alloc(512);
var ExEBuffer = Memory.alloc(512);
var FopenBuffer = Memory.alloc(512);
var MountBuffer = Memory.alloc(512);
var StatusBuffer = Memory.alloc(512);
var Open64MapsBuffer = Memory.alloc(512);
//openptr在前面申明了,是open函数的地址
Interceptor.replace(openPtr, new NativeCallback(function(pathname, flag) {
    //pathname = "/proc/" + currentPid + "/maps";
    var FD = open(pathname, flag);
    var ch = pathname.readCString();
    //如果路径是/proc/xxx/maps
    if (ch.indexOf("/proc/") >= 0 && ch.indexOf("maps") >= 0) {
          console.log("open : ", pathname.readCString(),11111) 
          //parseInt:将字符串转换成整数
        while (parseInt(read(FD, MapsBuffer, 512)) !== 0) {
            //读取打开的文件的字符串
            var MBuffer = MapsBuffer.readCString();
            //将所有调试文件的名字替换
            //console.log(1);
            MBuffer = MBuffer.replaceAll("/data/local/tmp/re.frida.server/frida-agent-64.so", "FakingMaps");
            MBuffer = MBuffer.replaceAll("re.frida.server", "FakingMaps");
            MBuffer = MBuffer.replaceAll("re.frida", "FakingMaps");
            MBuffer = MBuffer.replaceAll("re.", "FakingMaps");
            MBuffer = MBuffer.replaceAll("frida.", "FakingMaps");
            MBuffer = MBuffer.replaceAll("frida-agent-64.so", "FakingMaps");
            MBuffer = MBuffer.replaceAll("rida-agent-64.so", "FakingMaps");
            MBuffer = MBuffer.replaceAll("agent-64.so", "FakingMaps");
            MBuffer = MBuffer.replaceAll("frida-agent-32.so", "FakingMaps");
            MBuffer = MBuffer.replaceAll("frida-helper-32", "FakingMaps");
            MBuffer = MBuffer.replaceAll("frida-helper", "FakingMaps");
            MBuffer = MBuffer.replaceAll("frida-agent", "FakingMaps");
            MBuffer = MBuffer.replaceAll("pool-frida", "FakingMaps");
            MBuffer = MBuffer.replaceAll("frida", "FakingMaps");
            MBuffer = MBuffer.replaceAll("frida-", "FakingMaps");
            MBuffer = MBuffer.replaceAll("/data/local/tmp", "/data");
            MBuffer = MBuffer.replaceAll("server", "FakingMaps");
            MBuffer = MBuffer.replaceAll("frida-server", "FakingMaps");
            MBuffer = MBuffer.replaceAll("linjector", "FakingMaps");
            MBuffer = MBuffer.replaceAll("gum-js-loop", "FakingMaps");
            MBuffer = MBuffer.replaceAll("frida_agent_main", "FakingMaps");
            MBuffer = MBuffer.replaceAll("gmain", "FakingMaps");
            MBuffer = MBuffer.replaceAll("frida", "FakingMaps");
            MBuffer = MBuffer.replaceAll("magisk", "FakingMaps");
            MBuffer = MBuffer.replaceAll(".magisk", "FakingMaps");
            MBuffer = MBuffer.replaceAll("/sbin/.magisk", "FakingMaps");
            MBuffer = MBuffer.replaceAll("libriru", "FakingMaps");
            MBuffer = MBuffer.replaceAll("xposed", "FakingMaps");
            MapsFile.write(MBuffer);
             //console.log("MBuffer : ",MBuffer);                                     
        }
        var filename = Memory.allocUtf8String(FakeMaps);
        return open(filename, flag);
    }
    //如果路径是/proc/xxx/task,检测正在运行的任务
    if (ch.indexOf("/proc") >= 0 && ch.indexOf("task") >= 0) {
        // console.log("open : ", pathname.readCString()) 
        while (parseInt(read(FD, TaskBuffer, 512)) !== 0) {
            var buffer = TaskBuffer.readCString();
            buffer = buffer.replaceAll("re.frida.server", "FakingTask");
            buffer = buffer.replaceAll("frida-agent-64.so", "FakingTask");
            buffer = buffer.replaceAll("rida-agent-64.so", "FakingTask");
            buffer = buffer.replaceAll("agent-64.so", "FakingTask");
            buffer = buffer.replaceAll("frida-agent-32.so", "FakingTask");
            buffer = buffer.replaceAll("frida-helper-32", "FakingTask");
            buffer = buffer.replaceAll("frida-helper", "FakingTask");
            buffer = buffer.replaceAll("frida-agent", "FakingTask");
            buffer = buffer.replaceAll("pool-frida", "FakingTask");
            buffer = buffer.replaceAll("frida", "FakingTask");
            buffer = buffer.replaceAll("/data/local/tmp", "/data");
            buffer = buffer.replaceAll("server", "FakingTask");
            buffer = buffer.replaceAll("frida-server", "FakingTask");
            buffer = buffer.replaceAll("linjector", "FakingTask");
            buffer = buffer.replaceAll("gum-js-loop", "FakingTask");
            buffer = buffer.replaceAll("frida_agent_main", "FakingTask");
            buffer = buffer.replaceAll("gmain", "FakingTask");
            buffer = buffer.replaceAll("magisk", "FakingTask");
            buffer = buffer.replaceAll(".magisk", "FakingTask");
            buffer = buffer.replaceAll("/sbin/.magisk", "FakingTask");
            buffer = buffer.replaceAll("libriru", "FakingTask");
            buffer = buffer.replaceAll("xposed", "FakingTask");
            buffer = buffer.replaceAll("pool-spawner", "FakingTask");
            buffer = buffer.replaceAll("gdbus", "FakingTask");            
            TaskFile.write(buffer);
            // console.log(buffer);
        }
        var filename2 = Memory.allocUtf8String(FakeTask);
        return open(filename2, flag);
    }
    //如果路径是/proc/xxx/mounts
    if (ch.indexOf("/proc/") >= 0 && ch.indexOf("mounts") >= 0) {
        console.log("open : ", pathname.readCString())
        while (parseInt(read(FD, MountBuffer, 512)) !== 0) {
            var MNTBuffer = MountBuffer.readCString();
            MNTBuffer = MNTBuffer.replaceAll("magisk", "StaySafeStayHappy");
            MNTBuffer = MNTBuffer.replaceAll("/sbin/.magisk", "StaySafeStayHappy");
            MNTBuffer = MNTBuffer.replaceAll("libriru", "StaySafeStayHappy");
            MNTBuffer = MNTBuffer.replaceAll("xposed", "StaySafeStayHappy");
            MNTBuffer = MNTBuffer.replaceAll("mirror", "StaySafeStayHappy");
            MNTBuffer = MNTBuffer.replaceAll("system_root", "StaySafeStayHappy");
            MNTBuffer = MNTBuffer.replaceAll("xposed", "StaySafeStayHappy")
            FMountFile.write(MNTBuffer);
            // console.log("MNTBuffer : ",MNTBuffer);                                     
        }
        var mountname = Memory.allocUtf8String(FakeMounts);
        return open(mountname, flag);
    }
    
      if (ch.indexOf("/proc/") >=0 && ch.indexOf("status") >=0) {     
         console.log("open : ", pathname.readCString()) 
         while (parseInt(read(FD, StatusBuffer, 512)) !== 0) {
         var PStatus = StatusBuffer.readCString();   
         if (PStatus.indexOf("TracerPid:") > -1) {
                StatusBuffer.writeUtf8String("TracerPid:\t0");
                console.log("Bypassing TracerPID Check");               
            }
         StatusFile.write(PStatus);                                                
                }
            var statusname = Memory.allocUtf8String(FakeStatus);
            return open(statusname, flag);  
    }
     
    if (ch.indexOf("/proc") >= 0 && ch.indexOf("exe") >= 0) {
        console.log("open : ", pathname.readCString())
        while (parseInt(read(FD, ExEBuffer, 512)) !== 0) {
            var buffer = ExEBuffer.readCString();
            //  console.warn(buffer)
            buffer = buffer.replaceAll("frida-agent-64.so", "StaySafeStayHappy");
            buffer = buffer.replaceAll("frida-agent-32.so", "StaySafeStayHappy");
            buffer = buffer.replaceAll("re.frida.server", "StaySafeStayHappy");
            buffer = buffer.replaceAll("frida-helper-32", "StaySafeStayHappy");
            buffer = buffer.replaceAll("frida-helper", "StaySafeStayHappy");
            buffer = buffer.replaceAll("pool-frida", "StaySafeStayHappy");
            buffer = buffer.replaceAll("frida", "StaySafeStayHappy");
            buffer = buffer.replaceAll("/data/local/tmp", "/data");
            buffer = buffer.replaceAll("frida-server", "StaySafeStayHappy");
            buffer = buffer.replaceAll("linjector", "StaySafeStayHappy");
            buffer = buffer.replaceAll("gum-js-loop", "StaySafeStayHappy");
            buffer = buffer.replaceAll("frida_agent_main", "StaySafeStayHappy");
            buffer = buffer.replaceAll("gmain", "StaySafeStayHappy");
            buffer = buffer.replaceAll("frida-agent", "StaySafeStayHappy");
            ExEFile.write(buffer);
        }
        var filename3 = Memory.allocUtf8String(FakeExE);
        return open(filename3, flag);
    }
    return FD;
}, 'int', ['pointer', 'int']))
var fgetsPtr = Module.findExportByName("libc.so", "fgets");
var fgets = new NativeFunction(fgetsPtr, 'pointer', ['pointer', 'int', 'pointer']);
Interceptor.replace(fgetsPtr, new NativeCallback(function(buf, size, fp) {
    //var retval = fgets(buf, size, fp);
    var buffer = buf.readCString();
    buffer = buffer.replaceAll("re.frida.server", "FakingGets");
    buffer = buffer.replaceAll("frida-agent-64.so", "FakingGets");
    buffer = buffer.replaceAll("rida-agent-64.so", "FakingGets");
    buffer = buffer.replaceAll("agent-64.so", "FakingGets");
    buffer = buffer.replaceAll("frida-agent-32.so", "FakingGets");
    buffer = buffer.replaceAll("frida-helper-32", "FakingGets");
    buffer = buffer.replaceAll("frida-helper", "FakingGets");
    buffer = buffer.replaceAll("frida-agent", "FakingGets");
    buffer = buffer.replaceAll("pool-frida", "FakingGets");
    buffer = buffer.replaceAll("frida", "FakingGets");
    buffer = buffer.replaceAll("/data/local/tmp", "/data");
    buffer = buffer.replaceAll("server", "FakingGets");
    buffer = buffer.replaceAll("frida-server", "FakingGets");
    buffer = buffer.replaceAll("linjector", "FakingGets");
    buffer = buffer.replaceAll("gum-js-loop", "FakingGets");
    buffer = buffer.replaceAll("frida_agent_main", "FakingGets");
    buffer = buffer.replaceAll("gmain", "FakingGets");
    buffer = buffer.replaceAll("magisk", "FakingGets");
    buffer = buffer.replaceAll(".magisk", "FakingGets");
    buffer = buffer.replaceAll("/sbin/.magisk", "FakingGets");
    buffer = buffer.replaceAll("libriru", "FakingGets");
    buffer = buffer.replaceAll("xposed", "FakingGets");
    buf.writeUtf8String(buffer);
    //  console.log(buf.readCString());
    return fgets(buf, size, fp);
}, 'pointer', ['pointer', 'int', 'pointer']))

var readlinkPtr = Module.findExportByName("libc.so", "readlink");
var readlink = new NativeFunction(readlinkPtr, 'int', ['pointer', 'pointer', 'int']);
Interceptor.replace(readlinkPtr, new NativeCallback(function(pathname, buffer, bufsize) {
    var retval = readlink(pathname, buffer, bufsize);  
    //从内存中读取字符串,判断是否含有特征字符
     if(buffer.readCString().indexOf("frida")!==-1 ||
            buffer.readCString().indexOf("gum-js-loop")!==-1||
            buffer.readCString().indexOf("gmain")!==-1 ||
            buffer.readCString().indexOf("linjector")!==-1 || 
            buffer.readCString().indexOf("/data/local/tmp")!==-1 || 
            buffer.readCString().indexOf("pool-frida")!==-1 || 
            buffer.readCString().indexOf("frida_agent_main")!==-1 ||
            buffer.readCString().indexOf("re.frida.server")!==-1 || 
            buffer.readCString().indexOf("frida-agent")!==-1 ||
            buffer.readCString().indexOf("frida-agent-64.so")!==-1 ||
            buffer.readCString().indexOf("frida-agent-32.so")!==-1 ||
            buffer.readCString().indexOf("frida-helper-32.so")!==-1 ||
            buffer.readCString().indexOf("frida-helper-64.so")!==-1                        
            ){
            console.log(buffer.readCString(), "Check in readlink");
            buffer.writeUtf8String("/system/framework/services.jar");            
            return readlink(pathname, buffer, bufsize);  
     }
     
//    console.log("readlink : ", pathname.readCString(), buffer.readCString());
    return retval;   
}, 'int', ['pointer', 'pointer', 'int']))


var readlinkatPtr = Module.findExportByName("libc.so", "readlinkat");
var readlinkat = new NativeFunction(readlinkatPtr, 'int', ['int', 'pointer', 'pointer', 'int']);
Interceptor.replace(readlinkatPtr, new NativeCallback(function(dirfd, pathname, buffer, bufsize) {
    var retval = readlinkat(dirfd, pathname, buffer, bufsize);
    
     if(buffer.readCString().indexOf("frida")!==-1 ||
            buffer.readCString().indexOf("gum-js-loop")!==-1||
            buffer.readCString().indexOf("gmain")!==-1 ||
            buffer.readCString().indexOf("linjector")!==-1 || 
            buffer.readCString().indexOf("/data/local/tmp")!==-1 || 
            buffer.readCString().indexOf("pool-frida")!==-1 || 
            buffer.readCString().indexOf("frida_agent_main")!==-1 ||
            buffer.readCString().indexOf("re.frida.server")!==-1 || 
            buffer.readCString().indexOf("frida-agent")!==-1 ||
            buffer.readCString().indexOf("frida-agent-64.so")!==-1 ||
            buffer.readCString().indexOf("frida-agent-32.so")!==-1 ||
            buffer.readCString().indexOf("frida-helper-32.so")!==-1 ||
            buffer.readCString().indexOf("frida-helper-64.so")!==-1                              
            ){
            console.log(buffer.readCString(), "Check in readlinkat");
            buffer.writeUtf8String("/system/framework/services.jar");           
            return readlinkat(dirfd, pathname, buffer, bufsize);
     }
     
 //   console.log("readlinkat : ", pathname.readCString(), buffer.readCString());
   return retval;
}, 'int', ['int', 'pointer', 'pointer', 'int']))

/*
Interceptor.attach(Module.findExportByName(null, "strstr"),{
    onEnter: function(args){
        this.frida = false;
        console.log(3);
        var str1 = args[0].readCString();
        var str2 = args[1].readCString();      
        if(str1.indexOf("frida")!==-1  || str2.indexOf("frida")!==-1 ||
          str1.indexOf("gum-js-loop")!==-1 || str2.indexOf("gum-js-loop")!==-1 ||
          str1.indexOf("gmain")!==-1 || str2.indexOf("gmain")!==-1 ||
          str1.indexOf("linjector")!==-1  || str2.indexOf("linjector")!==-1 ||
          str1.indexOf("/data/local/tmp")!==-1  || str2.indexOf("/data/local/tmp")!==-1 ||
          str1.indexOf("pool-frida")!==-1  || str2.indexOf("pool-frida")!==-1 ||
          str1.indexOf("frida_agent_main")!==-1  || str2.indexOf("frida_agent_main")!==-1 ||
          str1.indexOf("re.frida.server")!==-1  || str2.indexOf("re.frida.server")!==-1 ||
          str1.indexOf("frida-agent")!==-1  || str2.indexOf("frida-agent")!==-1 ||
          str1.indexOf("pool-spawner")!==-1  || str2.indexOf("pool-spawner")!==-1 ||
          str1.indexOf("frida-agent-64.so")!==-1  || str2.indexOf("frida-agent-64.so")!==-1 ||
          str1.indexOf("frida-agent-32.so")!==-1  || str2.indexOf("frida-agent-32.so")!==-1 ||
          str1.indexOf("frida-helper-32.so")!==-1  || str2.indexOf("frida-helper-32.so")!==-1 ||
          str1.indexOf("frida-helper-64.so")!==-1  || str2.indexOf("frida-helper-64.so")!==-1  ||
          str1.indexOf("/sbin/.magisk")!==-1  || str2.indexOf("/sbin/.magisk")!==-1  ||
          str1.indexOf("libriru")!==-1  || str2.indexOf("libriru")!==-1  ||
          str1.indexOf("magisk")!==-1  || str2.indexOf("magisk")!==-1  
                                         
          ){          
            this.frida = true;
            console.log("检测到:strstr : ",str1,str2);
        }
    },
    onLeave: function(retval){
        if (this.frida) {
            retval.replace(ptr("0x0"));
        }
    }
});
*/

//Enabling it might give crash on some apps 
/*
Interceptor.attach(Module.findExportByName("libc.so", "read"), {
    onEnter: function(args) {
        try {
            var buffer = args[1].readCString();
            if (buffer.indexOf("frida") >= 0) {
                buffer = buffer.replaceAll("re.frida.server", "StaySafeStayHappy");
                buffer = buffer.replaceAll("frida-agent-64.so", "StaySafeStayHappy");
                buffer = buffer.replaceAll("rida-agent-64.so", "StaySafeStayHappy");
                buffer = buffer.replaceAll("agent-64.so", "StaySafeStayHappy");
                buffer = buffer.replaceAll("frida-agent-32.so", "StaySafeStayHappy");
                buffer = buffer.replaceAll("frida-helper-32", "StaySafeStayHappy");
                buffer = buffer.replaceAll("frida-helper", "StaySafeStayHappy");
                buffer = buffer.replaceAll("frida-agent", "StaySafeStayHappy");
                buffer = buffer.replaceAll("pool-frida", "StaySafeStayHappy");
                buffer = buffer.replaceAll("frida", "StaySafeStayHappy");
                buffer = buffer.replaceAll("/data/local/tmp", "/data");
                buffer = buffer.replaceAll("server", "StaySafeStayHappy");
                buffer = buffer.replaceAll("frida-server", "StaySafeStayHappy");
                buffer = buffer.replaceAll("linjector", "StaySafeStayHappy");
                buffer = buffer.replaceAll("gum-js-loop", "StaySafeStayHappy");
                buffer = buffer.replaceAll("frida_agent_main", "StaySafeStayHappy");
                buffer = buffer.replaceAll("gmain", "StaySafeStayHappy");
                buffer = buffer.replaceAll("magisk", "StaySafeStayHappy");
                buffer = buffer.replaceAll(".magisk", "StaySafeStayHappy");
                buffer = buffer.replaceAll("/sbin/.magisk", "StaySafeStayHappy");
                buffer = buffer.replaceAll("libriru", "StaySafeStayHappy");
                buffer = buffer.replaceAll("xposed", "StaySafeStayHappy");
                args[1].writeUtf8String(buffer);
            }
        } catch (e) {
            //console.error(e);
        }
    }
});
*/

/*
var memcpyPtr = Module.findExportByName("libc.so", "memcpy");
var memcpy = new NativeFunction(memcpyPtr, 'pointer', ['pointer', 'pointer', 'int']);
Interceptor.replace(memcpyPtr, new NativeCallback(function(dest, src, len) {
    var retval = memcpy(dest, src, len);
    if(dest.readCString() != null && src.readCString() != null && (dest.readCString().indexOf("frida")>=0 || src.readCString().indexOf("frida")>=0) )
    {
        //console.warn("memcpy : ",dest.readCString(),src.readCString());
        var buffer = dest.readCString();
        var buffer2 = src.readCString();
        buffer = buffer.replaceAll("re.frida.server","StaySafeStayHappy");                                                         
        buffer = buffer.replaceAll("frida-agent-64.so","StaySafeStayHappy");
        buffer = buffer.replaceAll("rida-agent-64.so","StaySafeStayHappy");
        buffer = buffer.replaceAll("agent-64.so","StaySafeStayHappy");        
        buffer = buffer.replaceAll("frida-agent-32.so","StaySafeStayHappy");       
        buffer = buffer.replaceAll("frida-helper-32","StaySafeStayHappy");        
        buffer = buffer.replaceAll("frida-helper","StaySafeStayHappy"); 
        buffer = buffer.replaceAll("frida-agent","StaySafeStayHappy");        
        buffer = buffer.replaceAll("pool-frida","StaySafeStayHappy");            
        buffer = buffer.replaceAll("frida","StaySafeStayHappy");
        buffer = buffer.replaceAll("/data/local/tmp","/data");
        buffer = buffer.replaceAll("server","StaySafeStayHappy");
        buffer = buffer.replaceAll("frida-server","StaySafeStayHappy");
        buffer = buffer.replaceAll("linjector","StaySafeStayHappy");
        buffer = buffer.replaceAll("gum-js-loop","StaySafeStayHappy");
        buffer = buffer.replaceAll("frida_agent_main","StaySafeStayHappy");
        buffer = buffer.replaceAll("gmain","StaySafeStayHappy");
        buffer2 = buffer2.replaceAll("re.frida.server","StaySafeStayHappy");                                                         
        buffer2 = buffer2.replaceAll("frida-agent-64.so","StaySafeStayHappy");
        buffer2 = buffer2.replaceAll("rida-agent-64.so","StaySafeStayHappy");
        buffer2 = buffer2.replaceAll("agent-64.so","StaySafeStayHappy");        
        buffer2 = buffer2.replaceAll("frida-agent-32.so","StaySafeStayHappy");       
        buffer2 = buffer2.replaceAll("frida-helper-32","StaySafeStayHappy");        
        buffer2 = buffer2.replaceAll("frida-helper","StaySafeStayHappy"); 
        buffer2 = buffer2.replaceAll("frida-agent","StaySafeStayHappy");        
        buffer2 = buffer2.replaceAll("pool-frida","StaySafeStayHappy");            
        buffer2 = buffer2.replaceAll("frida","StaySafeStayHappy");
        buffer2 = buffer2.replaceAll("/data/local/tmp","/data");
        buffer2 = buffer2.replaceAll("server","StaySafeStayHappy");
        buffer2 = buffer2.replaceAll("frida-server","StaySafeStayHappy");
        buffer2 = buffer2.replaceAll("linjector","StaySafeStayHappy");
        buffer2 = buffer2.replaceAll("gum-js-loop","StaySafeStayHappy");
        buffer2 = buffer2.replaceAll("frida_agent_main","StaySafeStayHappy");
        buffer2 = buffer2.replaceAll("gmain","StaySafeStayHappy");
        dest.writeUtf8String(buffer);
        src.writeUtf8String(buffer2);
       // console.log(buffer,buffer2);
        return memcpy(dest, src, len);
    }
    return retval;
}, 'pointer', ['pointer', 'pointer', 'int']))
*/


打印堆栈

将函数加在代码中,然后在hook的函数中调用printStack();即可。


// 日志打印和调用堆栈输出函数
// 日志输出
function LOG(sth)
{
    console.log(sth);
}
// 打印调用堆栈的函数
function printStack()
{
    Java.perform
    (
        function()
        {
            var Exception = Java.use("java.lang.Exception"); //加载Java类 java.lang.Exception
            var ins = Exception.$new("Exception");// Exception构造方法调用
            var straces = ins.getStackTrace();// 调用Exception对象的getStackTrace方法
            if (straces != undefined && straces != null) 
            {
                var strace = straces.toString();
                var replaceStr = strace.replace(/,/g, "\n");
                LOG("============================= 调用堆栈开始 =======================\n");
                LOG(replaceStr);
                LOG("============================= 调用堆栈结束 ==========================\n");
                Exception.$dispose();
            }
        }   
    );
}

bilibili反调的脚本

在网上找到的,可以绕过bilibili的反调。

function create_fake_pthread_create() {
    const fake_pthread_create = Memory.alloc(4096)
    Memory.protect(fake_pthread_create, 4096, "rwx")
    Memory.patchCode(fake_pthread_create, 4096, code => {
        const cw = new Arm64Writer(code, { pc: ptr(fake_pthread_create) })
        cw.putRet()
    })
    return fake_pthread_create
}
 
function hook_dlsym() {
    var count = 0
    console.log("=== HOOKING dlsym ===")
    var interceptor = Interceptor.attach(Module.findExportByName(null, "dlsym"),
        {
            onEnter: function (args) {
                const name = ptr(args[1]).readCString()
                console.log("[dlsym]", name)
                if (name == "pthread_create") {
                    count++
                }
            },
            onLeave: function(retval) {
                if (count == 1) {
                    retval.replace(fake_pthread_create)
                }
                else if (count == 2) {
                    retval.replace(fake_pthread_create)
                    // 完成2次替换, 停止hook dlsym
                    interceptor.detach()
                }
            }
        }
    )
    return Interceptor
}
 
function hook_dlopen() {
    var interceptor = Interceptor.attach(Module.findExportByName(null, "android_dlopen_ext"),
        {
            onEnter: function (args) {
                var pathptr = args[0];
                if (pathptr !== undefined && pathptr != null) {
                    var path = ptr(pathptr).readCString();
                    console.log("[LOAD]", path)
                    if (path.indexOf("libmsaoaidsec.so") > -1) {
                        hook_dlsym()
                    }
                }
            }
        }
    )
    return interceptor
}
 
// 创建虚假pthread_create
var fake_pthread_create = create_fake_pthread_create()
var dlopen_interceptor = hook_dlopen()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

&阿权&

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值