DDCTF的两道简单逆向

re1

32位PE文件,加了upx壳,先脱壳,随便一个工具就可以

脱完壳扔IDA,

逻辑其实很简单就是输入一串字符串,经过sub_401000这个函数处理之后,结果跟”DDCTF{reverseME}”进行比较

那么主要就是分析这个函数了,

虽然看起来干干净净,但是会发现有几个地方,v1定义了之后 直接用了,并没有任何的赋值,静态是看不出个所以然来的,所以我选择OD一波

这就是加密函数的汇编0x402FF8对应的就是数组 byte_402FF8,在IDA里可以看到,其实就是ASCII码表上的所以有值,

从0x20到0x7e就是可见字符,这个函数里面最核心的就是这句汇编mov dl byte ptr ds:[eax+0x402FF8],它就是通过你输入的字符,倒着来找,其实就是把0x20~0x7e倒一下然后一一对应就没了(所以就很类似异或),把DDCTF{reverseME},扔进去再倒一下就能得到正确的输入了

re2

这也是一道 32位PE逆向,加了aspack壳,也找个脱壳工具一脱就行,不过有个问题就是,脱完壳不能运行了,不过逻辑是没有错的,所以要动态调的话就用没脱壳的就行

汇编直接逆

先说一说头铁的做法,直接OD跟踪写出加密过程,再根据加密过程写去解密脚本,粗略地,的IDA上可以看到第一步检测和第一步加密

检测输入,长度为偶数,只能是[0,9]和[‘A’,’B’] (其实就是限制只能输入16进制数)

第一步加密,这里的加密逻辑还是可以从IDA里看出来的,(说白了就是将输入的字符转成16进制数,两个字符是一个16进制 嘛 )但是接下来的加密看起来就会有点懵(但是它就只是个base64加密,后面再讲),所以就去OD跟一下看看情况喽

因为用的是未脱壳的程序,在pushad后,下ESP硬件断点,F9运行至popad后

单步到程序的真正入口,就可以搜索到程序的字符,下断,F9过去

单步进去加密函数,接下来就是单步看汇编,整出来的结果就是

1
2
3
4
5
a = x>>2;
b = ((x&3)<<4)+(y>>4);
c = ((y&0xf)*4)+(z>>6);
d = z&0x3f;
(x,y,z为我们输入的三个16进制数(也就是6位字符))

最后将a,b,c,d拼在一起就是结果 ,出来跟’DDCTF{reverse+}’比较,逆回去其实很简单,就是已知a,b,c,d求,x,y,z,reverse+共8位,所以两次爆破就可以了

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
for(int x=0;x<=256;x++){
for(int y=0;y<=256;y++){
for(int z=0;z<=256;z++){
if(0x2b == x/4
&& 0x1e == (x&3)*16+y/16
&& 0x2f == (y&0xf)*4+z/64
&& 0x1e == (z&0x3f))
{
printf("%02x %02x %02x\n",x,y,z);
}
}
}
}
for(int x=0;x<=256;x++){
for(int y=0;y<=256;y++){
for(int z=0;z<=256;z++){
if(0x2b == x/4
&& 0x2c == (x&3)*16+y/16
&& 0x1e == (y&0xf)*4+z/64
&& 0x3e == (z&0x3f))
{
printf("%02x %02x %02x\n",x,y,z);
}
}
}
}

base64

其实这题的正解应该是base64,这也是常规的base64加密,只不过不是以输入字符去加密,而是直接输入16进制,也就是可以加密所有包括不可见字符,第一步转成16进制数就不用再说了,第二步的就是base64编码

所以我们只需要实现一个base64解码,以16进制形式输出就行了

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
#include <stdio.h>
#include <string.h>
int main()
{
char base64code[65] = {'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/','='};
char s[2048];
gets(s);
int l = strlen(s);
int t = 0;
char a[4];
while(t<l){
char x,y,z;
int temp = 0;
for(int i=0;i<4;i++){
a[i] = s[t++];
if(a[i]>='A'&&a[i]<='Z')
a[i] = a[i]-'A';
else if(a[i]>='a'&&a[i]<='z')
a[i] = a[i]-'G';
else if(a[i]>='0'&&a[i]<='9')
a[i] = a[i] + 4;
else if(a[i] == '='){
a[i] = a[i] + 3;
if(t == l){
temp = 1;
t = l;
break;
}
else{
temp = 2;
t = l;
break;
}
}
else if(a[i] == '+')
a[i] = a[i] + 19;
else if(a[i] == '/')
a[i] = a[i] + 16;
}
if(!temp){
x = (a[0]<<2) + (a[1]>>4);
y = (a[1]<<4) + (a[2]>>2);
z = (a[2]<<6) + (a[3]);
}
else if(!(temp-1)){
x = (a[0]<<2) + (a[1]>>4);
y = (a[1]<<4) + (a[2]>>2);
z = ' ';
}
else{
x = (a[0]<<2) + (a[1]>>4);
y = ' ';
z = ' ';
}
// printf("%c%c%c",x,y,z);
printf("%x %x %x ",x&0xff,y&0xff,z&0xff);
}
printf("\n");
return 0;
}

转成大写字母就是flag了

0%