#include "ntimage.h"
//#include <ntddk.h>
#pragma pack(1)
typedef struct ServiceDescriptorEntry {
unsigned int *ServiceTableBase;
unsigned int *ServiceCounterTableBase;
unsigned int NumberOfServices;
unsigned char *ParamTableBase;
} ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t;
#pragma pack()
/* 从内核中导入的变量,定义后里面就有值,感觉很新颖的写法 */
__declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable;
ServiceDescriptorTableEntry_t *pNewSSDT;
ULONG h_org_NtOpenProcess;
ULONG addr_hookaddr=0;
ULONG jmp_ret;
ULONG OrigImage=0x804d8000; //硬编码地址,要确定自己的nt内核地址
/*
kd> lm nt
start end module name
804d8000 806d0480 nt ntkrnlpa.exe Mon Apr 14 02:31:06 2008 (4802516A)
*/
typedef
NTSTATUS (*NTOPENPROCESS) (
__out PHANDLE ProcessHandle,
__in ACCESS_MASK DesiredAccess,
__in POBJECT_ATTRIBUTES ObjectAttributes,
__in_opt PCLIENT_ID ClientId
);
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
}
}
/*
ServiceTableBase: SSDT指针
FuncIndex: 当前函数在SSDT中的索引
OrigFuncAddress: 原函数地址,ebx中
*/
ULONG display(ULONG ServiceTableBase,ULONG FuncIndex,ULONG OrigFuncAddress)
{
if (ServiceTableBase==(ULONG)KeServiceDescriptorTable.ServiceTableBase)
{//比较当前调用的进程是不是ce
/*
reloadKernel!display+0x21:
f8963071 0574010000 add eax,174h
kd> p
reloadKernel!display+0x26:
f8963076 8945f8 mov dword ptr [ebp-8],eax
kd> db eax
824af534 76 6d 74 6f 6f 6c 73 64-2e 65 78 65 00 00 00 00 vmtoolsd.exe....
*/
if (!strcmp((char*)PsGetCurrentProcess()+0x174,"cheatengine-i38"))
{
return pNewSSDT->ServiceTableBase[FuncIndex];
}
}
return OrigFuncAddress;
}
/*
调用display函数
*/
__declspec(naked)
void MyKiFastCallEntry()
{
__asm
{
pushad
pushfd
push ebx //原函数地址
push eax //SSDT index
push edi //SSDT指针
call display
mov [esp+0x14],eax //改EBX
popfd
popad //改EBX
//恢复以前的代码,以便内核正常运行
sub esp,ecx
shr ecx,2
jmp jmp_ret
}
}
/*
hook KiFastCallEntry函数 跳到 MyKiFastCallEntry
*/
void hook_KiFastCallEntry()
{
UCHAR jmp_code[5];
jmp_code[0]=0xe9;
//计算jmp_code
*(ULONG *)&jmp_code[1]=(ULONG)MyKiFastCallEntry-5-addr_hookaddr;
//计算返回jmp
jmp_ret = addr_hookaddr + 5;
PageProtectOff();
//inline hook
RtlCopyMemory((PVOID)addr_hookaddr,jmp_code,5);
PageProtectOn();
}
NTSTATUS h_NtOpenProcess (
__out PHANDLE ProcessHandle,
__in ACCESS_MASK DesiredAccess,
__in POBJECT_ATTRIBUTES ObjectAttributes,
__in_opt PCLIENT_ID ClientId
)
{
ULONG retaddr;
UCHAR *p=NULL;
int i=0;
/* 驱动程序保存为.c文件时,变量不能随处定义 */
KdPrint(("h_NtOpenProcess函数被调用
"));
__asm
{
pushad
mov eax,[ebp+0x04]
mov retaddr,eax
popad
}
p=(UCHAR *)retaddr; //获取kifsatcallentry对SSDT的调用
/*
reloadKernel!h_NtOpenProcess+0x27:
f8a2b1a7 8b4504 mov eax,dword ptr [ebp+4]
kd> r eax
eax=8053e638
kd> ub eax
nt!KiFastCallEntry+0xde:
8053e61e 8b1c87 mov ebx,dword ptr [edi+eax*4]
8053e621 2be1 sub esp,ecx
8053e623 c1e902 shr ecx,2
8053e626 8bfc mov edi,esp
8053e628 3b35d4995580 cmp esi,dword ptr [nt!MmUserProbeAddress (805599d4)]
8053e62e 0f83a8010000 jae nt!KiSystemCallExit2+0x9f (8053e7dc)
8053e634 f3a5 rep movs dword ptr es:[edi],dword ptr [esi]
8053e636 ffd3 call ebx
*/
KdPrint(("h_NtOpenProcess函数 retaddr: %x
",retaddr));
/*
向前搜索字节码,找到这里,记下这个地址用于hook KiFastCallEntry
8053e621 2be1 sub esp,ecx
8053e623 c1e902 shr ecx,2
*/
for(i=0;i<100;i++)
{
if(*p==0x2b&&*(p+1)==0xe1&&*(p+2)==0xc1&&*(p+3)==0xe9&&*(p+4)==0x02)
{
addr_hookaddr=(ULONG)p;
break;
}
else
{
p--;
}
}
if(addr_hookaddr==0)
{
KdPrint(("%x",retaddr));
KdPrint(("Find addr_hookaddr failed!"));
}
else
{
KdPrint(("You Have Find The Addr_hookaddr!"));
PageProtectOff();
KeServiceDescriptorTable.ServiceTableBase[122] =(unsigned int ) h_org_NtOpenProcess; //去掉老内核对h_org_NtOpenProcess的hook
PageProtectOn();
hook_KiFastCallEntry(); //改为hook KiFastCallEntry
}
return ((NTOPENPROCESS)h_org_NtOpenProcess)(ProcessHandle,DesiredAccess,ObjectAttributes,ClientId);
}
void Hook_NtOpenProcess()
{
h_org_NtOpenProcess = KeServiceDescriptorTable.ServiceTableBase[122];
PageProtectOff();
KeServiceDescriptorTable.ServiceTableBase[122] = (unsigned int)h_NtOpenProcess; //hook 老内核的NtOpenProcess,再调用NtOpenProcess函数时,进入我们的h_NtOpenProcess函数
/* 注意KdPrint使用双括号 */
KdPrint(("[+] h_NtOpenProcess函数地址: %x
", KeServiceDescriptorTable.ServiceTableBase[122]));
PageProtectOn();
}
/*
解除KiFastCallEntry的hook
*/
void UnHook_KiFastCallEntry()
{
UCHAR org_code[]={0x2b,0xe1,0xc1,0xe9,0x2};
if(addr_hookaddr!=0)
{
PageProtectOff();
RtlCopyMemory((PVOID)addr_hookaddr,org_code,5);
PageProtectOn();
}
}
void UnHookNtOpenProcess()
{
if(addr_hookaddr)
return;
PageProtectOff();
KeServiceDescriptorTable.ServiceTableBase[122]=(unsigned int )h_org_NtOpenProcess;
PageProtectOn();
}
VOID SetNewSSDT(PVOID pNewImage)
{
ULONG uIndex;
ULONG uNewKernelInc,uOffset;
//新内核地址-老内核地址,得到相对偏移
uNewKernelInc = (ULONG)pNewImage -OrigImage;
//老内核的ssdt指针加上相对偏移,得到新内核的ssdt指针
pNewSSDT = (ServiceDescriptorTableEntry_t *)((ULONG)&KeServiceDescriptorTable + uNewKernelInc);
KdPrint(("%x
",&KeServiceDescriptorTable)); //打印老内核SSDT指针,输出80553fa0
/*
kd> dd nt!KeServiceDescriptorTable
80553fa0 80502b8c 00000000 0000011c 80503000
*/
if (!MmIsAddressValid(pNewSSDT))
{
KdPrint(("pNewSSDT is unaviable!"));
return;
}
//由于数量是一个数值,因此不必作相对偏移
pNewSSDT->NumberOfServices = KeServiceDescriptorTable.NumberOfServices;
//计算相对函数地址
uOffset = (ULONG)KeServiceDescriptorTable.ServiceTableBase -OrigImage;
//得到新的ssdt函数表地址
pNewSSDT->ServiceTableBase = (unsigned int*)((ULONG)pNewImage + uOffset);
if (!MmIsAddressValid(pNewSSDT->ServiceTableBase))
{
KdPrint(("pNewSSDT->ServiceTableBase: %X",pNewSSDT->ServiceTableBase));
return;
}
//依次遍历
for (uIndex = 0;uIndex<pNewSSDT->NumberOfServices;uIndex++)
{//新的函数地址再加上相对加载地址,得到现在的ssdt函数地址
pNewSSDT->ServiceTableBase[uIndex] += uNewKernelInc;
}
}
void FixBaseRelocTable(PVOID pNewImage)
{
ULONG uIndex;
ULONG uRelocTableSize;
ULONG OriginalImageBase;
ULONG Type;
ULONG *uRelocAddress;
PIMAGE_DOS_HEADER pImageDosHeader;
PIMAGE_NT_HEADERS pImageNtHeader;
IMAGE_DATA_DIRECTORY ImageDataDirectory;
IMAGE_BASE_RELOCATION *pImageBaseRelocation;
//将新内核地址作为一个PE文件头,依次向下,目的是寻找重定位表结构
pImageDosHeader=(PIMAGE_DOS_HEADER)pNewImage;
//定位到IMAGE_NT_HEADER
pImageNtHeader=(PIMAGE_NT_HEADERS)((ULONG)pNewImage+pImageDosHeader->e_lfanew);
//获取内核文件的imagebase,以便后面做偏移修改。
OriginalImageBase=pImageNtHeader->OptionalHeader.ImageBase;
//定位到数据目录
ImageDataDirectory = pImageNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
//定位到重定位表结构
pImageBaseRelocation = (PIMAGE_BASE_RELOCATION)(ImageDataDirectory.VirtualAddress + (ULONG)pNewImage);
if (pImageBaseRelocation==NULL)
{
return;
}
while (pImageBaseRelocation->SizeOfBlock)
{ //计算需要修改的地址的个数
uRelocTableSize=(pImageBaseRelocation->SizeOfBlock-8)/2;
//循环遍历
for (uIndex=0;uIndex<uRelocTableSize;uIndex++)
{//判断高4位是否等于3
Type=pImageBaseRelocation->TypeOffset[uIndex]>>12;
if (Type==3)
{
//修改地址,相对地址加上一个新内核地址,使其成为一个实际地址
uRelocAddress=(ULONG *)((ULONG)(pImageBaseRelocation->TypeOffset[uIndex]&0x0fff)+pImageBaseRelocation->VirtualAddress+(ULONG)pNewImage);
//再加上内核首地址到imagebase的偏移
*uRelocAddress=*uRelocAddress+(OrigImage-OriginalImageBase);
}
}
//进行下一个重定位表的修改
pImageBaseRelocation=(IMAGE_BASE_RELOCATION *)((ULONG)pImageBaseRelocation+pImageBaseRelocation->SizeOfBlock);
}
}
void LoadKernel()
{
NTSTATUS status;
UNICODE_STRING uFileName;
HANDLE hFile;
OBJECT_ATTRIBUTES ObjAttr;
IO_STATUS_BLOCK IoStatusBlock;
LARGE_INTEGER FileOffset;
ULONG retsize;
PVOID lpVirtualPointer;
ULONG uLoop;
ULONG SectionVirtualAddress,SectionSize;
IMAGE_DOS_HEADER ImageDosHeader;
IMAGE_NT_HEADERS ImageNtHeader;
IMAGE_SECTION_HEADER *lpImageSectionHeader;
InitializeObjectAttributes(&ObjAttr,
&uFileName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
RtlInitUnicodeString(&uFileName,L"\??\C:\WINDOWS\system32\ntkrnlpa.exe");
//打开文件
status = ZwCreateFile(
&hFile,
FILE_ALL_ACCESS,
&ObjAttr,
&IoStatusBlock,
0,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN,
FILE_NON_DIRECTORY_FILE,
NULL,
0);
if(!NT_SUCCESS(status))
{
KdPrint(("CreateFile Failed!"));
return;
}
//读取DOS头
FileOffset.QuadPart = 0;
status = ZwReadFile(hFile,
NULL,
NULL,
NULL,
&IoStatusBlock,
&ImageDosHeader,
sizeof(IMAGE_DOS_HEADER),
&FileOffset,
0);
if(!NT_SUCCESS(status))
{
KdPrint(("Read ImageDosHeader Failed!"));
ZwClose(hFile);
return;
}
//读取NT头
FileOffset.QuadPart = ImageDosHeader.e_lfanew;
status = ZwReadFile(hFile,
NULL,
NULL,
NULL,
&IoStatusBlock,
&ImageNtHeader,
sizeof(IMAGE_NT_HEADERS),
&FileOffset,
0);
if(!NT_SUCCESS(status))
{
KdPrint(("Read ImageNtHeaders Failed!"));
ZwClose(hFile);
return;
}
//读取区表
lpImageSectionHeader = (IMAGE_SECTION_HEADER *)ExAllocatePool(NonPagedPool,
sizeof(IMAGE_SECTION_HEADER)*ImageNtHeader.FileHeader.NumberOfSections);
FileOffset.QuadPart += sizeof(IMAGE_NT_HEADERS);
status = ZwReadFile(hFile,
NULL,
NULL,
NULL,
&IoStatusBlock,
lpImageSectionHeader,
sizeof(IMAGE_SECTION_HEADER)*ImageNtHeader.FileHeader.NumberOfSections,
&FileOffset,
0);
if(!NT_SUCCESS(status))
{
KdPrint(("Read ImageSectionHeader Failed!"));
ExFreePool(lpImageSectionHeader);
ZwClose(hFile);
return;
}
//COPY数据到内存
lpVirtualPointer = ExAllocatePool(NonPagedPool,
ImageNtHeader.OptionalHeader.SizeOfImage);
if(lpVirtualPointer == 0)
{
KdPrint(("lpVirtualPointer Alloc space Failed!"));
ZwClose(hFile);
return;
}
memset(lpVirtualPointer,0,ImageNtHeader.OptionalHeader.SizeOfImage);
//COPY DOS头
RtlCopyMemory(lpVirtualPointer,
&ImageDosHeader,
sizeof(IMAGE_DOS_HEADER));
//COPY NT头
RtlCopyMemory((PVOID)((ULONG)lpVirtualPointer+ImageDosHeader.e_lfanew),
&ImageNtHeader,
sizeof(IMAGE_NT_HEADERS));
//COPY 区表
RtlCopyMemory((PVOID)((ULONG)lpVirtualPointer+ImageDosHeader.e_lfanew+sizeof(IMAGE_NT_HEADERS)),
lpImageSectionHeader,
sizeof(IMAGE_SECTION_HEADER)*ImageNtHeader.FileHeader.NumberOfSections);
//依次COPY 各区段数据
for(uLoop = 0;uLoop < ImageNtHeader.FileHeader.NumberOfSections;uLoop++)
{
SectionVirtualAddress = lpImageSectionHeader[uLoop].VirtualAddress;//对应区段相对偏移
if(lpImageSectionHeader[uLoop].Misc.VirtualSize > lpImageSectionHeader[uLoop].SizeOfRawData)
SectionSize = lpImageSectionHeader[uLoop].Misc.VirtualSize;//取最大的占用空间
else
SectionSize = lpImageSectionHeader[uLoop].SizeOfRawData;
FileOffset.QuadPart = lpImageSectionHeader[uLoop].PointerToRawData;//对应区段的超始地址
status = ZwReadFile(hFile,
NULL,
NULL,
NULL,
&IoStatusBlock,
(PVOID)((ULONG)lpVirtualPointer+SectionVirtualAddress),
SectionSize,
&FileOffset,
0);
if(!NT_SUCCESS(status))
{
KdPrint(("SectionData Read Failed!"));
ExFreePool(lpImageSectionHeader);
ExFreePool(lpVirtualPointer);
ZwClose(hFile);
return;
}
}
ExFreePool(lpImageSectionHeader);//释放区段内存空间
KdPrint(("lpVirtualPointer: %X
",lpVirtualPointer));
FixBaseRelocTable(lpVirtualPointer);
SetNewSSDT(lpVirtualPointer);
ZwClose(hFile);//关闭句柄
}
void DriverUnload(PDRIVER_OBJECT pDriverObject)
{
UnHook_KiFastCallEntry();
UnHookNtOpenProcess();
DbgPrint("Driver Unload Success !
");
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,PUNICODE_STRING pRegsiterPath)
{
DbgPrint("This is My First Driver!
");
LoadKernel();
Hook_NtOpenProcess();
pDriverObject->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
}