easytree ---- 2018.10月安恒
2019-01-30 本文已影响0人
Adam_0
首先,用upxshell去壳。
upxshell去壳.png
再用ida打开,shift+F12查找关键字,F5分析主函数。
int __cdecl main(int argc, const char **argv, const char **envp)
{
const char *v3; // eax@4
int v5; // [sp+14h] [bp-2Ch]@1
__int16 v6; // [sp+1Ah] [bp-26h]@4
_BYTE v7[3]; // [sp+29h] [bp-17h]@1
int v8; // [sp+38h] [bp-8h]@4
int *v9; // [sp+3Ch] [bp-4h]@1
__main();
v5 = 0;
v9 = &v5;
welcome();
gets(v7);
if ( strlen(v7) != 15 )
{
printf("Nah... ur a fake reverser!");
exit(0);
}
v8 = createBinTree((int)v7, 15); // 创建完美二叉树
preOrderTraverse(v8, v9, (int)&v6); // 前序遍历
v3 = (const char *)enc((char *)&v6); // 猜测 base64加密
if ( !strncmp(v3, "aWNuZXJyc2VhZXRydmVl", 0x14u) )
{
puts("well done bro!");
printf("ur really know something about tree!");
}
else
{
printf("Nah.. ur an idiot!");
}
return 0;
}
将 “aWNuZXJyc2VhZXRydmVl” base64解密 “icnerrseaetrvee”。
接下来分析 createBinTree 函数:
为每个节点创建12个字节,前面四个存自己的值,中间四个存左孩子的地址,最后四个存右孩子的地址。
v13 = 1;
v12 = 0;
v11 = 0;
v7 = malloc(4 * a2);
while ( v12 < a2 )
{
v6 = (signed int)floor(pow(2.0, (long double)(v13 - 1)));
v10 = 0;
for ( i = 0; i < v6; ++i )
{
v5 = v12 + i;
if ( v12 + i >= a2 )
break;
v8 = 0;
if ( *(_BYTE *)(v5 + a1) != 35 ) // 结尾
{
v8 = malloc(12u); // 创建12个字节
*(_BYTE *)v8 = *(_BYTE *)(v5 + a1);
v8[1] = 0;
v8[2] = 0;
v7[v5] = v8;
}
if ( v12 > 0 )
{
v4 = v7[v11 + v10];
if ( i & 1 ) // 左右孩子
{
*(_DWORD *)(v4 + 8) = v8;
++v10;
}
else
{
*(_DWORD *)(v4 + 4) = v8;
}
}
}
v11 = v12;
v12 += v6;
++v13;
}
v2 = *v7;
free(v7);
return v2;
}
在分析 preOrderTraverse 函数:
这个是二叉树的遍历,遍历又分:前序遍厉,中序遍历,后序遍历。这个是前序遍历。
int __cdecl preOrderTraverse(int a1, _DWORD *a2, int a3)
{
int v3; // eax@2
int result; // eax@2
if ( a1 )
{
v3 = (*a2)++;
*(_BYTE *)(a3 + v3) = *(_BYTE *)a1;
preOrderTraverse(*(_DWORD *)(a1 + 4), a2, a3);
result = preOrderTraverse(*(_DWORD *)(a1 + 8), a2, a3);
}
return result;
}
将得到的字符串“icnerrseaetrvee”根据所创建的二叉树结构和前序遍历得到树的结构
二叉树结构.png得到flag : icanreversetree
注:
1.树与二叉树以及二叉树的遍历:(参考大佬文章)(https://blog.csdn.net/johnny901114/article/details/80574803)