查壳
分析
-
IDA反编译:
-
主要的验证算法在 sub_4011C0中:
`bool __cdecl sub_4011C0(char *a1) { size_t v2; // eax signed int v3; // [esp+50h] [ebp-B0h] char v4[32]; // [esp+54h] [ebp-ACh] int v5; // [esp+74h] [ebp-8Ch] int v6; // [esp+78h] [ebp-88h] size_t i; // [esp+7Ch] [ebp-84h] char v8[128]; // [esp+80h] [ebp-80h] if ( strlen(a1) <= 4 ) return 0; i = 4; v6 = 0; while ( i < strlen(a1) - 1 ) v8[v6++] = a1[i++]; v8[v6] = 0; v5 = 0; v3 = 0; memset(v4, 0, 0x20u); for ( i = 0; ; ++i ) // 大小写互换 { v2 = strlen(v8); if ( i >= v2 ) break; if ( v8[i] >= 'a' && v8[i] <= 'z' ) { v8[i] -= 32; v3 = 1; } if ( !v3 && v8[i] >= 'A' && v8[i] <= 'Z' ) v8[i] += 32; v4[i] = byte_4420B0[i] ^ sub_4013C0(v8[i]); v3 = 0; } return strcmp("GONDPHyGjPEKruv{{pj]X@rF", v4) == 0; }` int __cdecl sub_4013C0(int a1) { return (a1 ^ 0x55) + 72; }
-
加密的算法很简单,先是大小写互换,然后给sub_4013C0处理,最后与硬编码异或。
脚本
import string
cipher=r'GONDPHyGjPEKruv{{pj]X@rF'
k=[0xd,0x13,0x17,0x11,0x2,0x1,0x20,0x1d,0xc,0x2,0x19,0x2f,0x17,0x2b,0x24,0x1f,0x1e,0x16,0x9,0xf,0x15,0x27,0x13,0x26,0xa,0x2f,0x1e,0x1a,0x2d,0xc,0x22,0x4]
ch=''
flag=''
i=0
'''
for c in cipher:
if c>='a' and c<='z':
ch=chr(ord(c)-32)
else:
if c>='A' and c<='Z':
ch=chr(ord(c)+32)
else:
ch=c
flag+=chr((((ord(ch)^k[i])-72)^0x55)&0xff)
i+=1
'''
for i in range(len(cipher)):
for c in string.printable:
if c>='a' and c<='z':
ch=chr(ord(c)-32)
else:
if c>='A' and c<='Z':
ch=chr(ord(c)+32)
else:
ch=c
ch=chr(k[i]^((ord(ch)^0x55)+72))
if ch==cipher[i]:
flag+=c
break
print 'EIS{'+flag+'}'
注意
注释的部分就是想说明一个问题:加密过程中涉及到异或+位移的,在求逆时有可能会超出字符范围,最保守的做法还是爆破,毕竟都是一对一的变换,也不费多少时间。