64位无壳,ida,会发现有花指令,手动去除就行了
去掉后的主函数内容:
int __cdecl main(int argc, const char **argv, const char **envp)
{
char *v3; // rdx
int v4; // ecx
unsigned int v5; // eax
char *v7; // r15
char *v8; // rdi
int *v9; // r12
char *v10; // r14
char *v11; // rbx
char *v12; // r13
int v13; // eax
__int64 v14; // rax
int v15; // edx
int v16; // eax
__int64 v17; // rax
int v18; // edx
int v19; // ecx
int v20; // eax
__int64 v21; // rax
char v22; // dl
char v23[80]; // [rsp+30h] [rbp-3F8h] BYREF
char v24[72]; // [rsp+80h] [rbp-3A8h] BYREF
__int64 v25; // [rsp+C8h] [rbp-360h] BYREF
__int64 v26; // [rsp+110h] [rbp-318h] BYREF
__int64 v27; // [rsp+158h] [rbp-2D0h] BYREF
char v28[36]; // [rsp+1A0h] [rbp-288h] BYREF
int v29; // [rsp+1C4h] [rbp-264h] BYREF
__int64 v30; // [rsp+1E8h] [rbp-240h] BYREF
int v31; // [rsp+20Ch] [rbp-21Ch] BYREF
char v32[360]; // [rsp+2C0h] [rbp-168h] BYREF
sub_40CC40(argc, argv, envp);
memset(v23, 0, sizeof(v23));
printf_0(byte_4A68E0, "Input Your Key:");
scanf(byte_4A6580, v23);
v3 = v23;
do
{
v4 = *(_DWORD *)v3;
v3 += 4;
v5 = ~v4 & (v4 - 16843009) & 0x80808080;
}
while ( !v5 );
if ( (~v4 & (v4 - 16843009) & 0x8080) == 0 )
v5 >>= 16;
if ( (~v4 & (v4 - 16843009) & 0x8080) == 0 )
v3 += 2;
if ( &v3[-__CFADD__((_BYTE)v5, (_BYTE)v5) - 3] - v23 == 64 )
{
if ( __OFADD__(1, 2004318072) && !__OFADD__(1, 2004318072) )
JUMPOUT(0x4A2A4Fi64);
v7 = v23;
v8 = v32;
v9 = (int *)&unk_4A4020;
v10 = v32;
printf_0(byte_4A68E0, "Are You Sure You Want To Keep Waiting...\n");
v11 = v24;
v12 = v24;
do
{
v13 = sub_401DB0(v7, 8i64);
v11[8] = 0;
*((_DWORD *)v11 + 1) = v13;
v14 = 4i64;
while ( 1 )
{
v15 = v14;
if ( v11[v14 + 3] )
break;
if ( !--v14 )
{
v15 = 0;
break;
}
}
*(_DWORD *)v11 = v15;
v16 = *v9;
v10[8] = 0;
*((_DWORD *)v10 + 1) = v16;
v17 = 4i64;
while ( 1 )
{
v18 = v17;
if ( v10[v17 + 3] )
break;
if ( !--v17 )
{
v18 = 0;
break;
}
}
v7 += 8;
*(_DWORD *)v10 = v18;
v11 += 36;
v10 += 36;
++v9;
}
while ( v7 != &v23[64] );
sub_403460(v28, 13i64);
sub_403460(&v29, 14i64);
sub_403460(&v30, 15i64);
sub_403460(&v31, 16i64);
sub_4029E0(v24, v28);
sub_4029E0(&v25, v28);
sub_402030(&v26, v28);
sub_402030(&v27, v28);
v19 = 0;
while ( 1 )
{
v20 = *(_DWORD *)v12;
if ( *(_DWORD *)v12 != *(_DWORD *)v8 )
break;
if ( v20 - 1 >= 0 )
{
if ( v32[36 * v19 - 573 + v20] != v32[36 * v19 + 3 + v20] )
break;
v21 = v20 - 2;
while ( (int)v21 >= 0 )
{
v22 = v12[v21-- + 4];
if ( v22 != v8[v21 + 5] )
goto LABEL_8;
}
}
++v19;
v12 += 36;
v8 += 36;
if ( v19 == 8 )
{
sub_401550("QWB{%s}\n", v23);
return 0;
}
}
}
LABEL_8:
sub_401550("sorry\n");
return 0;
}
逐步分析逻辑:
这里进行了一个判断,判断是否等于64,动调可以知道,这里其实就是判断输入值的长度
然后就是一些操作,都没有影响我们的输入值。
最关键的是接下来的几个函数:
前面四个实际上是创造四个key值,内部函数如下:
void __fastcall make_key(__int64 a1, int a2)
{
int v3; // eax
__int64 v4; // rax
int v5; // edx
v3 = sub_401EF0(3, a2); // 内部malloc了一大堆空间,并且没有进行释放
*(_BYTE *)(a1 + 8) = 0;
*(_DWORD *)(a1 + 4) = v3;
v4 = 4i64;
while ( 1 )
{
v5 = v4;
if ( *(_BYTE *)(a1 + v4 + 3) )
break;
if ( !--v4 )
{
v5 = 0;
break;
}
}
*(_DWORD *)a1 = v5;
}
由于开拓的内存空间并没有释放,会导致并不能直接动调获取,非要动调需要花费一定的时间,换个思路,可以通过部分区间动调判断函数内部进行了什么操作
可以确定RDX寄存器保存a2的值,RAX寄存器为函数输出值,动调获取多组数据,判断函数内部进行的操作,规律如下:
RDX RAX 10进制 差值
0X0 0X5 5 -
0x1 0xD 13 8
0x2 0x1D 29 16 //从这里开始,可以视作等比数列求和+13
0x3 0x3D 61 32
0x4 0x7D 125 64
0x5 0xFD 253 128
0x6 0x1FD 509 256
0x7 0x3FD 1021 512
0x8 0x7FD 2045 1024
0x9 0XFFD 4093 2048
......
基本确定规律:类似于求一个等比数列的和
{5,n=0
Sn={13,n=1
{((2<<(input-2))-1)*16+13,n>1
推出四个key值:
0xfffd,0x1fffd,0x3fffd,0x7fffd
加密部分:
xtea加密内部,主要内容:
sum = 0;
do
{
left_move((__int64)v72, &a2, 4); // v72=a2<<4
right_move((__int64)v73, &a2, 5); // v73=a2>>5
Xor(v74, v72, v73); // v74=v72^v73
Plus(v75, v74, &a2); // v75=v74+a2
v58 = 0;
v14 = 4i64;
v57 = sum;
while ( 1 )
{
v15 = v14;
if ( *((_BYTE *)&v56 + v14 + 3) )
break;
if ( !--v14 )
{
v15 = 0;
break;
}
}
v56 = v15;
v16 = sum & 3;
sum -= 0x70C88617; // sum+=0x8F3779E9
Plus(v76, &v56, &key[9 * v16]);
Xor(v77, v75, v76); // all:v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]) sum+=0x8F3779E9
Plus(&v52, &v52, v77);
left_move((__int64)v78, &v52, 4);
right_move((__int64)v79, &v52, 5);
Xor(v80, v78, v79);
Plus(v81, v80, &v52);
v58 = 0;
v17 = 4i64;
v57 = sum;
while ( 1 )
{
v18 = v17;
if ( *((_BYTE *)&v56 + v17 + 3) )
break;
if ( !--v17 )
{
v18 = 0;
break;
}
}
v56 = v18;
Plus(v82, &v56, &key[9 * ((sum >> 11) & 3)]);
Xor(v84, v81, v82);
Plus(&a2, &a2, v84); // all:v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3])
}
while ( sum != 0xE6EF3D20 ); // 0xE6EF3D20=-0x1910C2E0 ==>-9e3779b9//6
然后对值进行了Xor处理,是一个变种xtea,tea加密过程一样,也是有点小改动的加密
其中delta的值:
同样对值进行了Xor处理,简单计算可以得:delta=0x3d3529bc
最后一部分,判断:
解题脚本:
#include<stdio.h>
#include <stdint.h>
void xtea_decipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
unsigned int i;
uint32_t v0=v[0]^0xfd, v1=v[1]^0x1fd, delta=0x8F3779E9, sum=delta * num_rounds;
for (i=0; i < num_rounds; i++) {
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
sum -= delta;
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
}
v[0]=v0; v[1]=v1;
}
void tea_decrypt (uint32_t* v, uint32_t* k) {
uint32_t v0=v[0]^0x3fd, v1=v[1]^0x7fd, sum=0xA6A53780, i;
uint32_t delta=0x3d3529bc;
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;
}
int main()
{
uint32_t v[8]={0x1F306772,0xB75B0C29,0x4A7CDBE3,0x2877BDDF,0x1354C485,0x357C3C3A,0x738AF06C,0x89B7F537},arr[2],k[4]={0xfffd,0x1fffd,0x3fffd,0x7fffd};
unsigned int num_rounds=0;
int sum=0;
do{
sum-=0x70C88617;
num_rounds++;
}while(sum!=0xE6EF3D20);
for(int i=0;i<8;i+=2)
{
if(i<4)
{
arr[0]=v[i];
arr[1]=v[i+1];
xtea_decipher(num_rounds,arr,k);
}
else
{
arr[0]=v[i];
arr[1]=v[i+1];
tea_decrypt(arr,k);
}
printf("%08X%08X",arr[0],arr[1]);
}
}
//answer:QWB{CD402B6A139283822F0DEA49E65794356F44EA9B3F56652F2DA39881EC491878}