一、安装内核调试
1.配置虚拟机
编辑C:\boot.ini ,该文件为隐藏文件,将文件按下面方式进行修改
- /debug表示开启内核调试
- /debugport=COM1表示使用哪个端口来连接调试系统与被调试系统
- /baudrate=115200表示指定串口数据传输速率。
[boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(1)\WINDOWS
[operating 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
2.配置VMware
添加串口设备
设置串口设备。使用命名的管道**\.\pipe\com_1**,IO模式勾选轮询时主动放弃CPU
3.设置windbg
windbg如下配置File->Kernel Debug,baudRate选择115200,Port为\.\pipe\com_1,勾选Pipe
windbg preview如下配置
配置符号表
.sympath srv*G:\vm\XPSP3Symbols*https://msdl.microsoft.com/download/symbols
这里的地址是本地机器上符号表的保存地址
windbg安装symbols下载地址参考下面链接https://www.cnblogs.com/csnd/p/11800535.html
双击调试配置 https://bbs.pediy.com/thread-261326.htm
4.补充xp以后的系统增加的内容
windows7以后使用BCDEdit的程序配置启动项
内核补丁保护机制PatchGuard,阻止第三方程序修改内核(代码自身、系统服务表、IDT)
在系统引导时附加系统,补丁保护不会运行,在系统引导结束后,内核调试器再附加到系统,PatchGuard会使系统崩溃
64位vista开始,强制驱动签名。关闭驱动签名(关闭nointegritychecks)
二、windbg常用命令
这里只记录一下之后用到的。详细的windbg命令以后再记录
内存读取
da 读取内存数据并以ASCII文本显示
du 读取内存数据并以Unicode文本显示
dd 读取内存数据并且以32位双字显示
内存修改(x为a u d)
ex addressToWrite dataToWrite
+ - * /算术运算
dwo用来解引用32位的指针
du dwo (esp+4)
设置断点
bp命令
每次调用GetProcAddress函数时,在不中断程序执行的前提下,打印出第二个参数
bp GetProcAddress "da dwo(esp+8);g"
列举模块
lm
反汇编
u
列出最接近给定内存地址的符号
ln 805717aa
查看一个结构的类型信息
dt nt!_DRIVER_OBJECT
显示某个地址的结构体
dt nt!_DRIVER_OBJECT 828b2648
查看ssdt
dd nt!KeServiceDescriptorTable
查看中断
!idt
查看驱动对象地址
!drvobj drvobjName
列出所有驱动
!object \Driver
三、Lab10-1
需要将Lab10-01.sys放在C:\Windows\System32目录下。
1.lab10-1.exe分析
- 创建驱动服务
- 启动服务
- 发生SERVICE_CONTROL_STOP信息,服务收到消息会卸载驱动
2.Lab10-01.sys分析
lab10-1.sys设置了DriverUnload设置了回调函数,创建了注册表。
3.动态调试
动态运行监控注册表。
用到的一些函数和结构体
动态调试需要在controlService前下断点,否则内核中驱动会被卸载。
本机windbg进行内核调试**!drvobj lab10-01 **定位设备对象(不知道设备对象名字的时候可以用!object \Driver)
查看Lab10-01.sys的驱动对象,并在DriverUnload回调函数下断点
继续运行会触发断点,单步运行可以看到调用了nt!RtlCreateRegistryKey
用到的数据结构和函数
发送控制码给服务
BOOL ControlService(
SC_HANDLE hService,
DWORD dwControl,
LPSERVICE_STATUS lpServiceStatus
);
4.习题答案
1.这个程序是否直接修改了注册表(使用procmon来检查)?
procmon无法检查出注册表的修改。RegShot可以检测出注册表的修改
2.用户态的程序调用了ControlService函数,你是否能够使用WinDbg设置一个断点,以此来观察由ControlService的调用导致内核执行了怎么样的操作?
用户态无法对内核太进行调试。
3.这个程序做了些什么?
修改了注册表,关闭了防火墙
四、Lab10-2
1.Lab10-2.exe分析
- 提取资源文件,并写入C:\Windows\System32\Mlwx486.sys
- 创建服务“486 WS Driver”
- 启动服务
用resourceHack提取资源,明显是一个PE文件提取出来,继续分析
2.Mlwx486.sys分析
- 找到SSDT地址和NtQueryDirectoryFile地址
- 遍历SSDT找到NtQueryDirectoryFile项
- 修改NtQueryDirectoryFile项修改为FakeNtQueryDirectoryFile
FakeNtQueryDirectoryFile函数:循环将文件名与”Mlxw“比较,如果匹配就修改上一个的NextEntryOffset跳过匹配文件
3.动态调试
直接蓝屏了没法调试。应该是有PatchGuard会检测SSDT是否被修改。
用到的数据结构体和函数
返回字符串代表函数的地址
PVOID MmGetSystemRoutineAddress(
PUNICODE_STRING SystemRoutineName
);
根据传入的目录句柄返回下面的各种文件信息
__kernel_entry NTSYSCALLAPI NTSTATUS NtQueryDirectoryFile(
HANDLE FileHandle,
HANDLE Event,
PIO_APC_ROUTINE ApcRoutine,
PVOID ApcContext,
PIO_STATUS_BLOCK IoStatusBlock,
PVOID FileInformation,
ULONG Length,
FILE_INFORMATION_CLASS FileInformationClass,
BOOLEAN ReturnSingleEntry,
PUNICODE_STRING FileName,
BOOLEAN RestartScan
);
结构体
typedef struct _FILE_BOTH_DIR_INFORMATION {
ULONG NextEntryOffset;//指向下一个结构体
ULONG FileIndex;
LARGE_INTEGER CreationTime;
LARGE_INTEGER LastAccessTime;
LARGE_INTEGER LastWriteTime;
LARGE_INTEGER ChangeTime;
LARGE_INTEGER EndOfFile;
LARGE_INTEGER AllocationSize;
ULONG FileAttributes;
ULONG FileNameLength;
ULONG EaSize;
CCHAR ShortNameLength;
WCHAR ShortName[12];
WCHAR FileName[1];
} FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION;
4.习题答案
1.这个程序创建文件了吗?它创建了什么文件?
C:\Windows\System32\Mlwx486.sys
2.这个程序有内核组件吗?
有。从资源文件中提取。
3.这个程序做了些什么?
通过修改SSDT的NtQueryDirectoryFile为FakeNtQueryDirectoryFIle,来隐藏文件。
五、Lab10-3
注意:需要将驱动程序放在C:\Windows\System32目录下。
1.Lab10-3.exe分析
- 先安装了一个服务名为:Process Helper。路径为C:\Windows\System32\Lab10-03.sys
- 使用COM组件,每30s 浏览器打开一次http://www.malwareanalysisbook.com/ad.html网页
rclsid注册表目录HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID
riid注册表目录**HKEY_CLASSES_ROOT\Interface**
2.Lab10-03.sys分析
- 创建设备驱动ProcHelper
- 设置驱动的MajorFunction。MajorFunction不同偏移代表IRP_MJ_CREATE、IRP_MJ_CLOSE和IRP_MJ_DEVICE_CONTROL。
- 将驱动ProcHelper与符号\DosDevices\ProcHelper链接
3.动态调试
动态调试主要是分析IRP_MJ_DEVICE_CONTROL对应的函数
在虚拟机中对DeviceIoControl下断点,启动之后在主机上用windbg连接虚拟机进行内核调试。
在!devobj ProcHelper搜索驱动对象,dt nt!_DRIVER_OBJECT 81a8ab00查看对象,dd 81a8ab00+0x38 L1c查看MajorFunction数组
这是第二次调试,所以地址和前面的不一样。可以看sub_10666函数主要作用就是先获取当前调用的进程的_EPROCESS并将的_LIST_ENTRY摘除
用到的数据结构和函数
STDAPI CoCreateInstance(
REFCLSID rclsid, //创建的Com对象的类标识符(CLSID)
LPUNKNOWN pUnkOuter, //指向接口IUnknown的指针
DWORD dwClsContext, //运行可执行代码的上下文
REFIID riid, //创建的Com对象的接口标识符
LPVOID * ppv //用来接收指向Com对象接口地址的指针变量
);
MajorFunction不同偏移代表的含义
#define IRP_MJ_CREATE 0x00
#define IRP_MJ_CREATE_NAMED_PIPE 0x01
#define IRP_MJ_CLOSE 0x02
#define IRP_MJ_READ 0x03
#define IRP_MJ_WRITE 0x04
#define IRP_MJ_QUERY_INFORMATION 0x05
#define IRP_MJ_SET_INFORMATION 0x06
#define IRP_MJ_QUERY_EA 0x07
#define IRP_MJ_SET_EA 0x08
#define IRP_MJ_FLUSH_BUFFERS 0x09
#define IRP_MJ_QUERY_VOLUME_INFORMATION 0x0a
#define IRP_MJ_SET_VOLUME_INFORMATION 0x0b
#define IRP_MJ_DIRECTORY_CONTROL 0x0c
#define IRP_MJ_FILE_SYSTEM_CONTROL 0x0d
#define IRP_MJ_DEVICE_CONTROL 0x0e
#define IRP_MJ_INTERNAL_DEVICE_CONTROL 0x0f
#define IRP_MJ_SHUTDOWN 0x10
#define IRP_MJ_LOCK_CONTROL 0x11
#define IRP_MJ_CLEANUP 0x12
#define IRP_MJ_CREATE_MAILSLOT 0x13
#define IRP_MJ_QUERY_SECURITY 0x14
#define IRP_MJ_SET_SECURITY 0x15
#define IRP_MJ_POWER 0x16
#define IRP_MJ_SYSTEM_CONTROL 0x17
#define IRP_MJ_DEVICE_CHANGE 0x18
#define IRP_MJ_QUERY_QUOTA 0x19
#define IRP_MJ_SET_QUOTA 0x1a
#define IRP_MJ_PNP 0x1b
#define IRP_MJ_PNP_POWER IRP_MJ_PNP // Obsolete....
#define IRP_MJ_MAXIMUM_FUNCTION 0x1b
创建驱动对象
NTSTATUS IoCreateDevice(
PDRIVER_OBJECT DriverObject,
ULONG DeviceExtensionSize,
PUNICODE_STRING DeviceName,
DEVICE_TYPE DeviceType,
ULONG DeviceCharacteristics,
BOOLEAN Exclusive,
PDEVICE_OBJECT *DeviceObject
);
为驱动创建符号名
NTSTATUS IoCreateSymbolicLink(
PUNICODE_STRING SymbolicLinkName,
PUNICODE_STRING DeviceName
);
返回当前的进程
PEPROCESS IoGetCurrentProcess();
4.习题答案
1.这个程序做了些什么?
加载驱动,每30秒弹出一次广告。驱动从系统_EPROCESS中摘除进程
2.一旦程序运行,怎么停止?
重启系统
3.它的内核组件做了什么操作?
从_EPROCESS->_LIST_ENTRY中摘除DeviceToControl请求进程的_LIST_ENTRY
六、总结
到这里为止《恶意代码代码分析实战》主要讲解了分析工具的使用、静态分析、动态分析、系统环境变化的抓取以及内核调试的方法。接下去才是重头戏,不同病毒的功能实现及分析。
双机内核调试入门 https://bbs.pediy.com/thread-261326.htm
Windows XP sp3 系统安装 Windbg 符号文件 Symbols 时微软失去支持的解决方案 https://www.cnblogs.com/csnd/p/11800535.html