UserPC 2017.12.03
你有没有想过,恶意软件是如何从web浏览器中获取口令密码凭证的呢?最流行的攻击方法是Man-in-The-Browser (MiTB),这也是大家所说的内联挂钩(inline hooking或者detours)。inline hook技术在恶意软件中非常常见而且难以置信的好用。有了inline hook技术后,恶意软件就成为了进程的傀儡师,可以按照恶意软件作者的意图来操纵进程来做任何想做的事情。让我们一起来看看他们是怎样做到的。
inline hook要做的第一件事就是让你的代码在目标进程上下文里跑。这个过程被称作注入(injection)。
我们常见的有几种注入方法。我举个栗子,我们使用VirtualAllocEx
函数在Firefox进程的0x0D000000处创建一块内存空间。然后在0x0D000000处执行CreateRemoteThread
函数来设置钩子(hook)和做一些初始化的工作(实际的注入过程本身就是一个复杂的话题,超出了本文的范围)。下面的图片中展示了我们的注入代码块的样子。随着我们继续下去,高亮显示的区域将变得更加简洁。
inline hook有四个要素:hook,恶意代码(这里暂时用NOPs指令填充), 要覆盖的字节和恶意代码执行后的恢复返回
它是一组函数和数据结构的集合,Windows程序可以调用这些函数来让Windows操作系统做一些事情,比如打开一个文件,显示一条信息等等。
几乎所有的Windows程序都会调用各种API函数。
所以所有的这些Windows提供的能被调用的API函数就称为“The Windows API”。
钩子(hook)有时候也被叫做蹦床(trampoline),就类似与交警把一处的流量引导到另一处。在我们这个例子中,我会hook ws2_32库里的send()函数。以下是ws2_32!send函数中前几个指令正如图片里显示的那样。为了放置钩子(hook),我们需要覆盖函数中现有的一些指令。 绿色框突出显示我们将覆盖的指令。
注意上面这五个字节就是将要被覆盖的。这也是放置我们钩子(hook)所需要的确切数字:一个跳转到我们的0x0D000000处的代码的jmp指令(其实还有其他的方法,比如使用push addr和ret指令的结合)。下面这里我们放置好钩子(hook)后的send()函数:
现在执行流已经被重定向到我们注入的代码中去了,记得,寄存器值一定得保存好以确保我们正确的返回到send()函数的执行中去的时候不会崩。在32位进程中,我们可以用pusha指令保存所有的寄存器值。当恶意代码执行完毕后,popad指令会将所有寄存器值恢复到最初执行send()调用时所处的状态。既然我们已经控制了send()函数了,我们可以做一些好玩的事情了。一个我们能做的就是去看看POST请求是否正在发送,并将这些要发送的数据同时传给我们的代码,看看里面会不会有登录口令凭证。
在我们的恶意代码执行完后,我们必须确保我们的进程恢复到我们的钩子(hook)接管之前的完全相同的状态。首先我们使用popad指令来恢复所有的寄存器值。还记得我们放置钩子(hook)时覆盖的那五个字节吗?这些指令其实也是需要运行的,所以在放置钩子(hook)时我把这些指令放到了我们的恶意代码的最末尾处,以便在寄存器值恢复后可以无缝继续运行。最后我们安全的跳回send()函数+0x5的地址(0x5是我们钩子(hook)的字节长度)。
让我们再看看我们所做的一切,获得一个整体的认识。按照箭头查看Firefox中正常的没有放置钩子(hook)的send()函数的执行流程:
在注入我们的detour后(hook后),执行流现在看起来是这样的:
你可能会在想到底要hook哪些API函数呢,这里有一些选择的理由:
这是一个简单的解决方案的伪代码,但是如果攻击者是一个厉害角色的话,那么这个伪代码可能就不是很有效了。以下代码将检查api函数ExitProcess是否以0xE9开头(操作码JMP):
原文链接:https://userpc.net/2017/12/03/understanding-detecting-inline-hooks-winapi-hooks-ring3/ 译者:knowit
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课