前言:
坛友们,年轻就是资本,和我一起逆天改命吧,我的学习过程全部记录及学习资源:https://www.52pojie.cn/thread-1791705-1-1.html
立帖为证!--------记录学习的点点滴滴
0x1 简单分析
1.下载题目:攻防世界easy_java:https://adworld.xctf.org.cn/media/file/task/3f06e60ded5e44e3b0f4c47020cbcb3c.apk
2.jadx反编译看源码:
package com.a.easyjava;
import android.os.Bundle;
import android.support.v7.app.c;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import java.util.Timer;
import java.util.TimerTask;
/* loaded from: classes.dex */
public class MainActivity extends c {
private static char a(String str, b bVar, a aVar) {
return aVar.a(bVar.a(str));
}
/* JADX INFO: Access modifiers changed from: private */
public static Boolean b(String str) {
if (str.startsWith("flag{") && str.endsWith("}")) {
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++) {
sb.append(a(substring.charAt(i2) + "", bVar, aVar));
Integer valueOf = Integer.valueOf(bVar.b().intValue() / 25);
if (valueOf.intValue() > i && valueOf.intValue() >= 1) {
i++;
}
}
return Boolean.valueOf(sb.toString().equals("wigwrkaugala"));
}
return false;
}
/* JADX INFO: Access modifiers changed from: protected */
@Override // android.support.v7.app.c, android.support.v4.a.i, android.support.v4.a.aa, android.app.Activity
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.activity_main);
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() { // from class: com.a.easyjava.MainActivity.1
@Override // android.view.View.OnClickListener
public void onClick(View view) {
if (MainActivity.b(((EditText) ((MainActivity) this).findViewById(R.id.edit)).getText().toString()).booleanValue()) {
Toast.makeText(this, "You are right!", 1).show();
return;
}
Toast.makeText(this, "You are wrong! Bye~", 1).show();
new Timer().schedule(new TimerTask() { // from class: com.a.easyjava.MainActivity.1.1
@Override // java.util.TimerTask, java.lang.Runnable
public void run() {
System.exit(1);
}
}, 2000L);
}
});
}
}
3.先看onCreate函数里面的onclick事件,很明显必须要让这个if语句为true,这句代码意思就是拿我们输入的文本作为b函数的参数去执行,booleanValue()函数用于返回Boolean对象对应的布尔原始值。
if (MainActivity.b(((EditText) ((MainActivity) this).findViewById(R.id.edit)).getText().toString()).booleanValue()) {
Toast.makeText(this, "You are right!", 1).show();
return;
}
4.接下来就看看b函数
1)首先判断输入的字符串是不是flag{开头, }结尾的
2)然后调用substring去掉开头和结尾,接着new两个对象,如果容易搞混可以重命名类和函数名
3)再看for循环,调用a类对象取里面的一个字符串追加到sb,valueOf=b类对象的值除以25,然后i++
4)最后比较sb是否等于wigwrkaugala
0x2 动态调试
1.光看我们不是很容易看出每句代码的作用,把程序拖进jeb,输入flag{123456}点击,先看看 b bVar = new b(2);这一句执行后bVar的返回值,这看的太不方便了。
2.直接把a类和b类拖进eclipse改造,再执行相同代码看看,打断点看,a类就是从下标3开始开始取值添加,最后再添加0,1,2下标的值进入ArrayList,b类和a类类似,所以初始化后两个对象的a值如下所示。
A类中
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};
a=[21, 4, 24, 25, 20, 5, 15, 9, 17, 6, 13, 3, 18, 12, 10, 19, 0, 22, 2, 11, 23, 1, 8, 7, 14, 16]
B类中
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};
a=[17, 23, 7, 22, 1, 16, 6, 9, 21, 0, 15, 5, 10, 18, 2, 24, 4, 11, 3, 14, 19, 12, 20, 13, 8, 25]
3.再看看for循环那里,同样把代码粘贴进去,调试可以到从我输入的字符串123456中取第一个字符,再把b对象和a对象一起作为参数调用a方法,a方法中直接一句aVar.a(bVar.a(str)),再去看B类的a方法,查看两个函数意思可知我们输入的内容应该为字母,去字符串b中查找指定位置,得到下标。
contains() 方法用于判断字符串中是否包含指定的字符或字符串。
toLowerCase() 方法将字符串转换为小写。
get() 方法通过索引值获取动态数组中的元素。
然后再看for循环里面遍历a数组中的元素,等于刚刚得到的下标时,赋值给i,最后返回i。
for (int i2 = 0; i2 < a.size() - 1; i2++) {
if (a.get(i2) == valueOf) {
i = Integer.valueOf(i2);
返回之前还去执行a函数,这个方法就是将a数组的第一个放到最后面(先删再加),将字符串b第一个字符放到最后面(先加在末尾,然后截取第二位到最后一位),之后d+1
int intValue = a.get(0);
a.remove(0);
a.add(Integer.valueOf(intValue));
b += "" + b.charAt(0);
b = b.substring(1, 27);
Integer num = d;
d = Integer.valueOf(d + 1);
上面的执行完后,i作为参数调用A类的a方法,先判断等不等于-10,也就是说前面我输入123456数字到这里gg了,重来一遍,这次用abcdef来试,这次匹配到i=9,所以正常进入下一个for循环,里面同样是遍历a元素匹配i,得到num2,然后再调用b.charAt根据下标取对应字符返回。返回之前也是去调用a函数,d+1,然后如果d变成了25,a数组就将第一个位置放到最后面(先删再加),然后d重新变成0.
public char a(Integer num) {
Integer num2 = 0;
if (num == -10) {
a();
return " ".charAt(0);
}
for (int i = 0; i < a.size() - 1; i++) {
if (a.get(i) == num) {
num2 = Integer.valueOf(i);
}
}
a();
return b.charAt(num2);
4.这一块分析完了再回去,就是将A类中b对应下标的元素取出来添加进sb,B类b方法就是直接返回d,小于25就不会触发下面的if,看前面也知道不会循环这么多次(wigwrkaugala的长度决定了)。
sb.append(a(substring.charAt(i2) + "", bVar, aVar));
Integer valueOf = Integer.valueOf(bVar.b().intValue() / 25);
if (valueOf.intValue() > i && valueOf.intValue() >= 1) {
i++;
}
0x3 计算flag
1.分析完了,接下来就要以wigwrkaugala作为输入,首先把需要的变量定义好:
public static ArrayList<Integer> A_a = new ArrayList<>();
static String A_b = "abcdefghijklmnopqrstuvwxyz";
static Integer A_d = 0;
//前面分析右移3位后的数据,就是new(3)了之后的值
Integer[] A_c = {21, 4, 24, 25, 20, 5, 15, 9, 17, 6, 13, 3, 18, 12, 10, 19, 0, 22, 2, 11, 23, 1, 8, 7, 14, 16};
public static ArrayList<Integer> B_a = new ArrayList<>();
static String B_b = "abcdefghijklmnopqrstuvwxyz";
static Integer B_d = 0;
//前面分析右移2位后的数据,就是new(2)了之后的值
Integer[] B_c = {17, 23, 7, 22, 1, 16, 6, 9, 21, 0, 15, 5, 10, 18, 2, 24, 4, 11, 3, 14, 19, 12, 20, 13, 8, 25};
2.接下来就是charAt根据下标查字符,变成idnexOf根据字符串查下标,根据wigwrkaugala长度判断A_c和B_c移动,然后前面是将第一个放到最后一个,这里就要循环向后移位,再将最后一个值set()到最前面。
3.一个小时后......,代码越写越乱,懵逼了,最后运算结果死活不对,去抄一抄别人的wp得到:
package test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Test {
public static ArrayList<Integer> A_a = new ArrayList<>();
static String A_b = "abcdefghijklmnopqrstuvwxyz";
static Integer A_d = 0;
// 前面分析右移3位后的数据,就是new(3)了之后的值
static Integer[] A_c = { 21, 4, 24, 25, 20, 5, 15, 9, 17, 6, 13, 3, 18, 12, 10, 19, 0, 22, 2, 11, 23, 1, 8, 7, 14,
16 };
public static ArrayList<Integer> B_a = new ArrayList<>();
static String B_b = "abcdefghijklmnopqrstuvwxyz";
static Integer B_d = 0;
// 前面分析右移2位后的数据,就是new(2)了之后的值
static Integer[] B_c = { 17, 23, 7, 22, 1, 16, 6, 9, 21, 0, 15, 5, 10, 18, 2, 24, 4, 11, 3, 14, 19, 12, 20, 13, 8,
25 };
static String str = "wigwrkaugala";
public static void main(String[] args) {
String res = "";
// 将B_a以及B_b推到最终结果的时候
changeB_c();
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(str.length() - 1 - i);
res += B_char(aInteger(c + ""));
// 最终res为rckvidivinev 然后将其反转就是答案
}
System.out.println("flag{" + new StringBuffer(res).reverse() + "}");
}
static void changeB_c() {
// 这里逆推,B_b,数组最终移动了12位,最后一次移动是结束了的结果,因此退11位就行,
int length = str.length();
for (int i = 0; i < length - 1; i++) {
String s = B_b.charAt(0) + "";
B_b = B_b.substring(1, B_b.length()) + s;
int t = B_c[0];
for (int j = 1; j < B_c.length; j++) {
B_c[j - 1] = B_c[j];
}
B_c[B_c.length - 1] = t;
}
List<Integer> list = Arrays.asList(B_c);
B_a = new ArrayList<>(list);
}
static void changeB_c2() {
// 获得最后一个
Integer integer = B_a.get(B_a.size() - 1);
// 把最后一个放到前面
List<Integer> list = B_a.subList(0, B_a.size() - 1);
ArrayList<Integer> integers = new ArrayList<>();
integers.add(integer);
integers.addAll(list);
B_a = new ArrayList<>(integers);
// 字符串交换后拼接
String substring = B_b.substring(25, B_b.length());
String substring1 = B_b.substring(0, 25);
B_b = substring + substring1;
}
static char B_char(Integer i) {
Integer cq = B_a.get(i);
char c = B_b.charAt(cq);
changeB_c2();
return c;
}
static Integer aInteger(String c) {
int i = A_b.indexOf(c);
return A_c[i];
}
}
4.运行得到flag{venividivkcr},验证成功。
5.这个算法题把我脑瓜子整的嗡嗡的,基础不牢,再加上好多java函数不知道意思,要反复去查,一不小心绕进去出不来了。
6.还有那个Integer类型,jeb必须点开一个个看数组,很麻烦,eclipse点开后看结果,数组移位就很方便了,Android studio应该也可以(不会用),不会导项目进去,jadx另存打包报错不知道咋处理。。
0x4 参考资料:
1.菜鸟教程
2.攻防世界Mobile新手入门题easyjava