zoukankan      html  css  js  c++  java
  • 第34章:高级全局API钩取 : IE连接控制

    Win 7 中 Process explorer 中 IE 浏览器所加载的 DLL 文件: 

    如何查看库文件的导出函数:

    下载 VS 后直接在搜索栏输入 VS (第一个和第三个都可以),打开命令窗口,输入 命令  " dumpbin /exports 库文件绝对路径 " 就可以看到函数. 若后面再加上" > C:Users123456Desktop1.txt " ,

    就可以将导出函数保存到文件中.

    wininet.dll 中有一个导出函数 InternetConnect() ,可能与网络连接有关.

    在Win 7 64位操作系统上,对 InternetConnectW() 下断点. 

    修改字符串后,禁止断点后继续运行,成功跳转到修改后的网站.

    目前的浏览器将每个选项卡都对应为一个进程,因此要钩取整个 IE 需要采用全局钩取.

    但是,同样需要注意的是,此处注入 DLL 成功后, 已加载的进程不受影响,未来加载的程序才会受影响.

    运行配套的进程,确实如书上所说,运行完 ZwCreateUserProcess() ,程序就被挂起( Suspended ) , EP 代码未运行:

    而 NtResumeThread() 从名字可知就是恢复线程运行的.

    在用户模式下, Zw 和 Nt 系列的函数调用并无不同.在内核模式下,有不同:

    Nt 系列 API 将直接调用对应的函数代码,而 Zw 系列 API 则通过 KiSystemService,最终跳转到对应的函数代码.

    ZW开头的函数是通过eax中系统服务号去SSDT中查找相应的系统服务,然后调用之,若在驱动中直接调用NT开头的函数是不会经过SSDT的 也不会被SSDT HOOK拦截的

    ssdt 全称为 System Services Descriptor Table,中文为系统服务描述符表,ssdt 表就是把 ring3 的 Win32 API 和 ring0 的内核 API 联系起来。SSDT 并不仅仅只包含一个庞大的地址索引表,它还包含着一些其它有用的信息,诸如地址索引的基地址、服务函数个数等

    BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
    {
        char            szCurProc[MAX_PATH] = {0,};
        char            *p = NULL;
    
        switch( fdwReason )
        {
            case DLL_PROCESS_ATTACH : 
                DebugLog("DllMain() : DLL_PROCESS_ATTACH
    ");
    
                GetModuleFileNameA(NULL, szCurProc, MAX_PATH);
                p = strrchr(szCurProc, '\');
                if( (p != NULL) && !_stricmp(p+1, "iexplore.exe") )
                {
                    DebugLog("DllMain() : current process is [iexplore.exe]
    ");
    
                    // 钩取 wininet!InternetConnectW() API 之前
                   // 预先加载 wininet.dll 
                    if( NULL == LoadLibrary(L"wininet.dll") )
                    {
                        DebugLog("DllMain() : LoadLibrary() failed!!! [%d]
    ",
                                 GetLastError());
                    }
                }
    
                // hook
                hook_by_code("ntdll.dll", "ZwResumeThread", 
                             (PROC)NewZwResumeThread, g_pZWRT);            // NewZwResumeThread、NewInternetConnectW 是本 DLL 中的函数
                hook_by_code("wininet.dll", "InternetConnectW",        // 因此会直接表示为地址传入函数
                             (PROC)NewInternetConnectW, g_pICW);        
                break;
    
            case DLL_PROCESS_DETACH :
                DebugLog("DllMain() : DLL_PROCESS_DETACH
    ");
    
                // unhook
                unhook_by_code("ntdll.dll", "ZwResumeThread", 
                               g_pZWRT);
                unhook_by_code("wininet.dll", "InternetConnectW", 
                               g_pICW);
                break;
        }
    
        return TRUE;
    }
    BOOL hook_by_code(LPCSTR szDllName, LPCSTR szFuncName, PROC pfnNew, PBYTE pOrgBytes)
    {
        FARPROC pFunc = NULL;
        DWORD dwOldProtect = 0, dwAddress = 0;
        BYTE pBuf[5] = {0xE9, 0, };
        PBYTE pByte = NULL;
        HMODULE hMod = NULL;
    
        hMod = GetModuleHandleA(szDllName);
        if( hMod == NULL )
        {
            DebugLog("hook_by_code() : GetModuleHandle("%s") failed!!! [%d]
    ",
                      szDllName, GetLastError());
            return FALSE;
        }
    
        pFunc = (FARPROC)GetProcAddress(hMod, szFuncName);
        if( pFunc == NULL )
        {
            DebugLog("hook_by_code() : GetProcAddress("%s") failed!!! [%d]
    ",
                      szFuncName, GetLastError());
            return FALSE;
        }
    
        pByte = (PBYTE)pFunc;
        if( pByte[0] == 0xE9 )
        {
            DebugLog("hook_by_code() : The API is hooked already!!!
    ");
            return FALSE;
        }
    
        if( !VirtualProtect((LPVOID)pFunc, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect) )
        {
            DebugLog("hook_by_code() : VirtualProtect(#1) failed!!! [%d]
    ", GetLastError());
            return FALSE;
        }
    
        memcpy(pOrgBytes, pFunc, 5);                  //修改5字节的属性
    
        dwAddress = (DWORD)pfnNew - (DWORD)pFunc - 5;        // 计算相对地址
        memcpy(&pBuf[1], &dwAddress, 4);                // 保存原地址
      
        memcpy(pFunc, pBuf, 5);                     // 覆写函数首地址
    
        if( !VirtualProtect((LPVOID)pFunc, 5, dwOldProtect, &dwOldProtect) )
        {
            DebugLog("hook_by_code() : VirtualProtect(#2) failed!!! [%d]
    ", GetLastError());
            return FALSE;
        }
    
        return TRUE;
    }
    
    

      #define STR_MODULE_NAME (L"redirect.dll")
      #define STATUS_SUCCESS (0x00000000L)


    NTSTATUS WINAPI NewZwResumeThread(HANDLE ThreadHandle, PULONG SuspendCount) // 对 ZwResumeThread API 进行全局钩取 {                                    // 每次创建新进程,都会调用CreateProcess 里面的 ZwResumeThread 函数来唤醒进程 NTSTATUS status, statusThread;                        // 钩取此函数,可以在每次唤醒线程前,将 DLL 注入子进程中. FARPROC pFunc
    = NULL, pFuncThread = NULL; DWORD dwPID = 0; static DWORD dwPrevPID = 0; THREAD_BASIC_INFORMATION tbi; HMODULE hMod = NULL; TCHAR szModPath[MAX_PATH] = {0,}; DebugLog("NewZwResumeThread() : start!!! "); hMod = GetModuleHandle(L"ntdll.dll"); if( hMod == NULL ) { DebugLog("NewZwResumeThread() : GetModuleHandle() failed!!! [%d] ", GetLastError()); return NULL; } // call ntdll!ZwQueryInformationThread() pFuncThread = GetProcAddress(hMod, "ZwQueryInformationThread"); if( pFuncThread == NULL ) { DebugLog("NewZwResumeThread() : GetProcAddress() failed!!! [%d] ", GetLastError()); return NULL; } statusThread = ((PFZWQUERYINFORMATIONTHREAD)pFuncThread) // 调用 ZwQueryInformationThread API, 获取当前线程的 PID 值 (ThreadHandle, 0, &tbi, sizeof(tbi), NULL); if( statusThread != STATUS_SUCCESS ) { DebugLog("NewZwResumeThread() : pFuncThread() failed!!! [%d] ", GetLastError()); return NULL; } dwPID = (DWORD)tbi.ClientId.UniqueProcess;                   // 获取到 PID 值 if ( (dwPID != GetCurrentProcessId()) && (dwPID != dwPrevPID) )       // 第一次调用时 PID 值不能为 0,后面再次调用时不能注入上次注入过的进程. { DebugLog("NewZwResumeThread() => call InjectDll() "); dwPrevPID = dwPID; // change privilege if( !SetPrivilege(SE_DEBUG_NAME, TRUE) ) DebugLog("NewZwResumeThread() : SetPrivilege() failed!!! "); // get injection dll path GetModuleFileName(GetModuleHandle(STR_MODULE_NAME),           // 获取要注入的 DLL 的路径 szModPath, MAX_PATH); if( !InjectDll(dwPID, szModPath) ) DebugLog("NewZwResumeThread() : InjectDll(%d) failed!!! ", dwPID); //注入进程 } // call ntdll!ZwResumeThread() if( !unhook_by_code("ntdll.dll", "ZwResumeThread", g_pZWRT) )         //脱钩 { DebugLog("NewZwResumeThread() : unhook_by_code() failed!!! "); return NULL; } pFunc = GetProcAddress(hMod, "ZwResumeThread");                  //获取原 API 地址 if( pFunc == NULL ) { DebugLog("NewZwResumeThread() : GetProcAddress() failed!!! [%d] ", GetLastError()); goto __NTRESUMETHREAD_END; } status = ((PFZWRESUMETHREAD)pFunc)(ThreadHandle, SuspendCount);        // 调用原 API ,运行挂起的线程 if( status != STATUS_SUCCESS ) { DebugLog("NewZwResumeThread() : pFunc() failed!!! [%d] ", GetLastError()); goto __NTRESUMETHREAD_END; } __NTRESUMETHREAD_END: if( !hook_by_code("ntdll.dll", "ZwResumeThread",                 // 执行完函数之后,继续钩取函数 (PROC)NewZwResumeThread, g_pZWRT) ) { DebugLog("NewZwResumeThread() : hook_by_code() failed!!! "); } DebugLog("NewZwResumeThread() : end!!! "); return status; }
    HINTERNET WINAPI NewInternetConnectW
    (
        HINTERNET hInternet,
        LPCWSTR lpszServerName,
        INTERNET_PORT nServerPort,
        LPCTSTR lpszUsername,
        LPCTSTR lpszPassword,
        DWORD dwService,
        DWORD dwFlags,
        DWORD_PTR dwContext
    )
    {
        HINTERNET hInt = NULL;
        FARPROC pFunc = NULL;
        HMODULE hMod = NULL;
    
        // 先 unhook
        if( !unhook_by_code("wininet.dll", "InternetConnectW", g_pICW) )          // 脱钩
        {
            DebugLog("NewInternetConnectW() : unhook_by_code() failed!!!
    ");
            return NULL;
        }
    
        // call original API
        hMod = GetModuleHandle(L"wininet.dll");                         
        if( hMod == NULL )
        {
            DebugLog("NewInternetConnectW() : GetModuleHandle() failed!!! [%d]
    ",
                      GetLastError());
            goto __INTERNETCONNECT_EXIT;
        }
    
        pFunc = GetProcAddress(hMod, "InternetConnectW");                   // 获取原 API 地址     
        if( pFunc == NULL )
        {
            DebugLog("NewInternetConnectW() : GetProcAddress() failed!!! [%d]
    ",
                      GetLastError());
            goto __INTERNETCONNECT_EXIT;
        }
    
        if( !_tcsicmp(lpszServerName, L"www.naver.com") ||                   // 对指定网址进行替换
            !_tcsicmp(lpszServerName, L"www.daum.net") ||    
            !_tcsicmp(lpszServerName, L"www.nate.com") || 
            !_tcsicmp(lpszServerName, L"www.yahoo.com") )
        {
            DebugLog("[redirect] naver, daum, nate, yahoo => reversecore
    ");
            hInt = ((PFINTERNETCONNECTW)pFunc)(hInternet,
                                               L"www.reversecore.com",
                                               nServerPort,
                                               lpszUsername,
                                               lpszPassword,
                                               dwService,
                                               dwFlags,
                                               dwContext);
        }
        else
        {
            DebugLog("[no redirect]
    ");
            hInt = ((PFINTERNETCONNECTW)pFunc)(hInternet,
                                               lpszServerName,
                                               nServerPort,
                                               lpszUsername,
                                               lpszPassword,
                                               dwService,
                                               dwFlags,
                                               dwContext);
        }
    
    __INTERNETCONNECT_EXIT:                        //函数执行完之后重新钩取原 API.
    
        // hook
        if( !hook_by_code("wininet.dll", "InternetConnectW", 
                          (PROC)NewInternetConnectW, g_pICW) )
        {
            DebugLog("NewInternetConnectW() : hook_by_code() failed!!!
    ");
        }
        
        return hInt;
    }

    CreateProcess 里面封装了 CreateProcessInternal , 实际测试中,钩取 CreateProcess ,并在其中调用 CreateProcessInternal 是没有问题的.

    在 XP 系统中能正常 hide 进程,只是在 show 时完成程序后会退出.

    另外,在 VS 中编译以前的代码时,需要在 工程 - 属性 - C/C++ - 常规中,把 SDL 检查关闭,

    并且,如果运行的系统中没有相应的 DLL ,可以在 VS 中选择 代码生成 ->  运行库,将模式改为多线程调试.即设置为静态库.VS默认是动态库.

  • 相关阅读:
    bugku crypto 告诉你一个秘密(ISCCCTF)
    递归法求组合数C(m,n)
    bugku 逆向 take the maze
    P1118 [USACO06FEB]数字三角形`Backward Digit Su`… (dfs)
    递归 dfs 记忆化搜索 动态规划
    c++ 取整:四舍五入 向上取整 向下取整
    2019 计蒜之道 初赛 第一场 商汤的AI伴游小精灵
    华南理工大学“三七互娱杯” D HRY and array
    华南理工大学 “三七互娱杯” G HRY and tree
    2019年湘潭大学程序设计竞赛(重现赛)
  • 原文地址:https://www.cnblogs.com/Rev-omi/p/13462983.html
Copyright © 2011-2022 走看看