情景再现

查壳

image-20230218165645390

运行程序 直接ollydbg 运行 顺便看下字符串 有无切入点

发现了类似base64的踪迹 但是好几个 应该有说法

以及 一串类似密文的东西

image-20230218165808128

笔者 动调了一会并没有发现非预期的解法(因为笔者是个大菜鸡)

其实完全没必要动调的 直接静态分析更容易理解

拖入ida静态分析

看过字符串了 所以直接跟踪主函数就好了

image-20230218170319468

跟进401080查看 发现经过了三个加密

image-20230218170519312

跟进第一个 很容易发现是换表操作

image-20230218170630025

新表exp

1
2
3
4
5
6
7
8
T1 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
baseT = list(T1)

for i in range(6, 15):
baseT[i] = T1[i + 10]
baseT[i + 10] = T1[i]
print(''.join(baseT))
# ABCDEFQRSTUVWXYPGHIJKLMNOZabcdefghijklmnopqrstuvwxyz0123456789+/

然后就是这一大坨base64了

base64 原理就是 3个8位字符 变4个6位字符

贴一个容易理解的源码

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
/*base64.c*/  
#include "base64.h"

unsigned char *base64_encode(unsigned char *str)
{
long len;
long str_len;
unsigned char *res;
int i,j;
//定义base64编码表
unsigned char *base64_table="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

//计算经过base64编码后的字符串长度
str_len=strlen(str);
if(str_len % 3 == 0)
len=str_len/3*4;
else
len=(str_len/3+1)*4;

res=malloc(sizeof(unsigned char)*len+1);
res[len]='\0';

//以38位字符为一组进行编码
for(i=0,j=0;i<len-2;j+=3,i+=4)
{
res[i]=base64_table[str[j]>>2]; //取出第一个字符的前6位并找出对应的结果字符
res[i+1]=base64_table[(str[j]&0x3)<<4 | (str[j+1]>>4)]; //将第一个字符的后位与第二个字符的前4位进行组合并找到对应的结果字符
res[i+2]=base64_table[(str[j+1]&0xf)<<2 | (str[j+2]>>6)]; //将第二个字符的后4位与第三个字符的前2位组合并找出对应的结果字符
res[i+3]=base64_table[str[j+2]&0x3f]; //取出第三个字符的后6位并找出结果字符
}

switch(str_len % 3)
{
case 1:
res[i-2]='=';
res[i-1]='=';
break;
case 2:
res[i-1]='=';
break;
}

return res;
}

unsigned char *base64_decode(unsigned char *code)
{
//根据base64表,以字符找到对应的十进制数据
int table[]={0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,62,0,0,0,
63,52,53,54,55,56,57,58,
59,60,61,0,0,0,0,0,0,0,0,
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,0,0,0,0,0,0,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
};
long len;
long str_len;
unsigned char *res;
int i,j;

//计算解码后的字符串长度
len=strlen(code);
//判断编码后的字符串后是否有=
if(strstr(code,"=="))
str_len=len/4*3-2;
else if(strstr(code,"="))
str_len=len/4*3-1;
else
str_len=len/4*3;

res=malloc(sizeof(unsigned char)*str_len+1);
res[str_len]='\0';

//以4个字符为一位进行解码
for(i=0,j=0;i < len-2;j+=3,i+=4)
{
res[j]=((unsigned char)table[code[i]])<<2 | (((unsigned char)table[code[i+1]])>>4); //取出第一个字符对应base64表的十进制数的前6位与第二个字符对应base64表的十进制数的后2位进行组合
res[j+1]=(((unsigned char)table[code[i+1]])<<4) | (((unsigned char)table[code[i+2]])>>2); //取出第二个字符对应base64表的十进制数的后4位与第三个字符对应bas464表的十进制数的后4位进行组合
res[j+2]=(((unsigned char)table[code[i+2]])<<6) | ((unsigned char)table[code[i+3]]); //取出第三个字符对应base64表的十进制数的后2位与第4个字符进行组合
}

return res;

}

第三个加密 也很简单 是大小写转化

贴exp

1
2
3
4
encData = 'zMXHz3TIgnxLxJhFAdtZn2fFk3lYCrtPC2l9'

print(encData.swapcase())
#ZmxhZ3tiGNXlXjHfaDTzN2FfK3LycRTpc2L9

然后贴一个完整的exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# -*- coding:utf-8 -*-
import base64

T1 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
baseT = list(T1)

for i in range(6, 15):
baseT[i] = T1[i + 10]
baseT[i + 10] = T1[i]
Str = ''.join(baseT)
print(Str)

encData = 'zMXHz3TIgnxLxJhFAdtZn2fFk3lYCrtPC2l9'.swapcase()
print(encData)

flag = ''
for i in encData:
flag += T1[Str.index(i)]
print(base64.b64decode(flag))

flag{bAse64_h2s_a_Surprise}

总结

这道题其实并不难

不过 笔者过于菜 花费了不少时间

原因应该是过于浮躁了

我真该死 Orz

Orz

最后 笔者想说的是 做逆向题一定要有耐心

仔细 不要浮躁 慢慢来 其实基本功扎实了 并没有什么难题

(当然, 笔者还是一个刚接触逆向的小白, 太多不会的了)

哈哈哈哈

好的 本题结束 感谢观看 Orz