检测是否是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())