Lab09-01
该恶意程序是在Lab3中最后一个实验里的可自我删除的程序,先前博客并未涉及,刚好此处使用IDAPro和Ollydbg详细分析一下该程序的行为
首先,我们依旧使用strings静态分析一下该程序,发现了如下字符串

可以合理推测该程序会向指定网址发送http报文下载或者上传文件资源,创建服务,伪造系统库文件,以及删除自身,接下来我们进入IDApro中进行详细分析

可以看到,程序开头先对参数个数进行判断,如果没有参数,便向左边代码块跳转,否则进入右边的执行逻辑。我们初始状态下是没有参数的,因此先步入左边代码块的函数进行分析

发现了OpenKey和QueryKey这两个参数,可以得知,该函数的作用便是去查询注册表 SOFTWARE\\Microsoft \\XPS\\Configuration项的,如果存在值便返回eax为1,否则clear eax
可惜,我的XP虚拟机主机中并没有该项注册表,因此我们分析返回为0的结果,此时将会进入函数sub_402410,我们深入分析该函数。由于IDA中将strcpy和strcat等函数直接使用汇编语句进行展示,不便于分析,因此我们此处可以使用IDA反汇编功能,将汇编代码转化成C语言分析(Tab键即可)


可以看出来,这里执行了操作 cmd.exe /c del "Filename" >> NUL结合动态分析的行为特征,不难得知,此处是要删除恶意程序本身
接下来,我们分析一下含有参数的程序运行情况

首先分析一下压入函数中的参数是什么:根据这一系列转换,不难看出压入了argv[argc-1]中的数据,也就是程序的最后一个参数,接下来我们进入函数

很简单便可以发现,此处对压入的字符串进行了一系列验证:首先长度要为4,其次首位字母为’a’,次位字母为’a’+1=’b’,第三位字母为99=’c’,第四位字母为’c’+1=’d’,结合这个字符串是原本恶意程序的最后一个参数,不难想到,这是程序的密码。如果读者还不熟悉字符串的操作,无法直接看出来密码,也可以使用python脚本进行分析
def find_correct_string():
# 逆推结果
a1 = [''] * 4
a1[0] = chr(97) # 第一个字符 'a'
a1[1] = chr(ord(a1[0]) + 1) # 第二个字符 'b'
v2 = ord(a1[1]) - ord(a1[0]) # v2 = 1
a1[2] = chr(99 * v2) # 第三个字符 'c'
v3 = 99 * v2 # v3 = 99
a1[3] = chr(v3 + 1) # 第四个字符 'd'
return ''.join(a1)
print(find_correct_string())
接下来我们继续向下分析,根据代码块结构可以发现是一连串的if判断语句,并且可以判断出来,此处是在比较第一个参数选项与指定字符串是否匹配
查看数据,可以得知程序一共有四个选项,分别为 -cc 、-c、 -re和-in,并且如果最后判断均不是的话,将会直接删除自身并退出

接下来,我们具体分析每个参数选项的行为
-cc

该段代码的作用是,将先前注册表中的项目的值分别复制到这几个地址中。接下来,通过下图中的格式化字符print出具体的值

-c
首先是判断输入的参数是否有7个,其次依次将第3、4、5、6个参数压入栈中,作为函数sub_401070的参数

我们继续深入函数进行分析,可以发现-c与-cc互相呼应,这里的作用便是创建对应注册表项的并且设置其键值,数值分别为压入的参数
-re
首先依据参数为3个或4个来进行分支,不满足的直接删除自身并退出

接下来先判断3个参数的情况,总共调用了两个函数,推测函数一用来为局部变量赋值,函数2用于对该处地址或者句柄进行操作

深入第一个函数,观察可发现作用为获取当前运行文件的路径并将路径分解为驱动器、目录、文件名和扩展名,并只将文件名存入到先前的局部参数中

在观察第二个函数,发现它先删除了对应的服务项目,然后通过调用函数等一系列操作又删除了注册表中的值以及根目录下的程序



那么结合我们的分析,不难猜出,这个参数选项的作用便是完全卸载该恶意程序,同理,参数为4的情况便是指定文件了

-in
经过我们上面这么多步骤的分析,不难想到,这一个选项便是”install”了,但我们依然分析一下安装过程它做了哪些操作。同样的参数为3、4两种分支,但结合-re的过程,不难猜出4个参数便是指定了文件名,因此,我们只分析3参数情况便够了。

此时我们只需要分析sub_402600便可,其他函数先前均已分析过了,我们深入该函数分析

可见其作用是创建服务项,依据服务指定位置,修改环境变量和拷贝对应源程序,并且将该程序的时间戳修改至与kernel32.dll时间戳一致。最后设置注册表值。
既然此时我们已经有了注册表中对应的值了,那么我们回头来看刚才略过的默认执行方案,进入剩下的函数分析,可以发现这是一个依据注册表中值来采取不同网络操作的函数

我们的静态分析到此结束,接下来使用ollydbg进行上述功能的验证,我们首先使用-in选项安装该程序

接下来我们会发现程序的入口点并不在main函数处,而是位于PE文件指定的入口点。我们根据IDA的分析可以得知,main函数位于0x402AF0,因此我们只需要进入call 0x402AF0操作的内部便可以了


此时我们根据IDA内的代码地址,选取几个调试的关键断点,用于判断我们刚才的静态分析是否正确,首先检验密码是否正确

接下来检查install后是否存在相应的注册表值、服务等等一系列特征


运行通过,我们检验一下本机特征值


可以看到程序如我们所预料的完成了这些操作,接下来再运行一下另外几个选项,观察我们分析的结果



运行结果表明分析正确,同时要想修复至不使用密码的状态,可以再ollydbg中如此操作:
首先在ollydbg中找到对应的跳转点,0x402B01,并将jnz指令后的地址修改为参数比较地址0x402b3f,并且要修复后续参数个数的比较部分,此处我们只用到了-in,-re以及-cc,因此只对这几处参数个数进行修改(鉴于篇幅原因,此处并未列出)



将修改复制到可执行文件中,再对修改后的程序进行测试;结果:无需密码也可运行,修改成功!!!

对于Lab09-01的分析就此结束。
Lab09-02
鉴于后面的程序逐渐庞大,我们不可能每一个程序都分析如此多的篇幅,因此接下来,我将采取任务导向的方式,围绕书中的任务展开对程序的分析
笔者在Lab09-01中依旧是以IDAPro为主导的,毕竟如果你真的能看懂程序源码的话,那么所有功能都自在掌握之中了(笑。但毕竟本章主题是使用Ollydbg进行动态分析,我们接下来还是回归正轨,先使用Ollydbg动态分析程序的行为,再使用IDAPro这个强大的工具吧
按照惯例,我们依旧首先进行基础的静态分析,使用strings当然是你快速了解一个程序功能的不二之选

着重关照一下这一部分字符串,存在CreateProcessA和WS2_32.dll,我们不难猜出,可能会通过远程网络连接在本地机留下后门程序。接下来,我们现将本次书上提及的任务展示出来吧,便于读者有一个大体的方向

其中第一个任务我们已经完成了。接下来看看第二个任务,为了以防万一,我们运行程序的时候还是在虚拟机中进行,同时打开Process Exploer观察恶意程序的操作

我们可以看到该程序在PM中只有注册表的访问和文件操作,在PE中完全看不到存活状态,应该是没有执行恶意操作便直接退出了。为了验证猜测,我们现在使用Ollydbg进行动态分析。
同理,当前入口点并不是main函数,我们结合IDA信息,判断出main函数地址为0x401128,在dbg中直接步入main函数

接下来我们向下运行,首先看到了加载到内存的一串字符以及程序获取了当前进程信息


我们在IDA中快速梳理一下逻辑,发现了两个字符串函数strrchr和strcmp

其中strrchr是用于获取程序名称的。并且发现在strcmp后程序立马进行了跳转。因此我们猜测,该程序通过名字是否一致来决定是否运行,在dbg中验证。发现期望程序名为ocl.exe.

如果字符串不相等,跳转以后直接到达main_end,结束程序运行。因此我们的二三问便有答案了,想要运行程序,首先得将程序名修改为ocl.exe.

我们在改名以后重新载入dbg,运行到分支点,再向下运行,经过套接字的创建和初始化以后,我们来到了程序中的自定义函数,首先步过观察一下返回情况


发现输入一串无意义字符以后,函数返回值为一串网址,猜测为解密函数。而这一串无意义字符正是在0x401133处赋值到栈上的,问题四解决。在IDA中大致看一下这个解密函数的操作


并且在我们也刚好解决了第五六七问:参数便是那一串无意义字符;域名为dbg中呈现的;编码函数已有图片。我们接下来分析最后一个问题,首先跳转到0x40106E.
由于教材上的网址早就失效了,所以我们进行静态分析是最为方便的,不需要修改参数。发现此处主要是修改了进程的启动信息,将标准输入输出报错等信息都重定向到了套接字中,并且无窗口的启动了一个cmd。可以推断出,此处是用于从远程主机上获取本地shell,是一个后门程序。

Lab09-03
依然,我们首先看一下此次任务

既然要查看导入的dll,我们首先用PEID打开该程序,发现静态加载了4个dll

但此处并未看到题上所说的Dll.dll,所以我们还要考虑采用LoadLibrary动态加载dll库的可能性,因此我们打开IDA,查看该函数的交叉引用。发现有两处调用



因此,一共调用了六个dll库。要想查看这三个DLL库的基地址,分别将他们放到PEID中查看imagebase即可,发现三个的基址都在0x10000000处



但是程序在动态调用的过程中必然不可能将3个DLL加载到同一地址,因此我们使用Ollydbg动态分析dll分配的基址


可以看到DLL1被加载到了0x10000000,DLL2被加载到了0x390000,但尚未看到DLL3地址–因为他是动态加载的,我们需要先运行到LoadLibrary后

接下来我们分析一下DLL1的调用函数,不难看出,该函数用于打印出DLL1的magic数字,该数字存储在0x10008030,对其交叉引用,看看写入了什么值

发现在此写入了GetCurrentProcessId的返回值,因此DLL1的magic数字为当前进程ID

接下来是第五问,我们可以看到,写入的文件名是DLL2ReturnJ的返回值,对该Dll文件进行分析

发现该函数是将0x1000B078处的值直接返回到eax中,因此我们交叉引用查看赋值的操作

可以看到,此处创建了一个名为temp.txt的文件,并且写入了此地址。可以知道了写入的文件名就是temp.txt了。同时发现,DLL2print的数字恰好为此处变量值


接下来分析第六个问题,我们在dbg中运行到此,发现第二个参数正是DLL3中的,因此我们打开DLL3进行分析

可以看到Buffer是由DLL3GetStructure函数赋值的,我们具体分析该函数

同样交叉引用分析,发现0x1000B0A0在此处赋值


我们再看一下DLL3会打印出什么,结合MultiByteToWideChar的操作,可以知道,WideCharStr中将存放着转换后的网址宽字符字符串

只剩下第八问,这个很好解决,只需要我们在加载DLL时选择手工加载,并依照着Ollydbg中的地址选择加载点便可以了

看到我们已经成功在IDA中把DLL2加载到0x390000处,至此,所有任务圆满完成!!!