首页
社区
课程
招聘
[原创]#30天写作挑战#GACTF2020 WannaUpFlag详解
发表于: 2020-9-8 11:39 12678

[原创]#30天写作挑战#GACTF2020 WannaUpFlag详解

2020-9-8 11:39
12678

这道题的计算由 某一处的异或爆破+循环移位操作+异或运算 组成。在题目的框输入正确的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 被绥术编辑 ,原因:
收藏
免费 0
支持
分享
最新回复 (1)
雪    币: 26205
活跃值: (63302)
能力值: (RANK:135 )
在线值:
发帖
回帖
粉丝
2

感谢分享!

欢迎更多的小伙伴参与到 #30天写作挑战#中来!活动详情:https://bbs.pediy.com/thread-261705.htm


2020-9-9 10:21
0
游客
登录 | 注册 方可回帖
返回
//