PE基础7-HOOK练习

HOOK练习

头文件内容

#include <windows.h>// Inline Hook: 原理是修改程序执行流程上的代码,使代码可以从目标地址跳转到
//              指定的位置,从而获取函数的调用情况。微软专门给所有的库函数
//              提供了 6 字节的垃圾指令进行 Hook。
// Inline Hook 要注意的地方: 线程安全。如果在修改指令的同时,其它的线程正
//              在调用该地址的指令,那么由于指令修改完成了一半,得到的OpCode
//              是不确定的,会导致崩溃。解决方式是
//              ①:在 Hook 前,暂停当前进程的所有其它线程
//              ②:使用原子操作: InterLocked 系列函数,原理是锁地址总线 lock
// 保存 Hook 之前的原始 OpCode
BYTE OldOpCode[5] = { 0x00 };
​
// 保存新的用于跳转的 OpCode: E9 xxxxxxxx
BYTE JmpOpCode[5] = { 0xE9 };
​
// 保存需要修改的函数所在的地址
LPVOID Addr = nullptr;
​
// 保存需要保护的 PID 
LONG Pid = 0;
​
​
// 1. 我要 Hook 的是哪一个进程, OD 和 Taskmgr
// 2. 为了 OD 不能附加目标进程,可以 Hook 函数 OpenProcess
// 3. 编写自己的函数,务必保证原型完全一致,用于接管原始函数,主要执行[筛选]工作
​
​
// 开启\关闭 Hook
void EnableHook(BOOL Enable = TRUE)
{
    DWORD OldProtect = 0;
​
    // 1. 修改目标地址所在分页的属性
    VirtualProtect(Addr, 5, PAGE_EXECUTE_READWRITE, &OldProtect);
​
    // 2. 根据开启或关闭,向内填充新的\旧的 OpCode
    memcpy(Addr, Enable ? JmpOpCode : OldOpCode, 5);
​
    // 3. 还原目标地址所在分页的属性
    VirtualProtect(Addr, 5, OldProtect, &OldProtect);
}
​
​
// 自己编写的函数,在不满足条件的情况下,应该要调用原始函数
HANDLE WINAPI MyOpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId)
{
    HANDLE Handle = 0;
​
    // 如果 pid 是 0x1515 就返回 -1
    if (dwProcessId == Pid)
    {
        Handle = INVALID_HANDLE_VALUE;
    }
    else
    {
        // 为了不产生递归,应该先还原被 Hook 的指令
        EnableHook(FALSE);
        Handle = OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId);
        // 为了下一次,还会进入 MyOpenProcess,要继续 Hook 
        EnableHook();
    }
​
    return Handle;
}
​
​
// 执行初始化的函数,例如保存原始指令,构建新的指令
void initialize()
{
    // 1. 获取需要 Hook 的函数的地址,在系统运行时,
    //    所有[系统模块]在不同进程中的地址都是相同的
    Addr = GetProcAddress(LoadLibraryA("kernel32.dll"), "OpenProcess");
​
    // 2. 保存原始的指令,为了恢复原始代码 InterlockedExchang()
    memcpy(OldOpCode, Addr, 5);
​
    // 3. 计算跳转偏移: 新的函数地址 - 旧的函数地址 - 5(E9XXXXXXXX)
    DWORD Offset = (DWORD)MyOpenProcess - (DWORD)Addr - 5;
​
    // 4. 组合成新的 OpCode
    *(DWORD*)&JmpOpCode[1] = Offset;
​
    // 5. 获取需要保护的 Pid,第三个参数返回上一次的信号个数
    HANDLE Semaphore = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, L"MYPID");
    ReleaseSemaphore(Semaphore, 1, &Pid);
}

 

Dllmain文件内容

#include "framework.h"
​
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        initialize();
        EnableHook();
        break;
    case DLL_PROCESS_DETACH:
        EnableHook(FALSE);
        break;
    }
    return TRUE;
}

 

main

#include <windows.h>// 务必确保使用的是绝对路径
const char* DllName = "C:\\Users\\Administrator\\Desktop\\2\\D15安全卫士0701\\Debug\\HookDll.dll";
​
int main()
{
    // 在编写 dll 时,最初应该在自己的程序上使用 LoadLibrary 进行测试
// 创建了一个信号量,保存了一些数值(初始信号Pid,最大信号Pid+1)
    HANDLE Semaphore = CreateSemaphore(NULL, 
        GetCurrentProcessId(), GetCurrentProcessId() + 1, "MYPID");
​
    // 1. 通过窗口名称确定目标的 Pid
    DWORD Pid = 0, Size = 0;
    HWND hWnd = FindWindow(NULL, "任务管理器");
    //HWND hWnd = FindWindow(NULL, "吾愛破解 - [LCG]");
    GetWindowThreadProcessId(hWnd, &Pid);
​
    // 2. 使用对应的权限打开目标进程
    HANDLE Handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, Pid);
​
    // 3. 申请空间,主要用于存放的是 LoadLibrary 的参数,务必确保版本(A/W)对应
    LPVOID Addr = VirtualAllocEx(Handle, NULL, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
    
    // 4. 写入数据,注意写入的长度
    WriteProcessMemory(Handle, Addr, DllName, strlen(DllName) + 1, &Size);
​
    // 5. 创建远程线程,注意版本
    CreateRemoteThread(Handle, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibraryA, Addr, NULL, NULL);
​
    system("pause");
​
    return 0;
}

 

 

posted @ 2019-07-01 21:42  ltyandy  阅读(354)  评论(0编辑  收藏  举报