• 逆向 | IAT Hook


    通过修改IAT来hook。

    注意点:由于IAT不一定是连续的,因此有时候会要先定位那个模块,再找对应的IAT表。

    主要测试代码如下:

    1.dll(用于注入的dll):

    // 1.cpp : Defines the entry point for the DLL application.
    //
    
    #include "stdafx.h"
    
    
    DWORD g_dwOldAddr;         // 原始函数地址
    DWORD g_dwNewAddr;         // Hook函数地址
    DWORD g_dwIATHookFlag;     // 标志有没有被hook
    
    BOOL SetIATHook(DWORD dwOldAddr, DWORD dwNewAddr){
    	BOOL bFlag = FALSE;
    	DWORD dwImageBase = 0;
    	PDWORD pFuncAddr = NULL;
    	PIMAGE_NT_HEADERS pNtHeader = NULL;
    	PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor = NULL;
    	DWORD dwOldProtect = 0;
    
    	// 得到exe模块基址
    	dwImageBase = (DWORD)GetModuleHandle(NULL);
    	pNtHeader = (PIMAGE_NT_HEADERS)(dwImageBase + ((PIMAGE_DOS_HEADER)dwImageBase)->e_lfanew);
    	pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(dwImageBase + 
    		pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
    	
    	// 遍历IAT表 找到这个函数的地址
    	while (pImportDescriptor->FirstThunk != 0 && bFlag == FALSE)
    	{
    		pFuncAddr = (PDWORD)(dwImageBase + pImportDescriptor->FirstThunk);
    		while (*pFuncAddr) // 遍历该模块中的函数
    		{
    			if(dwOldAddr == *pFuncAddr){
    				// 找到要Hook的函数,先修改内存页的属性
    				VirtualProtect(pFuncAddr, sizeof(DWORD), PAGE_READWRITE, &dwOldProtect);
    				*pFuncAddr = dwNewAddr;   // !!!更改过IAT中函数的地址
    				VirtualProtect(pFuncAddr, sizeof(DWORD), dwOldProtect, 0);
    				bFlag = TRUE;
    				break;
    			}
    			pFuncAddr ++;
    		}
    		pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pImportDescriptor+sizeof(IMAGE_IMPORT_DESCRIPTOR));   // 这里之前搞错了,现在更正一下
    	}
    	// 修改状态
    	g_dwOldAddr = dwOldAddr;
    	g_dwNewAddr = dwNewAddr;
    	g_dwIATHookFlag = 1;
    	return bFlag;
    }        
    
    BOOL UnIATHook(){
    	BOOL bFlag = FALSE;
    	DWORD dwImageBase = 0;
    	PDWORD pFuncAddr = NULL;
    	PIMAGE_NT_HEADERS pNtHeader = NULL;
    	PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor = NULL;
    	DWORD dwOldProtect = 0;
    
    	// 判断是否hook
    	if (!g_dwIATHookFlag)
    	{
    		OutputDebugString("UnIATHook失败:尚未进行IAT Hook!");
    		return bFlag;
    	}
    	
    	// 得到exe模块基址
    	dwImageBase = (DWORD)GetModuleHandle(NULL);
    	pNtHeader = (PIMAGE_NT_HEADERS)(dwImageBase + ((PIMAGE_DOS_HEADER)dwImageBase)->e_lfanew);
    	pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(dwImageBase + 
    		pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
    	
    	// 遍历IAT表 找到这个函数的地址
    	while (pImportDescriptor->FirstThunk != 0 && bFlag == FALSE)
    	{
    		pFuncAddr = (PDWORD)(dwImageBase + pImportDescriptor->FirstThunk);
    		while (*pFuncAddr) // 遍历该模块中的函数
    		{
    			if(g_dwNewAddr == *pFuncAddr){
    				// 找到要Hook的函数,先修改内存页的属性
    				VirtualProtect(pFuncAddr, sizeof(DWORD), PAGE_READWRITE, &dwOldProtect);
    				*pFuncAddr = g_dwOldAddr;   // !!!更改过IAT中函数的地址
    				VirtualProtect(pFuncAddr, sizeof(DWORD), dwOldProtect, 0);
    				bFlag = TRUE;
    				break;
    			}
    			pFuncAddr ++;
    		}
    		pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pImportDescriptor+sizeof(PIMAGE_IMPORT_DESCRIPTOR));
    	}
    	// 修改状态
    	g_dwOldAddr = 0;
    	g_dwNewAddr = 0;
    	g_dwIATHookFlag = 1;
    	return bFlag;
    }       
    
    
    int WINAPI MyMessageBox(HWND hWnd, LPCSTR lpText,LPCSTR lpCaption, UINT uType){
    	char lpNewText[] = "你被hook了";
    	// 定义MessageBox函数指针
    	typedef int (WINAPI *PFNMESSAGEBOX)(HWND, LPCSTR, LPCSTR, UINT);
    
    	// 执行真正的函数
    	int ret = ((PFNMESSAGEBOX)g_dwOldAddr)(hWnd, lpNewText, lpCaption, uType);
    	return ret;
    }
    
    
    
    
    // 线程函数
    DWORD WINAPI ThreadProc(LPVOID lpParameter){
    	// 保存原始函数地址
    	DWORD pOldFuncAddr = (DWORD)GetProcAddress(LoadLibrary("user32.dll"), "MessageBoxA");
    	// 安装或者卸载HOOK
    	if (!g_dwIATHookFlag){
    		SetIATHook(pOldFuncAddr, (DWORD)MyMessageBox);
    	}else{
    		UnIATHook();
    	}
    	return 0;
    }
    
    
    
    
    BOOL APIENTRY DllMain( HANDLE hModule, 
                           DWORD  ul_reason_for_call, 
                           LPVOID lpReserved
    					 )
    {
    	switch ( ul_reason_for_call)
        {
        case DLL_PROCESS_ATTACH:
            CreateThread(NULL,0,
                (LPTHREAD_START_ROUTINE)ThreadProc,
                NULL, 0,NULL);//创建新线程执行代码
            break;
        case DLL_PROCESS_DETACH:
            break;
        case DLL_THREAD_ATTACH:
            break;
        case DLL_THREAD_DETACH:
            break;
    	}
        return TRUE;
    }
    

    injection.cpp(运行来注入dll的程序):

    #include <windows.h>
    #include <tlhelp32.h>
    #include <stdio.h>
    
    DWORD GetPid(char* szName){
        HANDLE hprocessSnap = NULL;
        PROCESSENTRY32 pe32 = {0};
        hprocessSnap = CreateToolhelp32Snapshot(
            TH32CS_SNAPPROCESS,
            0);//捕捉所有进程的快照
        if (hprocessSnap == INVALID_HANDLE_VALUE){
            //快照失败
            return 0;
        }
        //初始化pe32结构体
        pe32.dwSize = sizeof(PROCESSENTRY32);
        if (Process32First(hprocessSnap, &pe32)){
            do{
                if (!strcmp(szName, pe32.szExeFile)){
                    printf("Process Found, PID: %d 
    ", (int)pe32.th32ProcessID);
                    return (int)pe32.th32ProcessID;
                }
                //遍历查找进程名
            }while (Process32Next(hprocessSnap, &pe32));
        }else{
            CloseHandle(hprocessSnap);
        }
        return 0;
    }
    
    
    
    //远程线程注入
    BOOL load_dll(DWORD dwProcessID, char* szDllPathName)
    //进程PID和dll完整的路径
    {
        BOOL bRet;
        HANDLE hProcess;
        HANDLE hThread;
        DWORD dwLength;
        DWORD dwLoadAddr;
        LPVOID lpAllocAddr;
        DWORD dwThreadID;
        HMODULE hModule;
        //获取进程句柄
        hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwProcessID);
        printf("%x 
    ", hProcess);
        if (hProcess == NULL)
        {
            OutputDebugString("fail to open process 
    ");
            return FALSE;
        }
        //把DLL文件路径字符串存入被注入进程的内存空间
        //计算dll路径名字长度,并且加上结尾0的空间
        dwLength = strlen(szDllPathName)+1;
        //远程申请内存空间
        lpAllocAddr = (LPVOID)VirtualAllocEx(hProcess,NULL,dwLength,MEM_COMMIT,PAGE_READWRITE);
        if (lpAllocAddr == NULL){
            OutputDebugString("VirtualAllocEx error 
    ");
            CloseHandle(hProcess);
            return FALSE;
        }
        //拷贝dll路径名字到目标进程的内存
        bRet = WriteProcessMemory(hProcess, lpAllocAddr,szDllPathName,dwLength,NULL);
        if (bRet == NULL){
            OutputDebugString("bRet error 
    ");
            CloseHandle(hProcess);
            return FALSE;
        }
        //获取kernel32.dll的地址
        hModule = GetModuleHandle("Kernel32.dll");
        if (!hModule)
        {
            OutputDebugString("GetModuleHandle error 
    ");
            CloseHandle(hProcess);
            return FALSE;
        }
        //获取LoadLibraryA函数地址
        dwLoadAddr = (DWORD)GetProcAddress(hModule, "LoadLibraryA");
        if (!dwLoadAddr )
        {
            OutputDebugString("GetProcAddress error 
    ");
            CloseHandle(hProcess);
            CloseHandle(hModule);
            return FALSE;
        }
    	
        //创建远程线程,加载dll
        hThread = CreateRemoteThread(hProcess, NULL, 0, (unsigned long (__stdcall *)(void *))dwLoadAddr, lpAllocAddr, 0, NULL);
        printf("%x 
    ", hThread);
        if (hThread == NULL)
        {
            OutputDebugString("fail to open RomoteThread 
    ");
            CloseHandle(hProcess);
            return FALSE;
        }
        CloseHandle(hProcess);
    	
        return TRUE;
    }
    void main(){
    	load_dll(GetPid("1.exe"), "C:\Users\thinkpad\Desktop\IATHook\dll\1\Debug\1.dll");
    }
    

    被注入的程序:

    #include <windows.h>
    
    int main(){
    	while (1){
    		MessageBox(0,0,0,0);
    		Sleep(1000);
    	}
    	return 0;
    }
    

    经过测试可以成功hookMessageBoxA这样一个函数。
    但是有些细节做的不是很好,有空改进一下。

    本文来自博客园,作者:Mz1,转载请注明原文链接:https://www.cnblogs.com/Mz1-rc/p/15308779.html

    如果有问题可以在下方评论或者email:mzi_mzi@163.com

  • 相关阅读:
    spark性能调优 数据倾斜 内存不足 oom解决办法
    python2的中文编码
    spark UDF函数
    spark cache table
    spark 创建稀疏向量和矩阵
    mysql 分组排序
    给pyspark 设置新的环境
    CF662C Binary Table
    bzoj 4310 跳蚤
    3.29省选模拟赛 除法与取模 dp+组合计数
  • 原文地址:https://www.cnblogs.com/Mz1-rc/p/15308779.html
Copyright © 2020-2023  润新知