pwnhub-sxbk

pwnhub的话,都是超级难的题目,这里先尝试解一下题吧,也算是尝试。

丧心病狂

这个题目。。。吓到我了,下下来是一个.jar文件,于是直接拖到jd-gui里面反编译,然后。。

我艹艹艹。。。。这么多类。。。。然后先看一看MANIFEST设置文件好了。。。然后发现里面写了主类:

1
2
Manifest-Version: 1.0
Main-Class: pwnhub.a02c83a7dbd96295beaefb72c2bee2de

好吧顺着找过去:

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
package pwnhub;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintStream;

public class a02c83a7dbd96295beaefb72c2bee2de
{
public static String code;

public static void main(String[] args)
throws Exception
{
System.out.println("no passcode, no game");
System.out.print("code:");
BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
code = strin.readLine();
if (4 != code.length()) {
throw new Exception("error code");
}
if (!a4a89174426b40307102e165374ab8ab.b(code)) {
throw new Exception("error code");
}
f2f3269806389d0789c558d2a652f950.code = code;
}
}

仔细一看这里出现了三个类。。。除了主类之外,还有一个什么什么a4a8917…这个似乎有一个方法b,并且要没有返回值,然后会将这个code赋值给一个f2什么的。。。
这里我们继续追踪a4a什么的

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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
package pwnhub;

class a4a89174426b40307102e165374ab8ab
{
static boolean b(String input_str)
{
int var46 = 0;

String str = input_str + "explorerexplorerexplorerexplorerexplorerexplorerexplorerexplorerexplorerexpl";
byte[] str_bytes = str.getBytes();

int[] sha1_str = new int[80];
int AA = 1732584193; //0x67452301
int BB = -271733879; //0xefcdab89
int CC = -1732584194; //0x98badcfe
int DD = 271733878; //0x10325476
int EE = -1009589776; //0xc3d2e1f0
int index = 0;

// 以下为sha1
while (index < str_bytes.length)
{
int aa = AA;
int bb = BB;
int cc = CC;
int dd = DD;
int ee = EE;

int round = 0;
while (round < 80)
{
if (round < 16)
{
sha1_str[round] = str_bytes[(index + round)];
}
else
{
int var10000 = sha1_str[(round - 3)] ^ sha1_str[(round - 8)] ^ sha1_str[(round - 14)];
int var136 = sha1_str[(round - 16)];

int var28 = var10000 ^ var136;
int var29 = var28 << 1 | var28 >>> 31;
sha1_str[round] = var29;
}
int var28 = AA << 5 | AA >>> 27; //AA*32
int var10000 = var28 + EE + sha1_str[round];
int var136;
int var136;
if (round < 20)
{
var136 = 1518500249 + (BB & CC | (BB ^ 0xFFFFFFFF) & DD);
}
else
{
var136 = round;
int var10002 = 40;
if (var136 < var10002)
{
var136 = 1859775393 + (BB ^ CC ^ DD);
}
else
{
var136 = round;
var10002 = 60;
if (var136 < var10002)
{
var136 = -1894007588 + (BB & CC | BB & DD | CC & DD);
}
else
{
var136 = -899497514;
var10002 = BB ^ CC ^ DD;

var136 += var10002;
}
}
}
int var29 = var10000 + var136;
EE = DD;
DD = CC;
CC = BB << 30 | BB >>> 2;
BB = AA;
AA = var29;
round++;
}
AA += aa;
BB += bb;
CC += cc;
DD += dd;
int var10000 = EE;
int var136 = ee;

EE = var10000 + var136;
index += 16;
}

// ===========sha1=============
byte sha1_index = 5;

int[] sha1_ans = new int[sha1_index];
sha1_ans[0] = AA;
sha1_ans[1] = BB;
sha1_ans[2] = CC;
sha1_ans[3] = DD;
sha1_ans[4] = EE;
int[] str_sha1 = sha1_ans;
byte[] f_20bit = new byte[20];
int cc = 0;

// ========== 取出每一个字节 ============
while (cc < 20)
{
int dd = str_sha1[(cc / 4)]; // 每四个为一个单位
int ee = (3 - cc % 4) * 8; // 24(0),16(1),8(2),0(3)
f_20bit[cc] = ((byte)(dd >>> ee)); // 相当于说,取出每一字节,分别存放在当前的bytes中
cc++;
}

// ========== base64处理 ==========
byte[] f_22bit = new byte[f_20bit.length + 2];//申请了22个空间(?)
System.arraycopy(f_20bit, 0, f_22bit, 0, f_20bit.length); // 完全拷贝过去
byte[] vf_28bit = new byte[f_22bit.length / 3 * 4]; // 申请了28个字节

byte[] var82 = vf_28bit;
AA = 0;
BB = 0;
while (AA < var100.length)
{
var82[BB] = ((byte)(f_22bit[AA] >>> 2 & 0x3F)); // 取出高6位数
var82[(BB + 1)] = ((byte)(f_22bit[(AA + 1)] >>> 4 & 0xF | f_22bit[AA] << 4 & 0x3F));
var82[(BB + 2)] = ((byte)(f_22bit[(AA + 2)] >>> 6 & 0x3 | f_22bit[(AA + 1)] << 2 & 0x3F));
var82[(BB + 3)] = ((byte)(f_22bit[(AA + 2)] & 0x3F));
AA += 3;
BB += 4;
}
AA = 0;
while (AA < var82.length)
{
int var10000 = var82[AA];
if (var10000 < 26)
{
var82[AA] = ((byte)(var82[AA] + 65));
}
else
{
var10000 = var82[AA];
byte var10001 = 52;
if (var10000 < var10001)
{
var82[AA] = ((byte)(var82[AA] + 97 - 26));
}
else
{
var10000 = var82[AA];
var10001 = 62;
if (var10000 < var10001)
{
var82[AA] = ((byte)(var82[AA] + 48 - 52));
if (var46 == 0) {}
}
else
{
vf_28bit = var82;
int var136 = AA;
if (var46 == 0)
{
var10000 = var82[AA];
var10001 = 63;
if (var10000 < var10001)
{
var82[AA] = 43;
}
else
{
vf_28bit = var82;
var136 = AA;
}
}
else
{
vf_28bit[var136] = 47;
}
}
}
}
AA++;
}
int var10000 = var82.length;
byte var10001 = 1;

AA = var10000 - var10001;
while (AA > var100.length * 4 / 3)
{
var82[AA] = 61;
AA--;
}
return new String(var82).equals("FVaFsOGplhi32uir9nCbgQTOLIM=");
}
}

哇!!!!!!!var10000!!!!!!我是不是眼花了!!!!!!!!!!
算法本身看起来非常复杂。。。但是然后我们会发现一个奇怪的地方。。。

这几个数字不是什么普通的数字吧。。。。看起来更像是sha1的样子,于是上网去查询:
发现sha1中用到了5个变量,并且这里面出现了sha1中才有的函数,那么就能看出来,这就是一个sha1加密了。。
然后那个算法。。仔细一看,又是凑成4的倍数,又是&0x3f,那么估计就是base64了。。。然后我们尝试的将加密的那段文字进行base64解密:
b’\x15V\x85\xb0\xe1\xa9\x96\x18\xb7\xda\xe8\xab\xf6p\x9b\x81\x04\xce,\x83’
看起来是一串二进制数字啊。。。但是毕竟是使用了sha1加密过的结果。所以应该是有可能变成了不可见的2进制,并且这一串数字又正好是20位数,正好就是之前得到的四个值。
虽然各种暗示都表示此时只有四个字符,但是我写了个脚本就是跑不出结果。。。我打算直接将这一段写成java试一试。。。
java的String 真·是·招·黑。。。。最后找到答案是mdzz。。我也觉得。。。开个eclipse真是卡的爆炸。。。
然后我们接着往下看:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package pwnhub;

import java.lang.reflect.InvocationTargetException;

public class f2f3269806389d0789c558d2a652f950
extends d1a2276cb6055f0a6d12ac4004352f0b
{
static String code;

public f2f3269806389d0789c558d2a652f950()
throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException
{}
}

这这。。。。又继承了一个类,那么接着看:

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
package pwnhub;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class d1a2276cb6055f0a6d12ac4004352f0b
{
static d1a2276cb6055f0a6d12ac4004352f0b e;

static
{
try
{
e = new d1a2276cb6055f0a6d12ac4004352f0b();
}
catch (ClassNotFoundException|NoSuchMethodException|IllegalAccessException|InvocationTargetException e1)
{
e1.printStackTrace();
}
}

public d1a2276cb6055f0a6d12ac4004352f0b()
throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException
{
e9b8eb59aee1bca0a57fa2091b3724b9.code = a02c83a7dbd96295beaefb72c2bee2de.code;
e9b8eb59aee1bca0a57fa2091b3724b9 mc = new e9b8eb59aee1bca0a57fa2091b3724b9();
Class<?> clazz = mc.loadClass("pwnhub.checkFlag");
Method c = clazz.getMethod("check", (Class[])null);
c.invoke(null, new Object[0]);
}
}

哦我tm快要打人了真的。。。这个e9是个什么鬼。。。而且令人讨厌的是,这个code是好像没有明确的指出来是用在那里的。。。而且这个pwnhub.checkFlag类又在哪里啊。。从这里看,似乎是加载了一个叫做pwnhub.checkFlag的类,然后企图调用里面的check方法吧。。那么我们就要注意到,这个e9什么的类,应该是个用于【读入类】的对象
看来这个乱码不是应为是 jd-gui的问题啊

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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package pwnhub;

import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class e9b8eb59aee1bca0a57fa2091b3724b9
extends ClassLoader
{
public static String code;

// ============= MD5加密(果然。。但是我测试过,好像不止md5) ==========
private static String md5(byte[] data)
throws NoSuchAlgorithmException
{
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(data);
byte[] md5 = md.digest();
return byte2HexStr(md5);
}

// ========= 将byte转变为可见字符(每个字节用两位表示) ============
private static String byte2HexStr(byte[] b)
{
String hs = "";
String stmp = "";
for (byte aB : b)
{
stmp = Integer.toHexString(aB & 0xFF);
if (stmp.length() == 1) {
hs = hs + "0" + stmp;//添加0凑够两位
} else {
hs = hs + stmp;
}
}
return hs.toUpperCase();
}


// =============== **关键找函数** ============
protected Class<?> findClass(String name)
throws ClassNotFoundException
{
String res = name.replace(".", "/");//将所有的。替换成/,比如pwnhub/checkFlag

res = "/" + res;
int l = res.lastIndexOf("/");
String className = res.substring(l + 1);//取出类名字
try
{
res = res.substring(0, l + 1) + md5(className.getBytes()) + ".class";//这里看到,res的内容为地址/MD5(class)
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
InputStream is = getClass().getResourceAsStream(res);//is 为当前取出的类作为文件流(?)

long len = 0L;
try
{
len = is.available();//当前文件的可见字符部分(文件大小)
}
catch (IOException e)
{
e.printStackTrace();
}
byte[] raw = new byte[(int)len];
try
{
int r = 0;
int off = 0;
for (;;)
{
r = is.read(raw, off, (int)len);//将文件内容读入raw中
if (r == len) {
break;
}
len -= r;
off += r;
}
}
catch (IOException e)
{
e.printStackTrace();
}
String ivStr = "****************";
MessageDigest md = null;
try
{
md = MessageDigest.getInstance("MD5");
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
assert (md != null);
// 关键!这里将我们的数mdzz传进来了而且即将加密
md.update(code.getBytes());
// 这里使用mdzz作为关键密码
byte[] key = md.digest();

Cipher cipher = null;
try
{
// TMD又是加密!!!这次而且是AES!!再玩上次那套就打人了!!!
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
}
catch (NoSuchAlgorithmException|NoSuchPaddingException e)
{
e.printStackTrace();
}
//冷静一下,这里我们已经得到了aes的密钥和iv
SecretKeySpec skey = new SecretKeySpec(key, "AES");
IvParameterSpec iv = new IvParameterSpec(ivStr.getBytes());
try
{
assert (cipher != null);
cipher.init(2, skey, iv);
}
catch (InvalidKeyException|InvalidAlgorithmParameterException e)
{
e.printStackTrace();
}
byte[] en = null;
try
{
// 这里将得到的文件,使用我们之前指定的内容进行加密卧槽。。。
en = cipher.doFinal(raw);
}
catch (IllegalBlockSizeException|BadPaddingException e)
{
e.printStackTrace();
}
assert (en != null);
// 最后定义我们得到的class,名字是传进来的name,en是我们需要加载的字节码(卧槽),我已经不想看了怎么办。。。
Class clazz = defineClass(name, en, 0, en.length);
if (clazz == null) {
throw new ClassNotFoundException(name);
}
return clazz;
}
}

简单来说,这个倒霉的程序,把我们需要的类给加密了。。这还是第一次捡到这类的。。不过从这个歌处理方式来看,所有的类的名字应该都是被加过密的,所以这里假设che这个checkFlag类也被加密了,那么此时得到的就会是:
b51e17dbdb36295e7ab7541157ae7480
令人兴奋的是,的确是存在对应的类的。那么我们就确定了被加密的文件,接下来需要将这个加密后的文件进行解密:
吐槽一句,java的题目最讨厌的就是,java的加密总是和其他程序的加密不太一样,非要用它自己的方法来解开。

然后,好像成功了?接下来就是将这个.class文件反编译一下了:
上面这一步骤我几乎做了一万年。。。。辣鸡eclipse真的不想再用第二次。。用了一个叫做beyond compare的软件完成了反汇编:

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
// Decompiled by Jad v1.5.8e2. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://kpdus.tripod.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: checkFlag.java

package pwnhub;

import java.io.*;
import java.util.Arrays;

// Referenced classes of package pwnhub:
// load, cadqa

public class checkFlag
{

public checkFlag()
{
}

public static void check()
throws Exception
{
load.l();
BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
System.out.println("ok, now give me flag");
System.out.print("flag:");
String flag = strin.readLine();
int b[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0
};
byte result[] = cadqa.i(flag.getBytes(), b);
byte tFlag[] = {
16, 37, -54, -1, -36, -34, -83, -64, 39, -112,
5, -85, 61, 108, -4, 13, 85, -22, -116, -77,
31, 21, -64, 13, -86, -48, -86, -115, -28, -82,
48, -15
};
if(Arrays.equals(result, tFlag))
System.out.println((new StringBuilder()).append("pwnhub{flag:").append(flag).append("}").toString());
else
System.out.println("try again");
}
}

我还以为做完的时候,突然当头一棒!这个cadqa是什么啊。。。。。。我仿佛看到了结局。。。。
a1ccf9b501dacecf3bae1c3a37bce98e
这个类也是存在的

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
// Decompiled by Jad v1.5.8e2. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://kpdus.tripod.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: cadqa.java

package pwnhub;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class cadqa
{

public cadqa()
{
}

public static byte[] i(byte a[], int b[])
throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException
{
b[2] ^= 0x1b54c30c;
String d = (new StringBuilder()).append("pwnhub.").append(y("#\033<k8")).toString();//这里还对输入的字符。。。我累了
Class c = Class.forName(d);
Method i = c.getMethod("i", new Class[] {
(new byte[0]).getClass(), (new int[0]).getClass()
});
return (byte[])(byte[])i.invoke(null, new Object[] {
a, b
});
}

private static String y(String a)//input :# \033 < k 8->
{ //output :wmyvg
byte b[] = a.getBytes();
for(int i = 0; i < 5; i++)
switch(i)
{
case 0: // '\0'
b[i] ^= 0x54;
break;

case 1: // '\001'
b[i] ^= 0x76;
break;

case 2: // '\002'
b[i] ^= 0x45;
break;

case 3: // '\003'
b[i] ^= 0x1d;
break;

case 4: // '\004'
b[i] ^= 0x5f;
break;
}

return new String(b);
}
}

我tm做着做着觉得不对。。。。。卧槽又有一个类。。。我真的睡了。。。

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
// Decompiled by Jad v1.5.8e2. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://kpdus.tripod.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: wmyvg.java

package pwnhub;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class wmyvg
{

public wmyvg()
{
}

public static byte[] i(byte a[], int b[])
throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException
{
b[14] ^= 0x181c64dc;
String d = (new StringBuilder()).append("pwnhub.").append(y("\007_d-'")).toString();
Class c = Class.forName(d);
Method i = c.getMethod("i", new Class[] {
(new byte[0]).getClass(), (new int[0]).getClass()
});
return (byte[])(byte[])i.invoke(null, new Object[] {
a, b
});
}

private static String y(String a)
{
byte b[] = a.getBytes();
for(int i = 0; i < 5; i++)
switch(i)
{
case 0: // '\0'
b[i] ^= 0x61;
break;

case 1: // '\001'
b[i] ^= 0x2b;
break;

case 2: // '\002'
b[i] ^= 0xc;
break;

case 3: // '\003'
b[i] ^= 0x54;
break;

case 4: // '\004'
b[i] ^= 0x4b;
break;
}

return new String(b);
}
}

我们来冷静分析一下,每次都是b[i]会被重新赋值,而我们知道,b[i]总共为16位,那么这个游戏应该会持续16次(卧槽)。虽然一开始的时候想着要将全部都反编译一下,但是此时我发现扰乱的部分太多了。。。还是得一点点做。。
==>\007_d-’
==>fthyl
==>
之后都不贴完整的了。。。。要找的太多。。
fthyl:
b[1] ^= 0x4b164dc6;
string = [Qg2t ==>knklz
knklz:
b[3] ^= 0x2e558ed3;
string = “Zg<P\037”==>swygk
swygk:
b[13] ^= 0x224b13e8;
string = “m\023y+8” ==>xbzvx
xbzvx:
b[3] ^= 0x545a51c4;
string = “yT(\b" ==>bstqh
bstqh:
b[9] ^= 0xb2bb4d8;
string = “\177M\034@?” ==>lmvxj
lmvxj:
b[4] ^= 0x15532729;
string = "Y|yB
” ==>iaclf
iaclf:
b[1] ^= 0xef2b115;
string = " b]Z8"==>cipgj
爆炸了这做到什么时候去啊粉蛋!!!!!仔细一想。。。这个文件是一个.jar…那么应该是可以执行的才对。。于是这里尝试上一波调试。。
eclipse再次爆炸,我渐渐明白了什么叫做一生黑。。。
使用jdb进行调试,首先java的调试方式是通过运行程序使其存在于在某个端口,然后通过jdb进行connect:

1
2
java -agentlib:jdwp=transport=dt_socket,server=y,address=8050,suspend=y -jar pwnhub.jar #设置端口

然后打开另一个终端,此时:

1
jdb -connect com.sun.jdi.SocketAttach:port=8050

将调试器attach上去,从而进行调试。
首先是 pwnhub.d1a2276cb6055f0a6d12ac4004352f0b.(), 行=24 bci=25处设置断点。
step
然后是:pwnhub.load.l(), 行=1,509 bci=10,247
next
在pwnhub.checkFlag.check(), 行=16 bci=37处发生了capda
然后每个16行就发生一次写入数据。。。
最后在同伴的帮助下,使用了grep找到了另一部分的类。。。。。发现原来有另一种函数,那个函数也是非常长…上网查询后估计是des加密的一种(猜测),然后注意到,这个类里面的方法叫做b,并不是之前的i,所以我们猜测在这种五个字母组成的字符串的类中一定存在着某一个类调用了这个方法(不然为什么最后的答案位数那么多),利用grep+正则表达式,找到了了一种以**【四个字母】**开头的程序:
frsu:

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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
public class frsu {
public frsu() {
}

static byte[] b(byte[] var0, int[] var2) throws Exception {
int[] var3 = new int[]{943331329, 170788368, 1008414755, 187049985, 1010368540, 220604441, 940377620, 255209728, 689771012, 221709344, 957157408, 892536332, 722417666, 1026621720, 655302664, 890966315};
int[] vark = new int[]{1847617210, 1994607775, 1906299266, 1443467998, 1753140052, 782026644, 743697037, 1500018807, 1015162722, 141403752, 1057274701, 1430471406, 921937966, 1419221067, 962664086, 2133607337};

// === key 发生了亦或处理 ===
for(int var11 = 0; var11 < 16; ++var11) {
var2[var11] ^= vark[var11];
}

// === 扩展成了32位的数据 ===
int[] ext_key = new int[32];


int key_index;
for(key_index = 0; key_index < 16; ++key_index) {
ext_key[key_index] = var3[key_index];
}

for(key_index = 0; key_index < 16; ++key_index) {
ext_key[key_index + 16] = var2[key_index];
}

byte[] cipher_text = var0;
int[] S0 = new int[]{16843776, 0, 65536, 16843780, 16842756, 66564, 4, 65536, 1024, 16843776, 16843780, 1024, 16778244, 16842756, 16777216, 4, 1028, 16778240, 16778240, 66560, 66560, 16842752, 16842752, 16778244, 65540, 16777220, 16777220, 65540, 0, 1028, 66564, 16777216, 65536, 16843780, 4, 16842752, 16843776, 16777216, 16777216, 1024, 16842756, 65536, 66560, 16777220, 1024, 4, 16778244, 66564, 16843780, 65540, 16842752, 16778244, 16777220, 1028, 66564, 16843776, 1028, 16778240, 16778240, 0, 65540, 66560, 0, 16842756};
int[] S1 = new int[]{-2146402272, -2147450880, '耀', 1081376, 1048576, 32, -2146435040, -2147450848, -2147483616, -2146402272, -2146402304, -2147483648, -2147450880, 1048576, 32, -2146435040, 1081344, 1048608, -2147450848, 0, -2147483648, '耀', 1081376, -2146435072, 1048608, -2147483616, 0, 1081344, '耠', -2146402304, -2146435072, '耠', 0, 1081376, -2146435040, 1048576, -2147450848, -2146435072, -2146402304, '耀', -2146435072, -2147450880, 32, -2146402272, 1081376, 32, '耀', -2147483648, '耠', -2146402304, 1048576, -2147483616, 1048608, -2147450848, -2147483616, 1048608, 1081344, 0, -2147450880, '耠', -2147483648, -2146435040, -2146402272, 1081344};
int[] S2 = new int[]{520, 134349312, 0, 134348808, 134218240, 0, 131592, 134218240, 131080, 134217736, 134217736, 131072, 134349320, 131080, 134348800, 520, 134217728, 8, 134349312, 512, 131584, 134348800, 134348808, 131592, 134218248, 131584, 131072, 134218248, 8, 134349320, 512, 134217728, 134349312, 134217728, 131080, 520, 131072, 134349312, 134218240, 0, 512, 131080, 134349320, 134218240, 134217736, 512, 0, 134348808, 134218248, 131072, 134217728, 134349320, 8, 131592, 131584, 134217736, 134348800, 134218248, 520, 134348800, 131592, 8, 134348808, 131584};
int[] S3 = new int[]{8396801, 8321, 8321, 128, 8396928, 8388737, 8388609, 8193, 0, 8396800, 8396800, 8396929, 129, 0, 8388736, 8388609, 1, 8192, 8388608, 8396801, 128, 8388608, 8193, 8320, 8388737, 1, 8320, 8388736, 8192, 8396928, 8396929, 129, 8388736, 8388609, 8396800, 8396929, 129, 0, 0, 8396800, 8320, 8388736, 8388737, 1, 8396801, 8321, 8321, 128, 8396929, 129, 1, 8192, 8388609, 8193, 8396928, 8388737, 8193, 8320, 8388608, 8396801, 128, 8388608, 8192, 8396928};
int[] S4 = new int[]{256, 34078976, 34078720, 1107296512, 524288, 256, 1073741824, 34078720, 1074266368, 524288, 33554688, 1074266368, 1107296512, 1107820544, 524544, 1073741824, 33554432, 1074266112, 1074266112, 0, 1073742080, 1107820800, 1107820800, 33554688, 1107820544, 1073742080, 0, 1107296256, 34078976, 33554432, 1107296256, 524544, 524288, 1107296512, 256, 33554432, 1073741824, 34078720, 1107296512, 1074266368, 33554688, 1073741824, 1107820544, 34078976, 1074266368, 256, 33554432, 1107820544, 1107820800, 524544, 1107296256, 1107820800, 34078720, 0, 1074266112, 1107296256, 524544, 33554688, 1073742080, 524288, 0, 1074266112, 34078976, 1073742080};
int[] S5 = new int[]{536870928, 541065216, 16384, 541081616, 541065216, 16, 541081616, 4194304, 536887296, 4210704, 4194304, 536870928, 4194320, 536887296, 536870912, 16400, 0, 4194320, 536887312, 16384, 4210688, 536887312, 16, 541065232, 541065232, 0, 4210704, 541081600, 16400, 4210688, 541081600, 536870912, 536887296, 16, 541065232, 4210688, 541081616, 4194304, 16400, 536870928, 4194304, 536887296, 536870912, 16400, 536870928, 541081616, 4210688, 541065216, 4210704, 541081600, 0, 541065232, 16, 16384, 541065216, 4210704, 16384, 4194320, 536887312, 0, 541081600, 536870912, 4194320, 536887312};
int[] S6 = new int[]{2097152, 69206018, 67110914, 0, 2048, 67110914, 2099202, 69208064, 69208066, 2097152, 0, 67108866, 2, 67108864, 69206018, 2050, 67110912, 2099202, 2097154, 67110912, 67108866, 69206016, 69208064, 2097154, 69206016, 2048, 2050, 69208066, 2099200, 2, 67108864, 2099200, 67108864, 2099200, 2097152, 67110914, 67110914, 69206018, 69206018, 2, 2097154, 67108864, 67110912, 2097152, 69208064, 2050, 2099202, 69208064, 2050, 67108866, 69208066, 69206016, 2099200, 0, 2, 69208066, 0, 2099202, 69206016, 2048, 67108866, 67110912, 2048, 2097154};
int[] S7 = new int[]{268439616, 4096, 262144, 268701760, 268435456, 268439616, 64, 268435456, 262208, 268697600, 268701760, 266240, 268701696, 266304, 4096, 64, 268697600, 268435520, 268439552, 4160, 266240, 262208, 268697664, 268701696, 4160, 0, 0, 268697664, 268435520, 268439552, 266304, 262144, 266304, 262144, 268701696, 4096, 64, 268697664, 4096, 266304, 268439552, 64, 268435520, 268697600, 268697664, 268435456, 262144, 268439616, 0, 268701760, 262208, 268435520, 268697600, 268439552, 268439616, 0, 268701760, 266240, 266240, 4160, 4160, 262208, 268435456, 268701696};
int cipher_text_length = var0.length;
key_index = cipher_text_length % 8;//注意,我们的字符串长度应该是8的倍数
if(key_index != 0) {
System.out.println("try again");
System.exit(0);
}

byte var301 = 2;
int[] var21 = new int[var301];
byte[] var22 = new byte[cipher_text_length];
int group = cipher_text_length / 8;

for(int var24 = 0; var24 < group; ++var24) {
int var25 = var24 * 8;

int var26;
// === 分组整合 ===
for(var26 = 0; var26 < 2; ++var26) {
var21[var26] = (cipher_text[var25 + var26 * 4] & 255) << 24 | (cipher_text[var25 + var26 * 4 + 1] & 255) << 16 | (cipher_text[var25 + var26 * 4 + 2] & 255) << 8 | cipher_text[var25 + var26 * 4 + 3] & 255;
}

int key_index = 0;
int var29 = var21[0];
int var28 = var21[1];
int var27 = (var29 >>> 4 ^ var28) & 252645135;//0xf0f0f0f
var28 ^= var27;
var29 ^= var27 << 4;
var27 = (var29 >>> 16 ^ var28) & '\uffff';//0x0000ffff
var28 ^= var27;
var29 ^= var27 << 16;
var27 = (var28 >>> 2 ^ var29) & 858993459;//0x33333333
var29 ^= var27;
var28 ^= var27 << 2;
var27 = (var28 >>> 8 ^ var29) & 16711935;//0x00ff00ff
var29 ^= var27;
var28 ^= var27 << 8;
var28 = var28 << 1 | var28 >>> 31 & 1;
var27 = (var29 ^ var28) & -1431655766;//0xaaaaaaaa
var29 ^= var27;
var28 ^= var27;
var29 = var29 << 1 | var29 >>> 31 & 1;

for(int var30 = 0; var30 < 8; ++var30) {
var27 = var28 << 28 | var28 >>> 4;
var27 ^= ext_key[key_index++];
var26 = S6[var27 & 63];
var26 |= S4[var27 >>> 8 & 63];
var26 |= S2[var27 >>> 16 & 63];
var26 |= S0[var27 >>> 24 & 63];
var27 = var28 ^ ext_key[key_index++];
var26 |= S7[var27 & 63];
var26 |= S5[var27 >>> 8 & 63];
var26 |= S3[var27 >>> 16 & 63];
var26 |= S1[var27 >>> 24 & 63];
var29 ^= var26;
var27 = var29 << 28 | var29 >>> 4;
var27 ^= ext_key[key_index++];
var26 = S6[var27 & 63];
var26 |= S4[var27 >>> 8 & 63];
var26 |= S2[var27 >>> 16 & 63];
var26 |= S0[var27 >>> 24 & 63];
var27 = var29 ^ ext_key[key_index++];
var26 |= S7[var27 & 63];
var26 |= S5[var27 >>> 8 & 63];
var26 |= S3[var27 >>> 16 & 63];
var26 |= S1[var27 >>> 24 & 63];
var28 ^= var26;
}

var28 = var28 << 31 | var28 >>> 1;
var27 = (var29 ^ var28) & -1431655766;
var29 ^= var27;
var28 ^= var27;
var29 = var29 << 31 | var29 >>> 1;
var27 = (var29 >>> 8 ^ var28) & 16711935;
var28 ^= var27;
var29 ^= var27 << 8;
var27 = (var29 >>> 2 ^ var28) & 858993459;
var28 ^= var27;
var29 ^= var27 << 2;
var27 = (var28 >>> 16 ^ var29) & '\uffff';
var29 ^= var27;
var28 ^= var27 << 16;
var27 = (var28 >>> 4 ^ var29) & 252645135;
var29 ^= var27;
var28 ^= var27 << 4;
var21[0] = var28;
var21[1] = var29;
int var32 = var24 * 8;

for(int var33 = 0; var33 < 2; ++var33) {
var22[var32 + var33 * 4] = (byte)(var21[var33] >>> 24);
var22[var32 + var33 * 4 + 1] = (byte)(var21[var33] >>> 16);
var22[var32 + var33 * 4 + 2] = (byte)(var21[var33] >>> 8);
var22[var32 + var33 * 4 + 3] = (byte)var21[var33];
}
}

byte var10000 = var22[var22.length - 1];
return var22;
}
}

由大量魔数可知,这一定是一个des加密方法,而des加密的重点在于其是一个**【对称】**的加密,它在密钥的时候上是一个对称的状态,尤其从下面代码中可以看出:

1
2
3
4
5
6
7
8
9
10
11
12
var27 = var28 << 28 | var28 >>> 4;
var27 ^= ext_key[key_index++];
var26 = S6[var27 & 63];
var26 |= S4[var27 >>> 8 & 63];
var26 |= S2[var27 >>> 16 & 63];
var26 |= S0[var27 >>> 24 & 63];
var27 = var28 ^ ext_key[key_index++];
var26 |= S7[var27 & 63];
var26 |= S5[var27 >>> 8 & 63];
var26 |= S3[var27 >>> 16 & 63];
var26 |= S1[var27 >>> 24 & 63];
var29 ^= var26;

这个加密是以2个为一组进行加密,而且des本身的解密就是将密钥倒过来使用,而由之前的代码可得到加密后的明文,所以这里我们将密码倒过来使用:

1
2
3
4
5
6
7
8
9
for (int i = 0; i < 16; i += 2) {
for (int j = 0; j < 2; ++j) {
int t = var291[30 - i + j];
var291[30 - i + j] = var291[i + j];
var291[i + j] = t;
System.out.printf("%d %d\n", 30 - i + j, i + j);
}

}

最终!!!!!我们成功的得到了一串不带负数的答案!!