因为兴趣广泛,我也做过一段时间的安卓开发,加之团队里的老司机们不是很熟练Android的动态调试,所以我总结一下现阶段我所使用的套路(~ ̄▽ ̄)~

taolu

0x00 资源准备

  • Android开发环境
    • Java环境(JDK)
    • Android Studio
    • ADT
    • Smalidea插件
  • 反编译工具
    • apktool
    • dex2jar 反编译classes.dex
    • jd-gui.exe 查看反编译的源代码
    • jeb反编译套件(可选)

0x01 举个栗子

熟悉安卓的dalao们晓得,apk其实就是一个zip压缩包,所以我们完全可以直接解压它

我电脑装了2345好压,为给后面的批处理做铺垫,所以使用了好压自带的解压命令

这个题目来自于suctf->Naive.apk

1
HaoZipc x Naive.apk -aoa -o CrackMe #将apk文件解压至目标文件夹

接下来,我们使用apktool工具反编译

1
2
3
cd Naive
apktool d ../Naive.apk -o xml -f #把这个apk文件进行反编译,目标文件夹xml
d2j-dex2jar classes.dex

运行jd-gui.exe打开classes-dex2jar.jar就可以看到源代码了
其中类MainActivity

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
42
43
44
45
46
47
48
package com.suctf.naive;

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

public class MainActivity extends AppCompatActivity
{
Button btn;
EditText flagText;
TextView hint;

static
{
System.loadLibrary("native-lib");
}

public native String getFlag();

public native String getHint();

protected void onCreate(Bundle paramBundle)
{
super.onCreate(paramBundle);
setContentView(2130968601);
this.hint = ((TextView)findViewById(2131492945));
this.hint.setText(getHint());
this.btn = ((Button)findViewById(2131492947));
this.flagText = ((EditText)findViewById(2131492946));
this.btn.setOnClickListener(new View.OnClickListener()
{
public void onClick(View paramAnonymousView)
{
if (MainActivity.this.getFlag().equals(MainActivity.this.flagText.getText().toString()))
{
Toast.makeText(MainActivity.this.getApplicationContext(), MainActivity.this.getFlag(), 1).show();
return;
}
Toast.makeText(MainActivity.this.getApplicationContext(), "Wrong!", 1).show();
}
});
}
}

阅读代码,我们可以得到一些信息,getFlag()返回了flag值,当你正确输入了flag,这个函数被调用。总结以下几点:

  • getFlag()函数定义于native-lib的so库中,要想得到flag的值,方法有两个
    • 动态调试apk
    • 逆向so库
  • 注意return,即使你正确的输入了flag,这个程序将退出

接下来我们来说说远程调试apk

0x02 Android Studio环境准备

ADT的安装以及Android Studio的配置我就不多说了,补充一点,Android Studio要安装Smalidea插件

我们选择动态调试smali文件,他们在上文中xml文件夹中的smali文件夹中。
as-1
首先,我们将它拷贝出来,导入Android Studio工程
as-2
导入成功后,我们设置配置文件
点击工具栏下拉框的Edit Configurations
as-3
因为要用ddms调试,所以选择端口8700

打开虚拟机
as-4
打开ddms
as-5

0x03 软件可调试准备

一般release版的apk是无法直接调试的,所以我们要更改AndroidManifest.xml文件开启debug并且重新打包

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.suctf.naive" platformBuildVersionCode="23" platformBuildVersionName="6.0-2704002">
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme" android:debuggable="true"><!--在application标签添加属性-->
<activity android:name="com.suctf.naive.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>

在application标签添加属性android:debuggable="true",然后重新打包

1
apktool b xml -o ..\newapk\new.apk #重新将xml文件夹打包成apk

打包过后要进行签名才能安装

1
jarsigner -verbose -keystore 1.keystore -signedjar .\newapk\signed.apk .\newapk\new.apk key1 -digestalg SHA1 -sigalg MD5withRSA

1.keystore是我生成的签名文件,具体生成方法可以去百度~
最后一步,安装到虚拟机

1
adb install signed.apk

0x04 开始调试

1
2
adb shell #进入adb远程shell
$ am start -D -n com.suctf.naive/.MainActivity #进入调试模式

我们会看到,ddms中com.suctf.naive进入了调试模式
as-6
虚拟机也进入等待调试器连接中
as-7
接下来点击调试按钮,在MainActivity$1.smali的66行下断点
as-8
在虚拟机中点击CHECK
as-9
在程序判断字符串equals时,监视变量v0和v1,v0是lib返回的字符串,v1是app输入的字符串
as-10
看,我们轻松的拿到了flagsuctf{Meet_jni_50_fun}

0x05 小结

多动手多实践,才能总结套路呀~最后还请各位大佬多带带我(o゜▽゜)o☆