标 题: 【原创】初步实现系统级拦截应用程序取硬盘物理序列号
作 者: rockhard
时 间: 2006-11-29,12:09
链 接: http://bbs.pediy.com/showthread.php?t=35626
【文章标题】: 初步实现系统级拦截应用程序取硬盘物理序列号
【文章作者】: rockhard
【作者邮箱】: wnh1@sohu.com
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
以前想模拟某个程序取硬盘系列号,就将一个DLL注入进去,拦截DeviceIoControl的返回值,将其修改为目标硬盘的值。
后来看到REGMON 从SSDT着手拦截注册表操作,可以看到任何程序的读写操作,就仿着改了一下程序。经测试可以欺骗相当
一部分程序读硬盘序列号,包括ASPROTECT及用其加密算法的子孙:)。
我的思路是这样的:
1、首先用程序取自己的真正的硬盘序列号,假设为XXXX
2、拦截系统的ZwDeviceIoControlFile,并判断入口参数中的IoControlCode ,只有某几个特定的值用来取序列号的,
目前在所有的程序中取硬盘序列号的,我只发现两个值,一个是0x7c088,另外一个是什么忘了。
如果IoControlCode为上面的值,读取系统原有的ZwDeviceIoControlFile返回BUFFER,并用串匹配方法查找这个返回值中存在
不存在XXXX,如果存在,替换为你要欺骗的值.
代码很简单:
UCHAR __DiskSerial[DISK_SERIAL_BUFF_LENGTH]={0};
UCHAR __ChangeTo [DISK_SERIAL_BUFF_LENGTH]={0};
//一个简单的低率串匹配算法 ,判断一个串S1是不是另外一个串S2的子串
PUCHAR IsSubString(PUCHAR String, PUCHAR SubString ,ULONG StringLength ,ULONG SubStringLength)
{
ULONG i,j;
for(i=0;i<StringLength - SubStringLength +1 ;i++){
for(j=0;j<SubStringLength;j++){
if(String[i+j]!=SubString[j])
break;
}
if(j==SubStringLength) //match a substring
return String+i;
}
return NULL;
}
//----------------------------------------------------------------------
//
// Our own routine for ZwDeviceIocontrolFile
// We change the hard disk serial number value requested by user
//
//----------------------------------------------------------------------
NTSTATUS HookZwDeviceIoControlFile(
IN HANDLE FileHandle,
IN HANDLE Event OPTIONAL,
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
IN PVOID ApcContext OPTIONAL,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN ULONG IoControlCode,
IN PVOID InputBuffer OPTIONAL,
IN ULONG InputBufferLength,
OUT PVOID OutputBuffer OPTIONAL,
IN ULONG OutputBufferLength
)
{
NTSTATUS rc;
rc = RealZwDeviceIoControlFile (
FileHandle,
Event,
ApcRoutine,
ApcContext,
IoStatusBlock,
IoControlCode,
InputBuffer,
InputBufferLength,
OutputBuffer,
OutputBufferLength
);
//判断IoControlcode是不是取序列号的值
if((0x7c088 ==IoControlCode) && OutputBufferLength >DISK_SERIAL_BUFF_LENGTH){
//判断返回值中是否包含当前的硬盘序列号,是的话用假的替换
PUCHAR Locate = IsSubString(OutputBuffer,__DiskSerial,OutputBufferLength,DISK_SERIAL_BUFF_LENGTH);
if(Locate){
UCHAR i;
for(i=0;i<20;i++){
Locate[i]= __ChangeTo[i];
}
}
}
return(rc);
}
目前,驱动只处理了简单的几个应用层的消息,包括停止欺骗,开始欺骗,设置新的欺骗值。
BOOLEAN HDHookDeviceControl( IN PFILE_OBJECT FileObject, IN BOOLEAN Wait,
IN PVOID InputBuffer, IN ULONG InputBufferLength,
OUT PVOID OutputBuffer, IN ULONG OutputBufferLength,
IN ULONG IoControlCode, OUT PIO_STATUS_BLOCK IoStatus,
IN PDEVICE_OBJECT DeviceObject ) {
BOOLEAN retval = FALSE;
ULONG i;
// Its a message from our GUI!
IoStatus->Status = STATUS_SUCCESS; // Assume success
IoStatus->Information = 0; // Assume nothing returned
switch ( IoControlCode ) {
// 开始欺骗
case HDHOOK_HOOK:
HookStart();
break;
// 停止欺骗
case HDHOOK_UNHOOK:
HookStop();
break;
// 告诉驱动当前自己硬盘的序列号值为多少
case HDHOOK_SETSELFVALUE:
if( InputBufferLength < DISK_SERIAL_BUFF_LENGTH || InputBuffer == NULL){
IoStatus->Status = STATUS_INVALID_PARAMETER;
break;
}
for(i=0; i< DISK_SERIAL_BUFF_LENGTH ;i++)
__DiskSerial[i] = ((UCHAR *)InputBuffer)[i];
break;
// 设置新的欺骗的硬盘序列号
case HDHOOK_SETEMULABLEVALUE:
if( InputBufferLength < DISK_SERIAL_BUFF_LENGTH || InputBuffer == NULL){
IoStatus->Status = STATUS_INVALID_PARAMETER;
break;
}
for(i=0;i< DISK_SERIAL_BUFF_LENGTH ;i++)
__ChangeTo[i] = ((UCHAR *)InputBuffer)[i];
break;
//返回驱动的版本号
case HDHOOK_VERSION:
if ( OutputBufferLength < sizeof(ULONG) ||
OutputBuffer == NULL ) {
IoStatus->Status = STATUS_INVALID_PARAMETER;
break;
}
*(ULONG *)OutputBuffer = REGMONVERSION;
IoStatus->Information = sizeof(ULONG);
break;
default:
IoStatus->Status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
return TRUE;
}
////////////////////////////////////////////////
应用层程序可以通过如下简单代码与驱动进行通信:
#define HDHOOK_HOOK (ULONG) CTL_CODE( FILE_DEVICE_REGMON, 0x00, METHOD_BUFFERED, FILE_ANY_ACCESS )
#define HDHOOK_UNHOOK (ULONG) CTL_CODE( FILE_DEVICE_REGMON, 0x01, METHOD_BUFFERED, FILE_ANY_ACCESS )
#define HDHOOK_VERSION (ULONG) CTL_CODE( FILE_DEVICE_REGMON, 0x02, METHOD_BUFFERED, FILE_ANY_ACCESS )
#define HDHOOK_SETSELFVALUE (ULONG) CTL_CODE( FILE_DEVICE_REGMON, 0x03, METHOD_BUFFERED, FILE_ANY_ACCESS )
#define HDHOOK_SETEMULABLEVALUE (ULONG) CTL_CODE( FILE_DEVICE_REGMON, 0x04, METHOD_BUFFERED, FILE_ANY_ACCESS )
#define DISK_SERIAL_BUFF_LENGTH 20
//设置新的序列号模拟值
DeviceIoControl(__SysHandle,HDHOOK_SETEMULABLEVALUE,szEmulSerial,DISK_SERIAL_BUFF_LENGTH, NULL, 0, &dwDummy, NULL) ;
//告诉驱动自己的硬盘序列号
DeviceIoControl(__SysHandle,HDHOOK_SETSELFVALUE,szBuffer,DISK_SERIAL_BUFF_LENGTH, NULL, 0, &dwDummy, NULL) ;
//开始拦截
DeviceIoControl(__SysHandle,HDHOOK_HOOK,NULL,0,NULL,0,&dwDummy,NULL) ;
//停止拦截
DeviceIoControl(__SysHandle,HDHOOK_UNHOOK,NULL,0,NULL,0,&dwDummy,NULL) ;
其中__SysHandle是安装驱动的句柄
这篇文章的思路来自regmon(regmon版权申明我保留在文件中),写出来是方便调试那些有正版注册号且以硬盘序列号生成注册码的程序,方便一下大家。
附件中包含我写的一个简单的UI,用来与驱动通信。
如果你觉得有用,希望有人能完成如下功能:
1、进程过滤功能,只对特定程序拦截。
2、考虑将上面的那个串匹配算法改得高效些,数据结构教材上有现成的:)
3、那个返回值中有硬盘厂家,磁道数等信息,完成完全模拟,还有IoControlCode 的完善。
若改好了希望能传一份给我 :)
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
2006年11月29日 12:03:24