inline使用DLL进行全局HOOK的改进(ring3_inline_dll_hook_Messagebox_临界区)

来源:互联网 发布:苏州大学知博书店 编辑:程序博客网 时间:2024/06/05 21:50
 

JMP HOOK API最简单的就是在MyFun()中先调用Hookoff,再调用原fun,再调用hookon,关于原理就不再多说。而它明显的不足也就在此,在瞬间两次修改系统API的代码,如果某个程序(不要说我自己的程序没使用多线程,这是全局HOOK,你不能保证其它程序没使用),使用了多线程,并且对此系统API频繁调用,最极端的情况就是在同一时刻系统API的前5个字节同时出现了读写,或还没写好,就来读了,从而出现产生错误,使JMP HOOK API在多线程下变的一塌糊涂,还好只是RING3下的HOOK,只是程序崩溃,如果是RING0下的系统立即就蓝屏。
要解决此问题就从两方向考虑,一是修改HOOK的思路,二是锁定那前5个字节的见容,让同一时刻只有一个线程访问。我先想到了第二种办法,即《电脑编程技巧与维护》中多线程技术中提到的“临界区”。
如果有多个线程试图同时访问临界区,那么在有一个线程进入后其他所有试图访问此临界区的线程将被挂起,并一直持续到进入临界区的线程离开。临界区在被释放后,其他线程可以继续抢占,并以此达到用原子方式操作共享资源的目的。就象上厕所,第一个人进去后关了门,第二个人等待,第一个人出来后门开,第二个人进去再关门。
主要使用以下API
CRITICAL_SECTION g_cs;//先定义一个变量
InitializeCriticalSection(&g_cs);//开始要初始化
EnterCriticalSection(&g_cs);//进入临界区
LeaveCriticalSection(&g_cs);//退出临界区
DeleteCriticalSection(&g_cs);//程序退出时要删除临界区
下面是HOOK OpenProcess的关键代码
HANDLE __stdcall MyOpenProcess(DWORD dwDesiredAccess,BOOL bInheritHandle,DWORD dwProcessId)
{
HANDLE nReturn;
    HookOff();
if((DWORD)dwProcessId!=(DWORD)ProcessId)
{
    nReturn=OpenProcess(dwDesiredAccess,bInheritHandle,dwProcessId);
}else
{
    nReturn =OpenProcess(dwDesiredAccess,bInheritHandle,0);
}
    HookOn();
    return(nReturn);
}

void HookOn()
{
    HANDLE hProc;
    dwIdOld = dwIdNew;
    // 得到所属进程的句柄
    hProc = GetCurrentProcess();
EnterCriticalSection(&g_cs);//进入临界区
    // 修改所属进程中MessageBoxA的前5个字节的属性为可写
    VirtualProtectEx(hProc,fpproc,5,PAGE_READWRITE,&dwIdOld);
    // 将所属进程中MessageBoxA的前5个字节改为JMP 到MyMessageBoxA
    WriteProcessMemory(hProc,fpproc,NewprocCode,5,0);
    // 修改所属进程中MessageBoxA的前5个字节的属性为原来的属性
    VirtualProtectEx(hProc,fpproc,5,dwIdOld,&dwIdOld);
LeaveCriticalSection(&g_cs);//退出临界区
    bHook=true;
}
void HookOff()
{
    HANDLE hProc;
    dwIdOld = dwIdNew;
    hProc = GetCurrentProcess();
EnterCriticalSection(&g_cs);//进入临界区
    VirtualProtectEx(hProc,fpproc,5,PAGE_READWRITE,&dwIdOld);
    WriteProcessMemory(hProc,fpproc,OldprocCode,5,0);
    VirtualProtectEx(hProc,fpproc,5,dwIdOld,&dwIdOld);
LeaveCriticalSection(&g_cs);//退出临界区
    bHook = false;
}

本例子中的 nReturn =OpenProcess(dwDesiredAccess,bInheritHandle,0);是把关闭对象转移到了系统空闲进程,会试图关闭本程序保护的进程会出现无权访问的提示,提权操作会挂掉系统,如果改成 nReturn =OpenProcess(dwDesiredAccess,bInheritHandle,GetCurrentProcess());会关闭任务管理器,实现谁关我我关谁的效果。最后临界区只是解决同一进程不同线程访问和问题,不同进程使用无效,因为出现了等待。所以可能影响和谐执行速度。