系统:虚拟机Windows 7 32bit
工具:VS2015+Windbg等各种调试工具
此demo只是内核编程的小小练习,只是遍历了驱动模块全路径,通过Ring3和Ring0通讯(使用比较复杂的控制码+MDL直接方式通讯),显示在了用户界面上.
想要做其他功能,根据这个思路,遍历进程信息,模块信息等等都很容易做到.如果以后有机会再发其他功能的实现
1.程序启动的时候加载驱动
2.驱动加载成功则向驱动发送控制码
3.驱动接收到控制码,进行遍历,把内容拷贝到用户内存区
4.使用接收到的数据(驱动模块全路径)添加到List控件中
PS:我直接给了200个驱动模块空间.实际上应该是先跟驱动通讯一次,驱动遍历第一次获取其遍历出来的模块数量,根据这个数量Ring3层申请新的空间,然后再次跟驱动通讯,把所有的数据都拷贝过来.
Ring0,处理控制码,遍历模块并拷贝数据:
NTSTATUS ControlProc(DEVICE_OBJECT *DeviceObject, IRP *pIrp)
{
UNREFERENCED_PARAMETER(DeviceObject);
// 获取IRP栈
PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
// 获取控制码
ULONG uControlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
PDRIVER_OBJECT pDriver = DeviceObject->DriverObject;
//获得指定的读取字节数
ULONG uReadLen = pIrpStack->Parameters.Read.Length;
//获取MDL缓冲区在内核中的映射
PVOID pKernelAddr = MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority);
//_asm int 3;
int nCount = 0;
switch (uControlCode)
{
case CTL_WRITE:
break;
case CTL_READ:
if (pKernelAddr != NULL)
{
GetDriverInfo(pDriver, pKernelAddr, &nCount);
}
break;
default:
break;
}
// 设置IRP完成状态
pIrp->IoStatus.Status = STATUS_SUCCESS;
// 设置IRP操作了多少字节
pIrp->IoStatus.Information = nCount;
// 处理IRP
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
VOID GetDriverInfo(PDRIVER_OBJECT pDriver, PVOID OutBuffer,int* nCount)
{
PSTDRIVERINFO pOutBuffer = (PSTDRIVERINFO)OutBuffer;
//_asm int 3;
PLDR_DATA_TABLE_ENTRY pLdr =
(PLDR_DATA_TABLE_ENTRY)pDriver->DriverSection;
LIST_ENTRY *pTemp = &pLdr->InLoadOrderLinks;
do
{
PLDR_DATA_TABLE_ENTRY pDriverInfo =
(PLDR_DATA_TABLE_ENTRY)pTemp;
KdPrint(("%wZ\n", &pDriverInfo->FullDllName));
pTemp = pTemp->Blink;
if (pDriverInfo->FullDllName.Buffer != 0)
{
RtlCopyMemory(pOutBuffer->wcDriverFullPath, pDriverInfo->FullDllName.Buffer, wcslen(pDriverInfo->FullDllName.Buffer) * 2 + 2);
}
pOutBuffer++;
(*nCount)++;
} while (pTemp != &pLdr->InLoadOrderLinks);
}
Ring3,跟驱动通讯,发送控制码和OutBuffer地址,并把返回的数据插入到List控件
//给驱动发送控制码消息
BOOL CMFCEnumDriverDlg::SendMessageToDriver()
{
m_hDevice = CreateFile(
L"\\??\\EnumDriver",//符号链接名
GENERIC_ALL,
NULL,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (m_hDevice == INVALID_HANDLE_VALUE)
{
GetDlgItem(IDC_STATIC_TIPS)->SetWindowText(_T("Tips:打开驱动文件失败"));//设置控件文本内容
}
ULONG BuffSize = 200 * sizeof(STDRIVERINFO);
DWORD dwRealSize = 0;
DeviceIoControl(m_hDevice,
CTL_READ, //ControlNumber
NULL, //InputBuff
0, //size
m_stDriverInfo, //OutputBuff
BuffSize, //size
&dwRealSize,
NULL
);
m_ReadInfoCount = dwRealSize;
CString strResault;
strResault.Format(L"读取成功了%d个驱动", dwRealSize);
MessageBox(strResault);
return TRUE;
}
//插入信息到List
void CMFCEnumDriverDlg::InsertDriverInfo()
{
CString temp;
PSTDRIVERINFO bufTemp = m_stDriverInfo;
for (int i = 0;i < m_ReadInfoCount;i++)
{
m_DriveInfoList.InsertItem(i, bufTemp->wcDriverFullPath);
bufTemp++;
}
}
对比DebugView捕获到的内核输出: