原贴:
【原创】关于拦截“通过WMI读取硬件序列号”的一些心得
http://bbs.pediy.com/showthread.php?t=127176
本人做了一个WMIDataDevice过滤驱动, 然而似乎并不会拦截到ExecQuery(L"SQL"..)查询硬件序列号??
根据如上,做了一个过淲驱动, 部分代码如下:
// 找过滤目标驱动
UNICODE_STRING FilterToDriverName;
RtlInitUnicodeString(&FilterToDriverName, L"\\Device\\WMIDataDevice");
PFILE_OBJECT FilterToFileObject;
PDEVICE_OBJECT FilterToDevice;
status = IoGetDeviceObjectPointer(&FilterToDriverName, FILE_ALL_ACCESS, &FilterToFileObject, &FilterToDevice);
if (!NT_SUCCESS(status))
{
DbgPrint("IoGetDeviceObjectPointer ERR: %wZ, %p", FilterToDriverName, status);
return 0-__LINE__;
}
ObDereferenceObject(FilterToFileObject);
//....
// 一系列初始化
for (int i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
DriverObject->MajorFunction[i] = DriverWMIFilterDefaultHandler;
//....
NTSTATUS DriverWMIFilterDefaultHandler(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
FilterDriverExtension* fltEx = (FilterDriverExtension*)DeviceObject->DeviceExtension;
KdPrint(("DriverWMIFilterDefaultHandler: %p %lx, %d", fltEx, Irp->CurrentLocation, fltEx->IrpPenddingCount));
if (!fltEx || !fltEx->NextDevice)
return 0-__LINE__;
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(fltEx->NextDevice, Irp);
}
当直接createfile 时,能够成拦截:
HANDLE hDev = CreateFile(L"\\\\.\\WMIDataDevice",
GENERIC_READ | GENERIC_WRITE,
0, // share mode none
NULL, // no security
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL ); // no template
TRACERlsn(L"hDev: %p\r\n", hDev);
BYTE rd[10];
ULONG rdsize =0;
OVERLAPPED vp;
BOOL bRd = ReadFile(hDev, rd, 10, &rdsize, &vp);
TRACERlsn(L"ReadFile: %d, %d\r\n", bRd, rdsize);
CloseHandle(hDev);
而当使用wmi获取硬件序列号时, 并不能成功拦截. 部分代码如下:
// WQL查询语句
const T_WQL_QUERY szWQLQuery[] = {
// 网卡原生MAC地址
"SELECT * FROM Win32_NetworkAdapter WHERE (MACAddress IS NOT NULL) AND (NOT (PNPDeviceID LIKE 'ROOT%'))",
L"PNPDeviceID",
// 硬盘序列号
"SELECT * FROM Win32_DiskDrive WHERE (SerialNumber IS NOT NULL) AND (MediaType LIKE 'Fixed hard disk%')",
L"SerialNumber",
// 主板序列号
"SELECT * FROM Win32_BaseBoard WHERE (SerialNumber IS NOT NULL)",
L"SerialNumber",
// 处理器ID
"SELECT * FROM Win32_Processor WHERE (ProcessorId IS NOT NULL)",
L"ProcessorId",
// BIOS序列号
"SELECT * FROM Win32_BIOS WHERE (SerialNumber IS NOT NULL)",
L"SerialNumber",
// 主板型号
"SELECT * FROM Win32_BaseBoard WHERE (Product IS NOT NULL)",
L"Product",
// 网卡当前MAC地址
"SELECT * FROM Win32_NetworkAdapter WHERE (MACAddress IS NOT NULL) AND (NOT (PNPDeviceID LIKE 'ROOT%'))",
L"MACAddress",
};
// 基于Windows Management Instrumentation(Windows管理规范)
INT WMI_DeviceQuery( INT iQueryType, T_DEVICE_PROPERTY *properties, INT iSize )
{
HRESULT hres;
INT iTotal = 0;
// 判断查询类型是否支持
if( (iQueryType < 0) || (iQueryType >= sizeof(szWQLQuery)/sizeof(T_WQL_QUERY)) )
{
return -1; // 查询类型不支持
}
// 初始化COM
hres = CoInitializeEx( NULL, COINIT_MULTITHREADED );
if( FAILED(hres) )
{
return -2;
}
// 设置COM的安全认证级别
hres = CoInitializeSecurity(
NULL,
-1,
NULL,
NULL,
RPC_C_AUTHN_LEVEL_DEFAULT,
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL,
EOAC_NONE,
NULL
);
if( FAILED(hres) )
{
CoUninitialize();
return -2;
}
// 获得WMI连接COM接口
IWbemLocator *pLoc = NULL;
hres = CoCreateInstance(
CLSID_WbemLocator,
NULL,
CLSCTX_INPROC_SERVER,
IID_IWbemLocator,
reinterpret_cast<LPVOID*>(&pLoc)
);
if( FAILED(hres) )
{
CoUninitialize();
return -2;
}
// 通过连接接口连接WMI的内核对象名"ROOT//CIMV2"
IWbemServices *pSvc = NULL;
hres = pLoc->ConnectServer(
_bstr_t( L"ROOT\\CIMV2" ),
NULL,
NULL,
NULL,
0,
NULL,
NULL,
&pSvc
);
if( FAILED(hres) )
{
pLoc->Release();
CoUninitialize();
return -2;
}
// 设置请求代理的安全级别
hres = CoSetProxyBlanket(
pSvc,
RPC_C_AUTHN_WINNT,
RPC_C_AUTHZ_NONE,
NULL,
RPC_C_AUTHN_LEVEL_CALL,
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL,
EOAC_NONE
);
if( FAILED(hres) )
{
pSvc->Release();
pLoc->Release();
CoUninitialize();
return -2;
}
// 通过请求代理来向WMI发送请求
IEnumWbemClassObject *pEnumerator = NULL;
hres = pSvc->ExecQuery(
bstr_t("WQL"),
bstr_t( szWQLQuery[iQueryType].szSelect ),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pEnumerator
);
if( FAILED(hres) )
{
pSvc->Release();
pLoc->Release();
CoUninitialize();
return -3;
}
// 循环枚举所有的结果对象
while( pEnumerator )
{
IWbemClassObject *pclsObj = NULL;
ULONG uReturn = 0;
if( (properties != NULL) && (iTotal >= iSize) )
{
break;
}
pEnumerator->Next(
WBEM_INFINITE,
1,
&pclsObj,
&uReturn
);
if( uReturn == 0 )
{
break;
}
if( properties != NULL )
{ // 获取属性值
VARIANT vtProperty;
VariantInit( &vtProperty );
pclsObj->Get( szWQLQuery[iQueryType].szProperty, 0, &vtProperty, NULL, NULL );
StringCchCopy( properties[iTotal].szProperty, PROPERTY_MAX_LEN, W2T(vtProperty.bstrVal) );
VariantClear( &vtProperty );
// 对属性值做进一步的处理
if( WMI_DoWithProperty( iQueryType, properties[iTotal].szProperty, PROPERTY_MAX_LEN ) )
{
iTotal++;
}
}
else
{
iTotal++;
}
pclsObj->Release();
} // End While
// 释放资源
pEnumerator->Release();
pSvc->Release();
pLoc->Release();
CoUninitialize();
return iTotal;
}
请教:这是因为WIN7不适用,
还是WMIDataDevice这个驱动名称不对,
还是上面的获取序列号的方法不是WMI,不能用这种拦截方法??
谢谢
//===========================================================
谢谢下面的各位,
现在用的是NtAlpcSendWaitReceivePort;
呵呵,为了方便其它有同样问题的朋友,NtAlpcSendWaitReceivePort相关说明如下:
高手略过,错误指正. 有资料的来点。
typedef struct _PORT_MESSAGE // LPC(/ALPC)接受或发送的消息的信息头结构,其数据紧随其后(数据最大长度0x130??)
{
#define LPC_REQUEST 1 // Type
#define LPC_REPLY 2
#define LPC_DATAGRAM 3
#define LPC_LOST_REPLY 4
#define LPC_PORT_CLOSED 5
#define LPC_CLIENT_DIED 6
#define LPC_EXCEPTION 7
#define LPC_DEBUG_EVENT 8
#define LPC_ERROR_EVENT 9
#define LPC_CONNECTION_REQUEST 10
union
{
struct
{
CSHORT DataLength; // 尾随于结构之后的数据长度
CSHORT TotalLength; // 总长度 == (DataLength + TotalLength)
} s1;
ULONG Length;
} u1;
union
{
struct
{
CSHORT Type;
CSHORT DataInfoOffset;
} s2;
ULONG ZeroInit;
} u2;
union
{
CLIENT_ID ClientId;
double DoNotUseThisField; // Force quadword alignment
};
ULONG MessageId; // Identifier of the particular message instance
union
{
SIZE_T ClientViewSize; // only valid for LPC_CONNECTION_REQUEST messages
ULONG CallbackId; // only valid for LPC_REQUEST messages
};
} PORT_MESSAGE, *PPORT_MESSAGE;
typedef struct _ALPC_MESSAGE_ATTRIBUTES // 此结构后面还有跟有数据
{
ULONG AllocatedAttributes;
ULONG ValidAttributes;
} ALPC_MESSAGE_ATTRIBUTES, *PALPC_MESSAGE_ATTRIBUTES;
typedef NTSTATUS (_stdcall *_NtAlpcSendWaitReceivePort)(
IN HANDLE PortHandle,
IN ULONG Flags,
IN PPORT_MESSAGE SendMessage,
IN OUT OPTIONAL PALPC_MESSAGE_ATTRIBUTES SendMessageAttributes,
OUT PPORT_MESSAGE ReceiveMessage,
IN OUT OPTIONAL PSIZE_T BufferLength, // 此处大小 == ReceiveMessage->u1.TotalLength;
IN OUT OPTIONAL PALPC_MESSAGE_ATTRIBUTES ReceiveMessageAttributes,
IN OPTIONAL PLARGE_INTEGER Timeout
);
// 我用的是win7系统,
// 当数据很大时,比如0x2000, 数据本身是mapview进来的。
// NtAlpcSendWaitReceivePort资数很少,为了找到map指针,逆向了下
// 没有完全,勉强能找到map指针
if (ReceiveMessage &&
ReceiveMessage->u2.s2.Type & 2 &&
ReceiveMessage->u1.s1.TotalLength >= 0x48 &&
*(PULONG)(PUCHAR(ReceiveMessage) +0x28) == 0x3 &&
((*(PUCHAR)(PUCHAR(ReceiveMessage) +0x30)) & 4) && // +34是一种计数
ReceiveMessageAttributes
) // 此时,数据是map进来的
{
KdPrint((__FUNCTION__ "[%p] haven map region 1, %lx",
PsGetCurrentProcessId(), ReceiveMessageAttributes->AllocatedAttributes));
// 32位与64位获得map指针有区别
// 不知道内核是如何知道调用它的是32位或是64位, 难道是从PortHandle获得的?
// 有知道的朋友告知下
static ULONG AttAllocatedOffset64[] = {0x08, 0, 0x28, 0, 0x28, 0, 0x48, 0, 0x20, 0, 0x40, 0, 0x40, 0, 0x60};
static ULONG AttAllocatedOffset32[] = {0x08, 0, 0x1c, 0, 0x18, 0, 0x2c, 0, 0x14, 0, 0x28, 0, 0x24, 0, 0x38};
ULONG offIdx = ((ReceiveMessageAttributes->AllocatedAttributes >>0x1c) & 8);
if (offIdx < _countof(AttAllocatedOffset64))
{
struct AllocatedInfo64 // 位于ReceiveMessageAttributes +AttAllocatedOffset64[offIdx]
{
ULONG_PTR someSign; // 有位检测bt someSign,0x12
ULONG_PTR notSure;
LPVOID memPtr; // 此处即map指针
ULONG_PTR memLen;
};
struct AllocatedInfo32 // 位于ReceiveMessageAttributes +AttAllocatedOffset32[offIdx]
{
ULONG someSign; // 有位检测bt someSign,0x12
ULONG notSure;
ULONG memPtr; // 此处即map指针
ULONG memLen;
};
AllocatedInfo64* alcInfo = (AllocatedInfo64*)((PUCHAR)ReceiveMessageAttributes +AttAllocatedOffset64[offIdx]);
LPVOID memPtr = alcInfo->memPtr;
ULONG_PTR memLeaveLen = *(ULONG_PTR*)(PUCHAR(ReceiveMessage) +0x40);
ULONG_PTR memLen = alcInfo->memLen;
// 好吧,如果map指针大于0x7fffffff为32位
if (memPtr > (LPVOID)0x7fffffff || memLen < memLeaveLen)
{
AllocatedInfo32* alcInfo = (AllocatedInfo32*)((PUCHAR)ReceiveMessageAttributes +AttAllocatedOffset32[offIdx]);
memPtr = (LPVOID)alcInfo->memPtr;
memLen = alcInfo->memLen;
}
KdPrint(("haven map region 2: %lx, %llx, %llx, %llx, - %llx, \r\n",
offIdx, alcInfo->notSure, memPtr, memLen, memLeaveLen
));
}
}
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)