安全路透社
当前位置:安全路透社 > 网络转载 > 正文

Loadlibrary:将Windows的动态链接库移植到Linux下

项目来源https://github.com/taviso/loadlibrary

这样的事是可能的

Loadlibrary在干什么?

loadlibrar运行在linux上,它可以调用windows上dll文件中的函数,实现windows下的程序在linux上运行。目前我们介绍的这部分实现的是对windows Denfender反病毒组件中的mpengine.dll的移植,使得我们可以在linux上进行对文件进行检测以确定文件是否携带病毒。

loadlibrary有什么意义?

简单来说,它的意义就是在linux上更加容易进行fuzz测试,耗费更少的资源、时间以及能够更加方便地进行fuzz测试。windows上的安全产品使用了非常复杂的组件,这些组件往往会跨内核跨用户空间进行互联,如果我们要对他们进行测试,将要调用到整个虚拟化windows环境。举个例子,我们可以使用afl-fuzz在linux上对该程序其进行测试,并能够方便地得到相关数据,但在windows下想要实现这一目的就会非常麻烦。

Windows Defender

从原理上来说,我们现在的loadlibrary所做的事与windows Defender是相同的,这是因为我们将要导入的组件就是Windows Defender恶意软件保护服务中的核心组件–mpengine.dll

准备

由于该dll文件是32位dll文件,你的linux系统上需要安装一些依赖包来在64位机器上来解析它。(非常重要)

linux系统下需要安装的依赖包

我们需要的32位的反恶意软件文件下载链接:

mpengine

原作者说下载下来的名字叫mpam-fe.exe,但是我在ubuntu上下载下来并不叫这个名字而是一个.com文件。不过这个无所谓,我们只要利用cabextract命令提取就可以了。注意下载下来的文件要放在engine目录下再执行cabextract命令。

$ cabextract mpam-fe.exe
Extracting cabinet: mpam-fe.exe
  extracting MPSigStub.exe
  extracting mpavdlta.vdm
  extracting mpasdlta.vdm
  extracting mpavbase.vdm
  extracting mpasbase.vdm
  extracting mpengine.dll

All done, no errors.

查看版本

在engine目录下输入如下指令可以查看当前dll文件的版本。

$ exiftool mpengine.dll | grep 'Product Version Number'
Product Version Number          : 1.1.13701.0

运行

 先在loadlibrary目录下输入make构建可执行程序。

$make

完成之后得到一个可执行程序mpclient。该程序就是工具的入口。我们构建一个文件,用vi打开,输入欧洲计算机防病毒协会开发的病毒代码,保存为a.exe。将文件作为参数传给程序就可以进行验证。

X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*

 这段代码只是为了验证反病毒软件的功能,本身没有任何危害。

# ./mpclient a.exe
main(): Scanning a.exe...
EngineScanCallback(): Scanning input
EngineScanCallback(): Threat Virus:DOS/EICAR_Test_File identified.

  除此之外,类似的工具还有mpstreamfuzz和mpscript。


覆盖

在该项目中存在一个目录:coverage。这个目录包含了一个基本的pintool工具以收集覆盖数据,并且也包含了工具和脚本以便于去处理这些数据。这些工具可以支持语料库蒸馏与反语料库审查。

在最简单的操作模块中,这个工具提供了从dll文件中价值的可执行基本块的列表。

但是经过一些简单的处理我们就可以生成带注解的IDB文件或生成一个已蒸馏的语料库来进行fuzz测试。

带注解的IDB文件

下载pintool并将其解压在coverage目录下:

https://software.intel.com/en-us/articles/pintool-downloads

$ tar -zxvf pin-3.2-81205-gcc-linux.tar.gz
$ make

如果你想进行语料库蒸馏,那么执行如下命令。(需要glib-2.0的支持)

$ make coverage_parse_min

运行

执行如下命令,将会显示执行信息。

$ ./coverage/pin -t coverage/deepcover.so -- ./mpclient a.exe
main(): Scanning a.exe
EngineScanCallback(): Scanning input
EngineScanCallback(): Threat Virus:DOS/EICAR_Test_File identified.


----- COVERAGE ANALYSIS -----
         58590 Unique Instructions Executed
         10271 Unique Basic Blocks Executed
       3193230 Total Instructions Executed
        590362 Total Basic Blocks Executed
    Hottest Basic Block (0x00000000003918e7)
             11731 Executes
                 3 Instructions

默认名为coverage的生成报告

这个报告默认名称为coverage.txt,你可以重写它的名称通过设置环境变量COVERAGE_REPORT_FILE

如果你有很多的输入文件,你可以把它们放在一个目录下,利用xarg:

$ ls samples
sample1.exe
sample2.exe
sample3.zip
...
$ find samples -type f | xargs -t -I{} -P8 -n1 env COVERAGE_REPORT_FILE={}.txt ./coverage/pin -t coverage/deepcover.so -- ./mpclient {}

-P参数用来标识你能够并行处理的进程数量。把它设置成你的内核支持的数目。

语义库蒸馏:

$ find samples -type f | xargs -t -I{} -P8 -n1 env COVERAGE_REPORT_FILE={}.txt ./coverage/pin -t coverage/deepcover.so -- ./mpclient {}

构建coverage_parse_min工具

$ make -C coverage coverage_parse_min

你可以用如下命令找到蒸馏过的语义库

$ grep -H ^ samples/*.txt | awk -F: '{print $2FS$1}' | ./coverage_parse_min | cut -d: -f2 | sort -u

反语义库审查

经验告诉我们,我们的fuzz测试的覆盖率是不够高的。这个工作能够帮助我们构建出已经覆盖的数据,并标识出来我们没有覆盖到的部分。

如下的脚本可以简单地产生带注解的idb文件,处理你上述产生的覆盖报告。

$ grep -H ^ *.txt | awk -F: '{print $2FS$1}' | ./coverage_parse_min | sed -e 's#:.*/#:#g' -e 's/.txt$//' > minimal.txt
$ bash genidc.sh minimal.txt > coverage.idc

之后,你可以在IDA中加载产生的coverage.idc文件通过File->Script File....

注意事项

只有当你调用了InstrumentationCallback().这个pintool工具才会开始收集覆盖数据。

你可以通过把你不希望加载的块放置在blacklist.h上来把他们加入黑名单。


调试

 如果这个程序出现了崩溃需要进行调试,你可以按照如下步骤:

首先需要安装好gdb的环境。

然后,你需要用mpengine.dll生成一个.map文件。这个操作可以在Linux上进行也可以在window下进行。mpengine.dll在之前的步骤中已经生成的engine文件夹下。

linux执行如下命令:

> idaw -A -P+ -S"createmap.idc mpengine.map"mpengine.dll

windows执行如下步骤:

windows执行步骤

选择mpengine.dll,一路yes点过去。

产生的map文件

产生一个map文件。

将该文件放在你的linux上,进行处理。在控制台输入如下命令使得文件可以在Linux上被识别:

$ dos2unix mpengine.map

使用gdb进行调试:

$ gdb -q ./mpclient
(gdb) r a.exe

添加符号文件:

(gdb) add-symbol-file engine/mpengine.dll 0xf6af4008+0x1000 
add symbol table from file "engine/mpengine.dll"at      
.text_addr=0xf6af5008
Reading symbols from engine/mpengine.dll...done.
(gdb) shell bash genmapsym.sh 0xf6af4008+0x1000 symbols_19009.o < mpengine.map
(gdb) add-symbol-file symbols_19009.o 0
add symbol table from file "symbols_19009.o" at      
 .text_addr = 0x0
Reading symbols from symbols_19009.o...done.
(gdb) p as3_parsemetadata_swf_vars_t
$1 = {void (void)} 0xf6feb842<as3_parsemetadata_swf_vars_t>
(gdb) c

如果你想要在gdb中使用硬件断点的话,你可以使用hb或hbreak命令来代替原本的break命令

(gdb) b as3_parsemethodinfo_swf_vars_t
Breakpoint 1 at 0xf6feb8da
(gdb) c
Continuing.
main(): Scanning test/input.swf...
EngineScanCallback(): Scanning input
Breakpoint 1, 0xf6feb8da in as3_parsemethodinfo_swf_vars_t()
(gdb) bt
#0  0xf6feb8da inas3_parsemethodinfo_swf_vars_t ()
#1  0xf6dbad7f inSwfScanFunc ()
#2  0xf6d73ec3 inUfsScannerWrapper__ScanFile_scanresult_t ()
#3  0xf6d6c9e3 inUfsClientRequest__fscan_SCAN_REPLY ()
#4  0xf6d6a818 inUfsNode__ScanLoopHelper_wchar_t ()
#5  0xf6d6a626 inUfsNode__Analyze_UfsAnalyzeSetup ()
#6  0xf6d71f7f inUfsClientRequest__AnalyzeLeaf_wchar_t ()
#7  0xf6d71bb9 inUfsClientRequest__AnalyzePath_wchar_t ()
#8  0xf6dbbd88 instd___String_alloc_std___String_base_types_char_std__allocator_char______Myptr_void_()
#9  0xf6d75e72 inUfsCmdBase__ExecuteCmd__lambda_c80a88e180c1f4524a759d69aa15f87e____lambda_c80a88e180c1f4524a759d69aa15f87e__()
Backtrace stopped: previous frame inner to this frame(corrupt stack?)
(gdb) x/3i $pc
=> 0xf6feb8da <as3_parsemethodinfo_swf_vars_t+7>:     lea   ebx,[edx+0x1c]
   0xf6feb8dd<as3_parsemethodinfo_swf_vars_t+10>:  push   esi
   0xf6feb8de<as3_parsemethodinfo_swf_vars_t+11>:  mov    edx,ebx

*本文作者:风起云端,转载请注明FreeBuf.COM

未经允许不得转载:安全路透社 » Loadlibrary:将Windows的动态链接库移植到Linux下

赞 (0)
分享到:更多 ()

评论 0

评论前必须登录!

登陆 注册