首页 »
安全 » linux内核函数:内核级利用通用Hook函数思路方法检测进程
Rss订阅
linux内核函数:内核级利用通用Hook函数思路方法检测进程
介绍通用Hook
点思想:
在系统内核级中
MS
很多信息都没公开
包括
参数数目
每个参数
类型等
在系统内核中
访问了大量
寄存器
而很多寄存器
值
是上层
者提供
如果值改变系统就会变得不稳定
很可能出现不可想象
后果
另外有时候对需要Hook
参数不了解
所以不能随便就去改变它
堆栈
如果不小心也有可能导致蓝屏
所以Hook
最佳原则是在自己
Hook
中呼叫原
时候
所有
寄存器值
堆栈里面
值和Hook前
信息
样
这样就能保证在原
中不会出错
般我们自己
Hook
都是写在C文件里面
例如Hook
目标
KiReadyThread
那么
般就自己实现
个:
MyKiReadyThread(...)
{
......
call KiReadyThread
......
}
但是用C编译器编译出来代码会出现个堆栈帧:
Push ebp
mov ebp,esp
这就和我们初衷不改变寄存器数违背了所以我们可以自己用汇编来实现MyKiReadyThread
_func@0 proc
pushad ;保存通用寄存器
call _cfunc@0 ;这里是在进入原来前进行些处理
popad ;恢复通用寄存器
push eax
mov eax,[esp+4] ;得到系统在call 目标时入栈返回地址
mov ds:_OrgRet,eax ;保存在个临时变量中
pop eax
mov [esp],retaddr ;把目标返回地址改成自己代码空间返回地址使其返回
后能接手继续处理
jmp _OrgDestFunction ;跳到原目标中
retaddr:
pushad ;原处理完后保存寄存器
call _HookDestFunction@0 ;再处理
popad ;回复寄存器
jmp ds:_OrgRet ;跳到系统目标下条指令
_func@0 endp
当我们要拦截目标API时候只要修改原头5个字节机器为个JMP_func就行了然后把原来5字节保存在跳入原时恢复那5个字节即可
Hook KiReadyThread检测系统中进程:
在线程调度抢占时候会KiReadyThread它原型为VOID FASTCALL KiReadyThread (IN PRKTHREAD Thread)在进入KiReadyThread时ecx指向Thread所以完全可以Hook KiReadyThread 然后用ecx值得到但前线程进程信息KiReadyThread没被ntosknrl.exe导出所以通过硬编码来在2000Sp4中地址为0x8043141f
具体实现:
////////////////////////////////
// 1.cpp
////////////////////////////////
#def __cplusplus
extern "C" {
#end
# "ntddk.h"
# ".h"
# "nts.h"
# "stdio.h"
# FILE_DEVICE_EVENT 0x8000
# IOCTL_PASSBUF \
CTL_CODE(FILE_DEVICE_EVENT, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS)
void DriverUnload (IN PDRIVER_OBJECT pDriverObject);
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath);
void cfunc ;
void HookDestFunction;
NTSTATUS DeviceIoControlDispatch(IN PDEVICE_OBJECT DeviceObject,
IN PIRP pIrp);
extern void func;
void ResumeDestFunction;
const WCHAR devLink = L"\\??\\MyEvent";
const WCHAR devName = L"\\Device\\MyEvent";
UNICODE_STRING devNameUnicd;
UNICODE_STRING devLinkUnicd;
ULONG OrgDestFunction = (ULONG)0x8043141f; //KiReadyThread
char JmpMyCode = {0xE9,0x00,0x00,0x00,0x00};
char OrgCode [5];
char OutBuf[128][16];
Count = 0;
ULONG orgcr0;
#def __cplusplus
}
#end
VOID DisableWriteProtect( PULONG pOldAttr)
{
ULONG uAttr;
_asm
{
push eax;
mov eax, cr0;
mov uAttr, eax;
and eax, 0FFFEFFFFh; // CR0 16 BIT = 0
mov cr0, eax;
pop eax;
};
*pOldAttr = uAttr; //保存原有 CRO 属性
}
VOID EnableWriteProtect( ULONG uOldAttr )
{
_asm
{
push eax;
mov eax, uOldAttr; //恢复原有 CR0 属性
mov cr0, eax;
pop eax;
};
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING RegistryPath)
{
NTSTATUS Status;
PDEVICE_OBJECT pDevice;
DbgPr("DriverEntry called!\n");
RtlInitUnicodeString (&devNameUnicd, devName );
RtlInitUnicodeString (&devLinkUnicd, devLink );
Status = IoCreateDevice ( pDriverObject,
0,
&devNameUnicd,
FILE_DEVICE_UNKNOWN,
0,
TRUE,
&pDevice );
( !NT_SUCCESS(Status))
{
DbgPr(("Can not create device.\n"));
Status;
}
Status = IoCreateSymbolicLink (&devLinkUnicd, &devNameUnicd);
( !NT_SUCCESS(Status))
{
DbgPr(("Cannot create link.\n"));
Status;
}
pDriverObject->DriverUnload = DriverUnload;
pDriverObject->MajorFunction[IRP_MJ_CREATE] =
pDriverObject->MajorFunction[IRP_MJ_CLOSE] =
pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DeviceIoControlDispatch;
pDriverObject->DriverUnload = DriverUnload;
* ( (ULONG*) (JmpMyCode+1) ) = (ULONG)func - (ULONG)OrgDestFunction - 5;
memcpy(OrgCode,(char*)OrgDestFunction,5);
HookDestFunction;
STATUS_SUCCESS;
}
void DriverUnload (IN PDRIVER_OBJECT pDriverObject)
{
NTSTATUS status;
ResumeDestFunction;
(pDriverObject->DeviceObject != NULL)
{
status=IoDeleteSymbolicLink( &devLinkUnicd );
( !NT_SUCCESS( status ) )
{
DbgPr(( "IoDeleteSymbolicLink failed\n" ));
}
IoDeleteDevice( pDriverObject->DeviceObject );
}
}
void DisplayName(PKTHREAD Thread)
{
PKPROCESS Process = Thread->ApcState.Process;
PEPROCESS pEprocess = (PEPROCESS)Process;
DbgPr("ImageFileName = %s \n",pEprocess->ImageFileName);
sprf(OutBuf[Count],"%s",pEprocess->ImageFileName);
}
void cfunc (void)
{
ULONG PKHeader=0;
__asm
{
mov PKHeader,ecx //ecx寄存器是KiReadyThread中PRKTHREAD参数
}
ResumeDestFunction;
( PKHeader != 0 && Count < 128 )
{
DisplayName((PKTHREAD)PKHeader);
}
}
void HookDestFunction
{
DisableWriteProtect(&orgcr0);
memcpy((char*)OrgDestFunction,JmpMyCode,5);
EnableWriteProtect(orgcr0);
}
void ResumeDestFunction
{
DisableWriteProtect(&orgcr0);
memcpy((char*)OrgDestFunction,OrgCode,5);
EnableWriteProtect(orgcr0);
}
NTSTATUS DeviceIoControlDispatch(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP pIrp
)
{
PIO_STACK_LOCATION irpStack;
NTSTATUS status;
PVOID inputBuffer;
ULONG inputLength;
PVOID outputBuffer;
ULONG outputLength;
OBJECT_HANDLE_INFORMATION objHandleInfo;
status = STATUS_SUCCESS;
// 取出IOCTL请求代码
irpStack = IoGetCurrentIrpStackLocation(pIrp);
switch (irpStack->MajorFunction)
{
IRP_MJ_CREATE :
DbgPr("Call IRP_MJ_CREATE\n");
;
IRP_MJ_CLOSE:
DbgPr("Call IRP_MJ_CLOSE\n");
;
IRP_MJ_DEVICE_CONTROL:
DbgPr("IRP_MJ_DEVICE_CONTROL\n");
inputLength=irpStack->Parameters.DeviceIoControl.InputBufferLength;
outputLength=irpStack->Parameters.DeviceIoControl.OutputBufferLength;
switch (irpStack->Parameters.DeviceIoControl.IoControlCode)
{
IOCTL_PASSBUF:
{
RtlCopyMemory(pIrp->UserBuffer, OutBuf, 20*16);
mem(OutBuf,0,128*16);
Count = 0;
;
}
default:
;
}
default:
DbgPr("Call IRP_MJ_UNKNOWN\n");
;
}
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = 0;
IoCompleteRequest (pIrp, IO_NO_INCREMENT);
status;
}
////////////////////////////////
// 1.asm
////////////////////////////////
.386
.model small
.data
_OrgRet dd 0
.code
public _func@0
extrn _cfunc@0:near
extrn _HookDestFunction@0:near
extrn _OrgDestFunction:DWORD
_func@0 proc
pushad
call _cfunc@0
popad
push eax
mov eax,[esp+4]
mov ds:_OrgRet,eax
pop eax
mov [esp],retaddr
jmp _OrgDestFunction
retaddr:
pushad
call _HookDestFunction@0
popad
jmp ds:_OrgRet
_func@0 endp
END
//////////////////////////////////////////
// app.cpp
//////////////////////////////////////////
# <windows.h>
# <stdio.h>
# FILE_DEVICE_EVENT 0x8000
# CTL_CODE( DeviceType, Function, Method, Access ) ( \
((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
)
# FILE_ANY_ACCESS 0
# METHOD_BUFFERED 0
# FILE_DEVICE_UNKNOWN 0x00000022
# IOCTL_PASSBUF \
CTL_CODE(FILE_DEVICE_EVENT, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS)
{
HANDLE hDevice;
bool status;
ULONG dwReturn;
char outbuf[129][16];
hDevice = NULL;
m_hCommEvent = NULL;
hDevice = CreateFile( "\\\\.\\MyEvent",
GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
(hDevice INVALID_HANDLE_VALUE)
{
prf("createfile wrong\n");
getchar;
0;
}
while(1)
{
mem(outbuf,0,129*16);
status =DeviceIoControl(hDevice,
IOCTL_PASSBUF,
NULL,
0,
&outbuf,
128*16,
&dwReturn,NULL);
( !status)
{
prf("IO wrong+%d\n", GetLastError);
getchar;
0;
}
c=0;
while( *((char*)(&outbuf)+c*16) )
{
//把csrss.exe和自身进程信息跳过会产生有大量信息
( strcmp((char*)(&outbuf)+c*16,"app.exe") && \
strcmp((char*)(&outbuf)+c*16,"csrss.exe") )
prf("%s\n",(char*)(&outbuf)+c*16);
c;
}
Sleep(1);
}
}
试验结果:
......
TTPlayer.exe
TTPlayer.exe
vrvmon.exe
TTPlayer.exe
Explorer.EXE
Explorer.EXE
Explorer.EXE
......
测试、编译环境Windows2000 Sp4、Windows2000 DDK没写出线程隐藏进程代码不过基本上实现得差不多了只需要把返回信息和Ring3级查询得到信息进行适时对比就能查出异常进程了
上篇文章: 种新穿透防火墙数据传输技术
下篇文章: 邮件蠕虫和垃圾邮件技术融合
延伸阅读
最新评论