Windows Practice_Dll&Hook_封装IAT Hook

来源:互联网 发布:网络打印被挂起 编辑:程序博客网 时间:2024/06/16 16:59

进程保护器的实现

本程序实现了一个简单的暴力的进程保护器,其原理也很简单,就是修改导入表,挂钩TerminateProcess函数,因为这个函数可以远程无条件的结束其它进程,所以我们要挂钩这个函数。
因为每一个程序都有可能结束要保护的程序,所以我们必须以Dll的形式注入到每一个进程中,这就涉及到注入的问题了,而Windows给我们提供了一个简单的全局挂钩的函数,即SetWindowsHook函数。
本工程主要有三个程序,分别是ProcessProtectorDll、ProcessProtectorExe以及TerminateProcessExe,从这三个程序的名字相信大家也都知道这些程序的作用了,就不再多做解释了。
下面我们一一将它们的源代码附上并稍作解释。

ProcessProtectorDll动态链接库程序

该程序主要是用来被其它的可执行程序调用,从而达到全局挂钩并保护相应进程的目的。代码如下:

// IATHook.h文件#pragma once#include <string>namespace PoEdu{    class CIATHook    {    public:        // 初始化即Hook        // 挂哪个Dll的哪个函数的钩        // 新的函数的地址        // 现有的所有Module        CIATHook(const std::string &dll_name, const std::string &func_name, void *new_func_addr);        HMODULE WINAPI LoadLibraryA(_In_ LPCSTR lpFileName);        HMODULE WINAPI LoadLibraryW(_In_ LPCWSTR lpFileName);        HMODULE WINAPI LoadLibraryExA(_In_ LPCSTR lpFileName, _Reserved_ HANDLE hFile, _In_ DWORD dwFlags);        HMODULE WINAPI LoadLibraryExW(_In_ LPCWSTR lpFileName, _Reserved_ HANDLE hFile, _In_ DWORD dwFlags);        FARPROC WINAPI GetProcAddress(_In_ HMODULE hModule, _In_ LPCSTR lpProcName ) const;    private:        void HookAllModule() const;        void HookOneModule(HMODULE hModule) const;    private:        std::string dll_name_;        void *new_func_addr_;        void *old_func_addr_;    };}
//IATHook.cpp文件#include "stdafx.h"#include "IATHook.h"#include <TlHelp32.h>#include <DbgHelp.h>#include <winbase.h>#pragma comment(lib, "DbgHelp.lib")// 这个类还有有些不足// 在启用新进程的时候还是挂不上namespace PoEdu{    CIATHook::CIATHook(const std::string& dll_name, const std::string& func_name, void* new_func_addr) :    dll_name_(dll_name), new_func_addr_(new_func_addr)    {        old_func_addr_ = GetProcAddress(GetModuleHandleA(dll_name.c_str()), func_name.c_str());        // 开始挂钩        // 每个Module都有自己的IAT,所以需要遍历所有的Module        HookAllModule();    }    HMODULE CIATHook::LoadLibraryA(LPCSTR lpFileName)    {        HMODULE hModule = ::LoadLibraryA(lpFileName);        HookOneModule(hModule);        return hModule;    }    HMODULE CIATHook::LoadLibraryW(LPCWSTR lpFileName)    {        HMODULE hModule = ::LoadLibraryW(lpFileName);        HookOneModule(hModule);        return hModule;    }    HMODULE CIATHook::LoadLibraryExA(LPCSTR lpFileName, HANDLE hFile, DWORD dwFlags)    {        HMODULE hModule = ::LoadLibraryExA(lpFileName, hFile, dwFlags);        HookOneModule(hModule);        return hModule;    }    HMODULE CIATHook::LoadLibraryExW(LPCWSTR lpFileName, HANDLE hFile, DWORD dwFlags)    {        HMODULE hModule = ::LoadLibraryExW(lpFileName, hFile, dwFlags);        HookOneModule(hModule);        return hModule;    }    FARPROC CIATHook::GetProcAddress(HMODULE hModule, LPCSTR lpProcName) const    {        FARPROC pAddr = ::GetProcAddress(hModule, lpProcName);        if (pAddr == old_func_addr_)        {            return static_cast<FARPROC>(new_func_addr_);        }        else        {            return pAddr;        }    }    void CIATHook::HookAllModule() const    {        HANDLE hSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId());        MODULEENTRY32 me32 = { sizeof(MODULEENTRY32) };        BOOL bNext = ::Module32FirstW(hSnap, &me32);        while (bNext)        {            // 给每个Module挂钩            HookOneModule(me32.hModule);            bNext = Module32NextW(hSnap, &me32);        }        CloseHandle(hSnap);    }    void CIATHook::HookOneModule(HMODULE hModule) const    {        ULONG ulSize = 0;        PIMAGE_IMPORT_DESCRIPTOR pImageImportDescriptor = static_cast<PIMAGE_IMPORT_DESCRIPTOR>(ImageDirectoryEntryToData(hModule, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ulSize));        if (!pImageImportDescriptor)        {            return;        }        while (pImageImportDescriptor->Name)        {            char *pDllName = reinterpret_cast<char *>(reinterpret_cast<BYTE *>(hModule) + pImageImportDescriptor->Name);            if (dll_name_.compare(pDllName) == 0)            {                break;            }            ++pImageImportDescriptor;        }        if (pImageImportDescriptor->Name)        {            PIMAGE_THUNK_DATA pImageThunkData = reinterpret_cast<PIMAGE_THUNK_DATA>(reinterpret_cast<BYTE *>(hModule) + pImageImportDescriptor->FirstThunk);            while (pImageThunkData->u1.Function)            {                DWORD *pDwAddr = &(pImageThunkData->u1.Function);                if (*pDwAddr == reinterpret_cast<DWORD>(old_func_addr_))                {                    MEMORY_BASIC_INFORMATION mbi;                    VirtualQuery(pDwAddr, &mbi, sizeof(MEMORY_BASIC_INFORMATION));                    DWORD dwOldProtection = 0;                    VirtualProtect(pDwAddr, sizeof(DWORD_PTR), PAGE_READWRITE, &dwOldProtection);                    // 为了安全起见,可以使用WriteProcessMemory函数进行远进程写入,这样即使权限不够,也不会报异常                    if (!WriteProcessMemory(GetCurrentProcess(), pDwAddr, &new_func_addr_, sizeof(DWORD_PTR), nullptr))                    {                        MessageBoxW(nullptr, L"WriteProcessMemory", L"WriteProcessMemory", MB_OK);                    }                    VirtualProtect(pDwAddr, sizeof(DWORD_PTR), dwOldProtection, nullptr);                    break;                }                ++pImageThunkData;            }        }    }}
// dllmain.cpp : 定义 DLL 应用程序的入口点。#include "stdafx.h"#include "IATHook.h"// 找到当前注入后的 IAT 表 Hook TerminateProcess//PoEdu::CIATHook g_MyHook;DWORD g_dwPID = 0;HHOOK g_hHook = nullptr;BOOL WINAPI MyTerminateProcess(_In_ HANDLE hProcess, _In_ UINT uExitCode){    return FALSE;//  DWORD dwPID = GetProcessId(hProcess);//  if (g_dwPID == dwPID)//  {//      MessageBoxW(nullptr, L"这是我要保护的进程,请不要无条件终止它!", L"警告", MB_OK);//      return TRUE;//  }    //return TerminateProcess(hProcess, uExitCode);}PoEdu::CIATHook g_MyHook("KERNEL32.dll", "TerminateProcess", MyTerminateProcess);BOOL APIENTRY DllMain( HMODULE hModule,                       DWORD  ul_reason_for_call,                       LPVOID lpReserved                     ){    switch (ul_reason_for_call)    {    case DLL_PROCESS_ATTACH:        break;    case DLL_THREAD_ATTACH:    case DLL_THREAD_DETACH:    case DLL_PROCESS_DETACH:        break;    default:        break;    }    return TRUE;}HMODULE GetFuncModule(void * pFuncAddr){    HMODULE hRet = nullptr;    MEMORY_BASIC_INFORMATION mbi;    if (VirtualQuery(pFuncAddr, &mbi, sizeof(MEMORY_BASIC_INFORMATION)) != 0)    {        hRet = static_cast<HMODULE>(mbi.AllocationBase);    }    return hRet;}LRESULT CALLBACK GetMsgProc(_In_ int code, _In_ WPARAM wParam, _In_ LPARAM lParam){    //MessageBoxW(nullptr, L"GetMsgProc", L"GetMsgProc", MB_OK);    return CallNextHookEx(g_hHook, code, wParam, lParam);}// 用SetWindowsHook做的注入extern "C" _declspec(dllexport) BOOL StartProtecting(DWORD dwPID)//extern "C" _declspec(dllexport) BOOL StartProtecting(){    BOOL bRet = FALSE;    if (g_hHook == nullptr)    {        g_hHook = SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, GetFuncModule(GetMsgProc), 0);        if (g_hHook != nullptr)        {            g_dwPID = dwPID;            bRet = TRUE;        }    }    return bRet;}extern "C" _declspec(dllexport) BOOL EndProtecting(){    BOOL bRet = FALSE;    if (g_hHook != nullptr)    {        if (UnhookWindowsHookEx(g_hHook))        {            bRet = TRUE;        }    }    return bRet;}

上面主要有问题的是MyTerminateProcess函数,从这个函数的实现可以看出,我们屏蔽的是所有的TerminateProcess,因为每一个进程在调用ProcessProtectorDll动态链接库的时候都是重新复制一份,所以没法简单的在挂钩的时候传递一个要保护的进程ID,因为在新的进程调用该动态链接库的时候,一切都是初始化状态,并没有要保护的进程ID,只能通过共享空间实现所有进程的数据共享,这里我们没有实现,感兴趣的朋友可以实现一下。。。

ProcessProtectorExe程序源码

该程序主要是加载ProcessProtectorDll动态链接库从而达到保护进程不被远程无条件结束的目的。

// ProcessProtectorExe.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include <Windows.h>#include <clocale>// 选择需要保护的进程// 启动Hooktypedef BOOL(*FUNC)(DWORD dwPID);void PrintErrorMessage(DWORD dwErrorCode){    setlocale(LC_ALL, "chs");    TCHAR strErrorMessage[MAXBYTE] = { 0 };    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, dwErrorCode, 0, strErrorMessage, MAXBYTE, nullptr);    wprintf(L"错误代码是:%d    %s\r\n", dwErrorCode, strErrorMessage);}int main(){    HMODULE hDllModule = nullptr;    FUNC StartProtecting = nullptr;    FARPROC EndProtecting = nullptr;    do    {        // 查找窗口        char strProcessName[MAXBYTE] = "计算器";        HWND hWnd = FindWindowA(nullptr, strProcessName);        if (hWnd == nullptr)        {            printf("the handle of window do not found!\r\n");            break;        }        // 根据窗口句柄查找进程ID        DWORD dwProcessId = 0;        GetWindowThreadProcessId(hWnd, &dwProcessId);        if (dwProcessId == NULL)        {            printf("process Id do not found!\r\n");            break;        }        // 打开进程        HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);        if (hProcess == nullptr)        {            printf("open the process failed!\r\n");            break;        }        // LoadLibray        hDllModule = LoadLibrary(L"ProcessProtectorDll.dll");        if (hDllModule == nullptr)        {            PrintErrorMessage(GetLastError());            break;        }        // SetHook        StartProtecting = reinterpret_cast<FUNC>(GetProcAddress(hDllModule, "StartProtecting"));        if (StartProtecting == nullptr)        {            PrintErrorMessage(GetLastError());            break;        }        if (!StartProtecting(dwProcessId))        {            PrintErrorMessage(GetLastError());            break;        }        printf("进程保护成功!\r\n");        MSG msg;        BOOL ret;        while ((ret = GetMessage(&msg, nullptr, 0, 0)))        {            if (ret == -1)                break;            TranslateMessage(&msg);            DispatchMessage(&msg);        }        // UnHook        EndProtecting = GetProcAddress(hDllModule, "EndProtecting");        if (EndProtecting == nullptr)        {            PrintErrorMessage(GetLastError());            break;        }        if (!EndProtecting())        {            PrintErrorMessage(GetLastError());            break;        }    } while (false);    if (hDllModule)    {        FreeLibrary(hDllModule);    }    system("pause");    return 0;}

由于动态链接库是被所有进程调用的,所以这里保护的是所有的进程不被远程无条件结束掉,而不只是计算器这个程序,这个需要注意一下。

**

// TerminateProcessExe.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include <Windows.h>int main(){    do    {        // 查找窗口        char strProcessName[MAXBYTE] = "计算器";        HWND hWnd = FindWindowA(nullptr, strProcessName);        if (hWnd == nullptr)        {            printf("the handle of window do not found!\r\n");            break;        }        // 根据窗口句柄查找进程ID        DWORD dwProcessId = 0;        GetWindowThreadProcessId(hWnd, &dwProcessId);        if (dwProcessId == NULL)        {            printf("process Id do not found!\r\n");            break;        }        // 打开进程        HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);        if (hProcess == nullptr)        {            printf("open the process failed!\r\n");            break;        }        MessageBoxW(nullptr, L"", L"", MB_OK);        if (TerminateProcess(hProcess, 1))        {            printf("已经被终止运行!\r\n");        }        else        {            printf("没有被终止运行!\r\n");        }    } while (false);    system("pause");    return 0;}

本程序就是尝试远程结束计算器程序,当开启了我们的进程保护器后,我们是无法终止计算器的,这也就达到了要保护的目的。

当然了,这种全局挂钩的方式是存在问题的,它会使我们的系统变得非常的慢。我们的这个进程保护器目的只是让大家了解一下什么是IAT Hook,它的原理是什么,实际上基本上不会用这种方式来实现进程保护器的。