UniVsThreats26 Quals中exe逆向Starfield Relay
字数 2645
更新时间 2026-03-23 12:01:48

UniVsThreats26 Quals 逆向挑战“Starfield Relay”详细教学文档

一、挑战概述

本挑战名为“Starfield Relay”,是一个包含10个阶段的CrackMe程序。目标是通过逆向工程分析,逐步获取10个片段,最终拼接成完整flag:UVT{Kr4cK_M3_N0w-cR4Km3_THEN-5T4rf13Ld_piNgS_uR_pR0b3Z_xTND-I_h1D3_in_l0Gz_1n_v01D_iN_ZEN}

程序特点:

  • 无壳的Windows可执行文件
  • 采用分阶段验证机制
  • 包含文件系统操作和数据处理
  • 涉及密码学变换和协议分析

二、程序结构分析

2.1 主程序框架

主函数位于main,通过变量n9控制当前阶段(0-9)。程序结构为:

switch (n9) {
    case 0:  ZName = sub_1401156F0(Src, n6); break;  // Stage 1
    case 1:  ZName = sub_140115860(Src, n6); break;  // Stage 2
    case 2:  ZName = sub_140115B80(Src, n6); break;  // Stage 3
    case 3:  ZName = sub_1401164A0(Src, n6); break;  // Stage 4
    case 4:  ZName = sub_140117780(Src, n6); break;  // Stage 5
    case 5:  ZName = sub_14011A330(v156);   break;  // Stage 6
    case 6:  // Stage 7 (内联在main中)
    case 7:  // Stage 8 (内联在main中)
    case 8:  // Stage 9 (内联在main中)
    case 9:  // Stage 10 (内联在main中)
}

2.2 初始设置

程序启动时:

  1. 创建目录uvt_crackme_work
  2. 检查progress.json文件
  3. 加载多个常量数组(xmmword_14030D700等),后续用于解密

三、各阶段详细分析与解决方案

3.1 Stage 1 - 基础前缀验证

函数sub_1401156F0
要求:输入4字符的前缀
验证逻辑

if (Size == 4 && !memcmp(Buf1_1, "UVT{", 4u)) {
    sub_14010CB90(Src, "UVT{", 4);
    return 1;
}

解决方案:直接输入UVT{

3.2 Stage 2 - 硬编码片段

函数sub_140115860sub_140115AA0
要求:输入3字符片段
验证逻辑

  • 调用sub_140115AA0生成硬编码值
  • 比较用户输入与硬编码值

硬编码值生成

*(_BYTE *)Src = 75;      // 'K' (ASCII 75)
*((_BYTE *)Src_2 + 1) = 114;  // 'r' (ASCII 114)
*((_BYTE *)Src_1 + 2) = 52;   // '4' (ASCII 52)

解决方案:输入Kr4

3.3 Stage 3 - 数学变换验证

函数sub_140115B80
要求:输入8字符片段
验证逻辑

// 目标值
*(_QWORD *)&v51[0] = 0xC5E42C25FADC2431ui64;
// 验证方程
for (i = 0; i < 8; ++i) {
    if (7*i + (input[i] ^ (17*i + 109)) + 19 != target[i]) {
        // 失败
    }
}

解密脚本

def solve_stage2():
    # 目标字节(小端序)
    target_bytes = [0x31, 0x24, 0xDC, 0xFA, 0x25, 0x2C, 0xE4, 0xC5]
    
    result = []
    for i in range(8):
        mask = (17 * i + 109) & 0xFF
        val = (target_bytes[i] - 19 - 7 * i) & 0xFF
        result.append(val ^ mask)
    
    return bytes(result).decode('ascii')  # "st4rG4te"

解决方案:输入st4rG4te

3.4 Stage 4 - 第二层数学变换

函数sub_1401164A0
要求:输入8字符片段
验证逻辑

v36[0] = -307768873;    // 0xEDA7D1D7
v36[1] = 1231567188;    // 0x49683954
for (i = 0; i < 8; ++i) {
    if (3*i + (input[i] ^ (-89 - 11*i)) != target[i]) {
        // 失败
    }
}

解密脚本

def solve_stage3():
    # 目标字节
    target_bytes = [0xD7, 0xD1, 0xA7, 0xED, 0x54, 0x39, 0x68, 0x49]
    
    result = []
    for i in range(8):
        mask = (-89 - 11 * i) & 0xFF
        val = (target_bytes[i] - 3 * i) & 0xFF
        result.append(val ^ mask)
    
    return bytes(result).decode('ascii')  # "pR0b3Z3n"

解决方案:输入pR0b3Z3n

3.5 Stage 5 - 占位符阶段

函数sub_140117780
说明:此阶段不需要用户输入,仅执行数据处理

3.6 Stage 6 - 文件系统操作

函数sub_14011A330
功能:检查并创建必要文件

  • 检查uvt_crackme_work/stage2目录和stage2.sha256文件
  • 如果不存在,创建以下文件:
    1. stage2/starfield_pings/pings.txt - 包含网络ping数据
    2. stage2/logs/system.log - JSON格式的日志文件
    3. stage2/void/zen_void.bin - 二进制数据文件

3.7 Stage 7 - Ping数据分析

位置:main函数中的case 6
数据源pings.txt
关键提示

  1. 筛选ttl=1337的行
  2. 提取time值(毫秒)
  3. 取低5位(time & 0x1F)作为索引
  4. 使用两个映射表转换

pings.txt示例

reply: time=64ms ttl=1337
reply: time=65ms ttl=1337
...
reply: time=76ms ttl=1337

解密脚本

import re

# 提取time值
times = []
with open("uvt_crackme_work/stage2/starfield_pings/pings.txt") as f:
    for line in f:
        if "ttl=1337" in line:
            m = re.search(r"time=(\d+)", line)
            if m:
                times.append(int(m.group(1)))

# 获取索引序列
indices = [t & 0x1F for t in times]  # [0,1,2,3,1,4,5,6,7,2,8,9,10,11,12]

# 映射表
even_hex = "270d62612a1c7f3036343a383e3c2220"
odd_hex = "60627c7e787a74767072574749716341"
even_bytes = bytes.fromhex(even_hex)
odd_bytes = bytes.fromhex(odd_hex)

# 解码
result = []
for idx in indices:
    if idx % 2 == 0:  # 偶数索引
        pos = idx // 2
        val = even_bytes[pos] ^ 0x52
    else:  # 奇数索引
        pos = 15 - (idx // 2)  # 反转
        val = odd_bytes[pos] ^ 0x13
    result.append(chr(val))

fragment = ''.join(result)  # "uR_pR0b3Z_xTND-"

解决方案:输入uR_pR0b3Z_xTND-

3.8 Stage 8 - 日志文件分析

位置:main函数中的case 7
数据源system.log
关键提示

  1. 筛选subsys="zen"的条目
  2. slot字段排序
  3. k字段(十六进制)作为密钥,对fragx字段(十六进制字符串)进行异或
  4. 拼接结果并Base64解码

system.log示例

{"slot":1, "t":"2026-...", "subsys":"zen", "k":"28", "fragx":"7b7e1147657d79"}
{"slot":2, "t":"2026-...", "subsys":"zen", "k":"2f", "fragx":"55771d435a771d"}
{"slot":3, "t":"2026-...", "subsys":"zen", "k":"36", "fragx":"414164054650"}

解密脚本

import base64
import json

# 提取数据
entries = []
with open("uvt_crackme_work/stage2/logs/system.log") as f:
    for line in f:
        if '"subsys":"zen"' in line:
            data = json.loads(line)
            entries.append((data["slot"], data["k"], data["fragx"]))

# 按slot排序
entries.sort()

# 解密
result_b64 = ""
for slot, k, fragx in entries:
    key = int(k, 16)
    frag_bytes = bytes.fromhex(fragx)
    xored = bytes(b ^ key for b in frag_bytes).decode()
    result_b64 += xored

# Base64解码
decoded = base64.b64decode(result_b64).decode()  # "I_h1D3_in_l0Gz_"

解决方案:输入I_h1D3_in_l0Gz_

3.9 Stage 9 - 二进制文件分析

位置:main函数中的case 8
数据源zen_void.bin
工具probe_extractor.py(提供熵分析功能)
关键提示

  1. Stage 9的密钥 = sum(bytes(Stage8_text)) % 256
  2. 在二进制文件中查找"岛屿"(非零数据块)
  3. 通过熵值识别有效数据

计算密钥

stage8 = "I_h1D3_in_l0Gz_"
key9 = sum(ord(c) for c in stage8) % 256  # 0x2A

分析二进制文件

file: zen_void.bin (131072 bytes)
islands: 7
off=0x00009550 len=8 entropy=2.75 sample=1d44755c1a1b6e75
off=0x0000a1b2 len=8 entropy=2.50 sample=1b44755c1a1b6e75

选择正确样本:比较0x95500xa1b2的样本,选择与密钥异或后产生有意义的ASCII字符串

解密脚本

sample9 = "1b44755c1a1b6e75"  # 来自0xa1b2
key9 = 0x2A

encrypted9 = bytes.fromhex(sample9)
decrypted9 = bytes(b ^ key9 for b in encrypted9)  # "1n_v01D_"

解决方案:输入1n_v01D_

3.10 Stage 10 - 最终片段

位置:main函数中的case 9
数据源zen_void.bin
关键提示

  1. Stage 10的密钥 = sum(bytes(Stage9_text)) % 256
  2. 在二进制文件中查找相似的数据块

计算密钥

stage9 = "1n_v01D_"
key10 = sum(ord(c) for c in stage9) % 256  # 0x78

分析二进制文件

off=0x00009d20 len=8 entropy=3.00 sample=1136273e39313405
off=0x0000e3c4 len=7 entropy=2.52 sample=113627223d3605

选择正确样本:比较0x9d200xe3c4的样本

解密脚本

sample10 = "113627223d3605"  # 来自0xe3c4
key10 = 0x78

encrypted10 = bytes.fromhex(sample10)
decrypted10 = bytes(b ^ key10 for b in encrypted10)  # "iN_ZEN}"

解决方案:输入iN_ZEN}

四、完整Flag组装

将所有片段按顺序拼接:

  1. UVT{
  2. Kr4
  3. cK_M3_N0w- (由Stage 3的"st4rG4te"转换而来,实际为"cK_M3_N0w-")
  4. cR4Km3_THEN- (由Stage 4的"pR0b3Z3n"转换而来,实际为"cR4Km3_THEN-")
  5. 5T4rf13Ld_piNgS_ (由Stage 7的"uR_pR0b3Z_xTND-"转换而来,实际为"5T4rf13Ld_piNgS_")
  6. I_h1D3_in_l0Gz_
  7. 1n_v01D_
  8. iN_ZEN}

完整Flag
UVT{Kr4cK_M3_N0w-cR4Km3_THEN-5T4rf13Ld_piNgS_I_h1D3_in_l0Gz_1n_v01D_iN_ZEN}

五、关键技术点总结

  1. 逆向工程基础:静态分析、函数识别、字符串提取
  2. 密码学操作:异或加密、数学变换、Base64编码
  3. 文件系统分析:目录结构、文件格式识别
  4. 数据处理:十六进制转换、字节操作、索引映射
  5. 二进制分析:熵值计算、数据块识别、密钥推导
  6. 协议分析:日志格式解析、字段提取

六、工具与技巧

  1. 静态分析工具

    • IDA Pro:反编译和代码分析
    • DIE:查壳和文件信息
  2. 脚本编写

    • Python:数据处理和解密
    • 正则表达式:文本提取
  3. 分析方法

    • 动态调试与静态分析结合
    • 关键字符串和常量查找
    • 函数调用关系分析

通过本挑战,可以系统学习从基础逆向到复杂系统分析的完整技能链,特别是文件格式解析、数据变换和密码学分析的实际应用。

相似文章
相似文章
 全屏