Android SO(动态链接库)UPX加固指南
前言
随着移动互联网的爆发性增长,人们对移动应用的需求变得越来越复杂,企业在带给用户众多便利和享受的同时,却容易忽视应用自身的安全性问题,一旦遭受攻击,就会给企业和用户的经济或声誉带来影响。本文主要是站在企业的角度,阐述如何通过给android SO(动态链接库)加壳来提升移动APP的安全性,减少SO被逆向反汇编分析的风险。
注:本文只做单方面的总结,如果对整体提升移动应用安全性有需求的人员,可参考作者另外一份文档:《移动应用安全开发指南v1.0(Android)》。
撰写本文的目的:
1、 为移动应用开发人员提供安全加固技术指导,作为发布时加固的实际依据。
2、 对实施过程做详细的记录和总结,为需要单独创建加固环境的人员提供具体细节,避免或少走弯路。
建议使用方法:
对于需要创建加固环境的人员,请阅读“创建加固环境”章节,对于只需要在加固环境下对SO加固的人员(比如开发人员),只需了解“加固步骤”章节即可。
创建加固环境(X64 Linux)
1、下载UPX和依赖组件的源码
UPX -3.92-src:https://www.pysol.org:4443/hg/upx.hg/archive/tip.tar.gz
注:v3.92为写本文档时的最新官方非正式发布版本(正式发布版本为v3.91)
下载入口如下:
LZMA4.43:http://nchc.dl.sourceforge.net/project/sevenzip/LZMA%20SDK/4.43/lzma443.tar.bz2
UCL1.03:http://www.oberhumer.com/opensource/ucl/download/ucl-1.03.tar.gz
2、删除UPX壳描述信息
编辑$(UPX_SRC_ROOT)/src/packer.cpp,删除该文件中定义的关于UPX壳的相关描述信息(详情请参考附录à相关问题总结5.5)。
3、编译
3.1、编译zlib:
tar zxvf zlib-1.2.3.tar.gz
cd zlib-1.2.3
make //编译生成libz.a
cp libz.a /usr/lib64/libz.a //拷贝到系统默认的动态链接库路径下。
3.2、编译UPX并执行
cd $(UPX_SRC_ROOT) //进入UPX源码根目录
CXX=g++ UPX_UCLDIR=/home/soft/ucl-1.03 UPX_LZMADIR=/home/soft/lzma-4.43 UPX_LZMA_VERSION=0x443 make all //编译UPX
说明:UPX_UCLDIR和UPX_LZMADIR的值分别为UCL和LZMA解压后的根路径,UPX_LZMA_VERSION环境变量则指定了LZMA的版本。
编译成功后可在$(UPX_SRC_ROOT)/src下查看到可执行文件upx.out,如下图所示:
执行效果如下:
加固步骤
1、配置NDK集成开发环境
参考附录《配置和使用NDK集成开发环境》的《配置步骤》章节。
2、修改native代码
2.1、在native代码中定义全局变量用于增加生成的二进制的体积,例如:
C:int const dummy_to_make_this_compressible[100000] = {1,2,3};
C++:extern "C" int const dummy_to_make_this_compressible[100000] = {1,2,3};
注意:如果编译出来的库本身足够大,则此步骤可省略。
2.2、在native代码中声明_init()函数,用于在编译时生成_init段,例如:
C:void _init(void){}
C++:extern "C" {void _init(void){}}
注意:C和C++代码定义或声明的方式是有所区别的,在C++中必须使用extern “C”关键 字进行修饰,被extern "C"修饰的变量和函数是按照C语言方式编译和连接的
2.3、在native代码中使用宏定义混淆函数名,用于增加静态反汇编分析难度,例如:
#define startSimpleWifi sSW
#define sendData sD
……
3、对SO库文件加壳
3.1、打开cygwin,进入Android工程目录,在NDK环境中编译native代码(详情可参考 附录《配置和使用NDK集成开发环境》的《编译native代码》章节),也可以通过CDT 自动编译(参考《配置和使用CDT编译环境》),编译通过后将在libs目录下生成SO 动态链接库文件。
3.2、将编译生成的SO库文件上传到加固服务器(本文将其和UPX执行文件放同一目录), 如下图所示:
3.3、对SO库进行加壳,常用命令:upx.out –o libhello-jniupx.so libhello-jni.so
4、验证
4.1、在eclipse的Android工程中使用加壳SO替换原有的SO,如图所示:
4.2、将使用加壳SO的Android程序安装到设备或模拟器中执行功能验证,若各项功能均正 常则表示加固成功。
加固前后效果对比
1、加固前反汇编:
2、加固后反汇编:
附录
1、术语表
术语 |
定义 |
UPX |
UPX是一个著名的压缩壳,主要功能是压缩可执行文件(比如exe,dll和elf等文件),有时候也可能被病毒用于免杀。 |
加壳 |
加壳的全称应该是可执行程序资源压缩,是保护文件的常用手段。加壳的程序经常想尽办法阻止外部程序或软件对加壳程序的反汇编分析或者动态分析,以达到它不可告人的目的,这种技术也常用来保护软件版权,防止被软件破解。 |
交叉编译 |
就是在一个平台上生成另一个平台上的可执行代码,比如在X86 Linux上编译出可在ARM Linux上执行的程序。 |
JNI |
JNI是Java Native Interface的缩写,中文为JAVA本地调用,它允许Java代码和其他语言(比如C/C++)写的代码进行交互。 |
反汇编 |
把目标代码转为汇编代码的过程,也可以说是把机器语言转换为汇编语言代码、低级转高级的意思,常用于软件破解、外挂技术、病毒分析、逆向工程、软件汉化等领域。 |
2、配置和使用NDK集成开发环境
2.1、配置步骤:
2.1.1、http://www.cygwin.com/下载cygwin并双击安装。
2.1.2、选择从internet安装。
2.1.3、选择一种能连上网络的方式
2.1.4、建议选国内的镜像站点(速度快)
2.1.5、在search中输入”make”,选择Devel列表中的所有package进行安装,选择方法是点击package名,由keep变成install字样即可。注:本机已安装,故显示为reinstall。
2.1.6、继续下一步直至安装完毕。
2.1.7、运行cgywin bash,输入cygcheck -c cygwin命令,若显示Cygwin 的package信息则表 示运行正常。
2.1.8、分别运行gcc –version、g++ --version make –version和gdb –version来检查相关组件是 否运行正常。
2.2、编译native代码:
2.2.1、使用NDK编译一个程序,首先我们要找到我们cygwin的程序安装目录,找到一个 home\<你的用户名>\.bash_profile文件,如下图所示
2.2.2、在该文件末尾添加ndk=/cygdrive/<你的盘符>/<android ndk 目录> 例如: ndk=/cygdrive/f/android/adt-bundle-windows-x86-20131030/android-ndk-r9d
export ndk
注:"ndk"这个名字随便起,因为后面要经常使用,建议不要太长。如下图所示
2.2.3、之后重新打开cygwin,输入 cd $ndk,如果进入了android ndk 目录,证明环境变量 设置成功了
2.2.4、尝试使用NDK编译android NDK的样例程序hello-jni,路径为:
<android ndk 目 录>/samples/hello-jni,比如:
F:\android\adt-bundle-windows-x86-20131030\android-ndk-r9d\samples\hello-jni
2.2.5、进入工程根目录
2.2.6、执行$ndk/ndk-build命令,执行成功后它会自动生成一个libs目录,把编译生成的.so文件放里边,使用file命令可查看到文件为经过交叉编译的ARM Linux 动态链接库。
注:执行$ndk/ndk-build实际等于执行NDK目录下的ndk-build命令,如下图所示:
3、配置和使用CDT编译环境(非必须)
3.1、为eclipse安装CDT插件,也可以直接下载带CDT插件的eclipse(略)。
3.2、在eclipse中选择右键选中项目,选择Properties,在弹出的对话框中选择Builders。
3.3、点击对话框中的New新建一个编译器,在新弹出对话框中选择ProgramàOK。
3.4、对新建编译器进行配置,如下图:
参数解析如下:
Name:编译器的名字,可随便取。
Location: <你cygwin安装路径>\bin\bash.exe程序,即cygwin的bash程序的路径。
Working Directory: 你cygwin安装路径>\bin目录。
Arguments:给cygwin bash传递的参数,里面主要包含进入工程目录并使用NDK执行编译的命令。
3.5、接着切换到Refresh选项卡,给Refresh resources upon completion打上钩,如图:
3.6、最后切换到Build Options选项卡,勾选上最后三项,如下图所示:
3.7、点击Specify Resources按钮,选择资源目录,勾选你的项目目录即可,如下图所示:
3.8、保存配置后将回到Properties对话框,点右边的Up按钮,把它排到第一位,否则C代码的编译晚于Java代码的编译,会造成你的C代码要编译两次才能看到最新的修改,如图:
3.9、在eclipse中build Android工程,可以看到同时编译native代码并生成了SO库。
4、APK重打包流程
4.1、下载并安装APK改之理,下载地址:http://www.xiaomiren.net/
4.2、启动APK改之理,选择项目à打开APK 打开要重打包的APK程序。
4.3、打开成功后可看到原有的工程目录结构,打开libs目录可以看到APK需要载入的SO库。
4.4、删除要替换的SO,并把修改过的SO(比如经过加壳的SO)添加进来。
4.5、重新编译APK,即可安装到设备中运行并观察替换SO后的效果。
5、相关问题总结
5.1、编译UPX出现“cannot find -lz”错误。
分析:原因是链接器LD没有找到编译出来的zlib库libz.so或libz.a。
解决方法:将libz.so或libz.a拷贝到系统默认的动态链接库路径下,比如/usr/lib,/usr/lib64 等。
5.2、编译UPX出现“CantPackException: DT_TEXTREL found; re-compile with -fPIC”错误。
分析:这是早期NDK版本的BUG。
解决方案:使用NDK9或以上的版本
5.3、编译UPX出现“NotCompressibleException”错误。
分析:UPX对被加壳的二进制文件有最小限制,太小的文件将无法被加壳。
解决方案:在native代码中定义足够大的数据变量,使得编译出来的二进制文件容易达 到UPX的要求(参考《加固步骤》之《修改native代码》章节)。
5.4、编译UPX出现“UnknownExecutableFormatException”错误。
分析:被加壳的二进制文件必须存在init段,否则UPX将无法脱壳还原原始代码。
解决方案:在native代码中定义_init()方法,需要注意C和C++的区别(参考《加固步 骤》之《修改native代码》章节)。
备注:查看二进制文件是否存在init段的命令:readelf –dynamic xxx.so,如下图:
5.5、使用UPX加壳的SO,在eclipse中启动Android程序时出现”Fatal signal…”错误,如图:
分析:此错误是因为UPX解析某些特殊字符处理不当导致的,该BUG已经有人提交UPX 官方解决,但是当前官方正式发布的正式版本(V3.91)并没有fix该问题,而是在未正 式发布的V3.92才解决了该问题,因此本文档使用源代码版本为V3.92而非V3.91。
解决方案:下载使用V3.92源码,下载入口请参考《创建加固环境》章节。
5.6、为何删除UPX源码中的软件信息,以及如何定位查找这些信息。
分析:UPX对文件进行加壳时会把这些信息写入壳内,通过静态反汇编可查看到这些壳信息,进而寻找对应的脱壳机进行脱壳,使得攻击难度降低。
解决方案:在UPX源码中删除这些信息,并重新编译,步骤如下:
5.6.1、使用原始版本对文件进行加壳。
5.5.2、使用IDA反汇编加壳文件,在反汇编文件的上下文中查找UPX壳特征字符串, 如下图所示:
5.5.3、在UPX源码中查找这些特征字符串(建议使用Search and Replace),并一一删除, 如下图:
5.5.4、重新编译UPX(参考“创建加固环境”章节)。
5.7、在没有eclipse源码工程的情况下如何直接替换APK的SO并观察结果?
解决方案:参考《附录》之《APK重打包流程》,值得注意的是,如果Android程序中 内置了检查签名合法性的安全机制,使用该方法的前提是先破解该签名验证机制。
Android SO(动态链接库)UPX加固指南的更多相关文章
- 【文章内容来自《Android 应用程序开发权威指南》(第四版)】如何设计兼容的用户界面的一些建议(有删改)
最近一直在看的一本书是<Android 应用程序开发权威指南>(第四版),十分推荐.书中讲到了一些用户界面设计的规范,对于初学者我认为十分有必要,在这里码给大家,希望对我们都有用. 在我们 ...
- 《大话移动APP测试:Android与iOS应用测试指南》
<大话移动app测试:android与ios应用测试指南> 基本信息 作者: 陈晔 出版社:清华大学出版社 ISBN:9787302368793 上架时间:2014-7-7 出版日期:20 ...
- 推荐——Monkey《大话 app 测试——Android、iOS 应用测试指南》
<大话移动——Android与iOS应用测试指南> 京东可以预购啦!http://item.jd.com/11495028.html 当当网:http://product.dangdang ...
- 【腾讯开源】Android性能测试工具APT使用指南
[腾讯开源]Android性能测试工具APT使用指南 2014-04-23 09:58 CSDN CODE 作者 CSDN CODE 17 7833 腾讯 apt 安卓 性能测试 开源 我们近日对腾讯 ...
- Android开发之API应用指南
原文:http://android.eoe.cn/topic/android_sdk 编辑流程 这里主要是和Android技术相关的开发指南,很多都是来源于官方的API Guides( http:// ...
- 我的Android进阶之旅------>Android APP终极瘦身指南
首先声明,下面文字转载于: APK瘦身实践 http://www.jayfeng.com/2015/12/29/APK%E7%98%A6%E8%BA%AB%E5%AE%9E%E8%B7%B5/ APP ...
- Android Wear(手表)开发 - 学习指南
版权声明:欢迎自由转载-非商用-非衍生-保持署名.作者:Benhero,博客地址:http://www.cnblogs.com/benhero/ Android Wear开发 - 学习指南 http: ...
- 【开发必备】今天我们来谈谈Android NDK动态链接库(so文件)的一些见解
一.写在前面 直到现在,基本我写的每一个项目都会用到NDK动态链接库的知识,可见这个也的确十分常用.那么,今天,咱们就来谈谈它. 二.什么是ABI和so 1.发展 早起的Android系统几乎只支持A ...
- 一个神奇的控件——Android CoordinatorLayout与Behavior使用指南
CoordinatorLayout是support.design包中的控件,它可以说是Design库中最重要的控件. 本文通过模仿知乎介绍了自定义Behavior,通过模仿百度地图介绍了BottomS ...
随机推荐
- 自动化测试===requests+unittest+postman的接口测试
postman是一个跨平台的接口测试工具,下载链接在这里:https://www.getpostman.com/ unittest是一个单元测试框架,python中安装:pip install uni ...
- 2017多校第6场 HDU 6105 Gameia 博弈
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6105 题意:Alice和Bob玩一个游戏,喷漆!现在有一棵树上边的节点最开始都没有被染色.游戏规则是: ...
- [How to]如何自定义plist文件和读取plist文件内容
1.简介 plist作为IOS的固化文件,就好比java中properties文件,但是在IOS中plist是可读写的. 本文将介绍自定义静态的plist文件. 2.自定义静态plist文件 右击你的 ...
- Linux系统编程——进程间通信(一)
基本操作命令: ps -ajx/-aux/-ef 查看进程间状态/的相互关系 top 动态显示系统中的进程 nice 按照指定的优先级运行 /renice 改变正在运行的进程的优先级 kill -9杀 ...
- linux下查看机器配置
查看cpu信息:lscpu Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Byte Order: Little Endian CPU(s): ...
- SEO优化:WordPress站点地图(html和xml)插件Baidu Sitemap Generator
前阵子分享了<如何实现纯代码制作网站地图的html和xml版本>,不过不是每个人都喜欢用纯代码来折腾博客的.今天,boke112就给大家分享一款国人柳城制作的包含html和xml两个版本的 ...
- 搭建owncloud私有云
参考:教程1,教程2,教程3,教程4 硬件:raspi 3b+ 系统:UbuntuMate 步骤: 1.安装Apache2 sudo apt-get install apache2 完成后访问服务器地 ...
- php api接口校验规则示例
1.发送 /** * 客户端请求 * @param url 接口地址 * @param array $params(post) * @return json * @throws Exception * ...
- React Native学习
学习 首先,假使你已经安装了Nodejs 6,也有使用npm进行Nodejs的包管理 npm install -g react-native-cli 也可以使用yarn作为包管理工具 npm inst ...
- 区间DP(区间最优解)题目讲解总结
1:给出一个括号字符串,问这个字符串中符合规则的最长子串的长度. [分析]区间DP要覆盖整个区间,那么要求所有情况的并集. 先想出状态方程: dp[i][j]:i ~ j区间内最大匹配数目 输出:dp ...