目标对象:2.crackme.exe
环境:windows
工具:IDA Pro(32bit) (带有F5插件)
目标:找到flag
程序功能描述:输入少于24个字符会提示需要24个字符并使得重新输入;如果输入正确的24个字符,即flag,输出成功;不正确的24个字符,则输出失败。
IDA分析目标程序
点击main函数 F5反汇编成C语言代码
main函数:
int __cdecl main(int argc, const char **argv, const char **envp)
{
FILE *v3; // eax@3
signed int i; // [sp+14h] [bp-44h]@4
char v6[28]; // [sp+18h] [bp-40h]@1
int v7; // [sp+34h] [bp-24h]@1
char v8; // [sp+38h] [bp-20h]@1
int v9; // [sp+39h] [bp-1Fh]@1
int v10; // [sp+3Dh] [bp-1Bh]@1
int v11; // [sp+41h] [bp-17h]@1
int v12; // [sp+45h] [bp-13h]@1
int v13; // [sp+49h] [bp-Fh]@1
__int16 v14; // [sp+4Dh] [bp-Bh]@1
char v15; // [sp+4Fh] [bp-9h]@1
int v16; // [sp+50h] [bp-8h]@1
int v17; // [sp+54h] [bp-4h]@1
v8 = 0;
v9 = 0;
v10 = 0;
v11 = 0;
v12 = 0;
v13 = 0;
v14 = 0;
v15 = 0;
v7 = 3;
v17 = 0;
v16 = 0;
printf_s("[*] To get the flag, you need to input a correct string.\n\n");
scanf_s("%s", v6, 25);//输入字符串被读取到v6
while ( strlen(v6) != 24 )//v6不为长度24,重新获取输入
{
v3 = (FILE *)sub_4017DA();
fflush(v3);
printf_s("\n[*] Please Input a string with 24 characters!\n\n");
scanf_s("%s", v6, 25);
}
//为长度24的处理
for ( i = 0; i < 4; ++i )
//将长度24的字符串截断为4组长度为6的,每次传入6个给sub处理,分别进行转换,得到对应v8字符串
sub_401000((int)&v6[6 * i], (int)(&v8 + 6 * i));//关键转换函数sub
while ( v16 < 24 )//逐长度24判断
{
switch ( *(&v8 + v16) )
{//针对v8的每一个字符,变化v7或者v17(v7初始为3,v17初始为0)
case 1:
--v7;
break;
case 2:
++v7;
break;
case 3:
--v17;
break;
case 4:
++v17;
break;
default:
break;
}
if ( *(&byte_40E018[10 * v7] + v17) != 35 )//条件1
{//由v7和v17索引的byte数组的位置为#,则可行,否则输入错误
printf("\n[*] Sorry! Your input is wrong!\n\n");
exit(0);//24个字符都要满足条件1,否则就退出
}
++v16;
}
if ( v7 != 9 || v17 != 8 )//经过24次变化后最后的v7和v17需要满足该条件
printf("\n[*] Sorry! Your input is wrong!\n\n");
else
printf("\n[*] Nice job! Here is the flag: flag{%s}\n\n", v6);//flag是v6
return 0;
}
逻辑:
- 由条件1得到每一次的v7或者v17的变化,进而得到v8。
将条件1的数组分割成10*10的,从初始位置索引3,0开始走完所有的#,最后到达9,8
**********
*####*****
*#**#*****
##*##*****
***#******
***#*#####
***###***#
*********#
*********#
********##
v8: 411444 221222 441444 422221
- 通过关键函数sub,由v8逆推v6
//关键函数sub
int __cdecl sub_401000(int a1, int a2)
{//a2传入v8,a1传入v6
int result; // eax@7
signed int v3; // [sp+0h] [bp-8h]@1
signed int i; // [sp+4h] [bp-4h]@1
v3 = 0;
for ( i = 0; i < 6; ++i )
{
while ( v3 < 4 )
{
if ( *(_BYTE *)(i + a1) == *(&byte_40E000[4 * i] + v3) )
{
//如果六个一组的v6对应的值与数组被v3索引的值相等(每个v6对应数组的一行),则把v8对应位置设成v3+1
*(_BYTE *)(i + a2) = v3 + 1;//v8对应的位置的值为v3+1
break;
}
++v3;
}
v3 = 0;
result = i + 1;
}
return result;
}
数组分成4个一组,每组6个
0A1B
a2b3
4C5D
c6d7
8E9F
e0f1
通过v8的值推出v3,定位数组,得到v6
v6:Ba47F1 A24c8e B347F1 B2C6Ee
- 推断过程的值还没有验证,但是逻辑是对的
- 数组明文通过IDA的Hex View看到二进制