android脱壳记录

记录一些手工和自动脱壳方法~

软件保护有多方面,如阻止程序被分析(如反调试),阻止程序被修改(如签名校验),加大分析难度(如代码混淆)等,而本篇的代码保护,主要是指在保证程序原有逻辑(功能)不变的前提下,对程序进行某种操作,使其不易被人类分析破解,这通常都是以效率换安全,传统的保护为加壳,即将要保护的代码作为一个整体进行某种操作(如加密)后存放,程序运行到被保护的代码前先对其进行逆操作(如解密)后再执行之,于是对这种保护的破解关键就是找到逆操作完成后保护代码执行前这个时间点,dump内存就可以拿到原数据,再进行修复就可以得到原始无保护的程序,再后来依据等效复杂化的思维出现了以代码(块)为单位的执行时解密与更复杂的代码虚拟化混淆等技术,极大的加大了分析难度,不过目前Android的Java层保护目前主要还在代码整体或以块为单位加密运行时解密这种级别,所以一般的脱壳思路也就是dump出程序解密后的dex,关键点也就是在什么时候dump这种问题了。

手工脱

xposed

作为一款hook框架,它当然不仅限于脱壳,它通过修改孵化器可以为所有进程注入hook核心,用户编写hook模块即可在不修改源程序的情况下钩取程序api实现钩取目的,遗憾的是它本身还不支持native层的hook,使用xposed最好使用真机,据说模拟器容易出现一些奇怪的问题,若要使用模拟器推荐雷电模拟器,它好装框架。

  1. 创建一个无界面的项目
  2. build.gradle的依赖中添加:
    1
    2
    provided 'de.robv.android.xposed:api:82'
    provided 'de.robv.android.xposed:api:82:sources'
  3. AndroidManifest.xml中添加
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <application
    <meta-data
    android:name="xposedmodule"
    android:value="true" />
    <meta-data
    android:name="xposeddescription"
    android:value="Easy example which makes the status bar clock red and adds a smiley" />
    <meta-data
    android:name="xposedminversion"
    android:value="82" />
    </application>
  4. 创建一个类:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    package com.example.wxjun.xposednew1;

    import android.util.Log;

    import de.robv.android.xposed.IXposedHookLoadPackage;
    import de.robv.android.xposed.XC_MethodHook;
    import de.robv.android.xposed.callbacks.XC_LoadPackage;

    import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;

    /**
    * Created by WxJun on 2018/8/10.
    */
    public class Test implements IXposedHookLoadPackage {
    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
    // if(loadPackageParam.packageName.equals("apk")) //通常都要在这里对包名过滤,否则将会对所有进程进行如下操作
    try{
    findAndHookMethod("android.content.res.Resources", //要钩取的函数所在类的全名
    loadPackageParam.classLoader, //一般不变动
    "getColor",int.class, //要钩取的函数名已经其参数
    new myGetColor()); //钩取操作
    }catch (Exception e){
    e.printStackTrace();
    }
    }
    }
    class myGetColor extends XC_MethodHook{
    @Override
    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
    //super.beforeHookedMethod(param); //钩取前一般是对参数进行操作
    Log.d("xposed","before");
    }
    @Override
    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
    // super.afterHookedMethod(param);
    Log.d("xposed","after");
    int res = (int)param.getResult();
    param.setResult(res& ~0x0000ff00|0x00ff0000); //钩取后当然是对结果进行操作了
    }
    }
  5. 创建assets目录,创建xposed_init文件,并在其中写入入口地址一行一个
    1
    com.example.wxjun.xposednew1.Test
  6. File -> Settings -> Build, Execution, Deployment -> Instant Run关闭
  7. 安装激活并重启

反射

对xposed模块编写的补充,Java作为面向对象的语言,在它的世界里万物皆对象,尽管对象是类的实例似乎类和对象并不是一回事,但是或许为了统一类也是对象,所有类都是Class的对象,所以对类也可以从对象角度对其进行处理。

怎么获得类对象?

准确的说是类类型(下面不再强调),有如下三种方法:

1
2
3
4
Foo foo = new Foo();
Class c1 = Foo.class; \\类用此属性
Class c2 = foo.getClass(); \\对象用此方法
Class c3 = Class.forName("foo"); \\这个需要处理异常

获取到类对象有什么用?

当获取到一个类对象,就能够像操纵普通对象一样操作它,于是首先回顾它有哪些功能与要素:

  • 作为一个类对象它应当是可以实例化为类的对象的
  • 一个类它里面应该是有构造方法的
  • 一个类他一般会有很多方法
  • 一个类一般他会有很多属性域

总的,它的要素包含自己声明的与从父类种继承的,同时除了构造方法各要素都或部分拥有自己名字,类型,返回值,参数等,当我们拿到一个类对象,理应能够获取到这些要素,调用这些功能,所以Class有如下常见方法:

1
2
3
4
5
6
c1.newInstance();   \\实例化对象,需要对其进行强制类型转换
Constructor[] cons = c1.getConstructors(); \\获取构造器
Method[] meth = c1.getMethods(); \\获取公开属性方法,包括从父类种继承的
Method[] meth = c1.getDeclaredMethods(); \\获取类自身定义的方法,不管属性是否为public
Field[] fields = c1.getFields(); \\获取公开属性
......

还有很多很多,它们也支持传入参数准确指定而为获取全部数组,一句话只要能想到的功能都有,现在获取到这些奇怪的东西能干什么呢?从设计的角度就能知道它们包含哪些内容能做哪些事,例如Method的对象:

  • 它表示一个方法对象
  • 它作为一个方法应该能被调用
  • 他应该有返回值类型
  • 他应该有方法名
  • 他应该有参数类型(参数可能有多个,这应该是一个数组)

理解这些,真正用的时候就可以很和逻辑的写代码了。

代码自修改

指令被放在每一个类方法的insns数组中,insns_size表明指令长度
Android运行时,解系Dex文件,并生成相关的结构体:DvmDex

工具脱

drizzleDumper

FDex2

通过Hook ClassLoader的loadClass方法,反射调用getDex方法取得Dex(com.android.dex.Dex类对象),再将里面的dex写出,代码十分简单,就hook了一个方法而已

使用环境:
1.安卓4.4以上的手机或模拟器
2.xposed
3.其它看软件提示
https://bbs.pediy.com/thread-224105.htm

可脱最新360壳

DumpDex

https://github.com/fooree/fooXposed/tree/master/DumpDex