诺莫12
开始
放入IDA:
int __cdecl main(int argc, const char **argv, const char **envp)
{
signed int v3; // eax
char v4; // al
signed int v5; // ecx
char v6; // al
signed int v7; // ecx
char v8; // al
signed int v9; // ecx
char v10; // al
signed int v11; // ecx
char v12; // al
signed int v13; // ecx
__int64 v15; // [rsp+0h] [rbp-1A0h]
signed int v16; // [rsp+4Ch] [rbp-154h]
char dest; // [rsp+50h] [rbp-150h]
int v18; // [rsp+E8h] [rbp-B8h]
int v19; // [rsp+ECh] [rbp-B4h]
char v20[64]; // [rsp+F0h] [rbp-B0h]
char s[108]; // [rsp+130h] [rbp-70h]
int v22; // [rsp+19Ch] [rbp-4h]
v22 = 0;
printf("please input string:\n", argv, envp);
gets(s);
v18 = strlen(s);
v19 = 5;
v16 = -1046111848;
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
while ( v16 == -2012804730 )
{
memcpy(&dest, &dword_401480, 0x90uLL);// J2261C63-3I2I-EGE4-IBCC-IE41A5I5F4HB
v4 = fun_check1(s); // 判断长度0-50
v5 = -1855144052;
if ( v4 & 1 )
v5 = 1890735184; // 满足check1
v16 = v5;
}
if ( v16 != -1855144052 )
break;
v16 = -1153978545;
LODWORD(v15) = printf("what a shame !!!\n", v15);
}
if ( v16 != -1612797716 )
break;
v10 = fun_check4(s); // 判断-
v11 = -1855144052;
if ( v10 & 1 )
v11 = -842747696;
v16 = v11;
}
if ( v16 == -1153978545 )
break;
switch ( v16 )
{
case -1046111848:
v3 = -2012804730;
if ( v19 < v18 - 1 )
v3 = -370117910;
v16 = v3;
break;
case -842747696:
v12 = fun_check5(v20, (int *)&dest); // ‘0’~‘9’,v13[v5] = v15[v5]+17,v5++
// ’a’~‘z’,v13[v5] = v15[v5] - 0x30,v5++
// ’A’~‘Z’,v5++
// ‘-’, v13[v5] = v15[v5],v5++
v13 = -1855144052;
if ( v12 & 1 )
v13 = -194644933;
v16 = v13;
break;
case -370117910:
v20[v19 - 5] = s[v19];
v16 = 805361575;
break;
case -194644933:
v16 = -1153978545;
HIDWORD(v15) = printf("you got it !\n", v15);
break;
case 805361575:
++v19;
v16 = -1046111848;
break;
case 1222385267:
v8 = fun_check3(s); // 判断最后是否为}
v9 = -1855144052;
if ( v8 & 1 )
v9 = -1612797716;
v16 = v9;
break;
case 1890735184:
v6 = fun_check2(s); // 判断前几个字符是否为flag{
v7 = -1855144052;
if ( v6 & 1 )
v7 = 1222385267;
v16 = v7;
break;
}
}
return 0;
}
数据:
分析
这是一个控制流平坦化程序,就是由控制中心把目标分发到要执行的块。
。
1.fun_check1:判断字符范围在 0-50
2.fun_check2:判断前面是否为 flag{
3.fun_check3:判断最后是否为 }
4.fun_check4:
‘0’~‘9’,v13[v5] = v15[v5]+17,v5++
’a’~‘z’,v13[v5] = v15[v5] - 0x30,v5++
’A’~‘Z’,v5++
‘-’, v13[v5] = v15[v5],v5++
再将处理后的字符与dest区域进行strcmp
逆向
我们将check4的代码逆向就行,对ascii码分析,如果在dest是字母(全大写),他是由源数字+17过去的,如果在dest是数字,他是由源小写字母-0x30得到的
写出你想脚本:
dest = "J2261C63-3I2I-EGE4-IBCC-IE41A5I5F4HB"
flag = ""
for i in dest:
if ord(i) >= 65 and ord(i) <= 90:
flag += chr(ord(i) - 17)
elif ord(i) >= 48 and ord(i) <= 57:
flag += chr(ord(i) + 0x30)
elif i == "-":
flag += "-"
print(flag)
因为check4省去了前面5个和最后一个字符,则需要自己套上flag{}
flag{9bbfa2fc-c8b8-464d-8122-84da0e8e5d71}
注:分析比较杂,建议以块来读
【附】
控制流平坦化
https://security.tencent.com/index.php/blog/msg/112