当前位置: 首页 > news >正文

Unidbg使用指南

Unidbg使用指南

  • 简介
  • 使用
  • Unidbg补环境
    • 仅含C语言
    • C调用 Java
  • 实操——车智赢+在unidbg实现执行so中的方法
  • 附——关于引用数据类型的转换
  • 附——静态注册和动态注册模板
    • 静态注册
    • 动态注册

现在很多的app使用了so加密,以后会越来越多。爬虫工程师可能会直接逆向app,看java代码,完成java层的算法破解,但是如果遇到so该怎么办呢?可能你会直接破解so,但是真的会有很多爬虫工程师会去破解so吗?有时候我们可以不用破解so,利用很多大佬写好的轮子即可完成so的调用。

说到调用,就有很多方法了,比如用frida+rpc、xposed+andserver、再者就是unicorn+web框架等等,今天要说的并不是这些,而是unidbg,这框架有什么好的地方呢?看看简介。

简介

unidbg是一个Java项目,可以帮助我们去模拟一个安卓或IOS设备,用于去执行so文件中的算法,从而不需要再去逆向他内部的算法。
关于so的解决方法:

  • 硬核分析+调试+破解
  • frida-rpc
  • unidbg

使用

  1. 在github上开源的项目:unidbg
    在这里插入图片描述
  2. 打开项目
    由于unidbg项目是由java编写的,所以需要用 Intellij IDEA 打开并操作。
    导入项目后我们运行下测试代码,看看我们的环境是否有问题
    在这里插入图片描述
    当我们运行测试代码后能出现sign值说明环境是没问题的。

Unidbg补环境

unidbg在运行so文件时会出现两类情况:

  • so算法都基于C语言实现,
  • so算法中还会读取Java中成员,

仅含C语言

这种直接基于unidbg来进行so文件即可。

在这里插入图片描述

C调用 Java

这种就需要补环境,将C中调用的Java中的功能给补上,这样so中的代码才能正常执行。
所谓的unidbg补环境,其实补的就是这个。

在这里插入图片描述

实操——车智赢+在unidbg实现执行so中的方法

在这里插入图片描述
在这里插入图片描述

  1. 创建类
    在这里插入图片描述

  2. 设备初始化
    在这里插入图片描述

    package com.com.demo;import com.github.unidbg.AndroidEmulator;
    import com.github.unidbg.Module;
    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.memory.Memory;import java.io.File;public class che extends AbstractJni{public static AndroidEmulator emulator;public static Memory memory;public static VM vm;public static DalvikModule dm;public static Module module;che() {// 1.创建设备(32位或64位模拟器), 具体看so文件在哪个目录。 在armeabi-v7a就选择32位emulator = AndroidEmulatorBuilder.for32Bit().setProcessName("com.che168.autotradercloud").build();// 2.获取内存对象(可以操作内存)memory = emulator.getMemory();// 3.设置安卓sdk版本(只支持19、23)memory.setLibraryResolver(new AndroidResolver(23));// 4.创建虚拟机(运行安卓代码需要虚拟机,就想运行py代码需要python解释器一样)vm = emulator.createDalvikVM(new File("unidbg-android/apks/che/atc282.apk"));vm.setJni(this);//vm.setVerbose(true); //是否展示调用过程的细节// 5.加载so文件DalvikModule dm = vm.loadLibrary(new File("unidbg-android/apks/che/libnative-lib.so"), false);//dm.callJNI_OnLoad(emulator);// 6.dm代表so文件,dm.getModule()得到module对象,基于module对象可以访问so中的成员。module = dm.getModule();}public static void main(String[] args) {che obj = new che();}
    }
    
  3. 执行签名

    public void sign() {// 找到java中native所在的类,并加载DvmClass CheckSignUtil = vm.resolveClass("com/autohome/ahkit/jni/CheckSignUtil");// 方法的符号表示String method = "get3desKey(Landroid/content/Context;)Ljava/lang/String;"; //JNI签名//导入的包					返回值// 执行类中的静态成员StringObject obj = CheckSignUtil.callStaticJniMethodObject(emulator,method,vm.resolveClass("android/content/Context").newObject(null));String keyString = obj.getValue();System.out.println(keyString);}

在这里插入图片描述

通过上述操作我们就完成了在unidbg实现执行so中的方法。

附——关于引用数据类型的转换

在这里插入图片描述

附——静态注册和动态注册模板

静态注册

  • 根据函数名将Java代码中的native方法与so中的JNI方法一一对应,当Java层调用so层的函数时,如果发现其上有JNIEXPORT和JNICALL两个宏定义声明时,就会将so层函数链接到对应的native方法上。
  • 而native方法和so方法对应规则是:以字符串“Java”为前缀,并且用“_”下划线将包名、类名以及native方法名连接起来就是对应的JNI函数名了。
Java.perform(function () {var dlsymadd = Module.findExportByName("libdl.so", 'dlsym');Interceptor.attach(dlsymadd, {onEnter: function (args) {this.info = args[1];}, onLeave: function (retval) {//那个so文件 module.namevar module = Process.findModuleByAddress(retval);if (module == null) {return retval;}// native方法var funcName = this.info.readCString();if (funcName.indexOf("getHNASignature") !== -1) {console.log(module.name);console.log('\t', funcName);}return retval;}})
});// Application(identifier="com.rytong.hnair", name="海南航空", pid=14958, parameters={})
// frida -U -f  com.rytong.hnair  -l static_find_so.js

动态注册

  • 在调用System.loadLibrary()时会在so层调用一个名为JNI_OnLoad()的函数,我们可以提供一个函数映射表,再在JNI_Onload()函数中通过JNI中提供的RegisterNatives()方法来注册函数。这样Java就可以通过函数映射表来调用函数,而不必通过函数名来查找对应函数。
var symbols = Module.enumerateSymbolsSync("libart.so");
var addrRegisterNatives = null;
for (var i = 0; i < symbols.length; i++) {var symbol = symbols[i];if (symbol.name.indexOf("art") >= 0 &&symbol.name.indexOf("JNI") >= 0 &&symbol.name.indexOf("RegisterNatives") >= 0 &&symbol.name.indexOf("CheckJNI") < 0) {addrRegisterNatives = symbol.address;console.log("RegisterNatives is at ", symbol.address, symbol.name);}
}
console.log("addrRegisterNatives=", addrRegisterNatives);if (addrRegisterNatives != null) {Interceptor.attach(addrRegisterNatives, {onEnter: function (args) {var env = args[0];var java_class = args[1];var class_name = Java.vm.tryGetEnv().getClassName(java_class);// 只有类名为com.bilibili.nativelibrary.LibBili,才打印输出var taget_class = "com.xunmeng.pinduoduo.secure.DeviceNative";if (class_name === taget_class) {console.log("\n[RegisterNatives] method_count:", args[3]);var methods_ptr = ptr(args[2]);var method_count = parseInt(args[3]);for (var i = 0; i < method_count; i++) {// Java中函数名字的var name_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3));// 参数和返回值类型var sig_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize));// C中的函数指针var fnPtr_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize * 2));var name = Memory.readCString(name_ptr); // 读取java中函数名var sig = Memory.readCString(sig_ptr); // 参数和返回值类型var find_module = Process.findModuleByAddress(fnPtr_ptr); // 根据C中函数指针获取模块var offset = ptr(fnPtr_ptr).sub(find_module.base) // fnPtr_ptr - 模块基地址// console.log("[RegisterNatives] java_class:", class_name);console.log("name:", name, "sig:", sig, "module_name:", find_module.name, "offset:", offset);//console.log("name:", name, "module_name:", find_module.name, "offset:", offset);}}}});
}// frida -U -f  com.xunmeng.pinduoduo  -l dynamic_find_so.js

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 基于MyBatis-plus的SpringBoot开发
  • go,gin封装gorm使用,增删改查
  • 【Web自动化测试】
  • 大话C语言:第40篇 结构体指针​
  • 【学习笔记】A2X通信的协议(十一)- 通过PC5的直接C2通信
  • 车辆横向控制的参考路径估计
  • 网络安全入门必备读书清单!(非常详细)零基础入门到精通,收藏这一篇就够了
  • 物理网卡MAC修改器v3.0-直接修改网卡内部硬件MAC地址,重装系统不变!
  • 单元训练10:定时器实现秒表功能-数组方式
  • 打卡学习Python爬虫第一天|抓取百度首页html代码
  • 若依框架中的mybatis依赖在哪里?
  • Vue2 和 Vue3中EventBus使用差异
  • EasyRecovery17中文版永久汉化版电脑数据恢复工具下载
  • 使用Labelme标注数据
  • C++面向对象单例模式禁止拷贝、禁止赋值操作(=delete)
  • 【知识碎片】第三方登录弹窗效果
  • co.js - 让异步代码同步化
  • Cumulo 的 ClojureScript 模块已经成型
  • E-HPC支持多队列管理和自动伸缩
  • ES10 特性的完整指南
  • Essential Studio for ASP.NET Web Forms 2017 v2,新增自定义树形网格工具栏
  • Eureka 2.0 开源流产,真的对你影响很大吗?
  • magento 货币换算
  • Spring Boot MyBatis配置多种数据库
  • Spring Security中异常上抛机制及对于转型处理的一些感悟
  • SpringCloud(第 039 篇)链接Mysql数据库,通过JpaRepository编写数据库访问
  • Tornado学习笔记(1)
  • 服务器从安装到部署全过程(二)
  • 个人博客开发系列:评论功能之GitHub账号OAuth授权
  • 关于springcloud Gateway中的限流
  • 湖南卫视:中国白领因网络偷菜成当代最寂寞的人?
  • 基于Dubbo+ZooKeeper的分布式服务的实现
  • 看图轻松理解数据结构与算法系列(基于数组的栈)
  • 前端
  • 前端学习笔记之观察者模式
  • 如何编写一个可升级的智能合约
  • 《TCP IP 详解卷1:协议》阅读笔记 - 第六章
  • hi-nginx-1.3.4编译安装
  • 如何在 Intellij IDEA 更高效地将应用部署到容器服务 Kubernetes ...
  • #单片机(TB6600驱动42步进电机)
  • #免费 苹果M系芯片Macbook电脑MacOS使用Bash脚本写入(读写)NTFS硬盘教程
  • (12)目标检测_SSD基于pytorch搭建代码
  • (8)Linux使用C语言读取proc/stat等cpu使用数据
  • (c语言+数据结构链表)项目:贪吃蛇
  • (C语言版)链表(三)——实现双向链表创建、删除、插入、释放内存等简单操作...
  • (Git) gitignore基础使用
  • (超详细)2-YOLOV5改进-添加SimAM注意力机制
  • (附源码)spring boot公选课在线选课系统 毕业设计 142011
  • (函数)颠倒字符串顺序(C语言)
  • (七)微服务分布式云架构spring cloud - common-service 项目构建过程
  • (四)activit5.23.0修复跟踪高亮显示BUG
  • (四)七种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
  • (原)本想说脏话,奈何已放下
  • (转载)(官方)UE4--图像编程----着色器开发
  • ****Linux下Mysql的安装和配置