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

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
|
接下来,我们使用apktool工具反编译
1 2 3
| cd Naive apktool d ../Naive.apk -o xml -f 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的值,方法有两个
- 注意
return,即使你正确的输入了flag,这个程序将退出
接下来我们来说说远程调试apk
0x02 Android Studio环境准备
ADT的安装以及Android Studio的配置我就不多说了,补充一点,Android Studio要安装Smalidea插件
我们选择动态调试smali文件,他们在上文中xml文件夹中的smali文件夹中。

首先,我们将它拷贝出来,导入Android Studio工程

导入成功后,我们设置配置文件
点击工具栏下拉框的Edit Configurations

因为要用ddms调试,所以选择端口8700
打开虚拟机

打开ddms

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"> <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
|
打包过后要进行签名才能安装
1
| jarsigner -verbose -keystore 1.keystore -signedjar .\newapk\signed.apk .\newapk\new.apk key1 -digestalg SHA1 -sigalg MD5withRSA
|
1.keystore是我生成的签名文件,具体生成方法可以去百度~
最后一步,安装到虚拟机
0x04 开始调试
1 2
| adb shell $ am start -D -n com.suctf.naive/.MainActivity
|
我们会看到,ddms中com.suctf.naive进入了调试模式

虚拟机也进入等待调试器连接中

接下来点击调试按钮,在MainActivity$1.smali的66行下断点

在虚拟机中点击CHECK

在程序判断字符串equals时,监视变量v0和v1,v0是lib返回的字符串,v1是app输入的字符串

看,我们轻松的拿到了flagsuctf{Meet_jni_50_fun}
0x05 小结
多动手多实践,才能总结套路呀~最后还请各位大佬多带带我(o゜▽゜)o☆
Author:
Appl3s
Permalink:
https://appl3s.github.io/2016/12/05/taolu/
License:
Copyright (c) 2025 CC-BY-NC-4.0 LICENSE
Slogan:
Do you believe in DESTINY?