Fibonacci-JavisOJ-wp

这题涉及到jar2exe的知识,所以单独拿出来写一下,顺便写一写jar2exe怎么入手

这种方法并不适用于jar2exe当前的最新版(2.1.7),经过我的测试2.1.2试可用的,而且由于2.1.2的第三种加密方式还没有这么激进,后续其它版本应该也是支持的,还需要再试验。

准备工作

拿到题目DIE查一下,发现不是一个普通的可执行文件

1

也就是说这本来是一个jar文件,通过jar2exe的方式转换成了windows可执行文件

Jar2Exe

一共有3种保护方式

  • 不隐藏也不加密
  • 隐藏
  • 隐藏且加密
Level1

第一种方式非常简单,只需要在16进制编辑器中找到第一个PK,即zip的文件头,然后把这之后的另存为新文件,就可以了。但是这一题并不是采用这种方式,以这种方式提取出来的程序只包含很多生成出来的附加文件。

其实也可以直接用winrar打开

Level2

第二种方式隐藏了原本的jar文件,可以通过RH来查看文件,这部分被放在了RCData

1

Level3

本题采用的是第三种,就像第二种一样,原先的jar文件被隐藏了,但是第三种方式还进行加密,并且将整个jar文件的结构和类名全部都混淆了(经过实验在jar2exe 2.1.2中并不会对文件结构进行破坏),不会像第二种方式中直接dump出来一个完整的jar文件

Dump

要解决这道题首先就是要把有效的代码Dump出来,这部分的内容对于第二种和第三种方式是基本一样的。

从上面可以看到这段密文的偏移,然后x64dbg打开之后,在程序内存处根据偏移找到这段内存,设内存访问断点,程序运行起来,在dec r8d处停下来,此时如果是采用第二种方式加密,经过一个简单的循环之后就可以把原jardump出来,但是这里还需要经过一些加密

3

根据脱壳的经验,找到向上跳转的最外层,就是最后一个跳转,然后直接执行到下一行

4

首先观察变红色的值即发生改变的值,发现r14r15的值很可疑,观察前面的代码,发现会在循环处inc r15dinc r14,根据这两个寄存器的值推断,r14中的值是解密后数据的结束位置,r15中的值B8B为解密后数据的长度,因此,利用Scylla把这部分内容dump出来,出题人使用的jar2exe版本里面的文件名都是混淆过的,需要手动修复成jar文件,找到其中的两个class文件,IDEA直接就可以反编译。

逆向

dump出来的文件包含了两个类,第一个类包含主要的处理过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package top.phrack.ctf.Fibonacci;

import java.util.Scanner;

public class Fibonacci {
public Fibonacci() {
}

private static void heheda() {
String bb = new String(b.x);
String cb = new String(b.y);
hello(cb, bb);
}

public static void main(String[] args) {
System.out.println("来让我们玩一个数列游戏:");
System.out.println("a[0]=0,a[1]=1");
System.out.println("a[2]=1,a[3]=2");
System.out.println("a[4]=3,a[5]=5");
System.out.println("..............");
System.out.println("请计算a[100000000000000]:");
Scanner scan = new Scanner(System.in);
String read = scan.nextLine();
System.out.println("答案错误!!");
}

private static String hello(String aaa, String bbb) {
int[] iS = new int[256];
byte[] iK = new byte[256];

int j;
for(j = 0; j < 256; iS[j] = j++) {
}

int j = true;

for(short i = 0; i < 256; ++i) {
iK[i] = (byte)bbb.charAt(i % bbb.length());
}

j = 0;

int i;
for(i = 0; i < 255; ++i) {
j = (j + iS[i] + iK[i]) % 256;
int temp = iS[i];
iS[i] = iS[j];
iS[j] = temp;
}

i = 0;
j = 0;
char[] iInputChar = aaa.toCharArray();
char[] iOutputChar = new char[iInputChar.length];

for(short x = 0; x < iInputChar.length; ++x) {
i = (i + 1) % 256;
j = (j + iS[i]) % 256;
int temp = iS[i];
iS[i] = iS[j];
iS[j] = temp;
int t = (iS[i] + iS[j] % 256) % 256;
int iY = iS[t];
char iCY = (char)iY;
iOutputChar[x] = (char)(iInputChar[x] ^ iCY);
}

return new String(iOutputChar);
}
}

由此可见什么斐波那契数列并没有什么用,真正有用的是heheda()hello(),其中调用了b类的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package top.phrack.ctf.Fibonacci;

public class b {
public static char[] x = new char[]{'}', '\u0010', 'ý', 'É', '\u000b', '\u0016', '9', 'D', '7', ',', ' ', 'Í'};
public static char[] y = new char[]{'t', '\u0096', '®', 'D', '´', 'Z', 'Ö', '½', 'O', '5', '\u0085', '\n', '+', '+', '½', 'Ù', 'O', '`', '\u0013', '\u008a', 'Ç', '\u0080', '@', 'Ü', 'Þ', 'ê', '\u000b', '¯', 'ä', '\u0081'};

public b() {
}
}

所以直接在java环境里运行一下就可以了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
//Main.java
package com.company;

public class Main {
private static void heheda() {
String bb = new String(b.x);
String cb = new String(b.y);
System.out.println(hello(cb, bb));
}

public static void main(String[] args) {
heheda();
}

private static String hello(String aaa, String bbb) {
int[] iS = new int[256];
byte[] iK = new byte[256];
int j;
for (j = 0; j < 256; iS[j] = j++) {
}

for (short i = 0; i < 256; ++i) {
iK[i] = (byte) bbb.charAt(i % bbb.length());
}

j = 0;

int i;
for (i = 0; i < 255; ++i) {
j = (j + iS[i] + iK[i]) % 256;
int temp = iS[i];
iS[i] = iS[j];
iS[j] = temp;
}

i = 0;
j = 0;
char[] iInputChar = aaa.toCharArray();
char[] iOutputChar = new char[iInputChar.length];

for (short x = 0; x < iInputChar.length; ++x) {
i = (i + 1) % 256;
j = (j + iS[i]) % 256;
int temp = iS[i];
iS[i] = iS[j];
iS[j] = temp;
int t = (iS[i] + iS[j] % 256) % 256;
int iY = iS[t];
char iCY = (char) iY;
iOutputChar[x] = (char) (iInputChar[x] ^ iCY);
}

return new String(iOutputChar);
}
}

//b.java
package com.company;

public class b {
public static char[] x = new char[]{'}', '\u0010', 'ý', 'É', '\u000b', '\u0016', '9', 'D', '7', ',', ' ', 'Í'};
public static char[] y = new char[]{'t', '\u0096', '®', 'D', '´', 'Z', 'Ö', '½', 'O', '5', '\u0085', '\n', '+', '+', '½', 'Ù', 'O', '`', '\u0013', '\u008a', 'Ç', '\u0080', '@', 'Ü', 'Þ', 'ê', '\u000b', '¯', 'ä', '\u0081'};

public b() {
}
}

运行直接输出flag

1
PCTF{1ts_not_5c2ipt_Chall3nge}
WPICTF-re-wp CrackRTF-buuctf

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×