46.安卓逆向2-补环境-使用unidbg(使用apk文件补环境)
免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动!
内容参考于:图灵Python学院
工具下载:
链接:https://pan.baidu.com/s/1bb8NhJc9eTuLzQr39lF55Q?pwd=zy89
提取码:zy89
复制这段内容后打开百度网盘手机App,操作更方便哦
上一个内容:45.安卓逆向2-补环境-使用unidbg(断点)
如下图,so文件中调用了java里Context类中的getPackageName方法
上一个内容写了手动补环境,这次写使用apk补环境,如下图创建安卓虚拟机的时候给他传一个apk文件,也就是受害者app的安装包
然后再运行,如下图它的缺少的方法就变成别的了
上图的错误是因为下图红框位置传了一个Java的Map类型,这个还是需要我们手动补的,但Context类中的getPackageName方法unidbg已经通过apk给我们补好了,下一节补Map这种类型
完整代码
package com.mmmm.wph;
import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.Emulator;
import com.github.unidbg.Module;
import com.github.unidbg.Symbol;
import com.github.unidbg.arm.context.RegisterContext;
import com.github.unidbg.debugger.BreakPointCallback;
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.*;
import com.github.unidbg.linux.android.dvm.jni.ProxyDvmObject;
import com.github.unidbg.memory.Memory;
import com.github.unidbg.pointer.UnidbgPointer;
import com.github.unidbg.utils.Inspector;
import com.sun.jna.Pointer;
import java.io.File;
import java.util.*;public class WphSign extends AbstractJni {private final AndroidEmulator emulator;private final VM vm;private final Module module;// 初始化的结构 模拟器搭建好public WphSign(){// 创建模拟器实例,要模拟32位或者64位,在这里区分emulator = AndroidEmulatorBuilder.for32Bit().setProcessName("com.xx.xx").build();// 模拟器的内存操作接口final Memory memory = emulator.getMemory();// 设置系统类库解析memory.setLibraryResolver(new AndroidResolver(23));// 创建Android虚拟机vm = emulator.createDalvikVM(new File("utils/xxx/xxx.apk"));// 加载SO文件DalvikModule dm = vm.loadLibrary(new File("utils/xxx/libkeyinfo.so"), false);// 手动执行JNI_OnLoad函数 动态注册需要 静态不用dm.callJNI_OnLoad(emulator);vm.setJni(this);// 基于module可以访问so中的成员module = dm.getModule();}/*** 获取签名信息的方法* 功能:调用指定Java类的静态方法,返回一个签名字符串*/String getSign() {// 1. 查找并加载目标Java类:com/vip/vcsp/KeyInfo// vm:可以理解为"虚拟机环境",用于模拟Android应用运行的环境// DvmClass:表示虚拟机中的一个类(类似Java中的Class对象,但用于虚拟机环境)DvmClass dvmClass = vm.resolveClass("com/xxx/xxx/KeyInfo");// 2. 定义要调用的方法签名// 格式:方法名(参数类型列表)返回值类型,用于精确指定要调用的方法String method = "gsNav(Landroid/content/Context;Ljava/util/Map;Ljava/lang/String;Z)Ljava/lang/String;";// 3. 准备方法需要的参数:创建一个有序键值对集合(TreeMap)Map<String, String> params = new TreeMap<>();// 4. 为方法参数创建"虚拟机可识别的对象"// DvmObject:【重点】这是虚拟机框架中定义的"对象包装类",不是Java标准类型// 作用:把普通Java对象(如Context、Map、字符串等)包装成虚拟机环境能识别的格式// 相当于"翻译官",让外部代码的对象能被虚拟机内部的方法识别和使用// 4.1 包装第一个参数:Context对象(Android中的环境上下文)// 先找到Context类,再创建其实例,最后用DvmObject包装DvmObject<?> a1 = vm.resolveClass("android/content/Context").newObject(null);// 4.2 包装第二个参数:上面创建的params集合(Map类型)// 通过ProxyDvmObject工具类,把普通Map转换成DvmObject格式DvmObject<?> a2 = ProxyDvmObject.createObject(vm, params);// 4.3 包装第三个参数:空字符串""// 同样用工具类转换成虚拟机可识别的DvmObject对象DvmObject<?> a3 = ProxyDvmObject.createObject(vm, "");// 4.4 包装第四个参数:布尔值false// 布尔值也需要包装成DvmObject才能被虚拟机方法接收DvmObject<?> a4 = ProxyDvmObject.createObject(vm, false);// 5. 调用目标类的静态方法,传入包装好的参数(都是DvmObject类型)// callStaticJniMethodObject:在虚拟机中调用静态方法的工具方法// 返回值value是StringObject类型(也是虚拟机中的字符串包装类)StringObject value = dvmClass.callStaticJniMethodObject(emulator, method, a1, a2, a3, a4);// 6. 从包装类中取出实际的字符串值并返回return value.getValue();}public static void main(String[] args) {WphSign hnGsign = new WphSign();String sgin = hnGsign.getSign();System.out.println(sgin);}
}