Android 下 APK 捆绑器的实现

作者: 海东青

利用捆绑器向正常程序捆绑病毒、木马等恶意程序,以达到隐蔽安装、运行的目的,这

在 Windows 平台下是一种很常规的攻击手段。那么,在智能终端十分流行的今天,如何实

现针对手机应用的捆绑器呢?对此,本文针对 Android 平台的应用程序 APK 文件,给出了

类似 Windows 下捆绑器的实现方案。

原理与基础

对任意的两个 APK 应用程序 A 和 B 进行捆绑,并且在手机上安装、运行捆绑生成的

APK 程序 C 后,仍然具备和 A 一样的运行效果,要实现这一目的,捆绑过程可以从两个思

路去实现。

1)对 Android 应用程序 A 进行反编译,通过修改反编译生成的 smali 代码,控制执行

流程,使其具备安装和执行应用程序 B 的功能,最后再打包生成捆绑后的应用 C。此方法

和早期的 Windows 环境下的 PE 病毒类似,插入额外的功能代码,修改入口点改变程序执行

流程,最后再回到原有流程执行 A 的功能。

2)考虑到 A、B 的任意性,以及生成程序 C 的稳定性,在这里重点介绍另外一种通过

宿主程序实现释放、安装、运行 A 和 B 的方法。其思路亦来自 Windows 下的捆绑器,即专

门写一个 host 程序作为宿主,其中应用程序 A、B 作为 host 的资源文件,运行 host 时可以

释放、安装和运行 A 和 B 的功能。此外,若考虑到安全性、免杀性,可对 A 和 B 进行加密、

编码。因此,根据方法2,可得出PC端和Android手机端的软件工作流程如图1和图2所示

QQ图片20140404144049.jpg (50.11 KB, 下载次数: 26)

2014-4-4 15:02 上传

QQ图片20140404150245.jpg (30.84 KB, 下载次数: 20)

2014-4-4 15:04 上传

功能实现

通过上面的介绍,可以知道总共需要实现两个程序,即作为宿主程序的 Android 应用

host.apk,以及作为捆绑器的 Windows 应用程序“捆绑器”,下面将详细介绍这两个程序内

部原理和实现方法。

1.宿主应用程序

1)工作流程

对于宿主程序 host.apk,要实现上文所定义的功能需求,则其内部的工作流程可设计如

成如图 3 所示的结构。在宿主程序初始化时,会调用MainActity 的 onCreate 函数。在 onCreate

函数中,通常用来初始化 MainActivity,但是考虑到最终呈现给用户的界面(即 Activity)

为 A 的界面,所以宿主程序的 onCreate 函数中无需处理自身界面,只需想办法启动 A 的

Activity 即可。

QQ图片20140404144738.jpg (81.05 KB, 下载次数: 16)

2014-4-4 15:03 上传

释放和安装指定的应用程序通常需要较长时间(与应用程序的大小相关),若所有流程

均在 onCreate 函数流程中实现,则会导致宿主程序界面卡顿或假死,故可通过在 onCreate

函数中创建子线程的方式避免该问题,在子线程中实现相关功能,其中主要有释放和安装应

用程序,以及启动主应用程序这两部分。

2)释放和安装应用程序

①释放指定文件

对于 Android 应用程序,需要捆绑的资源文件可以直接放置到 assets 目录下。在宿主程

序中,共计需要释放三个文件,即配置文件 config、主程序 update.res 和捆绑进去的程序

data.res,释放方式如下。当程序安装后,需要释放时可通过如下方式实现。

//dstFilePath 为释放出来的文件路径,resFileName 为需要释放的文件路径

private void dropFile(String dstFilePath, StringresFilename){

if(isFileExist(dstFilePath)) return;

InputStream inputFS;

try { inputFS = this.getResources().getAssets().open(resFilename);

} catch (IOException e1) {return; }

File outFile = new File(dstFilePath);

byte buf[] = new byte[1024];   int len;

try {

OutputStream outputFS = new FileOutputStream(outFile);

while((len = inputFS.read(buf))>0) {  outputFS.write(buf,0,len);}

outputFS.close();  inputFS.close();

} catch (IOException e) { return ; }

return;

}

②安装应用程序

文件释放后,接下来就要根据需要进行安装程序。对用户而言,已经安装程序了,故接

下来安装程序需要在后台完成,即不引起用户察觉,这就需要使用 shell 下的 pm 命令(Package

Manage),而 pm 命令需要 system 权限,故执行此操作时需要确保可以获取 root 权限。安装

一个指定程序可通过“pm installtarget_apk”实现。而执行 shell 命令利用 runtime.exec 即可

实现,可将其简单封装为 runCommand(String str)。

private void runCommand(String strCommand){

Runtime runtime = Runtime.getRuntime();

try { runtime.exec(strCommand);

} catch (IOException e) {e.printStackTrace(); }

}

综上,释放、安装的功能实现代码如下。

//Install the specified apk

public String installAPK(String apkFileName)

{

//获取 assets 中文件安装后的实际路径

String tmpDir =this.getApplicationContext().getFilesDir()+"/";

String apk_path = tmpDir+apkFileName;

//释放文件

dropFile(apk_path, apkFileName);

//安装的 apk 文件需要读写权限,故赋予读写权限

runCommand("su -c chmod 666 "+apk_path);

//使用 pm 安装文件

runCommand("su -c pm install -t "+apk_path);

return apk_path;

}

3)启动应用程序

启动应用程序可通过切换 Activity 实现,即调用主程序 A 的 MainActivity 就可实现启动

A 程序并切换界面为 A,该过程可通过如下几步实现。

①获取需要启动的 apk 的信息

具体包括 apk 的packagename 和MainActivity 名。对于宿主程序而言,由于捆绑器已成

功获取并将此信息写入了 config 文件,故只需要从 config 中分别读取这两个字符串即可。

②新建 intent

Intent intent = new Intent(Intent.ACTION_MAIN);

intent.addCategory(Intent.CATEGORY_LAUNCHER);

③切换 Activity,启动程序

ComponentName cn = new ComponentName(main_app,main_app_Acitivty);

intent.setComponent(cn);

startActivity(intent);

2.捆绑器程序

运行在 Windows 下的捆绑器程序主要是为宿主程序做准备:获取主程序 A 的

packagename 和MainActivity 信息,获取捆绑进去的程序 B 的 packagename;修改宿主程序

的图标,使其和程序 A 的一致;将准备好的宿主程序打包、签名等。下面将详述每个部分。

1)提取信息

需要提取的信息为应用程序的 Packagename 和 MainActivity 名,这些信息可以从 manifest

中解析,但更简单的办法就是使用现有工具 apktool。该工具可以对 apk 程序进行解包、打

包、提取信息等。具体的,提取信息仅需命令“aapt.exedump badging apk_name”即可。为

了方便应用,我们可以写一个专门提取信息的批处理脚本 aapt_apkinfo.bat,具体如下:

set PATH=%CD%;%PATH%;

"%~dp0\aapt.exe" dump badging %1 > %2

该批处理以“aapt_apkinfo.bata.apk info.txt”的方式调用,其中第一个参数为 apk 路径,

第二个参数为信息存储文件。在程序中则可以如下调用。

ShellExecute(NULL, TEXT("open"),szAaptCommand,szParameter, NULL, SW_HIDE);

其中,szAaptCommand 指向aapt_apkinfo.bat,szParameter 为参数 1 和参数 2 构成的字

符串,如“a.apkinfo.txt”。

由于此时获取到的信息如图 4 所示,内容太过冗余,我们需要从中解析出packagename

和 MainActivity。易知,此时得到的信息是按行存储的,即 info.txt 中的每行为一类或一条信

息 , 故 解 析 时 逐 行 判 断 即 可 。 其 中packagename 通 常 以 此 种 格 式 出 现 “ package:

name='com.tencent.mobileqq' ”, 可 以 认 为 package: name 之 后 的 单 引 号 内 的 内 容 为

packagename。mainactivity 的信息如图 5 所示,故同样易得其信息。相关文本搜索、字符串

判断等相关代码不再罗列。

QQ图片20140404160507.jpg (219.29 KB, 下载次数: 15)

2014-4-4 16:07 上传

图 4 利用 apt 从 apk 中提取的原始信息

QQ图片20140404160522.jpg (98.85 KB, 下载次数: 16)

2014-4-4 16:07 上传

图 5 info.txt 中 mainactivity 的格式

最后,通过上述方法将提取到的信息存入 assets 目录下的 config 文件中,供宿主程序使

用。

2)替换图标和标签

①获取图标和标签信息

考虑到安全性,需要对 host 程序进行必要的伪装,即重新打包后的 host 程序,安装后

在应用列表看上去要和 A 程序的一致,故还需要替换图标和标签。同理,通过上述方法,

可从 info.txt 中获得 label 和 icon 的信息,如图 6 所示。

QQ图片20140404160866666666666666666.jpg (70.56 KB, 下载次数: 15)

2014-4-4 16:10 上传

图 6 info.txt 中的 label 和 icon 信息

②替换图标和标签信息

在获得 icon 路径和 label 之后,接下来需要替换 host.apk 中的这些信息。

首先需要对主程序 A.apk 进行解包,以获得图标文件。Apk 解包同样使用 apktool。直

接使用 apktool 解包的命令为“java –jar apktool.jar –d apkpathunpackeddir”,其中 apktool 支

持很多参数,实现其他功能,方便起见将其封装为 bat 文件 unpack_apk.bat,内容如下。

set PATH=%CD%;%PATH%;

java -jar "%~dp0\apktool.jar" d %1 %2

该批处理的第一个参数为 apk 路径,第二个参数为解包后的目录路径。在捆绑器程序中,

可通过如下命令调用该批处理,实现相应的解包功能。

ShellExecute(NULL, TEXT("open"), szBatfilePath,szParameters, NULL, SW_HIDE);

其中,szParameters 即为批处理文件对应的两个参数。

在成功解包之后,替换图标就很简单了,只需要用上述 icon 路径对应的文件替换宿主

程序 host.apk 中的“\res\drawable-mdpi\ic_launcher.png”、 \res\drawable-hdpi\ic_launcher.png”、

“\res\drawable-ldpi\ic_launcher.png”和“\res\drawable-xhdpi\ic_launcher.png”文件。

宿主程序的标签信息位于“\res\values\strings.xml”中,具体如图 7 所示。

只需将其中的app_name 对应的值替换为前面获取到的 label 的值即可。

QQ图片20140404160910777777777777777.jpg (44.96 KB, 下载次数: 16)

2014-4-4 16:11 上传

图 7 宿主程序的 strings 文件内容

3)打包、签名

通过前面的步骤,我们已经成功修改好了宿主程序 host.apk,接下来需要对其进行打包、

签名。

①打包

对 APK 的打包,仍旧采用 apktool,将其封装成apk_apk.bat,内容如下。

set PATH=%CD%;%PATH%;

java -jar "%~dp0\apktool.jar" b %1

QQ图片2014040416131288888888888888.jpg (90.95 KB, 下载次数: 16)

2014-4-4 16:14 上传

其所需的唯一一个参数即为需要打包成 apk 的目录。类似的,程序中的调用方法依旧使

用“ShellExecute(NULL,TEXT("open"), szPackBatfile, m_szFinalApkDir, m_pctApkToolDir,

SW_HIDE);”。

②签名

对 apk 的签名,可通过使用工具 autosign 实现。其调用方式为“java -jar signapk.jar

testkey.x509.pem testkey.pk8 unsigined.apk signed.apk”,需要的两个参数为签名的文件路径和

成功签名后的文件路径。将其写为 sign.bat,内容为:“java -jar signapk.jar testkey.x509.pem

testkey.pk8 %1 %2”。在捆绑器程序中相应的调用方式为“ShellExecute(NULL, TEXT("open"),

szSignBatfile, szParameters, m_pctAutoSignDir, SW_HIDE);”,最终即可获得捆绑后的 apk 程

序。

总结

通过前面的步骤,最终生成了一套由“apktool”、“auto-sign”、“host.apk”和“捆绑器”

组成的 apk 捆绑器工具,如图 8 所示。

图 8 捆绑器工具组成(左)和捆绑器运行界面(右)

最终捆绑之后的 apk 应用程序具备和正常安装的 apk 一样的运行效果,但却能隐蔽的安

装所指定的任意 apk 文件,达到预期的目的和功能效果。

同时,在上述实现过程中仍存在一定的不足,如在安装捆绑之后的 apk 应用时,所显示

的权限和非正常安装的程序(主程序 A.apk)的权限不一致。一种更完美的方法则可以考虑

在修改 host.apk 文件时,同时将主程序 A.apk 的 manifest 中的权限也复制到 host.apk 的

manifest 中,有兴趣的读者可以自行尝试。

android开发apk捆绑,Android 下 APK 捆绑器的实现相关推荐

  1. android 获取wifi的ip地址吗,Android开发实现在Wifi下获取本地IP地址的方法

    本文实例讲述了Android开发实现在Wifi下获取本地IP地址的方法.分享给大家供大家参考,具体如下: 代码核心介绍: WifiManager类提供了对设备Wifi功能的管理,包括Wifi开关的打开 ...

  2. android禁止下拉刷新,Android开发之无痕过渡下拉刷新控件的实现思路详解

    相信大家已经对下拉刷新熟悉得不能再熟悉了,市面上的下拉刷新琳琅满目,然而有很多在我看来略有缺陷,接下来我将说明一下存在的缺陷问题,然后提供一种思路来解决这一缺陷,废话不多说!往下看嘞! 1.市面一些下 ...

  3. Android 开发工具集合 - (Android Dev Tools)

    收集整理Android开发所需的Android SDK.开发中用到的工具.Android开发教程.Android设计规范,免费的设计素材等. 欢迎大家推荐自己在Android开发过程中用的好用的工具. ...

  4. 全网最全Android开发工具,Android开发框架大全

    涵盖Android方方面面的技术, 目前保持更新. 时刻与Android开发流行前沿同步. 目录 一.工具 Android开发工具 在线工具宝典大全 二.框架 *缓存框架* DiskLruCache ...

  5. Android开发本地及网络Mp3音乐播放器(十二)创建NetMusicListAdapter、SearchResult显示网络音乐列表

    转载请注明出处:http://blog.csdn.net/iwanghang/article/details/51290181 觉得博文有用,请点赞,请留言,请关注,谢谢!~ 实现功能: 实现NetM ...

  6. 视频教程-快速入门Android开发 视频 教程 android studio-Android

    快速入门Android开发 视频 教程 android studio 任苹蜻,爱学啊创始人 & CEO,曾就职于某二车手公司担任Android工程师后离职创办爱学啊,我们的宗旨是:人生苦短,我 ...

  7. [android开发必备]Android开发者社区汇总

    [android开发必备]Android开发者社区汇总 经常收到很多人问做android开发去哪个社区,每次都回答的零零碎碎的很比系统,今天统一整理下,把截至目前为止有价值的android开发社区汇总 ...

  8. Android开发本地及网络Mp3音乐播放器(十三)网络音乐搜索功能实现,歌名歌手专辑名搜索

    转载请注明出处:http://blog.csdn.net/iwanghang/article/details/51298411 觉得博文有用,请点赞,请留言,请关注,谢谢!~ 实现功能: 实现网络音乐 ...

  9. Android开发工具视频Android 12(S)准备

    Android开发工具视频Android 12(S)准备 适配步骤 下载最新的Android studio工具,点我到官网下载最新的吧! 最新版的studio规定jdk使用必须至少11,所以请移步下载 ...

  10. 老罗Android开发视频教程( android解析json数据 )4集集合

    老罗Android开发视频教程( android解析json数据 )4集集合 老罗Android开发视频教程( android解析json数据 ) 第一集android解析json数据 http:// ...

最新文章

  1. WebClient.UploadValues Post中文乱码的解决方法
  2. android中设置ListView的选中的Item的背景颜色(附源码)
  3. VMware虚拟机安装Centos7
  4. netty源码分析之一:server的启动
  5. 七、SpringBoot整合elasticsearch集群
  6. 怎么把word转换pdf,pdf转换word ,pdf转换成高清图片
  7. ML.NET Cookbook:(4)如何调试实验或预览管道?
  8. (译) JSON-RPC 2.0 规范(中文版)
  9. python日志输入 print 常用格式化符号 logging 日志输出
  10. Qt绘制形状不规则窗口(二)
  11. 转:W10数字许可激活C#版v3.6 win10永久激活工具
  12. python爬取哔哩哔哩视频_python爬取哔哩哔哩小视频
  13. Collections、Set、Map、斗地主排序
  14. [爱奇艺]校招笔试(2017/9/11)
  15. PS制作六边形蜂窝状banner人物海报
  16. 【SpringBoot】之自定义 Filter 过滤器
  17. 学计算机专业的人,如何让别人明白“学习或从事计算机专业的人不一定会修电脑”,只是会秃头!...
  18. 【Arc GIS 零基础教学】这些常见的GIS数据格式你知道几个
  19. modelzoo,WDSR模型训练脚本问题
  20. 2017蚂蚁金服暑期实习生内推一面

热门文章

  1. 关于环境光、漫反射、镜面反射
  2. 计算机课反思的作文600字,中考反思作文600字6篇
  3. 详解汽车外饰行业如何利用MES系统进行生产防错?
  4. 儿童节html5小游戏,六一儿童节游戏大全,六一儿童节游戏有哪些
  5. 加息对股市影响利好还是利空
  6. 将lrc批量转换为txt,同时删除时间标签
  7. 西宾知乎语音下载工具(zhihudownload)
  8. linux终端联网网速慢,解决ubuntu 上网速度慢的问题
  9. 【数学建模】论文排版
  10. Kattis - battleship【模拟】