修改钩子函数的out参数 [英] Modifying an out parameter of a hooked function

查看:95
本文介绍了修改钩子函数的out参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想挂钩EnumProcesses(),作为第一个练习,从它填充的数组中删除一些进程ID。



这是一个out参数所以我不得不让函数执行,然后做我的脏东西。



基本思路,使用可以注入进程的DLL:

- hook EnumProcesses()(做了这个)

- 复制第一个(_Out_ DWORD * pProcessIds)和3rd(_Out_ DWORD * pBytesReturned)参数的地址(做了这个,但我存储了它们在一个全局变量中)

- 保存当前的返回地址(在[ebp + 4])(做了这个,但也在一个全局变量中)

- 改变回报地址,所以函数将在我的一个函数中返回

- 将控制权交还给EnumProcesses()

现在不是回到它被调用的地方,而是转到一个我的朋友们,它们将:

- 将eax的返回值保存到局部变量中(只是为了安全)

- 遍历数组进程ID,删除我要删除的内容

- 将返回值放回eax中

- 推送堆栈上的返回值,返回



这个按预期工作,有一个我不喜欢的小缺点:当我的原始程序(称为EnumProcesses的人)存在时,我得到:运行时检查失败#2 - 堆栈周围变量'allProcesses'已损坏,allProcesses是用作我的EnumProcesses调用的第一个参数的变量。

结果数组是预期的数组,但我不喜欢我的堆栈损坏。而且我也想知道我搞砸了哪里,



这里我保存了参数地址并更改了返回地址:

< pre lang =c ++> __ declspec naked
void
__ stdcall
InterceptEnumProc()
{
DWORD_PTR retAdr;

FARPROC变化;

HMODULE hModule;
FARPROC oldFuncAdr;

LPBYTE pJmpAdr;

__ asm
{
// 重做我们用钩子写的叮咬
sub edi edi
push ebp
mov ebp esp

sub esp ,_ _ LOCAL_SIZE

mov eax ,[ ebp + 4 ] // 返回地址
mov g_returnAdrEnumProc, eax

mov eax ,[ ebp + 8 ] // * pProcessIds
mov g_pProcIds, eax
mov eax ,[ ebp + 16 ] // * pBytesReturned
mov g_pBytedReturned, eax

// 保存寄存器
push esi
推送 ebx
};

change =(FARPROC)ChangeEnumProc; // 更改输出
retAdr =(DWORD_PTR)更改;

hModule = NULL;
oldFuncAdr = NULL;
hModule = LoadLibrary(TEXT( Psapi.dll));
// 错误检查此处省略了可能的LoadLibrary故障
oldFuncAdr = GetProcAddress( hModule,
EnumProcesses);
// 错误检查此处省略了可能的GetProcAddress

pJmpAdr =(LPBYTE)(DWORD_PTR)oldFuncAdr + 5 ;

__ asm
{
pop ebx
pop esi

mov eax ,retAdr // 新的返回地址
mov [ ebp + 4 ], eax
mov esp ebp
jmp pJmpAdr
};
}





我在这里更改结果:

  __ declspec  naked 
void
__ stdcall
ChangeEnumProc()
{
DWORD rValue;
DWORD bytesReturned;
DWORD procsReturned;
DWORD i;
DWORD currentProcId;
DWORD poz;

/ * 这就是问题:
__asm
{
mov rValue,eax //保存返回值
};
* /


__ asm
{
// 创建一个stacj框架
push ebp
mov ebp esp

sub esp ,_ _ LOCAL_SIZE
mov rValue, eax

push esi
push ebx
};

bytesReturned = *(DWORD *)g_pBytedReturned;
procsReturned = bytesReturned / sizeof(DWORD);

currentProcId = GetCurrentProcessId(); // 我只是从结果中隐藏当前流程

for (i = 0 ; i< procsReturned; i ++)
{
DWORD procId;

procId = * g_pProcIds;

if (procId == currentProcId)
{
poz = i;
break ;
}
g_pProcIds ++;
}

g_pProcIds ++;

for (i = poz + 1 ; i< procsReturned; i ++ )
{
*(g_pProcIds - 1 )= * g_pProcIds;
g_pProcIds ++;
}

// 同时,更改调用者应该的进程ID数量查找
bytesReturned = bytesReturned - sizeof (DWORD);
*(DWORD *)g_pBytedReturned = bytesReturned;

__ asm
{
pop ebx
pop esi

mov esp ebp
pop ebp

mov eax ,rValue
jmp g_returnAdrEnumProc // 返回来电者
};

}





全局变量:

 PDWORD g_pProcIds; 
PDWORD g_pBytedReturned;
DWORD_PTR g_returnAdrEnumProc;





EnumProcesses致电:

 DWORD allProcesses [ 1024 ]; 
DWORD bytesReturned = 0 ;

if (!EnumProcesses(allProcesses,
sizeof (allProcesses) ),
& bytesReturned))
{
// 等等
}





挂钩是基本内联挂钩,而不是写入前5个字节API。

当我操纵这些指针时,我认为我做了一些错误的事情。我利用了EnumProcesses需要第一个和第三个参数指针的事实,但我不确定整个方法有多正确。



作为一个方面 - 注意:我正在考虑松开全局变量,并在ChangeEnumProc的开头添加一些空格(用NOP填充它),然后用我需要的数据写入该空间。我也想对这个想法有一些反馈(好像过度杀人,但我从不喜欢全局变量)。



编辑:发现问题有点一步一步地跑。在为局部变量保留堆栈空间之前,我正在为局部变量赋值。编辑上面的代码来说明它。我仍然愿意接受反馈和建议。

解决方案

I want to hook EnumProcesses() and, as a first exercise, remove some process IDs from the array it populates.

This is an out parameter so I had to let the function to execute, and then to do my dirty thing.

Basic idea, using a DLL that can be injected into a process:
- hook EnumProcesses() (did this)
- copy the address of the first (_Out_ DWORD *pProcessIds) and 3rd (_Out_ DWORD *pBytesReturned) parameters (did this, but I store them in a global variable)
- save current return address (at [ebp + 4]) (did this, but also in a global variable)
- change the return address so the function will return in one of my functions
- give control back to EnumProcesses()
Now instead of going back to where it was called, it goes to one of my friends, which will:
- save the return value from eax into a local variable (just to be safe)
- iterate through the array of process IDs, removing what I want to remove
- put back the return value in eax
- push the return value on the stack, return

This works as intended with one little drawback which I don't like: when my original program (the one who called EnumProcesses) exists I get: "Run-Time Check Failure #2 - Stack around the variable 'allProcesses' was corrupted", allProcesses is the variable used as the first parameter for my EnumProcesses call.
The resulting array is the expected one, but I don't like having my stack corrupted. And I also want to know where I messed up,

Here I save the out parameters addresses and I change the return address:

__declspec(naked)
void
__stdcall
InterceptEnumProc()
{
    DWORD_PTR retAdr;

    FARPROC change;

    HMODULE hModule;
    FARPROC oldFuncAdr;

    LPBYTE pJmpAdr;

    __asm
    {
        // redo the bites we over written with our hook
        sub edi, edi
        push ebp
        mov ebp, esp

        sub esp, __LOCAL_SIZE

        mov eax, [ebp + 4] // return address
        mov g_returnAdrEnumProc, eax

        mov eax, [ebp + 8] // *pProcessIds
        mov g_pProcIds, eax
        mov eax, [ebp + 16] // *pBytesReturned
        mov g_pBytedReturned, eax

        // save registers
        push esi
        push ebx
    };

    change = (FARPROC)ChangeEnumProc; // change the output
    retAdr = (DWORD_PTR)change;

    hModule = NULL;
    oldFuncAdr = NULL;
    hModule = LoadLibrary(TEXT("Psapi.dll"));
    // error checks for possible LoadLibrary failure omitted here
    oldFuncAdr = GetProcAddress(hModule,
        "EnumProcesses");
    // error checks for possible GetProcAddress omitted here

    pJmpAdr = (LPBYTE)(DWORD_PTR)oldFuncAdr + 5;

    __asm
    {
        pop ebx
        pop esi

        mov eax, retAdr // new return address
        mov [ebp + 4], eax
        mov esp, ebp
        jmp pJmpAdr
    };
}



And here I change the result:

__declspec(naked)
void
__stdcall
ChangeEnumProc()
{
    DWORD rValue;
    DWORD bytesReturned;
    DWORD procsReturned;
    DWORD i;
    DWORD currentProcId;
    DWORD poz;

    /* this was the problem:
      __asm
      {
          mov rValue, eax // save return value
      };
    */

    __asm
    {
        // create a stacj frame
        push ebp
        mov ebp, esp

        sub esp, __LOCAL_SIZE
        mov rValue, eax

        push esi
        push ebx
    };

    bytesReturned = *(DWORD* )g_pBytedReturned;
    procsReturned = bytesReturned/sizeof(DWORD);

    currentProcId = GetCurrentProcessId(); // I just hide the current process from the results

    for(i = 0; i < procsReturned; i++)
    {
        DWORD procId;

        procId = *g_pProcIds;

        if(procId == currentProcId)
        {
            poz = i;
            break;
        }
        g_pProcIds++;
    }

    g_pProcIds++;

    for(i = poz + 1; i < procsReturned; i++)
    {
        *(g_pProcIds - 1) = *g_pProcIds;
        g_pProcIds++;
    }

    // also, change the number of process IDs the caller should look for
    bytesReturned = bytesReturned - sizeof(DWORD);
    *(DWORD* )g_pBytedReturned = bytesReturned;

    __asm
    {
        pop ebx
        pop esi

        mov esp, ebp
        pop ebp

        mov eax, rValue
        jmp g_returnAdrEnumProc // go back to the caller
    };

}



The global variables:

PDWORD g_pProcIds;
PDWORD g_pBytedReturned;
DWORD_PTR g_returnAdrEnumProc;



EnumProcesses call:

DWORD allProcesses[1024];
DWORD bytesReturned = 0;

if(!EnumProcesses(allProcesses,
    sizeof(allProcesses),
    &bytesReturned))
{
    // etc, etc
}



The hooking is basic inline hooking, over writing the first 5 bytes of the API.
I think I do some wrong things when I manipulate those pointers. I took advantage of the fact that EnumProcesses needs pointers for the first and 3rd argument, but I'm not sure how correct is the whole approach.

As a side-note: I was thinking to loose the global variables, and let some space at the beginning of ChangeEnumProc (fill it wit NOPs) and then over write that space with the data I need. I will also like some feedback on this idea too (it seems like over kill, but I never liked global variables).

EDIT: found the problem with a bit of step by step running. I was assigning a value to a local variable before I reserved space on the stack for my local variables. Edited the code above to illustrate it. I'm still open to feedback and advises.

解决方案

这篇关于修改钩子函数的out参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆