- 注册时间
- 2011-3-6
- 最后登录
- 1970-1-1
该用户从未签到
|
Inline hook的步骤
1。获得要inline hook的函数在内存中的地址
2。实现T_MyFunc()与MyFunc函数,在该函数中将参数压栈并调用MyFunc函数处理。
3。HOOK。保存函数开头的指令到某个内存中,并在该内存末尾附加JMP指令到开头指令的后面的指令。并将开头的指令替换为JMP T_MyFunc地址。
4。在T_MyFunc执行完MyFunc之后,调用保存的指令,跳回去。
直接的jmp分3种
Short Jump(短跳转)机器码 EB rel8
只能跳转到256字节的范围内
Near Jump(近跳转)机器码 E9 rel16/32
可跳至同一个段的范围内的地址
Far Jump(远跳转)机器码EA ptr 16:16/32
可跳至任意地址,使用48位/32位全指针
例子:
_declspec(naked) T_MyFunc(……)
{
_asm
{
mov edi, edi
push ebp
mov ebp ,esp
//参数压栈,传给MyFunc
push [ebp+0ch]
push [ebp+8]
call MyFunc
//获得结果,并跳回原来的指令
cmp eax,1
jz end
mov eax,FuncAddress
add eax,5
jmp eax
end:
//恢复栈
pop ebp
retn 8
}
}
[/code]
Naked call
编译器不会给这种函数增加初始化和清理代码,不能用return返回返回值,只能用插入汇编返回结果。
//naked 调用约定。用户自己清理堆栈。不能进行原型声明,否则错误。
__declspec(naked) int add(int a,int b)
{
__asm push ebp //必须加上两句修改栈帧,否则引用了错误的数据
__asm mov ebp, esp
__asm mov eax, a
__asm add eax, b
__asm pop ebp
__asm ret
}
这个修饰是和__stdcall及cdecl结合使用的,前面是它和cdecl结合使用的代码,对于和stdcall结合的代码,则变成:
__declspec(naked) int __stdcall function(int a,int b)
{
__asm mov eax, a
__asm add eax, b
__asm ret 8 //注意后面的8
}
cdecl/fastcall/stdcall/thiscall/nakedcall
扩展阅读(重要):Calling convention: http://gccfeli.cn/tag/naked-call
[/code]
例子:SwapContext inline hook
#include <ntddk.h>
#include <ntimage.h>
#include <ntdef.h>
#include "hash.h"
#include "xde.h"
#include "main.h"
typedef struct _BYTECODE
{
BYTE *pAddress;
SIZE_T size;
} BYTECODE, *PBYTECODE;
typedef struct _OFFSETS
{
BYTE threadsProcess;
BYTE CID;
BYTE imageFilename;
BYTE crossThreadFlags;
unsigned PID;
unsigned PPID;
unsigned pecreatetimeoff;
unsigned peexittimeoff;
} OFFSETS, *POFFSETS;
#define JMP_SIZE 5
#define SIG_SIZE 20
#define HASHTABLE_SIZE 256
#define MAINTAG1 'NIAM'
// NOTICE: WinDbg gives offsets in BYTEs, we use DWORDS.
OFFSETS offsets;
// The beginning of the SwapContext function is stored here.
BYTE *pSwapContext = NULL;
// The trampoline function which executes the replaced code and
// passes control to the hooked function.
BYTECODE trampoline;
// Inline assembler does not support structures, so this points
// directly to the pCode of the _BYTECODE structure.
BYTE *pTrampoline = NULL;
// The hashtable where we store the data.
PHASHTABLE pHashTable = NULL;
DWORD num = 0;
extern USHORT *NtBuildNumber;
const WCHAR deviceLinkBuffer[] = L"\\DosDevices\\SwapContextDrv";
const WCHAR deviceNameBuffer[] = L"\\Device\\SwapContextDrv";
PDEVICE_OBJECT g_HookDevice;
ULONG gNameOffset = 0x174;
PsLookupThreadByThreadId(
IN PVOID UniqueThreadId,
OUT PETHREAD *ppEthread
);
KIRQL OldIrql;
KSPIN_LOCK DpcSpinLock;
ULONG GetLocationOfProcessName(PEPROCESS CurrentProc)
{
ULONG ul_offset;
for(ul_offset = 0; ul_offset < PAGE_SIZE; ul_offset++) // This will fail if EPROCESS
// grows bigger than PAGE_SIZE
{
if( !strncmp( "System", (PCHAR) CurrentProc + ul_offset, strlen("System")))
{
return ul_offset;
}
}
return (ULONG) 0;
}
// This function returns an MDL to an nonpaged virtual memory area.
//
// IN pVirtualAddress Virtual address to the start of the memory area.
// IN length Length of the memory area in bytes.
//
// OUT PMDL Mdl to the nonpaged virtual memory area.
//
PMDL GetMdlForNonPagedMemory(PVOID pVirtualAddress, SIZE_T length)
{
PMDL pMdl;
if (length >= (PAGE_SIZE * (65535 - sizeof(MDL)) / sizeof(ULONG_PTR)))
{
DbgPrint("Size parameter passed to IoAllocateMdl is too big!\n");
return NULL;
}
pMdl = IoAllocateMdl((PVOID)pVirtualAddress, length, FALSE, FALSE, NULL);
if (NULL == pMdl)
{
DbgPrint("IoAllocateMdl returned NULL!\n");
return NULL;
}
MmBuildMdlForNonPagedPool(pMdl);
return pMdl;
}
// This function returns an MDL to a paged virtual memory area while
// making sure the pages are not paged out to the disk.
//
// IN pVirtualAddress Virtual address to the start of the memory area.
// IN length Length of the memory area in bytes.
// IN operation Desired mode of operation.
//
// OUT PMDL Mdl to the locked and nonpaged memory area.
//
PMDL GetMdlForPagedMemory(PVOID pVirtualAddress, SIZE_T length, LOCK_OPERATION operation)
{
PMDL pMdl;
if (length >= (PAGE_SIZE * (65535 - sizeof(MDL)) / sizeof(ULONG_PTR)))
{
DbgPrint("Size parameter passed to IoAllocateMdl is too big!\n");
return NULL;
}
pMdl = IoAllocateMdl((PVOID)pVirtualAddress, length, FALSE, FALSE, NULL);
if (NULL == pMdl)
{
DbgPrint("IoAllocateMdl returned NULL!\n");
return NULL;
}
// Make sure the memory is not paged on the disk.
try
{
MmProbeAndLockPages(pMdl, KernelMode, operation);
}
except (EXCEPTION_EXECUTE_HANDLER)
{
DbgPrint("MmProbeAndLockPages caused an exception!\n");
IoFreeMdl(pMdl);
return NULL;
}
return pMdl;
}
// This function writes the given data to the given non-paged kernel memory location.
// It makes sure that no other instance can access it in any way until we have finished
// our job.
//
// IN pDestination Pointer to the kernel memory where we want to write.
// IN pSource Pointer to the data we want to write.
// IN length Length of data we want to write in bytes.
//
// OUT NTSTATUS return code.
//
NTSTATUS WriteKernelMemory(BYTE *pDestination, BYTE *pSource, SIZE_T length)
{
KSPIN_LOCK spinLock;
KLOCK_QUEUE_HANDLE lockHandle;
PMDL pMdl;
PVOID pAddress;
pMdl = GetMdlForNonPagedMemory(pDestination, length);
if (NULL == pMdl)
{
DbgPrint("GetMdlForSafeKernelMemoryArea returned NULL!\n");
return STATUS_UNSUCCESSFUL;
}
pAddress = MmGetSystemAddressForMdlSafe(pMdl, HighPagePriority);
if (pAddress == NULL)
{
IoFreeMdl(pMdl);
DbgPrint("MmGetSystemAddressForMdlSafe returned NULL!\n");
return STATUS_UNSUCCESSFUL;
}
KeInitializeSpinLock(&spinLock);
// Only supported on XP and later. For Windows 2000 compatibility you can
// use the older, less efficient and less reliable KeAcquireSpinLock function.
KeAcquireInStackQueuedSpinLock (&spinLock, &lockHandle);
// We have the spinlock, so we can safely overwrite the kernel memory.
RtlCopyMemory(pAddress, pSource, length);
KeReleaseInStackQueuedSpinLock(&lockHandle);
IoFreeMdl(pMdl);
return STATUS_SUCCESS;
}
void __stdcall ProcessData(DWORD *pEthread)
{
DWORD *pEprocess = (DWORD *)*(pEthread + offsets.threadsProcess);
DWORD *pCid = (DWORD *)(pEthread+offsets.CID);
DWORD key = 0;
DATA data = {0};
data.processID = 0x0;
data.threadID = 0x0;
data.imageName = "NONE";
key = (DWORD)pEthread;
if (pCid != NULL)
{
data.processID = *pCid;
data.threadID = *(pCid + 0x1);
}
if (pEprocess != NULL)
{
data.imageName = (BYTE *)(pEprocess+offsets.imageFilename);
data.xlow = *(DWORD *)(pEprocess+offsets.peexittimeoff);
data.xhigh = *(DWORD *)(pEprocess+offsets.peexittimeoff+4);
}
if (*(pEthread + offsets.crossThreadFlags) & 1)
{
KeAcquireSpinLock(&DpcSpinLock,&OldIrql);
Remove(key, pHashTable);
KeReleaseSpinLock(&DpcSpinLock,OldIrql);
}
else
{
KeAcquireSpinLock(&DpcSpinLock,&OldIrql);
Insert(key, &data, pHashTable);
KeReleaseSpinLock(&DpcSpinLock,OldIrql);
}
}
void __declspec(naked) DetourFunction()
{
__asm
{
// Save parameters we will overwrite. We save all data to play it safe.
pushad
pushfd
// Disable interrupts. Assume single processor machine.
// cli
// EDI holds the thread whose context we will switch out.
push edi
call ProcessData
// ESI holds the thread whose context we will switch in.
push esi
call ProcessData
// Enable interrupts.
// sti
// Restore the saved state.
popfd
popad
// Jump to the trampoline function.
jmp dword ptr pTrampoline
}
}
BYTE * GetSwapAddr()
{
BYTE *res = 0;
NTSTATUS Status;
PETHREAD Thread;
if (*NtBuildNumber <= 2195)
Status = PsLookupThreadByThreadId((PVOID)4, &Thread);
else
Status = PsLookupThreadByThreadId((PVOID)8, &Thread);
if (NT_SUCCESS(Status))
{
if (MmIsAddressValid(Thread))
res = (BYTE *)(*(ULONG *)((BYTE *)(Thread)+0x28));
if (MmIsAddressValid(res+8))
res = (BYTE *)(*(ULONG *)(res+8));
else
res = 0;
}
return res;
}
ULONG GetFunctionAddr( IN PCWSTR FunctionName)
{
UNICODE_STRING UniCodeFunctionName;
RtlInitUnicodeString( &UniCodeFunctionName, FunctionName );
return (ULONG)MmGetSystemRoutineAddress( &UniCodeFunctionName );
}
VOID DoFindSwap(IN PVOID pContext)
{
NTSTATUS ret;
PSYSTEM_MODULE_INFORMATION module = NULL;
ULONG n=0;
void *buf = NULL;
ULONG ntosknlBase;
ULONG ntosknlEndAddr;
ULONG curAddr;
ULONG code1_sp1=0xc626c90a,code2_sp1=0x9c022d46,code3_sp1=0xbb830b8b,code4_sp1=0x00000994;
ULONG code1,code2,code3,code4;
ULONG i;
NtQuerySystemInformation=(NTQUERYSYSTEMINFORMATION)GetFunctionAddr(L"NtQuerySystemInformation");
if (!NtQuerySystemInformation)
{
DbgPrint("Find NtQuerySystemInformation faild!");
goto Ret;
}
ret=NtQuerySystemInformation(SystemModuleInformation,&n,0,&n);
if (NULL==( buf=ExAllocatePoolWithTag(NonPagedPool, n, 'AWS')))
{
DbgPrint("ExAllocatePool() failed\n" );
goto Ret;
}
ret=NtQuerySystemInformation(SystemModuleInformation,buf,n,NULL);
if (!NT_SUCCESS(ret)) {
DbgPrint("NtQuerySystemInformation faild!");
goto Ret;
}
module=(PSYSTEM_MODULE_INFORMATION)((PULONG)buf+1);
ntosknlEndAddr=(ULONG)module->Base+(ULONG)module->Size;
ntosknlBase=(ULONG)module->Base;
curAddr=ntosknlBase;
ExFreePool(buf);
code1 = code1_sp1;
code2 = code2_sp1;
code3 = code3_sp1;
code4 = code4_sp1;
for (i=curAddr;i<=ntosknlEndAddr;i++)
{
if (*((ULONG *)i)==code1)
{
if (*((ULONG *)(i+4))==code2)
{
if (*((ULONG *)(i+8))==code3)
{
if (*((ULONG *)(i+12))==code4)
{
pSwapContext=(BYTE *)i;
break;
}
}
}
}
}
Ret:
PsTerminateSystemThread(STATUS_SUCCESS);
}
void FindSwapAddr()
{
HANDLE hThread = NULL;
PVOID objtowait = 0;
NTSTATUS dwStatus =
PsCreateSystemThread(
&hThread,
0,
NULL,
(HANDLE)0,
NULL,
DoFindSwap,
NULL
);
if ((KeGetCurrentIrql())!=PASSIVE_LEVEL)
{
KfRaiseIrql(PASSIVE_LEVEL);
}
if ((KeGetCurrentIrql())!=PASSIVE_LEVEL)
{
return;
}
ObReferenceObjectByHandle(
hThread,
THREAD_ALL_ACCESS,
NULL,
KernelMode,
&objtowait,
NULL
);
KeWaitForSingleObject(objtowait,Executive,KernelMode,FALSE,NULL); //NULL表示无限期等待.
return;
}
NTSTATUS InstallSwapContextHook()
{
NTSTATUS rc;r
int length = 0;
int totalLength = 0;
struct xde_instr instr;
BYTE *pJmpCode = NULL;
long displacement = 0;
__asm
{
push eax
mov eax, CR0
and eax, 0FFFEFFFFh
mov CR0, eax
pop eax
}
// Disassemble the code to get how many bytes we have to replace.
// We use XDE v1.01 by Z0MBie (http://z0mbie.host.sk/).
while (totalLength < 5)
{
length = xde_disasm(pSwapContext + totalLength, &instr);
if (length == 0)
{
DbgPrint("xde_disasm returned 0!\n");
return STATUS_UNSUCCESSFUL;
}
totalLength += length;
}
DbgPrint("Hook will replace the first %d bytes.\n", totalLength);
// Allocate the required bytes for the trampoline function.
pTrampoline = trampoline.pAddress = ExAllocatePoolWithTag(NonPagedPool, totalLength + 5, MAINTAG1);
if (trampoline.pAddress == NULL)
{
DbgPrint("ExAllocatePoolWithTag returned NULL!\n");
return STATUS_UNSUCCESSFUL;
}
DbgPrint("Trampoline is at 0x%x\n", pTrampoline);
// This tells how many bytes we replaced from the original function.
trampoline.size = totalLength;
RtlCopyMemory(trampoline.pAddress, pSwapContext, totalLength);
// We are using JMP rel32 instruction to jump to the rest of the
// swapcontext function, so we first calculate the 32bit displacement
// and then create the five byte JMP instruction.
displacement = (pSwapContext + totalLength) - (trampoline.pAddress + totalLength + JMP_SIZE);
pJmpCode = trampoline.pAddress + totalLength;
//直接的jmp分3种
//Short Jump(短跳转)机器码 EB rel8
//只能跳转到256字节的范围内
//Near Jump(近跳转)机器码 E9 rel16/32
//可跳至同一个段的范围内的地址
//Far Jump(远跳转)机器码EA ptr 16:16/32
//可跳至任意地址,使用48位/32位全指针
*pJmpCode = 0xe9;
RtlCopyMemory(pJmpCode+1, &displacement, 4);
// Allocate the required bytes for the jmp code to the detour function.
pJmpCode = ExAllocatePoolWithTag(NonPagedPool, totalLength, MAINTAG1);
if (pJmpCode == NULL)
{
DbgPrint("ExAllocatePoolWithTag returned NULL!\n");
return STATUS_UNSUCCESSFUL;
}
// Initialize the jmp-code with NOPs.
RtlFillMemory(pJmpCode, totalLength, 0x90);
// We are using JMP rel32 instruction to jump to our hook function,
// so we first calculate the 32bit displacement and then create the
// five byte JMP instruction.
displacement = ((BYTE *)&DetourFunction) - (pSwapContext + JMP_SIZE);
*pJmpCode = 0xe9;
RtlCopyMemory(pJmpCode+1, &displacement, 4);
rc = WriteKernelMemory(pSwapContext, pJmpCode, totalLength);
ExFreePoolWithTag(pJmpCode, MAINTAG1);
__asm
{
push eax
mov eax, CR0
or eax, NOT 0FFFEFFFFh
mov CR0, eax
pop eax
}
return rc;
}
// This function removes our hook by restoring the bytes we have replaced
// from the original SwapContext function.
//
// OUT NTSTATUS return value.
//
NTSTATUS UninstallSwapContextHook()
{
return WriteKernelMemory(pSwapContext, trampoline.pAddress, trampoline.size);
}
NTSTATUS OnUnload(IN PDRIVER_OBJECT DriverObject)
{
NTSTATUS rc;
UNICODE_STRING deviceLinkUnicodeString;
PDEVICE_OBJECT p_NextObj;
PPROCLIST pTemp = NULL, pt = NULL;
PThreadData pTempT = NULL, pp = NULL;
PDriverData pTempD = NULL, pd = NULL;
PFileList pTempF = NULL, pf = NULL;
DbgPrint("OnUnload called\n");
rc = UninstallSwapContextHook();
if (STATUS_SUCCESS == rc)
{
DbgPrint("UninstallSwapContextHook succeeded.\n");
}
else
{
DbgPrint("UninstallSwapContextHook failed!\n");
}
// Show the collected data and release all resources.
//DumpTable(pHashTable);
KeAcquireSpinLock(&DpcSpinLock,&OldIrql);
DestroyTable(pHashTable);
KeReleaseSpinLock(&DpcSpinLock,OldIrql);
//num = 0;
ExFreePoolWithTag(pTrampoline, MAINTAG1);
// Delete the symbolic link for our device
//
RtlInitUnicodeString( &deviceLinkUnicodeString, deviceLinkBuffer );
IoDeleteSymbolicLink( &deviceLinkUnicodeString );
// Delete the device object
//
IoDeleteDevice( DriverObject->DeviceObject );
//return STATUS_SUCCESS;
return rc;
}
NTSTATUS DispatchCreate (
IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp )
{
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0; // no bytes xfered
IoCompleteRequest( pIrp, IO_NO_INCREMENT );
return STATUS_SUCCESS;
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
RTL_OSVERSIONINFOW osvi;
NTSTATUS ntStatus;
UNICODE_STRING deviceNameUnicodeString;
UNICODE_STRING deviceLinkUnicodeString;
RTL_OSVERSIONINFOEXW VersionInfo;
ULONGLONG ConditionMask = 0;
memset(&VersionInfo,0,sizeof(VersionInfo));
VER_SET_CONDITION (
ConditionMask,
VER_SERVICEPACKMAJOR,
VER_EQUAL
);
DbgPrint("DriverEntry called.\n");
RtlZeroMemory(&osvi, sizeof(RTL_OSVERSIONINFOW));
osvi.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOW);
// Initialize the OS specific data.
// gNameOffset = GetLocationOfProcessName(PsGetCurrentProcess());
// if (!gNameOffset)
// return STATUS_UNSUCCESSFUL;
if (STATUS_SUCCESS == RtlGetVersion(&osvi))
{
if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) //Windows XP
{
offsets.pecreatetimeoff = 0x070;
offsets.peexittimeoff = 0x078;
offsets.CID = 0x7b;
offsets.threadsProcess = 0x88;
offsets.crossThreadFlags = 0x92;
offsets.imageFilename = 0x5d;
}
//VersionInfo.wServicePackMajor = 3;
//if( STATUS_SUCCESS==RtlVerifyVersionInfo(&VersionInfo,VER_SERVICEPACKMAJOR,ConditionMask))//sp3
//{
//
//}
else
{
//更多的调试
DbgPrint("Unsupported OS version!\n");
return STATUS_UNSUCCESSFUL;
}
}
else
{
DbgPrint("RtlGetVersion failed!\n");
return STATUS_UNSUCCESSFUL;
}
RtlInitUnicodeString (&deviceNameUnicodeString,
deviceNameBuffer );
RtlInitUnicodeString (&deviceLinkUnicodeString, deviceLinkBuffer);
ntStatus = IoCreateDevice ( DriverObject,
0, // For driver extension
&deviceNameUnicodeString,
FILE_DEVICE_UNKNOWN,
0,
TRUE,
&g_HookDevice );
if(! NT_SUCCESS(ntStatus))
{
DbgPrint(("Failed to create device!\n"));
return ntStatus;
}
ntStatus = IoCreateSymbolicLink (&deviceLinkUnicodeString,
&deviceNameUnicodeString );
if(! NT_SUCCESS(ntStatus))
{
IoDeleteDevice(DriverObject->DeviceObject);
DbgPrint("Failed to create symbolic link!\n");
return ntStatus;
}
DriverObject->DriverUnload = OnUnload;
pHashTable = InitializeTable(HASHTABLE_SIZE);
if (pHashTable == NULL)
{
DbgPrint("InitializeTable failed!\n");
return STATUS_UNSUCCESSFUL;
}
//pSwapContext = GetSwapAddr();
FindSwapAddr();
if(NULL==pSwapContext)
{
DbgPrint("SwapContext addr not found!\n");
return STATUS_UNSUCCESSFUL;
}
else
{
DbgPrint("SwapContext found at 0x%x\n", pSwapContext);
ntStatus = InstallSwapContextHook();
}
if (STATUS_SUCCESS == ntStatus)
{
DbgPrint("InstallSwapContextHook succeeded.\n");
DbgPrint("DetourFunction is at 0x%x\n", DetourFunction);
}
else
{
DbgPrint("InstallSwapContextHook failed!\n");
return STATUS_UNSUCCESSFUL;
}
return STATUS_SUCCESS;
}
[/code]
两份inline hook NtOpenprocess保护进程的代码:
这份没有使用中间函数:
#include "ntddk.h"
#pragma pack(1)
#define IOCTL_HOOK CTL_CODE(FILE_DEVICE_UNKNOWN,0x801 , METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
typedef struct ServiceDescriptorEntry {
unsigned int *ServiceTableBase;
unsigned int *ServiceCounterTableBase; //仅适用于checked build版本
unsigned int NumberOfServices;
unsigned char *ParamTableBase;
} ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t;
#pragma pack()
__declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable;
//global
ULONG OpenprocessAddress;
ULONG JmpOldAddress;
UCHAR OldCode[5];
HANDLE MyPID;
HANDLE PID;
int *MyPIDEx;
void IninleHookOpenProcess(int *PID);
NTSTATUS __declspec(naked)(__stdcall MyNtOpenProcess)(
PHANDLE ProcessHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
PCLIENT_ID ClientId)
{
__asm
{
push eax
mov eax,[esp+0x14] //获取ClientId,因为是第四个参数所以【esp+10】,但上面有push eax 所以再加4
mov eax,[eax]
mov PID,eax //不能在naked函数里定义局部变量,会破坏本来的局部变量
pop eax
}
if(PID==MyPID)
{
__asm
{
mov [esp+4],0 //返回空句柄
mov eax,0xC0000022L //返回值STATUS_ACCESS_DENIED 无法发现进程
retn 0x10 //执行保护后的返回
}
}
/*__asm
{
push 0x0C4
mov edx,RealNtOpenProcess
add edx,5
jmp edx
}*/
__asm
{
mov edi,edi
push ebp
mov ebp,esp
jmp JmpOldAddress
}
}
void PageProtectOn()
{
__asm{//恢复内存保护
mov eax,cr0
or eax,10000h
mov cr0,eax
sti
}
}
void PageProtectOff()
{
__asm{//去掉内存保护
cli
mov eax,cr0
and eax,not 10000h
mov cr0,eax
}
}
NTSTATUS IODispatch(PDEVICE_OBJECT pDeviceObject, PIRP Irp)
{
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp,IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS IOManager(PDEVICE_OBJECT pDeviceObject, PIRP Irp)
{
PIO_STACK_LOCATION StackLocation = IoGetCurrentIrpStackLocation(Irp);
ULONG IRPcode = StackLocation->arameters.DeviceIoControl.IoControlCode;
char outText[]="保护成功";
ULONG returnSize;
UCHAR *oubuffer;
Irp->IoStatus.Status = STATUS_SUCCESS;
switch(IRPcode)
{
case IOCTL_HOOK:
KdPrint(("IOCTL_HOOK \n"));
MyPIDEx =(int*)Irp->AssociatedIrp.SystemBuffer;//得到传入数据地址
oubuffer = (UCHAR*)Irp->AssociatedIrp.SystemBuffer;
strcpy((char*)oubuffer,outText);
returnSize=strlen(outText);
IninleHookOpenProcess(MyPIDEx);
break;
}
Irp->IoStatus.Information=returnSize;
Irp->IoStatus.Status= STATUS_SUCCESS;
IoCompleteRequest(Irp,IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
void IninleHookOpenProcess(int *PID)
{
UCHAR jmpcode[5];
ULONG jmp_tmp_code;
jmpcode[0]=0xE9;
OpenprocessAddress = KeServiceDescriptorTable.ServiceTableBase[190];
jmp_tmp_code = (ULONG)MyNtOpenProcess - OpenprocessAddress - 5;
*(ULONG*)&jmpcode[1]=jmp_tmp_code;
JmpOldAddress = OpenprocessAddress + 5;
MyPID = (HANDLE)*PID;
PageProtectOff();
RtlCopyMemory(OldCode,(PVOID)OpenprocessAddress,5);
RtlCopyMemory((PVOID)OpenprocessAddress,jmpcode,5);
PageProtectOn();
}
void UnHookOpenprocess()
{
PageProtectOff();
RtlCopyMemory((PVOID)OpenprocessAddress,OldCode,5);
PageProtectOn();
}
NTSTATUS CreateDevice(PDRIVER_OBJECT pDriverObject)
{
NTSTATUS Status;
PDEVICE_OBJECT pDevObj;
UNICODE_STRING usDevName;
UNICODE_STRING usSymName;
RtlInitUnicodeString(&usDevName,L"\\Device\\MyDevice");
Status = IoCreateDevice(pDriverObject,\
0,\
&usDevName,\
FILE_DEVICE_UNKNOWN,\
0,\
TRUE,\
&pDevObj);
if (!NT_SUCCESS(Status))
{
return Status;
}
pDevObj->Flags |= DO_BUFFERED_IO;
RtlInitUnicodeString(&usSymName,L"\\??\\MyDevice");
Status = IoCreateSymbolicLink(&usSymName,&usDevName);
if (!NT_SUCCESS(Status))
{
IoDeleteDevice(pDevObj);
return Status;
}
return STATUS_SUCCESS;
}
void UnloadDriver(PDRIVER_OBJECT pDriverObject)
{
UNICODE_STRING usSymName;
RtlInitUnicodeString(&usSymName,L"\\??\\MyDevice");
if (pDriverObject->DeviceObject!=NULL)
{
IoDeleteSymbolicLink(&usSymName);
IoDeleteDevice(pDriverObject->DeviceObject);
KdPrint(("删除设备成功."));
}
UnHookOpenprocess();
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,PUNICODE_STRING pRegString)
{
NTSTATUS Status;
Status = CreateDevice(pDriverObject);
if (!NT_SUCCESS(Status))
{
KdPrint(("创建设备失败."));
}else{
KdPrint(("创建设备成功."));
}
pDriverObject->MajorFunction[IRP_MJ_CREATE] = IODispatch;
pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IOManager;
pDriverObject->DriverUnload = UnloadDriver;
return STATUS_SUCCESS;
}[/code]
另外一份使用了中间函数 这才是真正意义上inline hook
//为什么一个是esp+0x34 一个是esp+14 原因是下面这份使用了pushad
pushfd[/code]保护了现场 这将栈提高了0x24字节
#include "ntddk.h"
#pragma pack(1)
typedef struct ServiceDescriptorEntry {
unsigned int *ServiceTableBase;
unsigned int *ServiceCounterTableBase; //仅适用于checked build版本
unsigned int NumberOfServices;
unsigned char *ParamTableBase;
} ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t;
#pragma pack()
__declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable;
NTSTATUS
PsLookupProcessByProcessId(
IN HANDLE ProcessId,
OUT PEPROCESS *Process
);
//global
ULONG gfn_ntopenprocess;
ULONG g_jmp_origfunc;
UCHAR gs_origfunc_code[5];
void PageProtectOn()
{
__asm{//恢复内存保护
mov eax,cr0
or eax,10000h
mov cr0,eax
sti
}
}
void PageProtectOff()
{
__asm{//去掉内存保护
cli
mov eax,cr0
and eax,not 10000h
mov cr0,eax
}
}
ULONG FilterNtOpenProcess(PCLIENT_ID ClientId)
{
NTSTATUS status;
PEPROCESS process_obj;
status = PsLookupProcessByProcessId(ClientId->UniqueProcess,&process_obj);
if (!NT_SUCCESS(status))
{
return 0;
}
if (strstr((char*)process_obj+0x16c,"VistaLKD")!=0)
{
return 1;
}
return 0;
}
__declspec(naked)
NTSTATUS NewNtOpenProcess()
{
__asm{
pushad
pushfd
push [esp+0x34]
call FilterNtOpenProcess
test eax,eax
je __Exit
popfd
popad
mov eax,0
ret 0x10
__Exit:
popfd
popad
mov edi,edi
push ebp
mov ebp,esp
jmp g_jmp_origfunc
}
}
void UnHookNtOpenProcess()
{
PageProtectOff();
RtlCopyMemory((PVOID)gfn_ntopenprocess,gs_origfunc_code,5);
PageProtectOn();
}
void HookNtOpenProcess()
{
ULONG u_jmp_address;
UCHAR str_jmp_code[5];
gfn_ntopenprocess = KeServiceDescriptorTable.ServiceTableBase[190];
RtlCopyMemory(gs_origfunc_code,(PVOID)gfn_ntopenprocess,5);
str_jmp_code[0] = 0xE9;
u_jmp_address = (ULONG)NewNtOpenProcess - gfn_ntopenprocess - 5;
*(ULONG*)(&str_jmp_code[1]) = u_jmp_address;
PageProtectOff();
RtlCopyMemory((PVOID)gfn_ntopenprocess,str_jmp_code,5);
PageProtectOn();
g_jmp_origfunc = gfn_ntopenprocess + 5;
}
VOID MyUnload(PDRIVER_OBJECT pDriverObject)
{
UnHookNtOpenProcess();
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,PUNICODE_STRING Reg_Path)
{
HookNtOpenProcess();
pDriverObject->DriverUnload = MyUnload;
return STATUS_SUCCESS;
}[/code]
问:为什么一个esp+14 一个是esp+38 |
|