《逆向工程核心原理》<04-33> 通过DLL注入修改API代码实现API钩取的技术

来源:互联网 发布:淘宝给了好评能删除吗 编辑:程序博客网 时间:2024/05/19 23:11

原理:

原理(通过DLL注入修改API代码实现API钩取的技术):

(技术流程: 代码-DLL注入-CreatRemoteThread.etc)
库文件被加载到内存后, 在其目录映像中直接修改要钩取的API代码本身

Detail:先向目标进程注入用户DLL,将API代码的前5个字节修改为JMP xxxxxxxx指令来钩取API, 调用执行被钩取的API时, 修改后的JMP xxxxxxxx指令就会被执行, 转而控制hooking函数

原理(进程隐藏):

为了隐藏某个特定进程, 要潜入其他所有进程内存, 钩取相关API
实现进程隐藏的关键不是程序自身, 而是其他进程

Detail:ZwQuerySystemInformation()
NTSTATUS ZwQuerySystemInformation(    SYSTEM_INFORMATION_CLASS SystemInformationClass;    PVOID   SysINfomation;    ULONG   SystemInformationlength;    PULONG  ReturnLength;);

隐藏进程时需要钩取系统中运行的所有进程的 ZwQuerySystemInformation()API,
并且对后面将要启动运行的所有进程也要做相同的钩取操作, 这便是全局钩取

原理(全局API钩取):

向当前运行的所有进程注入DLL后, 如果在该DLL中将CreateProcess()API也一起钩取, 那么以后运行的进程也会自动注入该DLL文件

Detial:
所有进程都是由父进程(使用CreateProcess())创建的, 所以钩取父进程的CreateProcess()API就可以将DLL文件注入所有子进程(父进程通常都是explorer.exe)
考虑到钩取比kernel32.CreateProcess()更低级的API, 选择钩取ntdll.ZwResumeThread()API

原理(7字节代码修改技术_Hot Patch):

API起码代码的MOV指令(2个字节)与其上方的5个NOP指令(5个字节)合起来共7个字节的指令没有任何意义
原因是为了方便”打热补丁”. “热补丁”由API钩取组成, 在进程处于运行状态时临时更改进程内存中的库文件(重启系统时, 修改的目标库文件会被完全取代)

Detail:A. 二次跳转    API起始代码之前的5个字节修改为FAR JMP指令(E9 xxxxxxxx)    API起始代码的2个字节修改为SHORT JMP指令(E8 F9)B. 不需要在钩取函数内部进行"脱钩"/挂钩操作    在"5个字节代码修改技术"中"脱钩"/挂钩是为了"调用原函数"    在"热补丁"技术钩取API时, API代码在遭到修改的状态下也能正常调用原API    这是因为, 从API角度看只是修改了其起始代码的MOV EDI,EDI指令(无意义的两个字节), 从[API起始地址+2]地址开始, 仍然能正常调用原API, 且执行的动作完全一样

代码:

代码(HideProc.cpp):

01- InjectAllProcess()
BOOL InjectAllProcess(int nMode, LPCTSTR szDllPath){    DWORD                   dwPID = 0;    HANDLE                  hSnapShot = INVALID_HANDLE_VALUE;    PROCESSENTRY32          pe;    // Get the snapshot of the system 获取系统快照    pe.dwSize = sizeof( PROCESSENTRY32 );    hSnapShot = CreateToolhelp32Snapshot( TH32CS_SNAPALL, NULL );    // CreateToolhelp32Snapshot()获取系统中运行的所有进程列表    // find process 查找进程    Process32First(hSnapShot, &pe);    // Process32First() && Process32Next() 将获得的进程信息存放到PROCESSENTRY32结构体变量    do    {        dwPID = pe.th32ProcessID;        // 鉴于系统安全性的考虑        // 对于PID小于100的系统进程        // 不执行DLL注入操作        if( dwPID < 100 )            continue;        if( nMode == INJECTION_MODE )            InjectDll(dwPID, szDllPath);        else            EjectDll(dwPID, szDllPath);    }    while( Process32Next(hSnapShot, &pe) );    CloseHandle(hSnapShot);    return TRUE;}

代码(Stealth.cpp):

01- SetProcName()
// global variable (in sharing memory)#pragma comment(linker, "/SECTION:.SHARE,RWS")#pragma data_seg(".SHARE")    TCHAR g_szProcName[MAX_PATH] = {0,};#pragma data_seg()// export function#ifdef __cplusplusextern "C" {#endif__declspec(dllexport) void SetProcName(LPCTSTR szProcName){    _tcscpy_s(g_szProcName, szProcName);}#ifdef __cplusplus}#endif
02- DllMain()
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved){    char            szCurProc[MAX_PATH] = {0,};    char            *p = NULL;    // #1. 异常处理    // 若当前进程为HideProc.exe, 则终止, 不进行钩取操作    GetModuleFileNameA(NULL, szCurProc, MAX_PATH);    p = strrchr(szCurProc, '\\');    if( (p != NULL) && !_stricmp(p+1, "HideProc.exe") )        return TRUE;    switch( fdwReason )    {        // #2. API Hooking        case DLL_PROCESS_ATTACH :         hook_by_code(DEF_NTDLL, DEF_ZWQUERYSYSTEMINFORMATION,                      (PROC)NewZwQuerySystemInformation, g_pOrgBytes);        break;        // #3. API Unhooking         case DLL_PROCESS_DETACH :        unhook_by_code(DEF_NTDLL, DEF_ZWQUERYSYSTEMINFORMATION,                        g_pOrgBytes);        break;    }    return TRUE;}
03- hook_by_code()
BOOL hook_by_code(LPCSTR szDllName, LPCSTR szFuncName, PROC pfnNew, PBYTE pOrgBytes){    // hook_by_code() param:    // LPCSTR szDllName:  [IN]包含要钩取的API的DLL文件名称    // LPCSTR szFuncName: [IN]要钩取的API名称    // PROC pfnNew:       [IN]用户提供的钩取函数地址    // PBYTE pOrgBytes:   [OUT]存储原来5个字节的缓冲区, 后面"脱钩"时使用    FARPROC pfnOrg;    DWORD dwOldProtect, dwAddress;    BYTE pBuf[5] = {0xE9, 0, };    PBYTE pByte;    // 获取要钩取的API地址    pfnOrg = (FARPROC)GetProcAddress(GetModuleHandleA(szDllName), szFuncName);    pByte = (PBYTE)pfnOrg;    // 若已经被钩取, 则返回FALSE    if( pByte[0] == 0xE9 )        return FALSE;    // 为了修改5个字节, 先向内存添加"写"属性    VirtualProtect((LPVOID)pfnOrg, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect);    // 备份原有代码(5字节)    memcpy(pOrgBytes, pfnOrg, 5);    // 计算JMP地址(E9 xxxxxxxx)    // => XXXX = pfnNew - pfnOrg - 5    dwAddress = (DWORD)pfnNew - (DWORD)pfnOrg - 5;    memcpy(&pBuf[1], &dwAddress, 4);    // "钩子": 修改5个字节(JMP xxxxxxxx)    memcpy(pfnOrg, pBuf, 5);    // 恢复内存属性    VirtualProtect((LPVOID)pfnOrg, 5, dwOldProtect, &dwOldProtect);    return TRUE;}
04- unhook_by_code()
BOOL unhook_by_code(LPCSTR szDllName, LPCSTR szFuncName, PBYTE pOrgBytes){    FARPROC pFunc;    DWORD dwOldProtect;    PBYTE pByte;    // 获取API地址    pFunc = GetProcAddress(GetModuleHandleA(szDllName), szFuncName);    pByte = (PBYTE)pFunc;    // 若已经"脱钩", 贼返回FALSE    if( pByte[0] != 0xE9 )        return FALSE;    // 向内存添加"写"属性, 为恢复原代码(5个字节)准备    VirtualProtect((LPVOID)pFunc, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect);    // Unhook    memcpy(pFunc, pOrgBytes, 5);    // 恢复内存属性    VirtualProtect((LPVOID)pFunc, 5, dwOldProtect, &dwOldProtect);    return TRUE;}
05- NewZwQuerySystemInformation()
typedef NTSTATUS (WINAPI *PFZWQUERYSYSTEMINFORMATION)                 (SYSTEM_INFORMATION_CLASS SystemInformationClass,                   PVOID SystemInformation,                   ULONG SystemInformationLength,                   PULONG ReturnLength);// SystemInformationClass 参数设置为SystemProcessInformation(5)后调用ZwQuerySystemInformation()API// SystemInformation [in/out]参数中存储的是SYSTEM_PROCESS_INFORMATION结构体单向链表的起始地址, 该结构体链表中存储着运行中的所有进程信息// 所以, 隐藏某进程前, 先要查找与之对应的链表成员, 然后断开其与链表的链接typedef struct _SYSTEM_PROCESS_INFORMATION {    ULONG NextEntryOffset;    ULONG NumberOfThreads;    BYTE Reserved1[48];    PVOID Reserved2[3];    HANDLE UniqueProcessId;    PVOID Reserved3;    ULONG HandleCount;    BYTE Reserved4[4];    PVOID Reserved5[11];    SIZE_T PeakPagefileUsage;    SIZE_T PrivatePageCount;    LARGE_INTEGER Reserved6[6];} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;
NTSTATUS WINAPI NewZwQuerySystemInformation(                SYSTEM_INFORMATION_CLASS SystemInformationClass,                 PVOID SystemInformation,                 ULONG SystemInformationLength,                 PULONG ReturnLength){    NTSTATUS status;    FARPROC pFunc;    PSYSTEM_PROCESS_INFORMATION pCur, pPrev;    char szProcName[MAX_PATH] = {0,};    // 开始前先"脱钩"    unhook_by_code(DEF_NTDLL, DEF_ZWQUERYSYSTEMINFORMATION, g_pOrgBytes);    // 调用原始API    pFunc = GetProcAddress(GetModuleHandleA(DEF_NTDLL),                            DEF_ZWQUERYSYSTEMINFORMATION);    status = ((PFZWQUERYSYSTEMINFORMATION)pFunc)              (SystemInformationClass, SystemInformation,               SystemInformationLength, ReturnLength);    if( status != STATUS_SUCCESS )        goto __NTQUERYSYSTEMINFORMATION_END;    // 仅针对SystemProcessInformation类型操作    if( SystemInformationClass == SystemProcessInformation )    {        // SYSTEM_PROCESS_INFORMATION类型转换        // pCur是单向链表的头        pCur = (PSYSTEM_PROCESS_INFORMATION)SystemInformation;        while(TRUE)        {            // 比较进程名称            // g_szProcName为要隐藏的进程名称            // (= 在SetProcName()设置)            if(pCur->Reserved2[1] != NULL)            {                if(!_tcsicmp((PWSTR)pCur->Reserved2[1], g_szProcName))                {                    // 从链表中删除隐藏进程的节点                    if(pCur->NextEntryOffset == 0)                        pPrev->NextEntryOffset = 0;                    else                        pPrev->NextEntryOffset += pCur->NextEntryOffset;                }                else                            pPrev = pCur;            }            if(pCur->NextEntryOffset == 0)                break;            // 链表的下一项            pCur = (PSYSTEM_PROCESS_INFORMATION)                    ((ULONG)pCur + pCur->NextEntryOffset);        }    }__NTQUERYSYSTEMINFORMATION_END:    //     hook_by_code(DEF_NTDLL, DEF_ZWQUERYSYSTEMINFORMATION,                  (PROC)NewZwQuerySystemInformation, g_pOrgBytes);    return status;}

代码(stealth2.cpp):

01- Dllmain()
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved){    char            szCurProc[MAX_PATH] = {0,};    char            *p = NULL;    // 异常处理使注入不会发生在HideProc2.exe进程    GetModuleFileNameA(NULL, szCurProc, MAX_PATH);    p = strrchr(szCurProc, '\\');    if( (p != NULL) && !_stricmp(p+1, "HideProc2.exe") )        return TRUE;    // 改变 privilege    SetPrivilege(SE_DEBUG_NAME, TRUE);    switch( fdwReason )    {        case DLL_PROCESS_ATTACH :             // hook            hook_by_code("kernel32.dll", "CreateProcessA",                          (PROC)NewCreateProcessA, g_pOrgCPA);            hook_by_code("kernel32.dll", "CreateProcessW",                          (PROC)NewCreateProcessW, g_pOrgCPW);            hook_by_code("ntdll.dll", "ZwQuerySystemInformation",                          (PROC)NewZwQuerySystemInformation, g_pOrgZwQSI);            break;        case DLL_PROCESS_DETACH :            // unhook            unhook_by_code("kernel32.dll", "CreateProcessA",                            g_pOrgCPA);            unhook_by_code("kernel32.dll", "CreateProcessW",                            g_pOrgCPW);            unhook_by_code("ntdll.dll", "ZwQuerySystemInformation",                            g_pOrgZwQSI);            break;    }    return TRUE;}
02- NewCreateProcessA()
BOOL WINAPI NewCreateProcessA(    LPCTSTR lpApplicationName,    LPTSTR lpCommandLine,    LPSECURITY_ATTRIBUTES lpProcessAttributes,    LPSECURITY_ATTRIBUTES lpThreadAttributes,    BOOL bInheritHandles,    DWORD dwCreationFlags,    LPVOID lpEnvironment,    LPCTSTR lpCurrentDirectory,    LPSTARTUPINFO lpStartupInfo,    LPPROCESS_INFORMATION lpProcessInformation){    BOOL bRet;    FARPROC pFunc;    // unhook    unhook_by_code("kernel32.dll", "CreateProcessA", g_pOrgCPA);    // 调用初始API    pFunc = GetProcAddress(GetModuleHandleA("kernel32.dll"), "CreateProcessA");    bRet = ((PFCREATEPROCESSA)pFunc)(lpApplicationName,                                     lpCommandLine,                                     lpProcessAttributes,                                     lpThreadAttributes,                                     bInheritHandles,                                     dwCreationFlags,                                     lpEnvironment,                                     lpCurrentDirectory,                                     lpStartupInfo,                                     lpProcessInformation);    // 向生成的子进程注入stealth2.dll    if( bRet )        InjectDll2(lpProcessInformation->hProcess, STR_MODULE_NAME);    // hook    hook_by_code("kernel32.dll", "CreateProcessA",                  (PROC)NewCreateProcessA, g_pOrgCPA);    return bRet;}

代码(stealth3.cpp)

01- hook_by_hotpatch()
BOOL hook_by_hotpatch(LPCSTR szDllName, LPCSTR szFuncName, PROC pfnNew){    FARPROC pFunc;    DWORD dwOldProtect, dwAddress;    BYTE pBuf[5] = { 0xE9, 0, };    BYTE pBuf2[2] = { 0xEB, 0xF9 };    PBYTE pByte;    pFunc = (FARPROC)GetProcAddress(GetModuleHandleA(szDllName), szFuncName);    pByte = (PBYTE)pFunc;    if( pByte[0] == 0xEB )        return FALSE;    VirtualProtect((LPVOID)((DWORD)pFunc - 5), 7, PAGE_EXECUTE_READWRITE, &dwOldProtect);    // 1. NOP (0x90)    dwAddress = (DWORD)pfnNew - (DWORD)pFunc;    memcpy(&pBuf[1], &dwAddress, 4);    memcpy((LPVOID)((DWORD)pFunc - 5), pBuf, 5);    // 2. MOV EDI, EDI (0x8BFF)    memcpy(pFunc, pBuf2, 2);    VirtualProtect((LPVOID)((DWORD)pFunc - 5), 7, dwOldProtect, &dwOldProtect);    return TRUE;}
02- unhook_by_hotpatch()
BOOL unhook_by_hotpatch(LPCSTR szDllName, LPCSTR szFuncName){    FARPROC pFunc;    DWORD dwOldProtect;    PBYTE pByte;    BYTE pBuf[5] = { 0x90, 0x90, 0x90, 0x90, 0x90 };    BYTE pBuf2[2] = { 0x8B, 0xFF };    pFunc = (FARPROC)GetProcAddress(GetModuleHandleA(szDllName), szFuncName);    pByte = (PBYTE)pFunc;    if( pByte[0] != 0xEB )        return FALSE;    VirtualProtect((LPVOID)pFunc, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect);    // 1. NOP (0x90)    memcpy((LPVOID)((DWORD)pFunc - 5), pBuf, 5);    // 2. MOV EDI, EDI (0x8BFF)    memcpy(pFunc, pBuf2, 2);    VirtualProtect((LPVOID)pFunc, 5, dwOldProtect, &dwOldProtect);    return TRUE;}
03- NewCreateProcessA()
BOOL WINAPI NewCreateProcessA(    LPCTSTR lpApplicationName,    LPTSTR lpCommandLine,    LPSECURITY_ATTRIBUTES lpProcessAttributes,    LPSECURITY_ATTRIBUTES lpThreadAttributes,    BOOL bInheritHandles,    DWORD dwCreationFlags,    LPVOID lpEnvironment,    LPCTSTR lpCurrentDirectory,    LPSTARTUPINFO lpStartupInfo,    LPPROCESS_INFORMATION lpProcessInformation){    BOOL bRet;    FARPROC pFunc;    // 调用原始API    pFunc = GetProcAddress(GetModuleHandleA("kernel32.dll"), "CreateProcessA");    pFunc = (FARPROC)((DWORD)pFunc + 2);    bRet = ((PFCREATEPROCESSA)pFunc)(lpApplicationName,                                     lpCommandLine,                                     lpProcessAttributes,                                     lpThreadAttributes,                                     bInheritHandles,                                     dwCreationFlags,                                     lpEnvironment,                                     lpCurrentDirectory,                                     lpStartupInfo,                                     lpProcessInformation);    // 向生成的子进程注入stealth3.dll    if( bRet )        InjectDll2(lpProcessInformation->hProcess, STR_MODULE_NAME);    return bRet;}
0 0