攻防世界 进阶 crackeme
拿到程序后先查看,无壳64位程序,拖入ida分析
main函数中共有四个关键函数
先看最后一步的判断函数,当sub_400D6A返回1时,则输入的flag正确,查看函数
是一个16元一次的方程组,16个判断全部通过返回1,通过解方程组可以得到v10加密后的数据
from z3 import *
n0=Int('n0')
n1=Int('n1')
n2=Int('n2')
n3=Int('n3')
n4=Int('n4')
n5=Int('n5')
n6=Int('n6')
n7=Int('n7')
n8=Int('n8')
n9=Int('n9')
n10=Int('n10')
n11=Int('n11')
n12=Int('n12')
n13=Int('n13')
n14=Int('n14')
n15=Int('n15')
s=Solver()
s.add(-202850* n0 == -34078800)
s.add(182136 * n0 - 75396 *n1 == 18610884)
s.add(-360745* n1 - 465588 * n2 - 300043 * n0 == -145478307)
s.add(-97624 * n0 + 386642 * n3 - 515451 * n2 + 42526 * n1 == -8086825)
s.add(31288 * n0 - 324524 * n3 - 89265 * n1 - 239750 * n4 - 241348 * n2 == -91924377)
s.add(-266640* n2 + 216272 * n5 + 411737 * n0 + 210304 * n3 - 8658 * n4 + 454111 * n1 == 144299767 )
s.add(-402351* n4 - 496724 * n0 + 367831 * n2 + 371046 * n5 - 123257 * n3 + 188174 * n1 + 178541 * n6 == -37352471)
s.add(-415443* n1 + 237549 * n5 -323336 * n7 - 207212 * n3 - 23780 * n0 + 94300 * n4 + 364867 * n6 + 273839 * n2 == -8993582)
s.add(511561 * n5 -215494 * n0 + 44567 * n6 + 179735 * n2 + 55541 * n8 -204854 * n7 -160275 * n1 + 441741 * n4 + 443248 * n3 == 57425926)
s.add(407430 * n0 + 407030 * n3 + 503571 * n6 - 434809 * n5 + 385646 * n4 + 437781 * n7 + 20147 * n9 -10713 * n2 - 247694 * n8 + 4963 * n1 == 267063706 )
s.add(128236 * n7 -189787 * n4 + 298269 * n2 + 117737 * n8 - 59638 * n1 + 503873 * n5 -288072 * n9 -449297 * n3 -307883 * n6 - 60891 * n0+ 313065 * n10 == -99001600)
s.add(127585 * n3 + 447223 * n10-511720 * n0 - 64919 * n1 - 115935 * n11 -328029 * n6 + 2659 * n4 -246110 * n2 -491943 * n8 -392232 * n9 - 178041 * n5+ 49684 * n7 == -319105050)
s.add( 431281* n7 + 303436 * n10+ 322142 * n8 + 190343 * n2 + 522606 * n5 -368910 * n9 + 427328 * n12 -403570 * n11 -430137 * n0 + 436111 * n4 -435520 * n6 - 267519 * n3 - 525665 * n1 == -150506496)
s.add(-423522* n4 -393086 * n6 -323745 * n12+ 463495 * n1 + 345256 * n8 + 138356 * n7 -225302 * n0 + 251299 * n11 -82368 * n9 -428085 * n10 + 71943 * n13 + 425456 * n2 + 56298 * n3 - 365233 * n5 == -14594715)
s.add(-26106 * n14-143761 * n3 + 15549 * n13- 503539 * n10-398270 * n9+ 36874 * n2 -84278 * n7 + 434801 * n12 -472636 * n0 + 448925 * n8 -46393 * n5 -129268 * n4 -43783 * n11 + 60534 * n6 + 441341 * n1 == -38159340)
s.add(-408983* n3 -453493 * n9 + 246957 * n5 + 197292 * n15-62054 * n8 -21100 * n6 -500028 * n14 -386306 * n2 + 415182 * n13 + 24237 * n0 -414063 * n4 + 524530 * n1 + 93336 * n10+ 7350 * n12 + 129819 * n11- 293569 * n7 == -124057838)
print(s.check())
print(s.model())
取得加密后数据,然后后八位与前八位进行异或得到v10,再异或一遍得到加密前数据
for ( i = 0; i <= 7; ++i )
v10[i + 8] ^= v10[i];
//int flag[16]={168,159,81,112,113,9,237,115,89,52,216,216,56,120,138,68};
然后是sub_400A8C函数,进入查看,函数功能类似于base64加密的最后一步,表替换
只要找到v10[i]在表中的位置,就是替换前的数据
int search(int *ary,int a)
{
for(int i=0;i<256;i++)
{
if(a==ary[i])
{
return i;
}
}
}
int main()
{
for(int i=0;i<16;i++)
{
int m=search(key,a1[i]);
flag[i]=m;
printf("0x%x,",flag[i]);
}
}
//int flag[16]={ 0x6,0xb0,0x3a,0xba,0xc8,0xcc,0x8a,0x32,0x70,0x34,0x35,0x35,0x63,0x30,0x64,0x33}
最后是sub_4009AE(v10, v11); 就是变换了delta值的tea加密
但是加密的数据只是v10的前64位,密钥则是后128位,但是输入的flag只有128位(16个字符)
注意到上方有
这个函数就是strcat,将八个字符追加到flag后面,参与加密运算,可以动调一下看看
观察到nice2you追加到了flag末尾,此时flag长度24,后16个字符对前八个字符加密,得到结果
int flag[16]={ 0x6,0xb0,0x3a,0xba,0xc8,0xcc,0x8a,0x32,0x70,0x34,0x35,0x35,0x63,0x30,0x64,0x33}
tea解密就能得到flag,但是解密这一步我卡了大半天,因为对存储机制还不够了解,试了一遍才得到flag
总的来说就是 flag[16]后面拼上"nice2you",然后后面16个字符,每四个做一组密钥,对前面两组四个字符进行加密。
int all[24]={ 0x6,0xb0,0x3a,0xba,0xc8,0xcc,0x8a,0x32,
0x70,0x34,0x35,0x35,0x63,0x30,0x64,0x33,
0x6e,0x69,0x63,0x65,0x32,0x79,0x6f,0x75};
uint32_t v[2]={
0xba3ab006,0x328accc8
};
uint32_t k[4]={
0x35353470,0x33643063,0x6563696E,0x756F7932
};
//本来输入的密钥是 0x70343535,0x63306433,0x6e696365,0x32796f75
//但是动调后发现 进行计算的是0x35353470,0x33643063,0x6563696E,0x756F7932
//同样的输入的flag也是先输入字符在低位
最终
void decrypt (uint32_t *v,uint32_t *k){
uint32_t v0=v[0],v1=v[1],i;
unsigned int delta=0x12345678;
unsigned int sum = delta*32;
uint32_t k0=k[0],k1=k[1],k2=k[2],k3=k[3];
for (i=0;i<32;i++){
v1-=((v0<<4)+k2)^(v0+sum)^((v0>>5)+k3);
v0-=((v1<<4)+k0)^(v1+sum)^((v1>>5)+k1);
sum-=delta;
}
v[0]=v0;
v[1]=v1;
}
uint32_t v[2]={
0xba3ab006,0x328accc8
//犯的错误先输入的存放在低位,所以是0x6b0->0xb006
//同时0x6=0x06 放末尾也是0xb006不是0xb06位数不同
};
uint32_t k[4]={
0x35353470,0x33643063,0x6563696E,0x756F7932
};
decrypt(v,k);
printf("%x,%x\n",v[0],v[1]);
//5f753079,5f743067
char res[]="5f7530795f743067";
for(int i=0;i<strlen(res);i=i+2)
{
printf("0x%c%c,",res[i],res[i+1]);
}
printf("\n");
char aa[]={0x5f,0x75,0x30,0x79}; //得到的结果是右侧是低位,还要再逆序一下
char bb[]={0x5f,0x74,0x30,0x67};
for(int i=0;i<4;i++)
{
printf("%c",aa[3-i]);
}
for(int i=0;i<4;i++)
{
printf("%c",bb[3-i]);
}
flag{g0t_y0u_p455c0d3}