Lab 10-1
一些准备工作
首先就是配置内核调试的环境
我这里用的是VirtualBox而不是书上的VMware
所以这里可能会有一些的不同
书上说的是这样的
与用户态调试不同,内核调试需要一些初始化配置。首先需要配置虚拟操作系统并开启内核调试,然后配置VMware使虚拟机和宿主操作系统之间有一条虚拟化的串口,同时还应该配置宿主操作系统中的WinDbg
我们按照书上的做法开始,先配置C:\boot.ini
这里要把隐藏文件和隐藏系统配置文件取消勾选
然后我们打开这个boot.ini
注意改之前记得备份系统,防止起不来
然后我们开始修改boot.ini文件
[boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(1)\WINDOWS
[operation systems]
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional" /noexecute=optin /fastdetect
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional with Kernel Debugging" /noexecute=optin /fastdetect /debug /debugport=COM1 /baudrate=115200
注意这里的COM1这个端口,待会选的时候别选错了
然后这就是改变后的样子
然后下次重启虚拟机的时候,就会出现一个开启内核调试的选项给你选择
然后下面我们设置虚拟机和宿主机之间的那个虚拟连接,我这里是VritualBox,所以用VMware的同学照书做就行
选择这里
然后这里开启串口
开机的时候我们还开启不了,我们先关闭虚拟机
关了之后就可以修改了
然后我们这样设置,注意那个连接至不要打勾,不然启动虚拟机就会报错(如果你没报错可以点了试试哈哈哈)
然后进去就可以发现这个了
然后发现我这没激活的系统已经进不去了(无语),我还是先激活一下这个系统算了
然后这里放一个XP的OEM激活工具,省的找了,直接运行就行了
如果你打算使用简单一点只包括WinDbg的东西,用优快云那个(这个好像只支持xp和win7)
如果没积分的话,可以试试龟速的百度云这个我下载好上传的连接
资源中有两个文件:64位系统6.12版本和32位系统6.11版本
解压后是这样的
我们这是32位的系统,我们安装x86的就行
打开之后就是这样的
然后安装就行了
这里有个问题,笔者以前一直以为这个WinDbg是要安装在虚拟机上的,然后今天有时间好好查了一下,这个是要安装在宿主机上,也就是你运行虚拟机那个机器上(这就尴尬了)
现在我bing了一下,要安装Win10的WinDbg的话,你要先安装WDK,要安装WDK的话,你要安装这个
你必须先安装这个studio这个东西,慢慢装吧,继续链接在这里 安装WDK
然后我们安装这个studio
我就点了一个Python的开发还有一个Linux C的开发,就两个包,已经要下8G的内容,我也是很无语,这里需要选择这个使用 C++ 的桌面开发,这个会包含这个WDK东西
我们慢慢装一下这个东西吧,然后我们装这个Windbg
然后这里我们选择这个
就行了(默认是全部都选的)
然后在开始里面查找一下,出现这个就说明安装成功了
到这里,你已经做完了安装WinDbg的任务,现在我们开始设置VirtualBox
我这里使用的Version 5.2.6的最新版(2018-1-22),英文的
这里我们找到这个Serial Ports这个东西,然后Enable Serial Port这里点上勾勾,然后设置这个Port Mode为Host Pipe,然后确保这个Connect to existing pipe/socket这个没有打勾,其他的都不用配置
然后我们开启虚拟机
然后我们下载Windows Symbol去,我这里下载了一份,是SO的大神告诉我哪里下载的。。。
然后双击运行就行了
我是安装在了C盘
然后我们开始调试,我们设置好Windbg之后,重启虚拟机然后等着就行了
出现这个就说明脸上了,然后我们开始设置Symbol
我的做法是这样的,其他做法也可以,只要你可以调试就行了,我找到Windbg的文件夹,然后把这个程序创建一个桌面快捷方式,然后我们打开这个快捷方式
把这里这个目标改为这个(Windbg的路径一般不需要改,只需要增加后面那些参数就行了,记得结合你的虚拟机设置来稍微改动一下)
"C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\windbg.exe" -b -k com:port=\\.\pipe\com1,baud=115200,pipe -y C:\Windows\Symbols
也就是在原来的
"C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\windbg.exe"
后面加上
-b -k com:port=\\.\pipe\com1,baud=115200,pipe -y C:\Windows\Symbols
记得这两个字符串之间要有个空格
然后我们双击之后就会自动出来那个窗口了
这样就说明已经处于调试状态了
我这个Windbg并不会显示多余的信息,我们可以安装下面的这个教程拷出来的图片操作,输入g就继续
然后这样我们就配置好了WindowsXP Kernel调试环境
问题
1.这个程序是否直接修改了注册表(使用procmon来检查)?
解答: 现在我们调试器准备好之后,开始准备运行这个病毒,然后之前先做一下系统的备份
在运行调试器的时候,如果你不需要调试中断了,输入一个g就可以了
然后如果你突然需要终端介入了,然后点一下这里
然后就会产生一个中断,系统这时候就会暂停运行了
然后我们把这两个文件拖到C:\Windows\System32下面
也就是Lab10-01的两个实验样本(记得在这之前做备份)
复制完之后,我们按照书上的一些办法,执行一些基本的静态分析
然后我们可以发现第一个DLL里面导入了这么几个函数
ControlService
CreateServiceA
OpenSCManagerA
OpenServiceA
StartServiceA
都是和服务控制有关的,创建一个服务,控制一个服务,启动一个服务
然后第二个DLL导入的函数是这些
有点多,其中毕竟要注意的是
WriteFile
说明会有一个写入文件的操作
然后我们打开IDA来看看字符串有哪些
这个程序就操作了这么几个函数就完了,没有特别复杂的逻辑
然后我们看看字符串都有些什么东西
我们注意到最后那里有个C:\\Windows\\System32\\Lab10-01.sys这个路径,说明这个程序会去调用这个sys文件
然后我们研究一下这个sys文件是啥样的
这个文件只导入了这么几个函数
按照书上的说法,第一个函数KeTickCount是所有驱动都会包含的一个函数,这个可以忽略
然后第二个RtlCreateRegistryKey和第三个RtlWriteRegistryValue,看到这个Registry我们就大概知道这个操作是和注册表有关的操作,然后一个是Create一个是Write,所以这个是创建和写入注册表的操作
然后打开字符串看看都有哪些字符串
然后发现有个小Error
这个是缺少了一个Symbol,然后看来我们还要装一个,不行,装了还是不行Symbol这个东西
这里看不见书上那些字符串,过~
所以这里我们缺个symbol,sys文件没法看到具体的字符串是啥样的
然后下面我们开始动态分析,还原虚拟机,去除装的那个Symbol
执行之后,用procmon检查操作,会发现这么几个操作
这里有个调用恶意程序的操作,放大之后就是这样的,一个QueryOpen
还有这个
有个操作就是CreateFile
然后如果我们设置筛选条件为Process Name = Lab10-01.exe的话,我们就可以发现这些东西
这里显示我们运行这个Lab10-01.exe之后,起了一个线程(Thread Create),然后就是加载了一下DLL,然后创建了一个文件在C:\WINDOWS\system32\Lab10-01.EXE-xxxxx.pf
这里有个RegOpenKey,然后打开了这个键
这个的执行结果是
这里唯一改变了键的就只有这个操作
这里用RegSetValue改变了一个加密用的种子值,但是这个对分析恶意代码没用
然后函数在这里调用了sys驱动文件
这是我们动态分析能分析到的信息了,下面我们开始静态分析代码
然后这是整个函数的大概样子,其中有两个小+号里面藏着一些隐藏的函数
我们进入main函数看看
这里唯一的一个函数调用是OpenSCManagerA,这个是
在指定的计算机上建立与服务控制管理器的连接,并打开指定的服务控制管理器数据库。
这是连接到服务管理的一个函数,然后我们继续分析
如果失败,返回的NULL,然后这里用test测试了返回值,test指令是和and类似的,如果返回的是NULL,test之后,结果为0,则ZF=1,JNZ不会跳转,继续执行,走红线,然后就返回了
如果没有失败,我们继续往下走
往下走就是这里,之类调用了CreateServiceA这个函数,我们对应一下入参就是如下
SC_HANDLE WINAPI CreateService(
_In_ SC_HANDLE hSCManager = edi,
_In_ LPCTSTR lpServiceName = "Lab10-01",
_In_opt_ LPCTSTR lpDisplayName = "Lab10-01",
_In_ DWORD dwDesiredAccess = 0F01FFh,
_In_ DWORD dwServiceType = 1,
_In_ DWORD dwStartType = 3,
_In_ DWORD dwErrorControl = 1,
_In_opt_ LPCTSTR lpBinaryPathName = "C:\\Windows\\System32\\Lab10-01.sys",
_In_opt_ LPCTSTR lpLoadOrderGroup = 0,
_Out_opt_ LPDWORD lpdwTagId = 0,
_In_opt_ LPCTSTR lpDependencies = 0,
_In_opt_ LPCTSTR lpServiceStartName = 0,
_In_opt_ LPCTSTR lpPassword = 0
);
这里我们就关注这么几个点,首先是可以看出这个服务的名字就是Lab10-01,然后访问权限dwDesiredAccess是SERVICE_ALL_ACCESS
然后下一个是dwServiceType是SERVICE_KERNEL_DRIVER,这意味这这个文件会加载到内核里面
然后dwStartType是SERVICE_DEMAND_START,也就是会自动启动的一个服务
最后需要注意的就是lpBinaryPathName,这个的值是"C:\\Windows\\System32\\Lab10-01.sys",意味着服务起来的时候会去加载这个二进制文件
一样的,这个函数调用失败会返回NULL
在这里,如果函数失败,返回NULL,test之后,ZF=1,然后JNZ不会跳转,所以函数失败之后,会继续走红线,也就这写代码
这里程序会尝试打开这个服务通过OpenServiceA来实现
SC_HANDLE WINAPI OpenService(
_In_ SC_HANDLE hSCManager = edi,
_In_ LPCTSTR lpServiceName = "Lab10-01",
_In_ DWORD dwDesiredAccess = 0F01FFh
);
如果上面这个OpenServiceA失败,然后会继续通过StartServiceA来开启这个服务
如果上面的函数调用失败,还是会继续通过ControlService来将控制码发送给服务
然后对应一下就是
BOOL WINAPI ControlService(
_In_ SC_HANDLE hService = esi,
_In_ DWORD dwControl = 1,
_Out_ LPSERVICE_STATUS lpServiceStatus = eax
);
这里值得注意的是dwControl,代表的意思SERVICE_CONTROL_STOP,这个应该是停止这个服务,然后卸载这个驱动(书上的原话)
所以这些操作,只要一个成功了,就会直接一个JZ跳转然后返回了,如果失败,则继续往下尝试另外的函数
然后我们继续分析,这次我们分析Lab10-01.sys
我们找到驱动的入口点,然后查找
前面的
mov edi, edi
push ebp
mov ebp, esp
这些操作是在调用函数之前的初始化栈空间操作,如果你好好分析就会知道,这些操作会在栈上重新分配一些空间给要调用的函数,对我们分析来说,无关紧要
然后之后就调用了sub_10920,我们进去看看
这里执行的是驱动函数的一些必要操作
然后我们退出来,看看下一个函数sub_10906
这个代码我们来解释一下
mov edi, edi
push ebp
mov ebp, esp
/* 上面那些都是函数调用之前的初始化栈操作 */
mov eax, [ebp + arg_0] // 将入参的第一个值也就是文件名赋值给eax
mov dword ptr [eax+34h], offset sub_10486 // 然后将sub_10486的地址赋值给eax+34h
xor eax, eax
pop ebp
retn 8
这里虽然没有调用任何函数,然后出现了一个函数的赋值sub_10486,然后我们进去看看就会发现这个
这个函数会调用RtlCreateRegistryKey这个内核函数来创建一个键在\Registry\Machine\SOFTWARE\Policies\Microsoft,然后设置为0
然后下一个调用是
然后这里创建了一个键在\Registry\Machine\SOFTWARE\Policies\Microsoft\WindowsFire,然后写入的值是wall为0
再下面也是一样的\Registry\Machine\SOFTWARE\Policies\Microsoft\WindowsFire,然后写入的信息是wall\StandarProfile为0
然后下一个函数是RtlWriteRegistryValue
这里写入的值是\Registry\Machine\SOFTWARE\Policies\Microsoft\WindowsFire
入参是这么几个
这个函数在MSDN中的定义是这样的
NTSTATUS RtlWriteRegistryValue(
_In_ ULONG RelativeTo = 0,
_In_ PCWSTR Path = ebx,
_In_ PCWSTR ValueName = edi,
_In_ ULONG ValueType = 4,
_In_opt_ PVOID ValueData = eax,
_In_ ULONG ValueLength = 4
);
这里我们查看MSDN里面RelativeTo的数据会发现
这里并没有任何是值显示,我们用IDA替换一下
这里我们搜索之后会发现,这里只有这个,然后我们替换成这个RTL_REGISTRY_ABSOLUTE
这个的意思在MSDN里面解释是这样
意思就是
路径是一个绝对的注册表路径
然后我们看看这个Path的路径是多少,在这里的ebx显示是这样的,他被赋值为aRegistryMach_2之后就没被改变过了
所以这里的Path的值就是\Registry\Machine\SOFTWARE\Policies\Microsoft\WindowsFire,然后值为wall\DomainProfile, 0
然后ValueName的值是edi,在IDA里查找最后改变edi的值
最上面那里一个mov赋值之后就没有改变过了,然后这个ValueName的值是一个dw类型的
也就是E
然后下面的ValueType的值是4,查看MSDN
这里有个REG我们根据这个查查看
这里有很多的待选,我们再继续查找
这时候只有一个REG_DWORD_LITTLE_ENDIAN符合,这个选项的意思是
最低地址处的最低有效字节的4字节数值。与REG_DWORD相同。
所以最后,总结一下这个函数会做什么
RtlWriteRegistryValue例程将调用方提供的数据以指定的值名称写入指定的相对路径。
这里会将\Registry\Machine\SOFTWARE\Policies\Microsoft\WindowsFire\wall\DomainProfile的值写入成45h
2.用户态的程序调用了ControlService函数,你是否能够使用WinDbg设置一个断点,以此来观察由于ControlService的调用导致内核执行了怎样的操作?
解答: 我们开始刚刚一开始我们配置的Windbg来就行内核调试,书上的原话我就不重复了
这里说一下,我的Windbg连WinXP虚拟机的内核的时候,必须重启才可以连进去,然后现在书上的做法是虚拟机里面用Windbg来进行调试,加个断点之后,在来宿主物理机上,连Windbg,这个方法我感觉是不靠谱的,我的想法是最好还是虚拟机启动的时候就连Windbg,然后用g命令执行,再用OD来加载exe文件加断点,省的windbg界面不好调试,windbg还是用于内核调试算了
我们先在IDA里面找到这个ControlService的地址,这个是系统函数
然后找到地址为401080,我们在OD里面加载断点
我们找到这个位置,然后加断点,然后执行到这里
命中断点之后,我们的OD显示和Windbg一样,比Windbg更具有可读性
然后我们现在可以跳出虚拟机了,Windbg发送break然后暂停虚拟机的运行
然后我们继续跟着书走
我们已经暂停了虚拟机的执行,Windbg在等待我们的输入
我们输入!drvobj Lab10-01, 我在Win10物理机上做是有点慢,慢慢的才会出结果来,等一下
这里显示的和书上的不一样,因为我们输入的是大写的Lab10-01,然后我们试试小写的lab10-01
还是一样的无法得出和书中结果相似的结果,书中的结果如下
然后我们看这个WinDbg的ERROR,说的是symbols could not be loaded for Lab10-01这个东西,我以前装的symbols是WinXP SP3的…
现在我换个Symbols看看,换的是Windows 10 1701的,试试看
现在我们更换这个Symbols为安装在D盘的Windows 10的,但是这里显示是找不到这个Symbols文件,这里保证路径没有打错哈哈哈
看来我们只能用WindowsXP SP3那个版本的Symbol了
所以这里不知道什么Symbol的原因,无法显示和书中相似的结果,我们继续下面的操作
然后我们查找这个驱动对象的地址,在书本上是这里
然后我们查看我们出来的结果
这里我们试了大写和小写的,出来的驱动对象地址都是一样的896fa5f0,不过我们先试试82636b418这个地址
这里显示什么也没有,我们再试试我们得出的结果的那个地址896fa5f0
这里就和书上结论类似了,我们查看在0x034偏移DriverUnload(驱动程序卸载)的这个地方的值,这里有个DriverUnload的函数,这个偏移的地址是0xf7ab9486
下面我们在这个地址这里设置一个断点,来查看这里发生了什么(这个断点用物理机上的WinDbg设置)
bp 0xf7ab9486
注:每次运行地址都会不同
然后我们恢复虚拟机的运行,回到OD中用OD的F9运行代码
注:这里是我第二次运行虚拟机,上面那个是昨天写的,今天重连pipe所以重启了一下虚拟机,所以这个地址和前面的有不同,说明一下
这里我们的断点已经被命中,然后我们继续,这时候虚拟机也已经暂停了运行,下面我们执行单步调试,WinDbg的单步调试对话框输入p就可以了
这里显示了三行汇编代码,从这个结构和处理来说,我们刚刚WinDbg的断点应该是断在了一个函数的入口第一行汇编代码的地方
mov edi, edi
push ebp
mov ebp, esp
这三段代码都是调用函数之后的栈预处理,然后接下来的代码整理之后就是如下的
push ecx
push ebx
push esi
move esi, dword ptr [Lab10_01+0x780 f(7a54780)]
push edi
xor edi, edi
push offset Lab10_01+0x6bc(f7a546bc)
push edi
mov dword ptr [ebp-4], edi
call esi
执行到这里的时候我们想知道这个调用esi是什么函数,可以执行
u esi
然后就会显示了
这是一个nt!RtlCreateRegistryKey调用,而这个函数的定义是如下
NTSTATUS RtlCreateRegistryKey(
_In_ ULONG RelativeTo,
_In_ PWSTR Path
);
有两个入参,第一个入参是edi,即RelativeTo=edi,第二个是offset Lab10_01+0x6bc(f7a546bc),即Path=offset Lab10_01+0x6bc(f7a546bc)
这里的RelativeTo的值为0,接下来我们看看Path的值,这里我们先用da命令
在地址f7a546bc处的值的ASCII是\,当然,这样对查看单个地址上的数据比较有用,如果数据很多,要查看的话,我们用dc命令
dc f7a546bc
这里的Path的值就是\Registry\Machine\SOFTWARE\Policies\Microsoft,然后后面就是全0的截断符了
然后下面又是一个相同的调用nt!RtlCreateRegistryKey,edi的值没有改变还是0,我们看看f7a54640的值
push offset Lab10_01+0x640(f7a54640)
push edi
call esi
注意这里下面被圈黄的截断符(web渗透里面叫截断符’\00’,计算机里面叫文件结束符),这里我们得出的Path是\Registry\Machine\SOFTWARE\Policies\Microsoft\WindowsFirewall
从字面意思应该可以大概知道这个注册表是关于防火墙的
继续下面的汇编代码
push offset Lab10_01+0x6a8(f7a545a8)
push edi
call esi
还是一个nt!RtlCreateRegistryKey调用,和上面两个片段类似
edi至今未变,我们看看Path的值
这里还未出现文件结束符,说明这里还有数据没有显示出来,我们跳到最后显示这个地址继续显示
图上圈黄的是文件结束符的位置,然后我们可以得出这次调用的Path的值是\Registry\Machine\SOFTWARE\Policies\Microsoft\WindowsFirewall\DomainProfile
然后继续往下看代码
mov ebx, offset Lab10_01+0x50c(f7a5450c)
push ebx
push edi
call esi
这里的esi还是未变,我们看看Path的值
这里依旧是一次未能显示全,我们往下跳
可得出Path的值就是\Registry\Machine\SOFTWARE\Policies\Microsoft\WindowsFirewall\StandardProfile
所以应该是调用了四次nt!RtlCreateRegistryKey(书中有误),然后依次创建的键路径在如下所示
\Registry\Machine\SOFTWARE\Policies\Microsoft
\Registry\Machine\SOFTWARE\Policies\Microsoft\WindowsFirewall
\Registry\Machine\SOFTWARE\Policies\Microsoft\WindowsFirewall\DomainProfile
\Registry\Machine\SOFTWARE\Policies\Microsoft\WindowsFirewall\StandardProfile
然后我们继续往下分析,下面的代码如下
mov esi, dword ptr [Lab10_01+0x788(f7a54788)]
push 4
lea eax,[ebp-4]
push eax
push 4
mov edi,offset Lab10_01+0x4ee(f7a544ee)
push edi
push offset Lab10_01+0x5a8(f7a545a8)
push 0
call esi
遇到一个call函数了,这里的第一句已经改变了esi,再也不是那个nt!RtlCreateRegistryKey
我们看看这个函数是什么
是nt!RtlWriteRegistryValue,向注册表里面写入值的内核函数,这个函数定义如下
NTSTATUS RtlWriteRegistryValue(
_In_ ULONG RelativeTo,
_In_ PCWSTR Path,
_In_ PCWSTR ValueName,
_In_ ULONG ValueType,
_In_opt_ PVOID ValueData,
_In_ ULONG ValueLength
);
对应上面的汇编代码,我们可以得出下面对照
NTSTATUS RtlWriteRegistryValue(
_In_ ULONG RelativeTo = 0,
_In_ PCWSTR Path = offset Lab10_01+0x5a8(f7a545a8),
_In_ PCWSTR ValueName = offset Lab10_01+0x4ee(f7a544ee),
_In_ ULONG ValueType = 4,
_In_opt_ PVOID ValueData = eax,
_In_ ULONG ValueLength = 4
);
这里对我们来说有意义的参数,一个是Path,这个Path的值我们查查应该是\Registry\Machine\SOFTWARE\Policies\Microsoft\WindowsFirewall\DomainProfile
,然后ValueName的值是EnableFirewall
然后下一个是ValueData的值是,这里的eax的值是[ebp-4]的值,所以我们找ebp-4的值
所以这个eax的值是0,这里的意思就是将EnableFirewall这个的值设置为了0,意义就是从内核禁止了Windows的防火墙功能,然后我们继续往下分析看看
push 4
lea eax,[ebp-4]
push eax
push 4
push edi
push ebx
push 0
call esi
对照结构体,我们可以得出一下结论
NTSTATUS RtlWriteRegistryValue(
_In_ ULONG RelativeTo = 0,
_In_ PCWSTR Path = ebx,
_In_ PCWSTR ValueName = edi,
_In_ ULONG ValueType = 4,
_In_opt_ PVOID ValueData = eax,
_In_ ULONG ValueLength = 4
);
我们看看Path的值应该是\Registry\Machine\SOFTWARE\Policies\Microsoft\WindowsFirewall\StandardProfile
然后ValueName的值是EnableFirewall
最后是ValueData的值是0
所以这里还是通过内核改变注册表\Registry\Machine\SOFTWARE\Policies\Microsoft\WindowsFirewall\StandardProfile的键EnableFireawll为0来关闭防火墙
然后下面的代码就是退出和一些清理函数了
pop edi
pop esi
pop ebx
leave
然后书中还讲了如何计算偏移地址的方法,如何在静态分析中找到驱动卸载程序的地址等等,就不一一概述了
3.这个程序做了什么?
解答: 这个程序通过我们上面的分析可以知道,程序运行之后会启动一个服务,然后通过运行一个驱动创建修改注册表的值,来关闭防火墙
本文完
本文详细介绍如何在VirtualBox上配置Windows XP内核调试环境,包括安装WinDbg、设置虚拟串口、下载Windows Symbol及调试步骤。同时,通过一个具体示例分析了恶意软件如何利用系统API创建服务和修改注册表。

2195

被折叠的 条评论
为什么被折叠?



