From adc345e6a098ed974add212b3b06c28c2ef56e71 Mon Sep 17 00:00:00 2001 From: chyang Date: Mon, 19 May 2025 15:53:33 +0800 Subject: [PATCH 1/3] feat: lab8 --- lab8/solve.py | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/lab8/solve.py b/lab8/solve.py index 9ab3ee2..a28929f 100755 --- a/lab8/solve.py +++ b/lab8/solve.py @@ -1,11 +1,37 @@ #!/usr/bin/env python3 -import angr,sys +import angr +import sys def main(): - secret_key = b"" - sys.stdout.buffer.write(secret_key) - + # 創建一個新的 angr 專案 + proj = angr.Project('./chal', auto_load_libs=False) + + # 創建一個符號輸入 + state = proj.factory.entry_state() + input_str = state.solver.BVS('input', 8 * 8) # 8 bytes, 8 bits each + + # 將輸入寫入 stdin + state.posix.stdin.write(input_str) + + # 創建一個模擬管理器 + simgr = proj.factory.simulation_manager(state) + + # 尋找成功路徑(找到 "Correct!" 字串) + simgr.explore(find=lambda s: b"Correct!" in s.posix.dumps(1)) + + if len(simgr.found) > 0: + # 獲取找到的狀態 + found_state = simgr.found[0] + # 獲取輸入值 + secret_key = found_state.posix.stdin.read(0, 8) + # 求解具體值 + secret_key = found_state.solver.eval(secret_key, cast_to=bytes) + # 輸出結果 + sys.stdout.buffer.write(secret_key) + else: + print("No solution found", file=sys.stderr) + sys.exit(1) if __name__ == '__main__': main() From a7c3330293c685615d1e2965321c7bf25d44ab23 Mon Sep 17 00:00:00 2001 From: chyang Date: Wed, 21 May 2025 15:19:56 +0800 Subject: [PATCH 2/3] fix: lab8 --- lab8/solve.py | 78 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 51 insertions(+), 27 deletions(-) diff --git a/lab8/solve.py b/lab8/solve.py index a28929f..f904ad9 100755 --- a/lab8/solve.py +++ b/lab8/solve.py @@ -1,37 +1,61 @@ #!/usr/bin/env python3 +# solve.py —> 直接從 gate() 模擬,避開所有 C-library 呼叫 -import angr import sys +import angr +import claripy + +KEY_LEN = 8 def main(): - # 創建一個新的 angr 專案 + # 1) 建專案,不載入外部 libc proj = angr.Project('./chal', auto_load_libs=False) - - # 創建一個符號輸入 - state = proj.factory.entry_state() - input_str = state.solver.BVS('input', 8 * 8) # 8 bytes, 8 bits each - - # 將輸入寫入 stdin - state.posix.stdin.write(input_str) - - # 創建一個模擬管理器 - simgr = proj.factory.simulation_manager(state) - - # 尋找成功路徑(找到 "Correct!" 字串) - simgr.explore(find=lambda s: b"Correct!" in s.posix.dumps(1)) - - if len(simgr.found) > 0: - # 獲取找到的狀態 - found_state = simgr.found[0] - # 獲取輸入值 - secret_key = found_state.posix.stdin.read(0, 8) - # 求解具體值 - secret_key = found_state.solver.eval(secret_key, cast_to=bytes) - # 輸出結果 - sys.stdout.buffer.write(secret_key) - else: - print("No solution found", file=sys.stderr) + + # 2) 找到 gate 函式的載入地址 + gate_sym = proj.loader.find_symbol('gate') + if gate_sym is None: + print("找不到 gate 符號!", file=sys.stderr) + sys.exit(1) + gate_addr = gate_sym.rebased_addr + + # 3) blank_state:直接在 gate() 入口開始執行 + state = proj.factory.blank_state(addr=gate_addr) + + # 4) 在 heap 申請 KEY_LEN bytes,並逐字塞入符號變數 + # 從 heap 配置一塊記憶體空間 + buf = state.heap.allocate(KEY_LEN) + + key_vars = [] + # 用符號變數填充 buf + for i in range(KEY_LEN): + b = claripy.BVS(f'k{i}', 8) # 建立 8-bit 的符號變數,代表第 i 個字元 + key_vars.append(b) + state.memory.store(buf + i, b) # 依序寫入 buf 指向的記憶體中的第 i 個位置 + + # 5) 按照 SystemV x86_64 呼叫慣例,第一個參數放在 rdi + state.regs.rdi = buf + + # 避免符號 byte 為 0 / '\n' 造成奇怪結果 + for b in key_vars: + state.solver.add(b != 0) # 不允許是 NULL(0x00),否則 strlen(input) 會提早結束 + state.solver.add(b != 0x0a) # 不允許是換行(0x0a),否則 fgets() 會提早結束 + + # 6) 探索:找到 stdout 含「Correct!」的狀態;避開任何印出「Wrong key!」的分支 + # 建立一個模擬器(Simulation Manager),開始從 state 模擬執行。 + simgr = proj.factory.simgr(state) + # explore() 會自動走過所有可能的分支、跳轉與條件,尋找滿足目標條件的執行路徑。 + simgr.explore( + find=lambda s: b"Correct!" in s.posix.dumps(1), + avoid=lambda s: b"Wrong key!" in s.posix.dumps(1), + ) + + # 7) 取出解並輸出 + if not simgr.found: + print("[-] 沒有找到符合條件的輸入!", file=sys.stderr) sys.exit(1) + found = simgr.found[0] + solution = found.solver.eval(claripy.Concat(*key_vars), cast_to=bytes) + sys.stdout.buffer.write(solution + b'\n') if __name__ == '__main__': main() From 990991e8ba077b94a74338f3d1109fe01d4ba59f Mon Sep 17 00:00:00 2001 From: chyang Date: Wed, 21 May 2025 15:30:20 +0800 Subject: [PATCH 3/3] fix: use .bss section as input buffer --- lab8/solve.py | 51 +++++++++++++++++++++++---------------------------- 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/lab8/solve.py b/lab8/solve.py index f904ad9..0638ddb 100755 --- a/lab8/solve.py +++ b/lab8/solve.py @@ -18,44 +18,39 @@ def main(): sys.exit(1) gate_addr = gate_sym.rebased_addr - # 3) blank_state:直接在 gate() 入口開始執行 - state = proj.factory.blank_state(addr=gate_addr) + # 3) 準備一個 8 字元的符號向量 + sym_in = claripy.BVS('in', KEY_LEN * 8) - # 4) 在 heap 申請 KEY_LEN bytes,並逐字塞入符號變數 - # 從 heap 配置一塊記憶體空間 - buf = state.heap.allocate(KEY_LEN) + # 4) 取一塊 .bss 作為輸入緩衝區,並把符號寫進去 + bss_addr = proj.loader.main_object.sections_map['.bss'].min_addr + # blank_state 只用來寫記憶體 + tmp_state = proj.factory.blank_state() + tmp_state.memory.store(bss_addr, sym_in) - key_vars = [] - # 用符號變數填充 buf - for i in range(KEY_LEN): - b = claripy.BVS(f'k{i}', 8) # 建立 8-bit 的符號變數,代表第 i 個字元 - key_vars.append(b) - state.memory.store(buf + i, b) # 依序寫入 buf 指向的記憶體中的第 i 個位置 - - # 5) 按照 SystemV x86_64 呼叫慣例,第一個參數放在 rdi - state.regs.rdi = buf + # 5) 用 call_state 直接呼 gate(bss_addr) + # 注意這裡的 API:call_state(addr, *args) + state = proj.factory.call_state(gate_addr, bss_addr, base_state=tmp_state) - # 避免符號 byte 為 0 / '\n' 造成奇怪結果 - for b in key_vars: - state.solver.add(b != 0) # 不允許是 NULL(0x00),否則 strlen(input) 會提早結束 - state.solver.add(b != 0x0a) # 不允許是換行(0x0a),否則 fgets() 會提早結束 + # 6) 加入避免 strlen/fgets 斷掉的約束 + for i in range(KEY_LEN): + byte = claripy.Extract(i * 8 + 7, i * 8, sym_in) + state.solver.add(byte != 0) # 不允許 0x00 + state.solver.add(byte != 0x0a) # 不允許 '\n' - # 6) 探索:找到 stdout 含「Correct!」的狀態;避開任何印出「Wrong key!」的分支 - # 建立一個模擬器(Simulation Manager),開始從 state 模擬執行。 + # 7) 探索:stdout 含 "Correct!" 停止;含 "Wrong key!" 的路徑避開 simgr = proj.factory.simgr(state) - # explore() 會自動走過所有可能的分支、跳轉與條件,尋找滿足目標條件的執行路徑。 simgr.explore( - find=lambda s: b"Correct!" in s.posix.dumps(1), - avoid=lambda s: b"Wrong key!" in s.posix.dumps(1), + find = lambda s: b"Correct!" in s.posix.dumps(1), + avoid= lambda s: b"Wrong key!" in s.posix.dumps(1), ) - # 7) 取出解並輸出 if not simgr.found: - print("[-] 沒有找到符合條件的輸入!", file=sys.stderr) + print("[-] 沒找到符合條件的輸入!", file=sys.stderr) sys.exit(1) - found = simgr.found[0] - solution = found.solver.eval(claripy.Concat(*key_vars), cast_to=bytes) - sys.stdout.buffer.write(solution + b'\n') + + # 8) 取出解並輸出 + sol = simgr.found[0].solver.eval(sym_in, cast_to=bytes) + sys.stdout.buffer.write(sol + b'\n') if __name__ == '__main__': main()