题目描述:
一个pe文件
运行截图
如果乱输入,回车后就退出了,没有循环输入的机制,也没有输入错误提示。
解题过程:
用exeinfo pe检测有
这是一个32位没有壳的文件。
用IDA打开有:
下面是文件的main函数结构,根据提示可以确定程序正确执行步骤
汇编语言不好读,点击F5查看main函数伪代码有:
int __cdecl main(int argc, const char **argv, const char **envp)
{
void *v3; // eax
int v4; // edx
void *v5; // eax
int result; // eax
void *v7; // eax
void *v8; // eax
void *v9; // eax
size_t i; // [esp+4Ch] [ebp-8Ch]
char v11[4]; // [esp+50h] [ebp-88h]
char v12[28]; // [esp+58h] [ebp-80h]
char v13; // [esp+74h] [ebp-64h]
v3 = (void *)sub_402B30((int)&unk_446360, "Give me your flag:");
sub_4013F0(v3, (int (__cdecl *)(void *))sub_403670);
sub_401440((int)&dword_4463F0, v4, (int)v12, 127);
if ( strlen(v12) < 30 && strlen(v12) > 4 ) // if条件要吻合
{
strcpy(v11, "EIS{");
for ( i = 0; i < strlen(v11); ++i )
{
if ( v12[i] != v11[i] ) // v12是输入的值,要求以“EIS{”开头
{
v7 = (void *)sub_402B30((int)&unk_446360, "Sorry, keep trying! ");
sub_4013F0(v7, (int (__cdecl *)(void *))sub_403670);
return 0;
}
}
if ( v13 == '}' ) // if条件吻合,v13 = '}',v13是v12后一个字节
{
if ( sub_4011C0(v12) ) // if条件要吻合,sub_4011c0(v11)返回为真
//byte_4420B0[]={0Dh,13h,17h,11h,2,1,20h,1Dh,0Ch,2,19h,2Fh,17h,2Bh,24h,1Fh,1Eh,16h,9,0Fh,15h,27h,13h,26h,0Ah,2Fh,1Eh,1Ah,2Dh,0Ch,22h,4}
// sub_4013c0 = (v8[i] ^ 0x55) + 72
// "GONDPHyGjPEKruv{{pj]X@rF" == byte_4420B0[] ^ sub_4013c0
v9 = (void *)sub_402B30((int)&unk_446360, "Congratulations! ");
// Congratulations!这个应该就是要求的最后输出界面结果
else
v9 = (void *)sub_402B30((int)&unk_446360, "Sorry, keep trying! ");
sub_4013F0(v9, (int (__cdecl *)(void *))sub_403670);
result = 0;
}
else
{
v8 = (void *)sub_402B30((int)&unk_446360, "Sorry, keep trying! ");
sub_4013F0(v8, (int (__cdecl *)(void *))sub_403670);
result = 0;
}
}
else
{
v5 = (void *)sub_402B30((int)&unk_446360, "Sorry, keep trying!");
sub_4013F0(v5, (int (__cdecl *)(void *))sub_403670);
result = 0;
}
return result;
}
里面有一个很关键的函数sub_4011C0(),函数结构如下:
bool __cdecl sub_4011C0(char *a1)
{
size_t v2; // eax
signed int v3; // [esp+50h] [ebp-B0h]
char v4[32]; // [esp+54h] [ebp-ACh]
int v5; // [esp+74h] [ebp-8Ch]
int v6; // [esp+78h] [ebp-88h]
size_t i; // [esp+7Ch] [ebp-84h]
char v8[128]; // [esp+80h] [ebp-80h]
if ( strlen(a1) <= 4 ) // 不能成立, strlen > 4
return 0;
i = 4;
v6 = 0;
while ( i < strlen(a1) - 1 )
v8[v6++] = a1[i++]; // v8[0++] = a1[4++]
v8[v6] = 0; //v8[strlen(a1)] = 0
v5 = 0;
v3 = 0;
memset(v4, 0, 32u); // v4[32]被初始化为0
for ( i = 0; ; ++i )
{
v2 = strlen(v8); // v2 = strlen(a1) - 4
if ( i >= v2 )
break;
if ( v8[i] >= 97 && v8[i] <= 122 )
{
v8[i] -= 32; // 小写字符转大写字符
v3 = 1;
}
if ( !v3 && v8[i] >= 65 && v8[i] <= 90 )
v8[i] += 32; // 大写转小写
v4[i] = byte_4420B0[i] ^ sub_4013C0(v8[i]);
//byte_4420B0[]={0Dh,13h,17h,11h,2,1,20h,1Dh,0Ch,2,19h,2Fh,17h,2Bh,24h,1Fh,1Eh,16h,9,0Fh,15h,27h,13h,26h,0Ah,2Fh,1Eh,1Ah,2Dh,0Ch,22h,4}
// sub_4013c0 = (v8[i] ^ 0x55) + 72
v3 = 0;
}
return strcmp("GONDPHyGjPEKruv{{pj]X@rF", v4) == 0;
}
程序逻辑:
#include
#include
int main()
{
char str1[] = "GONDPHyGjPEKruv{{pj]X@rF";
int str2[] = {0x0D, 0x13, 0x17, 0x11, 2, 1, 0x20, 0x1D, 0x0C, 2, 0x19, 0x2F, 0x17, 0x2B, 0x24, 0x1F,
0x1E, 0x16, 9, 0x0F, 0x15, 0x27, 0x13, 0x26, 0x0A, 0x2F, 0x1E, 0x1A, 0x2D, 0x0C, 0x22, 4};
int len = strlen(str1);
// printf("%d", len);
char flag[24];
int i;
for(i = 0; i < len; i++)
{
flag[i] = ((str1[i] ^ str2[i]) - 72) ^ 0x55;
printf("%c", flag[i]);
}
printf("\n");
}
运行程序可以得出:WADX_TDGK_AIHC_IHKN_PJLM
最终答案:EIS{wadx_tdgk_aihc_ihkn_pjlm}
题目总结:
这个题目函数还是蛮多蛮长的,从头看的话难免会厌烦。可以先大概地看一遍,捋一捋大概流程,因为它给出了详细的提示信息,所以我们可以直接判断出函数的正确执行路线,然后根据最后的正确输出提示倒推,从最后面的函数一步步倒着看上去,然后就可以很高效地得到具体转换方式。