標 題: 【原創】初步實現系統級攔截應用程序取硬盤物理序列號
作 者: 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