刮开有奖
用 ida 打开,shift + F12 查看字符串列表,看到有一个字符串 “U g3t 1T!” ,有点像 “u got it!” 的感觉,可能是需要的信息,点进去,然后选中,Ctrl + x 交叉引用列表,f5 来到源代码
自下而上分析:
(1)输出 “U g3t 1T!” 的话,要满足 if 判断,if 判断里面,要求 String[0]、String[1]、String[2]、v4 和 v5 同时满足对应条件
(2)其中 v5 是数组 v18 经过 sub_401000 函数处理后的值,v18 的值又是分别等于 String[3]、String[2]、String[4]
(3)同时 v4 也是数组 v18 经过 sub_401000 函数处理后的值,这时 v18 的值又是分别等于 String[5]、String[7]、String[6]
(4)然后看到是对 v7 的处理,通过函数 sub_4010F0,在往上是对一系列变量的赋值
总体来说,就是通过 GetDlgItemTextA 获取了某个值之后,如果 String 长度为 8 时候,进行 (4)、(3)、(2) 的操作,然后如果通过了 (1) 的判断,最后输出 “U g3t 1T!”
下面先看对 v7 的处理,v7 的值为 ‘ZJ’,调用了 sub_4010F0(v7, 0, 10);,进去发现是这样的代码,如下
(_DWORD *)是强制类型转化,将值转换为指向 DWORD 的指针
经常看汇编的会觉得比较熟悉,尝试将其变得更易于理解
int __cdecl sub_4010F0(int a1[], int a2, int a3) // v7, 0, 10
//int __cdecl sub_4010F0(int a1, int a2, int a3)
{
int result; // eax
int i; // esi
int v5; // ecx
int v6; // edx
result = a3; // result=10
for ( i = a2; i <= a3; a2 = i ) // i=0, i<=10
{
v5 = i;//v5 = 4 * i;
v6 = a1[i];//v6 = *(_DWORD *)(4 * i + a1);
if ( a2 < result && i < result )
{
do
{
if ( v6 > a1[result] )//if ( v6 > *(_DWORD *)(a1 + 4 * result) )
{
if ( i >= result )
break;
++i;
a1[v5] = a1[result];// *(_DWORD *)(v5 + a1) = *(_DWORD *)(a1 + 4 * result);
if ( i >= result )
break;
while ( a1[i] <= v6 )// while ( *(_DWORD *)(a1 + 4 * i) <= v6 )
{
if ( ++i >= result )
goto LABEL_13;
}
if ( i >= result )
break;
v5 = i;//v5 = 4 * i;
a1[result] = a1[i];// *(_DWORD *)(a1 + 4 * result) = *(_DWORD *)(4 * i + a1);
}
--result;
}
while ( i < result );
}
LABEL_13:
a1[result] = v6;//*(_DWORD *)(a1 + 4 * result) = v6;
sub_4010F0(a1, a2, i - 1);
result = a3;
++i;
}
return result;
}
改完之后,可以发现一个问题,函数调用时候传参是 sub_4010F0(v7, 0, 10);,因此 v7 这个地址传入之后,它 v7[result] 寻址很明显超了 v7 的正常数组大小。
这个时候观察原本的 v7 - v16,发现它们的地址是连续的,因此可以判断,其实整个 sub_4010F0(v7, 0, 10) 的调用,是对 v7 - v16 整体进行操作,只不过可能 ida 在反编译时候,没有将这个整体识别成一个数组,我们可以用快捷键 Y 自行修改,这里就懒得改了。
虽然这个 sub_4010F0() 的操作没有看懂,但是影响不大,直接跑一轮看看结果
#include <iostream>
using namespace std;
int __cdecl sub_4010F0(int a1[11], int a2, int a3)
{
int result; // eax
int i; // esi
int v5; // ecx
int v6; // edx
result = a3; // result=10
for (i = a2; i <= a3; a2 = i) // i=0, i<=10
{
v5 = i;//v5 = 4 * i;
v6 = a1[i];//v6 = *(_DWORD *)(4 * i + a1);
if (a2 < result && i < result)
{
do
{
if (v6 > a1[result])//if ( v6 > *(_DWORD *)(a1 + 4 * result) )
{
if (i >= result)
break;
++i;
a1[v5] = a1[result];// *(_DWORD *)(v5 + a1) = *(_DWORD *)(a1 + 4 * result);
if (i >= result)
break;
while (a1[i] <= v6)// while ( *(_DWORD *)(a1 + 4 * i) <= v6 )
{
if (++i >= result)
goto LABEL_13;
}
if (i >= result)
break;
v5 = i;//v5 = 4 * i;
a1[result] = a1[i];// *(_DWORD *)(a1 + 4 * result) = *(_DWORD *)(4 * i + a1);
}
--result;
} while (i < result);
}
LABEL_13:
a1[result] = v6;//*(_DWORD *)(a1 + 4 * result) = v6;
sub_4010F0(a1, a2, i - 1);
result = a3;
++i;
}
return result;
}
int main()
{
int v7[11];
v7[0] = 90;
v7[1] = 74;
v7[2] = 83;
v7[3] = 69;
v7[4] = 67;
v7[5] = 97;
v7[6] = 78;
v7[7] = 72;
v7[8] = 51;
v7[9] = 110;
v7[10] = 103;
for (int i = 0; i < 11; i++)
{
printf("%c", v7[i]);
}
printf("\n");
sub_4010F0(v7, 0, 10);
for (int i = 0; i < 11; i++)
{
printf("%c", v7[i]);
}
printf("\n");
return 0;
}
结果如下
ZJSECaNH3ng
3CEHJNSZagn
下面看 sub_401000 函数,点进去之后如下
乍一看挺复杂的,但是观察一开始的处理,这里参数 v2 是字符的 len 长度,先判断 %3 是否为 0,从这个点上面,可能可以联想到 base64 的 %3 的操作,因为 base64 处理时候就是按照 3 bite 进行分组的。
往后看的话,在 byte_407830 这个数组里面,确实是找到了 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
这个特征,所以直接猜测 sub_401000 就是一个 base64 的处理操作
所以把 “ak1w”、“V1Ax” 解一下得到 jMp、WP1
现在回来看这个if判断
if ( String[0] == v7[0] + 34
&& String[1] == v10
&& 4 * String[2] - 141 == 3 * v8
&& String[3] / 4 == 2 * (v13 / 9)
&& !strcmp(v4, "ak1w")
&& !strcmp(v5, "V1Ax") )
结合
v9[0] = String[5];
v9[2] = String[7];
v9[1] = String[6];
v4 = (const char *)sub_401000(v9, strlen(v9));
memset(v9, 0, 0xFFFFu);
v9[1] = String[3];
v9[0] = String[2];
v9[2] = String[4];
那么每个 String 都可以解出来了
编写解密脚本
#include <iostream>
using namespace std;
int main()
{
string v7_s = "3CEHJNSZagn";
int v7[11] = {0};
for (int i = 0; i < v7_s.length(); i++)
{
v7[i] = int(v7_s[i]);
}
int String[8];
String[0] = v7[0] + 34;
String[1] = v7[4];
String[2] = (3 * v7[2] + 141) / 4;
String[3] = 2 * (v7[7] / 9) * 4;
string v9 = "WP1";
String[4] = int(v9[2]);
v9 = "jMp";
String[5] = int(v9[0]);
String[6] = int(v9[1]);
String[7] = int(v9[2]);
for (int i = 0; i < 8; i++)
{
printf("%c", String[i]);
}
return 0;
}