问题描述
这是我的问题:我试图反编译隐藏在预编译项目中的给定函数的代码,所以我看不到代码,只是原型。
int removeFromStack(tStack *p,void *d,unsigned cantBytes);
但是我从那个特定的函数中得到了这个伪代码,它包含了更多的参数:
__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;
}
为什么会这样?
我真的不明白为什么
编辑:
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
编辑#2
我使用了相同的项目,但使用的是 32 位版本而不是 x64 版本,现在我得到了这个:
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
解决方法
看起来你正在反编译,好像这是 x86-64 System V 调用约定(RCX 中的第四个参数,a1=RDI,a2=RSI,a3=RDX),
但实际上它是 Windows x64(RCX 中的第一个参数,然后是 RDX、R8、R9)。
@NateEldredge 在评论中对此的猜测是正确的。
这就解释了为什么将参数传递给 free
是错误的(实际上是 *first_arg
然后是 first_arg
),以及为什么它发明了未使用的虚拟参数 a1..3。好吧,实际上它认为 a1 和 a2(RDI 和 RSI)不变地传递给 memcpy。然后释放两次,因为我猜它假设 RDI 没有改变,即使在 memcpy 返回后没有再次设置它。编译器当然不会生成依赖于损坏寄存器值的代码,所以这应该是向 IDA 暗示该代码没有使用它假设的调用约定。
所以告诉 IDA 你的代码来自哪里(Windows),这样它就知道要假设什么调用约定。 (我不知道 IDA,但我可以从 asm 和 C 中看出这是问题所在。)