IDA Pro 显示了一个数组,其中应该有两个变量

逆向工程 艾达 六线谱 德尔福
2021-06-12 10:40:10

我正在使用 Delphi 二进制文件,在生成伪代码时发现了一个小问题。这是 IDA 给我的输出(经过一些清理):

Integer __fastcall LBCommon::TLBMemStream::GetFromId(PLBMemStream Self, Integer Id)
{
  int v4[2]; // [esp+0h] [ebp-10h] BYREF

  if ( LBCommon::IndexFromId(Self->FFullData, Id, &v4[1]) )
    v4[0] = &Self->FFullData[*&Self->FFullData[sizeof(TLBDataEntry) * v4[1] + 0x19] + offsetof(TLBDataItem, FData)];
  else
    v4[0] = 0;
  return v4[0];
}

如您所见,它只是一段简单的代码,它执行一些简单的数学运算然后返回。但是有一个问题:v4 表示为一个整数数组,而不是两个分隔的变量。

理论上,v4[0] 是一个指向将被返回的内存的“指针”,而 v4[1] 是一个应该有多次前进的变量。但是 IDA 将它们视为一个数组并将它们粘在一起。我尝试通过将类型设置为“int v4”来分离它们并且它起作用了,但是 IDA 然后告诉我:

/局部变量分配失败,输出可能有误!

它还显示了用红色生成的两个变量,表明出现问题。

我不太了解 IDA 如何从 ASM 生成伪代码,但我认为问题在于代码如何访问内存区域。对于 v4[0] 它执行“ mov edx, [esp+10h+var_10] ”而对于 v4[1] 它执行“ mov edx, [esp+10h+var_10+4] ” 所以我相信这就是原因它们被视为一个数组。

这是 ASM 中的函数以防万一:

CODE:0046A7E4 var_10          = dword ptr -10h
CODE:0046A7E4
CODE:0046A7E4                 push    ebx
CODE:0046A7E5                 push    esi
CODE:0046A7E6                 add     esp, 0FFFFFFF8h
CODE:0046A7E9                 mov     esi, edx
CODE:0046A7EB                 mov     ebx, eax
CODE:0046A7ED                 lea     ecx, [esp+10h+var_10+4] ; Index
CODE:0046A7F1                 mov     edx, esi        ; FId
CODE:0046A7F3                 mov     eax, [ebx+4]    ; Header
CODE:0046A7F6                 call    LBCommon::IndexFromId
CODE:0046A7FB                 test    al, al
CODE:0046A7FD                 jz      short loc_46A818
CODE:0046A7FF                 mov     eax, [ebx+4]
CODE:0046A802                 mov     edx, [esp+10h+var_10+4]
CODE:0046A806                 mov     eax, [eax+edx*8+19h]
CODE:0046A80A                 mov     edx, [ebx+4]
CODE:0046A80D                 lea     eax, [edx+eax]
CODE:0046A810                 add     eax, 0Dh
CODE:0046A813                 mov     [esp+10h+var_10], eax
CODE:0046A816                 jmp     short loc_46A81D
CODE:0046A818 ; ---------------------------------------------------------------------------
CODE:0046A818
CODE:0046A818 loc_46A818:
CODE:0046A818                 xor     eax, eax
CODE:0046A81A                 mov     [esp+10h+var_10], eax
CODE:0046A81D
CODE:0046A81D loc_46A81D:
CODE:0046A81D                 mov     eax, [esp+10h+var_10]
CODE:0046A820                 pop     ecx
CODE:0046A821                 pop     edx
CODE:0046A822                 pop     esi
CODE:0046A823                 pop     ebx
CODE:0046A824                 retn

有没有办法在不产生错误的情况下解决问题?因为我不相信最初的开发人员在这里使用数组来做这个简单的事情,并且在某些部分已经重复了一段时间的问题。

1个回答

在机器级别上,int[2] 数组、具有两个 int 的结构或两个碰巧并排放置的 int 变量之间没有区别。

此外,有时一个变量可能会分别存储在不同的位置。例如,在 32 位处理器上处理 64 位数字时,编译器必须一次处理 32 位。一种常见的方法是eax用于低部分和edx部分

您的示例的行为似乎非常相似(低部分var_10存储在eaxvar_10+4in 中edx),因此它可能会触发 64 位数学启发式算法,反编译器最初决定这var_10是一个 64 位变量,但后来将其替换为一个二元素数组. 如果没有数据库,很难确定发生了什么。

分离变量的一种可能方法是编辑堆栈帧结构。为此,var_10在反汇编视图或v4伪代码中双击,然后编辑var_10为 dword 而不是 qword ,然后在其后添加另一个 dword。通常这应该向反编译器提示它们是单独的变量。