• [dll注入实现IAT勾取] 计算器显示中文


    勾取dll源码详解:

    • 首先在创建时候来保存原始IAT地址到全局变量,然后通过Hook_iat函数来进行iat函数的勾取
    BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
    {
        switch( fdwReason )
        {
            case DLL_PROCESS_ATTACH : 
                //保存原始API(后面脱钩会用到此地址)
                   g_pOrgFunc = GetProcAddress(GetModuleHandle(L"user32.dll"), 
                                            "SetWindowTextW");
    
                // # hook
                //  用hookiat.mysetwindowText()勾取user32.serwindowTextW();
                hook_iat("user32.dll", g_pOrgFunc, (PROC)MySetWindowTextW);
                break;
    
            case DLL_PROCESS_DETACH :
                // # unhook
                //   把calc.exe的iat恢复原来的值
                hook_iat("user32.dll", (PROC)MySetWindowTextW, g_pOrgFunc);
                break;
        }
    
        return TRUE;
    }
    • hook_iat参数1,dll名称,
    • 参数2,原始的API地址(需要被勾取的)
    • 参数3,自己写的替换API地址的函数(勾取函数)
    // hook_iat
    //   负责iat的勾取
    BOOL hook_iat(LPCSTR szDllName, PROC pfnOrg, PROC pfnNew)
    {
        HMODULE hMod;
        LPCSTR szLibName;
        PIMAGE_IMPORT_DESCRIPTOR pImportDesc; 
        PIMAGE_THUNK_DATA pThunk;
        DWORD dwOldProtect, dwRVA;
        PBYTE pAddr;
        //*首先进行PE文件头信息的读取*/
        // hMod, pAddr = ImageBase of calc.exe
        //             = VA to MZ signature (IMAGE_DOS_HEADER)
        hMod = GetModuleHandle(NULL);
        pAddr = (PBYTE)hMod;
    
        // pAddr = VA to PE signature (IMAGE_NT_HEADERS)
        pAddr += *((DWORD*)&pAddr[0x3C]);
    
        // dwRVA = RVA to IMAGE_IMPORT_DESCRIPTOR Table
        dwRVA = *((DWORD*)&pAddr[0x80]);
    
        // pImportDesc = VA to IMAGE_IMPORT_DESCRIPTOR Table 如果想要找到IAT首先要找到导入表对应的位置
        pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)hMod+dwRVA);
        /*通过循环来比较找到user32.dll中的导入表结构*/
        for( ; pImportDesc->Name; pImportDesc++ )
        {
            // szLibName = VA to IMAGE_IMPORT_DESCRIPTOR.Name
            szLibName = (LPCSTR)((DWORD)hMod + pImportDesc->Name);
            if( !_stricmp(szLibName, szDllName) )
            {
                // pThunk = IMAGE_IMPORT_DESCRIPTOR.FirstThunk
                //        = VA to IAT(Import Address Table)
                pThunk = (PIMAGE_THUNK_DATA)((DWORD)hMod + 
                                             pImportDesc->FirstThunk);
    
                // pThunk->u1.Function = VA to API
                for( ; pThunk->u1.Function; pThunk++ )
                {
                    if( pThunk->u1.Function == (DWORD)pfnOrg )
                    {
                        // 更改内存属性为E/R/W
                        //由于计算器原有IAT内存区域是只可读的
                        //所以勾取之前通过VirtualProtect函数将相应的IAT的内存区域更改为可读写模式
                        VirtualProtect((LPVOID)&pThunk->u1.Function, 
                                       4, 
                                       PAGE_EXECUTE_READWRITE, 
                                       &dwOldProtect);
    
                        //修改IAT值(勾取)把原有指向user32.dll/Setwindowtext的值指向我们自己的函数MySetWindowTextW
                        pThunk->u1.Function = (DWORD)pfnNew;
                        
                        // 恢复内存属性
                        VirtualProtect((LPVOID)&pThunk->u1.Function, 
                                       4, 
                                       dwOldProtect, 
                                       &dwOldProtect);                        
    
                        return TRUE;
                    }
                }
            }
        }
    
        return FALSE;
    }
    • 自写的勾取函数主要功能是将阿拉伯数字转换为中文数字,具体如下:
    BOOL WINAPI MySetWindowTextW(HWND hWnd, LPWSTR lpString)
    {
        wchar_t* pNum = L"零一二三四五六七八九";
        wchar_t temp[2] = {0,};
        int i = 0, nLen = 0, nIndex = 0;
    
        nLen = wcslen(lpString);
        for(i = 0; i < nLen; i++)
        {
            // 将阿拉伯数字转换为中文数字
            //   lpString是宽字符的字符串
            if( L'0' <= lpString[i] && lpString[i] <= L'9' )
            {
                temp[0] = lpString[i];
                nIndex = _wtoi(temp);
                lpString[i] = pNum[nIndex];
            }
        }
    
        // 调用user32.setwindowsTextW()api
        //  修改lpstring缓冲区内的内容
        return ((PFSETWINDOWTEXTW)g_pOrgFunc)(hWnd, lpString);
    }

    全dll代码:

    // include
    #include "stdio.h"
    #include "wchar.h"
    #include "windows.h"
    
    
    // typedef
    typedef BOOL (WINAPI *PFSETWINDOWTEXTW)(HWND hWnd, LPWSTR lpString);
    
    
    // globals
    FARPROC g_pOrgFunc = NULL;
    
    
    
    BOOL WINAPI MySetWindowTextW(HWND hWnd, LPWSTR lpString)
    {
        wchar_t* pNum = L"零一二三四五六七八九";
        wchar_t temp[2] = {0,};
        int i = 0, nLen = 0, nIndex = 0;
    
        nLen = wcslen(lpString);
        for(i = 0; i < nLen; i++)
        {
            // 将阿拉伯数字转换为中文数字
            //   lpString是宽字符的字符串
            if( L'0' <= lpString[i] && lpString[i] <= L'9' )
            {
                temp[0] = lpString[i];
                nIndex = _wtoi(temp);
                lpString[i] = pNum[nIndex];
            }
        }
    
        // 调用user32.setwindowsTextW()api
        //  修改lpstring缓冲区内的内容
        return ((PFSETWINDOWTEXTW)g_pOrgFunc)(hWnd, lpString);
    }
    
    
    // hook_iat
    //   负责iat的勾取
    BOOL hook_iat(LPCSTR szDllName, PROC pfnOrg, PROC pfnNew)
    {
        HMODULE hMod;
        LPCSTR szLibName;
        PIMAGE_IMPORT_DESCRIPTOR pImportDesc; 
        PIMAGE_THUNK_DATA pThunk;
        DWORD dwOldProtect, dwRVA;
        PBYTE pAddr;
        //*首先进行PE文件头信息的读取*/
        // hMod, pAddr = ImageBase of calc.exe
        //             = VA to MZ signature (IMAGE_DOS_HEADER)
        hMod = GetModuleHandle(NULL);
        pAddr = (PBYTE)hMod;
    
        // pAddr = VA to PE signature (IMAGE_NT_HEADERS)
        pAddr += *((DWORD*)&pAddr[0x3C]);
    
        // dwRVA = RVA to IMAGE_IMPORT_DESCRIPTOR Table
        dwRVA = *((DWORD*)&pAddr[0x80]);
    
        // pImportDesc = VA to IMAGE_IMPORT_DESCRIPTOR Table 如果想要找到IAT首先要找到导入表对应的位置
        pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)hMod+dwRVA);
        /*通过循环来比较找到user32.dll中的导入表结构*/
        for( ; pImportDesc->Name; pImportDesc++ )
        {
            // szLibName = VA to IMAGE_IMPORT_DESCRIPTOR.Name
            szLibName = (LPCSTR)((DWORD)hMod + pImportDesc->Name);
            if( !_stricmp(szLibName, szDllName) )
            {
                // pThunk = IMAGE_IMPORT_DESCRIPTOR.FirstThunk
                //        = VA to IAT(Import Address Table)
                pThunk = (PIMAGE_THUNK_DATA)((DWORD)hMod + 
                                             pImportDesc->FirstThunk);
    
                // pThunk->u1.Function = VA to API
                for( ; pThunk->u1.Function; pThunk++ )
                {
                    if( pThunk->u1.Function == (DWORD)pfnOrg )
                    {
                        // 更改内存属性为E/R/W
                        //由于计算器原有IAT内存区域是只可读的
                        //所以勾取之前通过VirtualProtect函数将相应的IAT的内存区域更改为可读写模式
                        VirtualProtect((LPVOID)&pThunk->u1.Function, 
                                       4, 
                                       PAGE_EXECUTE_READWRITE, 
                                       &dwOldProtect);
    
                        //修改IAT值(勾取)把原有指向user32.dll/Setwindowtext的值指向我们自己的函数MySetWindowTextW
                        pThunk->u1.Function = (DWORD)pfnNew;
                        
                        // 恢复内存属性
                        VirtualProtect((LPVOID)&pThunk->u1.Function, 
                                       4, 
                                       dwOldProtect, 
                                       &dwOldProtect);                        
    
                        return TRUE;
                    }
                }
            }
        }
    
        return FALSE;
    }
    
    
    
    BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
    {
        switch( fdwReason )
        {
            case DLL_PROCESS_ATTACH : 
                //保存原始API(后面脱钩会用到此地址)
                   g_pOrgFunc = GetProcAddress(GetModuleHandle(L"user32.dll"), 
                                            "SetWindowTextW");
    
                // # hook
                //  用hookiat.mysetwindowText()勾取user32.serwindowTextW();
                hook_iat("user32.dll", g_pOrgFunc, (PROC)MySetWindowTextW);
                break;
    
            case DLL_PROCESS_DETACH :
                // # unhook
                //   把calc.exe的iat恢复原来的值
                hook_iat("user32.dll", (PROC)MySetWindowTextW, g_pOrgFunc);
                break;
        }
    
        return TRUE;
    }

     

    然后我们通过一个DLL注入程序来注入我们的DLL

    BOOL InjectDll(DWORD dwPID, LPCTSTR szDllName)
    {
        HANDLE hProcess, hThread;
        LPVOID pRemoteBuf;
        DWORD dwBufSize = (DWORD)(_tcslen(szDllName) + 1) * sizeof(TCHAR);
        LPTHREAD_START_ROUTINE pThreadProc;
        //#1.使用dwPID获取目标进程句柄
        if ( !(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)) )
        {
            DWORD dwErr = GetLastError();
            return FALSE;
        }
        //#2.在目标进程内存中分配注入szdllName大小的内存
        pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_READWRITE);
    
        //#3.将dll路径写入分配的内存
        WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID)szDllName, dwBufSize, NULL);
         
        //#4.获取loadLibraryW()API的地址
        pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryW");
    
        //#5.在计算器进程中运行线程
        hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, pRemoteBuf, 0, NULL);
        WaitForSingleObject(hThread, INFINITE);    
    
        CloseHandle(hThread);
        CloseHandle(hProcess);
    
        return TRUE;
    } 

    有注入就有卸载,那我们一起来看看DLL卸载的源码解析:

    hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID)

    使用

    CreateToolhelp32Snapshot
    可以获取加载到进程的模块信息,将获取的hSnapshot 句柄传递给Module32First/Module32Next函数后,即可设置与MODLUEENTRY32结构体相关的模块信息
    循环比较出需要卸载的Dll文件名称
    bMore = Module32First(hSnapshot, &me);
        for( ;bMore ;bMore = Module32Next(hSnapshot, &me) )
        {
            if( !_tcsicmp(me.szModule, szDllName) || !_tcsicmp(me.szExePath, szDllName) )
            {
                bFound = TRUE;
                break;
            }
        }

    获取目标进程的句柄

    hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)

    在目标进程中载入远程线程

        pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "FreeLibrary");
        hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, me.modBaseAddr, 0, NULL);
        WaitForSingleObject(hThread, INFINITE);    

    完整DLL卸载函数如下:

    BOOL EjectDll(DWORD dwPID, LPCTSTR szDllName)
    {
        BOOL bMore = FALSE, bFound = FALSE;
        HANDLE hSnapshot, hProcess, hThread;
        MODULEENTRY32 me = { sizeof(me) };
        LPTHREAD_START_ROUTINE pThreadProc;
        //dwPID =进程ID
        //使用TH32CS_SNAPMODULE参数,获取加载到进程的DLL名称
        if( INVALID_HANDLE_VALUE == (hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID)) )
            return FALSE;
    
        bMore = Module32First(hSnapshot, &me);
        for( ;bMore ;bMore = Module32Next(hSnapshot, &me) )
        {
            if( !_tcsicmp(me.szModule, szDllName) || !_tcsicmp(me.szExePath, szDllName) )
            {
                bFound = TRUE;
                break;
            }
        }
    
        if( !bFound )
        {
            CloseHandle(hSnapshot);
            return FALSE;
        }
    
        if( !(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)) )
        {
            CloseHandle(hSnapshot);
            return FALSE;
        }
    
        pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "FreeLibrary");
        hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, me.modBaseAddr, 0, NULL);
        WaitForSingleObject(hThread, INFINITE);    
    
        CloseHandle(hThread);
        CloseHandle(hProcess);
        CloseHandle(hSnapshot);
    
        return TRUE;
    }
  • 相关阅读:
    MySQL SQL语言学习
    02-MySQL执行计划详解(EXPLAIN)
    linux下删除oracle11g单实例的方法
    01. Oracle 实例恢复
    替代变量与SQL*Plus环境设置
    9. Oracle 归档日志
    8. Oracle 联机重做日志文件(ONLINE LOG FILE)
    7. Oracle 控制文件(CONTROLFILE)
    6. Oracle 回滚(ROLLBACK)和撤销(UNDO)
    5. Oracle 表空间与数据文件
  • 原文地址:https://www.cnblogs.com/hanhandaren/p/11499073.html
Copyright © 2020-2023  润新知