REGadgets - 新一代Reverser的妙妙工具箱
什么是REGadgets
REGadgets,顾名思义,就是一个Reverse中常用的,提供给使用者代码片段的库,可以加快逆向速度,甚至直接爆破出结果。
REGadgets 如何获取
REGadgets目前还在开发中,也就是只在小范围测试中,开发者将用它参加每一场XCTF分站赛,所有的WP都是用它来写的,以保证REGadgets库与时俱进。
REGadgets 项目结构
截至到 2024/09/30 REGadgets项目目录如下。
C:.
│ .gitignore
│ README.md
│ __init__.py
│
├───bases
│ base128.py
│ base2048.pyd
│ base2048.pyi
│ base45.py
│ base58.py
│ base62.py
│ base65536.py
│ base91.py
│ bases.py
│ py3base92.py
│ __init__.py
│
├───bits
│ bits.py
│ cstyle.py
│ __init__.py
│
├───bruteforce
│ bruteforcer.py
│ __init__.py
│
├───crypto
│ aes.py
│ blowfish.py
│ bxors.py
│ rc4.py
│ tea.py
│ xtea.py
│ xxtea.py
│ __init__.py
│
├───trans
│ sbox.py
│ __init__.py
│
└───utils
z3util.py
__init__.py
REGadgets库相关介绍及使用方法
regadgets.bases
这个库中,提供了 base 相关的编码解码,而且,regadgets提供了换表的快捷方案。
例题 BaseCTF2024 BasePlus
from regadgets import *
enc = b'lvfzBiZiOw7<lhF8dDOfEbmI]i@bdcZfEc^z>aD!'
k = 0xe
dec = decode_b64(bxor(enc, [k for _ in range(len(enc))]).decode(),
'/128GhIoPQROSTeUbADfgHijKLM+n0pFWXY456xyzB7=39VaqrstJklmNuZvwcdEC')
print(dec)
# b'BaseCTF{BA5e_DEcoD1N6_sEcr3t}\x00'
在本例中,通过regadgets.bases.decode_b64
我们对enc异或后的东西(base64编码后的东西)进行了解码,表是第二个参数。
例题 CDDC2024 Quals Emoji32
regadget的bases,支持换emoji表,因为Python的str对于Unicode非常友好。
from regadgets import *
emoji_table = ['😀','😥','😠','😱','😴','🤢','😇','😈','👋','✊','👌','✌','🤲','🙌','👏','🤝','🐶','🐱','🐭','🐹','🐰','🦊','🐻','🐼','🍎','🍌','🍓','🍑','🍕','🍔','🍟','🍦']
emoji_table = "".join(emoji_table)
encoded = "🤢😥😇😴🐭🦊😥✊✌️🍕🐰😴🍎🐭👌🐰🤢😴"
s = encoded.replace('\ufe0f', '') # Remove Wrong Char
while True:
try:
print(decode_b32(s, emoji_table))
# (LIT)_(LIT)
break
except:
s += '=' # Fix Padding
continue
regadgets.bits
这个子库中,提供了位与数的相关操作。
# 相关提供的函数有这些
from .bits import rol16, rol32, rol64, rol8, ror16, ror32, ror64, ror8, byte2dword, dword2byte, byte2qword, qword2byte, pack_dword, unpack_dword, b2l, l2b
from .cstyle import cstyle_arr32
rol & ror
这些函数用于在Python下执行相应位数的循环左移和循环右移。
byte2word byte2dword byte2qword
用于将Python的bytes 2个/4个/8个 打包成为 List[int],可选是否进行Padding。其中int是word或dword或qword,小端序,方便后续进行TEA族加密。
word2byte dword2byte qword2byte
用于将List[int] 解包为Python bytes,小端序。用于将外部的数据(程序中提取出来的)快速进行处理。
pack_dword
用于将[1, 2, 3, 4, 5, 6]
这样的List[int],两两打包为形如 [(1, 2), (3, 4), (5, 6)]
,方便进行TEA族加密。
unpack_dword
用于将 [(1, 2), (3, 4), (5, 6)]
解包为 [1, 2, 3, 4, 5, 6]
这样的List[int]
l2b b2l
从Crypto.Util.number里面复制出来的long_to_bytes和bytes_to_long,用于大端序的互相转换。
regadgets.bruteforce
本子库用于解决逆向工程中的一些基础爆破问题。
regadgets.bruteforce.rg_brute_forcer
基础的Reverse下的爆破函数,通过检测解密后文本是否含有flag
(可以进行修改),且解密后均为明文,来进行反向爆破,并还原出解密链。
本函数可以进行定制化扩展,由于特殊的模块化设计,可以自己手写一些常见算法,并在这些算法中爆破。
未来的话,这个函数可能会写成Cython实现的,用来加速爆破进程。
使用例
from regadgets import *
raw = list(b'flag{124214782134798217}')
for i in range(len(raw)):
raw[i] ^= 114
raw[i] += 514
raw[i] ^= 810
raw[i] &= 0xff
rg_brute_forcer(raw, 3)
'''
尝试深度 1 的解密...
[失败] 没有在深度 1 找到解密方案,用时 0.003998994827270508秒
尝试深度 2 的解密...
[失败] 没有在深度 2 找到解密方案,用时 2.940094470977783秒
尝试深度 3 的解密...
找到正确解密链: [('xor_decrypt', 20), ('mod_add_decrypt', 2), ('xor_decrypt', 76)]
解密结果: b'flag{124214782134798217}'
[成功] 在深度 3 找到解密方案,用时 59.33841252326965秒
'''
regadgets.crypto
regadgets.crypto.aes
标准的AES实现,根据比赛可以进行手动魔改。
regadgets.crypto.blowfish
标准的blowfish实现,根据比赛可以进行手动魔改。
regadgets.crypto.rc4
提供rc4_init
, rc4_crypt
, rc4_keystream
三个函数,在init的时候返回S盒,crypt的时候提供s盒和data用于加密,keystream函数可以只返回S盒生成的key长度,可以手动指定box_size,因为在 BaseCTF2024 出了一个 S盒大小128的题目。
regadgets.crypto.bxors
提供了相关的XOR实现,比如 x_0 ^ x_1, x_1 ^ x_2, x_2 ^ x_3, ..... , x_(n-1) ^ x_n, x_n
(我们称之为向右异或,bxorr)的加密解密。
除此之外,还提供了bxor(用于将两个等长的bytes | list进行互相异或)。
最常用的是,bxor_cycle,用于将第一个参数进行循环异或第二个参数(bytes | list)
一个常用的例子
# 对于一个数组循环异或 b'my_key'
enc = [...]
raw = bxor_cycle(enc, b'my_key')
# 对于一个数组进行异或 0xEE
raw = bxor_cycle(enc, b'\xee')
# 对于一个数组进行异或循环变量 i
raw = bxor_cycle(enc, range(len(enc)))
regadgets.crypto.tea / xtea / xxtea
用 python ctypes 实现的 TEA族加密。可以自行指定 delta / rounds, 对于xxtea可以指定很多参数,甚至是shift函数,具体请见其他题解。
regadgets.trans
用于S盒之类的变换
regadgets.trans.sbox
提供了 generate_sbox
和 sbox_transform
两个函数。
如例题
from regadgets import *
from hashlib import md5
str1 = [0x28, 0x5F, 0x40, 0x34, 0x36, 0x32, 0x30, 0x21, 0x30, 0x38, 0x21, 0x36, 0x5F, 0x30, 0x2A, 0x30, 0x34, 0x34, 0x32, 0x21, 0x40, 0x31, 0x38, 0x36, 0x25, 0x25, 0x30, 0x40, 0x33, 0x3D,
0x36, 0x36, 0x21, 0x21, 0x39, 0x37, 0x34, 0x2A, 0x33, 0x32, 0x33, 0x34, 0x3D, 0x26, 0x30, 0x5E, 0x33, 0x26, 0x31, 0x40, 0x3D, 0x26, 0x30, 0x39, 0x30, 0x38, 0x21, 0x36, 0x5F, 0x30, 0x2A, 0x26]
str2 = [0x35, 0x35, 0x35, 0x36, 0x35, 0x36, 0x35, 0x33, 0x32, 0x35, 0x35, 0x35, 0x35, 0x32, 0x32, 0x32, 0x35, 0x35, 0x36, 0x35, 0x35, 0x36, 0x35, 0x35, 0x35, 0x35, 0x32, 0x34, 0x33, 0x34,
0x36, 0x36, 0x33, 0x33, 0x34, 0x36, 0x35, 0x33, 0x36, 0x36, 0x33, 0x35, 0x34, 0x34, 0x34, 0x32, 0x36, 0x35, 0x36, 0x35, 0x35, 0x35, 0x35, 0x35, 0x32, 0x35, 0x35, 0x35, 0x35, 0x32, 0x32, 0x32]
xxx = [0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x2D, 0x3D, 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A, 0x28, 0x29, 0x5F, 0x2B, 0x71, 0x77, 0x65, 0x72, 0x74, 0x79, 0x75, 0x69, 0x6F, 0x70, 0x5B, 0x5D, 0x51, 0x57, 0x45, 0x52, 0x54, 0x59, 0x55, 0x49, 0x4F,
0x50, 0x7B, 0x7D, 0x61, 0x73, 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x3B, 0x27, 0x41, 0x53, 0x44, 0x46, 0x47, 0x48, 0x4A, 0x4B, 0x4C, 0x3A, 0x22, 0x5A, 0x58, 0x43, 0x56, 0x42, 0x4E, 0x4D, 0x3C, 0x3E, 0x3F, 0x7A, 0x78, 0x63, 0x76, 0x62, 0x6E, 0x6D, 0x2C, 0x2E, 0x2F]
r = []
for i in range(62):
a = xxx.index(str1[i])
b = xxx.index(str2[i])
r.append(b * 23 + a)
# private: char * __thiscall R0Pxx::My_Aut0_PWN(unsigned char *)
print(bytes(r))
# 手动转换一下 查表
r = b'?My_Aut0_PWN@R0Pxx@@AAEPADPAE@Z'
###### 从这里开始是S盒变换
data_from = b'abcdefghijklmnopqrstuvwxyz12345'
data_to = b'pqhrsidtujvwkebxylz1mf23n45ogca'
_, ibox = generate_sbox(data_from, data_to)
r = sbox_transform(r, ibox)
print(bytes(r))
print(f"flag{{{md5(bytes(r)).hexdigest()}}}")
# flag{63b148e750fed3a33419168ac58083f5}
regadgets.utils
regadgets.utils.z3util
目前只有z3_get_models
,用于获取Z3的Solver的所有解。