@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
");
GetModuleFileNameA(NULL, szCurProc, MAX_PATH);
p = strrchr(szCurProc, '\');
if( (p != NULL) && !_stricmp(p+1, "iexplore.exe") )
{
DebugLog("DllMain() : current process is [iexplore.exe]
");
//为了防止在Dll注入时wininet.dll还未被加载,所以手动加载一下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);
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;
}
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!!!
");
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");
if( pFunc == NULL )
{
DebugLog("NewInternetConnectW() : GetProcAddress() failed!!! [%d]
",
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
");
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:
// hook
if( !hook_by_code("wininet.dll", "InternetConnectW",
(PROC)NewInternetConnectW, g_pICW) )
{
DebugLog("NewInternetConnectW() : hook_by_code() failed!!!
");
}
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!!!
");
hMod = GetModuleHandle(L"ntdll.dll");
if( hMod == NULL )
{
DebugLog("NewZwResumeThread() : GetModuleHandle() failed!!! [%d]
",
GetLastError());
return NULL;
}
// 调用ntdll!ZwQueryInformationThread(),通过线程句柄获取其对应进程PID
pFuncThread = GetProcAddress(hMod, "ZwQueryInformationThread");
if( pFuncThread == NULL )
{
DebugLog("NewZwResumeThread() : GetProcAddress() failed!!! [%d]
",
GetLastError());
return NULL;
}
statusThread = ((PFZWQUERYINFORMATIONTHREAD)pFuncThread)
(ThreadHandle, 0, &tbi, sizeof(tbi), NULL);
if( statusThread != STATUS_SUCCESS )
{
DebugLog("NewZwResumeThread() : pFuncThread() failed!!! [%d]
",
GetLastError());
return NULL;
}
//子进程PID
dwPID = (DWORD)tbi.ClientId.UniqueProcess;
if ( (dwPID != GetCurrentProcessId()) && (dwPID != dwPrevPID) )
{
DebugLog("NewZwResumeThread() => call InjectDll()
");
dwPrevPID = dwPID;
// change privilege
// 打开SeDebugPrivilege特权
if( !SetPrivilege(SE_DEBUG_NAME, TRUE) )
DebugLog("NewZwResumeThread() : SetPrivilege() failed!!!
");
// 获取要注入的dll的路径
GetModuleFileName(GetModuleHandle(STR_MODULE_NAME),
szModPath,
MAX_PATH);
// 注入dll
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");
if( pFunc == NULL )
{
DebugLog("NewZwResumeThread() : GetProcAddress() failed!!! [%d]
",
GetLastError());
goto __NTRESUMETHREAD_END;
}
status = ((PFZWRESUMETHREAD)pFunc)(ThreadHandle, SuspendCount);
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;
}