高级全局API钩取 - IE连接控制

@author: dlive

@date: 2017/02/14

0x01 调试IE进程

常见网络连接库:ws2_32.dll(套接字),wininet.dll,winhttp.dll

使用Process Explorer查看IE加载的DLL

IE不仅加载了ws2_32.dll还加载了wininet.dll,wininet.dll中提供的API中有个名为InternetConnect()的API,这个API用来连接网站。

HINTERNET InternetConnect(
  _In_ HINTERNET     hInternet,
  _In_ LPCTSTR       lpszServerName,
  _In_ INTERNET_PORT nServerPort,
  _In_ LPCTSTR       lpszUsername,
  _In_ LPCTSTR       lpszPassword,
  _In_ DWORD         dwService,
  _In_ DWORD         dwFlags,
  _In_ DWORD_PTR     dwContext
);	

使用OD附加IE进程,但是发现IE有两个进程,不知道该附加哪个,那就都附加上。

在wininet!InternetConnect起始处下断点,使用IE访问www.zhihu.com

可以看到OD断在InternetConnect函数开始处,修改栈上的www.zhihu.com为www.163.com,然后去掉断点

可以看到最后访问的网站是www.163.com

0x02 IE的进程结构

IE的每个选项卡对应一个进程,统一由一个父进程管理。所以钩取API时需要使用全局钩取。

这里通过钩取ntdll!ZwResumeThread钩取子进程

0x03 全局钩取ntdll!ResumeThread API

因为最终目的是控制IE的网络连接,所以dll注入时仅需向所有的iexplore.exe进程中注入即可,无需对其他无关进程注入dll。

1.DllMain

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\n");

            GetModuleFileNameA(NULL, szCurProc, MAX_PATH);
            p = strrchr(szCurProc, '\\');
            if( (p != NULL) && !_stricmp(p+1, "iexplore.exe") )
            {
                DebugLog("DllMain() : current process is [iexplore.exe]\n");

                //为了防止在Dll注入时wininet.dll还未被加载,所以手动加载一下wininet.dll
                if( NULL == LoadLibrary(L"wininet.dll") )
                {
                    DebugLog("DllMain() : LoadLibrary() failed!!! [%d]\n",
                             GetLastError());
                }
            }

            // hook
            hook_by_code("ntdll.dll", "ZwResumeThread", 
                         (PROC)NewZwResumeThread, g_pZWRT);
            hook_by_code("wininet.dll", "InternetConnectW", 
                         (PROC)NewInternetConnectW, g_pICW);
            break;

        case DLL_PROCESS_DETACH :
            DebugLog("DllMain() : DLL_PROCESS_DETACH\n");

            // unhook
            unhook_by_code("ntdll.dll", "ZwResumeThread", 
                           g_pZWRT);
            unhook_by_code("wininet.dll", "InternetConnectW", 
                           g_pICW);
            break;
    }

    return TRUE;
}

2.NewInternetConnectW

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!!!\n");
        return NULL;
    }

    // call original API
    hMod = GetModuleHandle(L"wininet.dll");
    if( hMod == NULL )
    {
        DebugLog("NewInternetConnectW() : GetModuleHandle() failed!!! [%d]\n",
                  GetLastError());
        goto __INTERNETCONNECT_EXIT;
    }

    pFunc = GetProcAddress(hMod, "InternetConnectW");
    if( pFunc == NULL )
    {
        DebugLog("NewInternetConnectW() : GetProcAddress() failed!!! [%d]\n",
                  GetLastError());
        goto __INTERNETCONNECT_EXIT;
    }
	
  	//修改原API调用时的第二个参数
    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\n");
        hInt = ((PFINTERNETCONNECTW)pFunc)(hInternet,
                                           L"www.reversecore.com",
                                           nServerPort,
                                           lpszUsername,
                                           lpszPassword,
                                           dwService,
                                           dwFlags,
                                           dwContext);
    }
    else
    {
        DebugLog("[no redirect]\n");
        hInt = ((PFINTERNETCONNECTW)pFunc)(hInternet,
                                           lpszServerName,
                                           nServerPort,
                                           lpszUsername,
                                           lpszPassword,
                                           dwService,
                                           dwFlags,
                                           dwContext);
    }

__INTERNETCONNECT_EXIT:

    // hook
    if( !hook_by_code("wininet.dll", "InternetConnectW", 
                      (PROC)NewInternetConnectW, g_pICW) )
    {
        DebugLog("NewInternetConnectW() : hook_by_code() failed!!!\n");
    }
    
    return hInt;
}

3.NewZwResumeThread

//ThreadHandle是要恢复运行的线程的句柄(即子进程的主线程)
NTSTATUS WINAPI NewZwResumeThread(HANDLE ThreadHandle, PULONG SuspendCount)
{
    NTSTATUS status, statusThread;
    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!!!\n");

    hMod = GetModuleHandle(L"ntdll.dll");
    if( hMod == NULL )
    {
        DebugLog("NewZwResumeThread() : GetModuleHandle() failed!!! [%d]\n",
                  GetLastError());
        return NULL;
    }

  	// 调用ntdll!ZwQueryInformationThread(),通过线程句柄获取其对应进程PID
    pFuncThread = GetProcAddress(hMod, "ZwQueryInformationThread");
    if( pFuncThread == NULL )
    {
        DebugLog("NewZwResumeThread() : GetProcAddress() failed!!! [%d]\n",
                  GetLastError());
        return NULL;
    }

    statusThread = ((PFZWQUERYINFORMATIONTHREAD)pFuncThread)
                   (ThreadHandle, 0, &tbi, sizeof(tbi), NULL);
    if( statusThread != STATUS_SUCCESS )
    {
        DebugLog("NewZwResumeThread() : pFuncThread() failed!!! [%d]\n", 
                 GetLastError());
        return NULL;
    }
	
  	//子进程PID
    dwPID = (DWORD)tbi.ClientId.UniqueProcess;
    if ( (dwPID != GetCurrentProcessId()) && (dwPID != dwPrevPID) )
    {
        DebugLog("NewZwResumeThread() => call InjectDll()\n");

        dwPrevPID = dwPID;

        // change privilege
      	// 打开SeDebugPrivilege特权
       	if( !SetPrivilege(SE_DEBUG_NAME, TRUE) )
            DebugLog("NewZwResumeThread() : SetPrivilege() failed!!!\n");

      	// 获取要注入的dll的路径
        GetModuleFileName(GetModuleHandle(STR_MODULE_NAME), 
                          szModPath, 
                          MAX_PATH);
		// 注入dll
        if( !InjectDll(dwPID, szModPath) )
            DebugLog("NewZwResumeThread() : InjectDll(%d) failed!!!\n", dwPID);
    }

    // call ntdll!ZwResumeThread()
    if( !unhook_by_code("ntdll.dll", "ZwResumeThread", g_pZWRT) )
    {
        DebugLog("NewZwResumeThread() : unhook_by_code() failed!!!\n");
        return NULL;
    }

    pFunc = GetProcAddress(hMod, "ZwResumeThread");
    if( pFunc == NULL )
    {
        DebugLog("NewZwResumeThread() : GetProcAddress() failed!!! [%d]\n",
                  GetLastError());
        goto __NTRESUMETHREAD_END;
    }

    status = ((PFZWRESUMETHREAD)pFunc)(ThreadHandle, SuspendCount);
    if( status != STATUS_SUCCESS )
    {
        DebugLog("NewZwResumeThread() : pFunc() failed!!! [%d]\n", GetLastError());
        goto __NTRESUMETHREAD_END;
    }

__NTRESUMETHREAD_END:

    if( !hook_by_code("ntdll.dll", "ZwResumeThread", 
                      (PROC)NewZwResumeThread, g_pZWRT) )
    {
        DebugLog("NewZwResumeThread() : hook_by_code() failed!!!\n");
    }

    DebugLog("NewZwResumeThread() : end!!!\n");

    return status;
}
posted @ 2017-02-14 19:03  dlive  阅读(671)  评论(0编辑  收藏  举报