一、工具
idea
unidbg
记得电脑先安装好JDK,下载好idea后打开unidbg文件夹即可自动安装依赖。
如果需要永久激活idea的请私我。目前支持2023.1版本。
1)测试项目是否正常运行
打开标记出的项目文件直接运行即可,然后正常打印出结果代表项目可以正常运行。
二、文件目录截图
这个项目需要自己去创建的。
com.dta.lesson2.MainActivity
apk和so文件也会发到下面(用的是r0ysue-大数据安全入门课程里面的课件)。
三、代码部分
注释已经非常详细写了
最终打印的会是两个调用方法输出的md5加密字符串。
package com.dta.lesson2;
import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.LibraryResolver;
import com.github.unidbg.arm.backend.DynarmicFactory;
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.DalvikModule;
import com.github.unidbg.linux.android.dvm.DvmObject;
import com.github.unidbg.linux.android.dvm.StringObject;
import com.github.unidbg.linux.android.dvm.VM;
import com.github.unidbg.linux.android.dvm.jni.ProxyDvmObject;
import com.github.unidbg.memory.Memory;
import com.github.unidbg.Module;
import com.sun.jna.Pointer;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class MainActivity {
private final AndroidEmulator emulator;
private final VM vm;
private final Module module;
private MainActivity() {
// 创建模拟器实例,要模拟32位或者64位,在这里区分
emulator = AndroidEmulatorBuilder
// 指定32位CPU
.for32Bit()
// 添加后端, 推荐使用Dynarmic,运行速度快,但是不支持某些新特性
.addBackendFactory(new DynarmicFactory(true))
// 指定进程名,推荐以安卓包名做进程名
// .setProcessName("")
.build();
// 模拟器的内存操作接口
Memory memory = emulator.getMemory();
// 设置SDK版本
LibraryResolver resolver = new AndroidResolver(23);
// 设置系统类库解析
memory.setLibraryResolver(resolver);
// 创建Android虚拟机
vm = emulator.createDalvikVM(new File("D:\\unidbg-master\\unidbg-android\\src\\test\\java\\com\\dta\\lesson2\\app-debug.apk"));
// 设置是否打印Jni调用细节
vm.setVerbose(false);
// 加载libnative-lib.so到unicorn虚拟内存,加载成功以后会默认调用init_array等函数
DalvikModule dm = vm.loadLibrary(new File("D:\\unidbg-master\\unidbg-android\\src\\test\\java\\com\\dta\\lesson2\\libnative-lib.so"), false);
//获取本SO模块的句柄,后续需要用它
module = dm.getModule();
// 调用JNI OnLoad
dm.callJNI_OnLoad(emulator);
}
public void md5(){
/* 符号调用
创建项目要和包名一致, 因为unidbg会根据this的包名进行匹配JNI方法,所以this所属类的包名应该与目标函数相同(com.dta.lesson2)
例如这里this的包名是com.dta.lesson2,那么就相当于调用Java_com_dta_lesson2_md5(JNIEnv *env, jobject thiz, jstring str);
*/
DvmObject<?> obj = ProxyDvmObject.createObject(vm, this);
String data = "dta";
DvmObject<?> result = obj.callJniMethodObject(emulator,"md5(Ljava/lang/String;)Ljava/lang/String;", data);
String value = (String) result.getValue();
System.out.println("(symbol)md5 ====> result: " + value);
}
private void call_address() {
/* 地址调用(虽然复杂,但是最好用)
这部分基本上固定写法,只需要改地址偏移和参数类型就行
在so文件里面方法的一般是Java_com_dta_lesson2_md5(JNIEnv *env, jobject thiz, jstring str);
所以下面要创建对应的参数, 基本为固定写法
*/
Pointer jniEnv = vm.getJNIEnv();
DvmObject<?> obj = ProxyDvmObject.createObject(vm, this);
// 如果要传入vm.addLocalObject,String只能这么写
StringObject data = new StringObject(vm, "dta");
List<Object> args = new ArrayList<>();
args.add(jniEnv);
// 除了指针类型和Number类型都需要添加到vm(vm.addLocalObject)才能够在vm中操作该对象
args.add(vm.addLocalObject(obj));
args.add(vm.addLocalObject(data));
// 0x8E81是地址偏移(加过1的)
Number numbers = module.callFunction(emulator, 0x8E81, args.toArray());
DvmObject<?> object = vm.getObject(numbers.intValue());
String value = (String) object.getValue();
System.out.println("(addr)md5 ====> result: " + value);
}
public static void main(String[] args) {
MainActivity mainActivity = new MainActivity();
mainActivity.md5();
mainActivity.call_address();
}
}
四、文件
五、借鉴
r0ysue-大数据安全入门课程