在恶意代码分析中,Windows 平台的 API 函数是非常重要的信息来源,比如通过分析恶意代码中使用的 API 函数,我们不需要对已加壳的文件进行逆向分析,因为我们只需要对恶意代码所执行的 API 调用来进行动态分析,就可以知道某个特定文件具体的功能了。通过这样的方法(分析 API 调用),我们可以确定一个文件是否具有恶意性,而有些 API 调用只有某些特殊类型的恶意软件才会去使用。比如说,常用的恶意 payload 下载 API是 URLDownloadToFile,而GetWindowDC 这个 API 一般用于间谍软件或键盘记录器等恶意工具(用于屏幕截取),因此恶意软件作者会通过使用动态导入的方式隐藏 API 函数名称,避免直接使用静态导入而完全显示出来,动态导入在 shellcode 编写中也非常常见,而本次的 Sodinokibi/REvi 勒索软件隐藏 API 函数案例为 API hash 匹配技巧,完全避免了包含函数名,仅显示函数名称的固定大小的哈希,也节省了恶意代码的存储空间。
近期分析多个勒索软件时,会遇到使用计算 hash 来获取所需 API 函数的流程,这是一种非常常用的反静态分析技巧,本文对此进行学习记录。
静态导入是在 Windows 下由 PE 文件的导入地址表(IAT)中列出的,动态导入是使用 Windows API 提供的 LoadLibrary、GetProcAddress 函数进行导入的。而 API hash 匹配导入,指为每个函数名称计算哈希值,后续通过计算哈希值后经过匹配得到所需的函数地址。
IDA 载入该样本后,整体框架只有两个函数,查询后发现没有任何导入函数,如下:
双击进入第一个函数 sub_40369D,查看如下:
一步一步分析,再接着进入 sub_406A4D,发现有跳转,跟随跳转,如下:
函数一开头就是一个循环,发现 dword_41C9F8[esi]有循环赋值的操作,而 sub_405DCF 则是关键的重建 API 函数地址的函数(后续动态调试会发现),所以首要分析该函数。该处循环每次累加 0x4,直到累加和为 0x230大小时结束,也就是在 dword_41CC24地址处结束。每个 DWORD 值对应一个 API 函数,Sodinokibi/REvi 勒索软件会使用 API hash 解析成相应的 API 函数地址。进入该数组后,发现硬编码的 hash 值内容如下,每个值为 DWORD 类型。
函数一开头就是一个循环,发现 dword_41C9F8[esi]有循环赋值的操作,而 sub_405DCF 则是关键的重建 API 函数地址的函数(后续动态调试会发现),所以首要分析该函数。该处循环每次累加 0x4,直到累加和为 0x230大小时结束,也就是在 dword_41CC24地址处结束。每个 DWORD 值对应一个 API 函数,Sodinokibi/REvi 勒索软件会使用 API hash 解析成相应的 API 函数地址。进入该数组后,发现硬编码的 hash 值内容如下,每个值为 DWORD 类型。
进入上述的 API 构建函数 sub_405DCF 内部,如下:
可以发现存在很多分支结构,有很多判断条件,为了方便,转换成伪 C 代码看看。
函数开头的就对输入参数进行了处理,该函数的输入参数是刚刚硬编码的 DWORD 大小的值,也就是 API hash 值,为了便于分析,对其进行重命名为API_hash_a1。