首先下载 apk,然后使用 JADX 直接反编译,然后保存一下,使用 IDEA 打开即可

解法 一
可以看到,主 activity 是 MainActivity。我们安装 apk 后打开图像界面对照代码看看。

java
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.acticity_main_1);
this.passWord = (EditText) findViewById(R.id.passWord);
this.login = (Button) findViewById(R.id.button);
this.login.setOnClickListener(new View.OnClickListener() { // from class: com.example.test.ctf02.MainActivity.1
@Override // android.view.View.OnClickListener
public void onClick(View v) {
String str = MainActivity.this.passWord.getText().toString();
Check check = new Check();
if (check.checkPassword(str)) {
Toast.makeText(MainActivity.this, "Good,Please go on!", 0).show();
Intent intent = new Intent(MainActivity.this, MainActivity2.class);
MainActivity.this.startActivity(intent);
MainActivity.this.finish();
return;
}
Toast.makeText(MainActivity.this, "Failed", 0).show();
}
});
}
这里可以看到,当我们点击按钮的时候,系统会获取我们输入的字符串,然后放到 checkPassword() 这个函数里去,如果检测通过的话,就会开启 MainActivity2。
那么我们看一下 checkPassword() 是什么
java
public static boolean checkPassword(String str) {
char[] pass = str.toCharArray();
if (pass.length != 12) {
return false;
}
for (int len = 0; len < pass.length; len++) {
pass[len] = (char) (((255 - len) - 100) - pass[len]);
if (pass[len] != '0' || len >= 12) {
return false;
}
}
return true;
}
简单看看,调试一下,其实也不难,就是控制必须是 12 长度,然后每一位字符都必须经过处理后是 '0',其实就是一个一元一次方程,简单写个逆函数即可:
java
public static void main(String[] args) {
char[] pass = new char[12];
for(int i=0; i<12; i++){
pass[i] = (char) ((255 - i - 100) - 48);
}
System.out.println(Arrays.toString(pass));
}
跑一遍就能得出答案了:
java
kjihgfedcba`
OK,输入密码后就进入了第二个页面,我们对照代码看看需要干什么。

java
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_2);
init();
this.button.setOnClickListener(new View.OnClickListener() {
@Override // android.view.View.OnClickListener
public void onClick(View v) {
String str = MainActivity2.this.editText.getText().toString();
Intent intent = new Intent(str);
MainActivity2.this.sendBroadcast(intent);
}
});
}
可以看到,当点击按钮的时候,获取收入的文本的值,然后发送广播。
发送广播?为啥要发送广播呢?发送广播干啥呢?
好吧,其实在看 AndroidManifest.xml 的时候,还可以看到这里注册了一个广播接受者 receiver 实现类是 GetAndChange,接受的关键词是 android.is.very.fun

也就是说,广播的关键字是 android.is.very.fun
那么我们输入android.is.very.fun
就行了

确认即可,flag 就出来了

解法二
我们这里直接去看看这个接受广播的类,内部是如何实现的呢?
java
public class GetAndChange extends BroadcastReceiver {
@Override // android.content.BroadcastReceiver
public void onReceive(Context context, Intent intent) {
Intent intent1 = new Intent(context, NextContent.class);
context.startActivity(intent1);
}
}
当接受广播后,开启一个 activiye ,目标类是 NextContent
那么看看,NextContent 类如何实现的
java
public class NextContent extends AppCompatActivity {
ImageView imageView;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_next_content);
init();
Change();
}
public void init() {
this.imageView = (ImageView) findViewById(R.id.imageview);
}
public void Change() {
String strFile = getApplicationContext().getDatabasePath("img.jpg").getAbsolutePath();
try {
File f = new File(strFile);
if (f.exists()) {
f.delete();
}
} catch (Exception e) {
e.printStackTrace();
}
try {
InputStream is = getApplicationContext().getResources().getAssets().open("timg_2.zip");
FileOutputStream fos = new FileOutputStream(strFile);
byte[] buffer = new byte[1024];
while (true) {
int count = is.read(buffer);
if (count <= 0) {
break;
}
fos.write(buffer, 0, count);
}
fos.flush();
fos.close();
is.close();
} catch (Exception e2) {
e2.printStackTrace();
}
this.imageView.setImageBitmap(BitmapFactory.decodeFile(strFile));
}
}
主要看 Change() 方法,这里新建一个 img.jpg 的图像对象,然后读取资源 timg_2.zip 的内容,写到 img.jpg 中去,然后显示这个图片就完事了。
好吧,也就是说我们完全可以自己去改个文件名就行了。
直接在反编译的文件内容中找到 /resources/assets/timg_2.zip 重命名为 img.jpg 即可

解法 三
由解法一可得,其实只要发起一个广播,然后广播的关键词为 android.is.very.fun
,软件自动就展示 falg 了,那么使用 adb 发起一个广播。

打开 app ,然后使用命令即可
java
./adb shell am broadcast -a android.is.very.fun