Unidbg模拟执行某段子so实操教程(一) 先把框架搭起来

news2024/11/25 20:25:51

一、目标

最近又开始研究Unidbg了,费了好大劲,没有跑起来。今天就先找个软柿子捏捏看。

今天的目标是 之前研究的 某段子App签名计算方法(一)

  • 某段子App版本 5.5.10

二、步骤

先搭起框架来

/unidbg/unidbg-android/src/test/java/ 下面新建一个 com/fenfei/test 包, 我们的例子都放在这个包下。

然后再创建一个 RunZy

public class RunZy extends AbstractJni {public static void main(String[] args) throws IOException {// 1、需要调用的Apk文件所在路径String apkFilePath = "/Users/fenfei/Desktop/zy/cn.xxxxchuanxxxx.tieba_5.5.10_505100.apk";// 2、需要调用函数所在的Java类完整路径,比如a/b/c/d等等,注意需要用/代替.String classPath = "com/izxxyxx/network/NetCrypto";// 3、需要调用方法,再jadx中找到对应的方法,然后点击下面的Smail,复制方法的Smail代码。String methodSign = "sign(Ljava/lang/String;[B)Ljava/lang/String;";RunZy runZyObj = new RunZy(apkFilePath, classPath);runZyObj.destroy();}// ARM模拟器private final ARMEmulator emulator;// vmprivate final VM vm;// 载入的模块private final Module module;private final DvmClass TTEncryptUtils;/** * * @param apkFilePath需要执行的apk文件路径 * @param classPath需要执行的函数所在的Java类路径 * @throws IOException */public RunZy(String apkFilePath, String classPath) throws IOException {// 创建app进程,包名可任意写emulator = AndroidEmulatorBuilder.for32Bit().setProcessName("com.fenfei.RunZy").build(); // 创建模拟器实例,要模拟32位或者64位,在这里区分final Memory memory = emulator.getMemory(); // 模拟器的内存操作接口// 作者支持19和23两个sdkmemory.setLibraryResolver(new AndroidResolver(23));// 创建DalvikVM,利用apk本身,可以为nullvm = ((AndroidARMEmulator) emulator).createDalvikVM(new File(apkFilePath));vm.setVerbose(true);vm.setJni(this);new AndroidModule(emulator, vm).register(memory);// (关键处1)加载so,填写so的文件路径DalvikModule dm = vm.loadLibrary("net_crypto", false);// 调用jnidm.callJNI_OnLoad(emulator);module = dm.getModule();//emulator.traceCode(module.base, module.base + module.size);// (关键处2)加载so文件中的哪个类,填写完整的类路径TTEncryptUtils = vm.resolveClass(classPath);}/** * 关闭模拟器 * @throws IOException */private void destroy() throws IOException {emulator.close();System.out.println("emulator destroy...");}

} 

跑 native_init

从之前的分析我们知道,在执行 sign函数之前,需要执行 native_init

// runZyObj.initCall();private void initCall(){TTEncryptUtils.callStaticJniMethod(emulator,"native_init()V");} 

执行一下

java.lang.UnsupportedOperationException: com/izxxyxx/common/base/BaseApplication->getAppContext()Landroid/content/Context;
	at com.github.unidbg.linux.android.dvm.AbstractJni.callStaticObjectMethodV(AbstractJni.java:402) 

这个报错好解决,我们重写 callStaticObjectMethodV 来实现这个函数

@Overridepublic DvmObject<?> callStaticObjectMethodV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) {switch (signature) {case "com/izxxyxx/common/base/BaseApplication->getAppContext()Landroid/content/Context;":return vm.resolveClass("android/content/Context", vm.resolveClass("android/content/ContextWrapper", vm.resolveClass("android/content/Context"))).newObject(signature);return super.callStaticObjectMethodV(vm,dvmClass,signature,vaList);} 

这个 getAppContext 我们之前的文章实现过,这里就依葫芦画瓢。

再跑一下,Ok,native_init 算是跑过了。

执行sign

通过之前的分析我们知道,sign的入参有两个,第一个参数是个字符串,实际是个url,第二个参数也是这个so里面的加密结果,一个buf。我们从hook结果里面找一个入参来玩玩。

String InBuf = "50027f7f7f7f8e8e8e8e8e1......";

String ret = runZyObj.getSign(methodSign,new StringObject(runZyObj.vm, "https://zyadapi.izxxyxx.com/ad/popup_ad"),hexStringToBytes(InBuf));

// Out Rc=v2-1ff7402d2b4fa9a4c39b3853262f18fd
System.out.printf("ret:%s\n", ret);

/**
 * 调用so文件中的指定函数
 * @param methodSign 传入你要执行的函数信息,需要完整的smali语法格式的函数签名
 * @param args 是即将调用的函数需要的参数
 * @return 函数调用结果
 */
private String getSign(String methodSign, Object ...args) {// 使用jni调用传入的函数签名对应的方法()Object value = TTEncryptUtils.callStaticJniMethodObject(emulator, methodSign, args).getValue();return value.toString();
} 

再跑一下

java.lang.UnsupportedOperationException: android/content/Context->getClass()Ljava/lang/Class;
	at com.github.unidbg.linux.android.dvm.AbstractJni.callObjectMethodV(AbstractJni.java:349) 

没明白这个 getClass 是干啥用的,不管了,先实现再说

@Override
public DvmObject<?> callObjectMethodV(BaseVM vm, DvmObject<?> dvmObject, String signature, VaList vaList) {switch (signature) {case "android/content/Context->getClass()Ljava/lang/Class;":return vm.resolveClass("java/lang/Class");}return super.callObjectMethodV(vm, dvmObject, signature, vaList);
} 

继续跑

java.lang.UnsupportedOperationException: java/lang/Class->getSimpleName()Ljava/lang/String;
	at com.github.unidbg.linux.android.dvm.AbstractJni.callObjectMethodV(AbstractJni.java:349) 

这次是找我们要个 getSimpleName 这个值是啥呀?我也不知道,后面我再教大家找这个值的方法,这里先写死一个值吧。

case "java/lang/Class->getSimpleName()Ljava/lang/String;":
	return new StringObject(vm, "izxxyxx"); 

继续跑一下,

java.lang.UnsupportedOperationException: cn/xiaochuankeji/tieba/common/debug/AppLogReporter->reportAppRuntime(Ljava/lang/String;Ljava/lang/String;)V
	at com.github.unidbg.linux.android.dvm.AbstractJni.callStaticVoidMethodV(AbstractJni.java:576) 

遇上 debug 之类的要敏感,这个报错后面分析的时候会用到。 这里我们就先实现 reportAppRuntime

@Override
public void callStaticVoidMethodV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) {switch (signature) {case "cn/xiaochuankeji/tieba/common/debug/AppLogReporter->reportAppRuntime(Ljava/lang/String;Ljava/lang/String;)V":return;}

	throw new UnsupportedOperationException(signature);

} 

因为这个函数没有返回值,所以我们直接return即可。 继续跑…

java.lang.UnsupportedOperationException: android/content/Context->getFilesDir()Ljava/io/File;
	at com.github.unidbg.linux.android.dvm.AbstractJni.callObjectMethodV(AbstractJni.java:349) 

要读文件?先实现一把

case "android/content/Context->getFilesDir()Ljava/io/File;":
	return vm.resolveClass("java/io/File"); 

继续跑

java.lang.UnsupportedOperationException: java/lang/Class->getAbsolutePath()Ljava/lang/String;
	at com.github.unidbg.linux.android.dvm.AbstractJni.callObjectMethodV(AbstractJni.java:349) 

获取路径?我们也给他实现一个

case "java/lang/Class->getAbsolutePath()Ljava/lang/String;":
	return new StringObject(vm, "/sdcard"); 

再来

java.lang.UnsupportedOperationException: android/os/Debug->isDebuggerConnected()Z
	at com.github.unidbg.linux.android.dvm.AbstractJni.callStaticBooleanMethodV(AbstractJni.java:154) 

判断是否被调试?这我哪能让你得逞

@Override
public boolean callStaticBooleanMethodV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) {switch (signature) {case "android/os/Debug->isDebuggerConnected()Z":return Boolean.FALSE;}return super.callStaticBooleanMethodV(vm,dvmClass,signature,vaList);
} 

必须是要告诉你,我根本木有在调试呀。

java.lang.UnsupportedOperationException: android/os/Process->myPid()I
	at com.github.unidbg.linux.android.dvm.AbstractJni.callStaticIntMethodV(AbstractJni.java:174) 

要pid?给你一个

@Override
public int callStaticIntMethodV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) {switch (signature) {case "android/os/Process->myPid()I":return 123;}return super.callStaticIntMethodV(vm,dvmClass,signature,vaList);
} 

终极一跑

ret:v2-ABC1ff7402d2b4fa9a4c39b3853262f18fd
emulator destroy... 

欧耶,结果出来了。

结果很忧伤

我们之前Hook的结果是 v2-1ff7402d2b4fa9a4c39b3853262f18fd 现在跑出来的结果是 v2-ABC1ff7402d2b4fa9a4c39b3853262f18fd , 不大对劲呀。

以结果轮英雄,我们可以多跑几组,如果确定模拟执行出来的结果都是 加上了固定的 ABC ,那也好办,直接过滤掉就行。

但是我们是写教程了,得搞明白。 怎么搞明白?模拟执行的结果有些不对劲该怎么办? 我们下回分解。

网安零基础入门
对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。

路线图原图,或xmind文件,可以扫下方二维码下载:

同时每个成长路线对应的板块都有配套的视频提供:


当然除了有配套的视频,同时也为大家整理了各种文档和书籍资料&工具,并且已经帮大家分好类了。

因篇幅有限,仅展示部分资料,有需要的小伙伴,可以【扫下方二维码】免费领取:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/167983.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

K8S 三种探针ReadinessProbe、LivenessProbe和StartupProbe 之探索

一、事件背景因为k8s中采用大量的异步机制&#xff0c;以及多种对象关系设计上的解耦&#xff0c;当应用实例数增加/删除、或者应用版本发生变化触发滚动升级时&#xff0c;系统并不能保证应用相关的service、ingress配置总是及时能完成刷新。在一些情况下&#xff0c;往往只是…

Python爬虫之Scrapy框架系列(4)——项目实战【某瓣Top250电影更多信息的获取】

前言&#xff1a; 上篇文章使用Scrapy框架简单爬取并下载了某瓣Top250首页的排名前25个电影的电影名。 太寒酸了&#xff0c;这篇文章咱就来仔细搞一搞&#xff0c;搞到更加详细的信息&#xff01;&#xff01;&#xff01; 目录&#xff1a;1.分析2.使用scrapy shell提取电影详…

进程信号--Linux

文章目录信号&#xff1f;kill -l 指令查看所有信号信号的工作流程信号产生1.通过终端按键产生信号2.通过系统调用接口产生信号3.通过软件产生信号4.硬件异常产生信号信号接收信号处理总结信号&#xff1f; 进程间的通信我们了解到有管道通信&#xff0c;有共享内存的通信。这…

flowable编译

git clone -b flowable-release-6.7.2 https://github.com/flowable/flowable-engine.git下载之后File-Open&#xff0c;打开工程&#xff0c;modules是核心代码模块 找到flowable-root.xml按下altf12 &#xff0c;启动Terminal终端输入命令&#xff1a;mvn clean package -Ds…

《Buildozer打包实战指南》第三节 安装Buildozer打包所需的依赖文件

目录 3.1 安装依赖软件包 3.2 安装Cython 3.3 设置环境变量 3.4 安装p4a、Android SDK、NDK以及其他编译文件 Buidozer这个打包库下载安装完毕之后&#xff0c;我们还需要下载一些打包安卓apk所需要的依赖文件。 3.1 安装依赖软件包 首先输入以下命令更新Ubuntu上的软件包…

使众人行:如何带领一群人把事做成?

你好&#xff0c;我是雷蓓蓓&#xff0c;一名程序员出身的项目经理&#xff0c;曾任网易杭研项目管理部总监。 我所带领的网易杭研项目管理部&#xff0c;从2011年成立以来&#xff0c;就一直在互联网项目管理领域深耕&#xff0c;为网易云音乐、网易严选、云计算、智慧企业等…

智慧社区管理系统改造方案

伴随着城市发展的持续加速&#xff0c;许多在建智慧社区和老旧小区智能化改造都在有规划的展开着。如今许多老旧小区在展开设备升级&#xff0c;许多小区智能安防设备、物业管理服务系统软件、社区综合服务平台及其监控器设备等都会展开智能化改造。但是&#xff0c;很多人对老…

17.优于select的epoll

优于select的epoll epoll 理解及应用 select复用方法其实由来已久&#xff0c;因此&#xff0c;利用该技术后&#xff0c;无论如何优化程序性能也无法同时接入上百个客户端&#xff08;当然&#xff0c;硬件性能不同&#xff0c;差别也很大&#xff09;。这种select方式并不适…

IIC驱动中景园0.96寸OLED

驱动硬件介绍 1、驱动电压3.3到5,但是正点的也是这个芯片说用3.3 5会烧坏掉。 2、RST 上的低电平,将导致OLED 复位,在每次初始化之前,都应该复位一下 OLED 模块。而我们使用四线,里面就没有复位了 3、裸屏有多种接口方式(驱动芯片为SSD1306) 6800、8080 两种并行接口方…

Redis应用2(Redison)

不推荐使用application的配置方式,因为会替代spring内部的对于redis的配置方式 注意:如果redis数据库没有密码,不要使用 config.useSingleServer().setPassword("") 的形式,直接跳过setPassword()就可以,配置类写法如下: Configuration public class RedisConfig…

MySQL进阶——索引

一、索引及其分类 1.索引的概念 索引是一种特殊的文件&#xff0c;包含着对数据表中所有记录的引用指针通俗点说&#xff0c;索引就好比是一本书的目录&#xff0c;能加快数据库的查询速度例如需要遍历 200 条数据&#xff0c;在没有索引的情况下&#xff0c;数据库会遍历全部…

Spring之事务编程概述

目录 一&#xff1a;基本概念 搭建测试环境 基于xml声明式事务控制 二&#xff1a;事务相关配置 ​编辑 基于注解声明式事务控制 三&#xff1a;Spring事务角色 四&#xff1a;事务传播行为 五&#xff1a;案例&#xff1a;转账业务追加日志 一&#xff1a;基本概念 事…

Vue.nextTick核心原理

相信大家在写vue项目的时候&#xff0c;一定会发现一个神奇的api&#xff0c;Vue.nextTick。为什么说它神奇呢&#xff0c;那是因为在你做某些操作不生效时&#xff0c;将操作写在Vue.nextTick内&#xff0c;就神奇的生效了。那这是什么原因呢&#xff1f; 让我们一起来研究一…

手把手教你写Dockerfile以及测试

Dockerfile是什么&#xff1f; dockerfile就是用来构建docker镜像的构建文件,命令参数脚本。 如何使用Dockerfile&#xff1f; 1、编写一个Dockerfile文件2、docker build构建成 基础使用&#xff08;此处罗列一些我们经常用到的&#xff09; # 指定依赖镜像版本&#xff…

【附代码】十大主流聚类算法

准备工作安装必要的库pip install scikit-learn准备数据集使用 make _ classification ()函数创建一个测试二分类数据集。数据集将有1000个示例&#xff0c;每个类有两个输入要素和一个群集。这些群集在两个维度上是可见的&#xff0c;因此我们可以用散点图绘制数据&#xff0c…

第18章_JDBC

一、JDBC概述JDBC概述什么是JDBCJDBC&#xff08;Java DataBase Connectivity, Java数据库连接&#xff09; ,是一种用于执行SQL语句的Java API&#xff0c;为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成有了JDBC&#xff0c;程序员只需用JDBC API写一个…

夜深忽梦少年事,7年又一年,来看看95年那个小伙现在怎么样了

2022年已到尾声&#xff0c;疫情也结束了&#xff0c;这三年太不容易了&#xff0c;今年也是一样在疫情的艰难的度过&#xff0c;就是做了两件事&#xff0c;防疫和上班&#xff0c;没什么可写的。但是在一个深夜晚上&#xff0c;想了很多以前的事&#xff0c;想想还是写一点东…

亚马逊云科技Amazon DeepRacer互联网行业全国冠军诞生

1月11日&#xff0c;首届亚马逊云科技Amazon DeepRacer自动驾驶赛车互联网行业全国总决赛圆满结束&#xff0c;从全国各地选拔出的9支冠军队伍齐聚滨海三亚&#xff0c;向总决赛的桂冠发起了冲击。 本次比赛沿袭了Amazon DeepRacer League全球赛事标准&#xff0c;使用了全新的…

Vue.js的this如何取到data和method里的属性?

本篇文章介绍的是Vue.js如何取到data和methods里的属性&#xff1f; 准备工作 克隆源码到本地 git clone https://github.com/vuejs/vue.git 下载完毕后&#xff0c;用vscode打开&#xff0c;目光移动到package.json的scripts属性&#xff0c;我们看到有dev和build&#xff0…

Golang -- openwechat发送消息、自动回复

开篇 马上就要到农历新年了&#xff0c;不妨写一段代码准时为好友们送上祝福。 该 Demo 使用开源项目 openwechat &#xff0c;实现获取好友列表、为好友发送消息、图片或文件&#xff0c;接收来自好友或群组的消息并设置自动回复等功能。 openwechat Github地址 openwechat 文…