迷宫加Blowfish加密
ida打开,可以看到提示说一个鱼XXX,用findcrypt查密提示Blowfish而且有5行,估计是未改动过的原版加密
程序比较长,大概分这两块,一块是对输入解密生成一个串,再用这个串走迷宫
int __cdecl main(int argc, const char **argv, const char **envp)
{
...
char ArgList[68]; // [esp+1080h] [ebp-48h] BYREF
memset(ArgList, 0, 0x40u);
puts("LiHua is trapped on an isolated island. ", v43);
puts("One day, he caught a fish.\n", v44);
puts("Suddenly,the fish said: \"Dont eat me! I am Fish God,if you release me,as return ,you have one wish.\"\n", v45);
puts("Li said : I want to know how to escape from this island.\n", v46);
puts("Fish said: ", v47);
scanf("%s", (char)ArgList);
srand(0xDEADBEEF);
ModuleHandleA = GetModuleHandleA("Ntdll");
ZwSetInformationThread = GetProcAddress(ModuleHandleA, "ZwSetInformationThread");
CurrentThread = GetCurrentThread();
((void (__stdcall *)(HANDLE, int, _DWORD, _DWORD))ZwSetInformationThread)(CurrentThread, 17, 0, 0);
for ( i = 0; i < 8; ++i )
byte_4057A8[i] = rand();
byte_4057A8[0] = 0;
v58[0] = 0x4853494668736966i64;
LOBYTE(v7) = 104;
word_4057A9 = 0x1A0F; // key
word_4057AB = 0x3501;
byte_4057AD = 0x3A;
byte_4057AE = 0x3B;
byte_4057AF = 0x20;
sub_401090(v56, v7); // v57
v8 = strlen(ArgList);
v9 = v8;
v49 = v8;
if ( (v8 & 7) != 0 ) // 8字节向上取整
{
v9 = 8 * (v8 >> 3) + 8;
v49 = v9;
}
v54 = (char *)calloc(v9, 1u);
v10 = (unsigned __int8 *)calloc(v9 / 2, 1u);
v11 = 0;
v51 = v10;
if ( v9 / 2 > 0 )
{
v12 = ArgList; // 输入转16进制存
do
{
sprintf(v12, "%02x", v11 + (_BYTE)v10);
v10 = v51;
++v11;
v12 += 2;
}
while ( v11 < v9 / 2 );
v9 = v49;
}
v50 = 0;
v55 = v9 / 16;
if ( v9 / 16 <= 0 )
{
v26 = v54;
}
else
{
v13 = v10 + 2;
v53 = v13; // BlowFish加密
do
{
v14 = v57;
v52 = 16;
v15 = v13[1] | ((*v13 | ((*(v13 - 1) | (*(v13 - 2) << 8)) << 8)) << 8);
v16 = v13[5] | ((v13[4] | ((v13[3] | (v13[2] << 8)) << 8)) << 8);
do
{
v17 = *(_DWORD *)v14 ^ v15;
v14 -= 4;
v18 = v17;
v15 = v16 ^ (*(_DWORD *)&v57[4 * (unsigned __int8)v17 + 3076]
+ (*(_DWORD *)&v57[4 * BYTE1(v17) + 2052] ^ (*(_DWORD *)&v57[4 * BYTE2(v17) + 1028]
+ *(_DWORD *)&v57[4 * HIBYTE(v17) + 4])));
v19 = v52-- == 1;
v16 = v18;
}
while ( !v19 );
v20 = v18 ^ v56[0];
v21 = calloc(4u, 1u);
*v21 = HIBYTE(v20);
v21[1] = BYTE2(v20);
v21[2] = BYTE1(v20);
v21[3] = v20;
v22 = v56[1];
*(_DWORD *)&v54[8 * v50] = *(_DWORD *)v21;
v23 = v15 ^ v22;
v24 = calloc(4u, 1u);
*v24 = HIBYTE(v23);
v24[1] = BYTE2(v23);
v25 = v23 >> 8;
v24[3] = v23;
v26 = v54;
v24[2] = v25;
*(_DWORD *)&v54[8 * v50 + 4] = *(_DWORD *)v24;
v13 = v53 + 8;
v53 += 8;
++v50;
}
while ( v50 < v55 );
}
v58[0] = 0x4D746145746E6F44i64;
v27 = _byteswap_ushort(0x6F44u);
v28 = _byteswap_ushort(0x746Eu);
v29 = _byteswap_ushort(0x6145u);
v30 = _byteswap_ushort(0x4D74u);
v31 = &unk_40501A;
do
{
*(v31 - 1) ^= v27;
*v31 ^= v28;
v31[1] ^= v29;
v31[2] ^= v30;
v31 += 4; // 每次8字节
}
while ( (int)v31 < (int)&unk_40503A );
v32 = dword_4053A8;
v33 = (unsigned __int16 *)&unk_405018; // 将018-038按位展开(低位在前)放入3A8 迷宫
do
{
v34 = *v33;
for ( j = 15; j > -1; --j )
{
v36 = (v34 & (1 << j)) >> j;
*v32++ = v36;
}
++v33;
}
while ( (int)v33 < (int)&unk_405038 );
v37 = *v26;
v38 = 10;
v39 = 0;
v40 = 5;
if ( *v26 )
{
v41 = 160;
while ( 1 )
{
switch ( v37 )
{
case 'a':
--v40;
break;
case 'd':
++v40;
break;
case 's':
++v38;
v41 += 16;
break;
case 'w':
--v38;
v41 -= 16;
break;
default:
break;
}
if ( dword_4053A8[v41 + v40] == 1 )
break;
v37 = v26[++v39];
if ( !v37 )
{
if ( v38 == 4 && v40 == 9 && v39 < 17 )
{
puts("Congratulations! Here is your flag: RCTF{%s}", (char)ArgList);
return 0;
}
break;
}
}
}
puts("Oh no. Dont eat me!!!!", v48);
return 0;
}
迷宫这块相对独立,所以可以直接把这块逆向到解密后的结果
from pwn import *
data = open('DontEatMe.exe', 'rb').read()
#1迷宫部分
#45018-45038
a1 = list(data[0x3618: 0x3638])
xors = [0x6f,0x44,0x74,0x6e,0x61,0x45,0x4D,0x74]
print(a1)
for i in range(len(a1)-2):
a1[i] ^= xors[i%8]
s = ''
for i in range(16):
s+= bin(a1[i*2+1])[2:].rjust(8, '0')
s+= bin(a1[i*2])[2:].rjust(8, '0')
s+='\n'
print(s)
#ddddwwwaaawwwddd
'''
1111111111111111
1000000000111111
1011111110111111
1011111110111111
1011110000000111
1011110111110111
1011110111110111
1011110000110111
1011111110110111
1011111110110111
1000000000110111
1111101111110111
1111100000000111
1111111111111111
1111111111111111
1000101110110010
'''
得到的16位串再用Blowfish解密,8字节的key在主程序里先用rand填充后直接写入值覆盖。这人真够恶心的一共8字节分6次写。
byte_4057A8[0] = 0;
v58[0] = 0x4853494668736966i64;
LOBYTE(v7) = 104;
word_4057A9 = 0x1A0F; // key
word_4057AB = 0x3501;
byte_4057AD = 0x3A;
byte_4057AE = 0x3B;
byte_4057AF = 0x20;
最后调用函数解密
data = b'ddddwwwaaawwwddd'
key = b"\x00\x0F\x1A\x01\x35\x3A\x3B\x20"
import blowfish
cipher = blowfish.Cipher(key)
step = cipher.encrypt_block(data[:8]) + cipher.encrypt_block(data[8:])
print('flag{%s}'% step.hex())
#flag{db824ef8605c5235b4bbacfa2ff8e087}