首页
社区
课程
招聘
[原创]默默无闻·恶意代码分析第七章
2021-4-7 20:34 7065

[原创]默默无闻·恶意代码分析第七章

2021-4-7 20:34
7065

系列往期:

[原创]默默无闻·恶意代码分析Lab1

[原创]默默无闻·恶意代码分析Lab5

[原创]默默无闻·恶意代码分析Lab6


工具说明

参照书籍:《恶意代码分析实战》;

系统环境:Windows7 x86

使用工具:WinHex、CFF、StudyPE+、Exeinfo PE、Resource Hacker、Depends Walker、OD、IDA、MSDN;

摘要

这一章节还是比较重要的,总结了在逆向Windows恶意代码中可能遇到的形式;

 

所以此贴以知识点总结为主;


知识点总结

1、Windows API常见类型

类型和前缀 描述
WORD(w) 一个16位的无符号数值
DWORD(dw) 一个双字节、32位的无符号数值
Handles(H) 一个对象索引,只能被Windows API操作
Long Pointer(L) 指向另一类型的指针,如LPCSTR是一个指向字符串的指针
Callback 一个将会被Windows API调用的回调函数;
 

2、句柄

多说无益,首先要了解的是:

​ 1、每个进程内核有句柄表;

​ 2、系统有一个全局句柄表;

​ 3、而句柄就是指向这些表的指针,所以句柄是有两种情况的;

 

参考书籍《Windows 核心编程》

 

3、文件系统

 

根据《恶意代码分析实战》中列出的函数,更多的在之前和以后的帖子中,或者查询MSDN(最有效,,最详细)

函数 描述
CreateFile 用于创建和打开文件;可以打开已经存在的文件,管道,流,以及I/O设备,还能创建新的文件;
ReadFile和WriteFile 用来对文件的读和写,都将文件作为流来操作;
CreateFileMapping和MapViewOfFile 允许一个文件加载到内存中,以便更容易的进行操作;<br />CreteFileMapping函数负责从磁盘上加载一个文件到内存中;<br />MapViewOfFile函数则返回一个指向映射的基地址指针;
 

这些函数都是常被恶意代码用到的函数,比如可以模拟系统加载PE,写成一个加载器;

 

4、特殊文件

Windows系统中的特殊文件类型,这些文件在目录中不会显示出来,某些特殊文件可以提供对系统硬件和内部数据更强的访问能力;

书中介绍了三种类型,分别是共享文件通过名字空间访问的文件备用数据流

 

4.1、共享文件

 

共享文件以\\serverName\share\\?\serverName\share开头命名的特殊文件;

  • 它们用于访问保存在共享目录中的目录或文件;
  • \\?\前缀告诉操作系统禁用所有的字符串解析,并允许访问文件名;

4.2、通过名字空间访问的文件

 

名字空间可以被认为是固定数目的文件夹,每一个文件夹中保存不同类型的对象;

 

底层的名字空间是NT名字空间,以前缀\开始。

 

NT名字空间可以访问所有设备,以及所有在NT名字空间中存在的其它名字空间;

 

使用WinObj对象管理器名字空间查看器查看名字空间;

  • \\.\开始的Win32设备名字空间,经常被Malware用来直接访问物理设备;
    • 例如,使用\\.\PhysicalDisk1来直接访问PhysicalDisk1,而忽略它的文件系统,直接读写数据到一个未分配的扇区,以避开病毒和安全程序检查;
    • 也可以使用命名空间\Device\PhysicalMemory直接访问物理内存,允许用户空间程序写到内核空间;

从Windows 2003 SP1开始,Device\PhysicalMemory从用户空间已经无法访问。但是可以从内核空间访问由此可见,反病毒要把内核学好才行。

 

4.3、备用数据流

 

备用数据流(ADS)特性允许附加数据被添加到一个已存在 的MTFS文件;

 

就是添加一个文件到另外一个文件中,额外数据在列一个目录时不会被显示出来,只有在访问流时,它才可见;

  • ADS根据约定normalFile.txt::Stream:$DATA来命名,它允许要给程序去读写一个流;

Malware作者喜欢ADS,因为它能被用来隐藏数据;

 

5、Windows 注册表

 

注册表用来保存操作系统与程序的配置信息,例如设置和选项;

 

恶意代码经常使用注册表来完成持久驻留或者存储配置数据

 

注册表术语:

名称 描述
根键 注册表被划分为称为根键的5个顶层节。<br />每一个根键有一个特定的目的。
子键 就像是一个文件夹中的子文件夹
一个键是一个注册表中的文件夹,它可以包含额外的文件夹或键值。<br />根键和子键都是键;
值项 一个值项是一个配对的名字和值;
值或数据 值或数据是存储在注册表项中的数据;
 

5.1、注册表根键

注册表根键 描述
HKEY_LOCAL_MACHINE(HKLM) 保存对本地机器全局设置;
HKEY_CURRENT_USER(HKCU) 保存当前用户特定的设置;
HKEY_CLASSES_ROOT 保存定义的类型信息;
HKEY_CURRENT_CONTIG 保存关于当前硬件配置的设置,特别是与当前和标准配置直接不同的部分;
HKEY_USERS 定义默认用户、新用户和当前用户的配置;
 

两个最常用的根键是HKLMHKCU(这些键通常通过它们的缩写来引用)。

 

一些键实际是虚拟键值,提供一种引用底层注册表信息的方式:

 

​ 例如,HKEY_CURRENT_USER键实际上存储在HKEY_USERS\SID中,这里的SID是当前登陆用户的安全描述符;

 

​ 例如,一个常用的子健,HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run,包含一系列值,这些值列举了当一个用户登陆时被自动启动的可执行程序。
根键是HKEY_LOCAL_MACHINE,它保存了SOFTWAREMicrosoftWindowsCurrentVersion以及Run子键;

 

5.2、Regedit

  • 注册表编辑器(Regedit);

快捷键win+r,然后在运行窗口输入regedit,打开注册表编辑器;

 

5.2.1、自启动程序查找

  • 使用regedit.exe打开;

image-20210407152317840

 

根据选框中的路径查找(这是用windows10本机查找的);

 

5.2.2、常用注册表函数

函数名 描述
RegOpenKeyEx 打开一个注册表进行编辑和查询;<br />有些函数允许直接查询或编辑,但是大部分还是要用到这个函数;
RegSetValueEx 添加一个新值到注册表,并设置数值;
RegGetValue 返回注册表中的一个值项的数值;
 

如果在实战中遇到Malware访问一些键值时,可以通过搜索引擎寻找相关信息;

 

5.2.4、使用.reg文件的注册表脚本

 

.reg作为扩展的文件包含一个人类可读的注册表数据;

 

运行.reg文件,它会自动通过合并文件包含的信息到注册表中,来修改注册表;(几乎像一个脚本)

 

实例:

1
2
3
4
5
Windows Registry Editor Version 5.00
 
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run]
 
"MaliciousValue"="\"C:\\Windows\\evil.exe\""

image-20210407153808634

 

image-20210407162935721

 

这是Microsoft官网的教程:如何使用 .reg 文件添加、修改或删除注册表子项和值

 

6、网络API

 

这是Malware经常用到的东西了;

 

6.1、伯克利兼容套接字

 

最常使用的套接字,因为其功能在Windows和UNIX系统上是几乎一样的;

 

Windows系统中是由Winsock库实现的,主要在ws2_32.dll中,下表给出了对一些常用函数的描述;

函数 描述
socket 创建一个套接字;
bind 将一个套接字绑定到特定端口,应该在accept之前调用;
listen 预示着一个套接字将进入监听,等待入站连接;
accept 向一个远程套接字打开一个连接,并接受连接;
connect 向一个远程套接字打开要给连接,远程套接字必须在等待连接;
recv 从远程套接字接受数据;
send 发送数据到远程套接字;
 

WSAStartup函数必须要在其它网络函数之前被调用,以便为这些网络库分配资源;
当调试代码查找网络连接入口时,在WSAStartup函数中设置一个断点,是非常有效的方式;

 

6.2、网络的服务器和客户端

 

一个网络程序通常有两个端点:

 

​ 服务端:它维护一个打开套接字并等待入站连接;
​ 客户端:它连接到一个正在等待的套接字;

 

恶意代码可以是任意一个!!!

 

6.3、WinINet API

 

除了Winsock API以外,还有一个叫WinInetAPI的更高级的Windows API(这里的高级是指ISO/OSI网络体系结构和TCP/IP协议模型中的相对位置);

 

WinInet API实现了应用层协议,如HTTP和FTP,通过判断打开的是何种连接,来理解它的功能;

函数 描述
InternetOpen 用来初始化一个到互联网的连接;
InternetOpenUrl 用来访问一个url(它可以是一个HTTP页面或是一个FTP资源);
InternetReadFile 和ReadFile函数工作原理相似,允许程序从一个互联网下载的文件中读取数据;
 

7、跟踪恶意代码的运行

 

7.1、DLL

 

DLL本身是不能运行的,但是它可以导出函数,给其它应用程序调用;

 

DLL的基本结构:

 

​ 1、dll和exe文件都使用PE文件格式,有一个专门字段(File_Header.Characteristics)描述具体是哪个文件;
​ 2、通常DLL导出函数,导出函数多,导入函数少;
​ 3、DLL的主函数是DllMain,它并不是导出函数,只是在PE中被描述为入口点。
​ 4、任何时候一个进程加载或卸载库,会创建一个新进程,或是一个已存在的线程结束时,DllMain函数会被调用来通知DLL,这个通知允许DLL来管理每个进程或线程的资源;
​ 5、多数DLL没有线程粒度的资源,并且它们忽略由线程活动引起DllMain的调用;
​ 5.1、如果DLL必须在线程粒度进行管理的资源,那么这些资源可以为分析师提供一些提示,来了解这个DLL目的;

 

恶意代码是如何使用DLL的呢?

  • 保存恶意代码

将Malware保存到一个DLL文件,然后附加到其它进程;

  • 通过使用Windows DLL

任何程序都能使用系统上的Windows基础DLL程序,通过查看Malware的导入表中的Windows API,可以猜测实现了什么功能;

  • 通过使用第三方DLL

除了系统的基础DLL,还可以使用第三方的DLL;
例如:

 

​ 使用Mozilla Firefox DLL来连接服务器;
​ 自定义的DLL和Malware(exe文件)一同发布;

 

7.2、进程

 

恶意代码可以通过创建一个新进程,或修改一个已存在的进程,来执行当前程序之外的代码;

 

传统上,恶意代码包括它自己的独立进程(独立恶意行为程序);
现在更普遍的是将自身代码作为其它进程的一部分执行(导入表注入之类的操作);
这就好比,前者是一匹狼,后者是个披着羊皮的狼;

 

创建进程函数CreateProcess,MSDN中描述:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
函数的作用是:创建一个新进程及其主线程。新进程执行指定的可执行文件。
 
BOOL CreateProcess(
  LPCTSTR lpApplicationName,
                         // pointer to name of executable module
  LPTSTR lpCommandLine,  // pointer to command line string
  LPSECURITY_ATTRIBUTES lpProcessAttributes,  // process security attributes
  LPSECURITY_ATTRIBUTES lpThreadAttributes,   // thread security attributes
  BOOL bInheritHandles,  // handle inheritance flag
  DWORD dwCreationFlags, // creation flags
  LPVOID lpEnvironment,  // pointer to new environment block
  LPCTSTR lpCurrentDirectory,   // pointer to current directory name
  LPSTARTUPINFO lpStartupInfo,  // pointer to STARTUPINFO
  LPPROCESS_INFORMATION lpProcessInformation  // pointer to PROCESS_INFORMATION
);

7.3、线程

 

这里我们学习操作系统的时候描述的更清楚,这里就简单描述;

 

一个进程中有多个线程;

 

进程是执行代码的容器,线程才是Windows操作系统真正要执行的内容;

 

相同进程中的不同线程共享内存空间,但是每个线程有独立的寄存器和栈,独享处理器;

 

线程上下文跳转

 

当一个线程运行时,它独享CPU,并且其它线程不能影响CPU或核的状态;
当一个线程改变CPU中某个寄存器值时,它不会影响其它线程;
操作系统在线程间切换之前,CPU中所有值都被保存在一个叫做线程上下文的结构体中;
操作系统加载新线程的线程上下文结构体,使这个线程在CPU中执行;

 

创建进程函数CreateThread,MSDN中描述:

1
2
3
4
5
6
7
8
9
10
CreateThread函数创建一个线程,在调用进程的地址空间中执行。
 
HANDLE CreateThread(
  LPSECURITY_ATTRIBUTES lpThreadAttributes,  // pointer to security attributes
  DWORD dwStackSize,                         // initial thread stack size
  LPTHREAD_START_ROUTINE lpStartAddress,     // pointer to thread function
  LPVOID lpParameter,                        // argument for new thread
  DWORD dwCreationFlags,                     // creation flags
  LPDWORD lpThreadId                         // pointer to receive thread ID
);

微软还使用了纤程。纤程是被线程管理的;
可以简单的理解成:进程包含线程,线程包含纤程;

 

7.4、使用互斥量的进程间协作

 

一个和线程与进程相关的话题是互斥量(mutex);
内核中称为互斥门(mutant);
互斥量是全局对象,用于协调多个进程和线程;

 

同一时刻只有一个线程拥有一个互斥量,通过互斥量来控制共享资源的访问;

 

更多细节查看多线程编程相关书籍;

 

7.5、服务

 

恶意代码执行附加代码的另一种方式是将它作为服务安装。

 

Windows允许通过使用服务,来使任务作为后台应用程序运行,而不需要它们自己的进程或线程,代码被Windows服务管理器 调度和运行,但没有用户输入;

 

在Windows操作系统上的任何指定实践,都会有多个服务在运行;

 

服务是提供系统上持久化驻留的另外一种方式,因为它可以被设置成当操作系统启动时自动运行,甚至不会在任务管理器中作为进程显示出来;
net start命令可以列举处正在运行的服务。还可以通过Autoruns等工具查看更多细节

  • 操作服务的Windows API:
API 描述
OpenSCManager 返回一个服务控制管理器的句柄,它被用来进行所有后续与服务相关的函数调用。所有要和服务交互的代码都会调用这个函数
CreateService 添加一个新服务到服务控制管理器,并且允许调用者指定服务是否在引导时自动启动,或者必须手动启动;
StartService 启动一个服务,并且仅在服务被设置成手动启动时使用;
 

Windows操作系统支持多种服务类型,它们以独特的方式执行;

  • 恶意代码最常用的是WIN32_SHARE_PROCESS类型,这种类型将这个服务的代码保存在一个DLL中,并且在一个共享的进程中组合多个不同的服务。
    在任务管理器中,一个名叫svchost.exe进程的多个实例,它们在运行WIN32_SHARE_PROCESS类型的服务

  • WIN32_OWN_PROCESS类型有时也被使用,因为它在一个.exe文件中保存代码,而且作为一个独立进程运行;

  • 还有一个常见的服务类型是KERNEL_DRIVER,它被用来加载代码到内核中执行;

本地系统上服务的信息被保存在注册表中,每个服务在HKLM\SYSTEM\CurrentControset\Service下面有一个子键;

 

image-20210407190605173

 

这里要说明的我是用Win10找的,用Win7效果一样;

  • 利用SC程序是Windows命令行工具,可以用来查询和操作服务,包含了添加删除启动停止以及查询服务的命令;

image-20210407191132383

 

sc.exe使用官方文档

 

7.6、组件对象模型

 

微软组建对象模型(COM)是一个接口标准;
它使不同软件组件在不知道其它组件代码的接口规范时,互相之间可以进行调用;
分析使用COM的代码时,需要判断哪段代码会被作为一个COM函数进行调用运行;

 

更多细节请看《COM原理与应用》,这里只做一些总结;

  • COM被实现成一个C/S框架,客户端是那些使用COM对象的程序,服务器是那些可复用的软件组件–也就是COM对象本身。
  • 每一个使用COM的线程,必须在调用任何其它COM库函数之前,至少调用一次OleInitialize函数或CoInitializeEx函数;所以可以搜索这些调用判断是否使用了COM功能;

CLSID、IID以及COM对象的使用

 

COM对象通过它们的全局唯一标识符(GUID),分为类型标识符(CLSID)以及接口标识符(IID),来进行访问。

  • CoCreateInstance函数被用来获取对COM功能的访问;
  • Navigate函数允许一个程序启动Internet Explorer,并访问一个Web地址;

    • Navigate函数是IWebBrowser2组件接口的一部分,这个接口指定一个必须被实现的函数列表,但是它没有指定哪个程序会提供这个功能;
      • 提供这个功能的程序就是实现了IWebBrowser2接口的COM类;
    • 例如IWebBrowser2接口被Internet Explorer实现。接口通过一个叫做IIDGUID来标识,而COM类通过一个叫做CLSIDGUID来标识;
  • 当一个程序调用CoCreateInstance函数时,操作系统使用注册表中的信息,来判断哪个文件包含被请求的COM代码;

    • HKLM\SOFTWARE\Classes\CLSIDHKCU\SOFTWARE\Classes\CLSID注册表键存储了关于那些代码执行这个COM服务器的信息;

对于在实战逆向中IDA Pro无法识别的COM组件函数,一个策略是检查头文件,以寻找在调用CoCreateInstance时指定的接口;这些文件包含在微软Visual Studio和平台SDK中,并且都能在互联网上找到;

 

例如:Navigate函数是在.h文件中的第12个函数,它对应的偏移0x2C处,所以在调用时就是+0x2C的偏移;

 

有些COM对象会被作为DLL实现,它们被加载到到COM客户端可执行文件的进程空间中;
当这个COM对象被安装成DLL加载时,CLSID的注册表项会包含子键InprocServer32,而不是LocalServer32;

 

COM服务器恶意代码

 

Malware实现了一个恶意COM服务器,使其被其它应用使用;

 

对于Malware来说,常用的COM服务器功能是通过浏览器帮助对象(BHO),这是Internet Explorer的第三方插件。
BHO没有限制,所以恶意代码作者使用它们在Internet Explorer进程中运行代码,这允许它们监控互联网流量、跟踪浏览器的使用,以及与互联网通信,而且并不使用它们自己的进程;

 

一个实现COM服务器的Malware通常很容易检测,因为导出了几个函数,包括DllCanUnloadNowDllGetClassObjectDllInstallDllRegisterServer,以及DllUnregisterServer,它们都必须由COM服务器软件导出;

 

7.6、异常:当事情出错时

 

异常机制允许一个程序在普通执行流程之外处理事件;

 

结构化异常处理(SEH)是Windows的异常处理机制。SEH是一个重要知识点,后续单独开一帖再补充吧

 

7.7、内核模式与用户模式

 

这个也是老生常谈的一个点了,内核模式(R0),用户模式(R3);

 

当一个Windows API函数操作内核结构体时,它会通过一个调用进入内核。在反汇编中SYSENTERSYSCALL或者INT 0x2E的存在,指明一个调用被使用进入到内核;

  • 直接通过跳转从用户模式到内核模式是不可能的,这些指令使用查找表来定位一个预定义函数,从而在内核中执行代码;

  • 所有运行在内核的进程共享资源和内存地址。内核模式代码有更少的安全检查。如果内核运行的代码执行并且包含无效指令,操作系统就不能继续运行,产生结果就是Windows蓝屏;

  • 运行在内核中的代码可以操纵运行在用户空间的代码,但是运行在用户空间的代码只能通过定义好的接口来影响内核。
    • 即使所有运行在内核的代码共享内存和资源,处于活跃状态的进程上下文也总是只有一个;

更多的内容,将后续单独开帖再做补充

 

7.8、原生API

 

原生API是用来和Windows进行交互的底层API,调用原生API函数可以绕过普通的Windows API;

 

这里的原始API指的是最接近内核的API接口,书中指的是Ntdll.dll
ntdll.dll的导出表中,同样的函数会同时有Nt前缀或Zw前缀;

 

关于Ntdll.dll的更多信息,查询在线资源

总结

在分析Windows恶意程序时,Windows病毒的各种形式就显得尤为重要了;

 

光看书有点乏,就干脆写起了读书笔记,效果是好,就是进度有点慢了;

 

以上内容,欢迎大佬指点!


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2021-4-8 14:59 被平头猿小哥编辑 ,原因:
收藏
点赞2
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回