解题过程

IDA打开,分析主函数可以较容易的分析出所需的输入是Sangfor{30位hex},然后按照Label11所述的逻辑进行判定:

image.png
上图中duihua5是虚拟机逻辑通过(此处的虚拟机详见后文)但md5不正确的情况,duihua4是二者都正确的情况,但是上面的伪代码由于花指令的存在,不完全正确。
接下来的部分无法在F5中得到,但是可以基于汇编从text view得到,这部分十六进制字符的部分值得注意:
image.png
目前无法得到关于这些字符如何使用的信息,动态调试时,关注这部分地址(403xxx),可以分析出这是一个虚拟机,其中:

  • 最后的64个字符为opcode,这64个字节中前面32个决定偏移,后面32个决定计算方式。
  • 计算方式包括模加,模减,模乘和异或,4种计算方法,32个字节中的前30个分别对30位输入决定,因为是16进制,可以分析出高4位决定一种,低4位决定一种,两种计算分别进行,存在于两个变量中。
  • image.png
  • 偏移值决定输入是与前面30*32的十六进制数的哪一位做运算,第一种运算是:第i位与第i行的第x位(x受偏移值控制,最大为15)进行计算,第二种运算是:第i位与第i行的第15+x位做运算,两个结果都是与第i行最后一位比较,有一个相等即可完成检查。


image.png

  • 据此可以写爆破脚本,得到每一位的可行值。
  • 不计md5的逻辑,可行的flag可以由以下脚本爆破得到,修改md5值可得到多个文件,使用任何cpp编译器编译可得到文件。 ```python

    include

    include

    include

    include

    include

    unsigned char gua[64]; unsigned char table[32][33] = { “f686bee4665fa77525e0f784097f4b3f”, “8ec4b805f93e9edd178818b3993e4a5d”, “4edb219c1f7dcf6dfb5c471a1f44ffa5”, “bd244ed81f96aef43ea55704085af9b4”, “594537dc31688cc4ef722bacdfac518e”, “91f800e6787c42f26e939a391c398ec6”, “69cf503c8cadc12176e791c6615bd704”, “8b1b9b88692d3804b9710a72ae458843”, “fe77fb82cf016df3913ed002bccb7d6d”, “711453fe706aed138823de8dcbf2fc38”, “4f027901b70a595828647b3a1407078e”, “5be1878d4e222009f13a3aacb2192861”, “3109983436e0eebe2b5c5a5e3d668c6b”, “6b33b28e18d6d9f0db4688cfad20ccbe”, “b47b71f489033446d3d9f097060e33ec”, “28d0871eb3f67152d8aa820500ddeabc”, “df51b921388b8032190cf0a3760e6fb6”, “85f7c2f7689bbf43965d120e3e7d4989”, “2d291f1367021787efb4a9bf3a204a92”, “7caf326155610f1b827a16e31cb9e04d”, “026910fc9c1aee91868e39dc5c0a3828”, “6f6dd1338d58da08a6c3a5ac28e73728”, “9555bb8ef33de07ed414521b30d1ce1f”, “f45c235edf62094bbbdd63a7b8c6dbc3”, “db2b5f869cc8517f596a4cd182a812e7”, “c6cf507b8a27e604a04d999ad8b9c5b4”, “5292154eb9e144201ec8e87dbb49769f”, “e6f55bc893978043e128015cc02b0197”, “cf727d37d5347f6573f3c82b1cc36287”, “7f1412d1f3e82f7335d19fa944c368ed”, “c3fe545e249ef80f5327d01be270c784”, “5ccd45379ddf5c9be0654e88c6984c83” }; int hex2int(char h) { if (h >= ‘0’&&h <= ‘9’) {
    1. return h - '0';
    } else if (h >= ‘a’&&h <= ‘f’) {
      return h - 'a' + 10;
    
    } else {
      return 0;
    
    } } char int2hex(int x) { char t[] = “0123456789abcdef”; return t[x]; }

int modplus(int a, int b) { return (a + b) % 16; }

int modminus(int a, int b) { return (16 + a - b) % 16; }

int modmult(int a, int b) { return (a*b) % 16; }

int modxor(int a, int b) { return (a^b) % 16; }

int onechange(int index, int k) { int p1, p2; int g1, g2; g1 = hex2int(table[31][index]) / 4; g2 = hex2int(table[31][index]) % 4; if (g1 == 0) { p1 = modplus(k, hex2int(table[index][hex2int(table[30][index])])); } else if (g1 == 1) { p1 = modminus(k, hex2int(table[index][hex2int(table[30][index])])); } else if (g1 == 2) { p1 = modmult(k, hex2int(table[index][hex2int(table[30][index])])); } else if (g1 == 3) { p1 = modxor(k, hex2int(table[index][hex2int(table[30][index])])); } if (g2 == 0) { p2 = modplus(k, hex2int(table[index][hex2int(table[30][index]) + 15])); } else if (g2 == 1) { p2 = modminus(k, hex2int(table[index][hex2int(table[30][index]) + 15])); } else if (g2 == 2) { p2 = modmult(k, hex2int(table[index][hex2int(table[30][index]) + 15])); } else if (g2 == 3) { p2 = modxor(k, hex2int(table[index][hex2int(table[30][index]) + 15])); } if (p1 == hex2int(table[index][31]) || p2 == hex2int(table[index][31])) { return 1; } else { return 0; } } int main() { char input[64]=”Sangfor{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}”; int li = strlen(input); float kilo = (li - 9) / 2; //printf(“%.1f斤,%d块\n”, kilo, li - 9); Sleep(1500); if (li - 9 != 30) { printf(“重新挑一个\n”); exit(1); } for (int i = 0; i < li; i++) { if (i < 8) { } else if (i == li - 1) { } else { for (int t = 0; t < 16; t++) { input[i] = int2hex(t); int u = onechange(i - 8, hex2int(input[i])); if (u == 1) { printf(“%d %c\n”,i-8,int2hex(t)); } }

    }

}
system("pause");

}

得到的结果如下:
```python
0 9 e
1 5 9
2 8 b
3 b d
4 5 c
5 6 9
6 4 d
7 3 b
8 b e
9 b d
10 9 f
11 1 9
12 1 9
13 f
14 2 4
15 6 7 e
16 a f
17 2 4
18 4 e
19 b e
20 5 6
21 1 3 5 7 9 b d e f
22 2 3
23 7
24 0 5
25 0
26 6
27 4
28 4 e
29 3 c

此为每一位的可行值,逐位爆破,共计有2的23次方乘以3乘以9得出226492416种不同的flag,选择一个flag并将md5值写在题目中即可实现多文件。

基于以上爆破结果,此脚本即可完成功能。

import hashlib

p01=['95','e5','99','e9']
p23=['8b','bb','8d','bd']
p45=['56','c6','59','c9']
p67=['43','d3','4b','db']
p89=['bb','eb','bd','ed']
p10=['91','f1','99','f9']
p12=['1f','9f']
p14=['2','4']
p15=['6','7','e']
p16=['a2','f2','a4','f4']
p18=['4b','eb','4e','ee']
p20=['5','6']
p21=['1','3','5','7','9','b','d','e','f']
p22=['27','37']
p24=['0064','5064']
p28=['4','e']
p29=['3','c']
str = 'Sangfor{'
for a01 in range(len( p01 )):
    for a23 in range(len( p23 )):
        for a45 in range(len( p45 )):
            for a67 in range(len( p67 )):
                for a89 in range(len( p89 )):
                    for a10 in range(len( p10 )):
                        for a12 in range(len( p12 )):
                            for a14 in range(len( p14 )):
                                for a15 in range(len( p15 )):
                                    for a16 in range(len( p16 )):
                                        for a18 in range(len( p18 )):
                                            for a20 in range(len( p20 )):
                                                for a21 in range(len( p21 )):
                                                    for a22 in range(len( p22 )):
                                                        for a24 in range(len( p24 )):
                                                            for a28 in range(len( p28 )):
                                                                for a29 in range(len( p29 )):
                                                                    str = 'Sangfor{'+p01[a01]+p23[a23]+p45[a45]+p67[a67]+p89[a89]+p10[a10]+p12[a12]+p14[a14]+p15[a15]+p16[a16]+p18[a18]+p20[a20]+p21[a21]+p22[a22]+p24[a24]+p28[a28]+p29[a29]+'}'
                                                                    mk=hashlib.md5(bytes(str,"utf8")).hexdigest()
                                                                    if mk[0:10]=='16f6d95849':
                                                                        print(str+':')
                                                                        print(mk)