国赛-bbvvmm-SM4逆向分析,虚拟机指令分析
SM4
拿到程序是一个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码,并且存储到main函数的v13之中,继续往下分析main函数,有关v13的处理再main为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函数,进入401362函数分析
unsigned __int64 __fastcall sub_401362(__int64 a1, unsigned __int8 *a2, _BYTE *a3)
{
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;
该函数先将用户名生成的ASCII码即16个字符分成4组,接着执行32次循环,执行40EE2函数,第一次执行时参数为4组ASCCII码和一个不清楚的数字,进入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最后再与第一组ASCII码异或,再进入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个字符
并将这四个字符合并成新的字符,最后一步过长。。就不分析了。。。但是从这一遍流程
走下来,我们大概就能看出来是某种特定的加密方式,尤其是这个字母表更让人确信不疑。
如果了解SM4加密就知道其位SM4加密了,而那串未知的数字就是经过处理的密钥。
密钥加密的函数在主函数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
与其异或的就是密钥为主函数的v17将其整理一下
0xDA98F1DA
0X312AB753
0XA5703A0B
0XFD290DD6
密钥也便可以得知。
接着分析主函数的4067BD
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;
}
变种base64
将加密之后的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,且前面还有一些函数尚未分析 点开一看是虚拟机指令,由于函数较多只好将虚拟机指令拿出来慢慢分析
虚拟机分析
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{|}
就可以得到密码
xyz{|}
总结
逆向题目中虚拟机经常是一个重要的考点,而最近密码法的出台使得密码,尤其是国密受到了重视。就在最近的中石油比赛中也碰到了国密。这题收获还是不小的。
没有评论