Bite-code
Bite-code这道题目是ctf-learn网站中reversing中的一道相对来说比较简单的题目,该题目的链接地址如下题目地址。
将题目中的文件下载下来,是一个txt文件,通过观察文件中的信息,发现该文件是java的字节码,作者的意思应该是通过字节码文件逆行分析出函数的功能。
txt文件中的字节码文件如下所示:
public static boolean checkNum(int);
descriptor: (I)Z
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=3, args_size=1
0: iload_0
1: iconst_3
2: ishl
3: istore_1
4: iload_0
5: ldc #2 // int 525024598
7: ixor
8: istore_2
9: iload_1
10: iload_2
11: ixor
12: ldc #3 // int -889275714
14: if_icmpne 21
17: iconst_1
18: goto 22
21: iconst_0
22: ireturn
LineNumberTable:
line 3: 0
line 4: 4
line 5: 9
StackMapTable: number_of_entries = 2
frame_type = 253 /* append */
offset_delta = 21
locals = [ int, int ]
frame_type = 64 /* same_locals_1_stack_item */
stack = [ int ]
在上面的文件中我们需要关心的是code下的指令,这是该方法的执行指令。
接下来对上面的字节码文件进行分析:
public static boolean checkNum(int);这个语句可以看出函数的定义。当然下面的信息也可以看出
descriptor中描述的是该函数有一个形参,形参的类型是Int类型,同时该函数的返回值是布尔类型(I:表示整型, Z:表示)
flags:表示该函数的访问修饰,ACC_PUBLIC表示该函数是public类型,ACC_STATIC表示该函数是static
code:表示了该函数的指令,在JVM是基于堆栈来实现指令的执行的
在理解code下的指令之前,我们首先通过一个简单的例子来了解一下字节码中的指令。
一个简单的java程序例子如下所示;
# Test.java
public class Test {
public static void main(String[] args) {
int a = 1;
int b = 2;
int c = a + b;
}
}
对上面的程序进行编译,编译命令javac Test.java,编译完成之后通过命令javap -v Test.class就可以得到字节码文件,字节码文件如下所示(这里只展示code部分):
Code:
stack=2, locals=4, args_size=1
0: iconst_1
1: istore_1
2: iconst_2
3: istore_2
4: iload_1
5: iload_2
6: iadd
7: istore_3
8: return
上面的字节码上,stack表示栈的深度,locals表示局部变量的个数,args_size表示形参的个数。
iconst_1:将常量1压入栈中
istore_1: 将栈顶中的元素存储到索引值为1的内存区域,相对于把1赋给一个变量(a)
iconst_2:将常量2压入栈中
istore_2: 将栈顶中的元素存储到索引值为2的内存区域,相对于把1赋给一个变量(b)
**iload_1:将索引值为1的内存区域的值压栈,相当于把a的值入栈
iload_2: 将索引值为2的内存区域的值压栈, 相当于把b的值入栈
iadd:将栈顶的两个元素出栈,然后相加,把相加后的结果入栈
istore_3: 将栈顶中的元素存储到索引值为3的内存区域,相对于把a+b赋给一个变量(c)
通过上面的解释,大概了解指令的意义。我们可以得出之前的代码的函数,如下:
public static boolean checkNum(int x){
n1 = 525024598
n2 = -889275714
n3 = (x << 3) ^ (x ^ n1)
if (n3 == n2) {
return true;
}
else
return false;
}
因此,我们可以通过暴力破解来获取我们的flag,暴力破解程序如下:
public class Solution {
public static void main(String[] args) {
int n1 = 525024598;
int n2 = -889275714;
for (int i = Integer.MIN_VALUE; i < Integer.MAX_VALUE; i++) {
int n3 = (i << 3) ^ (n1 ^ i);
if (n3 == n2) {
System.out.println("Proper input: " + i);
break;
}
}
}
}