下载附件,用jadx打开
安装
看来是校验输入是否为flag
直奔按钮 onClick 事件的代码(本人对主要逻辑部分做了抽取和适当简化)
String inputVal = findViewById(R.id.edit)).getText();
if (b(inputVal)) {
Toast.makeText(this, "You are right!", 1).show();
return;
}
Toast.makeText(this, "You are wrong! Bye~", 1).show();
可以看到这部分就是对输入内容用MainActiveity.b()进行校验,那我们再来看看b()函数里有啥
public boolean b(String str) {
// 首先这里判断flag必须为flag{xxx格式}
if (str.startsWith("flag{") && str.endsWith("}")) {
// 这里是截取flag{xxx} 中间的 xx 部分
String substring = str.substring(5, str.length() - 1);
b bVar = new b(2);
a aVar = new a(3);
StringBuilder sb = new StringBuilder();
int i = 0;
for (int i2 = 0; i2 < substring.length(); i2++) {
char c = aVar.a(bVar.a(substring.charAt(i2)+""));
sb.append(c);
int valueOf = bVar.b() / 25;
if (valueOf > i && valueOf >= 1) {
i++;
}
}
return sb.toString().equals("wigwrkaugala");
}
return false;
}
首先分别调用了a类和b类的有参构造方法创建了a和b的实例,
然后用循环对flag内容每一位做处理,再重新拼接起来
看一眼a和b的构造方法
// Class c
public class a {
public static ArrayList<Integer> a = new ArrayList<>();
Integer[] c = {7, 14, 16, 21, 4, 24, 25, 20, 5, 15, 9, 17, 6, 13, 3, 18, 12, 10, 19, 0, 22, 2, 11, 23, 1, 8};
public a(Integer num) {
for (int intValue = num; intValue < this.c.length; intValue++) {
a.add(this.c[intValue]);
}
for (int i = 0; i < num; i++) {
a.add(this.c[i]);
}
}
}
public class b {
public static ArrayList<Integer> a = new ArrayList<>();
Integer[] c = {8, 25, 17, 23, 7, 22, 1, 16, 6, 9, 21, 0, 15, 5, 10, 18, 2, 24, 4, 11, 3, 14, 19, 12, 20, 13};
public b(Integer num) {
for (int intValue = num; intValue < this.c.length; intValue++) {
a.add(this.c[intValue]);
}
for (int i = 0; i < num; i++) {
a.add(this.c[i]);
}
}
}
一通分析发现,不难看出,这就是在对数组c做循环左移的操作。传入num是几就左移几位,结果用a保存。
再对每一位处理的函数进行分析。
aVar.a( bVar.a( substring.charAt(i) ) );
看一下bVar.a()函数做了什么
public class b{
static String b = "abcdefghijklmnopqrstuvwxyz";
static Integer d = 0;
public Integer a(String str) {
int i = 0;
if (b.contains(str.toLowerCase())) {
Integer valueOf = b.indexOf(str);
for (int i2 = 0; i2 < a.size() - 1; i2++) {
if (a.get(i2) == valueOf) {
i = i2;
}
}
} else {
i = str.contains(" ") ? -10 : -1;
}
a();
return i;
}
}
逻辑很简单,就是判断传入的是否是b中26个字母,
如果是的话,找到它在26个字母中的位置,并赋值给valueOf
然后在ArrayList a中遍历比对valueOf的值,然后返回在valueOf在a中的索引赋值给i
那如果传入的不是b中的26个字母的话,再判断是否是空格,如果是的话返回-10,不是的话返回-1
最后再调用一个无参a函数收尾
public class b{
public static void a() {
int intValue = a.get(0);
a.remove(0);
a.add(intValue);
b += "" + b.charAt(0);
b = b.substring(1, 27);
Integer num = d;
d = d + 1;
}
}
可以看出,这里又是对ArrayList a和b字母表做循环左移,也就是说下一次调用的时候a和b的状态会改变。
接下来分析一下外层的aVar.a()。
啊不对,源码都在我手上,分析个锤子,稍作改造,看我爆破
(记得把a和b类中的静态方法和静态变量的static关键字去掉,否则会全局变量值不隔离)
public class MainActivity{
//去掉外层if,直接返回值
public static String b(String str) {
b bVar = new b(2);
a aVar = new a(3);
StringBuilder sb = new StringBuilder();
int i = 0;
for (int i2 = 0; i2 < str.length(); i2++) {
sb.append(a(str.charAt(i2) + "", bVar, aVar));
int valueOf = bVar.b() / 25;
if (valueOf > i && valueOf >= 1) {
i++;
}
}
return sb.toString();
}
}
可以看到字符串某些位置的答案不唯一
比如最后一位可能是i,也可能是r,都试一下了。
可以看到也都能通过真机测试,经过最后平台测试,答案其实是flag{venividivkcr}