题目描述:
给了一个Android的apk文件
安卓上安装一下,运行截图:
由运行截图可以看出,这个程序是要求把时间耗尽,才会出flag,所以思路是修改时间(找到数字200000)。
得到编译过后的文件,文件夹下内容为:
打开AndroidMainfest.xml,其文件表示其主要活动问MainActivity:
找到lib文件夹下的.so文件,IDA打开提示有两种模式,经过一番折腾没效果:
package net.bluelotus.tomorrow.easyandroid;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
int beg;
int k;
int now;
long t;
static {
System.loadLibrary("lhm");
}
public MainActivity() {
super();
this.beg = (((int)(System.currentTimeMillis() / 1000))) + 200000;
this.k = 0;
this.t = 0;
}
public static boolean is2(int arg4) {
boolean v1 = true;
if(arg4 > 3) {
if(arg4 % 2 != 0 && arg4 % 3 != 0) {
int v0 = 5;
while(true) {
if(v0 * v0 <= arg4) {
if(arg4 % v0 != 0 && arg4 % (v0 + 2) != 0) {
v0 += 6;
continue;
}
return false;
}
else {
return v1;
}
}
return false;
}
v1 = false;
}
else if(arg4 <= 1) {
v1 = false;
}
return v1;
}
protected void onCreate(Bundle arg7) {
super.onCreate(arg7);
this.setContentView(2130968600);
View v2 = this.findViewById(2131492944);
View v3 = this.findViewById(2131492945);
Handler v0 = new Handler();
v0.postDelayed(new Runnable(((TextView)v3), ((TextView)v2), v0) {
public void run() {
MainActivity.this.t = System.currentTimeMillis();
MainActivity.this.now = ((int)(MainActivity.this.t / 1000));
MainActivity.this.t = 1500 - MainActivity.this.t % 1000;
this.val$tv2.setText("AliCTF");
if(MainActivity.this.beg - MainActivity.this.now <= 0) {
this.val$tv1.setText("The flag is:");
this.val$tv2.setText("alictf{" + MainActivity.this.stringFromJNI2(MainActivity.this.k) + "}");
}
if(MainActivity.is2(MainActivity.this.beg - MainActivity.this.now)) {
MainActivity.this.k += 100;
}
else {
--MainActivity.this.k;
}
this.val$tv1.setText("Time Remaining(s):" + (MainActivity.this.beg - MainActivity.this.now));
this.val$handler.postDelayed(((Runnable)this), MainActivity.this.t);//延时函数
}
}, 0);
}
public boolean onCreateOptionsMenu(Menu arg3) {
this.getMenuInflater().inflate(2131558400, arg3);
return 1;
}
public boolean onOptionsItemSelected(MenuItem arg3) {
boolean v1 = arg3.getItemId() == 2131492959 ? true : super.onOptionsItemSelected(arg3);
return v1;
}
public native String stringFromJNI2(int arg1) {
}
}
//加200000
this.beg = (((int)(System.currentTimeMillis() / 1000))) + 200000;
//之后的减法操作,小于0则打印出flag
if(MainActivity.this.beg - MainActivity.this.now <= 0) {
this.val$tv1.setText("The flag is:");
this.val$tv2.setText("alictf{" + MainActivity.this.stringFromJNI2(MainActivity.this.k) + "}");
}
这个操作会在其项目文件夹下生成一个dist文件夹,文件夹下就是新打包的apk:
对于反编译的apk,我们可以通过jarsigner(存在于Java JDK的安装包中,配好Java环境,可以直接在命令行使用)来对它进行签名。
签名需要keystore文件,可以使用keytool工具生成,一般Java环境都带有keytool命令,java环境配置好了直接可以在命令行使用。先把目录切换到前面说到的dist文件夹下,执行:
keytool -genkey -alias reverse1.keystore -keyalg RSA -validity 30000 -keystore reverse1.keystore
各个参数解释如下:
-genkey 产生证书文件
-alias 产生别名
-keystore 指定密钥库的.keystore文件
-keyalg 指定密钥的算法,这里指定为RSA(非对称密钥算法)
-validity 为证书有效天数
输入上述命令之后会有一系列的输入,倒数第二步它会问你确认自己的输入正确吗,你打个 y 进去就可以了,这里我的口令设置的是123456
使用jarsigner
jarsigner -verbose -keystore reverse1.keystore 60bac132cc17b02c58f27e3724e6f202.apk reverse1.keystore
参数分别是:apk文件,keystore文件的别名
-verbose 指定生成详细输出
-keystore 指定数字证书存储路径
运行成功结果截图:
最后安装到手机后发现flag里面包的是乱码,原来是自己的逻辑有错,它这里的k值是根据 is2 函数进行改变的输出也有着相应的改变,stringFromJNI2里面要的是k值,根据k值的变化会改变本地调用的接口返回的值。
所以说k的最终的值变的很关键,可以模拟它的调用过程算出来k的值,那个is2代码粘过来时需要删掉一个return flase;语句,因为那个语句不可达,this.val$handler.postDelayed(((Runnable)this), MainActivity.this.t);将这个函数进行延时,但是这个操作我看不太懂,app上显示的时间是每次减少一秒:
package test;
public class Home {
public static boolean is2(int arg4) {
boolean v1 = true;
if(arg4 > 3) {
if(arg4 % 2 != 0 && arg4 % 3 != 0) {
int v0 = 5;
while(true) {
if(v0 * v0 <= arg4) {
if(arg4 % v0 != 0 && arg4 % (v0 + 2) != 0) {
v0 += 6;
continue;
}
return false;
}
else {
return v1;
}
}
}
v1 = false;
}
else if(arg4 <= 1) {
v1 = false;
}
return v1;
}
public static void main(String args[]) {
int time = 200000;
int k = 0;
while (time > 0) {
if (is2(time)) {
k += 100;
}
else {
k--;
}
time--; //因为app运行时,每一次刷新都是减一,代码我也没看懂
}
System.out.println(k);
}
}
模拟出来的值为:1616384
之后进行以上的重新打包和签名的过程,然后安装的手机即可得到flag:
说明一下这里的TIme Remaining(s):0是因为我前面把 MainActivity.smali 中的 const v1, 0x30d40改成了0x0 才导致的
提交: flag{Y0vAr3TimerMa3te7}