1

I'm working in a Delphi binary and found a little issue while generating pseudocode. This is the output (after some clean up) that IDA gives me:

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];
}

As you can see, it is just a simple piece of code where it does some simple math en then returns. But there is a problem: v4 is represented as an array of integers instead of two separated variables.

In theory, v4[0] is a "Pointer" to memory that will be returned while v4[1] is a variable that should have a number of times to advance. But IDA thinks of them as an array and just sticks them together. I tried separating them by setting the type to "int v4" and it worked, but IDA then told me:

/ local variable allocation has failed, the output may be wrong!

It also shows the two variables generated with the color red signaling that something is wrong.

I don't know a lot about how IDA generates the Pseudocode from the ASM, but I believe that the issue is with how the code access the memory regions. For v4[0] it does "mov edx, [esp+10h+var_10]" and for v4[1] it does "mov edx, [esp+10h+var_10+4]" so I believe that it is the reason why they are seen as an array.

Here is the function in ASM just in case:

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

Is there a way to fix the issue without generating an error? Because I don't believe the original developers used an array here to do this simple thing and it is a problem that has been repeating itself for a while in some parts.

1 Answer 1

3

On the machine level, there is no difference between an int[2] array, a structure with two ints, or two int variables that happen to be placed next to each other.

In addition, sometimes one variable may be stored separately in different locations. For example, when dealing with 64-bit numbers on 32-bit processors, the compiler has to work with 32 bits at a time. A common aproach is to use eax for the low part and edx for the high.

Your sample seems to be behaving quite similarly (low part of var_10 is stored in eax and var_10+4 in edx), so possibly it triggers 64-bit math heuristics and the decompiler initially decides that var_10 is one 64-bit variable but later replaces it by a two-element array. It's difficult to say what's happening for sure without the database.

One possible way to separate the variables is to edit the stack frame structure. For this, double-click var_10 in disassembly view or v4 in pseudocode, then edit var_10 to be a dword instead of qword an add another dword after it. Normally this should give a hint to the decompiler that they are separate variables.

1
  • Your solution worked perfectly. Thank you very much!
    – Ricardo
    Aug 17, 2021 at 17:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.