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

news2024/9/20 1:00:46

文章目录

      • 总结
    • 基础
      • Android基础
      • 工具
    • 定位关键代码
      • 页面activity定位
      • 数据包参数定位
      • 堆栈追踪
    • 编写
    • 反调
    • 脱壳
    • 好用的脚本
      • 过ssl证书校验抓包
      • 反调的脚本
      • 打印堆栈
      • bilibili反调的脚本

总结

暑假做了两个月的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()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2116189.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Unity下如何播放8K超高分辨率的RTMP流?

在Unity中使用RTMP播放器播放8K流&#xff0c;需要考虑到多个方面的因素和技术要求。以下是一个详细的步骤和要点概述&#xff0c;帮助实现这一目标&#xff1a; 1. 选择合适的RTMP播放器插件 首先&#xff0c;需要选择一个支持8K视频流播放的RTMP播放器插件。并非所有插件都…

MATLAB绘图基础6:MATLAB绘图基础

参考书&#xff1a;《 M A T L A B {\rm MATLAB} MATLAB与学术图表绘制》(关东升)。 6.MATLAB绘图基础 6.1 MATLAB绘图基本流程 % 1.创建图形窗口; % 1.1 创建一个空白图形窗口; figure;% 1.2 创建一个带有指定标题的图形窗口; figure(Name, 图形窗口);% 1.3 创建一个具有指定…

【干货分享】基于SSM的体育场管理系统的开题报告(附源码下载地址)

中秋送好礼 中秋佳节将至&#xff0c;祝福大家中秋快乐&#xff0c;阖家幸福。本期免费分享毕业设计作品&#xff1a;《基于SSM的体育场管理系统》。 基于SSM的体育场管理系统的开题报告 一、课题背景与意义 随着全民健身理念的深入人心&#xff0c;体育场已成为广大师生和…

熟悉Kafka组成模块、Kafka消息提交的方式及优缺点

1. Kafka概念 1.1 Kafka组成模块 Kafka其实是一款基于发布与订阅模式的消息系统&#xff0c;如果按常理来设计&#xff0c;大家是不是把消息发送者的消息直接发送给消息消费者&#xff1f;但Kafka并不是这么设计的&#xff0c;Kafka消息的生产者会对消息进行分类&#xff0c;…

【LVI-SAM】激光雷达点云处理点云帧投影LIO-SAM 之ImageProjection实现细节

【LVI-SAM】激光雷达点云处理点云帧投影LIO-SAM 之ImageProjection实现细节 1. ImageProjection激光雷达点云预处理算法1.0 总结&#xff1a;1.1 功能概述&#xff1a;1.2 算法流程&#xff1a; 2. ImageProjection激光雷达点云预处理算法数学推倒3. ImageProjection激光雷达点…

安卓玩机工具------小米工具箱扩展工具 小米机型功能拓展

小米工具箱扩展版 小米工具箱扩展版 iO_Box_Mi_Ext是由晨钟酱开发的一款适用于小米&#xff08;MIUI&#xff09;、多亲&#xff08;2、2Pro&#xff09;、多看&#xff08;多看电纸书&#xff09;的多功能工具箱。该工具所有功能均可以免root实现&#xff0c;使用前&…

图解TCP三次握手|深度解析|为什么是三次

写在前面 这篇文章我们来讲解析 TCP三次握手。 TCP 报文段 传输控制块TCB&#xff1a;存储了每一个连接中的一些重要信息。比如TCP连接表&#xff0c;指向发送和接收缓冲的指针&#xff0c;指向重传队列的指针&#xff0c;当前的发送和接收序列等等。 我们再来看一下TCP报…

[高级人工智能 开放性调研] 近两年来[2022~2024]人工智能应用进展重要案例介绍

文章目录 [高级人工智能 开放性调研] 近两年来[2022-2024]人工智能应用进展重要案例介绍写在前面1. AIGC1.1 LLM | 大语言模型问答系统式的生成式AI文档解读——KimiChat代码生成——Cursor 1.2 AI绘画\视频生成 | Stable Diffusion | OpenAI SoraStable DiffusionOpenAI Sora …

模拟网络丢包常用方法以及工具

文章目录 背景常用方法代码实现使用方法测试代码 使用网络流量控制工具 常用工具Clumsy 背景 在软件开发过程中&#xff0c;经常需要模拟不同的网络环境来测试应用在不同条件下的表现。 这些模拟可以采用多种方式进行&#xff0c;包括在代码中实现随机丢包、随机延时、乱序&am…

《JavaEE进阶》----12.<SpringIOCDI【扫描路径+DI详解+经典面试题+总结】>

本篇博客主要讲解 扫描路径 DI详解&#xff1a;三种注入方式及优缺点 经典面试题 总结 五、环境扫描路径 虽然我们没有告诉Spring扫描路径是什么&#xff0c;但是有一些注解已经告诉Spring扫描路径是什么了 如启动类注解SpringBootApplication。 里面有一个注解是componentS…

【Leetcode152】乘积最大子数组(动态规划)

文章目录 一、题目二、思路三、代码 一、题目 二、思路 &#xff08;0&#xff09;读懂题意&#xff1a;题目的“连续”是指位置的连续&#xff0c;而不是说数字的连续&#xff0c;这是个大坑。 &#xff08;1&#xff09;确定状态&#xff1a;定义两个状态来记录当前子数组的…

Windows本地制作nginx证书

OpenSSL 是一个用于生成和管理 SSL/TLS 证书的工具。下载并安装 OpenSSL Select Additional Tasks页面勾选 The OpenSSL binaries (/bin) directory 将OpenSSL的bin目录配置到path中 开命令提示符&#xff08;cmd&#xff09;或 PowerShell。运行以下命令生成一个新的私钥和自…

哈希表的封装和位图

文章目录 2 封装2.1 基础框架2.2 迭代器(1)2.3 迭代器(2) 3. 位图3.1 问题引入3.2 左移和右移&#xff1f;3.3 位图的实现3.4 位图的题目3.5 位图的应用 2 封装 2.1 基础框架 文章 有了前面map和set封装的经验&#xff0c;容易写出下面的代码 // UnorderedSet.h #pragma on…

WireShark抓包软件介绍和安装

文章目录 一、WireShark软件介绍1. **概述**2. **主要功能**3. **使用场景**4. **安装和使用**5. **优点和限制**6. **结论** 二、WireShark的安装三、WireShark的基本使用1. **混杂模式&#xff08;Promiscuous Mode&#xff09;****概述****工作原理****应用场景****启用方式…

STM32F407VET6开发板RT-Thread memheap 内存堆的适配

相关文章 STM32F407VET6开发板RT-Thread的移植适配 STM32F407VET6开发板RT-Thread MSH 串口的适配 环境 STM32F407VET6 开发板&#xff08;魔女&#xff09;&#xff0c;http://www.stm32er.com/ Keil MDK5&#xff0c;版本 5.36 memheap 内存堆 RT-Thread 支持 memheap …

数据结构基础讲解(二)——线性表之单链表专项练习

本文数据结构讲解参考书目&#xff1a; 通过网盘分享的文件&#xff1a;数据结构 C语言版.pdf 链接: https://pan.baidu.com/s/159y_QTbXqpMhNCNP_Fls9g?pwdze8e 提取码: ze8e 上一节我讲了线性表中顺序表的定义以及常用的算法&#xff0c;那么这节我将继续讲解顺序表中的链式…

MySQL-CRUD入门1

文章目录 认识配置文件client节点mysql节点mysqld节点 数据的添加(Create)添加一行数据添加多行数据两种添加数据的效率对比 数据的查询(Retrieve)全列查询指定列查询查询中带有表达式关于字面量关于as重命名 临时表引入distinct去重order by 排序关于NULL 认识配置文件 在我们…

数据结构基础详解(C语言): 树与二叉树的应用_哈夫曼树与哈夫曼曼编码_并查集_二叉排序树_平衡二叉树

文章目录 树与二叉树的应用1.哈夫曼树与哈夫曼曼编码1.1 带权路径长度1.2 哈夫曼树1.2.1 哈夫曼树的构造1.3 哈夫曼编码 2.并查集2.1 并查集的三要素2.1.1 并查集的逻辑结构2.1.2 并查集的存储结构 2.2 并查集的优化2.2.1 初步优化&#xff08;并操作优化&#xff09;2.2.2 终极…

flink wordcount

Maven配置pom文件 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/P…

mybatis-plus使用@EnumValue搭配shardingsphere报错“getObject with type”

目录 一、背景二、修改方案三、如何让修改的TypeHandler生效1、在TableField中配置TypeHandler2、考虑直接在TypeHandlerRegistry注册该枚举的handler为自定义的handler处理类。3、不止重写MybatisEnumTypeHandler&#xff0c;还重写CompositeEnumTypeHandler类3.1、修改Compos…