Android逆向基础(XMAN DAY1)

Android原理

Android架构

  • linux kernel
    • 与linux的异同
    • adb
      # 基础操作
      adb devices //列出设备id
      adb shell //进入shell
      adb install xxx.apk //安装apk
      adb shell pm list packages // package manager,列出包名
      adb shell pm path com.tence01.mm //找到相应包名apk路径
      adb uninstall com.xxx.xxx //指明设备卸载apk
      adb pull /data/app/com.xxx.xxx.apk /apks/x.apk //取出apk
      adb logcat -s xxx // 指明标签为xxx的log输出
      # 调试有关
      adb shell ps // 查看进程
      adb forward tcp:8080 tcp:8000 //端口转发
      adb shell am start -D -n PackAgename.ActivityName 
      //activity manager,以调试方式启动应用 -D:指明调试 -n:指明启动参数的是包名+活动名 
      # 运行dex
      adb shell // 进入shell,并cd到相应目录
      delvikvm -classpath helloworld.dex HelloWorld 
    
  • 系统运行库
    • 程序库——Android包含一些C/C++库
    • android运行库——dalvik
      • dvm与jvm的异同
        • .dex将一堆.class封装,并减少冗余
        • dvm基于寄存器可用(0-65535)
        • jvm基于栈操作,四个常用寄存器
  • 应用程序框架
    • android SDK提供的
      • 视图
      • 内容提供器
      • 资源管理器
      • 通知管理器
      • 活动管理器
  • 应用
    • app——java与androidsdk的开发

      安卓应用也可以加载Jar,可以作为功能模块

编译java在android上运行

1. javac -source 1.6 -target 1.6 HelloWorld.java
# -source 指定用哪个版本的编译器对java源码进行编译.
# -target 指定生成的class文件将保证和哪个版本的虚拟机进行兼容。

2. dx --dex --debug --verbose-dump --output=helloworld.dex HelloWorld.class
# dx工具在 sdk/build-tools/版本号/ 目录中

3. push进安卓手机,adb shell 进入相应目录

4. dalvikvm -classpath helloworld.dex HelloWorld

二进制文件结构

dex文件结构

利用工具:010 Editor(win,mac,linux)进行分析。在菜单栏的templates中选择dex模板,可以自动分析dex文件结构,并可以在results窗口中查看分析结果。

image

apk文件结构

APK和Jar包一样,本质是Zip包

APK=DEX+资源+Manifest(+签名)

  • assets/
    资源文件夹,资源可任意存放,通过文件名来引用资源,文件不会被编译。
  • res/
    资源文件夹,资源需放在相应的子目录中,子目录只能有一层,且必须是预定义的。资源要通过R文件来引用,目录中的资源子目录除了raw外,其他资源目录中的资源文件都会被编译。
  • META-INF/
    工程属性文件夹,存放签名,工程信息以及资源校验hash。
  • lib/
    动态链接库so存放文件夹,分析so文件方法如下:
    • Readelf解析ELF文件
    • 链接视图 - IDA
    • 执行视图 - linker
  • AndroidManifest.xml
    工程基础配置属性文件。
  • classes.dex
    Dalvik字节码,DVM的可执行执行文件。程序的主体二进制文件。很多class集合成一个dex。

反编译

问题

如何将apk解析成代码

——反编译工具

字节码长什么样子

.method public onClick(View)V
          .registers 4
00000000  iget-object         v0, p0, b->a:MainActivity
00000004  iget-object         v0, v0, MainActivity->c:EditText
00000008  invoke-virtual      EditText->getText()Editable, v0
0000000E  move-result-object  v0
00000010  invoke-virtual      Object->toString()String, v0
00000016  move-result-object  v0
00000018  invoke-static       a->a(String)V, v0
0000001E  sget-object         v0, MainActivity->b:WebView
00000022  const-string        v1, "javascript:o0O0oo0o0o0o0oO()"
00000026  invoke-virtual      WebView->loadUrl(String)V, v0, v1
0000002C  return-void
.end method

语法

赋值操作
	const
	move-result
	new-instance
方法调用
	Invoke {参数},类->方法
数据类型
	简写为字母,对照关系如右

怎么修改字节码

——修改smali文件,保存,反编译打包,重新签名

工具

apktool

https://ibotpeaches.github.io/Apktool/

反编译dex为smali,以及反编译被编译过得资源文件。
$ apktool d xxx.apk foldername

打包修改过的文件,形成新的apk
$ apktool b foldername XXX.apk

dex2jar

https://sourceforge.net/projects/dex2jar/

反编译dex为java
$ dex2jar.bat classes.dex

JEB

https://www.52pojie.cn/forum.php?mod=viewthread&tid=556950

网上找到2.2.7破解版,需要配置jdk为1.8.0_31以下版本,否则会闪退。JEB集成了上述工具的功能,并且反编译结果较好。

Androidkiller(windows

链接:http://pan.baidu.com/s/1c1Ogeg4 密码:1nr6
参考:https://www.52pojie.cn/thread-650395-1-1.html

可以修改smali文件,改好后重新打包成新的apk并签名。还可以单独对apk进行签名。

调试与注入

调试的本质也是一种代码注入。等待debug源码。

IDA调试方法

http://blog.csdn.net/deathmemory/article/details/51489818

动态调试SO之在.init_array段下断点

http://blog.csdn.net/zihao2012/article/details/44226377

注入方法

xposed

Xposed框架是一款可以在不修改APK的情况下影响程序运行(修改系统)的框架服务,通过替换/system/bin/app_process程序控制zygote进程,使得app_process在启动过程中会加载XposedBridge.jar这个jar包,从而完成对Zygote进程及其创建的Dalvik虚拟机的劫持。

官网地址: http://repo.xposed.info/
源码地址: https://github.com/rovo89

Xposed安装

Android 6.0.x https://pan.baidu.com/s/1qY7oW36 密码:r3mh

  • 设备需要root
  • recovery 刷入 xposed-v78-sdk23-arm.zip
  • 安装xposed.apk
Xposed使用

打开Xposed Installer

  • 框架——安装、检查框架运行状态
  • 模块——列出当前可用模块以及状态
  • 下载——框架商店
  • 日志——Xposed中日志记录

注意:每次启用或者关闭模块均需要重启设备

Xposed模块开发

Xposed模块的安装包实际上就是一个有着特殊的AndroidManifest.xml和添加了XposedBridgeApi.jar包的apk文件,所以同样可以用Android Studio 来开发。同时我们在开发时需获取的目标(被劫持的)apk的信息有:

  • 包名
  • 类名
  • 函数名
  • 函数参数
LoginDemo
package com.example.xuanxuan.myapplication;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    private Button bt1;
    private EditText name1;
    private EditText password1;
    private final String ACCOUNT="xuanxuan";
    private final String PASSWORD="123456";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bt1 = (Button) findViewById(R.id.id_button);
        name1 = (EditText)findViewById(R.id.id_name);
        password1 = (EditText)findViewById(R.id.id_password);

        bt1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String username = name1.getText().toString();
                String password = password1.getText().toString();
                if(isOK(username,password)){
                    Toast.makeText(MainActivity.this,"login success",Toast.LENGTH_SHORT).show();
                }else{
                    Toast.makeText(MainActivity.this,"login failed",Toast.LENGTH_SHORT).show();
                }

            }
        });

    }
    private boolean isOK (String argc,String argv){
        return argc.equals(ACCOUNT)&&argv.equals(PASSWORD);
    }
}
HookDemo
  1. 新建一个不需要Activity的空白工程。
  2. 在空工程的java文件夹中新建一个类,该类就是一个模块类,这里命名为“Module”。
  3. 配置AndroidManifest.xml,其中的meta-data内容要照搬。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.xuanxuan.hackdemo">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme" >
        <meta-data
            android:name="xposedmodule"
            android:value="true"/>

        <meta-data
            android:name="xposeddescription"
            android:value="Hook Test!"/>

        <meta-data
            android:name="xposedminversion"
            android:value="54"/>
    </application>
</manifest>
  1. 在main文件夹下创建一个assets文件夹,并在里面创建一个名为“xposed_init”的普通文件,在里面添加一句字符串,即包名+模块类名,如com.example.xuanxuan.hackdemo.Module
  2. 新建一个名为lib的文件夹,注意不是libs。然后放入XposedBridgeApi.jar包,并在该jar包上右键Add as Library。并且在project structure中设置这个jar包为非complie模式,否则会在运行时冲突。

XposedBridgeApi.jar下载地址:
https://forum.xda-developers.com/xposed/xposed-api-changelog-developer-news-t2714067

  1. 编写模块类Module.java
package com.example.xuanxuan.hackdemo;

import android.util.Log;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;

/**
 * Created by xuanxuan on 2018/1/15.
 */

public class Module implements IXposedHookLoadPackage{


    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
        if(loadPackageParam.packageName.equals("com.example.xuanxuan.myapplication")){   //包名
            XposedHelpers.findAndHookMethod(
                    "com.example.xuanxuan.myapplication.MainActivity",  //类名
                    loadPackageParam.classLoader,
                    "isOK", //函数名
                    String.class,
                    String.class,   //函数参数
                    new XC_MethodHook() {
                        @Override
                        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                            XposedBridge.log("账号:"+(String)param.args[0]+"   密码:"+(String)param.args[1]);
                            Log.d("zz","账号:"+(String)param.args[0]+"   密码:"+(String)param.args[1]);
                        }

                        @Override
                        protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                            Log.d("zz", param.getResult().toString());
                        }
                    });
        }
    }
}

说明:

  • Module继承了IXposedHookLoadPackage接口,当系统加载应用包的时候回调 handleLoadPackage;

  • XposedHelpers的静态方法findAndHookMethod就是hook函数的的方法,其参数对应为:

    1. 类名,必须要有包名前缀,即“packageName+className”
    2. loadPackageParam.classLoader,有壳的例外:http://www.mamicode.com/info-detail-1705499.html
    3. 方法名
    4. 参数类型(根据所hook方法的参数的类型,即有多少个写多少个,加上.class)
    5. XC_MethodHook回调接口

如果代码被混淆过,即使你明知道代码中要hook的类名和方法名,但都不一定能用,必须以smali中的名字为准,比如:isOk()混淆之后在smali中的函数名为a,那么hook的时候就必须写a,而不是isOK,第一个参数类名同理!

  • 参数里有一个监听类XC_MethodHook,该类在hook前后回调,通过回调方法的MethodHookParam可以拦截到函数参数。
  1. 打包 Build->Generate Signed APK生成一个APK,并安装在手机,重启。即可在Xposed日志中查看到被记录的登录信息。

Xposed模块编写的那些事
http://www.freebuf.com/articles/terminal/114910.html

frida

https://www.jianshu.com/p/ca8381d3e094

混淆

java:proguard、dexguard、ZKM
c/c++:o-llvm

加壳

加固原理:反编译器毕竟不是运行时的虚拟机

第一代

加密隐藏真实dex,运行时动态加载
脱壳方法:通过各种办法得到在加载dex时的地址和长度

  1. http://blog.csdn.net/deathmemory/article/details/51489818
  2. hook:xposed(延时启动)+frida(hook libart.so中的加载函数)

第二代

内存里不再有完整DEX结构
脱壳方法:dexhunter

第三代

编译为未知语言解释执行
脱壳方法:

参考

android基本架构
https://www.cnblogs.com/lijunamneg/archive/2013/01/18/2866953.html

Android Dex文件结构解析
http://blog.csdn.net/feglass/article/details/51761902

Android 6.0.x 系统安装xposed框架
http://blog.csdn.net/u011303443/article/details/51031170

XPosed入门与登陆劫持演示
https://www.csdn.net/article/2015-08-14/2825462

Android逆向分析之Xposed的hook技术
http://blog.csdn.net/qq_18870023/article/details/51753587

IDA Pro Android 静态分析
https://www.52pojie.cn/thread-672885-1-1.html

IDA 调试 Android 方法及简单的脱壳实现
http://blog.csdn.net/deathmemory/article/details/51489818