静态分析
定位关键函数
通过字符串定位到关键函数,输入为flag{}括号里的值,长度应该为26
注意到函数指针byte_4018A0,联想到了SMC,会有写入它的地方
if ( sub_401610((int)&v1, (int)&savedregs)
&& ((int (__thiscall *)(char *))byte_4018A0)(&v1) )
{
puts("congrats!");
sub_401CA0("flag{%.26s}\n\n", &v1);
result = 0;
}
找与输入相关的地方
index1 = 0;
while ( 1 )
{
v5 = *(_BYTE *)(index1 + input);
if ( v5 >= '0' && v5 <= '9' ) // 输入为数字
{
v6 = v5 - 0x41;
goto LABEL_6;
}
v6 = v5 - 0x41; // A-F转为0-5
if ( (unsigned __int8)(v5 - 0x41) > 0x19u ) // v5 > 0x5a,输入为a-z
break;
LABEL_6:
v3 *= 16;
if ( (unsigned __int8)(v5 - 0x30) <= 9u ) // 输入为数字
{
v7 = v3 - 0x30;
LABEL_10:
v3 = v5 + v7;
goto LABEL_11;
}
if ( v6 <= 25u ) // A-Z
{
v7 = v3 - 0x37; // A-F转为10-15
goto LABEL_10;
}
LABEL_11:
if ( ++index1 >= 8 ) // 循环8次
{
v8 = 1;
goto LABEL_14;
}
}
又是熟悉的输入范围判断,追一遍流程就行
根据 0-9减0x30,A-F减0x37,v3 *= 16 推出应是对前8位进行了string2hex
后面有对第9和第10个数进行操作的代码,分析了一下应该也是判断范围,没什么特别的
找return 1
v9 = _mm_shuffle_epi32(_mm_cvtsi32_si128(v3), 0);
..............
v18 = _mm_cvtsi32_si128((char)v11);
v19 = _mm_unpacklo_epi8(v18, v18);
v27 = _mm_shuffle_epi32(_mm_unpacklo_epi16(v19, v19), 0);
if ( v17 )
{
v20 = 0;
if ( dword_4053C4 >= 2 )
{
v20 = 16;
v21 = _mm_mullo_epi32(_mm_cvtepu8_epi32(_mm_cvtsi32_si128(v27.m128i_u32[0])), (__m128i)xmmword_404380);
xmmword_405018 = (__int128)_mm_xor_si128(
_mm_add_epi32((__m128i)xmmword_404340, v9),
_mm_add_epi32(v21, (__m128i)xmmword_405018));
xmmword_405028 = (__int128)_mm_xor_si128(
_mm_add_epi32(_mm_add_epi32((__m128i)xmmword_404350, (__m128i)xmmword_404340), v9),
_mm_add_epi32(v21, (__m128i)xmmword_405028));
xmmword_405038 = (__int128)_mm_xor_si128(
_mm_add_epi32(_mm_add_epi32((__m128i)xmmword_404360, (__m128i)xmmword_404340), v9),
_mm_add_epi32(v21, (__m128i)xmmword_405038));
xmmword_405048 = (__int128)_mm_xor_si128(
_mm_add_epi32(_mm_add_epi32((__m128i)xmmword_404370, (__m128i)xmmword_404340), v9),
_mm_add_epi32(v21, (__m128i)xmmword_405048));
}
do
{
*((_DWORD *)&xmmword_405018 + v20) = (v20 + v3) ^ (0x1010101 * v11 + *((_DWORD *)&xmmword_405018 + v20));
++v20;
}
while ( v20 < 24 );
v22 = 0;
while ( *((_BYTE *)&xmmword_405018 + v22) == *((_BYTE *)&loc_404148 + v22) )
{
if ( ++v22 >= 96 )
{
v28 = 0;
v23 = __rdtsc();
if ( HIDWORD(v23) > HIDWORD(v26) || (v28 = v23 - v26, (unsigned int)(v23 - v26) >= 0xFFFFFF) )
MEMORY[0] = 0;
v24 = GetCurrentProcess();
WriteProcessMemory(v24, &byte_4018A0, &xmmword_405018, 96u, 0);
return 1;
}
}
}
return 0;
}
参与xmmword运算的v9和前8位有关,v21和9,10位有关
while ( *((_BYTE *)&xmmword_405018 + v22) == *((_BYTE *)&loc_404148 + v22) )
*((_DWORD *)&xmmword_405018 + v20) = (v20 + v3) ^ (0x1010101 * v11 + *((_DWORD *)&xmmword_405018 + v20))
25510约为107数量级
v3是int,v11是byte,爆破范围v3为0x10000000-0xFFFFFFFF,v11为0-0xFF
不过自己确实没搞懂爆破这一步…略过
v24 = GetCurrentProcess();
WriteProcessMemory(v24, &byte_4018A0, &xmmword_405018, 96u, 0);
写入byte_4018A0,写入的96字节只是真个函数的一部分
3DES(可PEiD插件识别)
OWORD输入的后16位
v1 = *(_OWORD *)(a1 + 10);
xmmword处,正常来说正确的结果应该是ida识别的字符串的倒序
&v23存了Src的24个Byte,再结合&v21为三个函数参数,v23,v25,v27相差八个字节,这里很像3个Key,那么就是三重DES
Src = xmmword_4041A8;
v2 = strlen((const char *)&Src);
memcpy(&v23, &Src, v2);
memset((char *)&v23 + v2, 0, 24 - v2);
v21 = v23;
v22 = v24;
sub_401000(&v21, &v20);
v21 = v25;
v22 = v26;
sub_401000(&v21, &v19);
v21 = v27;
v22 = v28;
sub_401000(&v21, &v18);
/8说明输入长度最好为8的倍数,正常明文是64位8字节,这里正好得16,16是加密轮数
DES循环左移 [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]
3DES循环左移{ 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0 };
然后到这,v21应该是明文,同时可得到加密后的结果应该要为v12
v21 = ((unsigned __int8)*(&v32 + v5) << 24) | ((unsigned __int8)*(&v31 + v5) << 16) | ((unsigned __int8)*(&v30 + v5) << 8) | (unsigned __int8)*(&Dst + v5);
.........
sub_401500((unsigned int *)&v21, (int)&v20, (int)&v19, (int)&v18);
*(&v37 + v5) = v21;
........
*(_QWORD *)&v12 = 0xFACE0987E6A97C50i64;
v10 = 0;
*((_QWORD *)&v12 + 1) = 0x6C97BB90CF0DD520i64;
v13 = -1326018416;
v14 = -391862661;
while ( *((_BYTE *)&v12 + v10) == *(&v37 + v10) )
{
if ( ++v10 >= 16 )
return 1;
}
1 0 1像3DES解密的的EDE,a2 a3 a4对应三个Key
sub_401250(a2, this, 1);
sub_401250(a3, v4, 0);
sub_401250(a4, v4, 1);
进入sub_401250
函数内跟踪1 0 1分析其代表的是加密模式还是解密模式
因为DES解密密钥要反过来,所以跟踪第一个参数 密钥 的变化
在if(a3)内v17 += 4; else里v18 -= 4;所以1为加密,0为解密
解题脚本
from Crypto.Cipher import DES
s = '\x50\x7C\xA9\xE6\x87\x09\xCE\xFA\x20\xD5\x0D\xCF\x90\xBB\x97\x6C'
des0 = DES.new('AFSAFCED', DES.MODE_ECB)
des1 = DES.new('YCXCXACN', DES.MODE_ECB)
des2 = DES.new('DFKDCQXC', DES.MODE_ECB)
#加密是E(0)D(1)E(2)所以解密D(2)E(1)D(0)
text = des0.decrypt(des1.encrypt(des2.decrypt(s)))
print text
其它一些点
rdtsc可用来获得程序或者一段代码运行的时间