- AndroidSec
- 1. Dalvik下DexClassLoader动态加载关键函数链(基于Android4.4)
- 2. Art下DexClassLoader动态加载关键函数链(基于Android8.0)
- 3. Art下InMemoryDexClassLoader动态加载关键函数链(基于Android8.0)
- 4. Dalvik下RegisterNatives动态注册关键函数链(基于Android4.4)
- 4. Art下RegisterNatives动态注册关键函数链(基于Android8.1)
- 2020-07-08 新增dex2apk.py
- 2020-09-19 将自己之前改的的DumpApkInfo工具引入
- 2020-10-09 增加unicorn trace arm64的基本代码
- 2020-10-10 增加一个byte数组转hexString的dex
- 2020-10-31 增加hook_init_array代码
- 2020-11-02 增加hook_constructors代码
- 2021-03-31 增加主动获取context方法
- 2021-04-06 增加hook RegisterNative函数的脚本
- 2021-04-14 增加在native层遍历HashMap代码
- 2021-04-17 get到一个新姿势:更改进程名
- 2021-04-24 又找到一个anti-frida的方式
- 2021-05-23 frida hook enum class 的方式
2020-07-08 新增dex2apk.py
一个用于将脱壳下来的众多dex重新组装成apk的脚本,免去Android安全测试人员在逆向过程中不停grep
的操作
将重新组合的apk
拖入jadx
和jeb
,展示结果如下:
DumpApkInfo可以用来dump加壳信息、签名信息、APK包名等等功能,具体参见子模块readme
2020-10-09 增加unicorn trace arm64的基本代码
大概效果如下
基于unicorn和capstone来trace函数执行流程并记录寄存器信息,具体自己看代码吧,只是一个demo
2020-10-10 增加一个byte数组转hexString的dex
手动封装了okio.ByteString
的函数,并打包成dex,避免frida在hook APP时无法使用ByteString
的转hex方法,frida使用方式
首先将dex push进/data/local/tmp/
目录下,然后chmod
给予dex
执行权限,frida调用时
Java.perform(function (){
var okio = Java.openClassFile("/data/local/tmp/okio.dex")
okio.load()
var ByteString = Java.use("com.Simp1er.okio.ByteString")
ByteString.$new(key_bytes).hex()// 其实接下来就是ByteString的函数调用了
})
参考: ByteString.java
2020-10-31 增加hook_init_array代码
通过hooklinker
的call_array
函数,hook得到init_array
地址,在Android8.1 64位程序和32为程序上都测试成功,其他的请自己测试更改。
2020-11-02 增加hook_constructors代码
通过hooklinker
的async_safe_format_log
函数,hook得到init_array
以及.init_proc
地址,在Android8.1 64位程序和32为程序上都测试成功,其他的请自己测试更改。
64位效果如下:
32位效果如下:
2021-03-31 增加主动获取context方法
利用ActivityThread
的单例模式获取到应用的上下文Context
用于后续利用
2021-04-06 增加hook RegisterNative函数的脚本
由于jni函数无论是动态注册或者静态注册的函数都会在加载过程中都会调用RegisterNative
函数注册JNI
函数最终函数地址,因此可以通过hook
RegisterNative
函数获取JNI
函数最终地址以及函数实现所在模块,最终效果如下:
注意:仅在Android 8.1.0_r1
下测试成功,其他版本可能失效
2021-04-14 增加在native层遍历HashMap
代码
在native
层遍历HashMap
中key
和value
类型都为String
的脚本
传入一个JNIEnv
和HashMap
的对象即可
最终效果如下
xxx => azU7Bc002xAAJ9QEYW1mGJrO8f0Ed9QH0FqzYdOlL8/Md/QHpENnwiLJhCBZB5mhQtIXdU8Pnw43BRB7hD6QY3VDdZfUF9QH1BfUB9
bbbb => HHnB_FCRa80QdwWegx+jn98jVfguVXqGwR3kh9ROtBHavXaYZV+qLX+lUnG4LVQfyqsJ/zFo0JH2gRVVSi98GPkuj9GWADR18oS+VyJ2XhLUQYev/wQDCMFWSAYaGABE2SOBT
cccc => JAE5zHBA7W55NB1VcTLaT8wI/An8Ae8A+wn5Gvsa7wj6CPQN/Qv6CPg=
dddd => hwIABwRLPF9s5QJ40ATaaW1cNymwhLCe
android.os.Process
中的setArgV0()
函数可用于改变APP
的进程名。感谢卓桐大佬!!Android修改进程名
注意:这里由于Java.lang.Process
类是默认导入的包,因此在使用时需要单独import
导入android.os.Process
类。
import android.os.Process;
try {
// https://bbs.pediy.com/thread-253676.htm
Method setArgV0 = Process.class.getDeclaredMethod("setArgV0", String.class);
setArgV0.setAccessible(true);
setArgV0.invoke(null,"com.tencent.mm");
} catch (Throwable e) {
// java.lang.NoSuchMethodException: setArgV0 [class java.lang.String]
e.printStackTrace();
Log.i("nicai", "onCreate: ");
}
这里测试APP
的包名为com.test.changeprocessname
但是当使用ps -e
命令查看进程会发现找不到这个进程,最终效果如下
frida在注入进程后如果脚本中使用registerClass
这个API
,在内存空间中会出现frida
为前缀的vdex/odex
,即使frida
退出后,本次进程的内存空间仍旧还存在这样的痕迹。
展示如下图
anti-anti
的方式是在调用registerClass
这个API
之前执行以下语句
Java.classFactory.tempFileNaming.prefix = "onetwothree"
..
Java.registerClass(...)
自定义后效果
当hook
Enum
类时,this
指针就是Enum
类中具体成员的值。
比如我这里写了一个枚举类,代码如下
public enum enumClazz {
OAID("QAID"),TOKEN("TOKEN"), VIP("1");
private String value;
enumClazz(String value){
this.value = value;
}
public String getValue(){
return this.value;
}
public void setValue(String value){
this.value = value;
Log.e("enum", "className: " + this );
}
}
在调用时使用方法像这样
enumClazz.OAID.setValue("OAID_value");
enumClazz.TOKEN.setValue("TOKEN_value");
enumClazz.VIP.setValue("VIP_value");
此时调用setValue(String)
函数打印出来的日志如下
2021-05-23 16:24:31.258 26207-26207/com.simp1er.enumdemo E/enum: className: OAID
2021-05-23 16:24:31.262 26207-26207/com.simp1er.enumdemo E/enum: className: TOKEN
2021-05-23 16:24:31.265 26207-26207/com.simp1er.enumdemo E/enum: className: VIP
可以发现其实对应的this
指针就是对应调用的枚举成员。
最终使用frida
进行hook
时,主要代码如下
function hook(){
Java.perform(function(){
var enumClazz = Java.use('com.simp1er.enumdemo.enumClazz')
enumClazz.setValue.implementation = function(){
var value = arguments[0];
console.log('class =>',this,", value =>",value) // this即代表enum类的对象名称。
// console.log('class =>',this.getString())
return this.setValue(value)
}
});
}
效果如下
class => OAID , value => OAID_value
class => TOKEN , value => TOKEN_value
class => VIP , value => VIP_value
但是参考中的this.getString()
方法并没有成功。
参考:https://bbs.pediy.com/thread-258772.htm#enum%E6%B5%8B%E8%AF%95