貌似很复杂的一个题一点点弄明白。
程序上来就给了加密方式,但由于里边用了and运算,所以本身是不可逆的,需要正向爆破。
int __thiscall sub_401080(char *this)
{
char v2; // al
char *v3; // edi
char *v4; // ebx
int v5; // edx
int v6; // ecx
int v7; // eax
int v8; // esi
int v9; // eax
int result; // eax
__int128 v11[4]; // [esp+4h] [ebp-44h] BYREF
memset(v11, 0, sizeof(v11));
v2 = *this;
if ( *this )
{
v3 = this + 2; // 第3个
v4 = (char *)v11 + 4;
do
{
v5 = *(v3 - 1);
v3 += 5;
v4 += 16;
v6 = (v5 >> 6) | (4 * v2);
v7 = *(v3 - 5);
*((_DWORD *)v4 - 5) = v6;
LOBYTE(v6) = *(v3 - 4);
*((_DWORD *)v4 - 4) = (v7 >> 4) | (16 * (v5 & 0x3F));
v8 = ((char)v6 >> 2) | ((v7 & 0xF) << 6);
v9 = ((v6 & 3) << 8) | *(v3 - 3);
*((_DWORD *)v4 - 3) = v8;
*((_DWORD *)v4 - 2) = v9;
v2 = *(v3 - 2);
}
while ( v2 );
}
result = 0;
v11[0] = (__int128)_mm_and_si128(
_mm_andnot_si128(
_mm_and_si128((__m128i)xmmword_4021D0, (__m128i)v11[0]),
(__m128i)xmmword_4021E0),
_mm_xor_si128((__m128i)xmmword_4021D0, (__m128i)v11[0]));
v11[1] = (__int128)_mm_and_si128(
_mm_andnot_si128(
_mm_and_si128((__m128i)xmmword_4021D0, (__m128i)v11[1]),
(__m128i)xmmword_4021E0),
_mm_xor_si128((__m128i)xmmword_4021D0, (__m128i)v11[1]));
v11[2] = (__int128)_mm_and_si128(
_mm_andnot_si128(
_mm_and_si128((__m128i)xmmword_4021D0, (__m128i)v11[2]),
(__m128i)xmmword_4021E0),
_mm_xor_si128((__m128i)xmmword_4021D0, (__m128i)v11[2]));
v11[3] = (__int128)_mm_and_si128(
_mm_andnot_si128(
_mm_and_si128((__m128i)xmmword_4021D0, (__m128i)v11[3]),
(__m128i)xmmword_4021E0),
_mm_xor_si128((__m128i)xmmword_4021D0, (__m128i)v11[3]));
do
{
if ( *(_DWORD *)((char *)v11 + result * 4) != dword_402188[result] )
{
sub_401020("wrong\n", v11[0]);
exit(0);
}
++result;
}
while ( result < 16 );
return result * 4;
}
前一半是把20年字符分成4组,每组5个放到4个32位整形里,后边一半是对其作and,andnot,xor操作,sse的128位运算,由于5个字符爆破基本是不可能的,所以需要找其实的关系。
从前边5变4可以看出,变后的整形使用了10位,一共40位正好存了5个字符,而后边的and等操作都是位操作,没改变位的位置。所以可以从结果里找出字符对应的小段来比较判断。这样每一个字符爆破1次就完成了。
u32 = lambda a: a[0] |(a[1]<<8) | (a[2]<<16) | (a[3]<<24)
p32 = lambda a: bytes([a>>i*8 & 0xff for i in range(4)])
p128 = lambda a: bytes([a>>i*8 & 0xff for i in range(16)])
mm_and = lambda a,b: bytes([a[i] & b[i] for i in range(16)])
mm_andnot = lambda a,b: bytes([(0xff - a[i]) & b[i] for i in range(16)])
mm_xor = lambda a,b: bytes([a[i]^b[i] for i in range(16)])
x_4021D0 = p128(0x20000000200000002000000020)
x_4021E0 = p128(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
dword_402188 = [0x1a9, 0x233, 0x179, 0x17f, 0x1a5, 0x2c6, 0x137, 0x358,
0xe1, 0x305, 0x3ec, 0x153, 0x15d, 0x247, 0x17b, 0x201]
#仅说明存储位置,不使用
def enc(a):
v4[0] = (a[0]<<2) | (a[1]>>6)
v4[1] = ((a[1]*0x3f)<<4) | (a[2]>>4)
v4[2] = ((a[2]&0xf)<<6) | (a[3]>>2)
v4[3] = ((a[3]&0x3)<<8) | a[4]
return p32(v4[0])+p32(v4[1])+p32(v4[2])+p32(v4[3])
letter = b'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_!'
for k in range(4):
for i in letter:
d = p128(i<<2)
v = mm_and(mm_andnot( mm_and(x_4021D0, d), x_4021E0), mm_xor(x_4021D0, d))
if (u32(v[0:4])>>2)&0xff == (dword_402188[k*4+0]>>2)&0xff :
print(chr(i), end='') #0
break
for i in letter:
d = p128(((i>>6)&0x3) | ((i&0x3f)<<(32+4)))
v = mm_and(mm_andnot( mm_and(x_4021D0, d), x_4021E0), mm_xor(x_4021D0, d))
if ( ( u32(v[0:4])&3 ) << 6 )|( ( u32(v[4:8] ) >> 4 ) ) == ( ( dword_402188[k*4+0]&3 ) << 6 )| (( dword_402188[k*4+1]&0x3f0 ) >> 4) :
print(chr(i), end='') #1
break
for i in letter:
d = p128( (i>>4<<32) | (i&0xf)<<(64+6) )
v = mm_and(mm_andnot( mm_and(x_4021D0, d), x_4021E0), mm_xor(x_4021D0, d))
if ( ( u32(v[4:8])&0xf ) << 4 )|( ( u32(v[8:12] ) >> 6 ) ) == ( ( dword_402188[k*4+1]&0xf ) << 4 )| (( dword_402188[k*4+2] ) >> 6) :
print(chr(i), end='') #2
break
for i in letter:
d = p128( (i>>2<<64) | (i&0x3)<<(96+8) )
v = mm_and(mm_andnot( mm_and(x_4021D0, d), x_4021E0), mm_xor(x_4021D0, d))
if ( ( u32(v[8:12])&0x3f ) << 2 )|( ( u32(v[12:16] ) >> 8 ) ) == ( ( dword_402188[k*4+2]&0x3f ) << 2 )| (( dword_402188[k*4+3] ) >> 8) :
print(chr(i), end='') #3
break
for i in letter:
d = p128(i<<96)
v = mm_and(mm_andnot( mm_and(x_4021D0, d), x_4021E0), mm_xor(x_4021D0, d))
if (u32(v[12:16]))&0xff == (dword_402188[k*4+3])&0xff :
print(chr(i), end='') #4
break
#ba5e_and_x0r_1s_fun!
#ctfshow{ba5e_and_x0r_1s_fun!}