您的位置:首页 > 其它

Windows Practice_Dll&Hook_封装IAT Hook

2017-09-24 12:32 459 查看

进程保护器的实现

本程序实现了一个简单的暴力的进程保护器,其原理也很简单,就是修改导入表,挂钩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>

// 选择需要保护的进程
// 启动Hook

typedef 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,它的原理是什么,实际上基本上不会用这种方式来实现进程保护器的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: