[长安“战疫”网络安全卫士守护赛]lemon
[RE] lemon
flag{23075096395}
-
字节码分析
依赖于下发的文件,可以从其中的标志指令jz
看出这是Python的字节码。字节码的读取和汇编类似,这里是后缀表达式类型,即操作数在前,操作符在后。因此可以简单的将这些汇编代码进行缩进。此处使用操作数比操作符缩进一位的形式使得整个代码更加直观。另外其中包含一些关键操作语句,这里进行一点解释:
- 所有
load
之后数据将会被压入栈顶,因此先压入的变量会成为函数调用时后面的参数。也就是此处的函数调用约定一律为stdcall
- 没有
store
或者setitem
方法出现时,原来的变量值不会变更 getattr
和getitem
,setitem
是魔法方法,作为保留字出现call x
代表调用函数,调用函数的对象为栈底元素,也就是最先入栈的元素。x
代表了调用时需要压入的参数个数
下面是已经做了一定的缩进的代码
0: const 60 ; <module 'main'> 5: module 9 592 11: const 26 ; 83 16: const 27 ; 69 21: const 28 ; 65 26: array 3 31: store 0 0 34: const 30 ; 101 39: const 31 ; 108 44: const 32 ; 111 49: const 33 ; 117 54: const 34 ; 122 59: const 30 ; 101 64: const 35 ; 105 69: const 36 ; 98 74: const 30 ; 101 79: const 31 ; 108 84: const 33 ; 117 89: const 35 ; 105 94: const 37 ; 113 99: const 33 ; 117 104: const 35 ; 105 109: const 37 ; 113 114: array 16 119: store 0 1 122: const 39 ; 0 127: store 0 2 130: array 0 135: store 0 3 138: load 0 2 141: const 42 ; 256 146: lt 147: jz 184 152: load 0 3 155: const 43 ; append 160: getattr 161: load 0 2 164: call 1 166: pop 167: load 0 2 170: const 44 ; 1 175: add 176: store 0 2 179: jmp 138 184: const 39 ; 0 189: store 0 4 192: load 0 4 195: const 42 ; 256 200: lt 201: jz 271 206: load 0 3 209: load 0 4 212: getitem 213: load 0 0 216: load 0 4 219: const 46 ; 3 224: mod 225: getitem 226: add 227: load 0 1 230: load 0 4 233: const 47 ; 16 238: mod 239: getitem 240: add 241: const 42 ; 256 246: mod 247: load 0 3 250: load 0 4 253: setitem 254: load 0 4 257: const 44 ; 1 262: add 263: store 0 4 266: jmp 192 271: const 39 ; 0 276: store 0 5 279: load 0 5 282: const 46 ; 3 287: lt 288: jz 448 293: const 39 ; 0 298: store 0 6 301: load 0 6 304: const 42 ; 256 309: lt 310: jz 366 315: load 0 3 318: load 0 6 321: getitem 322: load 0 3 325: load 0 6 328: const 44 ; 1 333: add 334: const 42 ; 256 339: mod 340: getitem 341: bxor 342: load 0 3 345: load 0 6 348: setitem 349: load 0 6 352: const 44 ; 1 357: add 358: store 0 6 361: jmp 301 366: const 39 ; 0 371: store 0 7 374: load 0 7 377: const 42 ; 256 382: lt 383: jz 431 388: load 0 3 391: load 0 7 394: getitem 395: const 44 ; 1 400: add 401: const 42 ; 256 406: mod 407: load 0 3 410: load 0 7 413: setitem 414: load 0 7 417: const 44 ; 1 422: add 423: store 0 7 426: jmp 374 431: load 0 5 434: const 44 ; 1 439: add 440: store 0 5 443: jmp 279 448: const 39 ; 0 453: store 0 5 456: const 39 ; 0 461: store 0 8 464: load 0 5 467: const 42 ; 256 472: lt 473: jz 509 478: load 0 8 481: load 0 3 484: load 0 5 487: getitem 488: add 489: store 0 8 492: load 0 5 495: const 44 ; 1 500: add 501: store 0 5 504: jmp 464 509: load 0 8 512: const 51 ; 20 517: mul 518: const 52 ; 5 523: add 524: store 0 8 527: load 0 8 530: const 54 ; 30 535: mul 536: const 52 ; 5 541: sub 542: store 0 8 545: load 0 8 548: const 56 ; 40 553: mul 554: const 52 ; 5 559: sub 560: store 0 8 563: load 0 8 566: const 58 ; 50 571: mul 572: const 59 ; 6645 577: add 578: store 0 8 581: const 23 ; <function 'print'> 586: load 0 8 589: call 1 591: pop
- 所有
-
后缀表达式转为中缀表达式
再上面的代码中已经很明显,调用函数都在最前面,他们都按照后缀表达式的形式写在了汇编代码上。下面要做的就是对应的还原代码。此处只需要按照操作数-操作符的方法进行依次编写,加上一些基本的修正就可以得到下述Python代码
var_00 = 'AES' var_01 = 'qiuqiulebiezuole' var_02 = 0 var_03 = [] while(256 > var_02): var_03.append(var_02) var_02 = var_02 + 1 var_04 = 0 while(256 > var_04): var_03[var_04] = (var_03[var_04] + ord(var_00[var_04 % 3]) + ord(var_01[var_04 % 16]) )% 256 var_04= var_04 +1 var_05 = 0 while(3 > var_05): var_06 = 0 while(256 > var_06): var_03[var_06] ^= var_03[(var_06 + 1) % 256] var_06 += 1 var_07 = 0 while(256 > var_07): var_03[var_07] = (var_03[var_07] + 1) % 256 var_07 += 1 var_05 +=1 var_05 = 0 var_08 = 0 while (256 > var_05): var_08 += var_03[var_05] var_05 +=1 var_08 *= 20 var_08 +=5 var_08 *=30 var_08 -=5 var_08 *=40 var_08 -= 5 var_08 *=50 var_08 += 6645 print(var_08)
要注意的一点是前面定义的两个数组是小端声明法,因此要进行反向。
-
运行此代码即可获得
output
,也就是flag
作者发布、转载的任何文章中所涉及的技术、思路、工具仅供以安全目的的学习交流,并严格遵守《中华人民共和国网络安全法》、《中华人民共和国数据安全法》等网络安全法律法规。
任何人不得将技术用于非法用途、盈利用途。否则作者不对未许可的用途承担任何后果。
本文遵守CC BY-NC-SA 3.0协议,您可以在任何媒介以任何形式复制、发行本作品,或者修改、转换或以本作品为基础进行创作
您必须给出适当的署名,提供指向本文的链接,同时标明是否(对原文)作了修改。您可以用任何合理的方式来署名,但是不得以任何方式暗示作者为您或您的使用背书。
同时,本文不得用于商业目的。混合、转换、基于本作品进行创作,必须基于同一协议(CC BY-NC-SA 3.0)分发。
如有问题, 可发送邮件咨询.