我用IDA pro反汇编了一个可执行文件。我的目标是挂钩__usercall函数。我知道我需要在我的C ++代码中使用inine asm包装__usercall,因为我无法键入def函数。但我不确定这是如何运作的。
我知道该函数将对象作为参数,将* Vector3作为参数,其中将存储计算值。有没有一种简单的方法来判断哪个参数将是什么?
(对不起长代码)
char __usercall sub_572EA0<al>(int a1<ecx>, int a2<edx>, int a3<eax>, int a4)
{
int v4; // edi@1
int v5; // esi@1
float v6; // eax@2
char v7; // al@3
int v8; // eax@5
char result; // al@11
int v10; // [sp+Ch] [bp-74h]@2
float v11; // [sp+10h] [bp-70h]@4
float v12; // [sp+14h] [bp-6Ch]@4
float v13; // [sp+18h] [bp-68h]@5
float v14; // [sp+1Ch] [bp-64h]@5
float v15; // [sp+20h] [bp-60h]@5
float v16; // [sp+24h] [bp-5Ch]@10
float v17; // [sp+28h] [bp-58h]@10
float v18; // [sp+2Ch] [bp-54h]@10
char v19; // [sp+30h] [bp-50h]@10
float v20; // [sp+3Ch] [bp-44h]@4
float v21; // [sp+40h] [bp-40h]@4
float v22; // [sp+44h] [bp-3Ch]@4
float v23; // [sp+54h] [bp-2Ch]@7
v4 = a3;
v5 = a1;
if ( a3 )
{
LODWORD(v6) = sub_55A920(*(_DWORD *)(a1 + 208));
if ( !sub_53ADD0(
v5,
v6,
v4,
(int)&v10) )
{
v7 = sub_4EC240(v4);
sub_4E3ED0(
1,
"Cannot find tag [%s]\n",
v7);
}
}
else
{
sub_572BE0();
*(float *)&v10 = *(float *)(v5 + 20) + v20;
v11 = *(float *)(v5 + 24) + v21;
v12 = *(float *)(v5 + 28) + v22;
}
v8 = dword_8FF12C;
v13 = flt_96A218;
v14 = flt_96A21C;
v15 = flt_96A220;
if ( dword_8FF12C == 2047 )
v8 = dword_8FF1D0;
sub_462250(
&v23,
&v13,
&v10,
&unk_82D6A0,
v8,
8400899);
if ( 1.0 == v23
|| (unsigned __int16)sub_492C50(&v23) == *(_DWORD *)(v5 + 208)
|| *(_UNKNOWN **)(v5 + 364) == &unk_FFFFFF
&& (v16 = v13
+ (*(float *)&v10 - v13)
* v23,
v17 = (v11 - v14) * v23 + v14,
v18 = v23 * (v12 - v15) + v15,
sub_4C35B0(
&v16,
v5 + 20,
v5 + 32,
&v19),
sub_432850(
*(_DWORD *)(v5 + 348),
&v19)) )
result = sub_550250(a4, &v13, &v10);
else
result = 0;
return result;
}
ASM可能是错误的,这样的事情会接近吗?
// Don't know what params goes where, ie: where the Vec3 goes and where the object goes
int __stdcall func_hook(param1, param2, param3, param4);
// Where to put the address? -->> 0x572EA0
// char __usercall sub_572EA0<al>(int a1<ecx>, int a2<edx>, int a3<eax>, int a4);
__declspec(naked) void func_hook()
{__asm{
push ebp
mov ebp, esp
mov ecx param1
mov edx param2
mov eax param3
push param4
call func_hook
leave
ret
}}
这段代码中缺少的一件事是用户调用的地址(0x572EA0)。不确定把它放在哪里......
这是程序调用函数的方式。电话在底部: http://i43.tinypic.com/2mez9c8.jpg
答案 0 :(得分:2)
你挂钩的那个函数是Borland __fastcall
,而不是__usercall
(事实上实际上没有这样的约定,它只是IDA的“未知约定”的版本)。
在使用内联asm挂钩时,ECX
,EDX
和EAX
是临时寄存器,所以我们不需要保留它们,并且调用很好我们不需要担心堆栈:
static DWORD the_hook_address = 0x572EA0;
//init this somewhere with the correct (Base + RVA) address in case of module relocation (from ASLR etc.)
__declspec(naked) bool __stdcall the_hook(int a1, int a2, int a3, int a3)
{
__asm
{
MOV ECX,[ESP + 4]//a1
MOV EDX,[ESP + 8]//a2
MOV EAX,[ESP + 12]//a3
PUSH [ESP + 16]//a4
CALL the_hook_address
RETN 16 //4 * 4 args
}
}
我知道该函数将对象作为参数,将* Vector3作为参数 将存储计算值的参数。有没有 简单地告诉哪个参数将是什么?
'简单'取决于你在逆向工程方面的经验以及你正在使用的程序,在这种情况下我会说它是a1
,因为你可以看到它移动到临时,然后被访问使用指针表示法(IDA表示未知结构的方式)来提取3 float
s,这通常是大多数应用程序用于矢量组件的(并且大多数矢量都有3个组件)。如果您可以实际调试操作中的调用,查看params指针,查看函数调用站点等,它也会有很大帮助。因此我更喜欢使用ollydbg作为RE,用IDA执行流程图补充它以获得棘手的跳转序列(在函数中考虑20 + goto
:&lt;)