返回列表 发新帖

《安卓逆向这档事》十八、表哥,你也不想你的Frida被检测吧

  [复制链接]

91

主题

3807

回帖

2万

积分

博士后

萌新

Rank: 8Rank: 8

金币
10363
好评
335
信誉
278

考神MT论坛帅哥MT论坛最佳新人MT论坛活跃会员

QQ
发表于 2024-5-9 12:42:42 | 显示全部楼层 | 阅读模式  来自 福建–石狮
本帖最后由 正己 于 2024-5-11 19:16 编辑



一、课程目标

1.了解常见frida检测
二、工具

1.教程Demo(更新)
2.jadx-gui
3.VS Code
4.jeb

三、课程内容
1.检测文件名、端口名、双进程保护、失效的检测点
1.检测/data/local/tmp路径下的是否有frida特征文件,server端改名,例如:fr
2.指定端口转发
  1. ./fs1 -l 0.0.0.0:6666
  2. adb forward tcp:6666 tcp:6666
  3. frida -H 127.0.0.1:6666 wuaipojie -l hook.js
复制代码

3.spawn启动过双进程保护
  1. frida -U -f 进程名 -l hook.js
复制代码


PS:学会看注入报错的日志,比如说当app主动附加自身进程时,这时候再注入就会提示`run frida as root`(以spawn的方式启动进程即可)
4.借助脚本定位检测frida的so
  1. function hook_dlopen() {
  2.     Interceptor.attach(Module.findExportByName(null, "android_dlopen_ext"),
  3.         {
  4.             onEnter: function (args) {
  5.                 var pathptr = args[0];
  6.                 if (pathptr !== undefined && pathptr != null) {
  7.                     var path = ptr(pathptr).readCString();
  8.                     console.log("load " + path);
  9.                 }
  10.             }
  11.         }
  12.     );
  13. }
复制代码

5.随着firda的版本迭代,以前诸多检测点以失效
(1.)例如`检测D-Bus`
D-Bus是一种进程间通信(IPC)和远程过程调用(RPC)机制,最初是为Linux开发的,目的是用一个统一的协议替代现有的和竞争的IPC解决方案。
  1. bool check_dbus() {
  2.     // 定义一个socket地址结构体变量sa
  3.     struct sockaddr_in sa;
  4.     // 创建一个socket文件描述符
  5.     int sock;
  6.     // 定义一个字符数组res,用于存储接收到的数据
  7.     char res[7];

  8.     // 循环遍历所有可能的端口号,从0到65535
  9.     for(int i = 0; i <= 65535; i++) {
  10.         // 创建一个新的socket连接
  11.         sock = socket(AF_INET, SOCK_STREAM, 0);
  12.         // 设置socket地址结构体的端口号
  13.         sa.sin_port = htons(i);
  14.         // 尝试连接到当前端口
  15.         if (connect(sock, (struct sockaddr*)&sa, sizeof(sa)) != -1) {
  16.             // 如果连接成功,记录日志信息,表示发现了一个开放的端口
  17.             __android_log_print(ANDROID_LOG_VERBOSE, "ZJ595", "FRIDA DETECTION [1]: Open Port: %d", i);
  18.             // 初始化res数组,清零
  19.             memset(res, 0, 7);
  20.             // 向socket发送一个空字节
  21.             send(sock, "\x00", 1, 0); // 注意这里的NULL被替换为0
  22.             // 发送AUTH请求
  23.             send(sock, "AUTH\r\n", 6, 0);
  24.             // 等待100微秒
  25.             usleep(100);
  26.             // 尝试接收响应
  27.             if (recv(sock, res, 6, MSG_DONTWAIT) != -1) {
  28.                 // 如果接收到响应,检查响应内容是否为"REJECT"
  29.                 if (strcmp(res, "REJECT") == 0) {
  30.                     // 如果是,关闭socket并返回true,表示检测到了Frida服务器
  31.                     close(sock);
  32.                     return true; // Frida server detected
  33.                 }
  34.             }
  35.         }
  36.         // 如果当前端口连接失败或没有检测到Frida服务器,关闭socket
  37.         close(sock);
  38.     }
  39.     // 如果遍历完所有端口都没有检测到Frida服务器,返回false
  40.     return false; // No Frida server detected
  41. }

复制代码

(2)`检测fd`
/proc/pid/fd 目录的作用在于提供了一种方便的方式来查看进程的文件描述符信息,这对于调试和监控进程非常有用。通过查看文件描述符信息,可以了解进程打开了哪些文件、网络连接等,帮助开发者和系统管理员进行问题排查和分析工作。
  1. bool check_fd() {
  2.     DIR *dir = NULL;
  3.     struct dirent *entry;
  4.     char link_name[100];
  5.     char buf[100];
  6.     bool ret = false;
  7.     if ((dir = opendir("/proc/self/fd/")) == NULL) {
  8.         LOGI(" %s - %d  error:%s", __FILE__, __LINE__, strerror(errno));
  9.     } else {
  10.         entry = readdir(dir);
  11.         while (entry) {
  12.             switch (entry->d_type) {
  13.                 case DT_LNK:
  14.                     sprintf(link_name, "%s/%s", "/proc/self/fd/", entry->d_name);
  15.                     readlink(link_name, buf, sizeof(buf));
  16.                     if (strstr(buf, "frida") || strstr(buf, "gum-js-loop") ||
  17.                         strstr(buf, "gmain") ||
  18.                         strstr(buf, "-gadget") || strstr(buf, "linjector")) {
  19.                         LOGI("check_fd -> find frida:%s", buf);
  20.                         ret = true;
  21.                     }
  22.                     break;
  23.                 default:
  24.                     break;
  25.             }
  26.             entry = readdir(dir);
  27.         }
  28.     }
  29.     closedir(dir);
  30.     return ret;
  31. }

复制代码

(3)`检测文件`
众所周知frida我们一般都会放在data/local/tmp目录下,旧版fridaserver端运行时都会释放到re.frida.server,所以这里在旧版也会被当做一个检测点,而新版已不再释放
2检测map
  1. adb shell ps | findstr com.zj.wuaipojie
  2. cat /proc/12186/maps|grep frida
复制代码






`/proc/self/maps` 是一个特殊的文件,它包含了当前进程的内存映射信息。当你打开这个文件时,它会显示一个列表,其中包含了进程中每个内存区域的详细信息。这些信息通常包括:
- 起始地址(Start Address)
- 结束地址(End Address)
- 权限(如可读、可写、可执行)
- 共享/私有标志(Shared or Private)
- 关联的文件或设备(如果内存区域是文件映射的)
- 内存区域的偏移量
- 内存区域的类型(如匿名映射、文件映射、设备映射等)
当注入frida后,在maps文件中就会存在 `frida-agent-64.so`、`frida-agent-32.so` 等文件。

  1. bool check_maps() {
  2.     // 定义一个足够大的字符数组line,用于存储读取的行
  3.     char line[512];
  4.     // 打开当前进程的内存映射文件/proc/self/maps进行读取
  5.     FILE* fp = fopen("/proc/self/maps", "r");
  6.     if (fp) {
  7.         // 如果文件成功打开,循环读取每一行
  8.         while (fgets(line, sizeof(line), fp)) {
  9.             // 使用strstr函数检查当前行是否包含"frida"字符串
  10.             if (strstr(line, "frida") || strstr(line, "gadget")) {
  11.                 // 如果找到了"frida",关闭文件并返回true,表示检测到了恶意库
  12.                 fclose(fp);
  13.                 return true; // Evil library is loaded.
  14.             }
  15.         }
  16.         // 遍历完文件后,关闭文件
  17.         fclose(fp);
  18.     } else {
  19.         // 如果无法打开文件,记录错误。这可能意味着系统状态异常
  20.         // 注意:这里的代码没有处理错误,只是注释说明了可能的情况
  21.     }
  22.     // 如果没有在内存映射文件中找到"frida",返回false,表示没有检测到恶意库
  23.     return false; // No evil library detected.
  24. }

复制代码

方法1
`anti脚本`
  1. // 定义一个函数anti_maps,用于阻止特定字符串的搜索匹配,避免检测到敏感内容如"Frida"或"REJECT"
  2. function anti_maps() {
  3.     // 查找libc.so库中strstr函数的地址,strstr用于查找字符串中首次出现指定字符序列的位置
  4.     var pt_strstr = Module.findExportByName("libc.so", 'strstr');
  5.     // 查找libc.so库中strcmp函数的地址,strcmp用于比较两个字符串
  6.     var pt_strcmp = Module.findExportByName("libc.so", 'strcmp');
  7.     // 使用Interceptor模块附加到strstr函数上,拦截并修改其行为
  8.     Interceptor.attach(pt_strstr, {
  9.         // 在strstr函数调用前执行的回调
  10.         onEnter: function (args) {
  11.             // 读取strstr的第一个参数(源字符串)和第二个参数(要查找的子字符串)
  12.             var str1 = args[0].readCString();
  13.             var str2 = args[1].readCString();
  14.             // 检查子字符串是否包含"REJECT"或"frida",如果包含则设置hook标志为true
  15.             if (str2.indexOf("REJECT") !== -1  || str2.indexOf("frida") !== -1) {
  16.                 this.hook = true;
  17.             }
  18.         },
  19.         // 在strstr函数调用后执行的回调
  20.         onLeave: function (retval) {
  21.             // 如果之前设置了hook标志,则将strstr的结果替换为0(表示未找到),从而隐藏敏感信息
  22.             if (this.hook) {
  23.                 retval.replace(0);
  24.             }
  25.         }
  26.     });

  27.     // 对strcmp函数做类似的处理,防止通过字符串比较检测敏感信息
  28.     Interceptor.attach(pt_strcmp, {
  29.         onEnter: function (args) {
  30.             var str1 = args[0].readCString();
  31.             var str2 = args[1].readCString();
  32.             if (str2.indexOf("REJECT") !== -1  || str2.indexOf("frida") !== -1) {
  33.                 this.hook = true;
  34.             }
  35.         },
  36.         onLeave: function (retval) {
  37.             if (this.hook) {
  38.                 // strcmp返回值为0表示两个字符串相等,这里同样替换为0以避免匹配成功
  39.                 retval.replace(0);
  40.             }
  41.         }
  42.     });
  43. }

复制代码

方法2
`重定向maps`
  1. // 定义一个函数,用于重定向并修改maps文件内容,以隐藏特定的库和路径信息
  2. function mapsRedirect() {
  3.     // 定义伪造的maps文件路径
  4.     var FakeMaps = "/data/data/com.zj.wuaipojie/maps";
  5.     // 获取libc.so库中'open'函数的地址
  6.     const openPtr = Module.getExportByName('libc.so', 'open');
  7.     // 根据地址创建一个新的NativeFunction对象,表示原生的'open'函数
  8.     const open = new NativeFunction(openPtr, 'int', ['pointer', 'int']);
  9.     // 查找并获取libc.so库中'read'函数的地址
  10.     var readPtr = Module.findExportByName("libc.so", "read");
  11.     // 创建新的NativeFunction对象表示原生的'read'函数
  12.     var read = new NativeFunction(readPtr, 'int', ['int', 'pointer', "int"]);
  13.     // 分配512字节的内存空间,用于临时存储从maps文件读取的内容
  14.     var MapsBuffer = Memory.alloc(512);
  15.     // 创建一个伪造的maps文件,用于写入修改后的内容,模式为"w"(写入)
  16.     var MapsFile = new File(FakeMaps, "w");
  17.     // 使用Interceptor替换原有的'open'函数,注入自定义逻辑
  18.     Interceptor.replace(openPtr, new NativeCallback(function(pathname, flag) {
  19.         // 调用原始的'open'函数,并获取文件描述符(FD)
  20.         var FD = open(pathname, flag);
  21.         // 读取并打印尝试打开的文件路径
  22.         var ch = pathname.readCString();
  23.         if (ch.indexOf("/proc/") >= 0 && ch.indexOf("maps") >= 0) {
  24.             console.log("open : ", pathname.readCString());
  25.             // 循环读取maps内容,并写入伪造的maps文件中,同时进行字符串替换以隐藏特定信息
  26.             while (parseInt(read(FD, MapsBuffer, 512)) !== 0) {
  27.                 var MBuffer = MapsBuffer.readCString();
  28.                 MBuffer = MBuffer.replaceAll("/data/local/tmp/re.frida.server/frida-agent-64.so", "FakingMaps");
  29.                 MBuffer = MBuffer.replaceAll("re.frida.server", "FakingMaps");
  30.                 MBuffer = MBuffer.replaceAll("frida-agent-64.so", "FakingMaps");
  31.                 MBuffer = MBuffer.replaceAll("frida-agent-32.so", "FakingMaps");
  32.                 MBuffer = MBuffer.replaceAll("frida", "FakingMaps");
  33.                 MBuffer = MBuffer.replaceAll("/data/local/tmp", "/data");
  34.                 // 将修改后的内容写入伪造的maps文件
  35.                 MapsFile.write(MBuffer);
  36.             }
  37.             // 为返回伪造maps文件的打开操作,分配UTF8编码的文件名字符串
  38.             var filename = Memory.allocUtf8String(FakeMaps);
  39.             // 返回打开伪造maps文件的文件描述符
  40.             return open(filename, flag);
  41.         }
  42.         // 如果不是目标maps文件,则直接返回原open调用的结果
  43.         return FD;
  44.     }, 'int', ['pointer', 'int']));
  45. }
复制代码

方法3
用eBPF来hook系统调用并修改参数实现目的,使用bpf_probe_write_user向用户态函数地址写内容直接修改参数
  1. char placeholder[] = "/data/data/com.zj.wuaipojie/maps";
  2. bpf_probe_write_user((void*)addr, placeholder, sizeof(placeholder));
复制代码

3.检测status(线程名)
  1. ls /proc/pid/task 列出线程id
  2. cat /proc/pid/task/线程id/status
复制代码

- 在 `/proc/pid/task` 目录下,可以通过查看不同的线程子目录,来获取进程中每个线程的运行时信息。这些信息包括线程的状态、线程的寄存器内容、线程占用的CPU时间、线程的堆栈信息等。通过这些信息,可以实时观察和监控进程中每个线程的运行状态,帮助进行调试、性能优化和问题排查等工作。
- 在某些app中就会去读取 `/proc/stask/线程ID/status` 文件,如果是运行frida产生的,则进行反调试。例如:`gmain/gdbus/gum-js-loop/pool-frida`等

1. gmain:Frida 使用 Glib 库,其中的主事件循环被称为 GMainLoop。在 Frida 中,gmain 表示 GMainLoop 的线程。
2. gdbus:GDBus 是 Glib 提供的一个用于 D-Bus 通信的库。在 Frida 中,gdbus 表示 GDBus 相关的线程。
3. gum-js-loop:Gum 是 Frida 的运行时引擎,用于执行注入的 JavaScript 代码。gum-js-loop 表示 Gum 引擎执行 JavaScript 代码的线程。
4. pool-frida:Frida 中的某些功能可能会使用线程池来处理任务,pool-frida 表示 Frida 中的线程池。
5. linjector 是一种用于 Android 设备的开源工具,它允许用户在运行时向 Android 应用程序注入动态链接库(DLL)文件。通过注入 DLL 文件,用户可以修改应用程序的行为、调试应用程序、监视函数调用等,这在逆向工程、安全研究和动态分析中是非常有用的。
PS:由于frida可以随时附加到进程,所以写的检测必须覆盖APP的全周期,或者至少是敏感函数执行前

  1. bool check_status() {
  2.     DIR *dir = opendir("/proc/self/task/");
  3.     struct dirent *entry;
  4.     char status_path[MAX_PATH];
  5.     char buffer[MAX_BUFFER];
  6.     int found = false;

  7.     if (dir) {
  8.         while ((entry = readdir(dir)) != NULL) {
  9.             if (entry->d_type == DT_DIR) {
  10.                 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
  11.                     continue;
  12.                 }
  13.                 snprintf(status_path, sizeof(status_path), "/proc/self/task/%s/status", entry->d_name);
  14.                 if (read_file(status_path, buffer, sizeof(buffer)) == -1) {
  15.                     continue;
  16.                 }
  17.                 if (strcmp(buffer, "null") == 0) {
  18.                     continue;
  19.                 }
  20.                 char *line = strtok(buffer, "\n");
  21.                 while (line) {
  22.                     if (strstr(line, "Name:") != NULL) {
  23.                         const char *frida_name = strstr(line, "gmain");
  24.                         if (frida_name || strstr(line, "gum-js-loop") || strstr(line, "pool-frida") || strstr(line, "gdbus")) {
  25.                             found = true;
  26.                             break;
  27.                         }
  28.                     }
  29.                     line = strtok(NULL, "\n");
  30.                 }
  31.                 if (found) break;
  32.             }
  33.         }
  34.         closedir(dir);
  35.     }
  36.     return found;
  37. }
复制代码


`anti脚本`
  1. function replace_str() {
  2.     var pt_strstr = Module.findExportByName("libc.so", 'strstr');
  3.     var pt_strcmp = Module.findExportByName("libc.so", 'strcmp');

  4.     Interceptor.attach(pt_strstr, {
  5.         onEnter: function (args) {
  6.             var str1 = args[0].readCString();
  7.             var str2 = args[1].readCString();
  8.             if (str2.indexOf("tmp") !== -1 ||
  9.                 str2.indexOf("frida") !== -1 ||
  10.                 str2.indexOf("gum-js-loop") !== -1 ||
  11.                 str2.indexOf("gmain") !== -1 ||
  12.                 str2.indexOf("gdbus") !== -1 ||
  13.                 str2.indexOf("pool-frida") !== -1||
  14.                 str2.indexOf("linjector") !== -1) {
  15.                 //console.log("strcmp-->", str1, str2);
  16.                 this.hook = true;
  17.             }
  18.         }, onLeave: function (retval) {
  19.             if (this.hook) {
  20.                 retval.replace(0);
  21.             }
  22.         }
  23.     });

  24.     Interceptor.attach(pt_strcmp, {
  25.         onEnter: function (args) {
  26.             var str1 = args[0].readCString();
  27.             var str2 = args[1].readCString();
  28.             if (str2.indexOf("tmp") !== -1 ||
  29.                 str2.indexOf("frida") !== -1 ||
  30.                 str2.indexOf("gum-js-loop") !== -1 ||
  31.                 str2.indexOf("gmain") !== -1 ||
  32.                 str2.indexOf("gdbus") !== -1 ||
  33.                 str2.indexOf("pool-frida") !== -1||
  34.                 str2.indexOf("linjector") !== -1) {
  35.                 //console.log("strcmp-->", str1, str2);
  36.                 this.hook = true;
  37.             }
  38.         }, onLeave: function (retval) {
  39.             if (this.hook) {
  40.                 retval.replace(0);
  41.             }
  42.         }
  43.     })

  44. }
复制代码


4.检测inlinehook
通过Frida查看一个函数hook之前和之后的机器码,以此来判断是否被Frida的inlinehook注入。

剩下内容太多了,看顶置评论


已有5人评分好评 金币 理由
Unknowing + 1 + 1 很给力!
zzzz22 + 1 + 1
虚伪的鲲 + 1 + 1
cxp521 + 1 + 1 很给力!
夏日的风 + 1 + 1 赞一个!

查看全部评分 总评分:好评 +5  金币 +5 

回复

使用道具 举报

91

主题

3807

回帖

2万

积分

博士后

萌新

Rank: 8Rank: 8

金币
10363
好评
335
信誉
278

考神MT论坛帅哥MT论坛最佳新人MT论坛活跃会员

QQ
发表于 2024-5-9 12:43:11 | 显示全部楼层  来自 福建–石狮
本帖最后由 正己 于 2024-5-10 19:54 编辑

下面的方案以内存中字节和本地对应的字节进行比较,如果不一致,那么可以认为内存中的字节被修改了,即被inlinehook了
  1. #include <jni.h>
  2. #include <string>
  3. #include <dlfcn.h>
  4. #include "dlfcn/local_dlfcn.h"

  5. bool check_inlinehook() {
  6.     // 根据系统架构选择对应的libc.so库路径
  7.     const char *lib_path;
  8.     #ifdef __LP64__
  9.     lib_path = "/system/lib64/libc.so";
  10.     #else
  11.     lib_path = "/system/lib/libc.so";
  12.     #endif

  13.     // 定义要比较的字节数
  14.     const int CMP_COUNT = 8;
  15.     // 指定要查找的符号名,这里是"open"函数
  16.     const char *sym_name = "open";

  17.     // 使用local_dlopen函数打开指定的共享库,并获取操作句柄
  18.     struct local_dlfcn_handle *handle = static_cast<local_dlfcn_handle *>(local_dlopen(lib_path));
  19.     if (!handle) {
  20.         return JNI_FALSE; // 如果无法打开共享库,返回false
  21.     }

  22.     // 获取"open"函数在libc.so中的偏移量
  23.     off_t offset = local_dlsym(handle, sym_name);

  24.     // 关闭handle,因为我们接下来使用标准的dlopen/dlsy来获取函数地址
  25.     local_dlclose(handle);

  26.     // 打开libc.so文件,准备读取数据
  27.     FILE *fp = fopen(lib_path, "rb");
  28.     if (!fp) {
  29.         return JNI_FALSE; // 如果无法打开文件,返回false
  30.     }

  31.     // 定义一个缓冲区,用于存储读取的文件内容
  32.     char file_bytes[CMP_COUNT] = {0};
  33.     // 读取指定偏移量处的CMP_COUNT个字节
  34.     fseek(fp, offset, SEEK_SET);
  35.     fread(file_bytes, 1, CMP_COUNT, fp);
  36.     fclose(fp);

  37.     // 使用dlopen函数打开libc.so共享库,并获取操作句柄
  38.     void *dl_handle = dlopen(lib_path, RTLD_NOW);
  39.     if (!dl_handle) {
  40.         return JNI_FALSE; // 如果无法打开共享库,返回false
  41.     }

  42.     // 使用dlsym函数获取"open"函数的地址
  43.     void *sym = dlsym(dl_handle, sym_name);
  44.     if (!sym) {
  45.         dlclose(dl_handle);
  46.         return JNI_FALSE; // 如果无法找到符号,返回false
  47.     }

  48.     // 比较原libc.so中的"open"函数内容与通过dlsym获取的"open"函数内容是否一致
  49.     int is_hook = memcmp(file_bytes, sym, CMP_COUNT) != 0;

  50.     // 关闭dlopen打开的共享库句柄
  51.     dlclose(dl_handle);

  52.     // 返回比较结果,如果函数被hook则返回JNI_TRUE,否则返回JNI_FALSE
  53.     return is_hook ? JNI_TRUE : JNI_FALSE;
  54. }

复制代码


`获取hook前字节码的脚本`
  1. let bytes_count = 8
  2. let address = Module.getExportByName("libc.so","open")

  3. let before = ptr(address)
  4. console.log("")
  5. console.log("[*] before hook: ")
  6. console.log(hexdump(before, {
  7.     offset: 0,
  8.     length: bytes_count,
  9.     header: true,
  10.     ansi: true
  11.   }));

复制代码


`anti脚本`
  1. function hook_memcmp_addr(){
  2.     //hook反调试
  3.     var memcmp_addr = Module.findExportByName("libc.so", "fread");
  4.     if (memcmp_addr !== null) {
  5.         console.log("fread address: ", memcmp_addr);
  6.         Interceptor.attach(memcmp_addr, {
  7.         onEnter: function (args) {
  8.             this.buffer = args[0];   // 保存 buffer 参数
  9.             this.size = args[1];     // 保存 size 参数
  10.             this.count = args[2];    // 保存 count 参数
  11.             this.stream = args[3];   // 保存 FILE* 参数
  12.         },
  13.         onLeave: function (retval) {
  14.             // 这里可以修改 buffer 的内容,假设我们知道何时 fread 被用于敏感操作
  15.             console.log(this.count.toInt32());
  16.             if (this.count.toInt32() == 8) {
  17.                 // 模拟 fread 读取了预期数据,伪造返回值
  18.                 Memory.writeByteArray(this.buffer, [0x50, 0x00, 0x00, 0x58, 0x00, 0x02, 0x1f, 0xd6]);
  19.                 retval.replace(8); // 填充前8字节
  20.                 console.log(hexdump(this.buffer));
  21.             }
  22.         }
  23.     });
  24.     } else {
  25.         console.log("Error: memcmp function not found in libc.so");
  26.     }
  27. }

复制代码


5.刷入魔改的frida-server端
注意版本!!!
strongR-frida-android


六、视频及课件地址
百度云
阿里云
哔哩哔哩
[教程开源地址](https://github.com/ZJ595/AndroidReverse)
PS:解压密码都是52pj,阿里云由于不能分享压缩包,所以下载exe文件,双击自解压

七、其他章节
《安卓逆向这档事》一、模拟器环境搭建  
《安卓逆向这档事》二、初识APK文件结构、双开、汉化、基础修改  
《安卓逆向这档事》三、初识smail,vip终结者  
《安卓逆向这档事》四、恭喜你获得广告&弹窗静默卡  
《安卓逆向这档事》五、1000-7=?&动态调试&Log插桩  
《安卓逆向这档事》六、校验的N次方-签名校验对抗、PM代{过}{滤}理、IO重定向  
《安卓逆向这档事》七、Sorry,会Hook真的可以为所欲为-Xposed快速上手(上)模块编写,常用Api  
《安卓逆向这档事》八、Sorry,会Hook真的可以为所欲为-xposed快速上手(下)快速hook  
《安卓逆向这档事》九、密码学基础、算法自吐、非标准加密对抗  
《安卓逆向这档事》十、不是我说,有了IDA还要什么女朋友?  
《安卓逆向这档事》十二、大佬帮我分析一下  
《安卓逆向这档事》番外实战篇1-某电全家桶  
《安卓逆向这档事》十三、是时候学习一下Frida一把梭了(上)
《安卓逆向这档事》十四、是时候学习一下Frida一把梭了(中)
《安卓逆向这档事》十五、是时候学习一下Frida一把梭了(下)
《安卓逆向这档事》十六、是时候学习一下Frida一把梭了(终)
《安卓逆向这档事》十七、你的RPCvs佬的RPC
《安卓逆向这档事》番外实战篇2-【2024春节】解题领红包活动,启动!
八、参考文档
frida常用检测点及其原理--一把梭方案
frida 检测
从inlinehook角度检测frida
Frida检测手段探究
Lsposed 技术原理探讨 && 基本安装使用
strongR-frida-android
基础反检测 frida-server
关于frida检测的一个新思路
读取本地so文件的符号的偏移
多种姿势花样使用Frida注入
回复

使用道具 举报

13

主题

3126

回帖

1万

积分

博士生

Rank: 7Rank: 7Rank: 7

金币
5042
好评
1
信誉
100
发表于 2024-5-9 12:49:28 来自手机  | 显示全部楼层  来自 山西
谢谢分享,辛苦了
回复

使用道具 举报

19

主题

1872

回帖

1万

积分

博士生

Rank: 7Rank: 7Rank: 7

金币
4944
好评
24
信誉
133

考神

发表于 2024-5-9 12:51:15 来自手机  | 显示全部楼层  来自 福建
看看
回复

使用道具 举报

111

主题

2595

回帖

1万

积分

博士生

Rank: 7Rank: 7Rank: 7

金币
3848
好评
10
信誉
100

MT论坛最佳新人MT论坛帅哥

发表于 2024-5-9 12:51:32 来自手机  | 显示全部楼层  来自 山东
感谢分享
回复

使用道具 举报

0

主题

3820

回帖

9826

积分

硕士生

Rank: 6Rank: 6

金币
8809
好评
0
信誉
127

MT论坛帅哥MT论坛新人考神MT论坛最佳新人

发表于 2024-5-9 12:52:02 来自手机  | 显示全部楼层  来自 河南
看看隐藏
回复

使用道具 举报

91

主题

3807

回帖

2万

积分

博士后

萌新

Rank: 8Rank: 8

金币
10363
好评
335
信誉
278

考神MT论坛帅哥MT论坛最佳新人MT论坛活跃会员

QQ
发表于 2024-5-9 12:52:48 | 显示全部楼层  来自 福建–石狮
本帖最后由 正己 于 2024-5-9 13:50 编辑

不小心评论多了
回复

使用道具 举报

1

主题

4036

回帖

9669

积分

硕士生

Rank: 6Rank: 6

金币
2571
好评
1
信誉
100

MT论坛最佳新人

发表于 2024-5-9 12:53:21 来自手机  | 显示全部楼层  来自 云南
看看隐藏
回复

使用道具 举报

134

主题

3460

回帖

1万

积分

博士生

无敌最俊朗

Rank: 7Rank: 7Rank: 7

金币
3010
好评
49
信誉
105
发表于 2024-5-9 12:54:37 来自手机  | 显示全部楼层  来自 四川
学习学习
回复

使用道具 举报

152

主题

7921

回帖

2万

积分

博士后

Rank: 8Rank: 8

金币
11462
好评
10
信誉
104

MT论坛最佳新人考神MT论坛新人MT论坛帅哥

发表于 2024-5-9 12:56:24 来自手机  | 显示全部楼层  来自 云南
看看隐藏
回复

使用道具 举报

1

主题

1283

回帖

3581

积分

大学生

Rank: 5Rank: 5

金币
2890
好评
1
信誉
109

考神

发表于 2024-5-9 12:58:35 来自手机  | 显示全部楼层  来自 广东
看看隐藏
回复

使用道具 举报

20

主题

1万

回帖

2万

积分

博士后

Rank: 8Rank: 8

金币
2644
好评
9
信誉
96

考神

发表于 2024-5-9 12:59:22 来自手机  | 显示全部楼层  来自 河北
回复看看
回复

使用道具 举报

171

主题

3614

回帖

1万

积分

博士生

Steve2280

Rank: 7Rank: 7Rank: 7

金币
92
好评
133
信誉
167

MT论坛最佳新人2018国庆节MT论坛帅哥MT论坛新人MT论坛灌水老大考神MT论坛侠客MT论坛活跃会员

发表于 2024-5-9 13:03:09 来自手机  | 显示全部楼层  来自 四川
谢谢分享
回复

使用道具 举报

7

主题

4007

回帖

9268

积分

硕士生

Rank: 6Rank: 6

金币
6096
好评
1
信誉
100

考神

发表于 2024-5-9 13:04:36 来自手机  | 显示全部楼层  来自 河南
看看隐藏
回复

使用道具 举报

0

主题

5325

回帖

1万

积分

博士生

Rank: 7Rank: 7Rank: 7

金币
3870
好评
1
信誉
108

MT论坛新人MT论坛最佳新人考神MT论坛帅哥

发表于 2024-5-9 13:11:03 来自手机  | 显示全部楼层  来自 福建
路过看看
回复

使用道具 举报

发表回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表