拿到程序是一个ELF,64位程序,让你输入用户名和密码,放入IDA中进行分析主函数
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
__int64 v3; // rax
char *s1; // ST28_8
char v5; // ST1B_1
unsigned __int8 i; // [rsp+19h] [rbp-1A7h]
int v8; // [rsp+1Ch] [rbp-1A4h]
void *virtual_1; // [rsp+20h] [rbp-1A0h]
char v10; // [rsp+30h] [rbp-190h]
__int64 username; // [rsp+140h] [rbp-80h]
char v12; // [rsp+148h] [rbp-78h]
__int64 v13; // [rsp+150h] [rbp-70h]
__int64 v14; // [rsp+158h] [rbp-68h]
__int64 v15; // [rsp+160h] [rbp-60h]
__int64 v16; // [rsp+168h] [rbp-58h]
char v17; // [rsp+170h] [rbp-50h]
char v18; // [rsp+171h] [rbp-4Fh]
char v19; // [rsp+172h] [rbp-4Eh]
char v20; // [rsp+173h] [rbp-4Dh]
char v21; // [rsp+174h] [rbp-4Ch]
char v22; // [rsp+175h] [rbp-4Bh]
char v23; // [rsp+176h] [rbp-4Ah]
char v24; // [rsp+177h] [rbp-49h]
char v25; // [rsp+178h] [rbp-48h]
char v26; // [rsp+179h] [rbp-47h]
char v27; // [rsp+17Ah] [rbp-46h]
char v28; // [rsp+17Bh] [rbp-45h]
char v29; // [rsp+17Ch] [rbp-44h]
char v30; // [rsp+17Dh] [rbp-43h]
char v31; // [rsp+17Eh] [rbp-42h]
char v32; // [rsp+17Fh] [rbp-41h]
__int64 v33; // [rsp+180h] [rbp-40h]
__int64 v34; // [rsp+188h] [rbp-38h]
char s[8]; // [rsp+190h] [rbp-30h]
__int64 v36; // [rsp+198h] [rbp-28h]
__int64 v37; // [rsp+1A0h] [rbp-20h]
__int64 v38; // [rsp+1A8h] [rbp-18h]
char v39; // [rsp+1B0h] [rbp-10h]
unsigned __int64 v40; // [rsp+1B8h] [rbp-8h]
v40 = __readfsqword(0x28u);
virtual_1 = malloc(0x4D0uLL);
setbuf(stdin, 0LL);
setbuf(stdout, 0LL);
setbuf(stderr, 0LL);
puts("Powered by ????? !");
sub_406656("Powered by ????? !", 0LL);
puts("---------[LOGIN]---------");
printf("Username:", a2);
sub_405B25((__int64)virtual_1);
username = 0LL;
v12 = 0;
__isoc99_scanf("%9s", &username);
printf("\x1B[?25l", &username);
printf("Password:");
for ( i = 0; i <= 5u; ++i )
read(0, (char *)ptr + 4 * (i + 36LL), 1uLL);// 读取输入的6个字节
sub_406607((__int64)virtual_1);
*(_QWORD *)s = 0LL;
v36 = 0LL;
v37 = 0LL;
v38 = 0LL;
v39 = 0;
v13 = 0LL;
v14 = 0LL;
sub_4066C0((__int64)&username, (__int64)&v13, 8);
v15 = 0LL;
v16 = 0LL;
v17 = -38;
v18 = -104;
v19 = -15;
v20 = -38;
v21 = 49;
v22 = 42;
v23 = -73;
v24 = 83;
v25 = -91;
v26 = 112;
v27 = 58;
v28 = 11;
v29 = -3;
v30 = 41;
v31 = 13;
v32 = -42;
v33 = 0LL;
v34 = 0LL;
sub_401738(&v10, (__int64)&v17);
sub_4018C4((__int64)&v10, 1, 16, &v15, &v13, &v33);
sub_4067BD((__int64)&v33, (__int64)s, 16);
v3 = strlen(s);
s1 = sub_400AA6(s, v3);
v5 = strcmp(s1, "RVYtG85NQ9OPHU4uQ8AuFM+MHVVrFMJMR8FuF8WJQ8Y=");
printf("\x1B[?25h", "RVYtG85NQ9OPHU4uQ8AuFM+MHVVrFMJMR8FuF8WJQ8Y=");
v8 = *((_DWORD *)ptr + 0x19);
sub_405AA8();
if ( v5 || v8 )
{
puts("\n----------[EXIT]----------");
system("exit");
}
else
{
puts("\n---------[WELCOME]---------");
system("cat flag");
}
return 0LL;
}
首先输入用户名,而用户名的处理在函数4066c0之中,进入该函数
unsigned __int64 __fastcall sub_4066C0(__int64 username, __int64 a2, signed int a3)
{
unsigned __int8 i; // [rsp+25h] [rbp-Bh]
unsigned __int8 v5; // [rsp+26h] [rbp-Ah]
char v6; // [rsp+27h] [rbp-9h]
unsigned __int8 v7; // [rsp+27h] [rbp-9h]
unsigned __int64 v8; // [rsp+28h] [rbp-8h]
v8 = __readfsqword(0x28u);
for ( i = 0; i < a3; ++i )
{
v6 = *(_BYTE *)(i + username) & 0xF;
v5 = (*(_BYTE *)(i + username) >> 4) + 0x30;
if ( v5 <= 0x39u )
*(_BYTE *)(a2 + 2 * i) = v5;
else
*(_BYTE *)(2 * i + a2) = (*(_BYTE *)(i + username) >> 4) + 55;
v7 = v6 + 0x30;
if ( v7 <= 0x39u )
*(_BYTE *)(a2 + 2 * i + 1LL) = v7;
else
*(_BYTE *)(2 * i + 1LL + a2) = v7 + 7;
}
return __readfsqword(0x28u) ^ v8;
}
分析可得该处将字符转换为ASCII码,并且存储到V13之中。
而有关v13的处理函数在函数4018c4,进入该函数
unsigned __int64 __fastcall sub_4018C4(__int64 a1, int a2, int a3, _QWORD *a4, _QWORD *a5, _QWORD *a6)
{
__int64 v6; // rdx
_QWORD *v8; // [rsp+8h] [rbp-58h]
_QWORD *encode_username; // [rsp+10h] [rbp-50h]
_QWORD *v10; // [rsp+18h] [rbp-48h]
int v11; // [rsp+20h] [rbp-40h]
signed int i; // [rsp+3Ch] [rbp-24h]
signed int j; // [rsp+3Ch] [rbp-24h]
__int64 v14; // [rsp+40h] [rbp-20h]
__int64 v15; // [rsp+48h] [rbp-18h]
unsigned __int64 v16; // [rsp+58h] [rbp-8h]
v11 = a3;
v10 = a4;
encode_username = a5;
v8 = a6;
v16 = __readfsqword(0x28u);
if ( a2 == 1 ) // a2恒为1
{
while ( v11 > 0 ) // v11的值为16
{
for ( i = 0; i <= 15; ++i )
*((_BYTE *)v8 + i) = *((_BYTE *)encode_username + i) ^ *((_BYTE *)v10 + i);// 复制数组
sub_401362(a1 + 8, (unsigned __int8 *)v8, v8);
v6 = v8[1]; // 两组复制
*v10 = *v8;
v10[1] = v6;
encode_username += 2;
v8 += 2;
v11 -= 16;
}
}
else
{
while ( v11 > 0 )
{
v14 = *encode_username;
v15 = encode_username[1];
sub_401362(a1 + 8, (unsigned __int8 *)encode_username, v8);
for ( j = 0; j <= 15; ++j )
*((_BYTE *)v8 + j) ^= *((_BYTE *)v10 + j);
*v10 = v14;
v10[1] = v15;
encode_username += 2;
v8 += 2;
v11 -= 16;
}
}
return __readfsqword(0x28u) ^ v16;
}
将变为ASCII码的数组复制到v8,后执行401362函数
unsigned __int8 *encode_username; // ST10_8
_BYTE *encode_username2; // [rsp+8h] [rbp-168h]
unsigned __int64 v6; // [rsp+28h] [rbp-148h]
unsigned __int64 s; // [rsp+30h] [rbp-140h]
unsigned __int64 v8; // [rsp+38h] [rbp-138h]
unsigned __int64 v9; // [rsp+40h] [rbp-130h]
unsigned __int64 v10; // [rsp+48h] [rbp-128h]
__int64 v11; // [rsp+130h] [rbp-40h]
__int64 v12; // [rsp+138h] [rbp-38h]
__int64 v13; // [rsp+140h] [rbp-30h]
__int64 v14; // [rsp+148h] [rbp-28h]
unsigned __int64 v15; // [rsp+158h] [rbp-18h]
encode_username = a2;
encode_username2 = a3;
v15 = __readfsqword(0x28u);
v6 = 0LL;
memset(&s, 0, 0x120uLL);
s = ((unsigned __int64)encode_username[2] << 8) | ((unsigned __int64)encode_username[1] << 16) | ((unsigned __int64)*encode_username << 24) | encode_username[3];
v8 = ((unsigned __int64)encode_username[6] << 8) | ((unsigned __int64)encode_username[5] << 16) | ((unsigned __int64)encode_username[4] << 24) | encode_username[7];
v9 = ((unsigned __int64)encode_username[10] << 8) | ((unsigned __int64)encode_username[9] << 16) | ((unsigned __int64)encode_username[8] << 24) | encode_username[11];
v10 = ((unsigned __int64)encode_username[14] << 8) | ((unsigned __int64)encode_username[13] << 16) | ((unsigned __int64)encode_username[12] << 24) | encode_username[15];
while ( v6 <= 0x1F ) // 将数组分成了四组ASCII码
{
*(&s + v6 + 4) = sub_400EE2(*(&s + v6), *(&s + v6 + 1), *(&s + v6 + 2), *(&s + v6 + 3), *(_QWORD *)(8 * v6 + a1));
++v6;
}
*encode_username2 = BYTE3(v14);
encode_username2[1] = BYTE2(v14);
encode_username2[2] = BYTE1(v14);
encode_username2[3] = v14;
encode_username2[4] = BYTE3(v13);
encode_username2[5] = BYTE2(v13);
encode_username2[6] = BYTE1(v13);
encode_username2[7] = v13;
encode_username2[8] = BYTE3(v12);
encode_username2[9] = BYTE2(v12);
encode_username2[10] = BYTE1(v12);
encode_username2[11] = v12;
encode_username2[12] = BYTE3(v11);
encode_username2[13] = BYTE2(v11);
encode_username2[14] = BYTE1(v11);
encode_username2[15] = v11;
return __readfsqword(0x28u) ^ v15;
该函数首先将数组8个字符生成的ASCII码即16个字符分成4组,接着执行32次循环执行函数40EE2函数,第一次执行时参数为4组ASCII码和一个不知道是啥的数字,进入40EE2处函数
unsigned __int64 __fastcall sub_400EE2(__int64 a1, __int64 a2, __int64 a3, __int64 a4, __int64 a5)
{
return a1 ^ sub_400D87(a5 ^ a4 ^ a3 ^ a2);
}
再将后3个ASCII码和数字异或后执行400D87最后再与a1异或,在进入400D87函数
unsigned __int64 __fastcall sub_400D87(int a1)
{
unsigned __int8 v1; // ST30_1
unsigned __int8 v2; // ST31_1
unsigned __int8 v3; // ST32_1
unsigned __int8 v4; // al
unsigned __int64 v5; // ST10_8
v1 = sub_400D38(HIBYTE(a1));
v2 = sub_400D38(BYTE2(a1));
v3 = sub_400D38(BYTE1(a1));
v4 = sub_400D38(a1);
v5 = ((unsigned __int64)v3 << 8) | ((unsigned __int64)v2 << 16) | ((unsigned __int64)v1 << 24) | v4;
return (((unsigned __int64)((v3 << 8) | (v2 << 16) | (v1 << 24) | (unsigned int)v4) << 18) | (v5 >> 14)) ^ v5 ^ (4LL * ((v3 << 8) | (v2 << 16) | (v1 << 24) | (unsigned int)v4) | (v5 >> 30)) ^ (((unsigned __int64)(unsigned int)v5 << 10) | (v5 >> 22)) ^ (((unsigned __int64)((v3 << 8) | (v2 << 16) | (v1 << 24) | (unsigned int)v4) << 24) | (v5 >> 8));
}
4个异或后生成的数字分成4组在下图表中执行4次替换,重新生成4个8位的字符
最后一步返回是一串比较复杂的加密,其实这便是SM4加密最后一步应该便是L变换,而上面那一串看不懂的数字便是轮密钥,那个字母表便是SM4的S盒,确定了加密明文盒加密方式之后便是寻找密钥了,然而密钥处理是第一步,便是主函数的401738.
unsigned __int64 __fastcall sub_401738(_DWORD *a1, __int64 a2)
{
unsigned __int64 v2; // ST18_8
v2 = __readfsqword(0x28u);
*a1 = 1;
sub_401063((__int64)(a1 + 2), (unsigned __int8 *)a2);
return __readfsqword(0x28u) ^ v2;
}
在进入函数401063
unsigned __int64 __fastcall sub_401063(__int64 a1, unsigned __int8 *a2)
{
unsigned __int64 v2; // ST28_8
unsigned __int64 v3; // ST30_8
unsigned __int64 v4; // ST38_8
__int64 v5; // r12
unsigned __int64 v7; // [rsp+18h] [rbp-168h]
unsigned __int64 v8; // [rsp+40h] [rbp-140h]
unsigned __int64 v9; // [rsp+48h] [rbp-138h]
unsigned __int64 v10; // [rsp+50h] [rbp-130h]
unsigned __int64 v11; // [rsp+58h] [rbp-128h]
unsigned __int64 v12; // [rsp+168h] [rbp-18h]
v12 = __readfsqword(0x28u);
v7 = 0LL;
v2 = ((unsigned __int64)a2[6] << 8) | ((unsigned __int64)a2[5] << 16) | ((unsigned __int64)a2[4] << 24) | a2[7];
v3 = ((unsigned __int64)a2[10] << 8) | ((unsigned __int64)a2[9] << 16) | ((unsigned __int64)a2[8] << 24) | a2[11];
v4 = ((unsigned __int64)a2[14] << 8) | ((unsigned __int64)a2[13] << 16) | ((unsigned __int64)a2[12] << 24) | a2[15];
v8 = (((unsigned __int64)a2[2] << 8) | ((unsigned __int64)a2[1] << 16) | ((unsigned __int64)*a2 << 24) | a2[3]) ^ 0xA3B1BAC6;
v9 = v2 ^ 0x56AA3350;
v10 = v3 ^ 0x677D9197;
v11 = v4 ^ 0xB27022DC;
while ( v7 <= 0x1F )
{
v5 = *(&v8 + v7);
*(&v8 + v7 + 4) = v5 ^ sub_400F3F(*(&v8 + v7 + 3) ^ *(&v8 + v7 + 2) ^ *(&v8 + v7 + 1) ^ qword_406D80[v7]);
*(_QWORD *)(a1 + 8 * v7) = *(&v8 + v7 + 4);
++v7;
}
return __readfsqword(0x28u) ^ v12;
}
在这里我们看到了系统参数FK分别为
0xA3B1BAC6
0x56AA3350
0x677D9197
0xB27022DC
与其异或的分别为
0xDA98F1DA
0X312AB753
0XA5703A0B
0XFD290DD6
由此便可以知道此处为密钥,继续向下分析
unsigned __int64 __fastcall sub_4067BD(__int64 a1, __int64 a2, int a3)
{
int v4; // [rsp+Ch] [rbp-34h]
int i; // [rsp+2Ch] [rbp-14h]
char s[2]; // [rsp+30h] [rbp-10h]
unsigned __int64 v7; // [rsp+38h] [rbp-8h]
v4 = a3;
v7 = __readfsqword(0x28u);
for ( i = 0; i < v4; ++i )
{
sprintf(s, "%02X", *(unsigned __int8 *)(i + a1));
*(_WORD *)(a2 + 2 * i) = *(_WORD *)s;
}
return __readfsqword(0x28u) ^ v7;
}
此处将加密之后的ASCII码转换为字符,之后进入400AA6函数
_BYTE *__fastcall sub_400AA6(char *a1, __int64 a2)
{
_BYTE *result; // rax
signed int v3; // edx
char *v4; // rax
__int64 v5; // rax
__int64 v6; // rax
__int64 v7; // rax
__int64 v8; // rax
signed int v9; // eax
__int64 v10; // [rsp+0h] [rbp-50h]
char *v11; // [rsp+8h] [rbp-48h]
signed int v12; // [rsp+18h] [rbp-38h]
signed int i; // [rsp+18h] [rbp-38h]
signed int j; // [rsp+1Ch] [rbp-34h]
int k; // [rsp+1Ch] [rbp-34h]
void *ptr; // [rsp+20h] [rbp-30h]
__int64 v17; // [rsp+28h] [rbp-28h]
unsigned __int8 v18; // [rsp+30h] [rbp-20h]
unsigned __int8 v19; // [rsp+31h] [rbp-1Fh]
unsigned __int8 v20; // [rsp+32h] [rbp-1Eh]
char v21; // [rsp+40h] [rbp-10h]
char v22; // [rsp+41h] [rbp-Fh]
char v23; // [rsp+42h] [rbp-Eh]
char v24; // [rsp+43h] [rbp-Dh]
unsigned __int64 v25; // [rsp+48h] [rbp-8h]
v11 = a1;
v10 = a2;
v25 = __readfsqword(0x28u);
v12 = 0;
v17 = 0LL;
ptr = malloc(1uLL);
if ( !ptr )
return 0LL;
while ( 1 )
{
v6 = v10--;
if ( !v6 )
break;
v3 = v12++;
v4 = v11++;
*(&v18 + v3) = *v4;
if ( v12 == 3 )
{
v21 = v18 >> 2;
v22 = 16 * (v18 & 3) + (v19 >> 4);
v23 = 4 * (v19 & 0xF) + (v20 >> 6);
v24 = v20 & 0x3F;
ptr = realloc(ptr, v17 + 4);
for ( i = 0; i <= 3; ++i )
{
v5 = v17++;
*((_BYTE *)ptr + v5) = byte_406C20[(unsigned __int8)*(&v21 + i)];
}
v12 = 0;
}
}
if ( v12 > 0 )
{
for ( j = v12; j <= 2; ++j )
*(&v18 + j) = 0;
v21 = v18 >> 2;
v22 = 16 * (v18 & 3) + (v19 >> 4);
v23 = 4 * (v19 & 0xF) + (v20 >> 6);
v24 = v20 & 0x3F;
for ( k = 0; v12 + 1 > k; ++k )
{
ptr = realloc(ptr, v17 + 1);
v7 = v17++;
*((_BYTE *)ptr + v7) = byte_406C20[(unsigned __int8)*(&v21 + k)];
}
while ( 1 )
{
v9 = v12++;
if ( v9 > 2 )
break;
ptr = realloc(ptr, v17 + 1);
v8 = v17++;
*((_BYTE *)ptr + v8) = 61;
}
}
result = realloc(ptr, v17 + 1);
result[v17] = 0;
return result;
}
此处便为base64解密但是字母表却发生了变化.之后便是与RVYtG85NQ9OPHU4uQ8AuFM+MHVVrFMJMR8FuF8WJQ8Y=进行比较
写脚本解密
base64_table='IJLMNOPKABDEFGHCQRTUVWXSYZbcdefa45789+/6ghjklmnioprstuvqwxz0123y'
base_encode=str(raw_input(u"请输入解密字符"))
counter=base_encode.count("=")
length=len(base_encode)
encode=""
encode_re=""
if(counter==2):
a=base64_table.find(base_encode[length-4:length-3])#取前六位
a=a<<2
b=base64_table.find(base_encode[length-3:length-2])#取2位
b=b>>4
encode_re=chr(a+b)
if(counter==1):
a=base64_table.find(base_encode[length-4:length-3])#第一个字符前6位
a=a<<2
b=base64_table.find(base_encode[length-3:length-2])#第二个字符前2位
b=b>>4
encode_re1=chr(a+b)
a=base64_table.find(base_encode[length-3:length-2])#第二个字符后4位
a=(a&0xf)<<4
b=base64_table.find(base_encode[length-2:length-1])#第三个字符前4位
b=b>>2
encode_re2=chr(a+b)
encode_re=encode_re1+encode_re2
length=length-4
if(counter==0):
length=length+4
for i in range(0,length,4):#以4个字符为一组
a=base64_table.find(base_encode[i:i+1])#第一个字符6位
a=a<<2
b=base64_table.find(base_encode[i+1:i+2])#第二个字符前2位
b=b>>4
encode=encode+chr(a+b)
a=base64_table.find(base_encode[i+1:i+2])#第二个字符后4位
a=((a&0xf)<<4)
b=base64_table.find(base_encode[i+2:i+3])#第三个字符前4位
b=b>>2
encode=encode+chr(a+b)
a=base64_table.find(base_encode[i+2:i+3])#取第三个字符后2位
a=(a&3)<<6
b=base64_table.find(base_encode[i+3:i+4])#取第四个字符6位
encode=encode+chr(a+b)
encode=encode+encode_re
print(encode)
解密出来之后为EF468DBAF985B2509C9E200CF3525AB6,再进行SM4解密参考教程,由于之前将ASCII码进行转换为字符串,所以解密时字符串就为其ASCII码
解密过程如下
得到0x36323631363437323635373233313332
由于前面将字符变为ASCII码在进行两次base16解密可得
用户名badrer12但是还缺少一个密码,由于最后的判断条件ptr+25的值要为0,且前面还有一些函数尚未分析 点开一看为虚拟机指令
nsigned __int64 __fastcall sub_405B25(__int64 a1)
{
unsigned __int64 v1; // ST18_8
v1 = __readfsqword(0x28u);
*(_DWORD *)a1 = 0;
*(_DWORD *)(a1 + 4) = 0;
*(_DWORD *)(a1 + 8) = 0;
*(_DWORD *)(a1 + 12) = 0;
*(_DWORD *)(a1 + 16) = 0;
*(_DWORD *)(a1 + 20) = 0;
*(_DWORD *)(a1 + 24) = 0;
*(_DWORD *)(a1 + 28) = 0;
*(_DWORD *)(a1 + 32) = 0;
*(_DWORD *)(a1 + 36) = 0;
*(_DWORD *)(a1 + 40) = 0;
*(_DWORD *)(a1 + 44) = 0;
*(_DWORD *)(a1 + 48) = (unsigned __int64)&unk_6090E0;
*(_QWORD *)(a1 + 56) = &unk_6090E0;
qword_609240 = malloc(0x1000uLL);
ptr = malloc(0x1000uLL);
qword_609260 = malloc(0x1000uLL);
qword_609248 = malloc(0x1000uLL);
qword_609268 = malloc(0x1000uLL);
qword_609250 = malloc(0x1000uLL);
memset(qword_609240, 0, 0x1000uLL);
memset(ptr, 0, 0x1000uLL);
memset(qword_609260, 0, 0x1000uLL);
memset(qword_609248, 0, 0x1000uLL);
memset(qword_609268, 0, 0x1000uLL);
memset(qword_609250, 0, 0x1000uLL);
*(_DWORD *)(a1 + 16) = (_DWORD)qword_609260;
*(_DWORD *)(a1 + 20) = (_DWORD)qword_609248;
*(_DWORD *)(a1 + 24) = (_DWORD)qword_609268;
*(_DWORD *)(a1 + 28) = (_DWORD)qword_609250;
*(_DWORD *)(a1 + 36) = (_DWORD)ptr;
*(_DWORD *)(a1 + 64) = 1;
*(_QWORD *)(a1 + 72) = sub_401AA3;
*(_DWORD *)(a1 + 80) = 2;
*(_QWORD *)(a1 + 88) = sub_401B32;
*(_DWORD *)(a1 + 96) = 3;
*(_QWORD *)(a1 + 104) = sub_401C23;
*(_DWORD *)(a1 + 112) = 4;
*(_QWORD *)(a1 + 120) = sub_401CCF;
*(_DWORD *)(a1 + 128) = 5;
*(_QWORD *)(a1 + 136) = sub_401DC0;
*(_DWORD *)(a1 + 144) = 16;
*(_QWORD *)(a1 + 152) = sub_401E94;
*(_DWORD *)(a1 + 160) = 17;
*(_QWORD *)(a1 + 168) = sub_401F89;
*(_DWORD *)(a1 + 176) = 18;
*(_QWORD *)(a1 + 184) = sub_40209B;
*(_DWORD *)(a1 + 192) = 19;
*(_QWORD *)(a1 + 200) = sub_4021C1;
*(_DWORD *)(a1 + 208) = 20;
*(_QWORD *)(a1 + 216) = sub_4022CA;
*(_DWORD *)(a1 + 224) = 38;
*(_QWORD *)(a1 + 232) = sub_4023F0;
*(_DWORD *)(a1 + 240) = 39;
*(_QWORD *)(a1 + 248) = sub_4024B4;
*(_DWORD *)(a1 + 256) = 40;
*(_QWORD *)(a1 + 264) = sub_402595;
*(_DWORD *)(a1 + 272) = 41;
*(_QWORD *)(a1 + 280) = sub_4026BB;
*(_DWORD *)(a1 + 288) = 42;
*(_QWORD *)(a1 + 296) = sub_4027C4;
*(_DWORD *)(a1 + 304) = 48;
*(_QWORD *)(a1 + 312) = sub_4028EA;
*(_DWORD *)(a1 + 320) = 49;
*(_QWORD *)(a1 + 328) = sub_4029AF;
*(_DWORD *)(a1 + 336) = 50;
*(_QWORD *)(a1 + 344) = sub_402A91;
*(_DWORD *)(a1 + 352) = 51;
*(_QWORD *)(a1 + 360) = sub_402BB8;
*(_DWORD *)(a1 + 368) = 52;
*(_QWORD *)(a1 + 376) = sub_402CC2;
*(_DWORD *)(a1 + 384) = 70;
*(_QWORD *)(a1 + 392) = sub_402DE9;
*(_DWORD *)(a1 + 400) = 71;
*(_QWORD *)(a1 + 408) = sub_402EAF;
*(_DWORD *)(a1 + 416) = 72;
*(_QWORD *)(a1 + 424) = sub_402F92;
*(_DWORD *)(a1 + 432) = 73;
*(_QWORD *)(a1 + 440) = sub_4030BA;
*(_DWORD *)(a1 + 448) = 74;
*(_QWORD *)(a1 + 456) = sub_4031C5;
*(_DWORD *)(a1 + 464) = 80;
*(_QWORD *)(a1 + 472) = sub_4032ED;
*(_DWORD *)(a1 + 480) = 81;
*(_QWORD *)(a1 + 488) = sub_4033B3;
*(_DWORD *)(a1 + 496) = 82;
*(_QWORD *)(a1 + 504) = sub_403496;
*(_DWORD *)(a1 + 512) = 83;
*(_QWORD *)(a1 + 520) = sub_4035BE;
*(_DWORD *)(a1 + 528) = 84;
*(_QWORD *)(a1 + 536) = sub_4036C9;
*(_DWORD *)(a1 + 544) = 102;
*(_QWORD *)(a1 + 552) = sub_4037F1;
*(_DWORD *)(a1 + 560) = 103;
*(_QWORD *)(a1 + 568) = sub_4038B5;
*(_DWORD *)(a1 + 576) = 104;
*(_QWORD *)(a1 + 584) = sub_403996;
*(_DWORD *)(a1 + 592) = 105;
*(_QWORD *)(a1 + 600) = sub_403ABC;
*(_DWORD *)(a1 + 608) = 106;
*(_QWORD *)(a1 + 616) = sub_403BC5;
*(_DWORD *)(a1 + 624) = 112;
*(_QWORD *)(a1 + 632) = sub_403CEB;
*(_DWORD *)(a1 + 640) = 113;
*(_QWORD *)(a1 + 648) = sub_403DAF;
*(_DWORD *)(a1 + 656) = 114;
*(_QWORD *)(a1 + 664) = sub_403E90;
*(_DWORD *)(a1 + 672) = 115;
*(_QWORD *)(a1 + 680) = sub_403FB6;
*(_DWORD *)(a1 + 688) = 116;
*(_QWORD *)(a1 + 696) = sub_4040BF;
*(_DWORD *)(a1 + 704) = 128;
*(_QWORD *)(a1 + 712) = sub_4041E5;
*(_DWORD *)(a1 + 720) = 129;
*(_QWORD *)(a1 + 728) = sub_4042A9;
*(_DWORD *)(a1 + 736) = 130;
*(_QWORD *)(a1 + 744) = sub_40438A;
*(_DWORD *)(a1 + 752) = 131;
*(_QWORD *)(a1 + 760) = sub_4044B0;
*(_DWORD *)(a1 + 768) = 0x84;
*(_QWORD *)(a1 + 776) = sub_4045B9;
*(_DWORD *)(a1 + 784) = 0x86;
*(_QWORD *)(a1 + 792) = sub_404BED;
*(_DWORD *)(a1 + 800) = 0x87;
*(_QWORD *)(a1 + 808) = sub_404CC3;
*(_DWORD *)(a1 + 816) = 0x88;
*(_QWORD *)(a1 + 824) = sub_404DB6;
*(_DWORD *)(a1 + 832) = 0x89;
*(_QWORD *)(a1 + 840) = sub_404E61;
*(_DWORD *)(a1 + 848) = 0x8A;
*(_QWORD *)(a1 + 856) = sub_404F3F;
*(_DWORD *)(a1 + 864) = 0x8B;
*(_QWORD *)(a1 + 872) = sub_404FEA;
*(_DWORD *)(a1 + 880) = 0x90;
*(_QWORD *)(a1 + 888) = sub_4050C8;
*(_DWORD *)(a1 + 896) = 145;
*(_QWORD *)(a1 + 904) = sub_405126;
*(_DWORD *)(a1 + 912) = 160;
*(_QWORD *)(a1 + 920) = sub_4046DF;
*(_DWORD *)(a1 + 928) = 0xA1;
*(_QWORD *)(a1 + 936) = sub_4047A7;
*(_DWORD *)(a1 + 944) = 0xA2;
*(_QWORD *)(a1 + 952) = sub_40488C;
*(_DWORD *)(a1 + 960) = 163;
*(_QWORD *)(a1 + 968) = sub_4049B6;
*(_DWORD *)(a1 + 976) = 164;
*(_QWORD *)(a1 + 984) = sub_404AC3;
*(_DWORD *)(a1 + 992) = 0xB0;
*(_QWORD *)(a1 + 1000) = sub_40516C;
*(_DWORD *)(a1 + 1008) = 0xB1;
*(_QWORD *)(a1 + 1016) = sub_4051E3;
*(_DWORD *)(a1 + 1024) = 0xB2;
*(_QWORD *)(a1 + 1032) = sub_4052BC;
*(_DWORD *)(a1 + 1040) = 0xB3;
*(_QWORD *)(a1 + 1048) = sub_405350;
*(_DWORD *)(a1 + 1056) = 0xB4;
*(_QWORD *)(a1 + 1064) = sub_4053C7;
*(_DWORD *)(a1 + 1072) = 0xB5;
*(_QWORD *)(a1 + 1080) = sub_4054A0;
*(_DWORD *)(a1 + 1088) = 192;
*(_QWORD *)(a1 + 1096) = sub_405534;
*(_DWORD *)(a1 + 1104) = 193;
*(_QWORD *)(a1 + 1112) = sub_4055D6;
*(_DWORD *)(a1 + 1120) = 194;
*(_QWORD *)(a1 + 1128) = sub_405649;
*(_DWORD *)(a1 + 1136) = 195;
*(_QWORD *)(a1 + 1144) = sub_4056BC;
*(_DWORD *)(a1 + 1152) = 196;
*(_QWORD *)(a1 + 1160) = sub_40572F;
*(_DWORD *)(a1 + 1168) = 197;
*(_QWORD *)(a1 + 1176) = sub_4057A2;
*(_DWORD *)(a1 + 1184) = 198;
*(_QWORD *)(a1 + 1192) = sub_405817;
*(_DWORD *)(a1 + 1200) = 199;
*(_QWORD *)(a1 + 1208) = sub_40588B;
*(_DWORD *)(a1 + 1216) = 200;
*(_QWORD *)(a1 + 1224) = sub_405904;
return __readfsqword(0x28u) ^ v1;
}
unsigned __int64 __fastcall sub_406607(__int64 virtual_1)
{
unsigned __int64 v2; // [rsp+18h] [rbp-8h]
v2 = __readfsqword(0x28u);
while ( **(_BYTE **)(virtual_1 + 56) != -1 ) // 第一个字符为B0
sub_40656D(virtual_1);
return __readfsqword(0x28u) ^ v2;
}
unsigned __int64 __fastcall sub_40656D(__int64 virtual_1)
{
unsigned __int8 i; // [rsp+17h] [rbp-9h]
unsigned __int64 v3; // [rsp+18h] [rbp-8h]
v3 = __readfsqword(0x28u);
for ( i = 0; i <= 0x48u; ++i )
{
if ( **(unsigned __int8 **)(virtual_1 + 56) == *(_DWORD *)(16 * (i + 4LL) + virtual_1) )// 第一个字符为B0执行40516c函数
{
(*(void (__fastcall **)(__int64))(16 * (i + 4LL) + virtual_1 + 8))(virtual_1);
return __readfsqword(0x28u) ^ v3;
}
}
return __readfsqword(0x28u) ^ v3;
和上次DDCTF的虚拟指令分析很像。字节码在6090E0处,起初分析了一会儿后来觉得挺复杂的干脆就动态调试看汇编,下硬件断点调试过也找到了异或的数据。但是其实虚拟机指令也可以分析
B019000000 push 0x19
B50A pop r11 r11=0x19
B20B push r12 r12=0
B409 pop ptr[r11] ptr[0x19]=0
B01A000000 push 0x1a
B50A pop r11 r11=0x1a
040B09 mov ptr[r11],r12 ptr[0x1a]=0
B01A000000 push 0x1a
B50A pop r11
B20B push r12
B409 pop ptr[r11] ptr[0x1a]=0
90c2 jmp 0xc2
26:
011a0000000a mov r11,0x1a r11=0x1a
020900 mov r1,ptr[r11] r1=ptr[0x1a]
10093000000001 r2=ptr[0x30] r2=&ptr[0x30]
b201 push r2
b200 push r1
c0 mov [esp+4],r2+4*r1
b500 pop r1 r1=&ptr[0x30]
b0f4ffffff push fffffff4
b50a pop r11 r11=-12
b100 push r1[r11] ptr[0x30-12]=ptr[0x24] 为第一个输入的字符
b501 pop r2 r2=input[0]
011a0000000a mov r11,0x1a r11=0x1a
b109 push ptr[r11]
b500 pop r1 r1=ptr[0x1a]
100078000000 r1=r1+78 r1=0x78+ptr[0x1a]
7000FF000000 r1=0xff&r1
500018000000 r1=r1<<0x18
b200 push r1
b018000000 push 0x18
c8 (esp_1)=r1>>18
b500 pop r1
b201 push r2
b200 push r1
c3 esp-1^=esp-2
b500 pop r1 r1=input[0]^0x78
500018000000 r1=r1<<0x18
b200 push r1
b018000000 push 0x18
c8 esp_1=r1>>0x18
b500 pop r1
7000ff000001 r2=r1&&0xff r2=(input[0]^0x78)&0xff
01190000000a r11=0x19
020900 r1=ptr[r11]
11010000 if(r2==0) r1=r2+4*r1 else r1=r2+r1
b019000000 push 0x19
b50a pop r11
b200 push r1
b409 pop ptr[r11] ptr[0x19]=r1
011a0000000a r11=0x1a
b109 push ptr[r11] prt[0x1a]
b500 pop r1
10000100000000 r1=r1+1
011a0000000a r11=0x1a
040009 ptr[0x1a]=r1=1
b01a000000 push 0x1a
b50a pop r11
020900 r1=ptr[r11]=ptr[0x1a]
86000600000000 r1=r1<0x6
8800026000000 r1!=0 jz 0x26
91 nop
ff exit
c2:
b01a000000 push 0x1a
b50a pop r11
020900 mov r1,ptr[r11] r1=0
86000600000000 r1=r1<0x6
880026000000 r1!=0;jz 0x26
91 nop
ff exit
由此可得知prt[0x1a]为计数循环,循环输入6次字符,且改变异或的值。ptr[0x19]为判断位。。判断异或后的值是否位0。
就可以得到密码
xyz{|}