前言
本文主要是介绍如何根据Bytecode手撸得到py源码,这是一种ctf常见题目。关于Bytecode的实现过程,和虚拟机之间的关系可以自行深入学习(我在写的时候查阅资料发现本站上面大部分文章都是将这一部分的,所以就不过多赘述啦(其实是我也不太会hhh))可能也是手撸其实比较基础吧,新手看看就好( ˝ᗢ̈˝ )
简介
字节码(Bytecode):通常指的是已经经过编译,但与特定机器代码无关,需要解释器转译后才能成为机器代码的中间代码。字节码通常不像源码一样可以让人阅读,而是编码后的数值常量、引用、指令(也称操作码,Operation Code)等构成的序列。
拿 Python 说明,Python 解释器先翻译 Python 源代码( .py 文件)为 Python 字节码( .pyc 文件),然后再由 Python 虚拟机来执行 Python 字节码。Python 字节码是一种类似于汇编指令的中间语言,一条 Python 语句会对应若干条字节码指令,虚拟机一条条执行字节码指令,将其翻译成机器代码,并交个 CPU 执行,从而完成程序的执行。
dis模块--python反汇编神器
dis模块是 Python 的标准库之一,用于反汇编 Python 字节码。它允许你查看 Python 函数或模块的字节码指令,这对于理解 Python 代码的底层运行方式和性能优化非常有帮助。
可以使用 dis
模块来查看函数、方法或模块中的字节码指令。以下是一个基本示例:
import dis
def example_function(x, y):
result = x + y
return result
dis.dis(example_function)
输出:
在这个示例中,我们导入 dis
模块,定义了一个名为 example_function
的函数,然后使用 dis.dis()
函数来查看该函数的字节码指令。
dis.dis()
输出的结果将显示函数中的每个字节码指令以及相关的信息,如字节码的偏移量、操作码、操作数等。
dis还有更多的用法,可以参考:
变量
比较常见的几种类型
LOAD_CONST
: 用于加载常量。STORE_FAST
: 用于将值存储到本地变量
import dis
def example_function(x, y):
x = 42 # x是整数
x = "Hello, World!" # x是字符串
n = n / p
dis.dis(example_function)
3.LOAD_FAST
一般加载局部变量的值,也就是读取值,用于计算或者函数调用传参等。
4.LOAD_GLOBAL
用来加载全局变量,包括指定函数名,类名,模块名等全局符号。
5.STORE_GLOBAL
用来给全局变量赋值。
import dis
def text():
global global1
global1 = 101
print(global1)
dis.dis(text)
常用数据类型
1.list
在 Python 字节码中,列表(List)是一种常见的数据结构,用于存储有序的数据元素。
BUILD_LIST
: 这个字节码操作用于构建一个列表对象。它接受一个整数参数,表示要构建的列表中元素的数量。后面的操作码会将元素依次添加到列表中。
LIST_APPEND
: 当要向列表添加元素时,这个字节码操作会从堆栈中弹出一个值,并将其添加到列表中。这通常与循环结构一起使用,以将多个值添加到列表。
BINARY_SUBSCR
: 当你需要获取列表中特定索引的元素时,这个操作码会获取列表和索引值,然后返回列表中对应索引的元素
示例代码:
import dis
def example_function(x, y):
my_list = [1, 2, 3, 4]
my_list.append(5)
element = my_list[2]
dis.dis(example_function)
输出:
在上述示例中,BUILD_LIST
指令用于构建列表,LOAD_FAST
用于加载变量 my_list
,LIST_APPEND
用于将元素添加到列表中,BINARY_SUBSCR
用于获取列表中的元素
2.dict
字典(Dictionary)是一种常见的数据结构,用于存储键-值对。
BUILD_MAP
用于创建一个空的dict。STORE_MAP
用于初始化dict的内容。
示例:
import dis
def example_function(x, y):
my_dict = {"name": "Alice", "age": 30, "city": "New York"}
my_dict["occupation"] = "Engineer"
occupation = my_dict["occupation"]
dis.dis(example_function)
输出:
3.slice
切片(Slice)是一种用于访问可迭代对象(如列表、字符串、元组等)的子集的方法。切片操作不会创建新的列表或字符串,而是返回原始对象的一个子集。
BUILD_SLICE
用于创建slice。对于list、元组、字符串都可以使用slice的方式进行访问
SLICE+0
,SLICE+1
,SLICE+2
,SLICE+3
: 这些字节码操作用于执行不同类型的切片操作。例如,
SLICE+2
用于执行a[start:stop]
形式的切片,其中start
和stop
由堆栈上的值提供。SLICE+1
用于执行a[start:]
形式的切片,其中start
由堆栈上的值提供。SLICE+0
用于执行a[:]
形式的切片,返回原始对象的一个拷贝。
STORE_SLICE+0
,STORE_SLICE+1
,STORE_SLICE+2
,STORE_SLICE+3
: 这些字节码操作用于将切片的结果存储回原始对象。例如,
STORE_SLICE+2
用于执行a[start:stop] = b
形式的切片赋值,其中start
和stop
由堆栈上的值提供,而b
是要赋值的对象。
DELETE_SLICE+0
,DELETE_SLICE+1
,DELETE_SLICE+2
,DELETE_SLICE+3
: 这些字节码操作用于删除切片的元素。例如,
DELETE_SLICE+1
用于执行del a[start:]
形式的切片删除,其中start
由堆栈上的值提供。
这里应该不太好理解。最好还是自己多写写,用dis反汇编看看观察一下特征。
代码示例:
import dis
def example_function(x, y):
my_list = [1, 2, 3, 4, 5]
sub_list = my_list[1:4]
my_list[2:4] = [6, 7]
del my_list[1:3]
dis.dis(example_function)
输出:
循环
SETUP_LOOP
用于开始一个循环。SETUP_LOOP 26 (to 35)
中35
表示循环退出点。
1.while
先看一下例子再分析:
示例程序:
import dis
def example_function(x, y):
total = 0
count = 1
while count <= 5:
total += count
count += 1
dis.dis(example_function)
输出:
在上述示例中,SETUP_LOOP
用于设置循环块,POP_JUMP_IF_FALSE
用于在条件不满足时跳出循环。循环体中的操作用于计算变量 total
的值,并在每次迭代中递增 count
,直到 count
不再小于等于5为止。
so.
SETUP_LOOP
用于开始一个循环。SETUP_LOOP 26 (to 35)
中35
表示循环退出点
POP_BLOCK
: 用于弹出循环块的指令,通常在循环的末尾使用。
BREAK_LOOP
: 用于中断当前循环的执行。
CONTINUE_LOOP
: 用于跳回循环开始的指令,以实现循循环的迭代。
POP_JUMP_IF_FALSE
: 用于在条件不满足时跳转到指定位置
COMPARE_OP
: 用于执行比较操作,例如,检查是否满足循环条件。
2. for in
FOR_ITER
: 这个字节码操作用于迭代可迭代对象(如列表、元组等)的元素。它通常与FOR_LOOP
指令一起使用,用于执行for
循环。
FOR_LOOP
: 这个字节码操作用于定义一个for
循环的循环体。它接受一个循环控制变量,该变量用于迭代可迭代对象中的元素。
示例:
import dis
def example_function(x, y):
my_list = [1, 2, 3, 4, 5]
total = 0
for item in my_list:
total += item
dis.dis(example_function)
反汇编结果:
if判断
POP_JUMP_IF_FALSE
和JUMP_FORWARD
一般用于分支判断跳转。
POP_JUMP_IF_FALSE
表示条件结果为FALSE
就跳转到目标偏移指令。
JUMP_FORWARD
直接跳转到目标偏移指令。
示例:
import dis
def example_function(x, y):
x = 10
if x < 5:
result = "x is less than 5"
else:
result = "x is not less than 5"
dis.dis(example_function)
反汇编结果:
COMPARE_OP
用于比较 x
和 5
,POP_JUMP_IF_FALSE
用于根据条件跳转到不同的代码块。条件语句根据 x
的值设置变量 result
的不同值。
其他指令
可以详见官方文档。
实战手撸反编译过程
[羊城杯2022]Bytecode
4 0 LOAD_CONST 0 (3)
3 LOAD_CONST 1 (37)
6 LOAD_CONST 2 (72)
9 LOAD_CONST 3 (9)
12 LOAD_CONST 4 (6)
15 LOAD_CONST 5 (132)
18 BUILD_LIST 6
21 STORE_NAME 0 (en)
5 24 LOAD_CONST 6 (101)
27 LOAD_CONST 7 (96)
30 LOAD_CONST 8 (23)
33 LOAD_CONST 9 (68)
36 LOAD_CONST 10 (112)
39 LOAD_CONST 11 (42)
42 LOAD_CONST 12 (107)
45 LOAD_CONST 13 (62)
48 LOAD_CONST 7 (96)
51 LOAD_CONST 14 (53)
54 LOAD_CONST 15 (176)
57 LOAD_CONST 16 (179)
60 LOAD_CONST 17 (98)
63 LOAD_CONST 14 (53)
66 LOAD_CONST 18 (67)
69 LOAD_CONST 19 (29)
72 LOAD_CONST 20 (41)
75 LOAD_CONST 21 (120)
78 LOAD_CONST 22 (60)
81 LOAD_CONST 23 (106)
84 LOAD_CONST 24 (51)
87 LOAD_CONST 6 (101)
90 LOAD_CONST 25 (178)
93 LOAD_CONST 26 (189)
96 LOAD_CONST 6 (101)
99 LOAD_CONST 27 (48)
102 BUILD_LIST 26
105 STORE_NAME 1 (output)
7 108 LOAD_CONST 28 ('welcome to GWHT2020')
111 PRINT_ITEM
112 PRINT_NEWLINE
9 113 LOAD_NAME 2 (raw_input)
116 LOAD_CONST 29 ('please input your flag:')
119 CALL_FUNCTION 1
122 STORE_NAME 3 (flag)
10 125 LOAD_NAME 3 (flag)
128 STORE_NAME 4 (str)
12 131 LOAD_NAME 5 (len)
134 LOAD_NAME 4 (str)
137 CALL_FUNCTION 1
140 STORE_NAME 6 (a)
13 143 LOAD_NAME 6 (a)
146 LOAD_CONST 30 (38)
149 COMPARE_OP 0 (<)
152 POP_JUMP_IF_FALSE 173
14 155 LOAD_CONST 31 ('lenth wrong!')
158 PRINT_ITEM
159 PRINT_NEWLINE
15 160 LOAD_NAME 7 (exit)
163 LOAD_CONST 32 (0)
166 CALL_FUNCTION 1
169 POP_TOP
170 JUMP_FORWARD 0 (to 173)
17 >> 173 LOAD_NAME 8 (ord)
176 LOAD_NAME 4 (str)
179 LOAD_CONST 32 (0)
182 BINARY_SUBSCR
183 CALL_FUNCTION 1
186 LOAD_CONST 33 (2020)
189 BINARY_MULTIPLY
190 LOAD_NAME 8 (ord)
193 LOAD_NAME 4 (str)
196 LOAD_CONST 34 (1)
199 BINARY_SUBSCR
200 CALL_FUNCTION 1
203 BINARY_ADD
204 LOAD_CONST 33 (2020)
207 BINARY_MULTIPLY
208 LOAD_NAME 8 (ord)
211 LOAD_NAME 4 (str)
214 LOAD_CONST 35 (2)
217 BINARY_SUBSCR
218 CALL_FUNCTION 1
221 BINARY_ADD
222 LOAD_CONST 33 (2020)
225 BINARY_MULTIPLY
226 LOAD_NAME 8 (ord)
229 LOAD_NAME 4 (str)
232 LOAD_CONST 0 (3)
235 BINARY_SUBSCR
236 CALL_FUNCTION 1
239 BINARY_ADD
240 LOAD_CONST 33 (2020)
243 BINARY_MULTIPLY
244 LOAD_NAME 8 (ord)
247 LOAD_NAME 4 (str)
250 LOAD_CONST 36 (4)
253 BINARY_SUBSCR
254 CALL_FUNCTION 1
257 BINARY_ADD
258 LOAD_CONST 37 (1182843538814603)
261 COMPARE_OP 2 (==)
264 POP_JUMP_IF_FALSE 275
18 267 LOAD_CONST 38 ('good!continue\xe2\x80\xa6\xe2\x80\xa6')
270 PRINT_ITEM
271 PRINT_NEWLINE
272 JUMP_FORWARD 15 (to 290)
20 >> 275 LOAD_CONST 39 ('bye~')
278 PRINT_ITEM
279 PRINT_NEWLINE
21 280 LOAD_NAME 7 (exit)
283 LOAD_CONST 32 (0)
286 CALL_FUNCTION 1
289 POP_TOP
23 >> 290 BUILD_LIST 0
293 STORE_NAME 9 (x)
24 296 LOAD_CONST 40 (5)
299 STORE_NAME 10 (k)
25 302 SETUP_LOOP 128 (to 433)
305 LOAD_NAME 11 (range)
308 LOAD_CONST 41 (13)
311 CALL_FUNCTION 1
314 GET_ITER
>> 315 FOR_ITER 114 (to 432)
318 STORE_NAME 12 (i)
26 321 LOAD_NAME 8 (ord)
324 LOAD_NAME 4 (str)
327 LOAD_NAME 10 (k)
330 BINARY_SUBSCR
331 CALL_FUNCTION 1
334 STORE_NAME 13 (b)
27 337 LOAD_NAME 8 (ord)
340 LOAD_NAME 4 (str)
343 LOAD_NAME 10 (k)
346 LOAD_CONST 34 (1)
349 BINARY_ADD
350 BINARY_SUBSCR
351 CALL_FUNCTION 1
354 STORE_NAME 14 (c)
28 357 LOAD_NAME 14 (c)
360 LOAD_NAME 0 (en)
363 LOAD_NAME 12 (i)
366 LOAD_CONST 4 (6)
369 BINARY_MODULO
370 BINARY_SUBSCR
371 BINARY_XOR
372 STORE_NAME 15 (a11)
29 375 LOAD_NAME 13 (b)
378 LOAD_NAME 0 (en)
381 LOAD_NAME 12 (i)
384 LOAD_CONST 4 (6)
387 BINARY_MODULO
388 BINARY_SUBSCR
389 BINARY_XOR
390 STORE_NAME 16 (a22)
30 393 LOAD_NAME 9 (x)
396 LOAD_ATTR 17 (append)
399 LOAD_NAME 15 (a11)
402 CALL_FUNCTION 1
405 POP_TOP
31 406 LOAD_NAME 9 (x)
409 LOAD_ATTR 17 (append)
412 LOAD_NAME 16 (a22)
415 CALL_FUNCTION 1
418 POP_TOP
32 419 LOAD_NAME 10 (k)
422 LOAD_CONST 35 (2)
425 INPLACE_ADD
426 STORE_NAME 10 (k)
429 JUMP_ABSOLUTE 315
>> 432 POP_BLOCK
33 >> 433 LOAD_NAME 9 (x)
436 LOAD_NAME 1 (output)
439 COMPARE_OP 2 (==)
442 POP_JUMP_IF_FALSE 453
34 445 LOAD_CONST 38 ('good!continue\xe2\x80\xa6\xe2\x80\xa6')
448 PRINT_ITEM
449 PRINT_NEWLINE
450 JUMP_FORWARD 15 (to 468)
36 >> 453 LOAD_CONST 42 ('oh,you are wrong!')
456 PRINT_ITEM
457 PRINT_NEWLINE
37 458 LOAD_NAME 7 (exit)
461 LOAD_CONST 32 (0)
464 CALL_FUNCTION 1
467 POP_TOP
39 >> 468 LOAD_NAME 5 (len)
471 LOAD_NAME 4 (str)
474 CALL_FUNCTION 1
477 STORE_NAME 18 (l)
40 480 LOAD_NAME 8 (ord)
483 LOAD_NAME 4 (str)
486 LOAD_NAME 18 (l)
489 LOAD_CONST 43 (7)
492 BINARY_SUBTRACT
493 BINARY_SUBSCR
494 CALL_FUNCTION 1
497 STORE_NAME 19 (a1)
41 500 LOAD_NAME 8 (ord)
503 LOAD_NAME 4 (str)
506 LOAD_NAME 18 (l)
509 LOAD_CONST 4 (6)
512 BINARY_SUBTRACT
513 BINARY_SUBSCR
514 CALL_FUNCTION 1
517 STORE_NAME 20 (a2)
42 520 LOAD_NAME 8 (ord)
523 LOAD_NAME 4 (str)
526 LOAD_NAME 18 (l)
529 LOAD_CONST 40 (5)
532 BINARY_SUBTRACT
533 BINARY_SUBSCR
534 CALL_FUNCTION 1
537 STORE_NAME 21 (a3)
43 540 LOAD_NAME 8 (ord)
543 LOAD_NAME 4 (str)
546 LOAD_NAME 18 (l)
549 LOAD_CONST 36 (4)
552 BINARY_SUBTRACT
553 BINARY_SUBSCR
554 CALL_FUNCTION 1
557 STORE_NAME 22 (a4)
44 560 LOAD_NAME 8 (ord)
563 LOAD_NAME 4 (str)
566 LOAD_NAME 18 (l)
569 LOAD_CONST 0 (3)
572 BINARY_SUBTRACT
573 BINARY_SUBSCR
574 CALL_FUNCTION 1
577 STORE_NAME 23 (a5)
45 580 LOAD_NAME 8 (ord)
583 LOAD_NAME 4 (str)
586 LOAD_NAME 18 (l)
589 LOAD_CONST 35 (2)
592 BINARY_SUBTRACT
593 BINARY_SUBSCR
594 CALL_FUNCTION 1
597 STORE_NAME 24 (a6)
46 600 LOAD_NAME 19 (a1)
603 LOAD_CONST 0 (3)
606 BINARY_MULTIPLY
607 LOAD_NAME 20 (a2)
610 LOAD_CONST 35 (2)
613 BINARY_MULTIPLY
614 BINARY_ADD
615 LOAD_NAME 21 (a3)
618 LOAD_CONST 40 (5)
621 BINARY_MULTIPLY
622 BINARY_ADD
623 LOAD_CONST 44 (1003)
626 COMPARE_OP 2 (==)
629 POP_JUMP_IF_FALSE 807
47 632 LOAD_NAME 19 (a1)
635 LOAD_CONST 36 (4)
638 BINARY_MULTIPLY
639 LOAD_NAME 20 (a2)
642 LOAD_CONST 43 (7)
645 BINARY_MULTIPLY
646 BINARY_ADD
647 LOAD_NAME 21 (a3)
650 LOAD_CONST 3 (9)
653 BINARY_MULTIPLY
654 BINARY_ADD
655 LOAD_CONST 45 (2013)
658 COMPARE_OP 2 (==)
661 POP_JUMP_IF_FALSE 807
48 664 LOAD_NAME 19 (a1)
667 LOAD_NAME 20 (a2)
670 LOAD_CONST 46 (8)
673 BINARY_MULTIPLY
674 BINARY_ADD
675 LOAD_NAME 21 (a3)
678 LOAD_CONST 35 (2)
681 BINARY_MULTIPLY
682 BINARY_ADD
683 LOAD_CONST 47 (1109)
686 COMPARE_OP 2 (==)
689 POP_JUMP_IF_FALSE 804
49 692 LOAD_NAME 22 (a4)
695 LOAD_CONST 0 (3)
698 BINARY_MULTIPLY
699 LOAD_NAME 23 (a5)
702 LOAD_CONST 35 (2)
705 BINARY_MULTIPLY
706 BINARY_ADD
707 LOAD_NAME 24 (a6)
710 LOAD_CONST 40 (5)
713 BINARY_MULTIPLY
714 BINARY_ADD
715 LOAD_CONST 48 (671)
718 COMPARE_OP 2 (==)
721 POP_JUMP_IF_FALSE 801
50 724 LOAD_NAME 22 (a4)
727 LOAD_CONST 36 (4)
730 BINARY_MULTIPLY
731 LOAD_NAME 23 (a5)
734 LOAD_CONST 43 (7)
737 BINARY_MULTIPLY
738 BINARY_ADD
739 LOAD_NAME 24 (a6)
742 LOAD_CONST 3 (9)
745 BINARY_MULTIPLY
746 BINARY_ADD
747 LOAD_CONST 49 (1252)
750 COMPARE_OP 2 (==)
753 POP_JUMP_IF_FALSE 798
51 756 LOAD_NAME 22 (a4)
759 LOAD_NAME 23 (a5)
762 LOAD_CONST 46 (8)
765 BINARY_MULTIPLY
766 BINARY_ADD
767 LOAD_NAME 24 (a6)
770 LOAD_CONST 35 (2)
773 BINARY_MULTIPLY
774 BINARY_ADD
775 LOAD_CONST 50 (644)
778 COMPARE_OP 2 (==)
781 POP_JUMP_IF_FALSE 795
52 784 LOAD_CONST 51 ('congraduation!you get the right flag!')
787 PRINT_ITEM
788 PRINT_NEWLINE
789 JUMP_ABSOLUTE 795
792 JUMP_ABSOLUTE 798
>> 795 JUMP_ABSOLUTE 801
>> 798 JUMP_ABSOLUTE 804
>> 801 JUMP_ABSOLUTE 807
>> 804 JUMP_FORWARD 0 (to 807)
>> 807 LOAD_CONST 52 (None)
810 RETURN_VALUE
有点长,不太好看;可以下载附件自己看;
接下来就是一步一步手撸出源代码,手撸的过程中我有些地方不理解的,就用dis反汇编查看一下,是否和txt中内容相似,介绍一下dis的第二种反汇编方式,在终端中输入:
python -m dis wenjianming.py
en = [3,31,72,9,6,132]
output = [101,96,23,68,112,42,107,62,96,53,176,179,98,53,67,29,41,120,60,106,51,101,178,189,101,48]
print('welcome to GWHT2020')
flag = input('please input your flag:')
str = flag
a = len(str)
if a < 38:
print('lenth wrong!')
exit(0)
if (ord((str[0] * 2020) + (ord(str[1]) * 2020) + (ord(str[2]) * 2020) + (ord(str[3]) * 2020) + (ord(str[4])))== 1182843538814603) :
print('good!continue\xe2\x80\xa6\xe2\x80\xa6')
else:
print('bye~')
exit(0)
x = []
k = 5
for i in range(13):
b = ord(str[k])
c = ord(str[k + 1])
a11 = c ^ en[i % 6]
a22 = b ^ en[i % 6]
x.append(a11)
x.append(a22)
k = k + 2
if x == output:
print('good!continue\xe2\x80\xa6\xe2\x80\xa6')
else:
print('oh,you are wrong!')
exit(0)
l = len(str)
a1 = ord(str[l - 7])
a2 = ord(str[l - 6])
a3 = ord(str[l - 5])
a4 = ord(str[l - 4])
a5 = ord(str[l - 3])
a6 = ord(str[l - 2])
if a1 * 3 + a2 * 2 + a3 * 5 == 1003:
if a1 *4 + a2 * 7 + a3 * 9 == 2013:
if a1 * 8 + a2 * 8 + a3 * 2 == 1109:
if a4 * 3 + a5 * 2 + a6 * 5 == 671:
if a4 * 4 + a5 * 7 + a6 * 9 == 1252:
if a4 * 8 + a5 * 8 + a6 * 2 == 644:
print("congraduation!you get the right flag!")
手撸的时候注意Python字节码是一种栈方式存储的,则可以翻译得比较快
例如下面这个代码就是将 ord,str,l,7依次入栈
# 调用BINARY_SUBTRACT则变成 l - 7
# 调用BINARY_SUBSCR则变成 str[l-7]
# 调用CALL_FUNCTION则变成 ord(str[l-7])
# 调用STORE_NAME则变成 a1 = ord(str[l-7])
;目前类似题目如果给的是 txt文件,应该都只能手动反编译出来,我没有找到什么可以一键反编译的。如果是pyc是文件的话,就可以用uncompyle6或者在线网站进行反编译。
这里反编译出来后,就比较简单了,三个地方分别加密。写个exp慢慢看:
#第一部分
前五个字符也可以用z3求,步过猜都可以猜出来是GWHT{
# 第二部分
#俩个字符异或一次
en = [3,37,72,9,6,132]
output = [101,96,23,68,112,42,107,62,96,53,176,179,98,53,67,29,41,120,60,106,51,101,178,189,101,48]
flag=''
k=0
for i in range(13):
flag+=chr(output[k+1]^en[i%6])
flag+=chr(output[k]^en[i%6])
k+=2
print(flag)
# cfa2b87b3f746a8f0ac5c5963f
# 第三部分
from z3 import *
s = Solver()
a1,a2,a3,a4,a5,a6 = Ints("a1 a2 a3 a4 a5 a6")
s.add(a1*3 + a2*2 + a3*5 == 1003)
s.add(a1*4 + a2*7 + a3*9 == 2013)
s.add(a1 + a2*8 + a3*2 == 1109)
s.add(a4*3 + a5*2 + a6*5 == 671)
s.add(a4*4 + a5*7 + a6*9 == 1252)
s.add(a4 + a5*8 + a6*2 == 644)
s.add(a1>0x20)
s.add(a1<0x7f)
if s.check()== sat:
ans = s.model()
print(ans)
# [a5 = 55, a2 = 101, a6 = 51, a3 = 102, a4 = 102, a1 = 97]
print(bytes([97,101,102,102,55,51]))
# b'aeff73'
[NSSCTF 2nd]Bytecode
题目在nssctf靶场上,直接搜就有,txt文件内容有点长。就不放出来了;
手撸源代码是真的累啊,本来还有几题想复现的,但是写着写着就十点多了,下次有机会再继续了,这次就练倆题吧。
import base64
import string
def check(key):
x = [78, 82, 81, 64, 80, 67, 125, 83, 96, 56, 121, 84, 61, 126, 81, 79, 79, 119, 38, 120, 39, 74, 112, 38, 44, 126, 103]
if len(key) != len(x):
print('Wrong length!')
exit()
for i in range(len(key)):
if ord(key[i])^i != x[i]:
return 0
return 1
def init(key):
s_box = list(range(256))
j = 0
for i in range(256):
j = (j + s_box[i] + ord(key[i]%len(key))%256)
s_box[j],s_box[i] = s_box[i],s_box[j]
return s_box
def fun(key):
key = "Just kidding, don't take it personally!"
x = []
for i in range(len(msg)):
x.append(ord(msg[i]) ^ ord(key[i%len(key)]))
for i in range(len(x)):
x[i] = x[i] ^ x[(i + 1) % len(x)]
return x
def encrypt1(msg, s_box):
x = []
i = 0
j = 0
for k in range(len(msg)):
i = (i + 1) % 256
j = (j + s_box[i]) % 256
s_box[j], s_box[i] = s_box[i],s_box[j]
t = (s_box[i] + s_box[j]) % 256
x.append(ord(msg[k]) ^ s_box[t])
return x
def encrtot2(msg, s_box):
x = []
i = 0
j = 0
for k in range(len(msg)):
i = (i + 1) % 256
j = (j + s_box[i]) % 256
s_box[j], s_box[i] = s_box[i], s_box[j]
t = (s_box[i] + s_box[j]) % 256
x.append(ord(msg[k]) ^ s_box[t] ^ ord(key[i]))
return x
def encrypt(msg, s_box):
x = [[]]
i = 0
j = 0
for k in range(len(msg)):
i = (i + 1) % 256
j = (j + s_box[i]) % 256
s_box[j], s_box[i] = s_box[i], s_box[j]
t = (s_box[i] + s_box[j]) % 256
x.append(ord(msg[k]) ^ s_box[t] ^ i)
return x
if __name__ == '__main__':
key = input('Please input your key:')
if check(key) == 1:
print('Right!')
else:
print('Wrong!')
exit()
msg = input('Please input your message:')
box = init(key)
encode = encrypt(msg,box)
string1 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
string2 = 'YRiAOe4PlGvxaCoNj2ZgX+q8t/5Em6IUpM9FrVb7BKwsT1n3fSydhDWuQHJ0ckzL'
encode = base64.b64encode(bytes(encode.translate(str.maketrans(string1,string2)))).decode('utf-8')
if encode == 'mWGFL24R/RSZY3pzK9H4FOmFOnXJKyCjXWbZ7Ijy11GbCBukDrjsiPPFiYB=':
print('Congraduation!You get the right flag!')
else:
print('Wrong!')
这一题的第29行,我其实也还不是很明白;
查了 DUP_TOP_TWO是用于在堆栈上复制最顶端的两个值,并将它们推送回堆栈。但是还是不很理解怎么操作的/(ㄒoㄒ)/~~,学习不到位了,明天接着继续研究了。
这道题我觉得烦就是手撸代码了,得到源代码就好多了
import base64
def init(key):
s_box = list(range(256))
j = 0
for i in range(256):
j = (j + s_box[i] + ord(key[i % len(key)])) % 256
s_box[i], s_box[j] = s_box[j], s_box[i]
return s_box
def decrypt(s_box, encoded_msg):
decoded_msg = []
i = 0
j = 0
for k in range(len(encoded_msg)):
i = (i + 1) % 256
j = (j + s_box[i]) % 256
s_box[i], s_box[j] = s_box[j], s_box[i]
t = (s_box[i] + s_box[j]) % 256
decoded_msg.append(encoded_msg[k] ^ s_box[t] ^ i)
return decoded_msg
key = "NSSCTF{Th1s_1s_@_f4k3_f14g}"
encoded_result = "mWGFL24R/RSZY3pzK9H4FOmFOnXJKyCjXWbZ7Ijy11GbCBukDrjsiPPFiYB="
string1 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
string2 = 'YRiAOe4PlGvxaCoNj2ZgX+q8t/5Em6IUpM9FrVb7BKwsT1n3fSydhDWuQHJ0ckzL'
decoded_encoded_result=base64.b64decode(encoded_result.translate(str.maketrans(string2,string1)))
s_box = init(key)
decoded_message = decrypt(s_box, decoded_encoded_result)
message = ''.join(chr(c) for c in decoded_message)
print(message)
exp抄的别人/(ㄒoㄒ)/~~
后言
就先这样也了,不是很难手动反编译,主要就是麻烦,不过多练就好,加油咯。慢慢学~/(ㄒoㄒ)/~~,笨鸟多飞hh。