题目:[NPUCTF2020]Baby Obfuscation
64位无壳程序
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v3; // eax
int v4; // ebx
int v5; // esi
int v6; // ebx
int v7; // ebx
int v8; // esi
int v9; // ebx
int v10; // ebx
int v11; // ebx
int v12; // esi
int v13; // eax
int v14; // ebx
int v15; // esi
int v16; // ebx
int v17; // eax
bool v18; // bl
int v19; // eax
int v20; // esi
int v21; // ebx
int v22; // ebx
int v23; // eax
int v24; // eax
int v25; // eax
int v26; // ebx
int v28[68]; // [rsp+20h] [rbp-60h] BYREF
char Str[1008]; // [rsp+130h] [rbp+B0h] BYREF
int v30[1008]; // [rsp+520h] [rbp+4A0h] BYREF
int v31[4]; // [rsp+14E0h] [rbp+1460h]
int v32; // [rsp+14F0h] [rbp+1470h]
int k; // [rsp+14F4h] [rbp+1474h]
int j; // [rsp+14F8h] [rbp+1478h]
int i; // [rsp+14FCh] [rbp+147Ch]
_main(argc, argv, envp);
memset(v30, 0, 0xFA0ui64);
v30[1000] = 0;
memset(v28, 0, 0x100ui64);
v28[64] = 0;
for ( i = 0; i <= 64; ++i )
v28[i] = i + 1;
v31[0] = 2;
v31[1] = 3;
v31[2] = 4;
v31[3] = 5;
v30[1004] = 2;
v30[1005] = 3;
v30[1006] = 4;
v30[1007] = 5;
puts("WHERE IS MY KEY!?");
scanf("%32s", Str);
v32 = strlen(Str);
v3 = F0X1(v28[j], v28[j]);
for ( j = v3 / v28[j]; j <= v32; ++j )
{
v4 = (v28[j] + v28[j + 1]) * (v28[j] + v28[j + 1]);
if ( v4 >= (int)(F0X5(2, 2) * v28[j] * v28[j + 1]) )
{
v5 = ~Str[(int)F0X4(j, 1)];
v6 = F0X4(j, 1);
v30[j] = ~(v5 + v31[v6 % (int)F0X5(2, 2)]);
}
v7 = F0X1(v28[j], v28[j + 1]);
if ( v7 > (int)F0X1(v28[j + 1], ~(~v28[j + 1] + v28[j])) )
{
v8 = v30[j];
v9 = F0X4(j, 1);
v30[j] = ~(~v8 + v28[v9 % (int)F0X5(2, 2)]) * v8;
}
v10 = v28[j + 1];
v11 = F0X5(2, 1) * v10;
v12 = v28[j];
v13 = F0X5(2, 1);
v14 = F0X1(v12 * v13, v11);
v15 = F0X5(2, 1);
if ( v14 == v15 * (unsigned int)F0X1(v28[j], v28[j + 1]) )
{
v16 = F0X4(j, 1);
v30[j] ^= v31[v16 % (int)F0X5(2, 2)];
}
v17 = F0X5(V0X3, v28[j]);
v18 = v17 < v28[j] + 1;
v19 = F0X5(2, 4);
if ( (unsigned __int8)F0X3(v19 >= j, v18) )
{
v20 = ~Str[(int)F0X4(j, 1)];
v21 = F0X4(j, 1);
v30[j] ^= ~(v20 + v31[v21 % (int)F0X5(2, 2)]);
}
v22 = F0X5(2, 3);
v23 = F0X1(v28[j], v28[j]);
v30[j] *= v22 + (unsigned int)F0X5(2, v23 / v28[j]);
}
v24 = F0X5(2, 4);
if ( (unsigned int)F0X4(v24, 1) != v32 )
goto LABEL_23;
v25 = F0X1(v28[k], v28[k]);
for ( k = v25 / v28[k]; k <= v32; ++k )
{
v26 = v30[k];
if ( v26 == (int)F0X4(A0X6[k], 1) / 10 )
++V0X2;
}
if ( V0X2 == v32 )
puts("\nPASS");
else
LABEL_23:
puts("\nDENIED");
return 0;
}
先分析一下几个处理函数再分析主函数
F0X1
看出来是欧几里得算法,返回a1和a2的最大公约数。
__int64 __fastcall F0X1(unsigned int a1, int a2)
{
__int64 result; // rax
if ( a2 )
result = F0X1(a2, a1 % a2);
else
result = a1;
return result;
}
F0X2 & F0X3
只有两个参数都是1的时候才返回1,别的都返回0。
_BOOL8 __fastcall F0X2(char a1, char a2)
{
return a1 == a2 && a1 != 1;
}
__int64 __fastcall F0X3(bool a1, bool a2)
{
char v2; // bl
char v3; // al
v2 = F0X2(a2, a2);
v3 = F0X2(a1, a1);
return F0X2(v3, v2);
}
F0X4
看着很奇怪的运算,其实就是 a1 - a2。
__int64 __fastcall F0X4(int a1, int a2)
{
return ~(~a1 + a2);
}
F0X5
返回a1^a2。
__int64 __fastcall F0X5(int a1, int a2)
{
unsigned int v4; // [rsp+Ch] [rbp-4h]
v4 = 1;
while ( a2 )
{
if ( (a2 & 1) != 0 )
v4 *= a1;
a1 *= a1;
a2 >>= 1;
}
return v4;
}
main
知道了这几个函数的实现就可以看主函数了。
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v3; // eax
int v4; // ebx
int v5; // esi
int v6; // ebx
int v7; // ebx
int v8; // esi
int v9; // ebx
int v10; // ebx
int v11; // ebx
int v12; // esi
int v13; // eax
int v14; // ebx
int v15; // esi
int v16; // ebx
int v17; // eax
bool v18; // bl
int v19; // eax
int v20; // esi
int v21; // ebx
int v22; // ebx
int v23; // eax
int v24; // eax
int v25; // eax
int v26; // ebx
int v28[68]; // [rsp+20h] [rbp-60h] BYREF
char Str[1008]; // [rsp+130h] [rbp+B0h] BYREF
int v30[1008]; // [rsp+520h] [rbp+4A0h] BYREF
int v31[4]; // [rsp+14E0h] [rbp+1460h]
int v32; // [rsp+14F0h] [rbp+1470h]
int k; // [rsp+14F4h] [rbp+1474h]
int j; // [rsp+14F8h] [rbp+1478h]
int i; // [rsp+14FCh] [rbp+147Ch]
_main(argc, argv, envp);
memset(v30, 0, 0xFA0ui64);
v30[1000] = 0;
memset(v28, 0, 0x100ui64);
v28[64] = 0;
for ( i = 0; i <= 64; ++i )
v28[i] = i + 1;
v31[0] = 2;
v31[1] = 3;
v31[2] = 4;
v31[3] = 5;
v30[1004] = 2;
v30[1005] = 3;
v30[1006] = 4;
v30[1007] = 5;
puts("WHERE IS MY KEY!?");
scanf("%32s", Str);
v32 = strlen(Str);
v3 = F0X1(v28[j], v28[j]); // v3=v28[j]
for ( j = v3 / v28[j]; j <= v32; ++j )
{
v4 = (v28[j] + v28[j + 1]) * (v28[j] + v28[j + 1]);// v4=(2j+3)^2=4j^2+12j+18(数学表达式)
if ( v4 >= (F0X5(2, 2) * v28[j] * v28[j + 1]) )// 满足
{
v5 = ~Str[F0X4(j, 1)]; // v5 = ~Str[j-1]
v6 = F0X4(j, 1); // v6=j-1
v30[j] = ~(v5 + v31[v6 % F0X5(2, 2)]); // v30[j]=Str[j-1]-v31[(j-1)%4]
}
v7 = F0X1(v28[j], v28[j + 1]);
if ( v7 > F0X1(v28[j + 1], ~(~v28[j + 1] + v28[j])) )// 不满足
{
v8 = v30[j];
v9 = F0X4(j, 1);
v30[j] = ~(~v8 + v28[v9 % F0X5(2, 2)]) * v8;
}
v10 = v28[j + 1]; // v10=j+2
v11 = F0X5(2, 1) * v10; // v11=2*j+4
v12 = v28[j]; // v12=j+1
v13 = F0X5(2, 1); // v13=2
v14 = F0X1(v12 * v13, v11); // v14=gcd(2*j+2,2*j+4)
v15 = F0X5(2, 1); // v15=2
if ( v14 == v15 * F0X1(v28[j], v28[j + 1]) )// 满足
{
v16 = F0X4(j, 1);
v30[j] ^= v31[v16 % F0X5(2, 2)]; // v30[j] ^=v31[(j-1)%4]
}
v17 = F0X5(V0X3, v28[j]);
v18 = v17 < v28[j] + 1; // v18=0
v19 = F0X5(2, 4);
if ( F0X3(v19 >= j, v18) ) // 不满足
{
v20 = ~Str[F0X4(j, 1)];
v21 = F0X4(j, 1);
v30[j] ^= ~(v20 + v31[v21 % F0X5(2, 2)]);
}
v22 = F0X5(2, 3);
v23 = F0X1(v28[j], v28[j]);
v30[j] *= v22 + F0X5(2, v23 / v28[j]); // v30[j] *= 10;
}
v24 = F0X5(2, 4);
if ( F0X4(v24, 1) != v32 )
goto LABEL_23;
v25 = F0X1(v28[k], v28[k]);
for ( k = v25 / v28[k]; k <= v32; ++k ) // k=1
{
v26 = v30[k];
if ( v26 == F0X4(A0X6[k], 1) / 10 ) // v30[k]== (A0X6[k] - 1) / 10;
// A0X6[]={0, 1E79h, 1E79h, 2135h, 170Dh, 1F41h,1901h, 2CEDh,11F9h, 2649h, 2581h,2DB5h, 14B5h, 25E5h, 2A31h, 30D5h.0,0, 415770h, 0,0,0,0,0}
++V0X2;
}
if ( V0X2 == v32 )
puts("\nPASS");
else
LABEL_23:
puts("\nDENIED");
return 0;
}
不难看出,v30数组是跟flag有密切联系的。进一步排查,其中v30的赋值语句中只有下面三个与flag加密有关。
- v30[j] = ~(v5 + v31[v6 % F0X5(2, 2)]);
- v30[j] ^= v31[v16 % F0X5(2, 2)];
- v30[j] *= v22 + F0X5(2, v23 / v28[j]);
这三个等价于
- v30[j]=Str[j-1]-v31[(j-1)%4]
- v30[j] ^=v31[(j-1)%4]
- v30[j] *= 10;
EXP
A0X6=[0x0, 0x1E79, 0x1E79, 0x2135, 0x170D, 0x1F41,0x1901, 0x2CED,0x11F9, 0x2649, 0x2581,0x2DB5, 0x14B5, 0x25E5, 0x2A31, 0x30D5,0x0,0x0,0x415770,0x0,0x0,0x0,0x0,0x0]
flag=''
v31=[2,3,4,5]
for j in range(1,len(A0X6)):
A0X6[j]//=100 #两次乘10
A0X6[j]^=v31[(j-1)%4]
A0X6[j]+=v31[(j-1)%4]
flag+=chr(A0X6[j])
print(flag)
flag{0bfu5er}