思路
还是先查壳和系统elf可执行文件,位系统,之后我们打开
__int __fastcall main(__int a1, char **a2, char **a3)
{
signed int i;
signed int j;
__int v6;
__int v7;
__int v8;
__int v9;
__int v10;
__int v11;
__int v12;
__int v13;
__int v14;
__int v15;
unsigned __int v16;
v16 = __readfsqword(0x28u);
puts("Let us play a game?");
puts("you have six chances to input");
puts("Come on!");
v6 = 0LL;
v7 = 0LL;
v8 = 0LL;
v9 = 0LL;
v10 = 0LL;
for ( i = 0; i <= 5; ++i )
{
printf("%s", "input: ", (unsigned int)i);
a2 = (char **)((char *)&v6 + 4 * i);
__isoc99_scanf("%d", a2);
}
v11 = 0LL;
v12 = 0LL;
v13 = 0LL;
v14 = 0LL;
v15 = 0LL;
for ( j = 0; j <= 4; j += 2 )
{
dword_601078 = *((_DWORD *)&v6 + j);
dword_60107C = *((_DWORD *)&v6 + j + 1);
a2 = (char **)&unk_601060;
sub_400686((unsigned int *)&dword_601078, &unk_601060);
*((_DWORD *)&v11 + j) = dword_601078;
*((_DWORD *)&v11 + j + 1) = dword_60107C;
}
if ( (unsigned int)sub_400770(&v11, a2) != 1 )
{
puts("NO NO NO~ ");
exit(0);
}
puts("Congratulation!\n");
puts("You seccess half\n");
puts("Do not forget to change input to hex and combine~\n");
puts("ByeBye");
return 0LL;
}
追到了这里,之后稍微修正一下变的容易阅读一些。
__int __fastcall main(__int a1, char **a2, char **a3)
{
signed int i;
signed int j;
__int v6[0];
__int v6[1];
__int v6[2];
__int v6[3];
__int v6[4];
__int v7[0];
__int v7[1];
__int v7[2];
__int v7[3];
__int v7[4];
unsigned __int v16;
v16 = __readfsqword(0x28u);
puts("Let us play a game?");
puts("you have six chances to input");
puts("Come on!");
v6[0] = 0LL;
v6[1] = 0LL;
v6[2] = 0LL;
v6[3] = 0LL;
v6[4] = 0LL;
for ( i = 0; i <= 5; ++i )
{
printf("%s", "input: ", (unsigned int)i);
__isoc99_scanf("%d", (char *)&v6[0] + 4 * i);
}
v7[0] = 0LL;
v7[1] = 0LL;
v7[2] = 0LL;
v7[3] = 0LL;
v7[4] = 0LL;
for ( j = 0; j <= 4; j += 2 )
{
dword_601078 = *((_DWORD *)&v6[0] + j);
dword_60107C = *((_DWORD *)&v6[0] + j + 1);
sub_400686((unsigned int *)&dword_601078, &unk_601060);
*((_DWORD *)&v7[0] + j) = dword_601078;
*((_DWORD *)&v7[0] + j + 1) = dword_60107C;
}
if ( (unsigned int)sub_400770(&v7[0]) != 1 )
{
puts("NO NO NO~ ");
exit(0);
}
puts("Congratulation!\n");
puts("You seccess half\n");
puts("Do not forget to change input to hex and combine~\n");
puts("ByeBye");
return 0LL;
}
之后开始反着来先进入sub_400700函数中查看
signed __int __fastcall sub_400770(_DWORD *a1)
{
signed __int result;
if ( a1[2] - a1[3] != 2225223423LL || a1[3] + a1[4] != 4201428739LL || a1[2] - a1[4] != 1121399208LL )
{
puts("Wrong!");
result = 0LL;
}
else if ( *a1 != -548868226 || a1[5] != -20448480 || a1[1] != 550153460 )
{
puts("Wrong!");
result = 0LL;
}
else
{
puts("good!");
result = 1LL;
}
return result;
}
这里就需要运算了,这里要注意最好转成十六进制,因为整数和无类型数,最后得到的答案是不一样的,之后利用python脚本计算出,这些数值是什么,为了以后做准备,脚本在下面,之后进入上面那个函数sub_400686中查看
__int __fastcall sub_400686(unsigned int *a1, _DWORD *a2)
{
__int result;
unsigned int v3;
unsigned int v4;
int v5;
unsigned int i;
v3 = *a1;
v4 = a1[1];
v5 = 0;
for ( i = 0; i <= 0x3F; ++i )
{
v5 += 11667954;
v3 += (v4 + v5 + 11) ^ ((v4 << 6) + *a2) ^ ((v4 >> 9) + a2[1]) ^ 0x20;
v4 += (v3 + v5 + 20) ^ ((v3 << 6) + a2[2]) ^ ((v3 >> 9) + a2[3]) ^ 0x10;
}
*a1 = v3;
result = v4;
a1[1] = v4;
return result;
}
又是一个表达式,之后进行反向的运算即可。
脚本
python利用z3约束来计算。
from z3 import *
a0, a1, a2, a3, a4, a5 = Ints('a0 a1 a2 a3 a4 a5')
s = Solver()
s.add(a2 - a3 == 0x84A236FF)
s.add(a3 + a4 == 0xFA6CB703)
s.add(a2 - a4 == 0x42D731A8)
s.add(a0 == 0xDF48EF7E)
s.add(a5 == 0x84F30420)
s.add(a1 == 0x20CAACF4)
if s.check() == sat:
print(s.model())
得到a0-a5是
[a2 = 3774025685,
a1 = 550153460,
a5 = 2230518816,
a0 = 3746099070,
a3 = 1548802262,
a4 = 26526277]
之后那时候我说了一嘴那个无类型的问题,如果我用直接十进制计算。
from z3 import *
a0, a1, a2, a3, a4, a5 = Ints('a0 a1 a2 a3 a4 a5')
s = Solver()
s.add(a2 - a3 == 2225223423)
s.add(a3 + a4 == 4201428739)
s.add(a2 - a4 == 1121399208)
s.add(a0 == -548868226)
s.add(a5 == -20448480)
s.add(a1 == 550153460)
if s.check() == sat:
print(s.model())
答案会变成
[a2 = 3774025685,
a1 = 550153460,
a5 = -20448480,
a0 = -548868226,
a3 = 1548802262,
a4 = 26526277]
所以推荐如果是无类型,最好是转换成十六进制之后利用z3进行约束计算。
之后利用c语言写sub_400686脚本,我写的尽量是按照他的格式进行写的,为了能看明白
#include <stdio.h>
int main()
{
int a1[6] = { 3746099070,550153460,3774025685,1548802262,26526277,2230518816 };
unsigned int a2[4] = { 2,2,3,4 };
unsigned int v3;
unsigned int v4;
int v5;
for (unsigned int j = 0; j < 5; j += 2)
{
v3 = a1[j];
v4 = a1[j + 1];
v5 = 11667954 * ;
for (unsigned int i = 0; i < ; i++)
{
v4 -= (v3 + v5 + 20) ^ ((v3 << 6) + a2[2]) ^ ((v3 >> 9) + a2[3]) ^ 0x10;
v3 -= (v4 + v5 + 11) ^ ((v4 << 6) + *a2) ^ ((v4 >> 9) + a2[1]) ^ 0x20;
v5 -= 11667954;
}
a1[j] = v3;
a1[j + 1] = v4;
}
for (unsigned int i = 0; i < 6; i++)
printf("%c%c%c", *((char*)&a1[i] + 2), *((char*)&a1[i] + 1), *(char*)&a1[i]);
}
最后算出来的就是flag{re_is_great!}就是flag。
总结
看你z3会不会用,其实手算也是可以算,但是后期数字在变大,和争夺时间做题速度的时候,其实很主要就是自动化,还有对于逻辑的分析,怎么样