攻防世界easyJava(re Moble)
easyJava
题目考察:jeb反编译工具的使用,逆向能力,本题是基于enigma密码机的一个加密,可以参考博客https://blog.csdn.net/kyoma/article/details/51857944,大致题目使用的加密就是这个原理。
题目分析
private static char a(String arg1, b arg2, a arg3) { return arg3.a(arg2.a(arg1)); } static Boolean a(String arg1) { return MainActivity.b(arg1); } private static Boolean b(String arg8) { Boolean v0_1; int v0 = 0; if(!arg8.startsWith("flag{")) { v0_1 = Boolean.valueOf(false); } else if(!arg8.endsWith("}")) { v0_1 = Boolean.valueOf(false); } else { String v2 = arg8.substring(5, arg8.length() - 1); b v4 = new b(Integer.valueOf(2)); a v5 = new a(Integer.valueOf(3)); StringBuilder v3 = new StringBuilder(); int v1 = 0; while(v0 < v2.length()) { v3.append(MainActivity.a(v2.charAt(v0) + "", v4, v5)); Integer v6 = Integer.valueOf(v4.b().intValue() / 25); if(v6.intValue() > v1 && v6.intValue() >= 1) { ++v1; } ++v0; } v0_1 = Boolean.valueOf(v3.toString().equals("wigwrkaugala")); } return v0_1; } protected void onCreate(Bundle arg3) { super.onCreate(arg3); this.setContentView(2130968603); this.findViewById(2131427446).setOnClickListener(new View$OnClickListener(((Context)this)) { public void onClick(View arg5) { if(MainActivity.a(this.a.findViewById(2131427445).getText().toString()).booleanValue()) { Toast.makeText(this.a, "You are right!", 1).show(); } else { Toast.makeText(this.a, "You are wrong! Bye~", 1).show(); new Timer().schedule(new TimerTask() { public void run() { System.exit(1); } }, 2000); } } }); }
首先,拿到题目一个apk文件,拖入jeb反编译,得到的MainActivity的大致代码如下。第一步肯定是要看到最下面的onCreate()方法,观察题目大概是要我们干什么。
可以发现,他是将我们输入的东西,传入到a()方法中,然后若返回结果是true,那么,就会输出“you are right!”。很显然我们需要令他成立。
可以看到a()方法其实并没有什么,就是调用了一下b()方法,将我们输入的传了过去。
b()方法是这个MainActivity中主要的一段代码。他有三个判断,第一个判断开头是否为“flag{”,第二个判断是否以"}"结尾。第三个比较关键,他初始化了a类和b类型为v4 v5,同时分别传入构造函数2和3.然后把我们输入的字符串的每个字符和v4,v5传入带有三个形参的a()方法中。就是去执行a.a(b.a(“字符”)),返回结果是一个字符类型的值,将每个我们输入的值执行后返回,拼接起来和”wigwrkaugala“比较,若相等就是正确的了。
public class a { public static ArrayList a; static String b; Integer[] c; static Integer d; static { a.a = new ArrayList(); a.b = "abcdefghijklmnopqrstuvwxyz"; a.d = Integer.valueOf(0); } public a(Integer arg8) { super(); this.c = new Integer[]{Integer.valueOf(7), Integer.valueOf(14), Integer.valueOf(16), Integer.valueOf(21), Integer.valueOf(4), Integer.valueOf(24), Integer.valueOf(25), Integer.valueOf(20), Integer.valueOf(5), Integer.valueOf(15), Integer.valueOf(9), Integer.valueOf(17), Integer.valueOf(6), Integer.valueOf(13), Integer.valueOf(3), Integer.valueOf(18), Integer.valueOf(12), Integer.valueOf(10), Integer.valueOf(19), Integer.valueOf(0), Integer.valueOf(22), Integer.valueOf(2), Integer.valueOf(11), Integer.valueOf(23), Integer.valueOf(1), Integer.valueOf(8)}; int v0; for(v0 = arg8.intValue(); v0 < this.c.length; ++v0) { a.a.add(this.c[v0]); } for(v0 = 0; v0 < arg8.intValue(); ++v0) { a.a.add(this.c[v0]); } } public char a(Integer arg5) { char v0_1; int v0 = 0; Integer v1 = Integer.valueOf(0); if(arg5.intValue() == -10) { a.a(); v0_1 = " ".charAt(0); } else { while(v0 < a.a.size() - 1) { if(a.a.get(v0) == arg5) { v1 = Integer.valueOf(v0); } ++v0; } a.a(); v0_1 = a.b.charAt(v1.intValue()); } return v0_1; } public static void a() { a.d = Integer.valueOf(a.d.intValue() + 1); if(a.d.intValue() == 25) { int v0 = a.a.get(0).intValue(); a.a.remove(0); a.a.add(Integer.valueOf(v0)); a.d = Integer.valueOf(0); } } }
首先对于这个a类,我们在初始化的时候传入了3,可以看到在a的构造函数中,他实现的就是相当于enigma密码机转动了三格,然后在调用a方法的时候,最终返回的值v0_1就是"abcdefghijklmnopqrstuvwxyz"的第v0个,v0就是传入的Integer类型的值在ArrayList[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]中的索引值
同时可以发现在他给v0_1赋值前,调用了void a()方法,可以发现这个方法本身是实现对ArrayList的转动,但是由于可以发现他有一个判断条件,要令成员变量d为25的时候才执行,因为d初始赋值是0,而我们也不会调用25次,所以是不会触发到这里面的。
public class b { public static ArrayList a; static String b; Integer[] c; static Integer d; static { b.a = new ArrayList(); b.b = "abcdefghijklmnopqrstuvwxyz"; b.d = Integer.valueOf(0); } public b(Integer arg9) { super(); this.c = new Integer[]{Integer.valueOf(8), Integer.valueOf(25), Integer.valueOf(17), Integer.valueOf(23), Integer.valueOf(7), Integer.valueOf(22), Integer.valueOf(1), Integer.valueOf(16), Integer.valueOf(6), Integer.valueOf(9), Integer.valueOf(21), Integer.valueOf(0), Integer.valueOf(15), Integer.valueOf(5), Integer.valueOf(10), Integer.valueOf(18), Integer.valueOf(2), Integer.valueOf(24), Integer.valueOf(4), Integer.valueOf(11), Integer.valueOf(3), Integer.valueOf(14), Integer.valueOf(19), Integer.valueOf(12), Integer.valueOf(20), Integer.valueOf(13)}; int v0; for(v0 = arg9.intValue(); v0 < this.c.length; ++v0) { b.a.add(this.c[v0]); } for(v0 = 0; v0 < arg9.intValue(); ++v0) { b.a.add(this.c[v0]); } } public Integer a(String arg5) { int v0 = 0; Integer v1 = Integer.valueOf(0); if(b.b.contains(arg5.toLowerCase())) { Integer v2 = Integer.valueOf(b.b.indexOf(arg5)); while(v0 < b.a.size() - 1) { if(b.a.get(v0) == v2) { v1 = Integer.valueOf(v0); } ++v0; } } else { if(arg5.contains(" ")) { v1 = Integer.valueOf(-10); goto label_24; } v1 = Integer.valueOf(-1); } label_24: b.a(); return v1; } public static void a() { int v0 = b.a.get(0).intValue(); b.a.remove(0); b.a.add(Integer.valueOf(v0)); b.b = b.b + "" + b.b.charAt(0); b.b = b.b.substring(1, 27); b.d = Integer.valueOf(b.d.intValue() + 1); } public Integer b() { return b.d; } }
b类的话其实和a类是很相似的,在构造函数的初始化适合a类的初始化是一样的,不过我们一开始传的值是2,所以就是相当于转动了二格。
然后看到b类中关键的a方法的代码,可以知道传入的是我们输入的字符串的单个字符,返回的是一个Integer类型的值,在MainActivity中作为a类的a方法的传入值。
可以知道我们的返回v1是等于v0,v0是v2在ArrayList[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]中的索引
而v2就是我们输入字符在"abcdefghijklmnopqrstuvwxyz"中的索引
然后在给v1赋值后我们可以发现,他调用了b类的void a()方法,void a()方法是实现了对ArrayList的一次转动,以及对字符串"abcdefghijklmnopqrstuvwxyz"的一次转动
到这边就分析完了,只需要写出逆向的脚本就可以得到正确的输入了。
python脚本
from collections import deque#双端队列 alpha = deque("abcdefghijklmnopqrstuvwxyz") t1 = deque([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]) t2 = deque([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]) ss = 'wigwrkaugala' for _ in range(2): t1.append(t1.popleft()) #实现转动 for _ in range(3): t2.append(t2.popleft()) print(t1) print(t2) def dec(s): i = t2[(ord(s) - ord('a'))] #ord(s) - ord('a')就可以得到在那个a到z的字符中的索引值 i = t1[(i)] print(alpha[i], end='') t1.append(t1.popleft()) alpha.append(alpha.popleft()) for s in ss: dec(s)
- 【CTF】攻防世界——easy_RSA(Crypto)
- Java基础知识:走进Java的世界
- [原创]一步一步带你进入Java世界(一)_Java环境配置
- 熬之滴水穿石:JAVA的世界(7)
- 7个改变世界的Java项目
- 7个改变世界的Java项目
- Groovy是连接脚本语言和企业级Java世界的桥梁 一
- EasyDemo*Java api常用软件包~util包体系结构(on Github)
- java的世界里,younggc与fullgc分别是在什么时候发生
- EasyDemo*java面试常见题
- 7个改变世界的Java项目
- XCTF攻防世界web进阶练习_ 5_mfw
- java easyreport 导入excel、 txt 数据行列索引(四)
- 攻防世界(新手篇)
- java.lang.NoSuchMethodError: org.jboss.resteasy.spi.ResteasyUriInfo.setRemoteAddress(Ljava/net/InetS
- JAVA世界的入门引领者——郝彬老师的视频
- Easy Java - 泛型
- Java解世界最难九宫格问题
- EasyDemo*Java面试常见题
- 走进Java Android 的线程世界