首页
社区
课程
招聘
HKCERT CTF 部分Re题解
发表于: 3天前 1924

HKCERT CTF 部分Re题解

3天前
1924

闲来无事,勾栏解题,看了看香港的这个网安夺旗赛,感觉题目质量都挺高的,写一个博客记录一下我做的几题

file
IDA分析报错,需要首先查看具体什么原因
file
decompress是异或,其实从compress这个词我们就知道应该是对数据做一些处理了,处理的数据正好就是传参的verify函数
file
看到verify函数我们会发现有很多,所以一个个手动解混淆花费的时间有点多,根据decompress的传参我们可以发现每一个verify的字节大小都是86,但是每一个verify的传参不一致,但是写脚本获取传参过于麻烦,发现参数都在-128-128之间,正确的话前四个字节必然是F3 0F 1E FA,直接梭就完事了,就不需要读取decompress传入的参数了。

IDApython直接识别开始爆破,修复后可能IDA还识别不过来,这个时候可以保存好patch后的附件,或者跑下面的IDApython代码重新识别

file

弄好之后小时的代码都回来了
file
每一次都是前后两个位置的异或等于一个值,继续搓脚本输出他,把每一位结果记录下来,构建约束关系,然后z3梭哈
file

file

file

file
Script语句中把解密后的源码打印出来即可
file

file
解包
file
随便解密就好了:

IL2CPP的题目,正好之前有过一段时间的研究。
file
用户输入产生MBTI数据,需要产生一一对应的数据
首先还是利用dumper把符号表之类的dump下来
恢复符号表啥的操作就不细说了详情可以看https://bbs.kanxue.com/thread-282821.htm
先用Dnspy观察:
file
可以发现逻辑不多,分析起来难度不会很大
根据Il2cpp的特性,我们知道方法传入的a1其实就是这个类里面一些成员变量组成的结构体之类的,我们可以通过偏移来推断到底是个什么类:
file
像这个charList就是a1+0x30:
于是我们在GameBehaviour__OnClick中就可以发现如下逻辑了:

file
首先看到偏移0x48就是InputName,在onclick中查找
不难发现:

file
这一段就是获取了onClick和charList,做一些基础的对象的处理
下面就是关键逻辑了:
file

调试发现,这里利用我们输入的名字在table中取了索引,然后对索引做了一个似乎是0x24进制的操作,储存到一个值中,我们可以看到UnityEngine_Random__InitState这个是Unity的一个设置随机中的的方法,类似于srand。
接下来过了一些基础操作就可以看到下一个关键逻辑了:

file
这里的0xc其实就是对应题目的12个MBTI
那么MBTI的生成逻辑肯定在里面
file
发现就是利用seed产生的value做运算了
file
到这里比较就完事了。
我们新建一个Unity项目
编辑->资源->创建一个C#脚本
然后点击我们的Main Camera,给Main Camera添加一个组件
file
添加我们的脚本进去,就可以执行我们的脚本了,正好一个很巧的事情发生了,一开始随便输入了一个1,然后程序居然正确了
file
这样正好给我们提供了一个测试思路的用例,1的索引正好就是1,我们写脚本验证一下
这里脚本需要注意:
file
继承的类得是MonoBehavior

file
对应上了,我们就直接开始爆破了

这里我只写了六位数据的爆破,需要跑大概半个小时,前面1-5个长度的名字基本都在一分钟内,五个长度需要一分钟
file
写个脚本整理结果就好了

file

import re
import idautils
import idaapi
import idc
 
def find_specific_verify_exports():
    """
    查找导出表中名称以 _Z8verify_ 或 _Z9verify_ 开头且后面接一个数字的函数,并返回其名称和地址。
    """
    verify_exports = []
    pattern = re.compile(r"^_Z(?:8|9)verify_(\d+)"# 匹配 _Z8verify_ 或 _Z9verify_ 后接数字的格式
 
    for i in range(idaapi.get_entry_qty()):
        ordinal = idaapi.get_entry_ordinal(i)
        func_name = idaapi.get_entry_name(ordinal)
 
        # 检查函数名是否符合指定格式
        if func_name and pattern.match(func_name):
            func_addr = idaapi.get_entry(ordinal)
            verify_exports.append((func_name, func_addr))
 
    return verify_exports
 
def xor_bytes(data, key):
    """将给定数据中的每个字节与指定的key进行异或"""
    return bytes([b ^ key for b in data])
 
def patch_memory(address, xor_key):
    """直接对内存中的数据进行补丁"""
    original_data = idc.get_bytes(address, 86# 读取从 address 到 address+85 的字节
    if not original_data:
        print(f"无法读取地址 {hex(address)} 的数据")
        return False
     
    # 对数据进行异或
    patched_data = xor_bytes(original_data, xor_key)
     
    # 写入补丁数据到内存中
    for offset, byte in enumerate(patched_data):
        idc.patch_byte(address + offset, byte)
     
    print(f"已在内存中补丁地址范围 {hex(address)} 到 {hex(address+85)},使用异或键 {xor_key}")
    return True
 
def process_address_range(address):
    """处理给定地址,尝试找到满足条件的异或数字并应用补丁"""
    original_data = idc.get_bytes(address, 86# 读取从 address 到 address+85 的字节
    if not original_data:
        print(f"无法读取地址 {hex(address)} 的数据")
        return None
     
    for xor_key in range(-255, 256):
        xor_key &= 0xFF  # 保证异或键值在 0 到 255 的范围内
        # 取地址到地址+3的数据并与当前 xor_key 异或
        test_data = xor_bytes(original_data[:4], xor_key)
         
        # 检查异或后的前四个字节是否等于 F3 0F 1E FA
        if test_data == b'\xF3\x0F\x1E\xFA':
            # 满足条件时,直接补丁内存
            if patch_memory(address, xor_key):
                print(f"成功对地址 {hex(address)} 应用补丁,异或键为 {xor_key}")
            return xor_key
 
    print(f"地址 {hex(address)} 没有找到满足条件的异或键")
    return None
 
# 获取符合条件的地址列表并进行补丁
filtered_exports = find_specific_verify_exports()
if filtered_exports:
    print("开始处理符合条件的 'verify' 函数地址...")
    for func_name, func_addr in filtered_exports:
        print(f"Processing function: {func_name} at Address: {hex(func_addr)}")
        process_address_range(func_addr)
else:
    print("No specific 'verify' functions found in export table.")
import re
import idautils
import idaapi
import idc
 
def find_specific_verify_exports():
    """
    查找导出表中名称以 _Z8verify_ 或 _Z9verify_ 开头且后面接一个数字的函数,并返回其名称和地址。
    """
    verify_exports = []
    pattern = re.compile(r"^_Z(?:8|9)verify_(\d+)"# 匹配 _Z8verify_ 或 _Z9verify_ 后接数字的格式
 
    for i in range(idaapi.get_entry_qty()):
        ordinal = idaapi.get_entry_ordinal(i)
        func_name = idaapi.get_entry_name(ordinal)
 
        # 检查函数名是否符合指定格式
        if func_name and pattern.match(func_name):
            func_addr = idaapi.get_entry(ordinal)
            verify_exports.append((func_name, func_addr))
 
    return verify_exports
 
def xor_bytes(data, key):
    """将给定数据中的每个字节与指定的key进行异或"""
    return bytes([b ^ key for b in data])
 
def patch_memory(address, xor_key):
    """直接对内存中的数据进行补丁"""
    original_data = idc.get_bytes(address, 86# 读取从 address 到 address+85 的字节
    if not original_data:
        print(f"无法读取地址 {hex(address)} 的数据")
        return False
     
    # 对数据进行异或
    patched_data = xor_bytes(original_data, xor_key)
     
    # 写入补丁数据到内存中
    for offset, byte in enumerate(patched_data):
        idc.patch_byte(address + offset, byte)
     
    print(f"已在内存中补丁地址范围 {hex(address)} 到 {hex(address+85)},使用异或键 {xor_key}")
    return True
 
def process_address_range(address):
    """处理给定地址,尝试找到满足条件的异或数字并应用补丁"""
    original_data = idc.get_bytes(address, 86# 读取从 address 到 address+85 的字节
    if not original_data:
        print(f"无法读取地址 {hex(address)} 的数据")
        return None
     
    for xor_key in range(-255, 256):
        xor_key &= 0xFF  # 保证异或键值在 0 到 255 的范围内
        # 取地址到地址+3的数据并与当前 xor_key 异或
        test_data = xor_bytes(original_data[:4], xor_key)
         
        # 检查异或后的前四个字节是否等于 F3 0F 1E FA
        if test_data == b'\xF3\x0F\x1E\xFA':
            # 满足条件时,直接补丁内存
            if patch_memory(address, xor_key):
                print(f"成功对地址 {hex(address)} 应用补丁,异或键为 {xor_key}")
            return xor_key
 
    print(f"地址 {hex(address)} 没有找到满足条件的异或键")
    return None
 
# 获取符合条件的地址列表并进行补丁
filtered_exports = find_specific_verify_exports()
if filtered_exports:
    print("开始处理符合条件的 'verify' 函数地址...")
    for func_name, func_addr in filtered_exports:
        print(f"Processing function: {func_name} at Address: {hex(func_addr)}")
        process_address_range(func_addr)
else:
    print("No specific 'verify' functions found in export table.")
import re
import idautils
import idaapi
import idc
 
# 步骤2:删除所有现有的函数定义
print("Starting to undefine all existing functions...")
for func_ea in idautils.Functions():
    func_name = idc.get_func_name(func_ea)
    print(f"Undefining function {func_name} at {hex(func_ea)}")
    idc.del_func(func_ea)  # 删除函数定义
 
print("All functions have been undefined.")
 
# 步骤3:将所有代码区域设置为未定义状态,但跳过数据段
print("Setting all instructions and data to undefined in code segments...")
for seg_ea in idautils.Segments():
    # 跳过数据段,仅处理代码段
    if idc.get_segm_attr(seg_ea, idc.SEGATTR_TYPE) != idc.SEG_CODE:
        print(f"Skipping data segment at {hex(seg_ea)}")
        continue
 
    start = seg_ea
    end = idc.get_segm_end(seg_ea)
     
    # 遍历段中的每个地址,并将其设置为未定义
    for head in idautils.Heads(start, end):
        idc.del_items(head, idc.DELIT_SIMPLE)  # 将所有指令和数据设置为未定义
 
print("All code in code segments set to undefined.")
 
# 步骤4:重新标记整个程序的代码段以进行重新分析
print("Marking all code segments for reanalysis...")
for seg_ea in idautils.Segments():
    if idc.get_segm_attr(seg_ea, idc.SEGATTR_TYPE) == idc.SEG_CODE:
        ida_auto.auto_mark_range(seg_ea, idc.get_segm_end(seg_ea), ida_auto.AU_CODE)
 
ida_auto.auto_wait()  # 等待重新分析完成
 
print("Reanalyzed all code segments, excluding data segments.")
import re
import idautils
import idaapi
import idc
 
# 步骤2:删除所有现有的函数定义
print("Starting to undefine all existing functions...")
for func_ea in idautils.Functions():
    func_name = idc.get_func_name(func_ea)
    print(f"Undefining function {func_name} at {hex(func_ea)}")
    idc.del_func(func_ea)  # 删除函数定义
 
print("All functions have been undefined.")
 
# 步骤3:将所有代码区域设置为未定义状态,但跳过数据段
print("Setting all instructions and data to undefined in code segments...")
for seg_ea in idautils.Segments():
    # 跳过数据段,仅处理代码段
    if idc.get_segm_attr(seg_ea, idc.SEGATTR_TYPE) != idc.SEG_CODE:
        print(f"Skipping data segment at {hex(seg_ea)}")
        continue
 
    start = seg_ea
    end = idc.get_segm_end(seg_ea)
     
    # 遍历段中的每个地址,并将其设置为未定义
    for head in idautils.Heads(start, end):
        idc.del_items(head, idc.DELIT_SIMPLE)  # 将所有指令和数据设置为未定义
 
print("All code in code segments set to undefined.")
 
# 步骤4:重新标记整个程序的代码段以进行重新分析
print("Marking all code segments for reanalysis...")
for seg_ea in idautils.Segments():
    if idc.get_segm_attr(seg_ea, idc.SEGATTR_TYPE) == idc.SEG_CODE:
        ida_auto.auto_mark_range(seg_ea, idc.get_segm_end(seg_ea), ida_auto.AU_CODE)
 
ida_auto.auto_wait()  # 等待重新分析完成
 
print("Reanalyzed all code segments, excluding data segments.")
import re
import idaapi
import idautils
import idc
 
def find_specific_verify_exports():
    """
    查找导出表中名称以 _Z8verify_ 或 _Z9verify_ 开头且后面接一个数字的函数,并返回其名称和地址。
    """
    verify_exports = []
    pattern = re.compile(r"^_Z(?:8|9)verify_(\d+)"# 匹配 _Z8verify_ 或 _Z9verify_ 后接数字的格式
 
    for i in range(idaapi.get_entry_qty()):
        ordinal = idaapi.get_entry_ordinal(i)
        func_name = idaapi.get_entry_name(ordinal)
 
        # 检查函数名是否符合指定格式
        if func_name and pattern.match(func_name):
            func_addr = idaapi.get_entry(ordinal)
            verify_exports.append((func_name, func_addr))
 
    return verify_exports
 
def extract_equation_from_verify(func_addr):
    """
    从每个 verify 函数中提取 mov esi 和 cmp al 指令来生成方程。
    """
    esi_values = []
    cmp_value = None
 
    # 遍历函数指令,直到找到目标指令或到达函数结束
    for instr_addr in idautils.FuncItems(func_addr):
        mnemonic = idc.print_insn_mnem(instr_addr)
         
        # 查找 mov esi, <imm> 指令
        if mnemonic == "mov" and "esi" in idc.print_operand(instr_addr, 0):
            esi_value = idc.get_operand_value(instr_addr, 1)
            esi_values.append(esi_value)
         
        # 查找 cmp al, <imm> 指令
        elif mnemonic == "cmp" and "al" in idc.print_operand(instr_addr, 0):
            cmp_value = idc.get_operand_value(instr_addr, 1)
         
        # 当找到两个 esi 值和一个 cmp 值时,可以生成方程
        if len(esi_values) == 2 and cmp_value is not None:
            break
 
    # 确保收集到所有所需的值
    if len(esi_values) == 2 and cmp_value is not None:
        equation = f"input[0x{esi_values[0]:X}] ^ input[0x{esi_values[1]:X}] == 0x{cmp_value:X}"
        return equation
    else:
        return None
 
# 主函数,获取所有符合条件的 verify 函数并提取方程
filtered_exports = find_specific_verify_exports()
if filtered_exports:
    print("生成 verify 函数的方程:")
    for func_name, func_addr in filtered_exports:
        equation = extract_equation_from_verify(func_addr)
        if equation:
            print(f"{func_name}: {equation}")
        else:
            print(f"{func_name}: 无法生成方程")
else:
    print("未找到符合条件的 'verify' 函数")
import re
import idaapi
import idautils
import idc
 
def find_specific_verify_exports():
    """
    查找导出表中名称以 _Z8verify_ 或 _Z9verify_ 开头且后面接一个数字的函数,并返回其名称和地址。
    """
    verify_exports = []
    pattern = re.compile(r"^_Z(?:8|9)verify_(\d+)"# 匹配 _Z8verify_ 或 _Z9verify_ 后接数字的格式
 
    for i in range(idaapi.get_entry_qty()):
        ordinal = idaapi.get_entry_ordinal(i)
        func_name = idaapi.get_entry_name(ordinal)
 
        # 检查函数名是否符合指定格式
        if func_name and pattern.match(func_name):
            func_addr = idaapi.get_entry(ordinal)
            verify_exports.append((func_name, func_addr))
 
    return verify_exports
 
def extract_equation_from_verify(func_addr):
    """
    从每个 verify 函数中提取 mov esi 和 cmp al 指令来生成方程。
    """
    esi_values = []
    cmp_value = None
 
    # 遍历函数指令,直到找到目标指令或到达函数结束
    for instr_addr in idautils.FuncItems(func_addr):
        mnemonic = idc.print_insn_mnem(instr_addr)
         
        # 查找 mov esi, <imm> 指令
        if mnemonic == "mov" and "esi" in idc.print_operand(instr_addr, 0):
            esi_value = idc.get_operand_value(instr_addr, 1)
            esi_values.append(esi_value)
         
        # 查找 cmp al, <imm> 指令
        elif mnemonic == "cmp" and "al" in idc.print_operand(instr_addr, 0):
            cmp_value = idc.get_operand_value(instr_addr, 1)
         
        # 当找到两个 esi 值和一个 cmp 值时,可以生成方程
        if len(esi_values) == 2 and cmp_value is not None:
            break
 
    # 确保收集到所有所需的值
    if len(esi_values) == 2 and cmp_value is not None:
        equation = f"input[0x{esi_values[0]:X}] ^ input[0x{esi_values[1]:X}] == 0x{cmp_value:X}"
        return equation
    else:
        return None
 
# 主函数,获取所有符合条件的 verify 函数并提取方程
filtered_exports = find_specific_verify_exports()
if filtered_exports:
    print("生成 verify 函数的方程:")
    for func_name, func_addr in filtered_exports:
        equation = extract_equation_from_verify(func_addr)
        if equation:
            print(f"{func_name}: {equation}")
        else:
            print(f"{func_name}: 无法生成方程")
else:
    print("未找到符合条件的 'verify' 函数")
from z3 import *
 
# 创建 0x37(55)个字节的输入变量(假设从 input[0] 到 input[0x36])
input_vars = [BitVec(f'input_{i}', 8) for i in range(0x37)]
 
# 初始化 Z3 Solver
solver = Solver()
 
# 添加方程到 solver
constraints = [
    input_vars[0x0] ^ input_vars[0x1] == 0x3,
    input_vars[0x1] ^ input_vars[0x2] == 0x8,
    input_vars[0x2] ^ input_vars[0x3] == 0x6,
    input_vars[0x3] ^ input_vars[0x4] == 0x17,
    input_vars[0x4] ^ input_vars[0x5] == 0x6,
    input_vars[0x5] ^ input_vars[0x6] == 0x46,
    input_vars[0x6] ^ input_vars[0x7] == 0x6,
    input_vars[0x7] ^ input_vars[0x8] == 0x4F,
    input_vars[0x8] ^ input_vars[0x9] == 0x8,
    input_vars[0x9] ^ input_vars[0xA] == 0x40,
    input_vars[0xA] ^ input_vars[0xB] == 0x5F,
    input_vars[0xB] ^ input_vars[0xC] == 0xA,
    input_vars[0xC] ^ input_vars[0xD] == 0x39,
    input_vars[0xD] ^ input_vars[0xE] == 0x32,
    input_vars[0xE] ^ input_vars[0xF] == 0x5D,
    input_vars[0xF] ^ input_vars[0x10] == 0x54,
    input_vars[0x10] ^ input_vars[0x11] == 0x55,
    input_vars[0x11] ^ input_vars[0x12] == 0x57,
    input_vars[0x12] ^ input_vars[0x13] == 0x1F,
    input_vars[0x13] ^ input_vars[0x14] == 0x48,
    input_vars[0x14] ^ input_vars[0x15] == 0x5F,
    input_vars[0x15] ^ input_vars[0x16] == 0x9,
    input_vars[0x16] ^ input_vars[0x17] == 0x38,
    input_vars[0x17] ^ input_vars[0x18] == 0x3C,
    input_vars[0x18] ^ input_vars[0x19] == 0x53,
    input_vars[0x19] ^ input_vars[0x1A] == 0x54,
    input_vars[0x1A] ^ input_vars[0x1B] == 0x57,
    input_vars[0x1B] ^ input_vars[0x1C] == 0x6C,
    input_vars[0x1C] ^ input_vars[0x1D] == 0x2B,
    input_vars[0x1D] ^ input_vars[0x1E] == 0x1C,
    input_vars[0x1E] ^ input_vars[0x1F] == 0x58,
    input_vars[0x1F] ^ input_vars[0x20] == 0x6F,
    input_vars[0x20] ^ input_vars[0x21] == 0x2B,
    input_vars[0x21] ^ input_vars[0x22] == 0x1C,
    input_vars[0x22] ^ input_vars[0x23] == 0x59,
    input_vars[0x23] ^ input_vars[0x24] == 0x4,
    input_vars[0x24] ^ input_vars[0x25] == 0x6A,
    input_vars[0x25] ^ input_vars[0x26] == 0x36,
    input_vars[0x26] ^ input_vars[0x27] == 0x5C,
    input_vars[0x27] ^ input_vars[0x28] == 0x6A,
    input_vars[0x28] ^ input_vars[0x29] == 0x31,
    input_vars[0x29] ^ input_vars[0x2A] == 0x5E,
    input_vars[0x2A] ^ input_vars[0x2B] == 0x64,
    input_vars[0x2B] ^ input_vars[0x2C] == 0xB,
    input_vars[0x2C] ^ input_vars[0x2D] == 0x1E,
    input_vars[0x2D] ^ input_vars[0x2E] == 0x1E,
    input_vars[0x2E] ^ input_vars[0x2F] == 0x32,
    input_vars[0x2F] ^ input_vars[0x30] == 0x59,
    input_vars[0x30] ^ input_vars[0x31] == 0x58,
    input_vars[0x31] ^ input_vars[0x32] == 0x1B,
    input_vars[0x32] ^ input_vars[0x33] == 0x43,
    input_vars[0x33] ^ input_vars[0x34] == 0x46,
    input_vars[0x34] ^ input_vars[0x35] == 0x41,
    input_vars[0x35] ^ input_vars[0x36] == 0x4E
]
 
# 将所有约束添加到 solver 中
for constraint in constraints:
    solver.add(constraint)
 
# 添加输入的范围约束
for var in input_vars:
    solver.add(var >= 0x20, var <= 0x7E# 限制每个 input 变量在可见 ASCII 字符范围内
 
# 找到并展示所有解
solutions = []
while solver.check() == sat:
    model = solver.model()
    solution = [model[input_vars[i]].as_long() for i in range(0x37)]
    solutions.append(solution)
 
    # 将解转换为排除条件,确保寻找不同的解
    solver.add(Or([input_vars[i] != solution[i] for i in range(0x37)]))
 
# 输出所有解
for i, solution in enumerate(solutions, 1):
    readable_solution = ''.join(chr(val) for val in solution)
    print(f"解 {i}: {readable_solution}")
from z3 import *
 
# 创建 0x37(55)个字节的输入变量(假设从 input[0] 到 input[0x36])
input_vars = [BitVec(f'input_{i}', 8) for i in range(0x37)]
 
# 初始化 Z3 Solver
solver = Solver()
 
# 添加方程到 solver
constraints = [
    input_vars[0x0] ^ input_vars[0x1] == 0x3,
    input_vars[0x1] ^ input_vars[0x2] == 0x8,
    input_vars[0x2] ^ input_vars[0x3] == 0x6,
    input_vars[0x3] ^ input_vars[0x4] == 0x17,
    input_vars[0x4] ^ input_vars[0x5] == 0x6,
    input_vars[0x5] ^ input_vars[0x6] == 0x46,
    input_vars[0x6] ^ input_vars[0x7] == 0x6,
    input_vars[0x7] ^ input_vars[0x8] == 0x4F,
    input_vars[0x8] ^ input_vars[0x9] == 0x8,
    input_vars[0x9] ^ input_vars[0xA] == 0x40,
    input_vars[0xA] ^ input_vars[0xB] == 0x5F,
    input_vars[0xB] ^ input_vars[0xC] == 0xA,
    input_vars[0xC] ^ input_vars[0xD] == 0x39,
    input_vars[0xD] ^ input_vars[0xE] == 0x32,
    input_vars[0xE] ^ input_vars[0xF] == 0x5D,
    input_vars[0xF] ^ input_vars[0x10] == 0x54,
    input_vars[0x10] ^ input_vars[0x11] == 0x55,
    input_vars[0x11] ^ input_vars[0x12] == 0x57,
    input_vars[0x12] ^ input_vars[0x13] == 0x1F,
    input_vars[0x13] ^ input_vars[0x14] == 0x48,
    input_vars[0x14] ^ input_vars[0x15] == 0x5F,
    input_vars[0x15] ^ input_vars[0x16] == 0x9,
    input_vars[0x16] ^ input_vars[0x17] == 0x38,
    input_vars[0x17] ^ input_vars[0x18] == 0x3C,
    input_vars[0x18] ^ input_vars[0x19] == 0x53,
    input_vars[0x19] ^ input_vars[0x1A] == 0x54,
    input_vars[0x1A] ^ input_vars[0x1B] == 0x57,
    input_vars[0x1B] ^ input_vars[0x1C] == 0x6C,
    input_vars[0x1C] ^ input_vars[0x1D] == 0x2B,
    input_vars[0x1D] ^ input_vars[0x1E] == 0x1C,
    input_vars[0x1E] ^ input_vars[0x1F] == 0x58,
    input_vars[0x1F] ^ input_vars[0x20] == 0x6F,
    input_vars[0x20] ^ input_vars[0x21] == 0x2B,
    input_vars[0x21] ^ input_vars[0x22] == 0x1C,
    input_vars[0x22] ^ input_vars[0x23] == 0x59,
    input_vars[0x23] ^ input_vars[0x24] == 0x4,
    input_vars[0x24] ^ input_vars[0x25] == 0x6A,
    input_vars[0x25] ^ input_vars[0x26] == 0x36,
    input_vars[0x26] ^ input_vars[0x27] == 0x5C,
    input_vars[0x27] ^ input_vars[0x28] == 0x6A,
    input_vars[0x28] ^ input_vars[0x29] == 0x31,
    input_vars[0x29] ^ input_vars[0x2A] == 0x5E,
    input_vars[0x2A] ^ input_vars[0x2B] == 0x64,
    input_vars[0x2B] ^ input_vars[0x2C] == 0xB,
    input_vars[0x2C] ^ input_vars[0x2D] == 0x1E,
    input_vars[0x2D] ^ input_vars[0x2E] == 0x1E,
    input_vars[0x2E] ^ input_vars[0x2F] == 0x32,
    input_vars[0x2F] ^ input_vars[0x30] == 0x59,
    input_vars[0x30] ^ input_vars[0x31] == 0x58,
    input_vars[0x31] ^ input_vars[0x32] == 0x1B,
    input_vars[0x32] ^ input_vars[0x33] == 0x43,
    input_vars[0x33] ^ input_vars[0x34] == 0x46,
    input_vars[0x34] ^ input_vars[0x35] == 0x41,
    input_vars[0x35] ^ input_vars[0x36] == 0x4E
]
 
# 将所有约束添加到 solver 中
for constraint in constraints:
    solver.add(constraint)
 
# 添加输入的范围约束
for var in input_vars:
    solver.add(var >= 0x20, var <= 0x7E# 限制每个 input 变量在可见 ASCII 字符范围内
 

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 3
支持
分享
最新回复 (4)
雪    币: 10
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
请问你你开头提到的ida那个报错是什么原因导致的呢
3天前
0
雪    币: 1459
活跃值: (1906)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
3
mb_ldbucrik 请问你你开头提到的ida那个报错是什么原因导致的呢
估计是SMC导致IDA认为的堆栈不平衡,去掉smc就正常了
3天前
0
雪    币: 1379
活跃值: (2769)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
感谢分享
2天前
0
雪    币: 2047
活跃值: (2582)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
5
感谢分享
18小时前
0
游客
登录 | 注册 方可回帖
返回
//