这道题的计算由 某一处的异或爆破+循环移位操作+异或运算 组成。在题目的框输入正确的flag后会生成一个flag.txt文件,里边便是flag
定位关键代码的几种方法
段落引用
1.ida查找字符串,发现flag.bin和flag.txt。再使用x查找到了函数sub_402280
2.ida查看import表 发现如CryptDecrypt GetWindowTextA 这类API,同样能定位到函数sub_402280
3.运行程序,一个gui界面,动态调试软件下断获取信息的api(r如GetDlgItemTextA GetWindowTextA GetWindowTextW)
总而言之,找关键api 函数
程序分析如下 函数sub_402280
len = strlen((const char *)&Paint);
if ( len >= 6 )
{
v37 = SLOBYTE(Paint.fErase) % 7; // 余7 所以要长度>6 这取到的总是第5位的值 再之后拿这个值求余(动态调试的结果)
v38 = 1;
for ( i = 2; i < v37; ++i )
v38 *= (_BYTE)i; // v38乘i i开始为2 即为阶乘
v40 = 0;
if ( (unsigned int)len >= 0x40 )
{
v41 = _mm_cvtsi32_si128(v38); // v38的低128位赋值给一个32bits的整数
v42 = _mm_unpacklo_epi8(v41, v41);// v41的高8位相互交错,低8位舍去
v43 = _mm_shuffle_epi32(_mm_unpacklo_epi16(v42, v42), 0);// 128位分为4份 4*32位
do
{
*(__int128 *)((char *)&input + v40) = (__int128)_mm_xor_si128(
*(__m128i *)((char *)&Paint.hdc + v40),
v43);// 异或运算
*(__int128 *)((char *)&v59 + v40) = (__int128)_mm_xor_si128(
*(__m128i *)((char *)&Paint.rcPaint.right + v40),
v43);
*(__int128 *)((char *)&v60 + v40) = (__int128)_mm_xor_si128(*(__m128i *)&Paint.rgbReserved[v40], v43);
*(__m128i *)((char *)&v61 + v40) = _mm_xor_si128(*(__m128i *)&Paint.rgbReserved[v40 + 16], v43);
v40 += 64;
}
while ( v40 < len - len % 64 );
}
for ( ; v40 < len; ++v40 )
*((_BYTE *)&input + v40) = v38 ^ *((_BYTE *)&Paint.hdc + v40);// 算出来的v38的值 异或 。得出结果
*((_BYTE *)&input + v40) = 0;
v44 = 0;
do
{
*((_BYTE *)&input + v44) = __ROL1__(*((_BYTE *)&input + v44) ^ byte_420AE0[v44], v44);// ANNAWGALFYBKVIAHMXTFCAACLAAAAYK
++v44; // 异或计算->循环左移
}
while ( v44 < len );
v45 = &input;
v46 = (char *)&unk_4278D8; // 0x4E, 0xAE, 0x61, 0xBA, 0xE4, 0x2B, 0x55, 0xAA, 0x59, 0xFC, 0x4D, 0x02, 0x17, 0x6B, 0x13, 0xA1, 0x41, 0xFE, 0x35, 0x0B, 0xB4, 0x0B, 0x52, 0x2F, 0x46, 0xCC, 0x35, 0x82, 0xE5, 0x88, 0x50
v47 = 27;
while ( *(_DWORD *)v45 == *(_DWORD *)v46 )
{
v45 = (__int128 *)((char *)v45 + 4);
v46 += 4;
v48 = v47 < 4;
v47 -= 4;
if ( v48 )
{
if ( *(_WORD *)v45 == *(_WORD *)v46 && *((_BYTE *)v45 + 2) == v46[2] )// 计算结果与v46比较
{
MessageBoxA(hWndParent, "orz", "orz", 0);
sub_401F20((BYTE *)&Paint); // 成功后会与flag.bin结合生成flag.txt文件
}
return 0;
解密脚本如下
"""
正向思路:
1.取input[4]的值
2.求余,求余的值作为循环的次数
3.一个循环求值,用于与input异或
3.异或数组
4.循环左移
逆向思路:
1.循环右移
2.异或数组
3.爆破出正确的那个用于与input异或的值
4.异或求出flag
"""
def ROR(i,index):
tmp = bin(i)[2:].rjust(8,"0")
for _ in range(index): # 模拟循环右移
tmp = tmp[-1] + tmp[:-1] #取最后一位 取从第1位到最后一位前一位,拼接起来。相当于右移了一位。
return int(tmp, 2)
def ROL(i,index):
tmp = bin(i)[2:].rjust(8, "0")
for _ in range(index): # 模拟循环左移 本题并没用到。
tmp = tmp[1:] + tmp[0]
return int(tmp, 2)
str_list1 = [ord(c) for c in "ANNAWGALFYBKVIAHMXTFCAACLAAAAYK"]
# print(str_list1)
str_list2 = [0x4E, 0xAE, 0x61, 0xBA, 0xE4, 0x2B, 0x55, 0xAA,
0x59, 0xFC, 0x4D, 0x02, 0x17, 0x6B, 0x13, 0xA1,
0x41, 0xFE, 0x35, 0x0B, 0xB4, 0x0B, 0x52, 0x2F,
0x46, 0xCC, 0x35, 0x82, 0xE5, 0x88, 0x50]
print(len(str_list2))
tmp1 = []
flag1 = []
for i in range(len(str_list2)):
flag1.append((ROR(str_list2[i],i) ^ str_list1[i]))
print(flag1)
print(t) # 1 2 6 24 120
num_list = [1,2,6,24,120] # v38的可能的取值,由v37可能的取值(0到6)进行阶乘计算得出。
for p in range(0x100): # 可打印字符串进行爆破得出n 即下边的0x78(十进制120)
for n in num_list:
if n ^ p == flag1[4]:
print(n)
flag = []
for f in flag1:
flag.append(chr(f ^ 0x78))
print("".join(flag))
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2020-9-8 11:39
被绥术编辑
,原因: