(本文由 id:小佳、fyrlove、roysue 共同完成)
这一篇可以看成是《 从零开始绕过 DexProtector 加固的 Frida 检测》的续集:
上一版文章里,我们从 0 开始,一路跟到 DexProtector 的匿名段,把 Frida 的几类检测点(maps / 线程监控 / inline hook / SHA256 校验等)一一打通,在当时的版本上实现了比较完整的一套绕过方案。
大家如果跟着实现了,可以发现,过掉检测后,会提示更新,这也是现实开发/对抗的真实场景:
App 隔三差五发个小版本更新,壳还是 DexProtector,
但 so 结构、偏移、匿名段位置都变了——旧脚本直接崩,
要不要从头再逆一次?
这篇文章要解决的,就是这个“日常但很致命”的问题:
当 app 小版本更新后,怎么在不推倒重来的前提下,
快速把上一版已经验证过的绕过思路迁移过来?
然后,顺着这个场景,我们再往前迈一步,目前都使用了开源模块来完成过检测,这里我们后面会魔改frida-server来完成过检测:
所以整篇文章分成两大部分:
为保证结论可复现、可迁移,所有实验都在同一套环境下完成:
合规声明:
适合谁看?
不适合谁?
阅读顺序建议:
本篇所有操作,都是在上一篇文章的基础上做“版本升级迁移”。如果你还没看过第一篇,建议先看完再回来:
下面从样本更新开始,一步步走一遍:先看旧脚本在新版本上是怎么崩的,再带着这些“已知检测点”,去新版 so 里做定位和迁移。
这一部分的目标很简单:在不推倒重来的前提下,把旧脚本迁移到新版本上继续可用。
核心思路是:
先定位“新的真实执行入口”,再用“老版本已知特征”去对齐“新版本偏移”。
更新后样本:kaiyue610.apks,放在附件和文章结尾。
这里我没有先去看 so,而是直接沿用上一篇已经验证过的完整脚本,先执行一次,看它“死在哪里”。这一步有两个目的:
端口转发:

执行结果:

不出意外的崩溃了。从日志可以看到是典型的“地址无效导致崩溃”。从对抗经验上,这往往意味着:
接下来根据 610 版本的 apk,获取一下新版本的 so,并重新 dump 匿名段上的 so。
第一步还是老流程:先拿到 DexProtector 自己的壳 so,也就是 libdexprotector.so。
这个so在split_config.arm64_v8a.apk里面,安装包里解压出来有,再给它解压就得到libdexprotector.so
把这个新版本的so用ida打开,可以看到:
这里的指针函数变成了off_B848,而上个版本这里是off_C838。
这一步很关键:
JNI_OnLoad 本身没什么花活,但它帮你给出了“下一步真正执行逻辑”的指针
一旦指针位置变了(off_C838 → off_B848),意味着后面所有“基于旧偏移”的脚本都要跟着调整
这一步和上一篇完全一样:
利用 __loader_android_dlopen_ext 的 hook,把匿名段里的真正执行代码 dump 出来。
具体执行过程,请参考上一篇文章,这里不再赘述。
从零开始绕过DexProtector加固的Frida检测
这里我们只关心:新版本的匿名段 so 也已经拿到了,接下来要重新找“真实执行入口”。
执行结果:
这里有几个信息点:
libdexprotector.so 还是正常通过 __loader_android_dlopen_ext 加载
off_B848 指向的地址,仍然落在一个匿名段范围内(0x75ffc04000 ~ 0x75ffc80000)
真正执行逻辑的入口偏移变成了 0x4ec38
小结一下这一节:
修复方法和上一篇一样:把 dump 出来的匿名段 so,按 text 段对齐、修复重定位,尽量恢复出一个“可读”的 IDA 工程。
这里是我已经修复之后的,修复手法,请参考上一篇文章。

到这里,准备工作就完成了。
剩下的,就是围绕新的入口偏移 0x4ec38,去重新定位各类检测点:pthread_create、inline hook 分发、SHA-256 校验、maps 检测等。
这里本质上是在阻断监控线程的创建,让它根本跑不起来。
另一类是“利用指针替换”的方式,把原来的校验函数指向我们想要的地址:
这两类逻辑,有一个共同点:
它们本身不承担“检测计算”,而是“调度 / 分发 / 接线”,属于非常稳定的结构。
版本更新时,里面被调用的具体函数地址会变,但“整体骨架 + 控制方式”大概率不变。
在ida中定位到0x61974,查看790,按tab,查看汇编,这个W8, #0x316,基本是不会变化的。
也就是


所以,总体上,我们需要处理的检测有这几类:
接下来就是实战部分:怎么把这些“共性特征”迁移到新版本上。
app小版本更新,检测点很大概率是不会发生变化的。所以按思路,拿到新dump下来的so之后,顺序进行分析。
上面已经拿到真实的执行函数 => 0x4ec38
在ida中打开新的libanon.so,按G,跳转到0x4ec38。

从这里开始,顺藤摸瓜往下点:点击第一个函数sub_4ED54,进去后,结果如下:

按之前文章分析,可以知道,新的so中,最关键的函数就是sub_4F508了。
进入sub_4F508了之后,顺序进行分析,很快就能找到做inline hook的地方,sub_165F0:

引用查找sub_165F0,找到需要定位的lr,完成后的代码是:
到这里,第一步“顺序查找 + inline hook 迁移”就完成了:
使用010editor,ctrl+f,进行搜索
搜索结果,右键复制地址:

到ida中跳转地址,直接就定位到了sha256的函数,sub_308B0:

修改之后的代码是:
执行一下脚本,拿到地址是0x7a8b0:
使用0x7a8b0,更新脚本:
这一步完成后,新版的 SHA-256 校验逻辑也已经被“接管”,后续就不会再因为 hash 校验失败而崩溃。
使用之前的C8628052,在010editor中进行搜索:

直接就搜索到了,右键复制地址,然后去ida中跳转地址,直接就定位上了,sub_61FBC:

修改之后的代码是:
通过这一步,可以验证两个结论:
在010editor中搜索:28108052

复制地址,到ida跳转地址:

定位到了sub_5AB20,按x查找引用:

跳转后,找到了pthread_create:

基本上可以确定这个sub_7A860这个函数就是pthread_create了,找它全部调用的地方全部ret掉。
在sub_7A860按x,查找所有引用:

然后修改之前的代码:
到这里,新版本的“监控线程创建”也已经全部封死。
执行新的代码:
执行结果,成功过掉了610版本的检测:


这一部分,把版本升级后,如果快速处理脚本更新做了一个详细的拆解。可以总结成一套反复可用的流程。
步骤如下:
以上就完成了版本更新后,快速定位修改脚本并过检测的目的。下面,开始详细分析字符串,还原分析过程。
这一节算是一个“预告性质”的内容:
当前样本在绕过后,继续打印了一些字符串日志,可以看出 DexProtector 在做更多维度的环境检测。
在输出中可以看到有zygisk字符串,选zygisk,在ida中去查看一下,

一般来说,有解密就有比较。分别查看sub_12374和sub_120B0之后,可以知道sub_120B0就是用来做比较的:
可以hook看一下:
运行结果,多输出了很多的字符串:
hook sub_12374
运行结果,又多了很多的字符串输出:
这里只截取了很小的一部分
关于字符串更多的分析,以后在深入分析。不是今天的目的。
接下来,进入第二部分:从环境本身下手,魔改一个属于自己的 frida-server
下面的过程分为两步:
在 Ubuntu 22.04.5 上,从 0 到 1 编译官方 Frida 16.5.2
在此基础上,用 ajeossida 进行魔改,生成自己的 fyrrida server
目标:
说明:
这里以 VMware 为例:
新建虚拟机 → 选择「稍后安装操作系统」或直接选择 ISO。
客户机操作系统选择:
类型:Linux
版本:Ubuntu 64-bit
分配资源(推荐):
CPU:2 核以上
内存:4 GB 起步,建议 8 GB
磁盘:60 GB 或以上,单文件虚拟磁盘
在虚拟机设置中,将 ubuntu-22.04.5-desktop-amd64.iso 挂载为 CD/DVD。
创建共享文件夹
右键虚拟机 -> 设置 -> 共享文件夹启动 -> 选择文件夹确认

右键打开终端执行
如果没有/mnt/hgfs创建一个目录,这个时候不是永久的
修改fstab文件
最后增加一行(如果使用vim要sudo vim)
ln把frida文件夹创建一个链接放到桌面上
这个时候桌面出现frida,它在右下角

更新包(这些打开终端直接执行就可以,简单)
安装gcc编译器相关的
安装git,vim
安装nvm(用来安装node的)
查看node安装版本(node 20.10最好)
安装
安装配置ndk开发环境
搜索ndk下载,下载ndk25版本的,可以window下载放到共享文件夹里面去。
创建value目录在Home里面

创建好了之后解压在home里面,设置/.bashrc环境变量代指home
ANDROID_NDK_ROOT是frida需要的
然后执行更新环境变量
这一小节的目标不是“立刻产出可躲检测版本”,而是:
先保证你在本机能 从源码 → 原版 frida-server 的整个过程跑通,
后面再在这个基础上去做魔改,会轻松很多。
在文件夹里面下载frida-core源码,我只需要frida-server,只拉取frida-core就行了,不用拉取整个frida
cd进去frida-core文件夹,执行加载子模块
配置(我这里使用android-arm64,是因为我的手机是arm64,)
可以选择:["android-arm64", "android-arm", "android-x86_64", "android-x86"]
这样就算是成功了:

使用 make 编译,注意arm64的个数是285

后面要魔改frida,这里必须要先编译一次。
重新编译直接把build全部删掉就可以
如果后面编译不了,删除deps目录,删除build目录
使用了开源库ajeossida进行编译
不想要自己编译的,可以在开源库的release里面去下载成品,不用关心后面的内容。
前面我们已经在 Ubuntu 22.04.5 上完成了 Frida 16.5.2 的基础编译环境。
在此基础上,使用开源库魔改编译一个自己的frida-server:
⚠️ 说明
准备构建脚本仓库
使用 ajeossida 项目,对 Frida 做一层“包装”:统一改名、注释掉一些经典 hook 点、修改线程名等。
强制使用 Frida 16.5.2 源码 + 自定义名字 fyrrida
执行构建脚本,生成 fyrrida server / gadget
在 Ubuntu 里:
完成后的目录结构是:
/home/fyr/value
找到main_ubuntu_android.py修改以下代码
修改代码,指定要编辑的frida版本:
修改代码后指定拉取的是16.5.2的版本,如果不修改的话,原代码会拉取最新的frida版本进行编译。
开始编译:
编译成功:

生成的文件,在assets目录下:

解压fyrrida-server-16.5.2-android-arm64.gz,然后推送到手机
给权限
启动frida-server
端口转发
执行脚本
结果,使用魔改的frida-server,脱离Zygisk Frida Gadget 开源模块。也实现了过检测:

可以看到:
在不依赖 Zygisk Frida Gadget 模块的前提下
仅使用 魔改后的 fyrrida-server + 迁移后的脚本
同样可以通过当前样本的 DexProtector 检测
这一点非常重要,让环境不再捆死在某个模块 / 某个框架上,
而是完全掌握在你自己的手里。
其实这篇文章做的事,就两件:
前者解决的是效率问题:下次 app 再发 6.1.1、6.1.2,你不用一遍遍从 JNI_OnLoad 开始重新看,只要按流程把几个关键偏移和特征重新对齐;
后者解决的是生存问题:哪怕 Zygisk Frida Gadget 被完全针对,你也可以随时从自己的构建环境里,再产一份新版“fyrrida”扔到手机上继续干活。
如果你已经跟着跑通了一遍,建议现在就做两件小事:
安全对抗本身没有"稳定"一说,DexProtector 也不会因为这一篇文章就“被通杀”。
但只要你的方法论是可复用的、环境是自己可控的,每一次小版本更新、每一次新样本,都会变成你工具箱里多长出来的一颗螺丝钉。
(本文内容由id:小佳、fyrlove、roysue 共同完成,属于小佳的系列体系课里的一部分,APK版本是半年前的不影响最新课程)
jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
int v3;
if ( dword_B840 )
return -dword_B840;
v3 = off_B848(vm, 0);
off_B848 = 0;
if ( v3 )
return -v3;
else
return 65540;
}
jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
int v3;
if ( dword_B840 )
return -dword_B840;
v3 = off_B848(vm, 0);
off_B848 = 0;
if ( v3 )
return -v3;
else
return 65540;
}
function hook_dlopen() {
var android_dlopen_ext = Module.findExportByName(null, "__loader_android_dlopen_ext")
Interceptor.attach(android_dlopen_ext, {
onEnter: function (args) {
var pathptr = args[0];
if (pathptr !== undefined && pathptr != null) {
var path = pathptr.readCString();
console.log(path)
if (path.indexOf("libdexprotector.so") !== -1) {
this.match = true
}
}
},
onLeave: function () {
if (this.match) {
let libdexprotector = Process.findModuleByName("libdexprotector.so")
var nativePointer = libdexprotector.base.add(0xB848).readPointer();
var rangeDetails = Process.findRangeByAddress(nativePointer);
console.log(rangeDetails.base)
console.log(rangeDetails.base.add(rangeDetails.size))
console.log("真实的执行函数 => "+nativePointer.sub(rangeDetails.base))
Thread.sleep(50)
}
}
})
}
hook_dlopen()
function hook_dlopen() {
var android_dlopen_ext = Module.findExportByName(null, "__loader_android_dlopen_ext")
Interceptor.attach(android_dlopen_ext, {
onEnter: function (args) {
var pathptr = args[0];
if (pathptr !== undefined && pathptr != null) {
var path = pathptr.readCString();
console.log(path)
if (path.indexOf("libdexprotector.so") !== -1) {
this.match = true
}
}
},
onLeave: function () {
if (this.match) {
let libdexprotector = Process.findModuleByName("libdexprotector.so")
var nativePointer = libdexprotector.base.add(0xB848).readPointer();
var rangeDetails = Process.findRangeByAddress(nativePointer);
console.log(rangeDetails.base)
console.log(rangeDetails.base.add(rangeDetails.size))
console.log("真实的执行函数 => "+nativePointer.sub(rangeDetails.base))
Thread.sleep(50)
}
}
})
}
hook_dlopen()
/system/framework/oat/arm64/org.apache.http.legacy.odex
/data/app/~~Z8NVPZHkUQBOvE5wdUvwlw==/com.Hyatt.hyt-h-4z3JSgsyZQX5dyLoDPUg==/oat/arm64/base.odex
/data/app/~~Z8NVPZHkUQBOvE5wdUvwlw==/com.Hyatt.hyt-h-4z3JSgsyZQX5dyLoDPUg==/split_config.arm64_v8a.apk!/lib/arm64-v8a/libalice.so
/data/app/~~Z8NVPZHkUQBOvE5wdUvwlw==/com.Hyatt.hyt-h-4z3JSgsyZQX5dyLoDPUg==/split_config.arm64_v8a.apk!/lib/arm64-v8a/libdpboot.so
/data/app/~~Z8NVPZHkUQBOvE5wdUvwlw==/com.Hyatt.hyt-h-4z3JSgsyZQX5dyLoDPUg==/split_config.arm64_v8a.apk!/lib/arm64-v8a/libdexprotector.so
0x75ffc04000
0x75ffc80000
真实的执行函数 => 0x4ec38
/system/framework/oat/arm64/org.apache.http.legacy.odex
/data/app/~~Z8NVPZHkUQBOvE5wdUvwlw==/com.Hyatt.hyt-h-4z3JSgsyZQX5dyLoDPUg==/oat/arm64/base.odex
/data/app/~~Z8NVPZHkUQBOvE5wdUvwlw==/com.Hyatt.hyt-h-4z3JSgsyZQX5dyLoDPUg==/split_config.arm64_v8a.apk!/lib/arm64-v8a/libalice.so
/data/app/~~Z8NVPZHkUQBOvE5wdUvwlw==/com.Hyatt.hyt-h-4z3JSgsyZQX5dyLoDPUg==/split_config.arm64_v8a.apk!/lib/arm64-v8a/libdpboot.so
/data/app/~~Z8NVPZHkUQBOvE5wdUvwlw==/com.Hyatt.hyt-h-4z3JSgsyZQX5dyLoDPUg==/split_config.arm64_v8a.apk!/lib/arm64-v8a/libdexprotector.so
0x75ffc04000
0x75ffc80000
真实的执行函数 => 0x4ec38
retFunc(libanon.base.add(0x5A708))
retFunc(libanon.base.add(0x5BE28))
retFunc(libanon.base.add(0x5D1A4))
retFunc(libanon.base.add(0x5D710))
retFunc(libanon.base.add(0x5A708))
retFunc(libanon.base.add(0x5BE28))
retFunc(libanon.base.add(0x5D1A4))
retFunc(libanon.base.add(0x5D710))
var hash_crc = {
"0x4f5a4" : "0x8A810",
"0x4f6cc" : "0x8A810",
"0x5c494" : "0x8AB20"
}
Interceptor.attach(libanon.base.add(0x161E8),{
onEnter:function(args){
console.log("sub_161E8 enter",this.context.lr.sub(libanon.base))
this.lr = this.context.lr.sub(libanon.base)
},onLeave:function(ret){
if(hash_crc[this.lr.toString()]){
ret.replace(libanon.base.add(hash_crc[this.lr.toString()]).readU64())
console.log("sub_161E8 leave",ret)
}
}
})
var hash_crc = {
"0x4f5a4" : "0x8A810",
"0x4f6cc" : "0x8A810",
"0x5c494" : "0x8AB20"
}
Interceptor.attach(libanon.base.add(0x161E8),{
onEnter:function(args){
console.log("sub_161E8 enter",this.context.lr.sub(libanon.base))
this.lr = this.context.lr.sub(libanon.base)
},onLeave:function(ret){
if(hash_crc[this.lr.toString()]){
ret.replace(libanon.base.add(hash_crc[this.lr.toString()]).readU64())
console.log("sub_161E8 leave",ret)
}
}
})
Interceptor.attach(libanon.base.add(0x304A8), {
onEnter: function (args) {
if (args[1].toString() === libanon.base.toString()) {
var rangeDetails = Process.findRangeByAddress(args[0]);
console.log("onEnter 0x304A8 ",args[0],args[1],args[2],"base ",rangeDetails.base)
args[1] = origin
console.log("[0x304A8] 替换成功")
}
}
})
Interceptor.attach(libanon.base.add(0x304A8), {
onEnter: function (args) {
if (args[1].toString() === libanon.base.toString()) {
var rangeDetails = Process.findRangeByAddress(args[0]);
console.log("onEnter 0x304A8 ",args[0],args[1],args[2],"base ",rangeDetails.base)
args[1] = origin
console.log("[0x304A8] 替换成功")
}
}
})
Interceptor.attach(libanon.base.add(0x61974),{
onEnter: function(){
this.lr = this.context.lr.sub(libanon.base)
},
onLeave: function(retval){
console.log("0x61974 => ",retval.toInt32()," lr => ",this.lr);
retval.replace(0);
}
})
Interceptor.attach(libanon.base.add(0x61974),{
onEnter: function(){
this.lr = this.context.lr.sub(libanon.base)
},
onLeave: function(retval){
console.log("0x61974 => ",retval.toInt32()," lr => ",this.lr);
retval.replace(0);
}
})
ROM:0000000000061C84 MOV W8,
ROM:0000000000061C84 MOV W8,
C8628052
var hash_crc = {
"0x4f858": "0x8AE20",
"0x4f980": "0x8AE20",
"0x53c58": "0x8AF00",
"0x5c8f0": "0x8B140"
}
Interceptor.attach(libanon.base.add(0x165F0),{
onEnter:function(args){
console.log("0x165F0 enter",this.context.lr.sub(libanon.base))
this.lr = this.context.lr.sub(libanon.base)
},onLeave:function(ret){
if(hash_crc[this.lr.toString()]){
ret.replace(libanon.base.add(hash_crc[this.lr.toString()]).readU64())
console.log("0x165F0 leave",ret)
}
}
})
var hash_crc = {
"0x4f858": "0x8AE20",
"0x4f980": "0x8AE20",
"0x53c58": "0x8AF00",
"0x5c8f0": "0x8B140"
}
Interceptor.attach(libanon.base.add(0x165F0),{
onEnter:function(args){
console.log("0x165F0 enter",this.context.lr.sub(libanon.base))
this.lr = this.context.lr.sub(libanon.base)
},onLeave:function(ret){
if(hash_crc[this.lr.toString()]){
ret.replace(libanon.base.add(hash_crc[this.lr.toString()]).readU64())
console.log("0x165F0 leave",ret)
}
}
})
6560045e5040115e
Interceptor.attach(libanon.base.add(0x308B0), {
onEnter: function (args) {
if (args[1].toString() === libanon.base.toString()) {
var rangeDetails = Process.findRangeByAddress(args[0]);
console.log("onEnter 0x308B0 ",args[0],args[1],args[2],"base ",rangeDetails.base)
args[1] = origin
console.log("[0x308B0] 替换成功")
}
}
})
Interceptor.attach(libanon.base.add(0x308B0), {
onEnter: function (args) {
if (args[1].toString() === libanon.base.toString()) {
var rangeDetails = Process.findRangeByAddress(args[0]);
console.log("onEnter 0x308B0 ",args[0],args[1],args[2],"base ",rangeDetails.base)
args[1] = origin
console.log("[0x308B0] 替换成功")
}
}
})
0x165F0 enter 0x4f858
0x165F0 leave 0x832d39a094055b4f
onEnter 0x308B0 0x7fc00018c0 0x79ee96c000 0x7a8b0 base 0x7fbf80b000
[0x308B0] 替换成功
0x165F0 enter 0x4f858
0x165F0 leave 0x832d39a094055b4f
onEnter 0x308B0 0x7fc00018c0 0x79ee96c000 0x7a8b0 base 0x7fbf80b000
[0x308B0] 替换成功
var origin
var size=0x7a8b0
var origin
var size=0x7a8b0
Interceptor.attach(libanon.base.add(0x61FBC),{
onEnter: function(){
this.lr = this.context.lr.sub(libanon.base)
},
onLeave: function(retval){
console.log("0x61FBC => ",retval.toInt32()," lr => ",this.lr);
retval.replace(0);
}
})
Interceptor.attach(libanon.base.add(0x61FBC),{
onEnter: function(){
this.lr = this.context.lr.sub(libanon.base)
},
onLeave: function(retval){
console.log("0x61FBC => ",retval.toInt32()," lr => ",this.lr);
retval.replace(0);
}
})
retFunc(libanon.base.add(0x5AB20))
retFunc(libanon.base.add(0x5C280))
retFunc(libanon.base.add(0x5D5FC))
retFunc(libanon.base.add(0x5DB68))
retFunc(libanon.base.add(0x5AB20))
retFunc(libanon.base.add(0x5C280))
retFunc(libanon.base.add(0x5D5FC))
retFunc(libanon.base.add(0x5DB68))
frida -H 127.0.0.1:9999 -F -l hook_dexprotectB848.js
frida -H 127.0.0.1:9999 -F -l hook_dexprotectB848.js
[0x40A68] XposedBridge lr => 0x65e28
[0x40A68] xposed/dummy/XResourcesSuperClass lr => 0x65a54
[0x40A68] /proc/self/status lr => 0x5a820
[0x40A68] dalvik/system/VMDebug lr => 0x5d770
[0x40A68] isDebuggerConnected lr => 0x5d7b8
[0x40A68] ()Z lr => 0x5d7d4
[0x40A68] /proc/self/maps lr => 0x3b68c
[0x40A68] libart.so lr => 0x5d8c4
[0x40A68] libriru lr => 0x61648
[0x40A68] .magisk lr => 0x61660
[0x40A68] zygisk lr => 0x616b8
[0x40A68] XposedBridge lr => 0x65e28
[0x40A68] xposed/dummy/XResourcesSuperClass lr => 0x65a54
[0x40A68] /proc/self/status lr => 0x5a820
[0x40A68] dalvik/system/VMDebug lr => 0x5d770
[0x40A68] isDebuggerConnected lr => 0x5d7b8
[0x40A68] ()Z lr => 0x5d7d4
[0x40A68] /proc/self/maps lr => 0x3b68c
[0x40A68] libart.so lr => 0x5d8c4
[0x40A68] libriru lr => 0x61648
[0x40A68] .magisk lr => 0x61660
[0x40A68] zygisk lr => 0x616b8
__int64 __fastcall sub_120B0(unsigned __int8 *a1, unsigned __int8 *a2)
{
int v2;
unsigned int v3;
while ( 1 )
{
v2 = *a1;
v3 = v2 - *a2;
if ( v3 )
break;
++a2;
++a1;
if ( !v2 )
return 0;
}
return v3;
}
__int64 __fastcall sub_120B0(unsigned __int8 *a1, unsigned __int8 *a2)
{
int v2;
unsigned int v3;
while ( 1 )
{
v2 = *a1;
[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!
最后于 1天前
被fyrlove编辑
,原因: 标题文字重复了