Reputation: 823
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
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
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