恶意样本分析精要及实践9-IDA使用(二)

VSole2021-10-21 15:23:17

STATEMENT

声明

由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,雷神众测及文章作者不为此承担任何责任。

雷神众测拥有对此文章的修改和解释权。如欲转载或传播此文章,必须保证此文章的完整性,包括版权声明等全部内容。未经雷神众测允许,不得任意修改或者增减此文章内容,不得以任何方式将其用于商业目的。

分子实验室 https://molecule-labs.com/

前言

相关说明及声明:

文章原文为K A, Monnappa. 2018年发表的《Learning Malware Analysis》,本文的相关内容均为相关内容翻译及实践记录,仅为学术交流使用,如要引用请做原文引用如下所示:

[序号]K A, Monnappa. Learning Malware Analysis[M]. 2018.06. Published by Packt Publishing Ltd. Livery Place 35 Livery Street Birmingham B3 2PB, UK.

使用IDA反汇编

3. 反编译windows API

恶意软件通常使用windows API函数影响操作系统(例如文件系统、进程、内存以及网络配置等)。如第二章静态分析和动态分析部分,windows扩展主要依赖文件DLL动态连接库文件。可执行程序的引用和调用来自于大量DLL中的提供不同功能的API。为了调用这些dll文件,需要先将其加载到内存中,然后调用API函数。检查一个恶意样本的dll引用情况可以指导我们分析其功能和能力。下面的表格展示了部分常见的DLL以及其执行功能:

3.1 弄清楚Windows API

为了展示病毒程序如何使用windows API并且帮助你了解关于一个API更多的信息。以一个病毒样本为例。加载样本到IDA,在引用窗口展示出的相关windows API函数里,检查函数在windows引用情况。

无论什么时候,在遇到windows API 函数的时候,可以通过微软的开发者MSDN中搜索或者在谷歌中搜索,https://msdn.microsoft.com/。MSDN文档对于API函数进行了相关描述,如函数参数、参数类型、返回值等。这里取Creat or open file 作为举例。

如 https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx 所示。

通过文档可以知道这个函数的功能为创建和打开文件。第一个参数(lpfilename),用于记录文件名称。第二个参数(dwdesiredaccess),说明需要的权限如读或血的权限,第5个参数也是对文件创建和打开一个已经存在的文件。

HANDLE CreateFileA(  LPCSTR                lpFileName,  DWORD                 dwDesiredAccess,  DWORD                 dwShareMode,  LPSECURITY_ATTRIBUTES lpSecurityAttributes,  DWORD                 dwCreationDisposition,  DWORD                 dwFlagsAndAttributes,  HANDLE                hTemplateFile);

Windows API使用匈牙利语命名变量。在这个语法中,变量前缀增加数据种类,这个有助于我们了解给数据种类。如第二个参数dwdesiredaccess,dw的前缀代表dword 32 位无符号整数。在win32 API支持的不同数据类型如(https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx)。下面的表格未一些数据类型:

与数据类型和参数不同,之前的函数样本包括注释,例如_in__out_,描述了函数使用的参数和返回的值。_in_表示输入参数,调用必须通过提供参数给函数才能执行函数。_in_opt表示可选的输入参数(可以为null)。_out_表示输出的参数;表示函数将会输出参数作为返回值。这个特性对于了解函数调用后是否从存储中读取任何数据到输出函数很有帮助。_inout_对象可以让我们分辨函数参数和函数的输出。

在交叉参考中我们可以看到API调用情况,通过查阅相关API手册,我们可以知道,相关API的输入和输出参数。以createfile为例,通过查看函数的相关的两个函数,起始地址如下:

双击第一个参数,调转到代码反汇编窗口对应位置。并且高亮显示。通过分散,IDA提供了一个叫做快速识别库的技术(FLIRT),包括图像匹配算法用于确定函数函数是库函数还是一个引用函数(从dll引入的函数)。在这个例子中IDA能够识别引入的分散的函数,并且将其命名为CreateFileA。IDA的分辨引用函数和库函数的能力非常有用,因为当你分析恶意样本的时候,不会去浪费时间分辨是引用的函数还是库函数。IDA还会为参数添加参数的名字作为注释,标记出Windows API函数调用的对应的参数的名称。

.text:00401708                 mov     dword ptr [esp+18h], 0 ; hTemplateFile.text:00401710                 mov     dword ptr [esp+14h], 80h ; dwFlagsAndAttributes.text:00401718                 mov     dword ptr [esp+10h], 3 ; dwCreationDisposition.text:00401720                 mov     dword ptr [esp+0Ch], 0 ; lpSecurityAttributes.text:00401728                 mov     dword ptr [esp+8], 3 ; dwShareMode.text:00401730                 mov     dword ptr [esp+4], 80000000h ; dwDesiredAccess.text:00401738                 mov     dword ptr [esp], offset FileName ; lpFileName.text:0040173F                 call    ds:CreateFileA

第一个参数表示需要创建的文件名lpFileName。第二个参数dwDesiredAccess内容80000000h,通过https://docs.microsoft.com/en-us/windows/win32/secauthz/access-mask-format,可以看到对应的是generic_read权限,这一部分应该在后面的针对widnows的API的详细解读中进一步细化。第5个参数值为3,通过https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea,可以知道代表OPEN_EXISTING,只有当其退出的时候打开文件或设备。

IDA的另一个特性是列出使用象征名标记Windows API,或C标准库函数。例如在80000000h可以通过右键值,选择使用标准象征内容参数,标记内容;这个操作将会出现一个窗口展示所有有关选择的值的象征名字。你需要选择一个适当的标志名称这里就是Generic_read。用相同的方式,你可以替换掉第五个参数内容3,为象征名称,OPEN_EXISTING;

在使用象征名替换了内容之后,反汇编窗口列被转化成下图所示内容。代码变得更加可读。在函数调用之后,句柄到文件(可以在EAX寄存器中找到)被返回。通过函数操作文件还可以通过其他API来实现,例如readfile()或者writefile(),也可以实现类似的效果:

3.1.1 ANSI和Unicode API函数

windows支持两个相似的API设置:一个是对于ANSI字符,另一个是Unicode字符。很多函数使用一个字符作为参数,在参数的名字后面包含A或者W。例如CreateFileA。换句话说,API名称的尾部,可以让你分辨通过函数的字符的种类(ANSI或Unicode)。以上面的CreateFileA为例,A表示函数使用一个ANSI字符作为输入。相应的CreateFileW则是表示函数使用一个Unicode字符作为输入。在恶意软件分析的过程中,当你看到一个函数名为CreateFileA或CreateFileW形式,可以删掉尾字母A或W,然后在MSDN中搜索函数文档。

3.1.2 执行API函数

你可能会遇到很多名字带有Ex后缀的函数,例如RegCreateKeyEx(扩展RegCreateKey的变体)。当Microsoft升级一个与旧函数矛盾的函数的时候,升级的函数命名在原函数名的基础上增加Ex。

3.2 32位和64位Windows API对比

让我们看一个32位恶意样本去了解恶意样本如何运用大量API函数去影响操作系统的,让我们尝试了解如何反汇编代码,去了解恶意程序的活动。在接下来的反汇编输出中,32位的恶意样本调用了RegOpenKeyEx API开启了一个句柄执行run注册表的值。当我们执行32位恶意样本的时候,所有regOpenKeyEx的API参数被压到栈上。

相关的文档可以在 https://msdn.microsoft.com/en-us/library/windows/desktop/ms724897(v=vs.85).aspx 找到。

输出参数phkResult是一个变量的指针(输出的参数由**out**注释指出)在函数调用后,指向打开注册表值的句柄。这里可以注意到,phkResult的地址是从ecx寄存器复制过去的,这个地址是作为RegOpenKeyEx API的第5个参数录入的。

lea  ecx, [esp+7E8h+phkResult] ➊push ecx ➋                        ; phkResultpush 20006h                       ; samDesiredpush 0                            ; ulOptionspush offset aSoftwareMicros ;Software\Microsoft\Windows\CurrentVersion\Runpush HKEY_CURRENT_USER            ; hKeycall ds:RegOpenKeyExW

在恶意软件通过调用RegOpenKeyEx打开run注册值后,返回的句柄(在phkResult变量存储)被移动到ecx寄存器中,并且作为RegSetValueExW的第一个参数传递。从MSDN关于这个API的文档中,可以发现使用RegSetValueEx API设置一个变量到run注册表的值中(持久化)。变量通过的第二个参数设置,system字符。对应的内容可以通过第五个参数的值去确认。从前面的描述中,可以确定eax保持由pszPath的地址的值。pszPath变量与在运行时的相关内容相关;因此通过查看代码,很难判断数据是病毒添加到注册表里的(你可以通过调试病毒样本确认)。但是在这点,通过静态分析(反汇编),你可以确定病毒添加了一个入口到注册表中作为持久化的方式:

mov   ecx, [esp+7E8h+phkResult] ➌sub   eax, edxsar   eax, 1lea   edx, ds:4[eax*4]push  edx                     ; cbDatalea   eax, [esp+7ECh+pszPath] ➐push  eax ➏                  ; lpDatapush  REG_SZ                 ; dwTypepush  0                      ; Reservedpush  offset ValueName       ; "System" ➎push  ecx ➍ ; hKeycall  ds:RegSetValueExW

在添加了一个入口到注册表中之后,病毒通过在句柄获取值之前(存有phkResult变量)关闭句柄到注册表值,如下所示:

mov   edx, [esp+7E8h+phkResult]push  edx                     ; hKeycall  esi                     ; RegCloseKey

之前的例子展示了恶意样本如何使用多个windows API添加一个入口到注册表中,该注册遍能够在计算机重启的时候自动运行。你还可以看到,恶意样本如何获得一个对象的句柄,并分享句柄到其他API函数执行其他行为。

当你在看从64位病毒程序反汇编输出的函数的时候,可能会略显不同,这是由于参数通过64位架构。接下的一个64位样本调用CreateFile函数。在64位架构下,在寄存器中前4个参数被使用(rcx,rdx,r8和r9),并且剩余的参数被放置在寄存器中。在接下来的反汇编中,注意到第一个参数是如何通过rcx寄存器,第二个参数在edx寄存器中,第三个参数在r8,第四个在r9寄存器中。新增的参数被放置在栈中(注意这里没有push指令),这里使用mov指令。注意IDA如何识别参数柄添加注释到指令旁边的。函数的返回值(到文件的句柄)从rax寄存器中被移动到rsi寄存器中:

xor  r9d, r9d  ➍                           ; lpSecurityAttributeslea  rcx, [rsp+3B8h+FileName] ➊             ; lpFileNamelea  r8d, [r9+1] ➌                          ; dwShareModemov  edx, 40000000h ➋                       ; dwDesiredAccessmov  [rsp+3B8h+dwFlagsAndAttributes], 80h ➏  ; dwFlagsAndAttributesmov  [rsp+3B8h+dwCreationDisposition], 2  ➎  ; lpOverlappedcall cs:CreateFileWmov  rsi, rax  ➐

下面的反汇编为WriteFile API的,注意文件句柄在API调用之前被复制到rsi寄存器,现在通过writeFile函数第一个参数移动到rex寄存器。相同的方式,另一个参数被传入寄存器进入堆,如下所示:

and  qword ptr [rsp+3B8h+dwCreationDisposition], 0lea  r9,[rsp+3B8h+NumberOfBytesWritten]       ; lpNumberOfBytesWrittenlea  rdx, [rsp+3B8h+Buffer]                   ; lpBuffermov  r8d, 146h                                ; nNumberOfBytesToWritemov  rcx, rsi ➑                               ; hFilecall cs:WriteFile From the preceding example,

从之前的案例可以看到,病毒程序创建一个文件和写入内容到文件,但是当你查找静态代码的时候,并不那么清楚的可以看出恶意软件创建了什么文件或者写入了什么内容到文件中。例如,想要知道软件创建的文件名,你需要检查ipFileName(传入CreateFile的一个参数)地址的内容;但ipFileName变量并非硬编码,并且只有当程序运行的时候才存在。

4. 使用IDA补丁二进制程序

当完成恶意程序分析,你想要修改二进制程序改变其内部工作原理或者逆向逻辑以便个人使用。你可以使用选择Edit/Patch program菜单。需要注意的是,当你使用这个菜单堆二进制进行修改的时候,你并不会直接对二进制文件本身进行修改;这个修改只会在IDA数据库中进行操作。如果需要应用修改到原始的二进制文件的话,你需要使用Apply patches to input file:

4.1 补丁程序字节

考虑到代码通过32位恶意软件dll执行(RDSS rootkit),通过检测可以确保其运行与spoolsv.exe下面。这里的检测会使用字符对比功能;如果自负对比失败,则代码跳转到函数结束,并且回到函数调用。特殊的,这个dll的恶意行为只发生在当其被spoolsv.exe调用的时候;除此之外,其都无返回。

10001BF2     push offset aSpoolsv_exe  ; "spoolsv.exe"10001BF7     push edi                  ; char *10001BF8     call _stricmp  ➊ 10001BFD     test eax, eax10001BFF     pop ecx10001C00     pop ecx10001C01     jnz loc_10001CF9 [REMOVED] 10001CF9 loc_10001CF9: ➋      ; CODE XREF: DllEntryPoint+10j10001CF9      xor  eax, eax10001CFB      pop  edi10001CFC      pop  esi10001CFD      pop  ebx10001CFE      leave10001CFF      retn 0Ch
K A, Monnappa. Learning Malware Analysis: Explore the concepts, tools, and techniques to analyze and investigate Windows malware (p. 189). Packt Publishing. Kindle 版本.

假定你想要恶意dll执行恶意行为在任一程序下,例如执行在notepad.exe下面。你可以改变硬编码的字符从spoolsv.exe到notepad.exe。为了实现这个,通过点击aSpoolsv_exe定位硬编码地址,在下面的内容中展示:

现在,将鼠标放在变量名上(aSpoolsv_exe)。此时,hex视图窗口中将会同步展示地址信息。在hex-View-1标签展示的hex和ascii导出内存地址。补丁字节内容,选择Edit/patch program/change byte;将会如下图所示带来补丁字节日志。你可以修改原始的二进制字节通过输入一个新的二进制值到栏目中。Address字段表示游标位置的虚拟地址,File offset字段指定二进制文件中字节所在的文件偏移量。

Original value字段显示当前地址的原始字节;即使你修改了这些值,该字段中的值也不会改变:

您所做的修改将应用于IDA数据库;要将更改应用到原始可执行文件,可以选择“Edit | Patch program | apply patches to the input file”。下面的屏幕截图显示了“应用补丁到输入文件”对话框。当您点击OK时,更改将应用到原始文件;您可以通过检查“创建备份”选项来保存原始文件的备份;在这种情况下,它会以.bak扩展名保存你的原始文件:

前面的示例演示了修补字节;以同样的方式,您可以通过选择Edit | patch program | Change word来一次打一个单词(2字节)的补丁。您还可以从十六进制视图窗口中修改字节,通过右键单击一个字节并选择Edit (F2),您可以通过再次右键单击并选择apply changes (F2)应用更改。

4.2 补丁命令

在之前的例子中,TDSS rootkit DLL执行了一个检查判断程序是否在spoolsv.exe下面运行。可以通过修改程序中的二进制信息将spoolsv.exe改为notepad.exe。可以通过逆向逻辑判断DLL可以运行在任意进程下面。为了实现这个想法,我们可以修改jnz命令使其变为jz,通过选择Edit|patch program|Assemble,如下所示。我们将要逆向逻辑并且让程序运行在spoolsv.exe下时,程序不会表现任何恶意行为表现,而运行在非spoolsv.exe时将会表现出恶意行为。在修改了命令之后,点击OK,命令将会被汇编,但是对话仍然保持打开状态,提示你在下一个地址汇编下一个命令。如果没有其他需要会变的可以点击取消结束。为了将修改保存到原始文件中,选择Edit|patch program|apply patches 将修改保存到文件中。

当你给任何命令打补丁的时候,小心需要确保所有的的命令的结合是正确的;除此之外,补丁的程序可能会出现无法预料的行为。如果新的命令比原始命令短的话,你可以使用nop命令保持长度完整。如果你在汇编一个新的命令超出原始的命令,IDA将会覆盖原始程序的后面的命令,这个行为可能并非我们希望如此的。

函数调用数据寄存器
本作品采用《CC 协议》,转载必须注明作者和本文链接
不可中断状态实际上是系统对进程和硬件设备的一种保护机制。当负载存在明显升高趋势时,及时进行分析和调查。系统调用过程中并不会涉及虚拟内存等进程用户态资源,也不会切换进程。因此系统调用通常称为特权模式切换。进程是由内核管理和调度的,进程上下文切换只能发生在内核态。因此相比系统调用来说,在保存当前进程的内核状态和CPU寄存器之前,需要先把该进程的虚拟内存,栈保存下来。
ARM PWN基础教程
2022-07-27 17:29:43
在CTF比赛中,我们所能接触到的大部分都是x86 x86_64架构的题目,而在我开始接触IOT方向的研究以后发现智能设备所用到的则是ARM和MIPS架构为主。本篇文章在介绍前置知识的基础上通过CTF的ARM架构类型题带读者更好的入门ARM PWN的世界。
这似乎又是一个0 day漏洞,这个漏洞与pif文件有关,是我在研究pif文件的时候发现的。
API(Application Programming Interface),我们调用时只需提供正确的参数以及接收返回值就可以判断API执行是否成功或者通过GetLastError获得错误原因.
静态分析法是在不执行代码文件的情形下,对代码进行静态分析的一种方法。静态分析时并不执行代码,而是观察代码文件的外部特征,获取文件的类型(EXE、DLI、DOC、ZIP等)、大小、PE头信息、Import/ExportAPI内部字符串、是否运行时解压缩、注册信息、调试信息、数字证书等多种信息。
本靶机难度为高难度,涉及到了缓冲区溢出的源码审计 ,逆向分析,动态调试等漏洞技能点,攻击方法有2种:??SQL 注入得到的密码可以保留。
这篇文章的内容是我在研究自制操作系统时遇到的一个问题,即如何从16位实模式切换到32位保护模式,网上的资料比较少,讲得也不是很详细,在这跟大家分享一下我的解决方案。
用来恢复线程,如果函数成功, 则传回线程的前一个挂起次数。如果失败, 则传回0xFFFFFFFF。
汇编语言是一种用于电子计算机、微处理器、微控制器或其他可编程器件的低级语言,亦称为符号语言。Smali汇编基础Smali语言最早是由JesusFreke发布在Google Code上的一个开源项目,并不是拥有官方标准的语言。因此也将Smali语言称作Android虚拟机的反汇编语言。基本类型Smali基本数据类型中包含两种类型,原始类型和引用类型。而在Smali中则是以LpackageName/objectName的形式表示对象类型。
VSole
网络安全专家