能力值:
( LV1,RANK:0 )
2 楼
pe用miasm,triton的多估计
能力值:
( LV9,RANK:195 )
3 楼
miasm用的比较多
能力值:
( LV2,RANK:10 )
4 楼
这些都是基础的运行环境或者运行框架 unicorn这类肯定是必须要有的 但是要完成你的去除混淆逻辑代码的效果 直接使用这些工具都是不能达到目的
能力值:
( LV1,RANK:0 )
5 楼
感觉可以试试LLVM去混淆框架,在外网还看过拿这个去VMP虚拟化的文章。这玩意可以拿来还原二进制文件,个人比较看好它的潜能,一个是LLVM IR的可操作性、文档、生态都比较好,还有就是因为本质上是代码的同语义变换,我觉得可以做一些额外的事,也许是辅助理解Shellcode,也许是处理一些叫不上名字的混淆手法(这里点名微软)
能力值:
( LV1,RANK:0 )
6 楼
同意
能力值:
( LV2,RANK:10 )
7 楼
tron主要用来逆向分析算法的
能力值:
( LV2,RANK:10 )
8 楼
Q: 有个场景,在这个函数内,他经过多重加密多重拷贝,最后得到一个数据,我要如何做? A:太棒了!你已经完成了最困难的部分——靠自己的经验和智慧理解了算法。现在,你想用更现代化的方法“复现”一遍,这正是从“高手”向“专家”迈进的关键一步。 这个场景(单函数内多重加密和拷贝)是绝佳的练习靶场。下面我为你设计一个详细、可操作的流程,教你如何使用现代化工具来自动化地解决你手动解决的问题。 我们将使用一个强大的、在逆向圈非常流行的Python库 **Triton**。它把污点分析和符号执行完美地结合在了一起,非常适合这个场景。 --- ### 准备工作 1. **安装Triton**: ```bash pip install triton ``` 2. **明确目标**: * 你的目标二进制文件。 * 你要分析的那个函数的**起始地址**和**结束地址**。 * 函数开始时,**原始明文**在哪个寄存器或内存地址。 * 函数结束时,**最终密文**在哪个寄存器或内存地址。 --- ### 第一阶段:使用“污点分析”自动过滤无用拷贝 **目标**:你手动逆向时,肯定花费了大量时间去跟踪数据在 `MOV`, `memcpy`, `PUSH`/`POP` 中是如何被搬来搬去。污点分析可以帮你**在几秒钟内**过滤掉这些“噪音”,只显示真正进行加密运算的“信号”。 #### **操作步骤:** 1. **编写Python脚本**: 创建一个Python文件,我们将用Triton库来模拟执行这个函数。 2. **初始化环境**: ```python from triton import * # --- 1. 初始化 Triton 上下文 --- ctx = TritonContext() ctx.setArchitecture(ARCH.X86_64) # 或者 ARCH.X86 # --- 2. 加载二进制代码 --- # 假设你已经将函数的所有机器码dump了出来 # 为简单起见,我们直接将代码映射到内存 binary_code = b"\x48\x89\xce\x48\x8b\..." # 这里是你的函数机器码 FUNC_START_ADDR = 0x401000 FUNC_END_ADDR = 0x401234 ctx.set_concrete_memory_area_value(FUNC_START_ADDR, binary_code) # --- 3. 设置初始状态 --- # 假设明文在 RSI 指向的内存,密钥在 RDI # 你需要根据你的实际情况设置寄存器和内存 ctx.set_concrete_register_value(ctx.registers.rsp, 0x7fffffff) # ... 设置其他需要的寄存器 ... # 将你的明文加载到内存 plaintext = b"THIS_IS_MY_DATA" PLAINTEXT_ADDR = 0x100000 ctx.set_concrete_memory_area_value(PLAINTEXT_ADDR, plaintext) ctx.set_concrete_register_value(ctx.registers.rsi, PLAINTEXT_ADDR) ``` 3. **标记“污染源”**: 这是污点分析的核心。告诉Triton,我们的明文是“脏”的。 ```python # 将我们存放明文的内存区域标记为污点 print(f"[*] Tainting the plaintext memory at {hex(PLAINTEXT_ADDR)}") ctx.taint_memory(PLAINTEXT_ADDR, len(plaintext)) ``` 4. **模拟执行并检测“有效指令”**: ```python print("\n[*] Starting emulation and taint analysis...") pc = FUNC_START_ADDR while pc != FUNC_END_ADDR: # 获取当前地址的机器码 opcode = ctx.get_concrete_memory_area_value(pc, 16) # 创建指令 instruction = Instruction() instruction.setOpcode(opcode) instruction.setAddress(pc) # 模拟执行这条指令 ctx.processing(instruction) # *** 关键:判断这条指令是否是我们关心的 *** # 我们只关心那些“被污染的”且“不是简单移动”的指令 # isTainted() 检查指令的操作数是否被污染 if instruction.isTainted() and not instruction.isControlFlow() and instruction.getType() not in [OPCODE.MOV, OPCODE.LEA, OPCODE.PUSH, OPCODE.POP]: print(f"---> Found interesting instruction at {hex(pc)}: {instruction.getDisassembly()}") # 更新PC到下一条指令 pc = ctx.get_concrete_register_value(ctx.registers.rip) print("\n[*] Analysis finished.") ``` #### **预期结果** 运行这个脚本后,你不会看到函数内成百上千条指令的完整列表。相反,你只会得到一个非常短的列表,其中包含的都是类似 `XOR EAX, EBX`、`ADD ECX, EDX`、`ROL EAX, 2` 这样的指令。 **你已经用自动化方式,完成了手动逆向中最繁琐的一步:从大量的拷贝和地址计算中,分离出了真正的加密核心逻辑。** --- ### 第二阶段:使用“符号执行”自动理解算法 **目标**:现在我们已经知道了哪些指令是核心。接下来,我们让机器去“理解”这些指令组合起来的数学意义。 #### **操作步骤:** 我们将修改刚才的脚本,从污点分析模式切换到符号执行模式。 1. **清理和切换**: 注释掉 `ctx.taint_memory(...)` 这行。 2. **“符号化”输入**: 不再给具体明文,而是给一个“符号”。 ```python # 以前是加载具体数据,现在是符号化这片内存 # ctx.set_concrete_memory_area_value(PLAINTEXT_ADDR, plaintext) print(f"[*] Symbolizing the plaintext memory at {hex(PLAINTEXT_ADDR)}") for i in range(len(plaintext)): ctx.symbolize_memory(MemoryAccess(PLAINTEXT_ADDR + i, CPUSIZE.BYTE)) ``` 3. **模拟执行**: 执行循环和之前一样,但Triton内部现在处理的不再是具体数值,而是数学表达式。 4. **获取最终的“数学公式”**: ```python # ... 执行完上面的循环后 ... print("\n[*] Emulation finished. Analyzing symbolic expressions.") # 假设最终的密文被存放在 RAX 寄存器里 final_expr_in_rax = ctx.get_symbolic_expression_from_id(ctx.get_symbolic_register_id(ctx.registers.rax)) print("\n[+] The algorithm's formula for RAX is:") print(final_expr_in_rax) ``` #### **预期结果** 这次,脚本最后会打印出一个复杂的、像Lisp语言一样的表达式。它可能长这个样子: ``` (bvxor (_ bv213 64) (bvrol (bvadd (bvxor (concat (_ bv0 56) (mem_100000_1_8)) (_ bv123 64)) (_ bv456 64) ) (_ bv2 64) ) ) ``` **这串天书,就是你手动逆向出来的加密算法的数学本质!** * `bvxor` 就是 `XOR`。 * `bvadd` 就是 `ADD`。 * `bvrol` 就是 `ROL` (循环左移)。 * `(mem_100000_1_8)` 就是我们定义的符号变量,代表明文的第一个字节。 #### **更进一步:让机器帮你解密** 你还可以用Triton的约束求解器来“逆转”这个公式。 ```python # 问一个问题:如果我想让最终RAX的值是 0xABCDEF,我的明文第一个字节应该是什么? target_ciphertext = 0xABCDEF1234567890 # 获取明文第一个字节的符号变量 plaintext_byte_0_var = ctx.get_symbolic_variable_from_id(ctx.get_symbolic_memory_id(PLAINTEXT_ADDR)) # 添加约束 constraint = final_expr_in_rax == target_ciphertext model = ctx.getModel(constraint) if model: solution = model[plaintext_byte_0_var.getId()].getValue() print(f"\n[+] Solution found! To get {hex(target_ciphertext)}, plaintext byte 0 must be: {hex(solution)}") ``` ### 总结 这个流程完美复现了你的手动工作,并且将其自动化: 1. **污点分析** 帮你回答了 **“哪些代码是重要的?”**,它自动过滤了所有的内存拷贝。 2. **符号执行** 帮你回答了 **“这些重要代码在干什么?”**,它自动推导出了算法的数学公式,甚至还能帮你求解(即解密)。 通过这个练习,你就能深刻体会到现代化工具如何将逆向工程师从繁重、重复的劳动中解放出来,让你能更专注于算法本身的设计和逻辑。