拿到逆向程序,按照常规逆向思路优先定位 main 函数梳理整体业务流程:
int __cdecl main_0(int argc, const char **argv, const char **envp)
{
char v4; // [esp+0h] [ebp-44Ch]
char v5; // [esp+0h] [ebp-44Ch]
char v6; // [esp+0h] [ebp-44Ch]
char v7; // [esp+0h] [ebp-44Ch]
char v8; // [esp+0h] [ebp-44Ch]
char v9; // [esp+0h] [ebp-44Ch]
char v10[4]; // [esp+194h] [ebp-2B8h] BYREF
int v11; // [esp+1A0h] [ebp-2ACh]
FILE *v12; // [esp+1ACh] [ebp-2A0h]
FILE *v13; // [esp+1B8h] [ebp-294h]
_BYTE v14[264]; // [esp+1C4h] [ebp-288h] BYREF
_BYTE v15[264]; // [esp+2CCh] [ebp-180h] BYREF
char Str1[60]; // [esp+3D4h] [ebp-78h] BYREF
char Str[56]; // [esp+410h] [ebp-3Ch] BYREF
__CheckForDebuggerJustMyCode(&unk_40B027);
memset(Str, 0, 50);
memset(Str1, 0, 50);
memset(v15, 0, 0x100u);
memset(v14, 0, 0x100u);
v11 = 1;
do
{
sub_401037(asc_406BA0, v4);
sub_401037((char *)&byte_406BFC, v5);
sub_401037(asc_406C48, v6);
sub_401037((char *)&byte_406CA8, v7);
sub_401037((char *)&byte_406D0C, v8);
sub_401037(a1, v9);
sub_401073("%d", (char)v10);
if ( *(_DWORD *)v10 == 1 )
{
v13 = fopen("flag.txt", "r");
if ( !v13 )
{
sub_401037((char *)&byte_406D48, v4);
getchar();
exit(0);
}
v12 = fopen("enflag.txt", "w");
if ( !v12 )
{
sub_401037((char *)&byte_406D70, v4);
getchar();
exit(0);
}
sub_401037(asc_406D84, v4);
sub_401073("%s", (char)Str);
sub_401069(Str, Str1);
sub_401028(Str, v15, v14, v13, v12);
}
else if ( *(_DWORD *)v10 == 2 )
{
v11 = 0;
}
else
{
sub_401037(asc_406D98, v4);
}
}
while ( v11 );
return 0;
}
程序执行流程:
1 进入文件加密功能,输入 2 退出程序Strsub_401069 进行密钥合法性校验flag.txt,使用密钥加密,密文写入 enflag.txtError!,不会执行加密逻辑sub_401069 是跳板函数,仅跳转至 sub_401A70,直接进入真实校验函数分析:
char __cdecl sub_401A70(char *Str, char *Str1)
{
char v3; // [esp+0h] [ebp-E4h]
signed int i; // [esp+D0h] [ebp-14h]
signed int v5; // [esp+DCh] [ebp-8h]
__CheckForDebuggerJustMyCode(&unk_40B027);
v5 = strlen(Str);
for ( i = 0; i < v5; ++i )
Str1[i] += Str[i] ^ 0x1F;
if ( !strcmp(Str1, "DH~mqqvqxB^||zll@Jq~jkwpmvez{") )
sub_401037((char *)&byte_406B80, v3);
else
sub_401037("Error!\n", v3);
return *Str1;
}
关键点:main 中提前 memset(Str1,0,50) 将数组全部置零,因此运算式可简化:
Str1[i] = Str[i] ^ 0x1F
校验条件:Str1 == "DH~mqqvqxB^||zll@Jq~jkwpmvez{"
逆推公式:Str[i] = 目标字节 ^ 0x1F
编写Python脚本还原合法密钥:
target = b"DH~mqqvqxB^||zll@Jq~jkwpmvez{"
key = bytes([c ^ 0x1F for c in target])
print(key)
运行结果:[Warnning]Access_Unauthorized
密钥校验通过后进入 sub_401028 加密函数,通过函数调用链特征判定为标准RC4:
RC4特性:加密与解密使用同一套算法,使用合法密钥对密文文件 enflag.txt 解密即可还原明文。
def rc4(key, data):
S = list(range(256))
j = 0
key_len = len(key)
# KSA 密钥调度
for i in range(256):
j = (j + S[i] + key[i % key_len]) % 256
S[i], S[j] = S[j], S[i]
# PRGA 密钥流生成
i = j = 0
result = []
for byte in data:
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
keystream_byte = S[(S[i] + S[j]) % 256]
result.append(byte ^ keystream_byte)
return bytes(result)
if __name__ == "__main__":
key = b"[Warnning]Access_Unauthorized"
with open("enflag.txt", "rb") as f:
cipher_data = f.read()
plain_data = rc4(key, cipher_data)
print(plain_data.decode())
flag{RC4&->ENc0d3F1le}