exe->pyc && RC4 &&pyc反编译

D0wnBe@t Lv4

内容

这篇文章主要介绍ctfre部分,从exe文件转化成pyc文件,顺便提一下rc4加密。

题目来自basectf,如果选手看到了请务必避开。

转化

exe->pyc

  • 首先明白为什么要从exe->pyc,见下图:

    exe例子

我们发现图片虽然是一个exe,但是程序图标是可以发现是一个.py文件,于是我们要去转化成pyc

介绍一篇文章看看csdn-blog

觉得麻烦提供一个在线网站:PyInstaller Extractor WEB (pyinstxtractor-web.netlify.app)

自己选择exe文件运行就行,会得到一个压缩包,里面会有pyc文件

pyc->py代码:

  • 先了解什么是pyc:我们所看到的pyc文件,其实是PyCodeObject,是Python编译后的结果。当python程序运行时,编译的结果是保存于PyCodeObject,程序运行结束后,Python就将PyCodeObject写入到pyc文件中,这是个字节码文件。[引用 ]

  • 在线网站:在线Python pyc文件编译与反编译 (lddgo.net)

RC4

  • 先前得到的pyc转化为py代码,我们可以发现如下的加密脚本:

    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
    # Visit https://www.lddgo.net/string/pyc-compile-decompile for more information
    # Version : Python 3.9
    import Key
    import sys

    def init_Sbox(seed):
    k_b = (lambda .0 = None: [ ord(seed[i % len(seed)]) for i in .0 ])(range(256))
    s = list(range(256))
    j = 0
    for i in range(256):
    j = (j + s[i] + k_b[i]) % 256
    s[i] = s[j]
    s[j] = s[i]
    return s

    def KeyStream(text, Sbox):
    s = Sbox.copy()
    (i, j) = (0, 0)
    k = [0] * len(text)
    for r in range(len(text)):
    i = (i + 1) % 256
    j = (j + s[i]) % 256
    s[i] = s[j]
    s[j] = s[i]
    t = (s[i] + s[j]) % 256
    k[r] = s[t] ^ Key.keykey[r % len(Key.keykey)]
    return k


    def Encrypt(text, seed):
    Sbox = init_Sbox(seed)
    key = KeyStream(text, Sbox)
    enc = (lambda .0 = None: [ text[i] ^ key[i] for i in .0 ])(range(len(text)))
    return bytes(enc)

    enc = b'\xe6\xaeC~F\xf2\xe3\xbb\xac\x9a-\x02U\x85p\xeb\x19\xd1\xe4\xc93sG\xb0\xeb1\xb5\x05\x05\xc3\xd7\x00\x18+D\xbc\x0cO\x9em\xf1\xbd'
    flag = input('Please input Your flag:')
    flag = (lambda .0: [ ord(i) for i in .0 ])(flag)
    flag = Encrypt(flag, Key.key)
    if flag != enc:
    print("It's not flag!")
    continue
    print('You are right!')
    sys.exit(1)
    continue

    '''
    key = 'yOU_f1nd_m3'
    keykey = [66,97,115,101]
    '''

这就是很明显的RC4加密了,256次循环初始化Sbox,目的就是为了打乱数字顺序,顺序依靠key,然后再通过异或获得flag。

  • 解密脚本(仅针对本题,因为此题有两个key)
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
import numpy as np

# Given key and keykey
key = 'yOU_f1nd_m3'
keykey = [66, 97, 115, 101]

def init_Sbox(seed):
k_b = [ord(seed[i % len(seed)]) for i in range(256)]
s = list(range(256))
j = 0
for i in range(256):
j = (j + s[i] + k_b[i]) % 256
s[i], s[j] = s[j], s[i]
return s

def KeyStream(text, Sbox):
s = Sbox.copy()
i = j = 0
k = [0] * len(text)
for r in range(len(text)):
i = (i + 1) % 256
j = (j + s[i]) % 256
s[i], s[j] = s[j], s[i]
t = (s[i] + s[j]) % 256
k[r] = s[t] ^ keykey[r % len(keykey)]
return k

def Decrypt(enc, seed):
Sbox = init_Sbox(seed)
key_stream = KeyStream(enc, Sbox)
decrypted = [enc[i] ^ key_stream[i] for i in range(len(enc))]
return ''.join(chr(c) for c in decrypted)

# Given encrypted message
enc = b'\xe6\xaeC~F\xf2\xe3\xbb\xac\x9a-\x02U\x85p\xeb\x19\xd1\xe4\xc93sG\xb0\xeb1\xb5\x05\x05\xc3\xd7\x00\x18+D\xbc\x0cO\x9em\xf1\xbd'
flag = Decrypt(enc, key)
print(flag)

通用解密脚本

参考:Python3.7实现RC4加密解密(超详细) - 简书 (jianshu.com)

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
import base64
def rc4_main(key = "init_key", message = "init_message"):
# print("RC4解密主函数调用成功")
s_box = rc4_init_sbox(key)
crypt = rc4_excrypt(message, s_box)
return crypt
def rc4_init_sbox(key):
s_box = list(range(256)) # 我这里没管秘钥小于256的情况,小于256不断重复填充即可
# print("原来的 s 盒:%s" % s_box)
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]
# print("混乱后的 s 盒:%s"% s_box)
return s_box
def rc4_excrypt(plain, box):
# print("调用解密程序成功。")
plain = base64.b64decode(plain.encode('utf-8'))
plain = bytes.decode(plain)
res = []
i = j = 0
for s in plain:
i = (i + 1) % 256
j = (j + box[i]) % 256
box[i], box[j] = box[j], box[i]
t = (box[i] + box[j]) % 256
k = box[t]
res.append(chr(ord(s) ^ k))
# print("res用于解密字符串,解密后是:%res" %res)
cipher = "".join(res)
# print("解密后的字符串是:%s" %cipher)
# print("解密后的输出(没经过任何编码):")
return cipher
# rc4_main("123456sh", "ABHCum92PMOXwqI=")

加解密其实没太大区别,可以上网搜搜

pyc反编译

在线网站

magic number

  • 正常的直接丢到在线网站分解发现无法分解,发现给的附件里面还有struct文件,上网查了查,发现是给的pyc文件的magic number出现错误
  • 正确的magic number在struct

E3前面的就是magic number,修改或者增添到给的pyc文件,再去网站解密即可。

  • 标题: exe->pyc && RC4 &&pyc反编译
  • 作者: D0wnBe@t
  • 创建于 : 2024-08-22 20:56:07
  • 更新于 : 2024-10-14 19:13:51
  • 链接: http://downbeat.top/2024/08/22/exe-pyc-RC4/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论