JustToKnow
JustToKnow

Reputation: 823

De-compiling a C function but obtaining a strange code (too many args, double-free)

I'm new to this topic and I got stuck while trying to decompile a c function.

This is my problem: I was trying to decompile the code of a given function that is hidden in a pre-compiled project so I cannot see the code, just the prototype.

This is my function (I cannot see the code):

int  removeFromStack(tStack *p, void *d, unsigned cantBytes);

But I got this pseudo code from that particular function and it contains much more parameters:

__int64 __fastcall removeFromStack(void *a1, const void *a2, __int64 a3, size_t **a4)
{
  __int64 result; // rax
  size_t *v5; // rbx

  result = 0LL;
  v5 = *a4;
  if ( *a4 )
  {
    *a4 = (size_t *)v5[2];
    memcpy(a1, a2, *v5);
    free(a1);
    free(a1);
    result = 1LL;
  }
  return result;
}

Why is it happening?

I do not really understand why


EDIT:

public removeFromStack
removeFromStack proc near
push    rbx
sub     rsp, 20h
xor     eax, eax
mov     rbx, [rcx]
test    rbx, rbx
mov     r9, rdx
jz      short loc_525

mov     rax, [rbx+10h]
cmp     [rbx+8], r8d
cmovbe  r8d, [rbx+8]
mov     [rcx], rax
mov     rdx, [rbx]      ; Size
mov     rcx, r9
mov     r8d, r8d
call    memcpy
mov     rcx, [rbx]
call    free
mov     rcx, rbx
call    free
mov     eax, 1

loc_525:
add     rsp, 20h
pop     rbx
retn
removeFromStack endp


EDIT #2

image

I used the same project but a 32-bit version instead of the x64 one and now i got this:

int __cdecl removeFromStack(int a1, void *a2, int a3)
{
  int result; // eax
  int Size; // edx
  int Block; // ebx

  result = 0;
  Size = a3;
  Block = *(_DWORD *)a1;
  if ( *(_DWORD *)a1 )
  {
    if ( *(_DWORD *)(Block + 4) <= (unsigned int)a3 )
      Size = *(_DWORD *)(Block + 4);
    *(_DWORD *)a1 = *(_DWORD *)(Block + 8);
    memcpy(a2, *(const void **)Block, Size);
    free(*(void **)Block);
    free((void *)Block);
    result = 1;
  }
  return result;
}

; int __cdecl removeFromStack(int, void *, int)
public _removeFromStack
_removeFromStack proc near

Block= dword ptr -1Ch
Src= dword ptr -18h
Size= dword ptr -14h
arg_0= dword ptr  4
arg_4= dword ptr  8
arg_8= dword ptr  0Ch

push    ebx
xor     eax, eax
sub     esp, 18h
mov     ecx, [esp+1Ch+arg_0]
mov     edx, [esp+1Ch+arg_8]
mov     ebx, [ecx]
test    ebx, ebx
jz      short loc_53D

mov     eax, [ebx+8]
cmp     [ebx+4], edx
cmovbe  edx, [ebx+4]
mov     [ecx], eax
mov     eax, [ebx]
mov     [esp+1Ch+Size], edx ; Size
mov     [esp+1Ch+Src], eax ; Src
mov     eax, [esp+1Ch+arg_4]
mov     [esp+1Ch+Block], eax ; void *
call    _memcpy
mov     eax, [ebx]
mov     [esp+1Ch+Block], eax ; Block
call    _free
mov     [esp+1Ch+Block], ebx ; Block
call    _free
mov     eax, 1

loc_53D:
add     esp, 18h
pop     ebx
retn
_removeFromStack endp

Upvotes: 2

Views: 509

Answers (1)

Peter Cordes
Peter Cordes

Reputation: 364811

Looks like you're decompiling as if this was the x86-64 System V calling convention (4th arg in RCX, with a1=RDI, a2=RSI, a3=RDX),
but actually it's Windows x64 (1st arg in RCX, then RDX, R8, R9).
@NateEldredge's guess about this in comments was right.

That explains why it's wrong about the args being passed to free (it's actually *first_arg and then first_arg), and why it's inventing unused dummy args a1..3. Well, actually it thinks a1 and a2 (RDI and RSI) are passed on unchanged to memcpy. And then to free twice, because I guess it assumes RDI is unchanged even though nothing sets it again after memcpy returns. Compilers would of course not make code that depended on the value of a clobbered register, so this should have been a hint to IDA that this code wasn't using the calling convention it was assuming.

So tell IDA what where your code is from (Windows) so it knows what calling convention to assume. (I don't know IDA, but I can see from the asm and the C that this is the problem.)

Upvotes: 3

Related Questions