堆栈指针分析失败

逆向工程 艾达 反编译 混淆 反编译器
2021-06-30 17:41:22

我正在针对 IDA 的反编译器测试我的玩具混淆 C 编译器,但 IDA 拒绝始终运行(那么反编译是不可能的)。例如,在混淆的最低级别之一,函数喜欢

int foo(int i) {
  return i;
}

被编译为

0x0         40 55                          push rbp
0x2         48 89 e5                       mov rbp, rsp
0x5         41 56                          push r14
0x7         41 57                          push r15
0x9         48 83 ec 10                    sub rsp, 0x10
0xd         40 89 bc 24 0c 00 00 00        mov [rsp+0xc], edi
0x15        48 8d 05 e4 ff ff ff           lea rax, [rip-0x1c]
0x1c        44 8b bc 24 0c 00 00 00        mov r15d, [rsp+0xc]
0x24        44 8b b4 24 0c 00 00 00        mov r14d, [rsp+0xc]
0x2c        45 0f af fe                    imul r15d, r14d
0x30        44 89 f9                       mov ecx, r15d
0x33        83 c1 01                       add ecx, 0x1
0x36        44 8b b4 24 0c 00 00 00        mov r14d, [rsp+0xc]
0x3e        45 0f af f7                    imul r14d, r15d
0x42        48 63 c9                       movsxd rcx, ecx
0x45        49 63 d6                       movsxd rdx, r14d
0x48        48 39 d1                       cmp rcx, rdx
0x4b        0f 95 c1                       setnz cl
0x4e        40 84 c9                       test cl, cl
0x51        75 1c                          jnz 0x1c
0x53        44 8b bc 24 0c 00 00 00        mov r15d, [rsp+0xc]
0x5b        49 63 cf                       movsxd rcx, r15d
0x5e        44 8b bc 24 0c 00 00 00        mov r15d, [rsp+0xc]
0x66        44 89 ff                       mov edi, r15d
0x69        48 89 c6                       mov rsi, rax
0x6c        40 ff d1                       call rcx
0x6f        44 8b bc 24 0c 00 00 00        mov r15d, [rsp+0xc]
0x77        44 89 f8                       mov eax, r15d
0x7a        48 83 c4 10                    add rsp, 0x10
0x7e        41 5f                          pop r15
0x80        41 5e                          pop r14
0x82        40 5d                          pop rbp
0x84        c3                             ret

我仍然不明白为什么这种情况下堆栈帧分析会失败。修改指令只有两组rsp,前5组:

0x0         40 55                          push rbp
0x2         48 89 e5                       mov rbp, rsp
0x5         41 56                          push r14
0x7         41 57                          push r15
0x9         48 83 ec 10                    sub rsp, 0x10

最后5个:

0x7a        48 83 c4 10                    add rsp, 0x10
0x7e        41 5f                          pop r15
0x80        41 5e                          pop r14
0x82        40 5d                          pop rbp
0x84        c3                             ret

它们实际上使堆栈指针平衡。

我该如何解决?

更新:@chentiangemalc 建议它来自call rcx,然后我将混淆选项更改为不生成此类调用,并删除了几乎所有其他混淆选项,以下是一个更简单的结果

0x0         40 55                          push rbp
0x2         48 89 e5                       mov rbp, rsp
0x5         40 53                          push rbx
0x7         48 83 ec 08                    sub rsp, 0x8
0xb         c1 ef 00                       shr edi, 0x0
0xe         89 f8                          mov eax, edi
0x10        81 c8 33 19 d0 39              or eax, 0x39d01933
0x16        89 f9                          mov ecx, edi
0x18        81 e1 33 19 d0 39              and ecx, 0x39d01933
0x1e        0f af c1                       imul eax, ecx
0x21        40 b9 33 19 d0 39              mov ecx, 0x39d01933
0x27        89 ca                          mov edx, ecx
0x29        f7 d2                          not edx
0x2b        89 fb                          mov ebx, edi
0x2d        21 d3                          and ebx, edx
0x2f        f7 d7                          not edi
0x31        21 f9                          and ecx, edi
0x33        0f af d9                       imul ebx, ecx
0x36        01 d8                          add eax, ebx
0x38        81 c0 31 d6 93 7f              add eax, 0x7f93d631
0x3e        40 b9 fb 89 99 8c              mov ecx, 0x8c9989fb
0x44        0f af c1                       imul eax, ecx
0x47        81 c0 f5 c4 23 fd              add eax, -0x2dc3b0b
0x4d        48 8d 8c 24 04 00 00 00        lea rcx, [rsp+0x4]
0x55        40 89 01                       mov [rcx], eax
0x58        48 8d 84 24 04 00 00 00        lea rax, [rsp+0x4]
0x60        40 8b 00                       mov eax, [rax]
0x63        48 83 c4 08                    add rsp, 0x8
0x67        40 5b                          pop rbx
0x69        40 5d                          pop rbp
0x6b        c3                             ret

但 IDA 总是抱怨sp-analysis failed((我把 ELF 放在这里)。

不过,其他工具如 Ghidra 或 JEB Decompiler 很高兴地识别出该功能。

更新:@chentiangemalc 的方法完美运行。对于上面的示例,不幸的是,有些情况下 IDA 并不满意(示例:ELF

1个回答

当我组装代码时,有问题的指令是:

0x6c        40 ff d1                       call rcx

您将需要在 IDA 中使用Change Stack Pointer命令来在反汇编中修复此问题。根据 IDA 文档:

  • 此命令允许您指定当前指令如何修改堆栈指针 (SP)。
  • 如果当前指令不属于任何功能,则不能使用该命令。
  • 仅当 IDA 无法跟踪 SP 寄存器的值时,您才需要使用此命令。
  • 通常 IDA 可以处理它,但在某些特殊情况下它会失败。这种情况的一个例子是从堆栈中清除其参数的函数的间接调用。在这种情况下,IDA 没有关于函数的信息,无法正确跟踪 SP 的值。
  • 请注意,您需要指定 SP 的新旧值之间的差异。
  • 如果当前函数通过 [ESP+xxx] 符号访问局部变量,则使用 SP 的值。

这也可以通过删除 call rcx 指令并确认它删除 IDA 中的 SP 分析失败错误来验证。

基于上传 ELF 的第二个版本,问题是 IDA 没有正确检测到函数的结束。

在此处输入图片说明

在函数视图中右键单击函数foo并选择编辑函数并将结束地址更改为 0:000000000000006C 修复了 SP 分析问题。

对 SP 分析故障进行故障排除时,还启用选项中的堆栈指针| 常规和选择堆栈指针可以帮助您确定问题的原因,这将在指令左侧以绿色文本显示堆栈指针值。

在此处输入图片说明

第三个样本提供了同样的问题。要查找函数结束,切换到文本视图查找retn 的偏移量并添加一个,例如提供的最后一个示例中的函数结束是5D5。

问题的根本原因是开始时冗余的 REX 前缀 (0x40)。正常的 64 位函数序言以 55 48 89 E5 开头,因此 IDA 尝试在地址 1 创建一个函数,该函数会干扰 0 处的实际函数并使其在一条指令后停止。这计划在 IDA 的未来版本中修复。