跳转至

2019 西湖论剑初赛

标签:C++, 进制转换, 花指令, MFC, 最短路径, ttl, 编码

西湖论剑的初赛题目,质量不是很高,但是由于这是我第一次接触花指令,再加上对MFC不熟悉,有点懵逼,第三题题没做出来。最终卡着线进了决赛。。。

比赛时间:4月7日

题目下载地址

Re

easyCpp

输入16个数a[16],用vector保存

动调中可以发现,依次用a[0]减去a[1]到a[15]的每一个数,然后反序,跟斐波那契数列的前16位对比。

1
2
3
4
5
6
7
8
9
a = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987]
b = [0 for i in range(16)]
for i in range(16):
    b[i] = a[15-i]
c = [0 for i in range(16)]
c[0] = b[0]
for i in range(1,16):
    c[i] = b[i] - b[0]
print(c)

testre

输入一串长度16的字符串后,先跟常量异或再加。但是之后并没有用到,所以这一步没用。

还是原先的输入,将输入转成58进制(其实从%58再/58就能看出来了)存进一个数组,然后按照一个table转成字符,跟常量对比。期间穿插了一个base64的数组,并没什么用直接忽略。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  _i = zero;
  current_lenth = n - 1;
  while ( _i < input_lenth )
  {
    decnumber = (unsigned __int8)input_[_i];
    for ( j = n - 1; ; --j )
    {
      v10 = 1;
      if ( j <= current_lenth )
        v10 = decnumber != 0;
      if ( !v10 )
        break;
      noused = base58bit[j] << 6;
      decnumber += base58bit[j] << 8;
      v9 = 64;
      base58bit[j] = decnumber % 0x3A;
      b64noused[j] = noused & 0x3F;
      noused >>= 6;
      decnumber /= 0x3A;
      v27 /= v9;
      if ( !j )
        break;
    }
    ++_i;
    current_lenth = j;
  }

直接转dec再转string就行了

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
s = 'D9cS9N9iHjMLTdA8YSMRMp'
t = []
table = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
for i in range(len(s)):
    t.append(table.index(s[i]))
res = 0
for i in range(22):
    res+=t[i]*(58**(21-i))
t = hex(res)[2:-1]
print(t.decode('hex'))

Junk Instruction

此题为MFC程序。由于不太擅长窗体程序,一开始跟踪了很久,也没找到点击事件函数。后来知道了有xspy这个工具,可以查看到点击事件函数在0x00AA2420

进入IDA静态分析,在sub_402420中可以看到有两个分支,里面明显有Correct和Error,跟进去可以看到对应的字符串。sub_402600就是check函数了,一进去也能看到一串常量。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
  if ( sub_402600(v4 + 16) )
  {
    sub_401BF0(v5);
    v10 = 0;
    v12 = 0;
    sub_403DC0(129, 0);
    v9 = &CCorrect::`vftable';
    v19 = 0;
    sub_40484E(v7, v8);
    v9 = &CCorrect::`vftable';
    v19 = 2;
    sub_407B3B(&v13);
    LOBYTE(v19) = 1;
    v11 = &CBrush::`vftable';
    sub_401580(&v11);
  }
  else
  {
    sub_401BF0(v5);
    v15 = 0;
    v17 = 0;
    sub_403DC0(130, 0);
    v14 = &CError::`vftable';
    v19 = 3;
    sub_40484E(v7, v8);
    v14 = &CError::`vftable';
    v19 = 5;
    sub_407B3B(&v18);
    LOBYTE(v19) = 4;
    v16 = &CBrush::`vftable';
    sub_401580(&v16);
  }
  v19 = -1;
  return sub_40434D(v7, v8);

一进去发现反编译不动,往下看有几条可疑的指令:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
.text:0040293A 4D8                 call    sub_402CA0
.text:0040293F 4D8                 call    $+5
.text:00402944
.text:00402944     loc_402944:                             ; DATA XREF: check+398↓r
.text:00402944 4DC                 pop     eax
.text:00402945 4D8                 mov     [ebp+var_23C], eax
.text:0040294B 4D8                 call    loc_402953
.text:0040294B     ; --------------------------------------------------------------------
.text:00402950 4D8                 db 0EAh
.text:00402951     ; --------------------------------------------------------------------
.text:00402951 4D8                 jmp     short loc_40295C
.text:00402953     ; --------------------------------------------------------------------
.text:00402953
.text:00402953     loc_402953:                             ; CODE XREF: check+34B↑j
.text:00402953 4D8                 pop     ebx
.text:00402954 4D4                 inc     ebx
.text:00402955 4D4                 push    ebx
.text:00402956 4D8                 mov     eax, 11111111h
.text:0040295B 4D8                 retn
.text:0040295C     ; --------------------------------------------------------------------
.text:0040295C
.text:0040295C     loc_40295C:                             ; CODE XREF: check+351↑j
.text:0040295C 4D8                 call    loc_402968
.text:00402961 4D8                 mov     ebx, 33333333h
.text:00402966 4D8                 jmp     short loc_402975
.text:00402968     ; --------------------------------------------------------------------
.text:00402968
.text:00402968     loc_402968:                             ; CODE XREF: check:loc_40295C↑p
.text:00402968 4D8                 mov     ebx, 11111111h
.text:0040296D 4D8                 pop     ebx
.text:0040296E 4D4                 mov     ebx, offset loc_402975
.text:00402973 4D4                 push    ebx
.text:00402974 4D8                 retn
.text:00402975     ; --------------------------------------------------------------------
.text:00402975
.text:00402975     loc_402975:                             ; CODE XREF: check+366↑j
.text:00402975                                             ; DATA XREF: check+36E↑o
.text:00402975 4D8                 mov     ebx, 22222222h
.text:0040297A 4D8                 lea     ecx, [ebp+var_38]
.text:0040297D 4D8                 mov     [ebp+var_260], ecx
.text:00402983 4D8                 mov     edx, [ebp+var_260]

0040293F的call就是下一条指令,之后pop eax将返回地址出栈,之后0040294B的call调用到00402953后,返回地址出栈,加一,再入栈,这样返回地址指向的实际是00402951,下一个位于0040295C的call完成了相似的操作,将返回地址改为00402975,之后程序就正常进行了。

通过刚刚的分析可以看出,虽然经过了三个call,但并没有对数据进行实质的改变,所以中间的指令都没什么用,但是却阻碍了ida的分析,因此我们将第一个call直接改为jmp到00402975,这样ida就能成功分析了。在这些指令中看起来改变了一些寄存器eax,ebx的值,但这些值都没用到,期间保存到栈上的数据(00402945的指令)也没用到,比如eax到最后被幅值为了0x11111111h,再往后看可以发现这个数据没用。

剩下的部分就照常分析了,期间几个函数内也有相同的花指令,用相同的方式处理即可。

加密方式:

将输入除去"flag{}"后反序,再以“qwertyuiop”为密钥进行ARC4加密。

1
2
3
4
5
6
7
from Crypto.Cipher import ARC4
key = 'qwertyuiop'
arc4 = ARC4.new(key)
a = [0x5B, 0xD6, 0xD0, 0x26, 0xC8, 0xDD, 0x19, 0x7E, 0x6E, 0x3E, 0xCB, 0x16, 0x91, 0x7D, 0xFF, 0xAF, 0xDD, 0x76, 0x64, 0xB0, 0xF7, 0xE5, 0x89, 0x57, 0x82, 0x9F, 0xC, 0, 0x9E, 0xD0, 0x45, 0xFA]
c = ''.join(map(chr,a))
p = arc4.decrypt(c)
print(p[::-1])

第一次搞花指令,花的类型也比较简单,多多学习。

Misc

ttl

将ttl的头两位提取出来,每4个(8位)组成一个字符

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
with open("flag.txt","w") as flag:
    with open("ttl.txt","r") as ttlfile:
        j=0
        temp=0
        for i in ttlfile.readlines():
            j+=1
            this=i.split("=")[1]
            this=(int(this)&0xc0)>>6
            temp=(temp<<2)+this
            if(j%4==0):
                #print temp
                flag.write(chr(temp))
                # print chr(temp)
                temp=0
                j=0

直接转二进制写入文件,观察文件头可以看出是jpeg。打开后是一部分二维码。foremost分离后得六部分,拼接一下扫出来是:

key:AutomaticKey cipher:fftu{2028mb39927wn1f96o6e12z03j58002p}

用自动密钥解,明文开头肯定是flag,因此再密钥后面加个flag然后解维吉尼亚密码就出flag了。

路径

图的最短路径问题,每个条边权值一样。用Dijkstra很容易求出结果

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# -*-coding:utf-8 -*-
class DijkstraPath():
    def __init__(self, node_map):
        self.node_map = node_map
        self.node_length = len(node_map)
        self.used_node_list = []
        self.collected_node_dict = {}
    def __call__(self, from_node, to_node):
        self.from_node = from_node
        self.to_node = to_node
        self._init_dijkstra()
        return self._format_path()
    def _init_dijkstra(self):
        self.used_node_list.append(self.from_node)
        self.collected_node_dict[self.from_node] = [0, -1]
        for index1, node1 in enumerate(self.node_map[self.from_node]):
            if node1:
                self.collected_node_dict[index1] = [node1, self.from_node]
        self._foreach_dijkstra()
    def _foreach_dijkstra(self):
        if len(self.used_node_list) == self.node_length - 1:
            return
        for key, val in self.collected_node_dict.items():  # 遍历已有权值节点
            if key not in self.used_node_list and key != to_node:
                self.used_node_list.append(key)
            else:
                continue
            for index1, node1 in enumerate(self.node_map[key]):  # 对节点进行遍历
                # 如果节点在权值节点中并且权值大于新权值
                if node1 and index1 in self.collected_node_dict and self.collected_node_dict[index1][0] > node1 + val[0]:
                    self.collected_node_dict[index1][0] = node1 + val[0] # 更新权值
                    self.collected_node_dict[index1][1] = key
                elif node1 and index1 not in self.collected_node_dict:
                    self.collected_node_dict[index1] = [node1 + val[0], key]
        self._foreach_dijkstra()
    def _format_path(self):
        node_list = []
        temp_node = self.to_node
        node_list.append((temp_node, self.collected_node_dict[temp_node][0]))
        while self.collected_node_dict[temp_node][1] != -1:
            temp_node = self.collected_node_dict[temp_node][1]
            node_list.append((temp_node, self.collected_node_dict[temp_node][0]))
        node_list.reverse()
        return node_list
def set_node_map(node_map, node, node_list):
    for x, y, val in node_list:
        node_map[node.index(x)][node.index(y)] = node_map[node.index(y)][node.index(x)] =  val
if __name__ == "__main__":
    node = []
    node_list = [('FloraPrice','E11', 1),('FloraPrice','E9', 1),('FloraPrice','75D}', 1),('NoraFayette','E11', 1),('NoraFayette','E10', 1),('NoraFayette','E13', 1),('NoraFayette','E12', 1),('NoraFayette','E14', 1),('NoraFayette','E9', 1),('NoraFayette','E7', 1),('NoraFayette','E6', 1),('E10','SylviaAvondale', 1),('E10','MyraLiddel', 1),('E10','HelenLloyd', 1),('E10','KatherinaRogers', 1),('VerneSanderson','E7', 1),('VerneSanderson','E12', 1),('VerneSanderson','E9', 1),('VerneSanderson','E8', 1),('E12','HelenLloyd', 1),('E12','KatherinaRogers', 1),('E12','SylviaAvondale', 1),('E12','MyraLiddel', 1),('E14','SylviaAvondale', 1),('E14','75D}', 1),('E14','KatherinaRogers', 1),('FrancesAnderson','E5', 1),('FrancesAnderson','E6', 1),('FrancesAnderson','E8', 1),('FrancesAnderson','E3', 1),('DorothyMurchison','E9', 1),('DorothyMurchison','E8', 1),('EvelynJefferson','E9', 1),('EvelynJefferson','E8', 1),('EvelynJefferson','E5', 1),('EvelynJefferson','E4', 1),('EvelynJefferson','E6', 1),('EvelynJefferson','E1', 1),('EvelynJefferson','E3', 1),('EvelynJefferson','E2', 1),('RuthDeSand','E5', 1),('RuthDeSand','E7', 1),('RuthDeSand','E9', 1),('RuthDeSand','E8', 1),('HelenLloyd','E11', 1),('HelenLloyd','E7', 1),('HelenLloyd','E8', 1),('OliviaCarleton','E11', 1),('OliviaCarleton','E9', 1),('EleanorNye','E5', 1),('EleanorNye','E7', 1),('EleanorNye','E6', 1),('EleanorNye','E8', 1),('E9','TheresaAnderson', 1),('E9','PearlOglethorpe', 1),('E9','KatherinaRogers', 1),('E9','SylviaAvondale', 1),('E9','MyraLiddel', 1),('E8','TheresaAnderson', 1),('E8','PearlOglethorpe', 1),('E8','KatherinaRogers', 1),('E8','SylviaAvondale', 1),('E8','BrendaRogers', 1),('E8','LauraMandeville', 1),('E8','MyraLiddel', 1),('E5','TheresaAnderson', 1),('E5','BrendaRogers', 1),('E5','LauraMandeville', 1),('E5','CharlotteMcDowd', 1),('E4','CharlotteMcDowd', 1),('E4','TheresaAnderson', 1),('E4','BrendaRogers', 1),('E7','TheresaAnderson', 1),('E7','SylviaAvondale', 1),('E7','BrendaRogers', 1),('E7','LauraMandeville', 1),('E7','CharlotteMcDowd', 1),('E6','TheresaAnderson', 1),('E6','PearlOglethorpe', 1),('E6','BrendaRogers', 1),('E6','LauraMandeville', 1),('E1','LauraMandeville', 1),('E1','BrendaRogers', 1),('E3','TheresaAnderson', 1),('E3','BrendaRogers', 1),('E3','LauraMandeville', 1),('E3','CharlotteMcDowd', 1),('E3','flag{', 1),('E2','LauraMandeville', 1),('E2','TheresaAnderson', 1),('KatherinaRogers','E13', 1),('E13','SylviaAvondale', 1)]
    for i in node_list:
        for j in range(2):
            if i[j] in node:
                continue
            else:
                node.append(i[j])
    node_map = [[0 for val in xrange(len(node))] for val in xrange(len(node))]
    set_node_map(node_map, node, node_list)
    # A -->; D
    from_node = node.index('flag{')
    to_node = node.index('75D}')
    dijkstrapath = DijkstraPath(node_map)
    path = dijkstrapath(from_node, to_node)
    for i in path:
        print(node[i[0]])
    print path

Crypto

Haffman

哈夫曼编码,画一个哈夫曼树,用lg{}这些来确定构造哈夫曼树的规则

1
2
3
4
5
6
a = ['110','00111','000','00101','00100','10','10','110','01','10','110','10','111','110','111','01','01','01','111','01','111','111','000','01','000','110','01','01','10','10','111','10','01','10','111','000','10','00110']
key = {'00100':'{','00101':'g','00110':'}','00111':'l','000':'a','110':'f','111':'0','10':'d','01':'5'}
s = ''
for i in a:
    s+=key[i]
print(s)

评论