写这个插件其实主要是因为现在32位下各种内核钩子,用一些调试工具畏首畏尾的,一会挂钩这里,一会挂钩那里,遂干脆一了百了,直接写个内核重载插件,虽说是OD插件,也可以支持其他软件。此插件名字就叫ReloadKernel V1.0吧,贴切一点:(支持2003,XP,WIN7)请避免和360,QQ管家,百度杀毒等一同使用,对于没有DebugPort清零的保护应该是可以秒的,比如HS(亲测),当然你要处理R3的反调试,对于有调试权限清零的自己恢复,端口清零的自己改下偏移也就OK了,不会改的话再不济用这个插件也可以读写内存吧!,请别瞎想,本人写这个插件主要是为了学习交流,请大家不要用于非法用途,先来个图
首先内核重载插件我分成以下几个步骤完成
1, 获取当前系统下的内核文件
2, 按PE格式加载硬盘中的内核文件,修复重定位表,导入导出表
3, 挂钩KiFastCallEntry
4, 实现过滤框架
5, R3,R0通信
6, OD插件GUI与逻辑部分
1,因为在单核,多核处理器等不同情况下,微软会加载不同的内核文件,所以我们需要知道当前系统所加载的是哪一个内核文件,之后获取到它的全路径,并Copy到内存中,已便操作
下面这个函数是获取系统加载的内核模块基址,没什么好说的,原理就是ZwQuerySystemInformation的11号功能,查询内核模块
PVOID
GetKernelFileBase()
{
DWORD dwsize = 0;
PVOID pKernelBase = NULL;
PVOID pSysInfo = NULL;
__try
{
ZwQuerySystemInformation(SystemModuleInformation,NULL,0,&dwsize);
pSysInfo = ::ExAllocatePool(NonPagedPool,dwsize);
if(pSysInfo)
{
memset(pSysInfo,0,dwsize);
if(NT_SUCCESS(ZwQuerySystemInformation(SystemModuleInformation,pSysInfo,dwsize,&dwsize)))
{
PSYSTEM_MODULE_INFORMATION_ENTRY psmi = (PSYSTEM_MODULE_INFORMATION_ENTRY)((PBYTE)pSysInfo + 4);
pKernelBase = (PVOID)psmi->Base;
}
else
{
KdPrint(("GetKernelFileBase.ZwQuerySystemInformation error\n"));
}
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
KdPrint(("GetKernelFileBase异常\n"));
}
if(pSysInfo)
{
ExFreePool(pSysInfo);
pSysInfo = NULL;
}
return pKernelBase ;
}
bool
GetKernelFileFullPath(
OUT PUNICODE_STRING pUnicodeStr
)
{
bool bResult = FALSE;
DWORD dwsize = 0;
PVOID pSysInfo = NULL;
_try
{
ZwQuerySystemInformation(SystemModuleInformation,NULL,0,&dwsize);
pSysInfo = ::ExAllocatePool(NonPagedPool,dwsize);
if(pSysInfo)
{
memset(pSysInfo, 0, dwsize);
if(NT_SUCCESS(ZwQuerySystemInformation(SystemModuleInformation,pSysInfo,dwsize,&dwsize)))
{
PSYSTEM_MODULE_INFORMATION_ENTRY psmi = (PSYSTEM_MODULE_INFORMATION_ENTRY)((char*)pSysInfo + 4);
char *szKernelModuleName = psmi->ImageName + psmi->PathLength;
KdPrint(("模块 %s\n",szKernelModuleName));
char szKernelModuleFullPath[255];
ANSI_STRING asModuleName;
//"\\Device\\HarddiskVolume1\\Windows\\System32\\"
char szSystemPath[] = "\\??\\c:\\Windows\\System32\\";
strcpy(szKernelModuleFullPath,(char*)szSystemPath);
strcat(szKernelModuleFullPath,szKernelModuleName);
::RtlInitAnsiString(&asModuleName,szKernelModuleFullPath);
::RtlAnsiStringToUnicodeString(pUnicodeStr,&asModuleName,TRUE);
bResult = TRUE;
}
else
{
KdPrint(("GetKernelFileFullPath.ZwQuerySystemInformation error"));
}
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
KdPrint(("GetKernelFileFullPath.异常"));
}
if(pSysInfo)
{
ExFreePool(pSysInfo);
pSysInfo = NULL;
}
return bResult;
}
PVOID
CreateImageFromFile(
IN PUNICODE_STRING ImageFile)
{
NTSTATUS Status = STATUS_UNSUCCESSFUL;
HANDLE FileHandle = NULL;
OBJECT_ATTRIBUTES ObjAttributes = {0};
IO_STATUS_BLOCK IoStatusBlock = {0};
InitializeObjectAttributes(
&ObjAttributes,
ImageFile,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = ZwCreateFile(
&FileHandle,
GENERIC_READ,
&ObjAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
if(NT_SUCCESS(Status))
{
FILE_STANDARD_INFORMATION fsi = {0};
IO_STATUS_BLOCK iostatus = {0};
Status = ZwQueryInformationFile(
FileHandle,
&iostatus,
&fsi,
sizeof(FILE_STANDARD_INFORMATION),
FileStandardInformation);
if(NT_SUCCESS(Status))
{
PVOID pBuffer = ExAllocatePool(PagedPool,(LONG)fsi.EndOfFile.QuadPart);
if(pBuffer)
{
memset(pBuffer,0,(LONG)fsi.EndOfFile.QuadPart);
Status = ZwReadFile(FileHandle, NULL, NULL, NULL,&iostatus, pBuffer, (LONG)fsi.EndOfFile.QuadPart, NULL, NULL);
if(NT_SUCCESS(Status))
{
KdPrint(("Read %x bytes\n", iostatus.Information));
ZwClose(FileHandle);
return pBuffer;
}
else
{
KdPrint(("CreateImageFromFile.读取文件失败 %x",Status));
return 0;
}
}
else
{
KdPrint(("CreateImageFromFile.申请非分页内存失败"));
}
}
else
{
KdPrint(("CreateImageFromFile.获取文件尺寸失败"));
return 0;
}
}
else
{
KdPrint(("CreateImageFromFile.打开文件失败"));
return 0;
}
return 0;
}
ULONG
CreatePeStructFromMem(
IN ULONG ulFileAddress,
IN ULONG ntKernelAddress)
{
__try
{
PIMAGE_DOS_HEADER pIMAGE_DOS_HEADER = (PIMAGE_DOS_HEADER)ulFileAddress;
PIMAGE_NT_HEADERS pIMAGE_NT_HEADERS = (PIMAGE_NT_HEADERS)(ulFileAddress + pIMAGE_DOS_HEADER->e_lfanew);
PIMAGE_FILE_HEADER pIMAGE_FILE_HEADER = &pIMAGE_NT_HEADERS->FileHeader;
PIMAGE_OPTIONAL_HEADER32 pIMAGE_OPTIONAL_HEADER = &pIMAGE_NT_HEADERS->OptionalHeader;
KdPrint(("DOS 头 %x \n",pIMAGE_DOS_HEADER));
KdPrint(("NT 头 %x \n",pIMAGE_NT_HEADERS));
KdPrint(("文件 头 %x \n",pIMAGE_FILE_HEADER));
KdPrint(("可选 头 %x \n",pIMAGE_OPTIONAL_HEADER));
if(!pIMAGE_NT_HEADERS || !pIMAGE_FILE_HEADER || !pIMAGE_OPTIONAL_HEADER) return 0;
ULONG pMy_ImageBase = (ULONG)ExAllocatePool(NonPagedPool,pIMAGE_OPTIONAL_HEADER->SizeOfImage);
if(pMy_ImageBase)
{
memset((PVOID)pMy_ImageBase,0,pIMAGE_OPTIONAL_HEADER->SizeOfImage);
//复制头加段表
RtlCopyMemory((PVOID)pMy_ImageBase,(PVOID)ulFileAddress,pIMAGE_OPTIONAL_HEADER->SizeOfHeaders );
//节表展开
PIMAGE_SECTION_HEADER pSectionHeadTmp = (PIMAGE_SECTION_HEADER)((ULONG)pIMAGE_OPTIONAL_HEADER + sizeof(IMAGE_OPTIONAL_HEADER32));
for(int i = 0;i < pIMAGE_NT_HEADERS->FileHeader.NumberOfSections;i ++)
{
RtlCopyMemory((PVOID)(pSectionHeadTmp->VirtualAddress + (ULONG)pMy_ImageBase),//计算VA
(PVOID)(pSectionHeadTmp->PointerToRawData + (ULONG)ulFileAddress),//文件偏移
pSectionHeadTmp->SizeOfRawData);//计算尺寸
pSectionHeadTmp ++;
}
//导入表处理
for(
PIMAGE_IMPORT_DESCRIPTOR pImportDescriptorTmp = (PIMAGE_IMPORT_DESCRIPTOR)(pIMAGE_OPTIONAL_HEADER->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + (ULONG)pMy_ImageBase);
!IsStructEmpty<IMAGE_IMPORT_DESCRIPTOR>(pImportDescriptorTmp);
pImportDescriptorTmp++
)
{
KdPrint(("导入模块 %s\n",(char*)(pImportDescriptorTmp->Name + (ULONG)pMy_ImageBase)));
PVOID pModule = KernelGetModuleBase(((char*)(pImportDescriptorTmp->Name + (ULONG)pMy_ImageBase)));
if(pModule)
{
for(
PIMAGE_THUNK_DATA pThunkData = (PIMAGE_THUNK_DATA)(pImportDescriptorTmp->FirstThunk + (ULONG)pMy_ImageBase);
!IsStructEmpty<IMAGE_THUNK_DATA>(pThunkData);
pThunkData++
)
{
PVOID pFunctionTmp =
pThunkData->u1.AddressOfData & IMAGE_ORDINAL_FLAG32 ?
KernelGetProcAddress(pModule,(PCHAR)(pThunkData->u1.AddressOfData & 0xffff))
:
KernelGetProcAddress(pModule,(PCHAR)((PIMAGE_IMPORT_BY_NAME)(pThunkData->u1.AddressOfData + (ULONG)pMy_ImageBase))->Name);
if(!pFunctionTmp)
{
if(pThunkData->u1.AddressOfData & IMAGE_ORDINAL_FLAG32)
{
KdPrint(("有函数没找到,序号 %d",(PCHAR)(pThunkData->u1.AddressOfData & 0xffff)));
}
else
{
KdPrint(("有函数没找到,名字%s",(PCHAR)((PIMAGE_IMPORT_BY_NAME)(pThunkData->u1.AddressOfData + (ULONG)pMy_ImageBase))->Name));
}
}
else
{
if(pThunkData->u1.AddressOfData & IMAGE_ORDINAL_FLAG32)
{
KdPrint(("已经修复函数,序号 %d",(PCHAR)(pThunkData->u1.AddressOfData & 0xffff)));
}
else
{
KdPrint(("已经修复函数,名字%s",(PCHAR)((PIMAGE_IMPORT_BY_NAME)(pThunkData->u1.AddressOfData + (ULONG)pMy_ImageBase))->Name));
}
pThunkData->u1.Function = (DWORD)pFunctionTmp;
}
}
}
else
{
KdPrint(("获取模块 %s失败\n",(char*)(pImportDescriptorTmp->Name + (ULONG)pMy_ImageBase)));
}
}
int nRelocNum = 0;
ULONG ulR = ntKernelAddress - pIMAGE_OPTIONAL_HEADER->ImageBase;
KdPrint(("重定位偏移 ulR = %x",ulR));
for(
PIMAGE_BASE_RELOCATION pLoc = (PIMAGE_BASE_RELOCATION)(pIMAGE_OPTIONAL_HEADER->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress + (ULONG)pMy_ImageBase);
!IsStructEmpty<IMAGE_BASE_RELOCATION>(pLoc);
pLoc = (PIMAGE_BASE_RELOCATION)((DWORD)pLoc + pLoc->SizeOfBlock)
)
{
nRelocNum ++;
for(PWORD pHandleAddress = (PWORD)((DWORD)pLoc + sizeof(IMAGE_BASE_RELOCATION));pHandleAddress < (PWORD)((DWORD)pLoc + pLoc->SizeOfBlock);pHandleAddress ++)
{
if((*pHandleAddress & 0xf000) == IMAGE_REL_BASED_HIGHLOW * 0X1000)//x86重定位标记
{
*(PDWORD((*pHandleAddress & 0xfff) + pLoc->VirtualAddress + (ULONG)pMy_ImageBase)) += ulR;
}
}
}
KdPrint(("重定位块 = %d个",nRelocNum));
return pMy_ImageBase;
}
else
{
KdPrint(("CreatePeStructFromMem.申请内存失败"));
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
KdPrint(("CreatePeStructFromMem.执行异常"));
}
return 0;
}
int nRelocNum = 0;
ULONG ulR = ntKernelAddress - pIMAGE_OPTIONAL_HEADER->ImageBase;
KdPrint(("重定位偏移 ulR = %x",ulR));
for(
PIMAGE_BASE_RELOCATION pLoc = (PIMAGE_BASE_RELOCATION)(pIMAGE_OPTIONAL_HEADER->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress + (ULONG)pMy_ImageBase);
!IsStructEmpty<IMAGE_BASE_RELOCATION>(pLoc);
pLoc = (PIMAGE_BASE_RELOCATION)((DWORD)pLoc + pLoc->SizeOfBlock)
)
{
nRelocNum ++;
for(PWORD pHandleAddress = (PWORD)((DWORD)pLoc + sizeof(IMAGE_BASE_RELOCATION));pHandleAddress < (PWORD)((DWORD)pLoc + pLoc->SizeOfBlock);pHandleAddress ++)
{
if((*pHandleAddress & 0xf000) == IMAGE_REL_BASED_HIGHLOW * 0X1000)//x86重定位标记
{
*(PDWORD((*pHandleAddress & 0xfff) + pLoc->VirtualAddress + (ULONG)pMy_ImageBase)) += ulR;
}
}
}
template <class T>
bool IsStructEmpty(
IN T *Mystruct)
{
bool bIsEmpty = true;
__try
{
for(PBYTE p = (PBYTE)Mystruct;p < (PBYTE)((DWORD)Mystruct + sizeof(T)) ;p++)
{
if((*p) != 0 )
{
bIsEmpty = false;
break;
}
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
KdPrint(("IsStructEmpty Exception"));
}
return bIsEmpty;
}
ULONG GetAddressOfKiFastCallEntry()
{
ULONG dwAddress = 0;
BYTE vgdtr[8] = {0};
__asm
{
push eax
push ebx
push ecx
push edx
mov ecx, 0x174
rdmsr
mov ebx, eax //Selector offset
sgdt vgdtr
// mov edx, vgdtr
lea edx,vgdtr
add edx, 0x02
mov eax, [edx] //GDT base
add ebx, eax //Selector base
mov edx, ebx
add edx, 0x07
mov eax, [edx]
shl eax, 24;
mov edx, ebx
add edx, 0x02
mov ecx, [edx]
and ecx, 0x00FFFFFF
add eax, ecx //Address CodeSegment
mov ebx, eax
mov ecx, 0x176
rdmsr
add eax, ebx
mov dwAddress, eax
pop edx
pop ecx
pop ebx
pop eax
}
return dwAddress;
}
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课