首页
社区
课程
招聘
[翻译]理解/检测 Inline Hooks/ WinAPI Hooks (Ring3)
2017-12-14 21:01 5762

[翻译]理解/检测 Inline Hooks/ WinAPI Hooks (Ring3)

2017-12-14 21:01
5762

[翻译]理解/检测 Inline Hooks/ WinAPI Hooks (Ring3)

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 API?

它是一组函数和数据结构的集合,Windows程序可以调用这些函数来让Windows操作系统做一些事情,比如打开一个文件,显示一条信息等等。

 

几乎所有的Windows程序都会调用各种API函数。

 

所以所有的这些Windows提供的能被调用的API函数就称为“The Windows API”。

 

钩子(hook)

钩子(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原则

你可能会在想到底要hook哪些API函数呢,这里有一些选择的理由:

  • urlmon!URLDownloadToFile – 用于拦截下载的文件。 Shifu在每个进程中都hook了这个函数,以防止新的恶意软件下载。
  • ws2_32!send – 用于从未加密的通信流量中捕获POST口令凭据。
  • GetHostByName – Shifu hook此函数,以忽略到他的命令和控制站点的流量。
  • ws2_32!recv – 用于从未加密的流量中捕获传入的数据包数据。
  • Advapi32!CryptEncrypt – 用于在数据被加密之前捕获数据,因为它在send()函数时不会是纯文本了。
  • Advapi32!CryptDecrypt – 用于解密来自recv()函数的加密数据
  • User32!GetMessage – Shifu在这里使用钩子(hook)来拦截鼠标点击消息,来获得键盘输入。
  • Kernel32!ExitProcess– 用于防止进程自行关闭(绕过一些游戏中的反作弊措施)。

检测

这是一个简单的解决方案的伪代码,但是如果攻击者是一个厉害角色的话,那么这个伪代码可能就不是很有效了。以下代码将检查api函数ExitProcess是否以0xE9开头(操作码JMP):

FARPROC Address = GetProcAddress(GetModuleHandle("kernel32.dll"),"ExitProcess");
if (*(BYTE*)Address == 0xE9)
{
 printf("Api hooked\n");//Do your thing
}

谢谢


 

原文链接:https://userpc.net/2017/12/03/understanding-detecting-inline-hooks-winapi-hooks-ring3/
译者:knowit


[培训]内核驱动高级班,冲击BAT一流互联网大厂工 作,每周日13:00-18:00直播授课

收藏
点赞1
打赏
分享
最新回复 (4)
雪    币: 1176
活跃值: (1219)
能力值: ( LV12,RANK:380 )
在线值:
发帖
回帖
粉丝
Tennn 5 2017-12-14 21:17
2
0
没有对文件做任何混淆的话    对比静态文件是不是更好  官方库就更不用说了…
雪    币: 1152
活跃值: (847)
能力值: ( LV8,RANK:150 )
在线值:
发帖
回帖
粉丝
freakish 1 2017-12-15 09:16
3
0
提几点小建议,楼主看有没有道理,没道理直接忽略我哈:
1.  Inline  Hook这样的大家比较熟知的词汇,其实可以保持原文,有时候阅读效果更好
2.  Injection  一般大家普遍认为是    注入  的意思
3.  Reasons  for  hooking  API  calls
You  can  probably  think  of  a  reason  to  hook  every  API  call  imaginable.  Here  are  a  few:
          如果翻译成:    为什么要进行API  Hook呢?
                                  我们能想到的需要进行API  Hook的场景可能有很多,我这里随便列举几条:
雪    币: 293
活跃值: (232)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
瀚海云烟 1 2017-12-15 09:22
4
0
shifu  应该是某个恶意程式的名字吧。(写这样详细的文章不像国人之作)
雪    币: 228
活跃值: (30)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
knowit 2017-12-15 15:43
5
0
谢谢freakish和瀚海云烟的建议,原文已修改  :)
游客
登录 | 注册 方可回帖
返回