逆向工程核心原理——全局API钩取

  1. 目标
  2. 目标API
    1. 查看IE加载了哪些DLL
    2. 验证:调试IE进程
  3. IE进程结构
  4. ntdll!ZwResumeThread()
  5. 总结

目标

钩取IE进程的API,当它在连接到特定网站的过程中,将其连接到其他网站,类似于拦截恶意网站功能

目标API

API钩取的核心就是选择目标API,我们首先猜测一下,可能会钩取套接字库(ws2_32.dll)、微软提供的网络访问的相关库(wininet.dll、winhttp.dll)就可以了。

查看IE加载了哪些DLL

在Wininet.dll中有个API(InternetConnect())用来连接某个网络

HINTERNET InternetConnectA(
  [in] HINTERNET     hInternet,
  [in] LPCSTR        lpszServerName,//要连接的URL
  [in] INTERNET_PORT nServerPort,
  [in] LPCSTR        lpszUserName,
  [in] LPCSTR        lpszPassword,
  [in] DWORD         dwService,
  [in] DWORD         dwFlags,
  [in] DWORD_PTR     dwContext
);

验证:调试IE进程

我们用OD开启一个IE浏览器,在InternetConnect下断点,然后在浏览器输入www.baidu.com

程序会在InternetConnect断下来,连接地址就是我们输入的网站,现在我们将“www.baidu.com”改成“www.sohu.cocm”试试

这时候我们F9运行还是会在这断下来,因为一个网站是由多个链接地址组成,需要将断点删除后再运行

IE进程结构

我们先打开多个选项卡,用PChunter查看

PID为2628的iexplore.exe进程与其他几个iexplore.exe进程形成了父子关系,每个选项卡是一个单独的进程,所以当其中一个发生错误时,不会影响到其他的选项卡或者父进程。

由于创建新的选项卡就会创建新的进程,我们就需要钩取相关的进程API,达到全局钩取API的目的,否则新创建的选项卡在连接网站时无法钩取。

ntdll!ZwResumeThread()

在创建进程的API中最具有代表性的就是kernel32.CreateProcess()API,现在调试一下利用这个API编写的程序

#include<Windows.h>
#include<stdio.h>
#include<tchar.h>

void main(){
	STARTUPINFO si={0,};
	PROCESS_INFORMATION pi={0,};
	TCAHR szCmd[MAX_PATH]={0,};
	
	si.cb=sizeof(STARTUPINFO);
	_tcscpy(szCmd,L"notepad.exe");
	if(!CreateProcess(NULL,szCmd,NULL,NULL,FALSE,NORMAK_PRIORITY_CLASS,NULL,NULL,&si,&pi))
	return ;
	
	if(pi.hProcess!=NULL)
	CloseHandle(pi.hProcess);
}

我们先跟踪到kernel32.CreateProcessW(),然后F7跟进内部

我们看到在内部又调用了kernel32!CreateProcessInternalW(),这里连续的PUSH和CreateProcessW是相同的参数

kernel32!CreateProcessInternalW()比较大,我们往下面拉,就能看到ntdll!ZwCreateUserProcess()

此时的栈空间和原来的区别很大

在执行完这个API后,我们的子进程就会被挂起,然后暂停运行,notepad.exe进程已经生成,但是其EP代码尚未运行。

ntdll!ZwResumeThread()函数就是用来恢复运行线程的。这个线程即是子进程的主线程,所以当执行完后,子进程的EP代码才会执行。

总结

综上所述,CreateProcessW()API的调用流程整理如下:

kernel32!CreateProcessW
	kernel32!CreateProcessInternalW()
		ntdll!ZwCreateUserProcess()
		ntdll!ZwResumeThread()

创建子进程的过程中最后调用的API是ntdll!ZwResumeThread(),所以钩取该API。

注意

ntdll!ZwResumeThread()是尚未公开的API,函数定义如下:

NTSTATUS NtResumeThread{
IN  	HANDLE ThreadHandle,
OUT		PULONG SuspendCount OPTIONAL
}

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 767778848@qq.com