Reverse练习 writeup

0x1 apk.apk

反编译之后看java源码,涉及到的关键函数有点多,但是耐心的分析下代码程序的逻辑并不难,通过uc这个函数可以知道程序对“XRL}D6hy4yfE7tuF6{”这个字符串做了加密处理,下面这段程序就它的处理方法

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
public class cc
{
public static String encrypt(String paramString)
{
String str = "";
int i = 0;
if (i >= paramString.length()) {
return str;
}
int j = paramString.charAt(i);
char c;
if ((j >= 97) && (j <= 109)) {
c = (char)(j + 13);
}
for (;;)
{
str = str + c;
i += 1;
break;
if ((j >= 65) && (j <= 77)) {
c = (char)(j + 13);
} else if ((j >= 110) && (j <= 122)) {
c = (char)(j - 13);
} else if ((j >= 78) && (j <= 90)) {
c = (char)(j - 13);
} else if ((j >= 48) && (j <= 57)) {
c = (char)(j ^ 0x7);
} else {
c = (char)(j ^ 0x6);
}
}
}
}

把这段算法逆向回去就能得到正确的flag:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
str='XRL}D6hy4yfE7tuF6{'
str1=''
flag=''
for i in range(len(str)):
if(ord(str[i])>=97 and ord(str[i])<=109):
str1=str1 + chr(ord(str[i])+13)
else:
str1=str1+str[i]
for i in range(len(str1)):
if(ord(str1[i])>=65 and ord(str1[i])<=77):
flag=flag+chr(ord(str1[i])+13)
elif(ord(str1[i])>=110 and ord(str1[i])<=122):
flag = flag + chr(ord(str1[i]) - 13)
elif (ord(str1[i]) >= 78 and ord(str1[i]) <= 90):
flag = flag + chr(ord(str1[i]) - 13)
elif (ord(str1[i]) >= 48 and ord(str1[i]) <= 57):
flag = flag + chr(ord(str1[i]) ^ 7)
else:
flag = flag + chr(ord(str1[i]) ^ 6)
print(flag)

最后得到的结果是:KEY{Q1hl3lfR0ghS1}

0x2 Win.exe

载入IDA分析,找到关键代码处然后分析算法:根据程序的逻辑可以看出来,flag由两部分组成,上部分是由byte_415767这个数组中的字符串组成,并且根据v9这个数组里的值取下标组成上半部分flag,下半部分flag可以直接得到:1024}

解密代码如下:

1
2
3
4
5
6
7
str='sKfxEeft}f{gyrYgthtyhifsjei53UUrrr_t2cdsef66246087138\0087138'
list=[1,4,14,10,5,36,23,42,13,19,28,13,27,39,48,41,42]
str1='1024}'
flag=''
for i in list:
flag=flag+str[i]
print(flag+str1)

运行后法人结果为:KEY{e2s6ry3r5s8f61024}

0x3 defcamp

用IDA进行反汇编分析,找到关键代码,可以看到需要用户输入正确的password

函数sub_40074D是一个关键函数,里面有两个for循环,第一个for循环取qword_601080地址上的数据存入v6这个数组,第二个for循环是用v6和v9进行比较,数组v9的值为:5 2 7 2 5 6

但是在主函数中的for循环里面也调用了qword_601080,经过分析可以知道:v3=109+v9[i],所以最后得到的结果为:114 111 116 111 114 115,password就是:rotors

0x4 catalyst-system

用IDA反汇编,得到如下的伪代码

需要输入username和password,下面5个自定义函数分别对username和password做了相应的处理

将12个字节长的usrname分成3个4字节的int型并做成了方程组:

1
2
3
a−b+c=1550207830
3a+3c+b=12465522610
bc=3651346623716053780

最后解出:a = 1635017059 b = 1953724780 c = 1868915551
即username:catalyst_ceo
继续分析sub_400977这个函数

v2这个数组里存的是password,这里v2是等于一个随机数加上一个已知的数得到的,随机数有固定的随机种子srand(a1),a1是固定的所以产生的随机数也是固定的,这里可以写个C程序跑出来:

1
2
3
4
5
6
7
8
#include<stdlib.h>
#include<stdio.h>
int main()
{
srand(0x454d3e2e);
for (int i = 0;i < 10;i++)
printf("%x\n", rand());
}

最后产生的10组数为

1
2
3
4
5
6
7
8
9
10
0x684749
0x673ce537
0x7b4505e7
0x70a0b262
0x33d5253c
0x515a7675
0x596d7d5d
0x7cd29049
0x59e72db6
0x4654600d

计算出password的值后跟数组byte_6020A0数组中的值进行异或

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import os
import pwn
usr=""
pwd=""
flag=""
a = 1635017059
b = 1953724780
c = 1868915551
usr +=pwn.p32(a)+pwn.p32(b)+pwn.p32(c)
rand = [0x684749, 0x673ce537, 0x7b4505e7, 0x70a0b262, 0x33d5253c, 0x515a7675, 0x596d7d5d, 0x7cd29049, 0x59e72db6, 0x4654600d]
s=[1441465642,251096121,-870437532,-944322827,647240698,638382323,282381039,-966334428,-58112612,605226810]
s2=[0x42, 0x13, 0x27, 0x62, 0x41, 0x35, 0x6B, 0x0F, 0x7B, 0x46, 0x3C, 0x3E, 0x67, 0x0C, 0x08, 0x59, 0x44, 0x72, 0x36, 0x05, 0x0F, 0x15, 0x54, 0x43, 0x38, 0x17, 0x1D, 0x18, 0x08, 0x0E, 0x5C, 0x31, 0x21, 0x16, 0x02, 0x09, 0x18, 0x14, 0x54, 0x59]
for i, j in enumerate(rand):
print hex(s[i])
pwd += pwn.p32(j+s[i])
print "pwd:", pwd
for i,j in zip(pwd,s2):
flag+=chr(ord(i)^j)
print "flag:",flag

最后得到的结果为:
ALEXCTF{1_t41d_y0u_y0u_ar3__gr34t__reverser__s33}