吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 357|回复: 6
上一主题 下一主题
收起左侧

[CTF] 【2026春节】Windows 中级题writeup

  [复制链接]
跳转到指定楼层
楼主
神奇的人鱼 发表于 2026-3-4 10:12 回帖奖励
本帖最后由 神奇的人鱼 于 2026-3-4 10:14 编辑

1. 欢迎来到windows中级,先看什么编写的

这不是巧了吗,之前做过nuitka的逆向分析,参考:破解 [CrackMe] 我又来了,这次用py的nuitka,我打包工具的另一个分支 思路 - 吾爱破解 - 52pojie.cn
2. 既然知道了nuitka,直接提取相关文件,可以通过github上的一个库提取内置的二进制文件,可以通过监控程序查看释放路径地址:https://github.com/extremecoders-re/nuitka-extractor

得到关键dll
3. 提取资源使用Resource Hacker提取id为3的资源

4. 内容解析
首先先尝试使用上个帖子中的代码尝试解析
[Python] 纯文本查看 复制代码
import io
import sys
import struct
 
 
def read_uint8(bio):
    return struct.unpack("<B", bio.read(1))[0]
 
def read_uint16(bio):
    return struct.unpack("<H", bio.read(2))[0]
 
def read_uint32(bio):
    return struct.unpack("<I", bio.read(4))[0]
 
def read_utf8_size_1(bio):
    return bio.read(1).decode("utf-8")
 
def read_utf8(bio):
    bs = b""
    while True:
        c = bio.read(1)
        if c == b"\x00" or not c:  # 读取到空字节或文件末尾时停止
            break
        bs += c
    return bs.decode("utf-8")
 
def read_bytearray(bio):
    bs = b""
    while True:
        c = bio.read(1)
        if c == b"\x00" or not c:
            break
        bs += c
    return bs
 
def decode_blob(bio, count):
    container = []
    for i in range(count):
        type_ = chr(read_uint8(bio))
        if type_ in ('a', 'u'):
            o = read_utf8(bio)
        elif type_ == 'l':
            o = read_uint32(bio)
        elif type_ == 'w':
            o = read_utf8_size_1(bio)
        elif type_ == 'T':
            sub_count = read_uint32(bio)
            o = tuple(decode_blob(bio, sub_count))
        elif type_ == 'c':
            o = read_bytearray(bio)
        elif type_ == 'b':
            size = read_uint32(bio)
            o = bio.read(size)
        else:
            raise ValueError(f"unhandled type {type_}")
        container.append(o)
    return container
 
 
def main():
    with open("main.bin", "rb") as f_in:
        bs = f_in.read()
    bio = io.BytesIO(bs)
 
    hash_ = read_uint32(bio)
    size = read_uint32(bio)
    # print(f"Header Hash: {hex(hash_)}")
    # print(f"Total Size: {hex(size)}")
 
    while bio.tell() < size:
        blob_name = read_utf8(bio)
        blob_size = read_uint32(bio)
        blob_count = read_uint16(bio)
        # print(f"Found Blob - Name: '{blob_name}', Size: {hex(blob_size)}, Count: {hex(blob_count)}")
 
        # 检查是否是我们要找的 '__main__' 数据块
        if blob_name == "__main__":
            print("Decoding '__main__' blob...")
            # 解码 '__main__' 数据块中的所有对象
            decoded = decode_blob(bio, blob_count)
            # 打印出每个对象的索引和值
            for idx, obj in enumerate(decoded):
                print(f"{idx}: {obj}")
            break  # 如果只需要 __main__,找到后就可以退出
 
        else:
            # 跳过当前数据块的剩余部分
            bio.seek(bio.tell() + (blob_size - 2))
 
 
if __name__ == "__main__":
    main()

不出所料解析失败,看来使用的nuitka版本不同

5. IDA分析
直接定位到解析函数

和之前帖子中的函数对比还是差距比较大的

6. 编写新的解析代码
借助AI的帮助也是很快的编写出来的新的解析代码
[Python] 纯文本查看 复制代码
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Nuitka 新版 Blob 解析器
适配 sub_31340ECE0 反编译逻辑
"""

import io
import struct
import sys
from typing import Any, List, Dict, Optional


def read_uint8(bio: io.BytesIO) -> int:
    return struct.unpack("<B", bio.read(1))[0]


def read_uint16(bio: io.BytesIO) -> int:
    return struct.unpack("<H", bio.read(2))[0]


def read_uint32(bio: io.BytesIO) -> int:
    return struct.unpack("<I", bio.read(4))[0]


def read_leb128(bio: io.BytesIO) -> int:
    """读取无符号 LEB128 编码整数"""
    result = 0
    shift = 0
    while True:
        byte_val = read_uint8(bio)
        result |= (byte_val & 0x7F) << shift
        if not (byte_val & 0x80):
            break
        shift += 7
    return result


def _read_leb128_signed(bio: io.BytesIO) -> int:
    """读取有符号 LEB128(Nuitka 内部使用无符号编码+符号位)"""
    return read_leb128(bio)


def _decode_utf8_safe(data: bytes) -> str:
    """安全解码 UTF-8,使用 surrogatepass 处理代理对"""
    return data.decode("utf-8", errors="surrogatepass")


class BlobParser:
    """Nuitka blob 解析器类,维护解析状态"""
    
    # 预定义浮点数索引映射 (根据 C 代码 Z 类型推断)
    PREDEFINED_DOUBLES = [
        0.0,        # index 0
        -0.0,       # index 1  
        float('inf'),   # index 2
        -float('inf'),  # index 3
        float('nan'),   # index 4
        1.0,        # index 5
    ]
    
    # M 类型匿名对象映射
    ANON_TYPES = {
        0: None,
        1: Ellipsis,
        2: NotImplemented,
        3: "<PyFunction_Type>",
        4: "<PyGen_Type>",
        5: "<PyCFunction_Type>",
        6: "<PyCode_Type>",
        7: "<PyModule_Type>",
        10: "<Unknown_M_10>",
    }
    
    # Q 类型特殊值映射
    SPECIAL_VALUES = {
        0: Ellipsis,
        1: NotImplemented,
        2: "<SELF_REFERENCE>",
    }
    
    def __init__(self):
        self.stack: List[Any] = []  # 对象栈,用于 'p' 引用
        self.ctx: Dict[str, Any] = {}  # 上下文
        
    def decode_one(self, bio: io.BytesIO) -> Any:
        """解析单个 blob 对象"""
        type_byte = read_uint8(bio)
        type_char = chr(type_byte)
        
        result = self._decode_type(bio, type_char, type_byte)
        
        # 将结果压栈(供 'p' 引用使用)
        if result is not None or type_char == 'p':
            self.stack.append(result)
        return result
    
    def _decode_type(self, bio: io.BytesIO, tc: str, tb: int) -> Any:
        """根据类型字符分发解析逻辑"""
        
        # ========== 基础类型 ==========
        if tc == 'n':  # None
            return None
        if tc == 't':  # True
            return True
        if tc == 'F':  # False
            return False
            
        # ========== 字符串类型 ==========
        if tc in ('a', 'u'):  # null-terminated UTF-8 string
            bs = b""
            while True:
                c = bio.read(1)
                if not c or c == b"\x00":
                    break
                bs += c
            result = _decode_utf8_safe(bs)
            # 'a' 会 intern,这里简化处理
            return result
            
        if tc == 'w':  # single char interned
            return _decode_utf8_safe(bio.read(1))
            
        if tc == 'v':  # length-prefixed UTF-8 string
            length = read_leb128(bio)
            return _decode_utf8_safe(bio.read(length))
            
        if tc == 's':  # interned empty string (new version)
            # C 代码: PyUnicode_DecodeUTF8(v7, 0, ...) 长度为 0
            return ""
            
        # ========== 整数类型 ==========
        if tc in ('l', 'q'):  # small int
            value = read_leb128(bio)
            return -value if tc == 'q' else value
            
        if tc in ('G', 'g'):  # big int (LEB128 chunked)
            byte_count = read_leb128(bio)
            if byte_count == 0:
                return 0
            # 读取 byte_count 个 LEB128 编码的 7-bit chunks
            result = 0
            shift = 0
            for _ in range(byte_count):
                chunk = read_leb128(bio)
                result |= chunk << shift
                shift += 7
            return -result if tc == 'g' else result
            
        # ========== 容器类型 ==========
        if tc == 'T':  # tuple
            count = read_leb128(bio)
            return tuple(self.decode_one(bio) for _ in range(count))
            
        if tc == 'L':  # list
            count = read_leb128(bio)
            return [self.decode_one(bio) for _ in range(count)]
            
        if tc == 'D':  # dict
            count = read_leb128(bio)
            result = {}
            for _ in range(count):
                k = self.decode_one(bio)
                v = self.decode_one(bio)
                result[k] = v
            return result
            
        if tc in ('S', 'P'):  # set / frozenset
            count = read_leb128(bio)
            items = [self.decode_one(bio) for _ in range(count)]
            return set(items) if tc == 'S' else frozenset(items)
            
        # ========== 字节类型 ==========
        if tc == 'B':  # bytearray
            length = read_leb128(bio)
            return bytearray(bio.read(length))
            
        if tc == 'b':  # bytes
            length = read_leb128(bio)
            return bio.read(length)
            
        if tc == 'c':  # interned bytes (null-terminated)
            bs = b""
            while True:
                c = bio.read(1)
                if not c or c == b"\x00":
                    break
                bs += c
            return bs
            
        # ========== 浮点/复数 ==========
        if tc == 'd':  # predefined float index
            idx = read_uint8(bio)
            return f"<PREDEFINED_FLOAT_{idx}>"
            
        if tc == 'f':  # float - new version skips 8 bytes
            # 实际值需要查 PyRuntime 表,这里跳过并返回占位符
            bio.seek(8, io.SEEK_CUR)
            return f"<FLOAT_PLACEHOLDER>"
            
        if tc == 'j':  # complex - new version skips 16 bytes
            bio.seek(16, io.SEEK_CUR)
            return f"<COMPLEX_PLACEHOLDER>"
            
        if tc == 'Z':  # predefined double index
            idx = read_uint8(bio)
            if idx < len(self.PREDEFINED_DOUBLES):
                return self.PREDEFINED_DOUBLES[idx]
            return f"<PREDEFINED_DOUBLE_{idx}>"
            
        # ========== 特殊对象 ==========
        if tc == 'M':  # anonymous types
            idx = read_uint8(bio)
            return self.ANON_TYPES.get(idx, f"<ANON_{idx}>")
            
        if tc == 'Q':  # special values
            idx = read_uint8(bio)
            return self.SPECIAL_VALUES.get(idx, f"<SPECIAL_{idx}>")
            
        if tc == 'O':  # getattr dynamic
            name = b""
            while True:
                c = bio.read(1)
                if not c or c == b"\x00":
                    break
                name += c
            return f"<GETATTR:{_decode_utf8_safe(name)}>"
            
        # ========== 控制/引用类型 ==========
        if tc == 'X':  # skip bytes
            skip_len = read_leb128(bio)
            bio.seek(skip_len, io.SEEK_CUR)
            return None  # 不产生对象
            
        if tc == 'p':  # stack reference (previous object)
            return self.stack[-1] if self.stack else "<UNDEF_REF>"
            
        if tc == 'E':  # skip to null
            while True:
                c = bio.read(1)
                if not c or c == b"\x00":
                    break
            return "<SKIP_E>"
            
        if tc == '.':  # error
            raise ValueError("Missing blob values")
            
        # ========== 复杂类型 ==========
        if tc == 'C':  # Code Object (complex flags)
            return self._decode_code_object(bio)
            
        if tc == 'A':  # GenericAlias
            origin = self.decode_one(bio)
            args = self.decode_one(bio)
            return f"<GenericAlias[{origin}, {args}]>"
            
        if tc == ';':  # range/lambda-like (4 params)
            items = [self.decode_one(bio) for _ in range(4)]
            return f"<RANGE_LIKE:{items}>"
            
        if tc == ':':  # slice
            start = self.decode_one(bio)
            stop = self.decode_one(bio)
            step = self.decode_one(bio)
            return slice(start, stop, step)
            
        if tc == 'H':  # bitwise OR reduction
            count = read_leb128(bio)
            if count == 0:
                return None
            result = self.decode_one(bio)
            for _ in range(count - 1):
                item = self.decode_one(bio)
                try:
                    if result is not None and item is not None:
                        result = result | item
                except TypeError:
                    result = f"<OR[{result}, {item}]>"
            return result
            
        # ========== 未处理类型 ==========
        raise ValueError(f"Unhandled type: '{tc}' (0x{tb:02X})")
    
    def _decode_code_object(self, bio: io.BytesIO) -> Any:
        """
        解析 Code Object (类型 'C')
        根据 C 代码的位掩码逻辑解析可选字段
        """
        # 读取 flags byte 和可能的扩展
        flags_byte = read_uint8(bio)
        base_val = flags_byte & 0x7F
        has_extended = flags_byte < 0  # sign bit indicates LEB128 extension
        
        if has_extended:
            # 扩展 LEB128 解码
            shift = 7
            while True:
                b = read_uint8(bio)
                base_val |= (b & 0x7F) << shift
                if not (b & 0x80):
                    break
                shift += 7
        
        # 解析基础参数
        argcount = read_leb128(bio)      # 参数数量
        kwonlyargcount = read_leb128(bio) # 仅关键字参数数量
        posonlyargcount = kwonlyargcount + 1  # C 代码逻辑
        
        # 可选字段标志 (base_val 的位掩码)
        has_defaults = bool(base_val & 0x01)      # bit 0
        has_kwdefaults = bool(base_val & 0x02)    # bit 1  
        has_cellvars_count = bool(base_val & 0x04)  # bit 2
        has_freevars_count = bool(base_val & 0x08)  # bit 3
        has_name = bool(base_val & 0x100)         # bit 8
        has_qualname = bool(base_val & 0x200)     # bit 9
        has_doc = bool(base_val & 0x400)          # bit 10
        has_annotations = bool(base_val & 0x10)   # bit 4 (inferred)
        
        code_info = {
            'type': 'code_object',
            'argcount': argcount,
            'kwonlyargcount': kwonlyargcount,
            'posonlyargcount': posonlyargcount,
        }
        
        # 解析可选字段
        if has_defaults:
            code_info['defaults'] = self.decode_one(bio)
        if has_kwdefaults:
            code_info['kwdefaults'] = self.decode_one(bio)
        if has_annotations:
            code_info['annotations'] = self.decode_one(bio)
        if has_cellvars_count:
            count = read_leb128(bio)
            code_info['cellvars'] = [self.decode_one(bio) for _ in range(count)]
        if has_freevars_count:
            count = read_leb128(bio)
            code_info['freevars'] = [self.decode_one(bio) for _ in range(count)]
        if has_name:
            code_info['name'] = self.decode_one(bio)
        if has_qualname:
            code_info['qualname'] = self.decode_one(bio)
        if has_doc:
            code_info['doc'] = self.decode_one(bio)
            
        # CO flags 计算 (简化)
        co_flags = 0x400000  # CO_NEWLOCALS
        if base_val & 0x40:
            co_flags |= 0x200000  # CO_OPTIMIZED
        if has_extended:
            co_flags |= 0x02
            
        code_info['co_flags'] = co_flags
        return f"<CODE_OBJECT:{code_info}>"


def decode_blob_list(bio: io.BytesIO, count: int) -> List[Any]:
    """解析多个 blob 对象"""
    parser = BlobParser()
    return [parser.decode_one(bio) for _ in range(count)]


def parse_blob_file(filepath: str, target_name: str = "__main__") -> Optional[List[Any]]:
    """
    解析 Nuitka blob 文件
    
    :param filepath: blob 文件路径
    :param target_name: 要解析的 blob 名称,默认 "__main__"
    :return: 解析结果列表,或 None
    """
    with open(filepath, "rb") as f:
        data = f.read()
    
    bio = io.BytesIO(data)
    
    # 文件头: hash(4) + total_size(4)
    hash_val = read_uint32(bio)
    total_size = read_uint32(bio)
    
    while bio.tell() < total_size:
        # 读取 blob 名称 (null-terminated)
        name_bytes = b""
        while True:
            c = bio.read(1)
            if not c or c == b"\x00":
                break
            name_bytes += c
        blob_name = name_bytes.decode("utf-8", errors="replace")
        
        # 读取 blob 元数据
        blob_size = read_uint32(bio)
        blob_count = read_uint16(bio)
        
        if blob_name == target_name:
            print(f"[+] Decoding '{blob_name}': size={blob_size}, count={blob_count}")
            return decode_blob_list(bio, blob_count)
        else:
            # 跳过非目标 blob
            bio.seek(blob_size - 2, io.SEEK_CUR)
    
    print(f"[-] Blob '{target_name}' not found")
    return None


def main():
    if len(sys.argv) < 2:
        print(f"Usage: {sys.argv[0]} <blob_file> [blob_name]")
        print(f"  blob_name: default is '__main__'")
        return
    
    filepath = sys.argv[1]
    target = sys.argv[2] if len(sys.argv) > 2 else "__main__"
    
    try:
        results = parse_blob_file(filepath, target)
        if results:
            print(f"\n[+] Decoded {len(results)} objects:")
            for i, obj in enumerate(results):
                # 限制长对象输出
                obj_repr = repr(obj)
                if len(obj_repr) > 200:
                    obj_repr = obj_repr[:197] + "..."
                print(f"  [{i:3d}] {obj_repr}")
    except Exception as e:
        print(f"[!] Error: {e}", file=sys.stderr)
        if '--debug' in sys.argv:
            raise


if __name__ == "__main__":
    main()

代码运行后结果:
[Python] 纯文本查看 复制代码
[+] Decoding '__main__': size=1579, count=83

[+] Decoded 83 objects:
  [  0] [b'dc!a;`b', '<PREDEFINED_FLOAT_17>', b'cacg', '<PREDEFINED_FLOAT_47>', b'\x19e!!(', '<PREDEFINED_FLOAT_14>', b'\x1fb&', '<PREDEFINED_FLOAT_14>', b'\x08be#', b'ppp']
  [  1] '_parts'
  [  2] 81
  [  3] '_key'
  [  4] 30
  [  5] '_total_len'
  [  6] '解密单个字符'
  [  7] 'current'
  [  8] '_decrypt_char'
  [  9] '获取指定位置的字符'
  [ 10] 'self'
  [ 11] '_get_char_at_position'
  [ 12] '验证用户输入'
  [ 13] 'total'
  [ 14] '计算校验和'
  [ 15] ''
  [ 16] 'flag'
  [ 17] 'checksum'
  [ 18] '获取目标校验和'
  [ 19] 'hashlib'
  [ 20] 'sha256'
  [ 21] 'encode'
  [ 22] 'hexdigest'
  [ 23] slice(None, 8, None)
  [ 24] 16
  [ 25] '哈希函数'
  [ 26] 305419896
  [ 27] -94069293185
  [ 28] 1380994890
  [ 29] 'hash_input'
  [ 30] '假检查'
  [ 31] 'print'
  [ 32] ('==================================================',)
  [ 33] ('   CrackMe Challenge - Binary Edition',)
  [ 34] ('Keywords: 52pojie, 2026, Happy New Year',)
  [ 35] ('Hint: 1337 5p34k & 5ymb0l5!',)
  [ 36] ('      Try to decompile this in IDA!',)
  [ 37] ('--------------------------------------------------',)
  [ 38] 'CrackMeCore'
  [ 39] '\n[?] Enter the password: '
  [ 40] 'fake_check'
  [ 41] ('\n[!] Close, but not quite there...',)
  [ 42] '\nPress Enter to exit...'
  [ 43] 'verify'
  [ 44] 'get_target_checksum'
  [ 45] ('\n==================================================',)
  [ 46] ('        *** SUCCESS! ***',)
  [ 47] ('[+] L33T H4X0R!',)
  [ 48] '[+] Your answer: '
  [ 49] '\n[!] Checksum mismatch: '
  [ 50] ' != '
  [ 51] ('\n[X] Access Denied!',)
  [ 52] ('[X] Wrong password!',)
  [ 53] '主函数'
  [ 54] '__doc__'
  [ 55] '__file__'
  [ 56] '__cached__'
  [ 57] '__annotations__'
  [ 58] 'sys'
  [ 59] '__main__'
  [ 60] '__module__'
  [ 61] '核心验证类 - 将被编译成二进制'
  [ 62] '__qualname__'
  [ 63] '__init__'
  [ 64] 'CrackMeCore.__init__'
  [ 65] 'CrackMeCore._decrypt_char'
  [ 66] 'CrackMeCore._get_char_at_position'
  [ 67] 'CrackMeCore.verify'
  [ 68] 'CrackMeCore.checksum'
  [ 69] 'CrackMeCore.get_target_checksum'
  [ 70] 'main'
  [ 71] ('\n\n[!] Interrupted',)
  [ 72] 'crackme_hard.py'
  [ 73] '<module>'
  [ 74] ('self',)
  [ 75] ('self', 'part_idx', 'char_idx', 'encrypted_byte')
  [ 76] ('self', 'pos', 'current', 'part_idx', 'part')
  [ 77] ('self', 's', 'total', 'i', 'c')
  [ 78] ('user_input', 'fake_hashes', 'user_hash')
  [ 79] ('self', 'flag', 'i')
  [ 80] ('s',)
  [ 81] ('core', 'user_input', 'cs', 'target')
  [ 82] ('self', 'user_input', 'i', 'expected')

看起来像那么回事了,需要我们猜测解密的方式,我们可以参照初级题目中的python代码来进行合理猜测
下面是初级题目的python代码
[Python] 纯文本查看 复制代码
# Decompiled with PyLingual ([url=https://pylingual.io]https://pylingual.io[/url])
# Internal filename: 'crackme_easy.py'
# Bytecode version: 3.14rc3 (3627)
# Source timestamp: 1970-01-01 00:00:00 UTC (0)

import hashlib
import base64
import sys
def xor_decrypt(data, key):
    """XOR解密"""
    result = bytearray()
    for i, byte in enumerate(data):
        result.append(byte ^ key ^ i & 255)
    return result.decode('utf-8', errors='ignore')
def get_encrypted_flag():
    """获取加密的flag"""
    enc_data = 'e3w+fiRvfW18fnx4ZAZ6Pj43YwB9OWMXfXo8Dg4O'
    return base64.b64decode(enc_data)
def generate_flag():
    """动态生成flag"""
    encrypted = get_encrypted_flag()
    key = 78
    result = bytearray()
    for i, byte in enumerate(encrypted):
        result.append(byte ^ key)
    return result.decode('utf-8')
def calculate_checksum(s):
    """计算校验和"""
    total = 0
    for i, c in enumerate(s):
        total += ord(c) * (i + 1)
    return total
def hash_string(s):
    """计算字符串哈希"""
    return hashlib.sha256(s.encode()).hexdigest()
def verify_flag(user_input):
    """验证flag"""
    correct_flag = generate_flag()
    if len(user_input)!= len(correct_flag):
        return False
    else:
        for i in range(len(correct_flag)):
            if user_input[i]!= correct_flag[i]:
                return False
        return True
def fake_check_1(user_input):
    """假检查1"""
    fake_hash = 'a1b2c3d4e5f67890abcdef1234567890abcdef1234567890abcdef1234567890'
    return hash_string(user_input) == fake_hash
def fake_check_2(user_input):
    """假检查2"""
    fake_hash = '1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef'
    return hash_string(user_input) == fake_hash
def main():
    """主函数"""
    print('==================================================')
    print('   CrackMe Challenge - Python Edition')
    print('==================================================')
    print('Keywords: 52pojie, 2026, Happy New Year')
    print('Hint: Decompile me if you can!')
    print('--------------------------------------------------')
    user_input = input('\n[?] Enter the password: ').strip()
    if fake_check_1(user_input):
        print('\n[!] Nice try, but not quite right...')
        input('\nPress Enter to exit...')
        return None
    else:
        if fake_check_2(user_input):
            print('\n[!] You\'re getting closer...')
            input('\nPress Enter to exit...')
        else:
            if verify_flag(user_input):
                checksum = calculate_checksum(user_input)
                expected_checksum = calculate_checksum(generate_flag())
                if checksum == expected_checksum:
                    print('\n==================================================')
                    print('        *** SUCCESS! ***')
                    print('==================================================')
                    print('[+] Congratulations! You cracked it!')
                    print(f'[+] Correct flag: {user_input}')
                else:
                    print('\n[!] Checksum failed!')
            else:
                print('\n[X] Access Denied!')
                print('[X] Wrong password. Keep trying!')
            input('\nPress Enter to exit...')
if __name__ == '__main__':
    try:
        main()
    except KeyboardInterrupt:
        print('\n\n[!] Interrupted by user')
        sys.exit(0)


结合分析得到解密代码
[Python] 纯文本查看 复制代码
def decrypt_flag():
    """解密 crackme_hard.py 中的正确 flag"""
    
    # ========== 原始加密数据(从 Nuitka Blob 提取) ==========
    # 格式:bytes 数据 和 标记数字交替出现
    parts = [
        b'dc!a;`b',   # [0] → 52p0j13
        17,           # [1] → @  (17 ^ 81 = 64)
        b'cacg',      # [2] → 2026
        47,           # [3] → ~  (47 ^ 81 = 126)
        b'\x19e!!(',  # [4] → H4ppy
        14,           # [5] → _  (14 ^ 81 = 95)
        b'\x1fb&',    # [6] → N3w
        14,           # [7] → _  (14 ^ 81 = 95)
        b'\x08be#',   # [8] → Y34r
        b'ppp',       # [9] → !!!
    ]
    
    key = 81          # XOR 密钥
    total_len = 30    # flag 总长度
    
    flag_chars = []
    
    # ========== 逐部分解密 ==========
    for part in parts:
        if isinstance(part, bytes):
            # bytes 类型:每个字节 XOR key
            for byte in part:
                decrypted_char = chr(byte ^ key)
                flag_chars.append(decrypted_char)
        elif isinstance(part, int):
            # int 类型(标记数字):直接 XOR key
            decrypted_char = chr(part ^ key)
            flag_chars.append(decrypted_char)
        else:
            # 字符串类型(如果有)
            for char in part:
                decrypted_char = chr(ord(char) ^ key)
                flag_chars.append(decrypted_char)
    
    # 拼接得到完整 flag
    correct_flag = ''.join(flag_chars)
    
    return correct_fla


最终flag是52p0j13@2026~H4ppy_N3w_Y34r!!!

免费评分

参与人数 3威望 +2 吾爱币 +101 热心值 +3 收起 理由
杨辣子 + 1 + 1 谢谢@Thanks!
Hmily + 2 + 100 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
Coxxs + 1 用心讨论,共获提升!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

沙发
shyjeai 发表于 2026-3-4 10:52
看代码就头疼
3#
geesehoward 发表于 2026-3-4 11:03
版本问题,导致脚本总报错,所以最后干脆IDA直接调试,内存拿结果了。这种异或后逐字节比对的方式,内存调试直接了当,暴力美学。另外,crackme_hard.dll不需要任何工具解原exe,在用户的AppData\Local\Temp目录下,会自动释放。
4#
 楼主| 神奇的人鱼 发表于 2026-3-4 11:12 |楼主
geesehoward 发表于 2026-3-4 11:03
版本问题,导致脚本总报错,所以最后干脆IDA直接调试,内存拿结果了。这种异或后逐字节比对的方式,内存调 ...

是的,内存调试是另一种方法了,大佬也写一个帖子学习一下
5#
xiaomumu 发表于 2026-3-4 11:25
感谢分享~~
6#
Hmily 发表于 2026-3-4 12:20
大佬的文章帮助了很多同学解密这次活动,赞一个!
7#
 楼主| 神奇的人鱼 发表于 2026-3-4 12:24 |楼主
Hmily 发表于 2026-3-4 12:20
大佬的文章帮助了很多同学解密这次活动,赞一个!

能帮助大家,倍感荣幸
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-3-4 15:12

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表