Android so库加固加壳方案

2018-01-06

Android so库加固加壳方案

Android应用主要包含资源文件和代码,而代码一般包括Java代码和C/C++代码。Java代码编译后会生成dex文件,而C/C++编译后会生成so文件。Android应用的保护,主要对编译后的dex文件和so文件来保护,防止被别人反编译查看到里面的核心代码和逻辑。

对于Java代码,一般在编译时做代码混淆,编译后的文件名,函数名和变量名会变成一些无意义的名字,这个即使代码被反编译出来,也很难读懂。不过由于调用关系和逻辑都还在,花些时间还是有可能读懂。所以就有了一些防止反编译的方法出现。这就包括了dex加壳或者加密方法。对dex文件保护的方法现在有不少成熟的方案,有不少第三方公司免费提供加固方案。

对于C/C++代码的保护方案,会比Java代码的更麻烦一下。C/C++经过编译后生成so文件,这个so文件同样会能被反编译。由于我们的主要算法都采用C/C++来实现,并生成so文件提供给合作方使用,我们重点说的是C/C++代码和so文件的保护。

对于so文件的保护,可分为有so源代码和无so源码的情况。

有源码保护

针对有源代码的情况,可以大致分为代码混淆,Section或者函数加密。

代码混淆

代码混淆最简单的方法就是利用宏定义混淆函数名。例如通过一个宏定义把一个有意义的函数名变为一个无意义的字母组合,在编译后有意义的函数名就被替换为无意义的字母组合,增加了被反编译后阅读理解难度。当然这种方法效率太低,最好当然是编译器来做。NDK编译工具并没有提供这种混淆的功能,但是可以利用LLVM-Obfuscator功能来混淆代码。LLVM-Obfuscator是一个开源的专门用于代码混淆的工具。在Android的NDK编译工具中可以集成LLVM-Obfuscator,需要修改交叉工具链的代码和一些配置参数,可以编译出混淆代码。现在网上也有一个专做这种混淆的方案商 叫Safengine。

Section或者函数加密

so库是一个ELF文件,它是有一定的格式的,包含了ELF header,若干Section header,若干section等。我们可以在代码中将核心函数定义在自定义的一个section中 (通过 __attribute__ ((section (".mytext")))) 。然后编译出来的so文件中就能找到这个自定义的section。我们可以对这个section进行加密。当程序load这个so库的时候,我们需要确保在main函数之前把section部分解密了。解密函数代码是写在so的源代码里,为了确保解密函数优先于main函数,需对加密函数加了一个 __attribute__((constructor))特性声明,会先于main前执行。解密函数需要先找到so的起始地址,获取到section的偏移值和size,然后修改内存操作权限和解密。

对于特定的函数加密,原理跟对自定义section加密的原理是一样,只不过是查找不再是section,而是特定函数名。这里不再展开。

无源码保护

对于只有so库,没有其源码的情况下,就无法进行代码混淆。一种简单的方法是破坏ELF header或者删除Section header。因为在动态库的链接过程中,so文件ELF header某些字段是无用的,这些字段可以随意修改。修改了这些字段会导致反编译软件ida打不开这个so文件。同样Section header也是在链接过程中是没有用到的,可以随意删除,也会导致ida打不开这个so文件。不过这种方式容易被修正和破解掉。

还有另外一种方式需要另外一个解密so库来实现。首先对源码so文件特定函数或者section进行加密,然后把解密函数放到另外一个so中。然后程序中需先加载被加密的so文件,然后加载解密so文件,解密so文件加载过程中就执行解密函数,这样确保加密的so中特定函数或者section解密了。

第三方解决方案

对于so文件或者apk文件加固加壳保护方法,是比较专业的领域,现在市场上也有一些专门的团队在做。不过主要提供的方案都是针对apk来加固加壳。对于dex文件的加固加壳方案比较成熟,不少第三方都是免费提供。但是对于so文件的加固加壳,都是属于高级功能,需要付费使用。

对于apk(主要是Java代码)加固加密提供第三方服务主要有:

  • 腾讯云应用乐固
  • 阿里聚安全
  • 360加固保
  • 爱加密

要做so文件的加固加壳,乐固暂时没有对外提供,阿里聚安全需要先付费。爱加密也提供了so文件的加固加壳,还提供专门的SDK加密方案,不过需要先找他们的人对接洽谈。

总的来说,要做好so文件的加固加壳保护并不是件容易的事,需要对so文件格式,so加载和链接过程有足够多的了解。另外加固和加壳后也不是绝对安全的,还是有可能被破解。不过加固和加壳对于核心算法还是需要的,加大被破解的难度和成本。有需要的话也可以采用第三方的服务。

参考资料

Android LLVM-Obfuscator C/C++ 混淆编译的深入研究

SO(ELF)文件格式详解

基于对so中的section加密技术实现so加固

基于对so中的函数加密技术实现so加固

简单粗暴的so加解密实现

无源码加解密实现 && NDK Native Hook

另一种无源码的so加壳实现

Android SO 加壳(加密)与脱壳思路

android-加固方案对比

Category: Android Tagged: 动画 加固 加壳

comments


Android下载器开发

2015-07-18

Android下载器开发

最近因为项目需要,我开发了一个Android下载管理器,我觉得很有必要记录一下,谈谈我是怎么开发的,遇到了什么问题以及如何解决的。算是一个总结吧。

需求分析

我们项目包含了一个功能:将文件下载手机上,并且要支持断点下载,因为我们下载的文件主要是图片和视频,其中视频基本上都是大文件,然后下载可能随时会被中断,所以首要一点就是要支持断点续传,然后要支持任务管理,例如暂停下载和继续下载,再然后就是要下载速度尽量快。不过这最后一点估计所有人都会这样要求。

为什么要自己开发

需求已经较清楚了,然后再看怎么实现。一般来说,像下载这么通用的功能,因为很多开源库可用才对。不过在开始之前我要说明一下,这个功能一开始不是我做的,是另外一个同事负责的,但是他离职了,我来接手。问题在于他离职之前这个功能算是实现了,但是很多问题,例如断点续传有问题,任务管理有问题,下载速度很慢。我接手之后,我特意去网上查找了有没有可用的较好的开源库。经过一轮搜索之后,我发现,很多博客上介绍的下载都是同一下载,就是黎活明老师的下载,估计这个下载是他讲课的案例,主要特点是多线程断点下载。而我们之前那个同事的实现就是把网上的例子弄来的。他这个下载确实还可以,支持断点下载,还支持多线程分片下载来提高下载速度。不足之处就是不支持任务管理,还有数据库很容易出现多线程问题。也就是说核心的东西它有了 ...

Category: Android Tagged: Android Download

comments

Read More

Android图片缓存和相关开源项目

2015-05-16

Android图片缓存和相关开源项目

现在几乎所有大一点的Android项目都会用到图片缓存。而Android应用的内存占用大户就是图片,几乎所有内存问题都会涉及到图片问题,而已图片为主的应用也会涉及到性能问题。我觉得每一个资深的Android工程师都要对图片缓存技术有所了解,并且有自己想法。图片缓存是在面试别人时必问的问题。

图片缓存可以分为两点:内存缓存和磁盘缓存,当然还有必然要涉及的图片解码,图片下载,这里主要讲讲内存缓存和磁盘缓存,附带说一下图片解码和下载。

内存缓存

由于一张图片基本上会被重用或者在多个界面显示,而图片的下载和解码都是比较耗时的动作,要给用户比较好的体验,将一张图片缓存在内存中就尤为必要。如果一个应用图片比较多,要将所有图片都缓存在内存中显然不现实,特别是比较低端的机器上,内存非常有限。所以这个内存缓存必然有所限制,那么问题来了,缓存池设置多大,并且满了之后怎么处理成了要点。我们知道Android系统中给每个应用设置了最大堆,超出了这个最大堆限制就会报OutOfMemory错误。所以一般就是根据这个最大堆来设置图片缓存池的大小,业内普遍做法是取最大堆内存的8分之一,这个经验值,我觉得可以应用情况做调整。而缓存池满了之后该又要加入新的图片,怎么对已在池中的图片移除,有很多方法。最常用的是LRU(least recently used)算法。我一般会问面试者这个算法是怎么实现的,看过代码的人或者算法学得比较好的人就能答出。还有用的比较多大算法是使用频率算法,移除最大图片算法等。然而我认为比较好的内存缓存技术还应结合弱引用来用。这里涉及到什么事强引用,软引用和弱引用也是我必考项。为什么还要结合弱引用来使用比较好呢?如果一个应用要显示的图片比较多 ...

Category: Android Tagged: Android源码学习 图片缓存 ImageLoader Fresco

comments

Read More

Android开发中何时使用多进程?

2015-03-10

问答-Android开发中何时使用多进程?

我在github上回答了一个问题: Android开发中何时使用多进程?

1.要想知道如何使用多进程,先要知道Android里的多进程概念。一般情况下,一个应用程序就是一个进程,这个进程名称就是应用程序包名。我们知道进程是系统分配资源和调度的基本单位,所以每个进程都有自己独立的资源和内存空间,别的进程是不能任意访问其他进程的内存和资源的。那如何让自己的应用拥有多个进程?很简单,我们的四大组件在AndroidManifest文件中注册的时候,有个属性是android:process,这里可以指定组件的所处的进程。默认就是应用的主进程。指定为别的进程之后,系统在启动这个组件的时候,就先创建(如果还没创建的话)这个进程,然后再创建该组件。你可以重载Application类的onCreate方法,打印出它的进程名称,就可以清楚的看见了。再设置android:process属性时候,有个地方需要注意:如果是android:process=":deamon",以:开头的名字,则表示这是一个应用程序的私有进程,否则它是一个全局进程 ...

Category: Android Tagged: 技术问答 github 进程

comments

Read More

Android源码学习之ViewGroup

2015-02-02

Android源码学习之ViewGroup

android继承于View,同时它包含了一个View数组存储它的子View,也就是说它是一个容器。这就是经典的设计模式中的组合模式。在Android的视图结构中,容器一定是ViewGroup,只有ViewGroup才能包含其他视图,像TextView,ImageView这些View是不能包含子视图的,它们是单一控件。这一点跟iOS的视图结构很不一样的。在iOS中所有的视图都是继承于UIView,同时UIView也是一个容器,能包含其他UIView。从这一点来说iOS的视图结构更简单。

是什么使得ViewGroup具有了容易功能呢?ViewGroup除了继承View外,还是实现了两个接口:ViewManagerViewParent。ViewManager主要定义了addView和removeView的方法,ViewParent主要定义了刷新容器的接口requestLayout和其他一些焦点事件的处理等接口。除此之外,还有非常重要的一点,ViewGroup是一个抽象类。我们知道View并不是抽象类,为什么ViewGroup继承了View反而成了抽象类呢,是增加了什么新的抽象方法吗?不是,ViewGroup中的抽象方法是继承于View的onLayout方法。onLayout方法在View中并不是抽象方法,只是一个空方法,但是在ViewGroup中它被定义为了抽象方法。我第一次发现原来还可以这样做。onLayout的主要作用是放置子View的位置,而不同的布局方式算法不一样,所有留给子类实现比较合理。

ViewGroup中并没有覆盖onMeasure方法,但是增加了一些计算子View大小的方法:measureChildren方法就是将所有的子View都遍历一遍,并调用他们的measure方法。ViewGroup中同样没有覆盖onDraw方法,但是覆盖了dispatchDraw方法。dispatchDraw方法主要作用是调用每个子View的draw方法。看来onXXX方法在ViewGroup中并不重要,它更多的在调用子View的方法。

LayoutParams

布局参数LayoutParams是ViewGroup的一个重要内部类 ...

Category: Android Tagged: Android源码学习 ViewGroup

comments

Read More

Android源码学习系列开篇

2014-12-20

Android源码学习开篇

最近一直觉得自己后劲不足,很多想做的效果都觉得很艰难,不知道怎么下手。从很早的时候我就想学习Android源代码。第一次下载Android的源代码是2011年四季度的时候,那时候在公司的电脑上安装了Linux系统,也把源码下载下来了。但是后来一段时间后,我离开那个公司。后来几年时间都没有下过Android源码,因为一直在Android和iOS直接切换开发。不过我确实下载了Android SDK源码。其实一般的应用开发只要了解Android SDK开发就够。这些年断断续续看过一些SDK的源码。

这段时间,我终于下定决心要好好学习一下Android源码,原因之一是我拥有了一部自己的MacBook Pro,不再为电脑而烦恼。为了下载Android源代码,我试了很多方法下载,人生第一次为软件付费,买了一个VPN。但是我电脑硬盘比较小,源码很大,我下载了好几次要么下载到一部分就中断了没法继续下载,要么是我的电脑磁盘装不下。。最后我还是在百度网盘下载了一个别人已经下载好的。

当然我的学习还是以framework的源码为主,然后逐渐往底层学习。要学习framework根本不必下载Android源码,直接下载Android SDK的源码就行,Google提供的SDK Manager就有下载源码功能,然后在Eclipse或者Android Studio关联即可。为了鞭策自己学习,我决定写一个自己Android源码学习系列文章,记录自己的学习心得。另外最近作为面试官,面了一些Android的求职者,感觉很多人都是满足实现功能,不能自己去探究实现原理。想当年自己也是这样。越早摆脱这种情况,越有优势。

Category: Android Tagged: Android源码学习

comments

Read More

Android源码学习之View

2014-12-20

Android源码学习之View

在Android中,View是所有视图控件的基类。Android的视图控件的设计采用了经典的设计模式--组合模式。View是基础控件,而ViewGroup是可以包含子View和管理子View的空间,ViewGroup同时也是一个View。这跟iOS的视图空间设计有很大不同。在iOS的视图框架中,所有视图都是继承UIView,而UIView本身是可以包含和管理子UIView的。我不知道这两种设计有什么优劣,感觉iOS的设计更简单直接。

View的源代码超过2万行,当然包括了很多注释。这里面定义了很多基本的方法,主要是视图渲染的相关方法和事件的相关方法,不过有一点我不是很明白的就是里面有不少是根scrollbar相关的方法。我们实际应用中貌似有scrollbar的控件貌似只有AdapterView的子控件,ScrollView和TextView,scrollbar的特性为什么不直接放到这些类中,或者专门为这些类专门建立一个父类来处理scrollbar。View中的scrollbar特性应该大部分视图控件都不需要吧。当然这些只是我的疑问罢了,Google这样设计也许有他的道理。

重要方法

一个View要渲染到屏幕上,有几个重要的方法:

  • onMeasure系方法
  • onLayout系方法
  • onDraw系方法

onMeasure系方法

每一个onXXX方法又有若干个相关XXX方法。例如onMeasure方法,相关的方法是measure(int widthMeasureSpec, int heightMeasureSpec)方法,setMeasuredDimension(int measuredWidth, int measuredHeight)方法,MeasureSpec内部类。其中measure(int widthMeasureSpec ...

Category: Android Tagged: Android源码学习 View

comments

Read More

快速滚动条(FastScroll)的定制

2014-11-27

最近项目中因为要做定制快速滚动条功能而研究这块,发现还不是那么好做。

我首先找了网上有类型功能应用,暂时只发现小米自动相册和腾讯的相册管家做了这个功能。然后网上找快速滚动条的定制的相关资料。最后发现只能通过style或者反射机制去改变快速滚动条,而且能改的东西非常有限----只能替换图片。但是小米和腾讯为什么能定制的那么好呢?小米可能是系统层面上改的,那腾讯的总不能也是吧。我只能去下载相册管家的包来反编译了。

经过我反复看他们的代码和资源文件,终于找到了相关的类--ExpandableListView,这个跟系统的ExpandableListView不是同一个,只是单纯的名字相同而已。因为代码混淆过了,我花了很大力气虽然看懂了个大概,却是,没办法完全搞清一些细节性的东西。原理大致是这样:他们并没有去定制FastScroll,而是自己生成了一个叫ScrollPanel的View,然后把这个View画上去,并且对这个View设置了OnTouchListener,对用户的触摸事件处理,拖动的时候不断去滚动ListView,实现类型FastScroll的效果。

由于它们的源代码混淆了很多细节看不了,我只好去参考系统的FastScroll源代码。虽然大致看懂了,但是自己去实现的时候,还是达不到想要的效果。因为时间和精力问题,我现在只能暂时放一放,之后有时间再研究,实在不行我心里也有其他曲线救国的方案可以试试。

今天发现了一个类型功能的库,很不错。记录一下.

QuickScroll

Category: Android Tagged: Android View Scroll

comments

Read More

自定义DateView控件

2014-11-21

最近因为项目需要自定义一个日期控件,我花了一个多小时写了这个控件。虽然跟设计效果图还有点细微差别,但是这个可以慢慢修改。

效果图1 效果图1

    public class DateView extends View {

    private static final int DAY_TEXT_SIZE = 32;
    private static final int MONTH_TEXT_SIZE = 16;

    private int mDay;
    private int mMonth;
    private int mYear;

    private TextPaint mDayPaint;
    private TextPaint mMonthPaint;

    public DateView(Context context) {
        super(context);
        initView();
    }

    public DateView(Context context, AttributeSet attrs) {
        super ...

Category: Android Tagged: Android 自定义控件 日期控件

comments

Read More

Android Activity动画

2014-11-03

Android 动画(一)

3.0之前的动画

Android动画一直是Android的痛点。Android的动画系统跟iOS系统的动画系统比起来真心差很多,特别是2.3之前。在2.3之前,Android的动画分两种,帧动画和逐渐动画(Tween).Tween动画包括alpha动画,translate动画,scale动画,rotate动画。这几种动画可以随意组合,产生更复杂的动画。但是我们想要做iOS的frame那样简单的动画,却是没有直接的方法。


3.0之后的动画

在Android3.0版本,终于加入了更多的动画支持,API也更加友好。加入我property动画和value动画,大大增加了动画的灵活性和可定制性。可以通过ObjectAnimator很方便的写出动画代码。像iOS的frame动画,可以通过value动画来实现。还有因为property特性,可以实现一些特别的动画,并且不局限与view,理论上任何object都可以实现property动画。

nineOldAnimation

这个是向下兼容的Android动画库,使得在3.0之前的系统也可以实现property和value动画。不过这个库早已不维护了,我之前使用发现了一些bug,不过这影响不大。如果要兼容2.3和一下系统,这个是很不错的库。

Android4.4和5.0 ...

Category: Android Tagged: 动画

comments

Read More
Page 1 of 1