首页
社区
课程
招聘
[原创] Unicorn 在 Android 的应用
发表于: 2019-8-15 01:32 76933

[原创] Unicorn 在 Android 的应用

2019-8-15 01:32
76933

这是我把最近学习记录整理成一个帖子,如果阅读不方便可以看
印象笔记链接

Unicorn 是一款非常优秀的跨平台模拟执行框架,该框架可以跨平台执行Arm, Arm64 (Armv8), M68K, Mips, Sparc, & X86 (include X86_64)等指令集的原生程序。
Unicorn 不仅仅是模拟器,更是一种“硬件级”调试器,使用Unicorn的API可以轻松控制CPU寄存器、内存等资源,调试或调用目标二进制代码,现有的反调试手段对Unicorn 几乎是无效的。 目前国内的Unicorn 学习资料尚少,防御手段也稀缺,官方入门教程虽短小精悍缺无法让你快速驾驭强大的Unicorn,故写这一些列文章。这几篇文章将带你学习Unicorn 框架并开发一款支持JNI的原生程序调用框架、o-llvm 还原脚本、静态脱壳机等。

分析基于https://github.com/AeonLucid/AndroidNativeEmu 开源项目做分析。本人能力微薄,冒昧对此项目进行完善,目前已经实现更多的JNI 函数和syscall,完善mmap映射文件等。参考我的项目:
https://github.com/Chenyuxin/AndroidNativeEmu。

我由衷地感谢AndroidNativeEmu 原作者提供函数hook及模拟JNI的思路,我曾日思夜想如何优雅地模拟JNI,没想到该项目的实现方式竟然十分优雅。

我希望通过这一系列的文章,让更多的人学习Unicorn 框架,学习如何模拟调用,也希望厂商重视对Unicorn的检测! 实践中,这都9102年了,我发现目前仍有加固产品能用Unicorn 跑出dex文件!这一些列的文章,不仅会学习Unicorn,还会学习到优秀的反汇编框架Capstone、汇编框架Keystone。

应用场景
Windows & Linux 跨平台调用Android Native 程序、Api监控、病毒分析、获取Code Coverage、加固方案分析、反混淆等。安全防御方面,简化Unicorn,魔改Unicorn,甚至可以打造一款让逆向工作者感觉云里雾里代码保护器。这里列出的应用场景只是冰山一角!

分析360加固的时候使用Unicorn , 反调试清晰可见

检查status和tcp 文件,只需模拟文件系统,就可以绕过。

360加固寻找解压缩函数地址的操作

Native 动态注册
图片描述

JNI操作一览无余
图片描述

dump 某加固dex
图片描述

Unicorn 是一款基于qemu模拟器的模拟执行框架,支持Arm, Arm64 (Armv8), M68K, Mips, Sparc, & X86 (include X86_64)等指令集。

Unicorn 为多种语言提供编程接口比如C/C++、Python、Java 等语言。Unicorn的DLL 可以被更多的语言调用,比如易语言、Delphi,前途无量。

Unicorn 设计之初就考虑到线程安全问题,能够同时并发模拟执行代码,极大的提高了实用性。

Unicorn 采用虚拟内存机制,使得虚拟CPU的内存与真实CPU的内存隔离。Unicorn 使用如下API来操作内存:

指令执行类

内存访问类

异常处理类

调用hook_add函数可添加一个Hook。Unicorn的Hook是链式的,而不是传统Hook的覆盖式,也就是说,可以同时添加多个同类型的Hook,Unicorn会依次调用每一个handler。hook callback 是有作用范围的(见hook_add begin参数)。

python包中的hook_add函数原型如下

不同类型的hook,对应的callback的参数也不相同,这里只给出C语言定义。
Python 编写callback的时候参考C语言即可(看参数)。

user_data: hook_add 设置的user_data参数

user_data: hook_add 设置的user_data参数

返回值
返回真,继续模拟执行
返回假,停止模拟执行

Unicorn 支持多种编译和安装方式,本课程以Linux作为学习环境,Python3作为主要语言。Linux 下可以直接使用pip安装,方便快捷。

更多详细安装过程可以参考
官方安装教程

Unicorn 支持多种不同的CPU指令集,每一种指令集都有自己独立的寄存器, Unicorn使用统一API管理多种不同的CPU指令集,并将寄存器名字映射成数字常量。

寄存器常量命名规则
UC_ + 指令集 + REG + 大写寄存器名
UC_ARMREG + 大写寄存器名 (UC_ARM_REG_R0)
UC_X86REG + 大写寄存器名 (UC_X86_REG_EAX)

本课程以python3 + arm指令集为例子,导入arm的常量

为了简单起见,我们直接将要执行代码的数据硬编码。

Uc 是unicorn的主类,Uc对象则代表了一个独立的虚拟机实例,它有独立的寄存器和内存等资源,不同Uc对象之间的数据是独立的。Uc的构造函数有两个参数 archmode,用来指定模拟执行的指令集和对应的位数或模式。
arch常量参数一般以 UCARCH 开头,MODE常量以UCMODE 开头。

同一种指令集可以有多种模式,比如x86可以同时运行32位和16位的汇编,arm也有arm模式和Thumb模式,它们是向下兼容的,并可以通过特殊指令来切换CPU运行模式。 调用构造函数时的模式(mode)以第一条执行指令的模式为准。

想用Unicorn模拟执行代码,是不能将代码字节流直接以参数形式传递给Unicorn,而是将要执行的代码写入到Unicorn 的虚拟内存中。Uc 虚拟机实例初始内存是没有任何映射的,在读写内存之前使用uc_mem_map函数映射一段内存。

这段代码在内存地址0x10000处映射了一段大小为2M的内存。mem_map函数特别娇气,要求 address 和 size 参数都与0x1000对齐,否则会报UC_ERR_ARG异常。

我们要执行代码,就需要将欲执行代码的字节数据写入到虚拟机内存中。

mem_write的第二个参数也很娇气,只支持python的byte数组,不能是String或者bytearray。

这个有点像单步调试的感觉。

在begin...end范围内的每一条指令被执行前都会调用callback。
让我们来看看hook_code 的实现吧

这段代码仅打印指令执行的地址和长度信息。 实际应用中可配合capstone反汇编引擎玩一些更骚的操作。

UC_HOOK_CODE的callback中可以修改PC或EIP等寄存器力来改变程序运行流程。实际上,unicorn调试器的单步调试就是以这个为基础实现的。

原谅我用开机这个词汇吧!我们已经映射内存并将数据写入到内存,并设置好执行Hook以监视指令是否正常执行,但是虚拟机还没有启动!

emu_start 可以通过timeout参数设置最长执行时长,防止线程死在虚拟机里面。原型如下

emu_start 执行完成后,可以通过读取内存或寄存器的方式来获取执行结果。

Unicorn 版的Hello world很好展示了Unicorn的使用过程。 美中不足的是,它过于简陋,没有涉及到栈操作、系统调用、API调用等,要知道,现在任何一段代码、一个函数都会至少涉及到其中的一项。

前一篇文章中,我们学习了如何使用Unicorn 来模拟执行一段二进制代码。然而目前Unicorn 对于我们来说,几乎就等同于黑盒子。我们只知输入输出,对于代码中间执行过程的失败与否全然不知,如果出现BUG将难以调试。 为了解决这种难以调试的状况,我决定写一个Unicorn 调试器, 用来调试Unicorn 模拟执行的二进制代码。

Unicorn 提供了强大的指令级Hook(UC_HOOK_CODE), 使得每一条指令执行前,我们都有机会处理。

UC_HOOK_CODE 的callback原型定义如下

调用hook_add 函数可以为指定的代码范围添加hook的callback。
python包中的hook_add函数原型如下

UC_HOOK_CODE 的功能是每条指令执行前调用callback。

callback中,我们可以通过参数得知指令执行地址、指令执行长度、虚拟机指针。
有了虚拟机指针,我们可以很方便的访问各种寄存器、内存等资源。在UC_HOOK_CODE的callback中,也可以直接修改PC寄存器来改变流程。

调试器要支持的调试指令如下

本文将编写一个UnicornDebugger 类,调试器的各种功能均在该类中实现, 调用该类的构造函数即可附加到一个Uc虚拟机对象上。
类的定义

附加调试器

可见,这段代码在0x1112233处添加了一个断点,当程序执行到0x1112233处的时候就会停下来,陷入调试器的处理,等待调试者的指令。

Unicorn 并没有反汇编功能,虽然它的内部一定有与反汇编相关的代码。我们只能自己想办法反汇编。Unicorn 有一个兄弟,它叫Capstone。Capstone是一款支持多种处理器和开发语言的反汇编框架。Capstone 官方地址 我将使用Capstone 作为调试模块的反汇编器。

Capstone 对python的支持特别好,我们的开发语言是python3,所以直接使用pip 安装capstone 即可。

Capstone 很强大,也可以很简单, 下面一段代码就是Capstone的入门例子。

上面这段代码的输出如下

可以看出,Capstone 十分简单, 而我们编写调试器的反汇编部分,也是如此简单。

Python的hexdump模块的偏移量不支持修改,所以我魔改了hexdump的代码实现了这个功能。

魔改的hexdump

Unicorn中的寄存器都是以常量来管理的,所以我们要把寄存器常量和文本映射起来。

使用list来记录所有断点的地址,当UC_HOOK_CODE的callback被调用的时候检查address是否在断点列表中,如果当前指令的执行地址没有断点,则直接返回,如果存在断点,则打印寄存器信息、最近的汇编代码、等待用户指令等操作。

单步分为两种:步入、步过。
步入:如果遇到call、bl指令会跟随进入(跟随每一条指令)
步过:遇到call、bl等指令不不进入(跟随每一条地址相邻的指令)
我这个思路可能有点牵强,因为按照地址相邻,会误判跳转指令,但是为了简单起见,我只好这么做。

下面是断点管理相关的代码。

callback 中判断断点。
_tmp_bpt 是临时断点, 用于支持步过。
_is_step 步入标记,每条指令都停下来。

处理调试指令

断点停下来后效果如下

本篇文章仅仅实现了一个ARM/Thumb调试器,能满足一些基本调试,很多地方仍需改进。其它架构的也可以按照类似方法设计!与传统的调试器断点相比,UnicornDebugger采用的是一种类似硬件断点的技术,Unicorn的指令级Hook 难以被模拟执行的代码检测到。UnicornDebugger从一个很低的level去调试程序,这有点像是硬件调试器了!基于时间的反调试无济于事,因为unicorn 可以读写任何一条指令或则API的执行结果。也不能通过检测status或其它系统特性检测调试器,因为UnicornDebugger不属于操作系统的调试体系。Unicorn 的虚拟机中没有运行任何操作系统,基于系统特性检测虚拟机的方法也是无效的!UnicornDebugger 借助Unicorn 接口,站在上帝视角调试程序,很无敌!

Android是基于Linux开发的,Android Native原生库是ELF文件格式。Unicorn 并不能加载ELF文件,所以我们要自己将ELF文件加载到Unicorn虚拟机的内存中去。 加载ELF 文件是一个很复杂的过程,涉及到ELF文件解析、重定位、符号解析、依赖库加载等。

python 可以使用elftools库解析ELF 文件。

elftools 安装

ELF 文件有两种视图,链接视图和执行视图。elftools 是基于链接视图解析ELF格式的,然而现在有一些ELF文件的section信息是被抹掉的,elftools就无法正常工作,我也没时间重写一个elf loader,就只能凑合用一下elftools。

我已经在前面一篇文章介绍了内存分配方面的东西,加载ELF文件第一步需要将ELF文件映射到内存。如何映射呢?只需要找到类型为PT_LOAD的segment,按照segment的信息映射即可。

代码如下:

ELF 的有一个列表,用于存储初始化函数地址,在动态链接的时候,linker会依次调用init_array中的每一个函数。init_array 中的函数一般用于初始化程序,偶尔也有ELF外壳程序在init_array中添加自解密代码,另外有一些字符串解密也是在init_array中完成的。想要模拟native程序,必然需要调用init_array 中的函数。

init_array 是一个数组, 一般情况下,每一项都是函数入口偏移, 然而也有为0的情况。因为init_array实际解析时机在重定位完成之后, init_array 也可能被重定位。 所以要解析init_array的时候还需要判断重定位表。

我的策略是,当读出init_array中为0的条目的时候就去重定位表中查找重定位值。

32位ELF文件 symbol table entry 的定义如下。

当st_shndx字段的值为SHN_UNDEF时,表明该符号在当前模块没有定义,是一个导入符号,要去其它模块查找。为了便于管理已经加载模块的符号地址,应该用一个map,将name和address映射起来。
其它情况,简单起见,均看成导出符号,将地址重定位后加入到管理符号map。

Unicorn 采用虚拟内存机制,使得虚拟CPU的内存与真实CPU的内存隔离。Unicorn 使用如下API来操作内存:

UC_MEM_ALIGN = 0x1000
Unicorn map的内存基地址和长度都需要对齐到0x1000,对齐函数如下

Memory类用于分配内存

为了对malloc和free等函数提供支持,需要实现heap。 可喜可贺,Afl-Unicorn 开源项目中已经有一个heap例子,可以直接使用。

unicorn heap

native程序可能直接通过syscall调用mmap2 映射内存。libc等库最底层也一定会调用mmap2分配内存。

mmap2 实际并不是一个纯粹的内存管理函数,它还能映射文件到内存,这就涉及到文件系统的支持。我在原作者的基础上进行了修改。

hook libc中的内存管理函数.
既然我们的框架支持加载多个lib库,直接加载libc就可以了,为何还需要hook libc中的这些符号呢?
实际上,目前的模拟框架并不完善,很多系统信息模拟不到位,libc初始化不完善,使用libc的malloc经常会出现异常。所以直接接替为内置的heap 管理器。

我们知道,常见的内存权限有可读可写可执行, 一般可以调用mprotect 函数修改指定内存页面的权限。为了方便,我们将所有内存设置为可读可写可执行。

很多情况下,有一些系统API无法直接调用,就需要手动实现它,比如以下应用场景:
1、在libc没有完全初始化的情况下,直接调用malloc 可能会崩溃, 为了使程序更加稳定,就需要自己实现malloc和free。
2、实现dlopen,就可以使用框架的模块管理器来加载模块,而不用linker。
3、打出dlopen、dlsym等函数的日志,还可以分析native程序运行过程中会调用的API。
4、360加固,在反调试完成后,它会调用dlopen加载libz.so,并调用uncompress函数解压数据。 hook uncompress 就可以拿到解压的数据。
5、目前,许多加固的整体加固会调用art中的api来加载dex文件,如果这些函数被Hook,那么就可以直接拿到dex文件,岂不美哉?
6、JNI Functions 实现,需要Hook 技术支撑。

不幸的是,Unicorn 内部并没有函数的概念,它只是一个单纯的CPU, 没有HOOK_FUNCTION的callback, Hook 函数看上去困难重重。AndroidNativeEmu 为我们提供了一个很好的Hook思路。

AndroidNativeEmu 中的函数级Hook 并不是真正意义上的Hook,它不仅能Hook存在的函数,还能Hook不存在的函数。AndroidNativeEmu 使用这种技术实现了JNI函数Hook、库函数Hook。 Jni函数是不存的,Hook它只是为了能够用Python 实现 Jni Functions。有一些库函数是存在的,Hook只是为了重新实现它。

用 Python 实现 Unicorn 虚拟机内部的函数,首先要解决 Unicorn 虚拟机内部如何与外部交互。AndroidNativeEmu 的实现类似于系统调用,它会为每一个Hook函数实现一个stub函数,stub函数中有一条“陷阱”指令,当虚拟CPU执行这一条”陷阱“指令的时候就会被HOOK_CODE 捕获,然后通过R4寄存器的值确定Python 的处理函数。

stub 函数代码如下:

HOOK_CODE的callback 直接检测PC寄存器指向内存的字节数据是否为"\xE8\xBF"来判断IT AL指令。如果是IT AL指令,则根据R4寄存器的值确定Python 回调的函数。

Native程序中可能会有许多IT AL指令,会误判吗?
HOOK_CODE 会trace每一条指令,这种方式效率岂不是很低?

这两个问题都很好解决,因为HOOK_CODE是有作用范围的,如果开辟一段空间,完全用于存放stub,然后将该callback设置在这个空间范围内,就可以很好的避免了冲突和效率问题!

Keystone 是一款很牛逼的汇编框架,Unicorn的兄弟!

使用pip安装

keystone 使用方法十分简单,不需要额外学习即可理解接下来的代码。write_function函数将python的func函数映射到Unicorn虚拟机,并返回虚拟机中的函数地址, 如果在虚拟机中调用该地址就会被Python捕获并调用func函数。

上一个小结中讲到如何实现stub,那么如何hook 呢?AndroidNativeEmu实现了Symbol Hook。这种HOOK与平时常见的IAT HOOK、GOT Hook 原理是一样的。 调用add_symbol_hook函数,可以将符号和新地址关联起来, 模块加载的时候,查找符号优先从该表中获取地址。 这种实现方式有点bug,比如有一些Native 程序,自身会got hook,那么这种方式可能就会出问题。

大家可能对Python 装饰器的语法不太熟悉,可以参考廖雪峰老师博客:Python 装饰器

简单的讲,装饰器可以自定义修改函数,为目标函数套一层外壳。native_method主要功能是处理参数数据,这样就能很优雅地编写Native 函数,不用再函数中冗杂地调用寄存器读写函数。

这篇文章讲了如何实现 Unicorn 内部的函数级Hook,原理是在模块加载重定位阶段,填充stub函数地址到目标函数的 got表。 stub函数是Unicorn 内部环境与外部环境的一个桥梁,使用小巧的IT AL和R4寄存器实现交互,像极了系统调用。使用Python的装饰器,简化了Python 编写Hook 函数的难度。

系统调用是操作系统给应用程序提供的最底层的基础接口。应用程序读写文件、访问网络等操作都需要操作系统支持。

Unicorn 拦截系统调用只需要添加UC_HOOK_INTR的callback,该callback的参数定义如下:

我们只需要用hook_add 添加一个 UC_HOOK_INTR 的callback 就能够处理中断了。根据intno 中断号分发不同的中断处理函数。

我们将在文件系统章节详细讨论如何实现文件系统。

这些实现都非常的简单,就不过多展开了。

如果想尽可能完美的模拟Android Native程序,那就必须加入虚拟文件系统的支持。虚拟文件系统可以将Unicorn 虚拟机内部访问文件的操作映射到主机。

Hook 拦截文件操作相关的系统调用,转换成对主机的文件操作。

为了安全性,我们要在主机上划分一个用于专门虚拟文件系统的目录。 处理系统调用的时候,将路径转换成虚拟文件系统目录的路径。

需要处理的syscall已经在上一篇文章介绍过了

进一步分析_open_file
这个函数先对路径进行一些简单检验,判断是否为特殊文件,如果不是,则调用translate_path转换安全路径,并调用os.open打开本地文件,最后调用_store_fd转换文件句柄。

调用JNI是工程量最大的一部分,不仅需要实现JNI Functions,还要模拟JNI Env和Java类似的引用管理。
在前面的文章中已经学习了如何在虚拟机中调用主机的Python函数,接下来就学习如何实现JNI Functions里面的所有函数。

可以参考 Jni Functions
Jni Function Table 是一个函数地址表,里面记录了Jni 函数地址。

write_function_table 函数实现了创建一个Function 地址表。
实现如下:

Jni Functions Table 中有 200 多个函数,全部实现的话工作量十分巨大。默认实现如下:

抛出异常可以保证当Native调用一个没有实现的JNI函数时能够及时发现,并实现它。

AndroidNativeEmu 支持使用Python类来代替Jvm中Java类,这是如何实现的呢?

jvm_super 指定父类
jvm_name 定义对应的类名
jvm_fields 定义字段,是一个列表,每一项都是由JavaFieldDef定义的字段,JavaFieldDef(name, signature, is_static, static_value=None)
如果不是static字段,则还需要在init 中创建这个这个私有的成员变量。

metaclass=JavaClassDef 是Python的元类机制,参考廖雪峰老师文章
元类可真的是魔法!它可以动态修改类的定义,比如给类增加成员变量,增加方法等。
JavaClassDef 将class 定义指定的jvm_name 和 jvm_fields保存到成员变量,并添加了find_method、find_method_by_id、find_field等函数,用于实现JNI。

注册方法

注册字段

查找字段的函数
支持类继承,Java是单继承,查找的时候先从基类开始递归查找。

metaclass 修饰了定义的java类,隐藏了类解析背后的细节,使得添加一个java类很方便。java类定义后,还需要添加模拟器的class管理。

保存的是类的定义而不是实例。

目前实现两种类型的引用,一种jobject和jclass。jobejct是用来引用实例对象,jclass用来引用类。
Python 实现java的类,如果返回一个String,那么就会自动创建一个String引用,然后把引用id返回给Native 函数。Native 函数再调用GetStringUtfChars获取引用的字符串。 GetStringUtfChars 的实现如下。

引用还分为局部引用和全局引用。局部引用的生命周期是进入native 函数到native 函数返回。 全局引用则作用于模拟器整个生命周期。

我们目前已经实现了Java 调用native 的过程,native再回调java是否可以实现呢?实际上,在class定义的时候就解析了所有带@java_method_def 装饰器的成员函数。native通过JNI调用java函数,我们可以模拟对应的JNI函数,使其在所有加载的类中查找是否有对应签名的函数,如果有则直接调用。

@java_method_def 装饰器不仅描述了函数的签名,还转换函数的参数数据和返回值信息。

这个修饰器的定义如下:

Java 调用 Native 的时候要把非数字类型转换为对象引用。
Native 调用 Java 或者 返回的时候要把引用转换成对象,转换方法实现如下:

附录:
Unicorn 优秀项目:http://www.unicorn-engine.org/showcase/

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

[招生]系统0day安全班,企业级设备固件漏洞挖掘,Linux平台漏洞挖掘!

最后于 2019-8-15 01:40 被无名侠编辑 ,原因:
收藏
免费 114
支持
分享
打赏 + 82.00雪花
打赏次数 9 雪花 + 82.00
 
赞赏  kanxue   +5.00 2019/09/05 精品文章~
赞赏  backahasten   +5.00 2019/09/04 又看了一遍,感觉真不错,再加5块(手动捂脸)
赞赏  backahasten   +10.00 2019/09/04 好文章,正在学unicorn,很强大
赞赏  orz1ruo   +5.00 2019/08/19 感谢分享~
赞赏  NearJMP   +2.00 2019/08/16
赞赏  supperlitt   +5.00 2019/08/15
赞赏  JoenChen   +20.00 2019/08/15 少有的好文章!!!
赞赏  capser   +10.00 2019/08/15 感谢分享~
赞赏  Imyang   +20.00 2019/08/15 精品文章~
最新回复 (98)
雪    币: 1144
活跃值: (1344)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
真大佬
2019-8-15 02:47
0
雪    币: 729
活跃值: (1321)
能力值: ( LV9,RANK:160 )
在线值:
发帖
回帖
粉丝
3
大佬,我是来喊666的
2019-8-15 08:36
0
雪    币: 193
活跃值: (1043)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
谢谢楼主,刚发现《Unicorn 调用SO之系统调用》 的链接有问题和《Unicorn 调用SO之文件系统》的链接重复了。
2019-8-15 08:41
0
雪    币: 76
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
666
2019-8-15 09:01
0
雪    币: 324
活跃值: (419)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
6
点赞
2019-8-15 09:02
0
雪    币: 3270
活跃值: (1941)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
认真!
2019-8-15 09:37
0
雪    币: 1927
活跃值: (49)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
8
感谢大哥总结
2019-8-15 09:40
0
雪    币: 298
活跃值: (113)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
9
999
2019-8-15 09:51
0
雪    币: 634
活跃值: (1503)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
10
大佬需要腿部挂件不?
2019-8-15 09:59
0
雪    币: 12
活跃值: (1180)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
6
2019-8-15 10:08
0
雪    币: 459
活跃值: (166)
能力值: ( LV9,RANK:165 )
在线值:
发帖
回帖
粉丝
12
tql
2019-8-15 10:36
0
雪    币: 1577
活跃值: (744)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
13
很有帮助,感谢无名侠大佬分享
2019-8-15 10:54
0
雪    币: 105
活跃值: (614)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
再加上QBDI,方案会很完美,,,为大佬点赞
2019-8-15 12:03
0
雪    币: 6931
活跃值: (9159)
能力值: ( LV17,RANK:797 )
在线值:
发帖
回帖
粉丝
15
asuralove 谢谢楼主,刚发现《Unicorn 调用SO之系统调用》 的链接有问题和《Unicorn 调用SO之文件系统》的链接重复了。
谢谢提醒,已经修正
2019-8-15 13:19
0
雪    币: 402
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
感谢无名侠大佬分享
2019-8-15 14:00
0
雪    币: 574
活跃值: (405)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
超硬核文章,感谢分享,慢慢消化学习
2019-8-15 14:19
0
雪    币: 4192
活跃值: (3612)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
18
神仙....
2019-8-15 15:49
0
雪    币: 6956
活跃值: (1522)
能力值: ( LV11,RANK:180 )
在线值:
发帖
回帖
粉丝
19
少有的好文章,写的很详细,道高一尺魔高一丈!!! 以后怼vmp可以用这个。。。
2019-8-15 17:05
0
雪    币: 977
活跃值: (435)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
20
致敬
2019-8-15 17:32
0
雪    币: 9771
活跃值: (2596)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
虽然看不太懂,但感觉很牛X的样子!
2019-8-15 22:40
0
雪    币: 346
活跃值: (50)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
22
是很好用的   ! 魔改后 可以不用od 能解决很多问题
2019-8-16 09:45
0
雪    币: 6881
活跃值: (3108)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
整理的非常好
2019-8-16 10:53
0
雪    币: 3134
活跃值: (1227)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
24
膜。正好最近想研究这个玩意儿
2019-8-16 18:37
0
雪    币: 2907
活跃值: (1301)
能力值: ( LV12,RANK:215 )
在线值:
发帖
回帖
粉丝
25
2019-8-16 21:57
0
游客
登录 | 注册 方可回帖
返回
//