c - 反编译一个 C 函数但得到一个奇怪的代码(参数太多,双重释放)
问题描述
我是这个话题的新手,在尝试反编译 ac 函数时遇到了困难。
这是我的问题:我试图反编译隐藏在预编译项目中的给定函数的代码,所以我看不到代码,只能看到原型。
这是我的功能(我看不到代码):
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 中的第 4 个参数,a1=RDI,a2=RSI,a3=RDX),
但实际上它是 Windows x64(RCX 中的第一个参数,然后RDX,R8,R9)。
@NateEldredge 在评论中对此的猜测是正确的。
这就解释了为什么将 args 传递给free
(实际上是*first_arg
then first_arg
)是错误的,以及为什么它发明了未使用的虚拟 args a1..3。好吧,实际上它认为 a1 和 a2(RDI 和 RSI)被原封不动地传递给 memcpy。然后释放两次,因为我猜它假设 RDI 没有改变,即使在 memcpy 返回后没有再次设置它。编译器当然不会生成依赖于被破坏寄存器的值的代码,所以这应该是对 IDA 的一个提示,即这段代码没有使用它假设的调用约定。
所以告诉 IDA 你的代码来自哪里(Windows),这样它就知道要假设什么调用约定。(我不知道 IDA,但我可以从 asm 和 C 中看出这是问题所在。)
推荐阅读
- css - CSS 转换在边框中显示背景颜色
- c++ - Chilkat 示例,linkSample.cpp 程序,无法编译
- android - 如何在登录活动中添加“记住我”?
- linux - whl 文件不是此平台上支持的轮子 - 我该如何解决?
- javascript - 使用 react-router 的无效挂钩调用 useSelector()
- python - 在 Simulink 中调用具有多个输出的 Python 函数
- swift - 迁移以更改 CoreData 的配置
- elasticsearch - kibana 中可用的已解析数据的问题
- android - 每次使用具有不同 TextView 的适配器
- excel - 全局变量在用户表单后失去价值