古典黑客技术之HOOK API

时间:2022-08-29 21:19:09

古典黑客技术之HOOK API

HOOK API技术可以拦截、控制某些API函数的调用。当一个API函数被拦截之后,用户可以让目标程序执行事先准备好的代码。(比如说,构造的代码是过滤此API函数传入的参数的,而此API函数又是用来获取进程的,当此API被拦截之后,我们就可以让它转去执行过滤参数的代码。)

PE文件的导入表

HOOK API其实是对远程进程内存数据的修改,可以通过修改导入表中的导入函数地址表来实现API HOOK,而进程内存数据又是文件在内存中以某种规则建立的映像。
PE(Portable Executable)意味着此文件格式是跨Win32平台的。即使Windows运行在非Intel的CPU上,任何Win32平台的PE装载器都可以识别和使用该文件格式。
古典黑客技术之HOOK API

这两天一直在忙其他的事情,今天终于可以接着写下去了。
先上一段完整的代码举个栗子吧,注释已经写得很清楚了,希望有兴趣的童鞋可以一行一行认真看完,肯定会有收获的。

#include "stdafx.h"
#include <windows.h>
using namespace std;

unsigned long* lpAddr;
PROC OldProc;
int ApiHook(char *DllName,PROC OldFunAddr,PROC NewFunAddr);

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        //得到TerminateProcess函数地址
        OldProc = (PROC)TerminateProcess;
        //定位,修改IAT表
        ApiHook("kernel32.dll", OldProc, (PROC)TerminateProcess);
        break;
    case DLL_PROCESS_DETACH:
        //恢复IAT表中的API函数的入口点地址
        WriteProcessMemory(GetCurrentProcess(), lpAddr, &OldProc, sizeof(DWORD), NULL);
        break;
    }
    return TRUE;
}

BOOL _stdcall MyTerminateProcess(HANDLE hProcess, UINT uExitCode)
{
    MessageBox(0,L"you can't terminate process!",L"APIHOOK by Elfsong",MB_OK|MB_ICONWARNING);
    return 0;
}

int ApiHook(char *DllName,   //DLL文件名
            PROC OldFunAddr, //需要HOOK的函数地址
            PROC NewFunAddr  //构造的函数地址
            )
{
    //得到函数进程模块基地址
    HMODULE lpBase = GetModuleHandle(NULL);
    IMAGE_DOS_HEADER *dosHeader;
    IMAGE_NT_HEADERS *ntHeader;
    IMAGE_IMPORT_BY_NAME *ImportName;

    //定位到Dos头
    dosHeader = (IMAGE_DOS_HEADER*) lpBase;

    //定位到Pe头
    ntHeader = (IMAGE_NT_HEADERS32*)((BYTE*)lpBase + dosHeader->e_lfanew);

    //定位到导出表
    IMAGE_IMPORT_DESCRIPTOR *pImportDesc = (IMAGE_IMPORT_DESCRIPTOR*)((BYTE*)lpBase+ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);

    //循环遍历IMAGE_IMPORT_DESCRIPTOR机构数组
    while(pImportDesc->FirstThunk)
    {
        //获得DLL文件名
        char* pszDllName = (char*)((BYTE*)lpBase + pImportDesc->Name);

        //比较得到的DLL文件名是否和要HOOK函数所在的DLL相同
        if(lstrcmpiA(pszDllName, DllName) == 0)
        {
            break;
        }
        pImportDesc++;
    }

    //定位到FirstThunk参数指向的IMAGE_THUNK_DATA,此时这个结构已经是函数入口点地址了
    IMAGE_THUNK_DATA* pThunk = (IMAGE_THUNK_DATA*)((BYTE*)lpBase + pImportDesc->FirstThunk);

    //遍历这部分IAT表
    while(pThunk->u1.Function)
    {
        //lpAddr是定义的全局变量,用来存放要HOOK的API函数的入口地址在IAT表中的内存地址。为了使此DLL被卸载后任务管理器不会崩溃,必须在DLL被卸载时,把修改的函数的入口点地址改回来。
        lpAddr = (DWORD*)&(pThunk->u1.Function);
        if(*lpAddr == (DWORD)OldFunAddr)
        {
            DWORD dwOldProtect;
            //修改内存包含属性
            VirtualProtect(lpAddr, sizeof(DWORD), PAGE_READWRITE, &dwOldProtect);

            //API函数的入口点地址改为构造函数的地址
            WriteProcessMemory(GetCurrentProcess(), lpAddr, &NewFunAddr, sizeof(DWORD), NULL);
        }
        pThunk++;
    }
    return 0;
}

把这个CPP编译成DLL注入到应用程序里,任务管理器就杀不掉他啦~

我等下就去写注入的代码,一定不会犯拖延症的!!!
未完待续哦~