-
-
[原创]默默无闻·恶意代码分析第七章
-
发表于: 2021-4-7 20:34 7879
-
参照书籍:《恶意代码分析实战》;
系统环境:Windows7 x86
使用工具:WinHex、CFF、StudyPE+、Exeinfo PE、Resource Hacker、Depends Walker、OD、IDA、MSDN;
这一章节还是比较重要的,总结了在逆向Windows恶意代码中可能遇到的形式;
所以此贴以知识点总结为主;
1、Windows API常见类型
2、句柄
多说无益,首先要了解的是:
1、每个进程内核有句柄表;
2、系统有一个全局句柄表;
3、而句柄就是指向这些表的指针,所以句柄是有两种情况的;
参考书籍《Windows 核心编程》
3、文件系统
根据《恶意代码分析实战》中列出的函数,更多的在之前和以后的帖子中,或者查询MSDN(最有效,,最详细)
这些函数都是常被恶意代码用到的函数,比如可以模拟系统加载PE,写成一个加载器;
4、特殊文件
Windows系统中的特殊文件类型,这些文件在目录中不会显示出来,某些特殊文件可以提供对系统硬件和内部数据更强的访问能力;
书中介绍了三种类型,分别是共享文件
、通过名字空间访问的文件
、备用数据流
;
4.1、共享文件
共享文件以\\serverName\share
或\\?\serverName\share
开头命名的特殊文件;
4.2、通过名字空间访问的文件
名字空间可以被认为是固定数目的文件夹,每一个文件夹中保存不同类型的对象;
底层的名字空间是NT名字空间,以前缀\
开始。
NT名字空间可以访问所有设备,以及所有在NT名字空间中存在的其它名字空间;
使用WinObj对象管理器名字空间查看器
查看名字空间;
从Windows 2003 SP1开始,Device\PhysicalMemory
从用户空间已经无法访问。但是可以从内核空间访问。由此可见,反病毒要把内核学好才行。
4.3、备用数据流
备用数据流(ADS)特性允许附加数据被添加到一个已存在 的MTFS文件;
就是添加一个文件到另外一个文件中,额外数据在列一个目录时不会被显示出来,只有在访问流时,它才可见;
Malware作者喜欢ADS,因为它能被用来隐藏数据;
5、Windows 注册表
注册表用来保存操作系统与程序的配置信息,例如设置和选项;
恶意代码经常使用注册表来完成持久驻留或者存储配置数据。
注册表术语:
5.1、注册表根键
两个最常用的根键是HKLM
和HKCU
(这些键通常通过它们的缩写来引用)。
一些键实际是虚拟键值,提供一种引用底层注册表信息的方式:
例如,HKEY_CURRENT_USER
键实际上存储在HKEY_USERS\SID
中,这里的SID
是当前登陆用户的安全描述符;
例如,一个常用的子健,HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
,包含一系列值,这些值列举了当一个用户登陆时被自动启动的可执行程序。
根键是HKEY_LOCAL_MACHINE
,它保存了SOFTWARE
、Microsoft
、Windows
、CurrentVersion
以及Run
子键;
5.2、Regedit
快捷键win+r
,然后在运行窗口输入regedit
,打开注册表编辑器;
5.2.1、自启动程序查找
根据选框中的路径查找(这是用windows10本机查找的);
5.2.2、常用注册表函数
如果在实战中遇到Malware访问一些键值时,可以通过搜索引擎寻找相关信息;
5.2.4、使用.reg文件的注册表脚本
用.reg
作为扩展的文件包含一个人类可读的注册表数据;
运行.reg
文件,它会自动通过合并文件包含的信息到注册表中,来修改注册表;(几乎像一个脚本)
实例:
这是Microsoft官网的教程:如何使用 .reg 文件添加、修改或删除注册表子项和值
6、网络API
这是Malware经常用到的东西了;
6.1、伯克利兼容套接字
最常使用的套接字,因为其功能在Windows和UNIX系统上是几乎一样的;
Windows系统中是由Winsock
库实现的,主要在ws2_32.dll
中,下表给出了对一些常用函数的描述;
WSAStartup
函数必须要在其它网络函数之前被调用,以便为这些网络库分配资源;
当调试代码查找网络连接入口时,在WSAStartup
函数中设置一个断点,是非常有效的方式;
6.2、网络的服务器和客户端
一个网络程序通常有两个端点:
服务端:它维护一个打开套接字并等待入站连接;
客户端:它连接到一个正在等待的套接字;
恶意代码可以是任意一个!!!
6.3、WinINet API
除了Winsock API
以外,还有一个叫WinInetAPI
的更高级的Windows API
(这里的高级是指ISO/OSI网络体系结构和TCP/IP协议模型中的相对位置);
WinInet API
实现了应用层协议,如HTTP和FTP,通过判断打开的是何种连接,来理解它的功能;
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程序,通过查看Malware的导入表中的Windows API,可以猜测实现了什么功能;
除了系统的基础DLL,还可以使用第三方的DLL;
例如:
使用Mozilla Firefox DLL来连接服务器;
自定义的DLL和Malware(exe文件)一同发布;
7.2、进程
恶意代码可以通过创建一个新进程,或修改一个已存在的进程,来执行当前程序之外的代码;
传统上,恶意代码包括它自己的独立进程(独立恶意行为程序);
现在更普遍的是将自身代码作为其它进程的一部分执行(导入表注入之类的操作);
这就好比,前者是一匹狼,后者是个披着羊皮的狼;
创建进程函数CreateProcess
,MSDN中描述:
7.3、线程
这里我们学习操作系统的时候描述的更清楚,这里就简单描述;
一个进程中有多个线程;
进程是执行代码的容器,线程才是Windows操作系统真正要执行的内容;
相同进程中的不同线程共享内存空间,但是每个线程有独立的寄存器和栈,独享处理器;
线程上下文跳转
当一个线程运行时,它独享CPU,并且其它线程不能影响CPU或核的状态;
当一个线程改变CPU中某个寄存器值时,它不会影响其它线程;
操作系统在线程间切换之前,CPU中所有值都被保存在一个叫做线程上下文
的结构体中;
操作系统加载新线程的线程上下文
结构体,使这个线程在CPU中执行;
创建进程函数CreateThread
,MSDN中描述:
微软还使用了纤程。纤程是被线程管理的;
可以简单的理解成:进程包含线程,线程包含纤程;
7.4、使用互斥量的进程间协作
一个和线程与进程相关的话题是互斥量
(mutex);
内核中称为互斥门
(mutant);
互斥量是全局对象,用于协调多个进程和线程;
同一时刻只有一个线程拥有一个互斥量,通过互斥量来控制共享资源的访问;
更多细节查看多线程编程相关书籍;
7.5、服务
恶意代码执行附加代码的另一种方式是将它作为服务安装。
Windows允许通过使用服务,来使任务作为后台应用程序运行,而不需要它们自己的进程或线程,代码被Windows服务管理器 调度和运行,但没有用户输入;
在Windows操作系统上的任何指定实践,都会有多个服务在运行;
服务是提供系统上持久化驻留的另外一种方式,因为它可以被设置成当操作系统启动时自动运行,甚至不会在任务管理器中作为进程显示出来;net start
命令可以列举处正在运行的服务。还可以通过Autoruns
等工具查看更多细节
Windows操作系统支持多种服务类型,它们以独特的方式执行;
恶意代码最常用的是WIN32_SHARE_PROCESS
类型,这种类型将这个服务的代码保存在一个DLL中,并且在一个共享的进程中组合多个不同的服务。
在任务管理器中,一个名叫svchost.exe
进程的多个实例,它们在运行WIN32_SHARE_PROCESS
类型的服务;
WIN32_OWN_PROCESS
类型有时也被使用,因为它在一个.exe
文件中保存代码,而且作为一个独立进程运行;
本地系统上服务的信息被保存在注册表中,每个服务在HKLM\SYSTEM\CurrentControset\Service
下面有一个子键;
这里要说明的我是用Win10找的,用Win7效果一样;
7.6、组件对象模型
微软组建对象模型(COM)是一个接口标准;
它使不同软件组件在不知道其它组件代码的接口规范时,互相之间可以进行调用;
分析使用COM的代码时,需要判断哪段代码会被作为一个COM函数进行调用运行;
更多细节请看《COM原理与应用》,这里只做一些总结;
CLSID、IID以及COM对象的使用
COM对象通过它们的全局唯一标识符(GUID),分为类型标识符(CLSID)以及接口标识符(IID),来进行访问。
Navigate
函数允许一个程序启动Internet Explorer,并访问一个Web地址;
当一个程序调用CoCreateInstance
函数时,操作系统使用注册表中的信息,来判断哪个文件包含被请求的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通常很容易检测,因为导出了几个函数,包括DllCanUnloadNow
、DllGetClassObject
、DllInstall
、DllRegisterServer
,以及DllUnregisterServer
,它们都必须由COM服务器软件导出;
7.6、异常:当事情出错时
异常机制允许一个程序在普通执行流程之外处理事件;
结构化异常处理(SEH)是Windows的异常处理机制。SEH是一个重要知识点,后续单独开一帖再补充吧
7.7、内核模式与用户模式
这个也是老生常谈的一个点了,内核模式(R0),用户模式(R3);
当一个Windows API函数操作内核结构体时,它会通过一个调用进入内核。在反汇编中SYSENTER
、SYSCALL
或者INT 0x2E
的存在,指明一个调用被使用进入到内核;
直接通过跳转从用户模式到内核模式是不可能的,这些指令使用查找表来定位一个预定义函数,从而在内核中执行代码;
所有运行在内核的进程共享资源和内存地址。内核模式代码有更少的安全检查。如果内核运行的代码执行并且包含无效指令,操作系统就不能继续运行,产生结果就是Windows蓝屏;
更多的内容,将后续单独开帖再做补充;
7.8、原生API
原生API是用来和Windows进行交互的底层API,调用原生API函数可以绕过普通的Windows API;
这里的原始API指的是最接近内核的API接口,书中指的是Ntdll.dll
;
在ntdll.dll
的导出表中,同样的函数会同时有Nt
前缀或Zw
前缀;
关于Ntdll.dll
的更多信息,查询在线资源
在分析Windows恶意程序时,Windows病毒的各种形式就显得尤为重要了;
光看书有点乏,就干脆写起了读书笔记,效果是好,就是进度有点慢了;
以上内容,欢迎大佬指点!
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
赞赏
- [原创]默默无闻·恶意代码分析Lab10 13505
- [原创] 默默无闻·恶意代码分析Lab9 15336
- [原创] 默默无闻·恶意代码分析Lab7 5580
- [原创]咬文嚼字·浅说OEP和EP 16505
- [原创]默默无闻·恶意代码分析第七章 7880