题目下载:re2.apk
关于Android Studio的使用一直不太熟悉,借着题目学习一下。
这里是Android Studio中NDK开发的官方文档。
将APK文件用JEB打开:
MainActivity中有这么一些代码,代码并不复杂,也没有混淆加密,逻辑大概是:有两个按钮,需要轮流点这两个按钮,奇数次点pong,偶数次点ping,总共要点100万次。还有一个关键是调用了pp
库,每次点击按钮会调用库中的ping()
和pong()
函数。
解决思路:新建一个项目,是通过编写代码,模拟点击,调用这两个库函数。
代码如下:
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
| package com.geekerchina.pingpongmachine;
import android.app.Activity; import android.os.Bundle; import android.util.Log;
public class MainActivity extends Activity {
static { System.loadLibrary("pp"); }
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); int p = 0; int num = 0; int ttt = 1000000; int tt = ttt; while (tt != 0) { if (tt % 2 == 0) { --tt; p = ping(p, num); ++num; if (num >= 7) num = 0; if (tt == 0) Log.d("FLAG:", "BCTF{MagicNum"+Integer.toString(p)+"}"); } else { --tt; p = pong(p, num); ++num; if (num >= 7) num = 0; if (tt == 0) Log.d("FLAG:", "BCTF{MagicNum"+Integer.toString(p)+"}"); } } }
public native int ping(int arg1, int arg2); public native int pong(int arg1, int arg2); }
|
需要注意的是项目的包名要与题目中的一致。
项目的关键向Android Studio中添加so文件,这里卡了好久,网上找了好多文章,没有一个成功的,真的不如eclipse方便。
后来不经意看到别人项目中的gradle文件内容才解决。
在src/main
下添加jniLibs/armeabi/xxx.so
删除build.gradle
中的
1 2 3 4 5
| externalNativeBuild { cmake { path "CMakeLists.txt" } }
|
build.gradle
完整的配置如下:
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
| apply plugin: 'com.android.application'
android { compileSdkVersion 24 buildToolsVersion "25.0.2" defaultConfig { applicationId "com.geekerchina.pingpongmachine" minSdkVersion 19 targetSdkVersion 24 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" externalNativeBuild { cmake { cppFlags "" } } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } }
dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) compile 'com.android.support.constraint:constraint-layout:1.0.2' testCompile 'junit:junit:4.12' }
|
从题目中解压出so文件放到自己创建的项目中(so库也没有加密或做其他处理,能够直接调用),运行程序,好长时间都没有结果。这时逆向so文件或在每次”点击”中加一个Log都行,我在”点击”中加了
1
| Log.d("pingpong", "tt:"+Integer.toString(tt))
|
监控tt的变化,发现Log打得很慢。用IDA打开so文件,发现ping()
和pong()
函数中都有一个sleep(1)
函数,只要NOP掉这个sleep就可以了。这里我犯了一个错误,sleep(1)对应的机器码是32位,我就改成mov r0, r0对应的ARM机器码00 00 A0 E1
了,结果程序运行不了。
其实这段代码对应的是Thumb指令,应该改成mov r0, r0对应的Thumb机器码,查机器码时我用的radare2的rasm2:
1 2
| $ rasm2 -a arm -b 16 'mov r0, r0' 0046
|
将sleep(1)的机器码改成00 46 00 46
,即两条mov r0, r0指令。将修改后的so文件放到项目中,再次运行项目:
最终得到FLAG: BCTF{MagicNum4500009}
补充:
最近看了一些Frida的用法,想自己用Frida解决一些问题,就选了以前做过的题目试试。之前用的patch的方法,这里借用来学一下Frida方法。
和上面一样,还是需要新建一个项目调用libpp.so,不过libpp.so不需要patch。
新建一个Frida脚本,hook so文件中调用的sleep函数,替换为自己的实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| setImmediate(function() { console.log("[*] Starting script"); Java.perform(function(){ var sleepPtr = undefined; imports = Module.enumerateImportsSync('libpp.so'); for (i = 0; i < imports.length; i++) { if (imports[i].name == "sleep") { sleepPtr = imports[i].address; break; } } console.log("[*] sleepPtr = " + sleepPtr); var sleep = new NativeFunction(sleepPtr, 'int', ['int']); Interceptor.replace(sleepPtr, new NativeCallback(function(t) { var ret = sleep(0); return ret; }, 'int', ['int'])); }); });
|
这里将so文件中的sleep调用替换为了sleep(0),达到的效果和patch是一样的。