2020-虎符网络安全赛道-Re-game

题目地址:

https://github.com/zhaijiahui/CTF_collect/blob/master/2020/2020数字中国创新大赛虎符网络安全赛道/Reverse/game.zip

解题分析:

题目解压是一个txt,内容是下面的python字节码,需要手工还原代码,再逆向算法。
https://www.jianshu.com/p/557cfe36f0f0
https://docs.python.org/zh-cn/3.6/library/dis.html

解题步骤:

# Python 2.7
# Embedded file name: game.py

文件名game.py

   1       0  LOAD_CONST               249
           3  LOAD_CONST               91
           6  LOAD_CONST               149
           9  LOAD_CONST               113
          12  LOAD_CONST               16
          15  LOAD_CONST               91
          18  LOAD_CONST               53
          21  LOAD_CONST               41
          24  BUILD_LIST_8          8
          27  STORE_NAME            0  'arr0'

列表arr0

arr0 = [249,91,149,113,16,91,53,41]
   2      30  LOAD_CONST               43
          33  LOAD_CONST               1
          36  LOAD_CONST               6
          39  LOAD_CONST               69
          42  LOAD_CONST               20
          45  LOAD_CONST               62
          48  LOAD_CONST               6
          51  LOAD_CONST               44
          54  LOAD_CONST               24
          57  LOAD_CONST               113
          60  LOAD_CONST               6
          63  LOAD_CONST               35
          66  LOAD_CONST               0
          69  LOAD_CONST               3
          72  LOAD_CONST               6
          75  LOAD_CONST               44
          78  LOAD_CONST               20
          81  LOAD_CONST               22
          84  LOAD_CONST               127
          87  LOAD_CONST               60
          90  BUILD_LIST_20        20
          93  STORE_NAME            1  'arr1'

列表arr1

arr1 = [43,1,6,69,20,62,6,44,24,113,6,35,0,3,6,44,20,22,127,60]
   3      96  LOAD_CONST               90
          99  LOAD_CONST               100
         102  LOAD_CONST               87
         105  LOAD_CONST               109
         108  LOAD_CONST               86
         111  LOAD_CONST               108
         114  LOAD_CONST               86
         117  LOAD_CONST               105
         120  LOAD_CONST               90
         123  LOAD_CONST               104
         126  LOAD_CONST               88
         129  LOAD_CONST               102
         132  BUILD_LIST_12        12
         135  STORE_NAME            2  'arr2'

列表arr2

arr2 = [90,100,87,109,86,108,86,105,90,104,88,102]
   5     138  LOAD_CODE                <code_object check0>
         141  MAKE_FUNCTION_0       0  None
         144  STORE_NAME            3  'check0'

   8     147  LOAD_CODE                <code_object check1>
         150  MAKE_FUNCTION_0       0  None
         153  STORE_NAME            4  'check1'

  14     156  LOAD_CODE                <code_object check2>
         159  MAKE_FUNCTION_0       0  None
         162  STORE_NAME            5  'check2'

  20     165  LOAD_CODE                <code_object check3>
         168  MAKE_FUNCTION_0       0  None
         171  STORE_NAME            6  'check3'

这里应该是声明了check0~3 函数

  37     174  LOAD_NAME             7  'raw_input'
         177  CALL_FUNCTION_0       0  None
         180  STORE_NAME            8  'flag'

  38     183  LOAD_NAME             3  'check0'
         186  LOAD_NAME             8  'flag'
         189  CALL_FUNCTION_1       1  None
         192  POP_JUMP_IF_FALSE   239  'to 239'
         195  LOAD_NAME             4  'check1'
         198  LOAD_NAME             8  'flag'
         201  CALL_FUNCTION_1       1  None
         204  POP_JUMP_IF_FALSE   239  'to 239'
         207  LOAD_NAME             5  'check2'
         210  LOAD_NAME             8  'flag'
         213  CALL_FUNCTION_1       1  None
         216  POP_JUMP_IF_FALSE   239  'to 239'
         219  LOAD_NAME             6  'check3'
         222  LOAD_NAME             8  'flag'
         225  CALL_FUNCTION_1       1  None
       228_0  COME_FROM           216  '216'
       228_1  COME_FROM           204  '204'
       228_2  COME_FROM           192  '192'
         228  POP_JUMP_IF_FALSE   239  'to 239'

  39     231  LOAD_CONST               'ok'
         234  PRINT_ITEM
         235  PRINT_NEWLINE_CONT
         236  JUMP_FORWARD          5  'to 244'

  41     239  LOAD_CONST               'no'
         242  PRINT_ITEM
         243  PRINT_NEWLINE_CONT
       244_0  COME_FROM           236  '236'
         244  LOAD_CONST               None
         247  RETURN_VALUE

这一块在整个程序的最后面,就是校验flag正不正确的

flag = input()
if check0(flag) & check1(flag) & check2(flag) & check3(flag):
    print('ok')
else:
    print('no')
# check0 line 5 of game.py

   6       0  LOAD_GLOBAL           0  'all'
           3  LOAD_GENEXPR             '<code_object <genexpr>>'
           6  MAKE_FUNCTION_0       0  None
           9  LOAD_FAST             0  's'
          12  GET_ITER
          13  CALL_FUNCTION_1       1  None
          16  CALL_FUNCTION_1       1  None
          19  RETURN_VALUE

这块创建了一个生成器

# check1 line 8 of game.py

   9       0  LOAD_GLOBAL           0  'len'
           3  LOAD_FAST             0  's'
           6  CALL_FUNCTION_1       1  None
           9  LOAD_CONST               100
          12  COMPARE_OP            0  <
          15  POP_JUMP_IF_FALSE    58  'to 58'
          18  LOAD_GLOBAL           0  'len'
          21  LOAD_FAST             0  's'
          24  CALL_FUNCTION_1       1  None
          27  LOAD_GLOBAL           0  'len'
          30  LOAD_FAST             0  's'
          33  CALL_FUNCTION_1       1  None
          36  BINARY_MULTIPLY
          37  LOAD_CONST               777
          40  BINARY_MODULO
          41  LOAD_CONST               233
          44  BINARY_XOR
          45  LOAD_CONST               513
          48  COMPARE_OP            2  ==
        51_0  COME_FROM            15  '15'
          51  POP_JUMP_IF_FALSE    58  'to 58'

  10      54  LOAD_GLOBAL           1  'True'
          57  RETURN_END_IF
        58_0  COME_FROM            51  '51'

  12      58  LOAD_GLOBAL           2  'False'
          61  RETURN_VALUE
          62  LOAD_CONST               None
          65  RETURN_VALUE

BINARY_MULTIPLY 乘法运算:TOS = TOS1 * TOS
BINARY_MODULO 取模运算 TOS = TOS1 % TOS.
BINARY_XOR 异或运算 :TOS = TOS1 ^ TOS.

def check1(s):
    if len(s) < 100 and (((len(s) * len(s)) % 777) ^ 233 == 513):
        return True
    else:
        return False
# 解密脚本
for i in range(100):
    if ((int(i) * int(i)) % 777) ^ 233 == 513:
        print(i) 
    else:
        pass

结果是39,代表flag的长度为39
现在flag的形式
flag{567890123456789012345678901234567}

# check2 line 14 of game.py

  15       0  LOAD_GLOBAL           0  'ord'
           3  LOAD_FAST             0  's'
           6  LOAD_CONST               0
           9  BINARY_SUBSCR
          10  CALL_FUNCTION_1       1  None
          13  LOAD_CONST               128
          16  BINARY_MULTIPLY
          17  LOAD_GLOBAL           0  'ord'
          20  LOAD_FAST             0  's'
          23  LOAD_CONST               1
          26  BINARY_SUBSCR
          27  CALL_FUNCTION_1       1  None
          30  BINARY_ADD
          31  LOAD_CONST               128
          34  BINARY_MULTIPLY
          35  LOAD_GLOBAL           0  'ord'
          38  LOAD_FAST             0  's'
          41  LOAD_CONST               2
          44  BINARY_SUBSCR
          45  CALL_FUNCTION_1       1  None
          48  BINARY_ADD
          49  LOAD_CONST               128
          52  BINARY_MULTIPLY
          53  LOAD_GLOBAL           0  'ord'
          56  LOAD_FAST             0  's'
          59  LOAD_CONST               3
          62  BINARY_SUBSCR
          63  CALL_FUNCTION_1       1  None
          66  BINARY_ADD
          67  LOAD_CONST               128
          70  BINARY_MULTIPLY
          71  LOAD_GLOBAL           0  'ord'
          74  LOAD_FAST             0  's'
          77  LOAD_CONST               4
          80  BINARY_SUBSCR
          81  CALL_FUNCTION_1       1  None
          84  BINARY_ADD
          85  LOAD_CONST               128
          88  BINARY_MULTIPLY
          89  LOAD_GLOBAL           0  'ord'
          92  LOAD_FAST             0  's'
          95  LOAD_CONST               5
          98  BINARY_SUBSCR
          99  CALL_FUNCTION_1       1  None
         102  BINARY_ADD
         103  LOAD_CONST               3533889469877L
         106  COMPARE_OP            2  ==
         109  POP_JUMP_IF_FALSE   138  'to 138'
         112  LOAD_GLOBAL           0  'ord'
         115  LOAD_FAST             0  's'
         118  LOAD_CONST               -1
         121  BINARY_SUBSCR
         122  CALL_FUNCTION_1       1  None
         125  LOAD_CONST               125
         128  COMPARE_OP            2  ==
       131_0  COME_FROM           109  '109'
         131  POP_JUMP_IF_FALSE   138  'to 138'

  16     134  LOAD_GLOBAL           1  'True'
         137  RETURN_END_IF
       138_0  COME_FROM           131  '131'

  18     138  LOAD_GLOBAL           2  'False'
         141  RETURN_VALUE
         142  LOAD_CONST               None
         145  RETURN_VALUE

BINARY_SUBSCR 索引运算: TOS = TOS1[TOS].

def check2(s):
    if (((((ord(s[0]) * 128 + ord(s[1])) * 128 + ord(s[2])) * 128 + ord(s[3])) * 128 + ord(s[4])) * 128 + ord(
            s[5]) == 3533889469877) and (ord(s[-1]) == 125):
        return True
    else:
        return False
# 解密代码

import string

s = 'flag{'
for i in string.digits +string.ascii_letters:
    if ((((ord(s[0]) * 128 + ord(s[1])) *128 + ord(s[2])) * 128 +ord(s[3])) * 128+ord(s[4]))*128+ord(i)==3533889469877:
        print(i)

结果为5 ,说明第五个字符是5,flag{5
flag{567890123456789012345678901234567}

# check3 line 20 of game.py

  21       0  LOAD_GLOBAL           0  'map'
           3  LOAD_GLOBAL           1  'ord'
           6  LOAD_FAST             0  's'
           9  CALL_FUNCTION_2       2  None
          12  STORE_FAST            1  'arr'

  22      15  LOAD_FAST             1  'arr'
          18  LOAD_CONST               6
          21  LOAD_CONST               30
          24  LOAD_CONST               3
          27  BUILD_SLICE_3         3
          30  BINARY_SUBSCR
          31  STORE_FAST            2  'a'

  23      34  SETUP_LOOP           62  'to 99'
          37  LOAD_GLOBAL           2  'range'
          40  LOAD_GLOBAL           3  'len'
          43  LOAD_FAST             2  'a'
          46  CALL_FUNCTION_1       1  None
          49  CALL_FUNCTION_1       1  None
          52  GET_ITER
          53  FOR_ITER             42  'to 98'
          56  STORE_FAST            3  'i'

  24      59  LOAD_FAST             2  'a'
          62  LOAD_FAST             3  'i'
          65  BINARY_SUBSCR
          66  LOAD_CONST               17684
          69  BINARY_MULTIPLY
          70  LOAD_CONST               372511
          73  BINARY_ADD
          74  LOAD_CONST               257
          77  BINARY_MODULO
          78  LOAD_GLOBAL           4  'arr0'
          81  LOAD_FAST             3  'i'
          84  BINARY_SUBSCR
          85  COMPARE_OP            3  !=
          88  POP_JUMP_IF_FALSE    53  'to 53'

  25      91  LOAD_GLOBAL           5  'False'
          94  RETURN_END_IF
        95_0  COME_FROM            88  '88'
          95  JUMP_BACK            53  'to 53'
          98  POP_BLOCK
        99_0  COME_FROM            34  '34'
    arr = map(ord, s)
    a = arr[6:30:3]
    for i in range(len(a)):
        if (a[i] * 17684 + 372511) % 257 != arr0[i]:
            return False
# 解密代码
arr0 = [249,91,149,113,16,91,53,41]

for i in arr0:
    for j in range(1,1000):
        if (j * 17684 + 372511) % 257 == i:
            if j > 0 and j <= 256:
                print(str(i)+'  '+chr(j))

得到s[6],s[9],s[12],s[15],s[18],s[21],s[24],s[27] = L5xiV5PK

flag{5L78501x34i67V90523P56K8901234567}

  26      99  LOAD_FAST             1  'arr'
         102  LOAD_CONST               -2
         105  LOAD_CONST               33
         108  LOAD_CONST               -1
         111  BUILD_SLICE_3         3
         114  BINARY_SUBSCR
         115  LOAD_CONST               5
         118  BINARY_MULTIPLY
         119  STORE_FAST            4  'b'

  27     122  LOAD_GLOBAL           0  'map'
         125  LOAD_LAMBDA              '<code_object <lambda>>'
         128  MAKE_FUNCTION_0       0  None
         131  LOAD_GLOBAL           6  'zip'
         134  LOAD_FAST             4  'b'
         137  LOAD_FAST             1  'arr'
         140  LOAD_CONST               7
         143  LOAD_CONST               27
         146  SLICE+3
         147  CALL_FUNCTION_2       2  None
         150  CALL_FUNCTION_2       2  None
         153  STORE_FAST            5  'c'

  28     156  LOAD_FAST             5  'c'
         159  LOAD_GLOBAL           7  'arr1'
         162  COMPARE_OP            3  !=
         165  POP_JUMP_IF_FALSE   172  'to 172'

  29     168  LOAD_GLOBAL           5  'False'
         171  RETURN_END_IF
       172_0  COME_FROM           165  '165'
    b = arr[-2:33:-1] * 5
    c = map(lambda b: b[0] ^ b[1], zip(b, arr[7:27]))
    if c != arr1:
        return False

这一段是最难理解的了,arr[-2:33:-1]取出[37, 36, 35, 34] 乘5 也就是取5遍,关键这几个值还是未知的。
zip函数 b是20个元素,arr[7:27]取了20个元素打包异或,结果应该是和arr1 相同。
这块要利用前面得到的已经值,反推出[37, 36, 35, 34]
s[9],s[12],s[15],s[18],s[21],s[24],s[27] = 5xiV5PK
[37] ^ [15] = arr1[8] [37] ^ i = 24 [37] =q
[36] ^ [12] = arr1[5] [36] ^ x = 62 [36] =F
[35] ^ [9] = arr1[2] [39] ^ 5 = 6 [] [39]=3
[34] ^ [18] = arr1[11] [34] ^ V = 35 [34]=u
因为要反推的值较少可以手工推出,再根据堆出的值计算7-27的全部值

#解题脚本
arr1 = [43, 1, 6, 69, 20, 62, 6, 44, 24, 113, 6, 35, 0, 3, 6, 44, 20, 22, 127, 60]

s = chr(ord('i')^arr1[15-7]) + chr(ord('x')^arr1[12-7]) + chr(ord('5')^arr1[9-7]) + chr(ord('V')^arr1[18-7])
print (s)
model = [ord(x) for x in s]
flag = ''.join([chr(model[x%4]^arr1[x]) for x in range(len(arr1))])
print (flag)
#qF3u
#ZG50ex5Yi75VqE5YePLI

这时候拼接的flag是这样的还差中间28-34这段
flag{5LZG50ex5Yi75VqE5YePLIK890123u3Fq}

  30     172  LOAD_CONST               0
         175  STORE_FAST            6  'p'

  31     178  SETUP_LOOP          105  'to 286'
         181  LOAD_GLOBAL           2  'range'
         184  LOAD_CONST               28
         187  LOAD_CONST               34
         190  CALL_FUNCTION_2       2  None
         193  GET_ITER
         194  FOR_ITER             88  'to 285'
         197  STORE_FAST            3  'i'

  32     200  LOAD_FAST             1  'arr'
         203  LOAD_FAST             3  'i'
         206  BINARY_SUBSCR
         207  LOAD_CONST               107
         210  BINARY_ADD
         211  LOAD_CONST               16
         214  BINARY_DIVIDE
         215  LOAD_CONST               77
         218  BINARY_ADD
         219  LOAD_GLOBAL           8  'arr2'
         222  LOAD_FAST             6  'p'
         225  BINARY_SUBSCR
         226  COMPARE_OP            3  !=
         229  POP_JUMP_IF_TRUE    268  'to 268'
         232  LOAD_FAST             1  'arr'
         235  LOAD_FAST             3  'i'
         238  BINARY_SUBSCR
         239  LOAD_CONST               117
         242  BINARY_ADD
         243  LOAD_CONST               16
         246  BINARY_MODULO
         247  LOAD_CONST               99
         250  BINARY_ADD
         251  LOAD_GLOBAL           8  'arr2'
         254  LOAD_FAST             6  'p'
         257  LOAD_CONST               1
         260  BINARY_ADD
         261  BINARY_SUBSCR
         262  COMPARE_OP            3  !=
       265_0  COME_FROM           229  '229'
         265  POP_JUMP_IF_FALSE   272  'to 272'

  33     268  LOAD_GLOBAL           9  'false'
         271  RETURN_END_IF
       272_0  COME_FROM           265  '265'

  34     272  LOAD_FAST             6  'p'
         275  LOAD_CONST               2
         278  INPLACE_ADD
         279  STORE_FAST            6  'p'
         282  JUMP_BACK           194  'to 194'
         285  POP_BLOCK
       286_0  COME_FROM           178  '178'

  35     286  LOAD_GLOBAL          10  'True'
         289  RETURN_VALUE
    p = 0
    for i in range(28, 34):
        if (((arr[i] + 107) // 16 + 77) != arr2[p]) or ((arr[i] + 117) % 16 + 99) != arr2[p + 1]:
            return False
        p = p + 2


arr2 = [90, 100, 87, 109, 86, 108, 86, 105, 90, 104, 88, 102]

for i in range(0, len(arr2), 2):
    for ch in range(256):
        if int((ch + 107) // 16) + 77 == arr2[i] and ((ch + 117) % 16) + 99 == arr2[i + 1]:
            print (chr(ch),end="")

这就是个等式判断,直接爆破反解就行,得到:l541pN
在拼接到前面合成最后的flag
flag{5LZG50ex5Yi75VqE5YePLIKl541pNu3Fq}

# <genexpr> line 6 of game.py

   6       0  LOAD_FAST             0  '.0'
           3  FOR_ITER             32  'to 38'
           6  STORE_FAST            1  'x'
           9  LOAD_GLOBAL           0  'ord'
          12  LOAD_FAST             1  'x'
          15  CALL_FUNCTION_1       1  None
          18  LOAD_GLOBAL           1  'range'
          21  LOAD_CONST               32
          24  LOAD_CONST               128
          27  CALL_FUNCTION_2       2  None
          30  COMPARE_OP            6  in
          33  YIELD_VALUE
          34  POP_TOP
          35  JUMP_BACK             3  'to 3'
          38  LOAD_CONST               None
          41  RETURN_VALUE

# <lambda> line 27 of game.py

  27       0  LOAD_FAST             0  'x'
           3  LOAD_CONST               0
           6  BINARY_SUBSCR
           7  LOAD_FAST             0  'x'
          10  LOAD_CONST               1
          13  BINARY_SUBSCR
          14  BINARY_XOR
          15  RETURN_VALUE

参考链接:

大佬博客相当厉害和详细
https://www.cnblogs.com/Mayfly-nymph/p/12764537.html

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335