《恶意代码分析实战》实验——Labs-16
记录《恶意代码分析实战》中的实验,提供相关链接:
- 电子书的下载
(*^-^*)
Labs-16-01实验
样本:Lab16-01.exe
静态分析:
- 查壳——无壳,Win32 console程序,需要命令行启动
- 查看输入表——
KERNEL32.DLL:读写、复制、删除文件,字符串比较等函数
ADVAPI32.dll:打开、创建服务,删除、创建注册表等函数
SHELLE32.DLL:执行shell命令的函数
WS2_32.dll:网络连接和操作相关函数
- Strngs分析——
字符串cmd.exe,/c del 可能会调用cmd执行命令
字符串 SOFTWARE\Microsoft\XPS,\kernel32.dll,%SYSTEMROOT%SYSTEM32\ 为注册表项,可能会修改注册表
字符串 HTTP/1.0 和 GET 可能会发送访问请求
字符串 -cc,-re,-in 可能为恶意程序的操作数/ 执行命令
IDA分析
- 程序首先进行了调试器的判定,如果当前程序运行在调试器中,则调用函数sub_401000(),在其中调用cmd进行自我删除:
- 继续往下,发现还会进行参数个数检测,如果只有一个参数,则调用函数sub_402C40,然后进行次调试器检测,如果只要不满足要求,都会调用函数sub_401000()函数进行自我删除。
- 对于函数sub_402C40()的功能,我们暂且不分析,因为其中会涉及一个关键的注册表操作,而此注册表操作又是再后面的代码进行初始化的,所以直接从此入手,会比较困难;同时结合下面的代码(参数‘in’, ‘-re’, ‘-cc’,用于程序的安装和移除),我们也应该推测出此函数的功能应该是整个恶意代码的核心功能部分。
- 继续往下,发下会将输入的第一个命令行参数传入函数sub_402D70,下面还会调用自我删除函数sub_401000,那么就可以推测出该函数应该是一个校验函数,
- 跟入该函数,该函数首先进行调试器检测,然后进行对传入的参数进行计算校验,根据算法,目标的参数应该是字符串“abcb”
- 继续往下,对命令行输入的第2个参数进行了匹配,根据不同的匹配执行不同的动作,其中 ‘in’ 进行恶意程序服务创建或者更新配置文件,‘re’ 进行服务的删除,‘c’ 用于创建新的注册表项,‘-cc’用于打印注册表项。
- 此处我们需要重点关注 ‘in’ 参数对应的安装操作——sub_402F40(),进入该函数进行分析;发现该函数会先检查服务是否存在,如果不存在,则创建新的服务,该服务的路径为被复制到系统路径下的恶意程序路径;同时还会修改注册表,将字符串 “ups“, “http://www.practicalmalwareanalysis.com”, “80” 和 “60” 保存在注册表项 “Configuration” 的值中。
- 安装过程已经分析完成了,我们再分析分析程序的主要功能部分——函数sub_402C40
- 进入函数sub_402C40函数进行分析,该函数内部依然会进行调试器检测,然后执行一个死循环,其中的循环体调用两个函数sub_4014B0和sub_402880
- 分别对这两个函数进行分析,先分析sub_4014B0,该函数会查询注册表项‘Configuration’ 的值,然后会取出其中的第二个值传递给输入的参数name;我们已经知道,安装时有四个字符串被保存在键值中,其中第二个正是一个URL:“http://www.practicalmalwareanalysis.com”,
- 再分析函数sub_402880,该函数有一个参数name=“http://www.practicalmalwareanalysis.com” ,对该函数分析,可疑发现该函数实现了一个远控的功能,根据不同的参数执行不同的操作,
- 可疑发现,进行判定的参数是来自参数v14,而该参数又作为参数被传递给函数sub_402650,那么可疑推测出该参数就是在此函数中被赋值的。
- 跟入函数sub_402650h进行分析,该函数将进行网络连接,并且将接收的数据进行返回:
- 因此,此程序的远控功能已经被证实了,通过网络连接进行数据传输,根据接收到的数据执行不同的操作,其中 “SLEEP” 直接调用函数sleep函数执行睡眠操作;“UPLOAD” 则是通过网络连接在被感染主机创建文件并向其中写入指定数据;“DOWNLOAD”将通过网络连接读取被感染主机中的指定文件,并且将数据通过网络传输给C&C;“CMD” 将通过一个网络连接执行一个shell远程命令,并且将执行结果发送回C&C。
- 到此,整个程序的分析就已经结束了,现在进行功能总结:
(1) 程序需要通过命令行继续执行,同时需要口令,否则程序会自我删除
(2) 程序在运行过程中会不断检测调试器的存在
(3) 程序的命令需要参数,根据不同的参数执行不同的操作,‘in’ 进行恶意程序服务创建或者更新配置文件,‘re’ 进行服务的删除,‘c’ 用于创建新的注册表项,‘-cc’用于打印注册表项
(4) 当程序成功被安装后,该程序就成了一个远控恶意程序,通过网络连接进行数据传输,根据接收到的数据执行不同的操作,其中 “SLEEP” 直接调用函数sleep函数执行睡眠操作;“UPLOAD” 则是通过网络连接在被感染主机创建文件并向其中写入指定数据;“DOWNLOAD”将通过网络连接读取被感染主机中的指定文件,并且将数据通过网络传输给C&C;“CMD” 将通过一个网络连接执行一个shell远程命令,并且将执行结果发送回C&C。
动态分析
- 打开PM 和PE进行监控
- 用命令行直接执行运行程序
- 查看PM注册表操作——无可疑操作
- 查看文件操作——多次打开cmd,
- 查看进程树——调用cmd,cmd 执行的命令正是 /c del 将程序本身自我删除。
问题
- 这个恶意代码使用了哪些反调试技术?
回答:会检测相关的标志(BeingDebugged, ProcessHeap, NTGlobalFlag)来判断程序是否运行在调试器中 - 当每种反调试技术执行成功时,有什么现象?
回答:如果发现程序运行在调试器中,则程序会调用cmd进行自我删除 - 如何应对这些反调试技术?
回答:在OD中手工修改相关的跳转代码,此方法比较繁琐,因为相关的检测代码有非常多处;另一种方法是借助调试器的插件来检查相应的数据结构。 - 如何在调试过程中手动修改检测的数据结构?
回答:找到相关标志的内存地址,然后修改这些标志的数据 - 哪一种OllyDbg插件可疑帮助你逃避恶意代码的反调试技术?
回答:OD的插件PhantOm, ImmDbg, PyCommand 和 hidedebug
Labs-16-02实验
样本:Lab16-02.exe
静态分析:
- 查壳——无壳
- 查看注册表——
Kernel32.dll:睡眠,创建线程,终止进程,获取进程名,写文件,加载库文件等函数
User32.dll:找到windows窗体
- 发现使用了TLS回调
- Strings 分析
发现字符串“Incorrect password. Try again”,推出该程序需要输入密码
发现字符串“OLLYDBG” ,猜测可能检测调试器
- 本来应当先进行初步的动态分析,然后再进行IDA分析;但恶意程序需要输入密码,所以先进行IDA分析
IDA分析
- IDA打开程序,发现main函数的第一个逻辑块检测运行的参数个数,如果检测失败,则输出字符串“usage: %s <4 character password>\n”,并且终止程序。
- 分析另一个分支,如果运行程序时存在参数,则会创建一个线程,线程的偏移地址是“StartAddress” ,该地址块的代码像是一个加密模块
- 先搁置这个地址块的代码继续往下分析;发现_strcmp函数的调用,根据它的跳转分支,可疑知道,在此处进行了密码的校验,
- 可疑发现密码应该是_strcmp的参数,被保存在内存Byte_48030处,跟入该内存地址进行分析,发现该内存的中存在0xFFh,该数据并不是可显示字符,同时右边对这四个字符进行了大量的交叉引用,跟进去发现正式前面我们跳过的加密函数中
- 可以看到,加密函数的内存计算还是比较复杂的,此时有两种方式继续往下进行分析:(1)可以一步一步分析加密算法计算出密码;(2)用OD进行动态调试,在strcmp函数的调用处下断点,然后查看内存数据中的密码。
- 当然,采用OD将会更加方便和快捷,此前先找到strncmp传入参数的地址——0040122E push offset byte_408030 ; char *
- 用OD打开文件,发现程序断在入口处,紧接着紧跟字符串“OLLYDBG”,并且调用函数user32.FindWindowA,可以知道该函数的目的是搜索OD窗口,进行调试器检测,如果发现调试器则终止程序。
- 在前面提到的strncmp传入参数的地址——0040122E处下断;F8单步执行,修改检测结果(此处的OD是汉化版的,所以不用修改就会通过检测,继续往下执行),然后继续执行程序(F9)——程序在0040122E处断下:
- 此时的内存中字符串是bzqr,用命令行执行程序并且分别以”bzqr”和“bzqrp@ss”作为密码进行输入——均错误
- 用OD传入参数进行调试,在strncmp处下断点,继续往下执行,发现成功地通过了检测,那为什么在命令行执行的时候会显示密码错误呢,那肯定是后面的模块的功能,在IDA中仔细分析。
- 回想一下PEID进行分析的时候发现了TLS段被占用,通常情况下,正常的程序是不是要.tls段的,那么我们有利于怀疑恶意程序使用了反调试技术。
- 用IDA来分析TLS回调函数,Ctrl+E调出程序的入口点,一个是main函数,另一个是回调函数的入口。
- main函数我们刚刚已经分析过,现在进入TLS回调函数进行分析,该部分的代码首先也会进行OLLYDBG窗口(此处的字符串 “OLLYDBG“ 指的是窗口的类名,并不是窗口名)的查找,如果找到则直接退出;反之则调用函数sub_401020进行下一步的操作。
- 跟入该函数,发现该函数调用了SetLastError函数进行错误码设置,调用OutputDebugStringA函数与调试器交互输出字符串,再调用函数GetLatError获取新的错误码;此处利用前面OutputDebugStringA函数与调试器交互,如果失败,则会生成新的错误码如果与调试器交互成功,则错误码不会改变
- 如果检测到调试器,则对内存byte_40A968中的数据进行自增操作,方便后续分析,对该内存进行重命名为“TLS_changed”
- 对该内存地址进行交叉引用分析,发现另外两处对该地址的访问,其中一处正是_strncmp函数进行访问,另一处为前面分析的创建的线程入口地址StartAddress偏移处
- 跟入该地址,就是前面我们分析过StartAddress这个代码块,知道它是一个加密函数,但是它将TLS_changed内存的数据添加到了加密计算中,而该数据又与TLS回调函数和检测调试器有关;这也就解释了为什么我们从OLLYDBG中下断得到的密码依然是错误的,因为在TLS回调函数中还对调试器进行了一次检测(但是我们并没有发现),TLS中的检测直接影响了参与加密函数的计算,所以得到的密码是错误的;那么需要怎么处理这个情况呢?
(1) 在TLS回调函数中调试器的检测处进行手动修改,我们可以直接修检测的返回值或者屏蔽进行检测的代码
(2) 当TLS回调函数中发现调试器后,会对内存byte_40A968中的数据进行自增操作,我们可以将自增操作用nop进行替换,然后重新保存修改后的二进制文件 - 此处我们采用第二种方式——用nop指令替换自增操作,然后另存为二进制文件
- 用OD打开新保存的二进制文件,在_trncmp函数下断(可以从IDA中找到地址):
- 执行程序,程序暂停在断点处,此时的栈中数据为“12345”和“byqrp@ss”,其中“12345”为我们输入的参数,那么“byqrp@ss”就是正确的解密后的密码,由于密码的位数是4位,故正确的密码应该是“byqr”
- 进行尝试,发现依旧提示密码错误
- 有点奇怪,我们再回到加密函数代码块进行分析,发现参与运算的数据除了TLS_changed数据外,还包括一个fs:30h的数据,在Lab16-01中我们已经分析过,该内存数据为PEB的基地址,改地址偏移为2的地址正是用于调试器检测的BeingDebuged标志,原来在这里还有一此调试器检测——真相大白了( •̀ ω •́ )✧
- 用OD的插件进行来屏蔽上面这个PEB结构中的调试器检测,打开PhantOm 选中“hide from PEB”
- 重新运行程序(输入参数并且在_strncmp的调用前下段),暂停后栈中出现了新的密码
- 用命令行再次进行尝试——正确
动态分析
- 命令行执行程序——失败,需要密码
问题
- 在命令行中运行Lab16-02.exe时,会发生什么?
回答:程序提示需要输入四位的密码
- 当使用猜测的命令参数运行Lab16-02.exe时,会发生什么?
回答:提示输入的密码错误 - 命令行的密码是什么?
回答:正确的密码是byrr - 使用IDA Pro加载Lab16-02.exe。在main函数的何处可疑找到strncmp函数?
回答:在地址0040123A处发现strncmp函数 - 在默认的设置下,将这个恶意代码加载到OllyDbg中会发生什么?
回答:程序立即终止 - Lab16-02.exe中的PE结构的独特之处是什么?
回答:在用PEID进查壳的时候发现了.tls段的占用,通常情况下,正常的程序是不是要.tls段的,那么我们有利于怀疑恶意程序使用了反调试技术 - 回调(callback)发生在哪些位置?(提示:在IDA Pro中使用Ctrl+E组合键)
回答:回调函数从地址00401060开始 - 恶意代码使用哪一种反调试技术使它在调试器中立即终止运行?如何避免这种检查?
回答:FindWindowA函数用于检测OD窗口(类名为OLLYDBG的窗口)。 - 当你禁用反调试技术后,你在调试器中看到的命令行密码是什么?
回答:禁用FindWindowA后,在strncmp函数的调用出下断,此时的OD栈中显示的密码是byqr - 调试器中找到的密码在命令行中运行有效吗?
回答:经过尝试后,发现byqr是错误的密码 - 那种反调试技术为调试器和命令行设置不同的密码?如何防御它们?
回答:经过分析后,发现函数OutputDebugString和PEB结构中的BeingDebugged标志被用于调试器检测;对于OutputDebugString的检测处理,可以将函数的调用用nop覆盖或者修改检测处调试器后的代码;对于BeingDebugged标志的调用,哦那个OD的插件PhantOm进行防御。
Labs-16-03实验
样本:Lab16-03.exe
静态分析:
- 查壳——无壳
- 查看输入表:
KERNEL32.DLL:创建、终止进程,获取程序路径,睡眠,加载库文件,读写文件等函数
SHELL32.DLL:执行shell命令
WS2_32.DLL:网络连接,网络域名和IP地址解析,网络编程初始化。
- Strings分析
发现字符串“cmd”,“/c del” ;猜测可能调用cmd执行文件删除命令
- 先进行简单的动态分析,再进行IDA分析
IDA分析
- IDA打开程序进行分析,发现字符串初始化
- 继续往下,发现一个函数sub_4011E0调用,其中的参数正是第二个字符串:
- 跟入函数sub_4011E0,发现该函数主要进行数学运算,猜测该函数是一个加密函数,对输入的字符串进行加密;同时调用两个QueryPerformanceCounter函数进行差值计算,从而影响加密的流程。
- 同时还发现一个异常处理,由于调试器中的异常处理比系统的异常处理时间更长,所以通过次方似乎来判断程序是否运行在调试器中。
- 回到main函数继续往下,发现会进行当前程序名的获取,然后进行检测;但是检测的字符串已经被加密了,我们需要动态调试中获取这个字符串。
- 用OD打开程序, 在strncmp函数调用处下断,程序执行到此处后查看堆栈,字符串为“peo.exe”,说名程序需要更名为“peo.exe”后才能继续往下执行。
- 将程序改名后重新执行,进行动态分析,并未发现可疑的注册表和文件操作
- 继续从main函数往下分析,发现如果匹配成功,则会进行网络连接初始化,
- 然后在两个系统时间函数中间调用了函数sub_401000,
- 进入该函数进行分析,发现该函数同样采用了上面的异常处理来判断是否存在调试器。
- 回到main函数继续往下,发现调用函数sub_401300,然后将其中的一个返回值传入gethostbyname函数:
- 跟入函数sub_401300,发现该函数采用了相同的除零异常方式来判断是否存在调试器,如果存在则调用cmd进行自我删除;如果没发现调试器,则将第一个初始化的字符串“lqbz2wsx3edc” 和内存0040604C处的数据作为参数进行计算得到gethostbyname函数的参数name
- 此处的name参数(域名)我们从OD中获取,在gethostbyname函数下断,然后得到域名为adg.malwareanalysisbook.com(先需要将上述的所有异常处理均用nop进行替换)
(1) 第一处地址00401271 QueryPerformanceCounter函数调用处,如果检测到调试器的存在,它的下方会将变量var_188赋值为2 ,我们将其中的mov指令用nop替换
(2) 第二处在地址00401595上方的除零异常函数sub_401000函数的调用,我们将此处的call指令用nop替换
(3) 00401360处调用rdtsc指令获取系统时钟,如果发现调试器则在下面的00401380调用函数sub_4010E0进行自我删除,我们将此处的call语句用nop替换,那么跳转到此处后的代码继续往下就将正常往下执行了
(4) 然后将OD中修改后的代码保存为可执行文件。
(5) 用OD打开新保存的可执行文件,并且在gethostbyname函数调用处下断,继续执行后得到恶意域名 “adg.malwareanalysisbook.com”
- 继续往下,成功建立连接后实现远控功——执行远程命令:
- 其中sub_401060函数会从C&C接受的数据创建新的进程调用cmd执行远程命令。
问题
- 当使用静态分析法分析这个二进制文件时,你看到了那些字符串?
回答:发现字符串“cmd”,“/c del” ;猜测可能调用cmd执行文件删除命令 - 当运行这个二进制文件时会发生什么?
回答:自动终止 - 如何重命名它,才能使这个二进制文件正常运行?
回答:重命名为peo.exe - 这个恶意代码使用了哪些反调试技术?
回答:异常处理时间(反调试时钟检测技术)差来检测调试器的存在:rdtsc, GetTickCount 和QueryPerformanceCounter - 对每一种反调试技术而言,如果恶意代码确定它运行在调试器中,它将做什么?
回答:
rdtsc——检测到调试器存在则进行自我删除
GetTickCount ——检测到调试器存在则产生一个异常导致程序崩溃
QueryPerformanceCounter——检测到调试器则修改需要重命名的字符串 - 为什么反调试技术在这个恶意代码中能够成功?
回答:因为恶意代码修改了SHE机制,在两个时钟函数间调用了自己的异常处理例程,这样就能捕获它的异常,而异常处理在调试器中会比在系统中慢得多。 - 恶意代码使用了什么域名?
回答:“adg.malwareanalysisbook.com”