usualCrypt
环境
- IDA pro
- windows10
题目
[ACTF新生赛2020]usualCrypt
先查壳

发现是32位程序,无壳,拖入IDA
IDA反编译后
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v3; // esi
int result; // eax
int v5[3]; // [esp+8h] [ebp-74h] BYREF
__int16 v6; // [esp+14h] [ebp-68h]
char v7; // [esp+16h] [ebp-66h]
char v8[100]; // [esp+18h] [ebp-64h] BYREF
sub_403CF8(&unk_40E140);
scanf("%s", v8);
v5[0] = 0;
v5[1] = 0;
v5[2] = 0;
v6 = 0;
v7 = 0;
sub_401080(v8, strlen(v8), v5);
v3 = 0;
while ( *((_BYTE *)v5 + v3) == byte_40E0E4[v3] )
{
if ( ++v3 > strlen((const char *)v5) )
goto LABEL_6;
}
sub_403CF8(aError);
LABEL_6:
if ( v3 - 1 == strlen(byte_40E0E4) )
result = sub_403CF8(aAreYouHappyYes);
else
result = sub_403CF8(aAreYouHappyNo);
return result;
}
注意几个关键的地方,一行行分析
sub_403CF8(&unk_40E140); //点入unk_40E140,发现是字符串
.data:0040E148 db 47h ; G
.data:0040E149 db 69h ; i
.data:0040E14A db 76h ; v
.data:0040E14B db 65h ; e
.data:0040E14C db 20h
.data:0040E14D db 6Dh ; m
.data:0040E14E db 65h ; e
.data:0040E14F db 20h
.data:0040E150 db 79h ; y
.data:0040E151 db 6Fh ; o
.data:0040E152 db 75h ; u
.data:0040E153 db 72h ; r
.data:0040E154 db 20h
.data:0040E155 db 66h ; f
.data:0040E156 db 6Ch ; l
.data:0040E157 db 61h ; a
.data:0040E158 db 67h ; g
.data:0040E159 db 3Ah ; :
估计sub_403CF8是输出函数,同时注意到 24行的sub_403CF8(aError),估计是输出错误信息的,果然
.data:0040E134 aError db 'error!',0Ah,0 ; DATA XREF: _main:loc_40122B↑o
看下一行
scanf("%s", v8);
v5[0] = 0;
v5[1] = 0;
v5[2] = 0;
v6 = 0;
v7 = 0;
输入的字符串放到v8这个char数组那里,v5是int数组,长度为3,并全部置零
继续
sub_401080(v8, strlen(v8), v5);
点入这个函数

注意该函数声明许多参数,并发现函数 sub_401000(),点入查看,内容如下
int sub_401000()
{
int result; // eax
char v1; // cl
for ( result = 6; result < 15; ++result )
{
v1 = byte_40E0AA[result];
byte_40E0AA[result] = byte_40E0A0[result];
byte_40E0A0[result] = v1;
}
return result;
}
注意到是对byte_40E0AA和byte_40E0A0进行操作,点击查看,查看如下
.data:0040E0A0 byte_40E0A0 db 41h ; DATA XREF: sub_401000:loc_401005↑r
.data:0040E0A0 ; sub_401000+17↑w ...
.data:0040E0A1 db 42h ; B
.data:0040E0A2 db 43h ; C
.data:0040E0A3 db 44h ; D
.data:0040E0A4 db 45h ; E
.data:0040E0A5 db 46h ; F
.data:0040E0A6 db 47h ; G
.data:0040E0A7 db 48h ; H
.data:0040E0A8 db 49h ; I
.data:0040E0A9 db 4Ah ; J
.data:0040E0AA ; char byte_40E0AA[]
.data:0040E0AA byte_40E0AA db 4Bh ; DATA XREF: sub_401000+B↑r
.data:0040E0AA ; sub_401000+11↑w
.data:0040E0AB aLmnopqrstuvwxy db 'LMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',0
.data:0040E0E1 align 4
估计两者应该是字符串数组,返回sub_401080函数,在经过sub_401000函数后,是一段很长的操作,发现都是对byte_40E0A0进行操作,但是好像byte_40E0A0只有10位,好吧,居然是40E0A0到40E0AA连起来的,然后继续看对其的操作,一开始并不知道是什么,经过查阅发现是base64加密,估计是对base的密钥表串进行了魔改,看到最后,发现sub_401030函数
int __cdecl sub_401030(const char *a1)
{
__int64 v1; // rax
char v2; // al
v1 = 0i64;
if ( strlen(a1) )
{
do
{
v2 = a1[HIDWORD(v1)];
if ( v2 < 97 || v2 > 122 )
{
if ( v2 < 65 || v2 > 90 )
goto LABEL_9;
LOBYTE(v1) = v2 + 32;
}
else
{
LOBYTE(v1) = v2 - 32;
}
a1[HIDWORD(v1)] = v1;
LABEL_9:
LODWORD(v1) = 0;
++HIDWORD(v1);
}
while ( HIDWORD(v1) < strlen(a1) );
}
return v1;
}
该函数把字符串每个英文字符进行了大小写转换,回到main,发现byte_40E0E4,查看发现是字符串MXHz3TIgnxLxJhFAdtZn2fFk3lYCrtPC2l9,是输入的数据进行了base64加密后的状态,整个拿到flag的过程就是对该程序执行逆向的过程
import base64
flag='' #保存flag
crypto='zMXHz3TIgnxLxJhFAdtZn2fFk3lYCrtPC2l9'.swapcase() #转换大小写,对sub_401030的逆向
base='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' #base64加密的索引表
# byte_40E0AA和byte_40E0A0字符数组的逆操作
dict={} #
for i in range(len(base)):
dict[base[i]] = base[i]
'''
for ( result = 6; result < 15; ++result )
{
v1 = byte_40E0AA[result];
byte_40E0AA[result] = byte_40E0A0[result];
byte_40E0A0[result] = v1;
}
'''
for i in range(6,15): #构造魔改后的索引表,10指的是byte_40E0A0长度
temp = dict[base[i]]
dict[base[i]] = dict[base[i+10]]
dict[base[i+10]] = temp
for i in range(len(crypto)):
flag += dict[crypto[i]]
flag = base64.b64decode(flag)
print(flag)
#b'flag{bAse64_h2s_a_Surprise}'

浙公网安备 33010602011771号