Skip to content

Commit c30b292

Browse files
committed
Unidbg
1 parent f79e2ea commit c30b292

File tree

6 files changed

+187
-47
lines changed

6 files changed

+187
-47
lines changed

Tool/Unidbg/A01/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public class oasis extends AbstractJni{
6969
### 0x02. 执行目标函数--参数构造
7070

7171
- 字节数组需要裹上unidbg的包装类,并加到本地变量里,两件事缺一不可。
72-
- 除了基本类型,比如int,long等,其他的对象类型一律要手动 `addLocalObject`
72+
- 除了基本类型(byte、char、short、int、long、float、double、 boolean),其他的对象类型一律要手动 `addLocalObject`
7373
- vm.getObject(number.intValue()).getValue().toString() 解释:在DalvikVM中有Map存储了jni交互的对象,key是该对象的hash,value是该对象。这个intValue就是这个对象的hash,通过vm.getObject方法,来取出这个hash对应的Object。
7474

7575
#### 字节数组以及布尔值

Tool/Unidbg/A02/README.md

Lines changed: 4 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,8 @@
2020
- [traceWrite](#traceWrite)
2121
* [0x05. Unidbg使用反射补Java的类](#0x05-Unidbg使用反射补Java的类)
2222
* [0x06. 打开系统调用日志](#0x06-打开系统调用日志)
23-
* [0x07. 加载Unidbg中不支持的SO](#0x07-加载Unidbg中不支持的SO)
24-
* [0x08. 使用Unidbg打印函数参数5之后的值](#0x08-使用Unidbg打印函数参数5之后的值)
25-
* [0x09. 使用Unidbg打印jobject](#0x09-使用Unidbg打印jobject)
23+
* [0x07. 使用Unidbg打印函数参数5之后的值](#0x07-使用Unidbg打印函数参数5之后的值)
24+
* [0x08. 使用Unidbg打印jobject](#0x08-使用Unidbg打印jobject)
2625

2726
<!-- /code_chunk_output -->
2827

@@ -586,48 +585,7 @@ public static void main(String[] args){
586585

587586
src/test/resources/log4j.properties中**INFO**全配置成**DEBUG**
588587

589-
### 0x07. 加载Unidbg中不支持的SO
590-
591-
- [原文传送](https://blog.csdn.net/qq_38851536/article/details/118024298)
592-
593-
- 查看Unidbg 支持哪些so: `unidbg-android/src/main/resources/android/sdk23/lib`
594-
595-
> 为什么Unidbg不内置支持所有系统SO的加载?
596-
>
597-
> 1. 大部分SO中主要的依赖项,就是Unidbg已经支持的这些,即已经够用了。
598-
> 2.Android系统中全部SO都成功加载进Unidbg虚拟内存中,既是很大的工作量,又会占用过多内存。
599-
> 3. 另一个原因是,比如libandroid.so,其依赖SO实在太多了,想顺利加载整个SO确确实实是个苦差事。
600-
601-
- 如果SO的依赖项中有Unidbg不支持的系统SO,怎么办?
602-
603-
> 首先Unifbg会给予提示:比如libnative-lib.so load dependency libandroid.so failed
604-
>
605-
> 其次,尽管SO加载了Unidbg不支持的SO,但有可能我们的目标函数并没有使用到这个系统SO,这种情况下就不用理会,当作不存在就行。
606-
607-
- 但如果目标函数使用到了这个系统SO,那就麻烦了,我们就得直面这个问题,一般有两种处理办法。
608-
609-
1. Patch/Hook 这个不支持的SO所使用的函数
610-
611-
2. 使用Unidbg VirtualModule
612-
613-
> VirtualModuleUnidbg为此种情况所提供的官方解决方案,并在代码中提供了两个示例,路径:unidbg-android/src/main/java/com/github/unidbg/virtualmodule/android
614-
615-
比如libandroid.so可以使用`AndroidModule`,只实现了libandroid中这几个常用的导出函数。
616-
617-
```java
618-
vm = emulator.createDalvikVM(new File("unidbg-android/src/test/java/com/lession8/demo2.apk"));
619-
// 注册libandroid.so虚拟模块
620-
new AndroidModule(emulator, vm).register(memory);
621-
622-
DalvikModule dm = vm.loadLibrary(new File("unidbg-android/src/test/java/com/lession8/readassets.so"), true);
623-
module = dm.getModule();
624-
```
625-
626-
需要注意,一定要在样本SO加载前加载它,道理也很简单,系统SO肯定比用户SO加载的早。VirtualModule并不是一种真正意义上的加载SO,它本质上也是Hook,只不过实现了SO中少数几个函数罢了。
627-
628-
需要注意的是,VirtualModule并不是一种真正意义上的加载SO,它本质上也是Hook,只不过实现了SO中少数几个函数罢了。
629-
630-
### 0x08. 使用Unidbg打印函数参数5之后的值
588+
### 0x07. 使用Unidbg打印函数参数5之后的值
631589

632590
[常见函数调用约定](https://bbs.pediy.com/thread-224583.htm)
633591

@@ -660,7 +618,7 @@ size: 112
660618
^-----------------------------------------------------------------------------^
661619
```
662620
663-
### 0x09. 使用Unidbg打印jobject
621+
### 0x08. 使用Unidbg打印jobject
664622
665623
[原文传送](https://blog.csdn.net/qq_38851536/article/details/118122592)
666624

Tool/Unidbg/A03/README.md

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,18 @@
44
* [补环境](#奇技淫巧)
55
* [0x01. JNI以及相关API](#0x01-JNI以及相关API)
66
- [构造最基本Context实例](#构造最基本Context实例)
7+
- [resolveClass解释](#resolveClass解释)
78
- [Context实例的getClass方法](#Context实例的getClass方法)
89
- [返回PID](#返回PID)
910
- [使用java的api返回一个对象](#使用java的api返回一个对象)
1011
- [VarArg的使用](#VarArg的使用)
1112
- [VaList的使用](#VaList的使用)
13+
- [newObject](#newObject)
1214
* [0x02. 文件访问](#0x02-文件访问)
1315
* [实体路径](#实体路径)
1416
* [代码方式](#代码方式)
17+
* [0x03. 加载Unidbg中不支持的SO](#0x03-加载Unidbg中不支持的SO)
18+
*
1519

1620
<!-- /code_chunk_output -->
1721

@@ -54,6 +58,106 @@ public DvmObject<?> callObjectMethodV(BaseVM vm, DvmObject<?> dvmObject, String
5458
return super.callObjectMethodV(vm, dvmObject, signature, vaList);
5559
}
5660
```
61+
#### resolveClass解释
62+
63+
[原文链接](https://t.zsxq.com/RBujayn)
64+
65+
```java
66+
@Override
67+
public DvmObject<?> callObjectMethodV(BaseVM vm, DvmObject<?> dvmObject, String signature, VaList vaList) {
68+
switch (signature){ case "android/app/ActivityThread->getApplication()Landroid/app/Application;":{
69+
return vm.resolveClass("android/app/Application", vm.resolveClass("android/content/ContextWrapper",
70+
vm.resolveClass("android/content/Context"))).newObject(signature);
71+
}
72+
}
73+
return super.callObjectMethodV(vm, dvmObject, signature, vaList);
74+
}
75+
```
76+
77+
- callObjectMethodV或者之前的getStaticObjectField,返回的都是jobject,Unidbg中如何构造一个Jobject?
78+
79+
jString在Unidbg中被封装成了StringObject,除此之外,下图中标准和的jobject也都封装好了。
80+
81+
Unidbg源码如下:`unidbg-android/src/main/java/com/github/unidbg/linux/android/dvm/array/`
82+
83+
<img src="pic/02.png" style="zoom:50%;" />
84+
85+
- 那么Unidbg中没有的Jobject该怎么处理呢,比如返回**ctrip.android.security.a**的实例?
86+
87+
```java
88+
return vm.resolveClass("ctrip/android/security/a").newObject(null);
89+
```
90+
91+
类名全路径中“.”替换成”/“,传入resolveClass,即创建了目标类,newObject即创建实例,newObject 的参数为null即可,这样就创建了一个目标类的实例jobject。除此之外,我们一般还会将signature签名 填入newObject,用于区分jobject,方便后续分别处理。
92+
93+
```java
94+
return vm.resolveClass("ctrip/android/security/a").newObject(signature);
95+
```
96+
97+
Application在Unidbg中并没有封装,所以按照上面的说法,Application对象应该这么表示
98+
99+
```java
100+
return vm.resolveClass("android/app/Application").newObject(signature);
101+
```
102+
103+
拆开来看
104+
105+
```java
106+
DvmClass context = vm.resolveClass("android/content/Context");
107+
DvmClass ContextWrapper = vm.resolveClass("android/content/ContextWrapper", context);
108+
DvmClass Application = vm.resolveClass("android/app/Application",ContextWrapper);
109+
return Application.newObject(signature);
110+
```
111+
112+
resolveClass其实是个可变参数方法,如果有第二个参数,那它代表我们创建的类其父类。 所以实际上这里是明确了继承关系。
113+
114+
<img src="pic/03.png">
115+
116+
- 为什么我们要在Unidbg中表明这个继承关系? 假如不填写继承关系,查看报错:
117+
118+
```java
119+
switch (signature) {
120+
case "android/app/ActivityThread->getApplication()Landroid/app/Application;": {
121+
DvmClass Application = vm.resolveClass("android/app/Application");
122+
return Application.newObject(signature);
123+
}
124+
```
125+
126+
<img src="pic/04.png">
127+
128+
查看526行代码:
129+
130+
```java
131+
DvmClass dvmClass = dvmObject == null ? null : dvmObject.getObjectType();
132+
DvmMethod dvmMethod = dvmClass == null ? null : dvmClass.getMethod(jmethodID.toIntPeer());
133+
if (dvmMethod == null) {
134+
throw new BackendException("dvmObject=" + dvmObject + ", dvmClass=" + dvmClass + ", jmethodID=" + jmethodID);
135+
}
136+
```
137+
138+
说明dvmMethod没有找到,方法找不到,methodID肯定有问题,我们发现了一个问题,对象是Application实例,但MethodID是从Context类找来的,为什么能这样做 呢?ApplicationContext的子孙类,getContentResolver是Context中的抽象方法,JAVA允许这么玩儿。Unidbg处理为什么出现问题了呢?
139+
140+
首先,Unidbg中执行GetMethodID方法时建立了一个对应关系,Context的methodMap中存储了这个对应关系,而CallObjectMethodV时,因为对象是Application实例,所以它去Application的methodMap里乱找一通,发现啥都没有,自然就报错了。但从Unidbg的代码逻辑中我们发现,当找不到方法时,它会去父类以及超类的methodMap中去寻找,当我们写如下代码时:
141+
142+
```java
143+
DvmClass context = vm.resolveClass("android/content/Context");
144+
DvmClass ContextWrapper = vm.resolveClass("android/content/ContextWrapper", context);
145+
DvmClass Application = vm.resolveClass("android/app/Application",ContextWrapper);
146+
return Application.newObject(signature);
147+
```
148+
149+
Unidbg先在Application自己的methodMap里找,找不到的话去ContextWrapper的methodMap里 找,最后在Context的methodMap里找,除此之外,它还会在接口类里找(resolveClass的第三个参数 开始代表所实现的接口类)。因此,AbstractJNI中给Application补齐了继承链,就是担心ID在超类的 methodMap里。
150+
151+
在我们自己分析样本时,可以不这么复杂,每次需要resolveClass+newObject声明jObject时候,就别管 什么继承,就当它没爹,但如果报错就直接检索methodID,看是哪个超类生成的ID,别管它在”**真实代码逻辑**“中是太爷爷、爷爷还是爸爸, 直接安排它做爸爸。这里直接省略了`ContextWrapper`
152+
153+
```java
154+
case "android/app/ActivityThread->getApplication()Landroid/app/Application;": {
155+
DvmClass context = vm.resolveClass("android/content/Context");
156+
DvmClass Application = vm.resolveClass("android/app/Application", context);
157+
return Application.newObject(signature);
158+
}
159+
```
160+
57161
#### Context实例的getClass方法
58162

59163
```java
@@ -167,6 +271,42 @@ public DvmObject<?> callStaticObjectMethodV(BaseVM vm, DvmClass dvmClass, String
167271
}
168272
```
169273

274+
#### newObject
275+
276+
```java
277+
@Override
278+
public DvmObject<?> newObject(BaseVM vm, DvmClass dvmClass, String signature,
279+
VarArg varArg) {
280+
switch (signature){
281+
case "java/lang/Throwable-><init>()V":{
282+
return vm.resolveClass("java/lang/Throwable").newObject(new Throwable());
283+
}
284+
case "java/io/ByteArrayOutputStream-><init>()V":{
285+
return vm.resolveClass("java/io/ByteArrayOutputStream").newObject(new ByteArrayOutputStream());
286+
} }
287+
return super.newObject(vm, dvmClass, signature, varArg);
288+
}
289+
```
290+
291+
另一种方式:
292+
293+
```java
294+
@Override
295+
public DvmObject<?> newObject(BaseVM vm, DvmClass dvmClass, String signature,
296+
VarArg varArg) {
297+
switch (signature){
298+
case "java/lang/Throwable-><init>()V":{
299+
return dvmClass.newObject(new Throwable());
300+
}
301+
case "java/io/ByteArrayOutputStream-><init>()V":{
302+
return dvmClass.newObject(new ByteArrayOutputStream());
303+
} }
304+
return super.newObject(vm, dvmClass, signature, varArg);
305+
}
306+
```
307+
308+
309+
170310
### 0x02. 文件访问
171311

172312
#### 实体路径
@@ -210,5 +350,47 @@ public DvmObject<?> callStaticObjectMethodV(BaseVM vm, DvmClass dvmClass, String
210350
}
211351
```
212352

353+
### 0x03. 加载Unidbg中不支持的SO
354+
355+
- [CSDN-样本八](https://blog.csdn.net/qq_38851536/article/details/118024298) [知识星球-样本二](https://t.zsxq.com/RBujayn)
356+
357+
- 查看Unidbg 支持哪些so: `unidbg-android/src/main/resources/android/sdk23/lib`
358+
359+
> 为什么Unidbg不内置支持所有系统SO的加载?
360+
>
361+
> 1. 大部分SO中主要的依赖项,就是Unidbg已经支持的这些,即已经够用了。
362+
> 2.Android系统中全部SO都成功加载进Unidbg虚拟内存中,既是很大的工作量,又会占用过多内存。
363+
> 3. 另一个原因是,比如libandroid.so,其依赖SO实在太多了,想顺利加载整个SO确确实实是个苦差事。
364+
365+
- 如果SO的依赖项中有Unidbg不支持的系统SO,怎么办?
366+
367+
> 首先Unidbg会给予提示:比如libnative-lib.so load dependency libandroid.so failed
368+
>
369+
> 然后去网上搜下是不是系统库,如果是APK本身自带的SO,手动加载一下即可,并默认执行其init函数,并调用JNIOnLoad
370+
> 注意:依赖项必须先加载
371+
>
372+
> 其次,尽管SO加载了Unidbg不支持的SO,但有可能我们的目标函数并没有使用到这个系统SO,这种情况下就不用理会,当作不存在就行。
373+
374+
- 但如果目标函数使用到了这个系统SO,那就麻烦了,我们就得直面这个问题,一般有两种处理办法。
375+
376+
1. Patch/Hook 这个不支持的SO所使用的函数
377+
378+
2. 使用Unidbg VirtualModule
379+
380+
> VirtualModuleUnidbg为此种情况所提供的官方解决方案,并在代码中提供了两个示例,路径:unidbg-android/src/main/java/com/github/unidbg/virtualmodule/android
381+
382+
比如libandroid.so可以使用`AndroidModule`,只实现了libandroid中这几个常用的导出函数。
383+
384+
```java
385+
vm = emulator.createDalvikVM(new File("unidbg-android/src/test/java/com/lession8/demo2.apk"));
386+
// 注册libandroid.so虚拟模块
387+
new AndroidModule(emulator, vm).register(memory);
388+
389+
DalvikModule dm = vm.loadLibrary(new File("unidbg-android/src/test/java/com/lession8/readassets.so"), true);
390+
module = dm.getModule();
391+
```
392+
393+
需要注意,一定要在样本SO加载前加载它,道理也很简单,系统SO肯定比用户SO加载的早。VirtualModule并不是一种真正意义上的加载SO,它本质上也是Hook,只不过实现了SO中少数几个函数罢了。
213394

395+
需要注意的是,VirtualModule并不是一种真正意义上的加载SO,它本质上也是Hook,只不过实现了SO中少数几个函数罢了。
214396

Tool/Unidbg/A03/pic/02.png

61.6 KB
Loading

Tool/Unidbg/A03/pic/03.png

26.4 KB
Loading

Tool/Unidbg/A03/pic/04.png

105 KB
Loading

0 commit comments

Comments
 (0)