小研究 - Android 字节码动态分析分布式框架(五)

安卓平台是个多进程同时运行的系统,它还缺少合适的动态分析接口。因此,在安卓平台上进行全面的动态分析具有高难度和挑战性。已有的研究大多是针对一些安全问题的分析方法或者框架,无法为实现更加灵活、通用的动态分析工具的开发提供支持。此外,很多研究只是针对单进程的分析,在安卓平台多个应用进程协作完成事务的情境下,则无法进行很好的分析。

目录

5  实例分析

5.1 覆盖率程序分析实例

5.1.1 注入与分析实现

5.1.2 Grinderbench 测试

5.1.3 安卓应用情景测试

 5.2 权限使用检测实例

5.2.1 注入与分析实现

5.2.2 结果以及分析

 5.3 本章小结


5  实例分析

5.1 覆盖率程序分析实例

测试程序的覆盖率,是一种评价测试活动覆盖产品代码比例的指标。代码覆盖率能够直接反映一个程序执行路径(比如某测试用例)的有效性。在 JVM 上已经有不少工具可以测试代码的覆盖率,比如 Emma和 Jacoco。JaCoCo 如今也能支持在安卓平台测试代码覆盖率,然而 JaCoCo 测试需要与安卓的部署系统Gradle 相结合,以在部署应用的时候预注入代码覆盖的相关逻辑和依赖的 JaCoCo类库。由于 JaCoCo 的功能已经固定在它复杂的代码体系里,要扩展并不容易。

5.1.1 注入与分析实现

由于方法属于类,分支属于方法,因此找到分支的覆盖情况的过程中也能获取类以及方法覆盖的情况。为此如何获取分支覆盖的数据是本实例重要的一点。在 Java 语言中,分支的产生只有两种情况,一种是条件分支语句,一种是 Switch分支语句(并不包含异常处理语句),这与 JaCoCo 的实现原理相同。为了识别某一次方法调用中分支覆盖的情况,可以静态得从遍历该方法内的所有字节码指令,获取方法的所有分支,在运行时记录每一个遍历到的分支。

下图表示了本实例在方法进入和方法退出时候进行的注入。本文利用了DiSL 的@SyntheticLocal 变量。这个变量会被 DiSL 加到目标程序的方法里,变为一个方法局部变量,以供分析使用。本案例中,创建了两个该种类的变量:encounterBranch 和 branches,分别表示是否在分支语句内,以及方法内分支覆盖率的统计信息(采取 boolean 数组的形式,分别对应一个方法内 b local 个分支)。

@SyntheticLocal
public static boolean encounterBranch = false;
@SyntheticLocal
public static boolean [] branches;
@Before (marker = BodyMarker.class, order = 2)
public static void onMethodEntry (CodeCoverageContext c) {
    branches = new boolean [c.getMethodBranchCount ()];
}
@After (marker = BodyMarker.class, order = 2)
public static void onMethodExit (CodeCoverageContext c) {
    CodeCoverageAnalysisStub.commitBranch (
        c.thisClassName(), c.thisMethodName(), branches);
}

通过两个实验来验证本实例分支覆盖率分析的正确性。第一个实验,通过与已有的 JaCoCo 分支覆盖率测试工具进行比较以及对 Grinderbench这个轻量级 Java 测试套件实验来验证本案例分析结果的正确性;第二个实验,通过对一个安卓应用程序的四个操作情景进行测试,统计并验证四种情境下几个核心方法的覆盖率情况与代码情况是否吻合。

@AfterReturning (marker = BranchInsnMarker.class, order = 1)
public static void afterBranchInstr (CodeCoverageContext c)
{
    if (encounterBranch) {
        branches [c.getIndex ()] = true;
        encounterBranch = false;
    }
}
@Before (marker = SwitchInsnMarker.class, order = 1)
public static void beforeSwitch () {
     encounterBranch = true;
}
@AfterReturning (marker = BranchLabelMarker.class, order = 1)
public static void afterBranchLabel (CodeCoverageContext c)
{
    if (encounterBranch) {
        branches [c.getIndex ()] = true;
        encounterBranch = false;
    }
}
5.1.2 Grinderbench 测试

Grinderbench 是一个 JVM 上的简单的测试套件,其包括 Parallel、kXML、PNGdecoding、Chess 和 Crypto 五个测试,涉及多线程、CPU 密集、I/O 密集等测试类型。在不添加任何参数的情况下,该测试会依次进行这五个测试。本案例就是测量这种模式下的程序覆盖率。为了能够在安卓平台上运行 Grinderbench,本文利用 dx 工具,将 Grinderbench 的 jar 文件转换成 DVM 下可以执行的 jar 文件,并通过 adb 工具将该 jar 包发送到安卓系统上。这样就可以在安卓系统上通过 dalvikvm来新建一个 DVM 进程从而进行测试。

在 JVM 上,首先利用 JaCoCo 工具,来测试上述的运行模式下程序的覆盖率测试结果;紧接着,在本框架下于安卓 Dalvik 虚拟机中执行分支覆盖率测试。由于这部分分析没有安卓独有的事件,因而可以与原 JVM 上的 ShadowVM 模型兼容。可以直接在 JVM 上利用相同的分析代码执行覆盖率测试。

实验结果如表 5-1 所示。第一段数据是 JaCoCo 分别在 JVM 和 DVM 上对GrinderBench 进行测试的结果汇总情况,二者完全一致。第二段是本文开发的覆盖率分析分别在JVM和DVM上的结果,可以发现无论是在JVM上还是DVM上,覆盖到的分支、方法和类的数目均与 JaCoCo 一致。然而在总数上与 JaCoCo 并不完全相同。

因此可以看出基于本文框架,不仅能够方便的开发动态分析,还可以兼有跨平台的可移植性,而分析结果也能正确的反映程序的实际执行。

5.1.3 安卓应用情景测试

DroidBench测试集合中的 ImplicitFlow4 应用来检测本分析在安卓应用中的测试情况。ImplicitFlow4 应用是一个简易的安卓程序,它含有一个动组件,组件中包含了用户名输入、密码输入的文本框和登陆的按钮。用户输入用户名密码以后点击按钮会触发程序的判断操作。该应用的具体代码参考DroidBench 的 github 源代码库。

本案例分析的目标是目标应用中的两个重要方法checkUsernamePassword 以及 lookup,用户输入错误的用户名或者密码都会触发不同的程序运行路径从而造成不同的分支覆盖结果。本案例采取了四组用户数据作为输入:

1-用户名错误;

2-用户名正确、密码错误;

3-用户名正确,密码正确;

4-用户依次按照前三个情况输入。

经过试验,这四种情况下的覆盖情况如下所示。通过直接阅读源代码,可以验证该结果的正确性。

 5.2 权限使用检测实例

安卓系统采取权限控制的方式控制应用的访问能力。应用在安装时会提示用户需要的权限,用户并没有办法了解这些赋予的权限会被如何使用。加上安卓存在很多利用 Intent 的跨进程消息,通过静态分析很难完全识别出所有的敏感函数调用。

5.2.1 注入与分析实现

先介绍本案例用户定义的分析事件,即注入部分需要插入的事件。为此首先需要监控 ActivityManagerService 类的 checkPermission 方法。

public class IPCAnalysis extends RemoteIPCAnalysis {
    /* Analysis Event Handler Starts */
    public void permissionUsed (
        Context ctx, int tid, ShadowString permissionName) {
        List<ThreadState> callers = ThreadState.getCallers (ctx,tid);
        for(ThreadState caller:callers){
            caller.addPermission(permissionName.toString ());
        }
}
public void boundaryStart (
    Context ctx, int tid, ShadowString boundaryName) {
    ThreadState state = ThreadState.get (ctx, tid);
    state.pushBoundary (boundaryName.toString ());
}
public void boundaryEnd (
    Context ctx, int tid, ShadowString boundaryName) {
    ThreadState state = ThreadState.get (ctx, tid);
    state.popBoundary (boundaryName.toString ());
}
/* Analysis Event Handler Ends */

ActivityManagerService.checkPermission 方 法 接 受 三 个 参 数 : (Stringpermission, int pid, int uid),其中 permission 参数是一个字符串,用来表示不同的权 限 的 名 称 , pid 与 uid 则 分 别 表 示 调 用 进 程 的 进 程 号 与 用 户 id 。ActivityManagerService类的checkPermission方法一般在System Server进程中被调用,而且一般都是响应来自别的进程的 API 调用,因此它处在 IPC Binder 调用的第二与第三个事件之间。本案例利用该方法来捕获System Server所有的权限验证。其次,为了在分析过程检测到权限使用时能够还原出目标应用进程的对应线程的栈情况,需要在分析端为每个分析进程的每个线程维护一个栈。这个实现原理如下,只要记录下每次进入一个方法以及离开一个方法,就能知道任意时刻的线程的栈信息。在注入端,可以通过监控目标应用中的所有类的方法入口以及方法出口,产生相应分析事件,这样在分析服务器就可以动态得掌握当前分析事件处在什么样的运行时栈当中。注入部分的代码此处略去,可以参考图 5-3 中的分析响应代码。

由于在分析中并不是所有的分析都需要完整的还原 IPC 事件的顺序,因此框架并不直接提供事件同步功能。而本案例需要严格的控制事件顺序,也展示了框架的灵活性和可扩展性。

@Override
public void onRequestSent (
    TransactionInfo info, NativeThread client, Context ctx) {
    ThreadState clientState = ThreadState.get (client);
    clientState.recordRequestSent(client,info);
}
@Override
public void onRequestReceived (
    TransactionInfo info, NativeThread client,
    NativeThread server, Context ctx) {
    ThreadState clientState = ThreadState.get (client);
    clientState.waitForRequestSent (info);
    ThreadState serverState = ThreadState.get (server);
    serverState.recordRequestReceived(client, server, info);
}
@Override
    public void onResponseSent (
        TransactionInfo info, NativeThread client, NativeThread
    server, Context ctx) {
        ThreadState serverState = ThreadState.get (server);
        serverState.recordResponseSent(client, server, info);
}
@Override
public void onResponseReceived (
    TransactionInfo info, NativeThread client,
    NativeThread server, Context ctx) {
        ThreadState serverState = ThreadState.get (server);
        serverState.waitForResponseSent (info, client);
        ThreadState clientState = ThreadState.get (client);
        if(clientState.getPermissionCount()>0){
            IPCLogger.reportPermissionUsage (clientState);
            clientState.clearPermissions ();
        }
        clientState.recordResponseReceived(client, server, info);
    }
}
5.2.2 结果以及分析

为了验证分析的有效性,本文通过一个简单的实例,来展示本实例的功能。本案例选取 DroidBench 测试程序组中的 Reflection_Reflection4 程序作为测试程序。该程序只包含了一个活动组件,在启动应用后活动组件 onCreate 会自动被调用。

应用程序 => Phone进程 => System Server 进程 => Phone进程 => 应用程序。

通过本文的框架,首先 System Server 进程中当调用 ActivityManagerService的 checkPermission 方法检测 READ_PHONE_STATE 权限时,分析中会识别所有的上层调用方(Phone 进程的某个线程以及应用进程的某个线程),并告知它们在这段 IPC 调用中这个权限被使用了。那么最后应用进程执行完 IPC 方法后,分析端收到 onResponseReceived 事件,即收到 getDeviceId 的 IPC 调用返回值的时候,它就知道了该 IPC 调用造成了 READ_PHONE_STATE 权限的使用。

分析端得到的分析结果如图 5-7 所示,第一段信息表明了在程序执行到ConcreteClass 的 foo 方 法 里 , 调 用 TelephoneManager.getDeviceId 的 时 候READ_PHONE_STATE 权限被使用了。类似的,第二段信息则表明在 Concrete 类的 bar 方法中,对 SmsManager.sendTextMessage 的调用引起了 SEND_SMS 以及WAKE_LOCK 权限的使用。从结果中也可以发现,一个 API 调用可能引起多个权限的使用,用户可以进一步在分析中筛选自己关注的那些权限。

 5.3 本章小结

首先介绍了基于本框架实现的一个覆盖测试分析,通过运行 GrinderBench 以及在执行安卓应用这两种情景,验证了覆盖率分析的正确性,并说明了一些分析可以跨平台复用。接着通过一个检测安卓权限使用的案例,介绍了用户如何将分析与Binder 事件联合使用,以进行多进程分析。通过这两个例子充分展示了本框架强大的功能性,以及用户友好的分析编写方式。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

linux字符串处理

目录 1 C 截取字符串,截取两个子串中间的字符串2 获取该字符串后面的字符串用 strstr() 函数查找需要提取的特定字符串&#xff0c;然后通过指针运算获取该字符串后面的字符串用 strtok() 函数分割字符串&#xff0c;找到需要提取的特定字符串后&#xff0c;调用 strtok() 传入…

十四五双碳双控时代下的“低碳认证”

目录 前言 十四五双碳双控时代下的“低碳认证” 一、关于“低碳认证” 二、低碳认证优势 三、环境产品认证EPD 四、EPD相关运营机构 五、碳中和相关机构 六、EPD的认证流程 七、低碳产品认证认证流程和要求 八、相关机构认证证书样例 九、证书附件表 前言 通过本篇文…

DOCKER 部署 webman项目

# 设置基础镜像 FROM php:8.2-fpm# 安装必要的软件包和依赖项 RUN apt-get update && apt-get install -y \nginx \libzip-dev \libpng-dev \libjpeg-dev \libfreetype6-dev \&& rm -rf /var/lib/apt/lists/*# 安装 PHP 扩展 RUN docker-php-ext-configure gd …

探讨C#、C++和Java这三门语言在嵌入式的地位

我理解对于初入嵌入式领域的担忧。你是想选择一款通用性最广的语言专心学习&#xff0c;但是不知如何选择&#xff0c;视频后方提供了免费的嵌入式学习资源&#xff0c;内容涵盖入门到进阶&#xff0c;需要的到后方免费获取。因为我也曾是一名计算机专业毕业生。通过一段时间的…

无涯教程-Python机器学习 - Analysis of Silhouette Score函数

剪影得分的范围是[-1,1]。其分析如下- 1分数-接近1 剪影分数表示样本距离其邻近簇很远。 0分数-0 剪影分数表示样本在将两个相邻聚类分隔开的决策边界上或非常接近。 -1分数-1 剪影分数表示样本已分配给错误的聚类。 Silhouette得分的计算可以使用以下公式完成 $$剪影得…

计算机竞赛 基于大数据的股票量化分析与股价预测系统

文章目录 0 前言1 课题背景2 实现效果3 设计原理QTChartsarma模型预测K-means聚类算法算法实现关键问题说明 4 部分核心代码5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于大数据的股票量化分析与股价预测系统 该项目较为新颖…

执行jmeter端口不够用报错(Address not available)

执行jmeter端口不够用报错(Address not available) linux解决方案 // 增加本地端口范围 echo 1024 65000 > /proc/sys/net/ipv4/ip_local_port_range// 启用快速回收TIME_WAIT套接字 sudo sysctl -w net.ipv4.tcp_tw_recycle1// 启用套接字的重用 sudo sysctl -w net.ipv4.t…

LLM-Rec:基于提示大语言模型的个性化推荐

1. 基本信息 论文题目:LLM-Rec: Personalized Recommendation via Prompting Large Language Models 作者:Hanjia Lyu, Song Jiang, Hanqing Zeng, Yinglong Xia, Jiebo Luo 机构:University of Rochester, University of California Los Angeles, Meta AI, University of Ro…

STM32f103入门(4)对射式红外传感器计次(外部中断)

中断:在主程序运行过程中&#xff0c;出现了特定的中断触发条件 (中断源)&#xff0c;使得CPU暂停当前正在运行的程序&#xff0c;转而去处理中断程序处理完成后又返回原来被暂停的位置继续运行中断优先级:当有多个中断源同时申请中断时&#xff0c;CPU会根据中断源的轻重缓急进…

Oracle监听器启动出错:本地计算机上的OracleOraDb11g_home1TNSListener服务启动后又停止了解决方案

在启动oracle的服务OracleOraDb11g_home1TNSListener时&#xff0c;提示服务启动后又停止了。 解决方法&#xff1a; 修改oracle安装目录下的两个配置文件&#xff1a; 以上两个文件&#xff0c;对应的HOST的值&#xff0c;都改为127.0.0.1 然后再启动服务&#xff0c;启动成…

秒懂算法2

视频链接 : 希望下次秒懂的是算法题_哔哩哔哩_bilibili P1094 [NOIP2007 普及组] 纪念品分组 原题链接 : [NOIP2007 普及组] 纪念品分组 - 洛谷 思路 : 排序 贪心 双指针首先先对输入进来的数组进行排序(由小到大)运用贪心的思想 : 前后结合,令l1,rn,若a[l]a[r]<w…

Linux centos7 bash编程(小练习)

一、打印九九乘法口诀 这一个for循环嵌套的小练习&#xff0c;难度不大。提供一种写法&#xff0c;供参考&#xff1a; #!/bin/bash # 文件名&#xff1a;99table.sh # 打印输出九九乘法口诀表 for i in {1..9} do for ((j1;j<$i;j)) do …

⛳ Docker 安装 MySQL

&#x1f38d;目录 ⛳ Docker 安装 MySQL&#x1f69c; 一、搜索 mysql , 查看版本&#x1f3a8; 二、拉取mysql镜像&#x1f463; 三、建立容器的挂载文件&#x1f9f0; 四、创建mysql配置文件&#xff0c;my.conf&#x1f3ed; 五、根据镜像产生容器&#x1f381; 六、远程连…

2023MySQL+MyBatis知识点整理

文章目录 主键 外键 的区别&#xff1f;什么是范式&#xff1f;什么是反范式&#xff1f;什么是事务&#xff1f;MySQL事务隔离级别&#xff1f;MySQL事务默认提交模式&#xff1f;MySQL中int(1)和int(10)的区别MySQL 浮点数会丢失精度吗&#xff1f;MySQL支持哪几种时间类型&a…

线性数据结构:数组与链表的探索与应用

文章目录 1. 数组&#xff1a;连续存储的有序元素集合1.1 创建和访问数组1.2 数组的搜索与排序 2. 链表&#xff1a;非连续存储的动态数据结构2.1 单链表与双链表2.2 链表的操作与应用 3. 数组与链表的比较与应用3.1 数组与链表的比较3.2 数组与链表的应用 4. 总结与展望 &…

【Go 基础篇】切片:Go语言中的灵活数据结构

在Go语言中&#xff0c;切片&#xff08;Slice&#xff09;是一种强大且灵活的数据结构&#xff0c;用于管理和操作一系列元素。与数组相比&#xff0c;切片的大小可以动态调整&#xff0c;这使得它成为处理动态数据集合的理想选择。本文将围绕Go语言中切片的引入&#xff0c;介…

如何在有或没有WiF适配器的情况下把台式机接入WiFi

Wi-Fi在台式电脑中越来越普遍,但并不是所有的台式电脑都有。添加Wi-Fi,你就可以无线连接到互联网,并为其他设备托管Wi-Fi热点。 这是一个简单、廉价的过程。买一个合适的小适配器,你甚至可以随身携带,通过将一个小设备插入USB端口,可以快速将Wi-Fi添加到你遇到的任何桌面…

screen命令,可以断开服务器连接,依旧能运行你的程序了

可以参考博客1&#xff1a;https://blog.csdn.net/nima_zhang_b/article/details/82797928 可以参考博客2:https://blog.csdn.net/herocheney/article/details/130984403 Linux中的screen是一个命令行工具&#xff0c;可以让用户在同一个终端会话中创建多个虚拟终端。它非常有…

element-ui 弹窗里面嵌套弹窗,解决第二个弹窗被遮罩层掩盖无法显示的问题

当我们在 element-ui 中使用弹窗嵌套弹窗时&#xff0c;会出现第二个弹窗打开时被一个遮罩层挡着&#xff0c;就像下面这样&#xff1a; 下面提供两种解决方案 &#xff1a; 一、第一种方案 我们查询element-ui 官网可以发现 el-dialog 有这样几个属性&#xff1a; 具体使用就…

Android Looper Handler 机制浅析

最近想写个播放器demo&#xff0c;里面要用到 Looper Handler&#xff0c;看了很多资料都没能理解透彻&#xff0c;于是决定自己看看相关的源码&#xff0c;并在此记录心得体会&#xff0c;希望能够帮助到有需要的人。 本文会以 猜想 log验证 的方式来学习 Android Looper Ha…
最新文章