zoukankan      html  css  js  c++  java
  • HOOKAPI之修改IAT法则

    HOOK是一种WINDOWS下存在很久的技术了。
    HOOK一般分两种1。HOOK MESSAGE  2。HOOK API 本问讨论的是HOOK API之修改IAT。(如果你是HOOK高手就不要看了)
    在最初学HOOK-API的时候通常都是通过覆盖地址和修改IAT的方法。
    通过这两种技术,我们基本都可以实现对本进程的API函数进行HOOK了。但是在高兴之余会有点遗憾,
    怎么才能HOOK其他进程的API函数呢?怎么才能对一个API函数进行全局的HOOK呢?
    下面是我的一个简单的“HOOK其他进程API函数”的实现。(对另一进程的MessageBoxA这个函数进行HOOK)

    其实里面的应用了两个技术
    1。远程线程注入
    2。修改IAT,HOOK-API

    好了贴出代码如下:
    一共是3个文件
    install.c  注入程序
    fundll.cpp  DLL程序
    test.cpp  测试程序  

    CODE:

    //-------------------------install.c--------------------------
    //
    //install.c

    #include "windows.h"
    #include "tlhelp32.h"

    #pragma comment(lib,"th32.lib")

    const char *pkill="fundll.dll";                //DLL文件的路径

    //这个路径很有意思,这个路径是相对于目标进程的,而不是自身进程。
    //所以要嘛写成绝对路径,要嘛写成相对于目标进程的相对路径。
    //如果写成相对于自身的路径就要麻烦了,本程序就找不到DLL文件了。

    char *prosess="test.exe";   //要注入的进程名(目标进程名)

    int main()
    {

           //变量声明
            HANDLE hSnap;
            HANDLE hkernel32;        //被注入进程的句柄
            PROCESSENTRY32 pe;
            BOOL bNext;
            HANDLE hToken;
            TOKEN_PRIVILEGES tp;
            LUID Luid;
            LPVOID p;
            FARPROC pfn;
            //提升进程权限
            if (!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hToken))
            {
                    return 1;
            }

            if (!LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&Luid))
            {
                    return 1;
            }

            tp.PrivilegeCount = 1;
            tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
            tp.Privileges[0].Luid = Luid;

            if (!AdjustTokenPrivileges(hToken,0,&tp,sizeof(TOKEN_PRIVILEGES),NULL,NULL))
            {
                    return 1;
            }
            

            //枚举进程
            pe.dwSize = sizeof(pe);
            hSnap=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
            bNext=Process32First(hSnap, &pe);
            while(bNext)
            {
                    if(!stricmp(pe.szExeFile,prosess))                //--->>
                    {
                            hkernel32=OpenProcess(PROCESS_CREATE_THREAD|PROCESS_VM_WRITE|PROCESS_VM_OPERATION,1,pe.th32ProcessID);
                            break;
                    }
                    bNext=Process32Next(hSnap, &pe);
            }

            CloseHandle(hSnap);


              //注入,关键所在!

            //1,在目标进程分配线程函数的参数空间大小
            p=VirtualAllocEx(hkernel32,NULL,strlen(pkill),MEM_COMMIT,PAGE_READWRITE);

            //2,把参数写到目标进程分配的空间中
            WriteProcessMemory(hkernel32,p,pkill,strlen(pkill),NULL);

            //3,获取LoadLiabray函数的地址,作为新线程的线程函数调用
            pfn=GetProcAddress(GetModuleHandle("kernel32.dll"),"LoadLibraryA");

            //在目标空间创建新线程,线程函数地址是pfn,函数的参数地址是p
            CreateRemoteThread(hkernel32,NULL,0,pfn,p,NULL,0);

            return 0;
    }


    //----------------------fundll.cpp-----------------------------
    //
    //fundll.cpp

    #include "windows.h"
    #include "process.h"
    #include "tlhelp32.h"
    #include "stdio.h"

    #pragma comment(lib,"th32.lib")

    PIMAGE_DOS_HEADER  pDosHeader;
    PIMAGE_NT_HEADERS  pNTHeaders;
    PIMAGE_OPTIONAL_HEADER   pOptHeader;
    PIMAGE_IMPORT_DESCRIPTOR  pImportDescriptor;
    PIMAGE_THUNK_DATA         pThunkData;
    PIMAGE_IMPORT_BY_NAME     pImportByName;
    HMODULE hMod;


    // 定义MessageBoxA函数原型
    typedef int (WINAPI *PFNMESSAGEBOX)(HWND, LPCSTR, LPCSTR, UINT uType);
    int WINAPI MessageBoxProxy(IN HWND hWnd, IN LPCSTR lpText, IN LPCSTR lpCaption, IN UINT uType);

    int * addr = (int *)MessageBoxA;        //保存函数的入口地址
    int * myaddr = (int *)MessageBoxProxy;


    void ThreadProc(void *param);//线程函数

    //-------------------------------------------------------主函数开始

    BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)
    {
            if(fdwReason==DLL_PROCESS_ATTACH)        
                    _beginthread(ThreadProc,0,NULL);        //创建线程,调用ThreadProc

            return TRUE;
    }


    //线程函数,修改IAT地址

    void ThreadProc(void *param)
    {
            //------------hook api----------------
            hMod = GetModuleHandle(NULL);

            pDosHeader = (PIMAGE_DOS_HEADER)hMod;
            pNTHeaders = (PIMAGE_NT_HEADERS)((BYTE *)hMod + pDosHeader->e_lfanew);
            pOptHeader = (PIMAGE_OPTIONAL_HEADER)&(pNTHeaders->OptionalHeader);

            pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)((BYTE *)hMod + pOptHeader->DataDirectory[1].VirtualAddress);

            while(pImportDescriptor->FirstThunk)
            {
                    char * dllname = (char *)((BYTE *)hMod + pImportDescriptor->Name);

                    pThunkData = (PIMAGE_THUNK_DATA)((BYTE *)hMod + pImportDescriptor->OriginalFirstThunk);

                    int no = 1;
                    while(pThunkData->u1.Function)
                    {
                            char * funname = (char *)((BYTE *)hMod + (DWORD)pThunkData->u1.AddressOfData + 2);
                            PDWORD lpAddr = (DWORD *)((BYTE *)hMod + (DWORD)pImportDescriptor->FirstThunk) +(no-1);
                   
                            //修改内存的部分
                            if((*lpAddr) == (int)addr)
                            {
                                    //修改内存页的属性
                                    DWORD dwOLD;
                                    MEMORY_BASIC_INFORMATION  mbi;
                                    VirtualQuery(lpAddr,&mbi,sizeof(mbi));
                                    VirtualProtect(lpAddr,sizeof(DWORD),PAGE_READWRITE,&dwOLD);
                                    
                                    WriteProcessMemory(GetCurrentProcess(),
                                                    lpAddr, &myaddr, sizeof(DWORD), NULL);    //此处,修改了IAT的地址为我们自己定义函数的地址
                                    //恢复内存页的属性
                                    VirtualProtect(lpAddr,sizeof(DWORD),dwOLD,0);
                            }
                //---------
                            no++;
                            pThunkData++;
                    }

                    pImportDescriptor++;
            }
            //-------------------HOOK END-----------------
    }

    //new messagebox function
    int WINAPI MessageBoxProxy(IN HWND hWnd, IN LPCSTR lpText, IN LPCSTR lpCaption, IN UINT uType)
    {
            return         ((PFNMESSAGEBOX)addr)(NULL, "gxter_test", "gxter_title", 0);
            //这个地方可以写出对这个API函数的处理代码
    }


    //----------------------------test.cpp------------------------------------
    //test.cpp

    #include "stdio.h"
    #include "windows.h"

    int main()
    {
            printf("test---/n");
            while(1)
            {
                    getchar();
                    MessageBoxA(NULL, "原函数", "09HookDemo", 0);
            }
            return 0;
    }



    测试过程:先运行TEST不要关闭(建立目标),再运行install(进行注入)。但要注意FUNDLL和TEST文件位置。

    上面的代码进本上就实现了对其他进程的API进行HOOK了。
    但还有一个问题就是对“API函数进行全局的HOOK”。我的想法就是注入所有进程就可以实现了。
    只要简单的改一下上面的代码就可以实现了。 这好象有点像SetWindowsHookEx这个函数的的实现过程。
    以上就是我想法了,如果在什么地方有错误还请纠正。


    参考资料:
    《WINDOWS 程序设计》
    《WINDOWS 核心编程》

  • 相关阅读:
    HDU 6984
    洛谷 P6776
    C语言 error C4996: This function or variable may be unsafe
    C语言 sizeof 函数
    C语言 strlen 函数
    C语言 char 字符串
    C语言 goto 语句
    C语言 switch 语句
    C语言 do while 和 while 循环
    C语言 while 循环
  • 原文地址:https://www.cnblogs.com/moodlxs/p/2345430.html
Copyright © 2011-2022 走看看