前段时间领导要求实现拦截恶意软件的代码注入(包括dll注入和代码Patch),需要兼容从Windows XP到Windows 8.1的所有PC版本和服务器版本操作系统,需要兼容杀毒软件。
当时拿到这个需求非常的头痛,因为需要拦截所有进程对其他进程的注入,而我们的软件本来就是安全软件,如果我再把代码注入到所有进程中去的话很有可能这个操作就被杀毒软件定性为恶意行为,而如果在内核中hook某些内核函数也不现实,因为PatchGuard的存在导致x64位内核函数Hook直接BSOD.
但是.....领导的需求,是必须满足的,不让领导失望是下属的最重要的准则之一。经过一个多星期的主动加班、几十次BSOD,终于搞定。最终的解决方案就是这篇日记的标题,下面详细的记录一下整个过程。
首先想到的是在ImageLoadNotification回调中检测dll.如果检测至是恶意dll,就直接写Patch Dllmain让其加载失败,但是很快就被自己否定了,因为我无法去判断一个dll是进程自己需要的dll,还是在被恶意注入。
然后想到从源头查起,在进程创建的时候,检测该进程中是否正在使用某些敏感函数,如CreateRemoteThread\QueueUserAPC等。如果有的话就inline hook它们。可是在调试过程中发现CreateProcessNotification回调被调用时EPROCESS的PEB还没有完全建立,取不到模块列表,当然也取不到函数地址,而且2003 64位上的32位进程的EPROCESS->Wow64Proess还与其他的64位版本不一样,多了一层指针,不知道微软当时为什么要这样设计。
后来把时机转到了SystemThread中才一切正常。
因为功能特殊,所以不得已用到了几个未公开的函数。
首先用MASM写两个程序用来实现hook敏感函数后跳板的功能。
编译后得到以下片段:
char PatchCodeX86[] = "\x55\x8b\xec\x83\xc4\xdc\x89\x5d\xdc\x89\x75\xe0\x89\x7d\xe4\xeb"
"\x3b\x00\x00\x00\x00\x8b\x5d\xdc\x8b\x75\xe0\x8b\x7d\xe4\xc9\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x68\x44\x33\x22\x11\xc3\x5c\x5c\x2e\x5c\x61\x68\x5f\x61\x6e\x74"
"\x69\x5f\x69\x6e\x6a\x65\x63\x74\x69\x6f\x6e\x00\x89\x5d\xe8\x89"
"\x6d\xec