mapmap2

作者:shixz 发布时间: 2025-10-05 阅读量:2 评论数:0

检测是否是wasd,0x440009,00000000 01000100 00000000 00001001,刚好是bit0 ,3, 18, 22刚好加97是wasd

用v10的高四位,低四位进行判断。查找v10数组的第i位。

能辨别这是一个走迷宫的程序,但是由于init_map函数太大了,难以反编译,无法进行静态分析的。只能使用gdb来dump了。

把堆给dump下来

#!/usr/bin/env python3

import networkx as nx
from hashlib import md5

map_entry = 0x65b3c0
map_exit = 0x667b40
heap_base = 0x640000 
# --------------------

# Load the heap dump file
try:
    with open('./heap', 'rb') as f:
        heap = f.read()
except FileNotFoundError:
    exit()

def get_bytes_at(addr, size):
    assert addr >= heap_base and addr + size <= heap_base + len(heap), \
        f"地址 {hex(addr)} 超出了堆内存范围 ({hex(heap_base)} - {hex(heap_base + len(heap))})"
    return heap[addr - heap_base: addr - heap_base + size]

def get_number_at(addr, size):
    return int.from_bytes(get_bytes_at(addr, size), 'little')

def get_dword_at(addr):
    return get_number_at(addr, 4)

def get_qword_at(addr):
    return get_number_at(addr, 8)

# Functions for C++ std::map (Red-Black Tree) traversal
def map_get_parent(node):
    return get_qword_at(node + 0x8)

def map_get_left(node):
    return get_qword_at(node + 0x10)

def map_get_right(node):
    return get_qword_at(node + 0x18)

def map_get_successor(map_addr, node):
    nil = map_addr + 8
    right = map_get_right(node)
    if right != 0 and right != nil:
        parent = right
        while True:
            left = map_get_left(parent)
            if left == nil or left == 0: return parent
            parent = left
    else:
        parent = map_get_parent(node)
        while map_get_right(parent) == node:
            node = parent
            parent = map_get_parent(node)
        return parent

def map_get_key(node):
    # Key is int (4 bytes) at offset 0x20
    return get_dword_at(node + 0x20)

def map_get_value(node):
    # Value is std::unordered_map* at offset 0x28 (node pointer)
    return node + 0x28

def map_get_items(map_addr):
    items = []
    nil = map_addr + 0x08
    min_node = get_qword_at(map_addr + 0x18)
    max_node = get_qword_at(map_addr + 0x20)

    if min_node == nil or min_node == 0: return items
    
    iter_node = min_node
    items.append(iter_node)
    
    while iter_node != max_node:
        iter_node = map_get_successor(map_addr, iter_node)
        if iter_node == nil or iter_node == 0: break 
        items.append(iter_node)
    return items

def unordered_map_get_items(map_value_addr):
    items = []
    iter_node = get_qword_at(map_value_addr + 0x10) 
    
    while iter_node != 0:
        items.append(iter_node)
        iter_node = get_qword_at(iter_node)
    return items

def unordered_map_get_key(node):
    # Key is int (4 bytes) at offset 0x8
    return get_dword_at(node + 0x8)

def unordered_map_get_value(node):
    # Value is the pointer to the next map object (8 bytes) at offset 0x10
    return get_qword_at(node + 0x10)


# --- Graph Construction and Path Finding ---
G = nx.DiGraph()
nodes = {}
nodes_to_process = {map_entry}
nodes_processed = set()

print(f"开始图遍历: {hex(map_entry)} -> {hex(map_exit)} (堆基址: {hex(heap_base)})")

while nodes_to_process:
    node = nodes_to_process.pop()
    nodes_processed.add(node)
    
    try:
        # Outer map: map<int, unordered_map<int, void*>>
        for item in map_get_items(node):
            # Key 'h' (高 4 位)
            h = map_get_key(item)
            
            # Inner map: unordered_map<int, void*>
            for inner_item in unordered_map_get_items(map_get_value(item)):
                # Key 'l' (低 4 位)
                l = unordered_map_get_key(inner_item)
                # Value is the pointer to the next map (node)
                _node = unordered_map_get_value(inner_item)
                
                if _node == 0: continue # NULL 
                
                # Check for new nodes to process (graph traversal)
                if _node not in nodes_processed and _node not in nodes_to_process:
                    nodes_to_process.add(_node)
                
                # Store the byte (h << 4) | l as the edge weight/label
                # The byte is constructed from the high nibble (h) and low nibble (l)
                if node not in nodes: nodes[node] = {}
                nodes[node][_node] = (h << 4) | l
                
                # Add edge to the graph
                G.add_edge(node, _node)

    except AssertionError:
        # 警告: 如果读取地址超出了堆转储范围,通常是遇到了指向堆外部的地址,跳过此节点。
        continue

# Find the shortest path between the entry and exit maps
try:
    path = nx.shortest_path(G, map_entry, map_exit)
except nx.NetworkXNoPath:
    print(f"\n致命错误: 在 {hex(map_entry)} 和 {hex(map_exit)} 之间未找到路径。")
    print("请检查你的地址和堆转储文件是否正确。")
    exit()

# Extract the input bytes from the path
input_bytes = []
for i in range(len(path) - 1):
    a = path[i]
    b = path[i + 1]
    # The byte is the value stored for the edge (a -> b)
    input_bytes.append(nodes[a][b])

final_input = bytes(input_bytes)

# Final calculation
print('\n--- 结果 ---')
print(f"路径长度 (节点数): {len(path)}")
print(f"输入数据长度 (字节数): {len(final_input)}")
# assert len(final_input) == 268 # 校验长度

# Final Flag Generation
print('\n--- FLAG ---')
print('SUCTF{%s}' % md5(final_input).hexdigest())

评论