揭秘灰色产业链中掖着藏着的底层技术(初级篇)
2012-08-14 22:42
741 查看
今天就来一段现在比较流行的,也算是有人藏着掖着的,能反反调试的一种手段之一,重载内核。一共两个函数,放在驱动程序里直接调用即可。废话不多说,上代码。
//////////////////////////////////////////////////////////////////////////////////////////////////// // // 函数名称: LoadKernel // 函数作用: 将内核文件载入内存 // 参数: newKernelBasePtrPtr[OUT]: 接收新内核基址的指针 // oldKernelBasePtrPtr[OUT]: 接收旧内核基址的指针 // 作者: 葛世超 // 时间: 2012年8月14日22:37 // //////////////////////////////////////////////////////////////////////////////////////////////////// NTSTATUS LoadKernel(OUT PUCHAR * newKernelBasePtrPtr, OUT PUCHAR * oldKernelBasePtrPtr) { ULONG rtlProcessModulesSize = 0; //获取枚举系统模块所需内存尺寸 NTSTATUS status = ZwQuerySystemInformation(SystemModuleInformation, NULL, 0, &rtlProcessModulesSize); //以获取的内存尺寸作为判断函数成功的依据是由于rtlProcessModulesSize为0时函数一定不能返回STATUS_SUCCESS if (!rtlProcessModulesSize) { return status; } //为系统模块分配内存空间 PRTL_PROCESS_MODULES rtlProcessModulesPtr = (PRTL_PROCESS_MODULES)ExAllocatePoolWithTag(PagedPool, rtlProcessModulesSize, 'NIMS'); if (!rtlProcessModulesPtr) { return STATUS_NO_MEMORY; } RtlZeroMemory(rtlProcessModulesPtr, rtlProcessModulesSize); //第二次调用该函数且rtlProcessModulesSize不为0时可返回有效内核模块信息 status = ZwQuerySystemInformation(SystemModuleInformation, rtlProcessModulesPtr, rtlProcessModulesSize, &rtlProcessModulesSize); //因rtlProcessModulesSize足够大且rtlProcessModulesPtr有效, 则可以使用函数返回值判断函数执行结果 if (!NT_SUCCESS(status)) { ExFreePoolWithTag(rtlProcessModulesPtr, 'NIMS'); return status; } UNICODE_STRING kernelFilePath; RtlZeroMemory(&kernelFilePath, sizeof(kernelFilePath)); PUCHAR oldKernelBasePtr = NULL; for (int i = 0; i < rtlProcessModulesPtr->NumberOfModules; ++i) { if (strstr(rtlProcessModulesPtr->Modules[i].FullPathName, "ntoskrnl.exe")) { RtlInitUnicodeString(&kernelFilePath, L"\\SystemRoot\\System32\\ntoskrnl.exe"); oldKernelBasePtr = (PUCHAR)rtlProcessModulesPtr->Modules[i].ImageBase; break; } if (strstr(rtlProcessModulesPtr->Modules[i].FullPathName, "ntkrnlpa.exe")) { RtlInitUnicodeString(&kernelFilePath, L"\\SystemRoot\\System32\\ntkrnlpa.exe"); oldKernelBasePtr = (PUCHAR)rtlProcessModulesPtr->Modules[i].ImageBase; break; } if (strstr(rtlProcessModulesPtr->Modules[i].FullPathName, "ntkrnlmp.exe")) { RtlInitUnicodeString(&kernelFilePath, L"\\SystemRoot\\System32\\ntkrnlmp.exe"); oldKernelBasePtr = (PUCHAR)rtlProcessModulesPtr->Modules[i].ImageBase; break; } if (strstr(rtlProcessModulesPtr->Modules[i].FullPathName, "ntkrpamp.exe")) { RtlInitUnicodeString(&kernelFilePath, L"\\SystemRoot\\System32\\ntkrpamp.exe"); oldKernelBasePtr = (PUCHAR)rtlProcessModulesPtr->Modules[i].ImageBase; break; } } ExFreePoolWithTag(rtlProcessModulesPtr, 'NIMS'); //oldKernelBasePtr等于NULL时没有找到内核文件路径 if (!oldKernelBasePtr) { return STATUS_NOT_FOUND; } //将内核文件内容读入内存 OBJECT_ATTRIBUTES objectAttributes; RtlZeroMemory(&objectAttributes, sizeof(objectAttributes)); InitializeObjectAttributes ( &objectAttributes, &kernelFilePath, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL ); IO_STATUS_BLOCK ioStatusBlock; RtlZeroMemory(&ioStatusBlock, sizeof(ioStatusBlock)); HANDLE kernelFileHandle = NULL; status = ZwOpenFile ( &kernelFileHandle, GENERIC_READ, &objectAttributes, &ioStatusBlock, FILE_SHARE_READ, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ); if (!NT_SUCCESS(status)) { return status; } FILE_STANDARD_INFORMATION fileStandardInformation; RtlZeroMemory(&fileStandardInformation, sizeof(fileStandardInformation)); status = ZwQueryInformationFile (kernelFileHandle, &ioStatusBlock, &fileStandardInformation, sizeof(fileStandardInformation), FileStandardInformation ); if (!NT_SUCCESS(status)) { ZwClose(kernelFileHandle); return status; } ULONG kernelFileSize = fileStandardInformation.EndOfFile.QuadPart; PUCHAR kernelFileContentPtr = (PUCHAR)ExAllocatePoolWithTag(PagedPool, kernelFileSize, 'TNTC'); if (!kernelFileContentPtr) { ZwClose(kernelFileHandle); return STATUS_NO_MEMORY; } RtlZeroMemory(kernelFileContentPtr, kernelFileSize); status = ZwReadFile( kernelFileHandle, NULL, NULL, NULL, &ioStatusBlock, kernelFileContentPtr, kernelFileSize, NULL, NULL ); ZwClose(kernelFileHandle); if (!NT_SUCCESS(status)) { ExFreePoolWithTag(kernelFileContentPtr, 'TNTC'); return status; } //IMAGE_DOS_HEADER PIMAGE_DOS_HEADER imageDosHeaderPtr = (PIMAGE_DOS_HEADER)kernelFileContentPtr; if (imageDosHeaderPtr->e_magic != IMAGE_DOS_SIGNATURE) { ExFreePoolWithTag(kernelFileContentPtr, 'TNTC'); return STATUS_INVALID_IMAGE_FORMAT; } //IMAGE_NT_HEADER PIMAGE_NT_HEADERS imageNtHeadersPtr = (PIMAGE_NT_HEADERS)(kernelFileContentPtr + imageDosHeaderPtr->e_lfanew); if (imageNtHeadersPtr->Signature != IMAGE_NT_SIGNATURE) { ExFreePoolWithTag(kernelFileContentPtr, 'TNTC'); return STATUS_INVALID_IMAGE_FORMAT; } ULONG kernelMemorySize = imageNtHeadersPtr->OptionalHeader.SizeOfImage; //为新内核分配内存空间(非分页内存) PUCHAR newKernelBasePtr = (PUCHAR)ExAllocatePoolWithTag(NonPagedPool, kernelMemorySize, 'LNRK'); if (!newKernelBasePtr) { ExFreePoolWithTag(kernelFileContentPtr, 'TNTC'); return STATUS_NO_MEMORY; } RtlZeroMemory(newKernelBasePtr, kernelFileSize); //将文件内容中PE头复制到内存区 RtlCopyMemory(newKernelBasePtr, kernelFileContentPtr, imageNtHeadersPtr->OptionalHeader.SizeOfHeaders); //按顺序装载各节 PIMAGE_SECTION_HEADER imageSectionHeaderPtr = (PIMAGE_SECTION_HEADER)(kernelFileContentPtr + imageDosHeaderPtr->e_lfanew + sizeof(IMAGE_NT_HEADERS)); for (int i = 0; i < imageNtHeadersPtr->FileHeader.NumberOfSections; ++i) { ULONG sectionVirtualAddress = imageSectionHeaderPtr[i].VirtualAddress; ULONG sectionFileOffset = imageSectionHeaderPtr[i].PointerToRawData; //只映射有效区域 ULONG sectionSize = imageSectionHeaderPtr[i].SizeOfRawData <= imageSectionHeaderPtr[i].Misc.VirtualSize ? imageSectionHeaderPtr[i].SizeOfRawData : imageSectionHeaderPtr[i].Misc.VirtualSize; if (sectionSize) { RtlCopyMemory(newKernelBasePtr + sectionVirtualAddress, kernelFileContentPtr + sectionFileOffset, sectionSize); } } //以旧内核基址为参考基址对新内核进行基址重定位 PIMAGE_BASE_RELOCATION imageBaseRelocationPtr = (PIMAGE_BASE_RELOCATION)(newKernelBasePtr + imageNtHeadersPtr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress); while (imageBaseRelocationPtr->SizeOfBlock) { PUSHORT relocationDataPtr = (PUSHORT)((PUCHAR)imageBaseRelocationPtr + sizeof(IMAGE_BASE_RELOCATION)); for (int i = 0; i < (imageBaseRelocationPtr->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(USHORT); ++i) { if (relocationDataPtr[i] >> 12 == IMAGE_REL_BASED_HIGHLOW) { PULONG relocationAddressPtr = (PULONG)(newKernelBasePtr + imageBaseRelocationPtr->VirtualAddress + (relocationDataPtr[i] & 0x0fff)); *relocationAddressPtr = *relocationAddressPtr - imageNtHeadersPtr->OptionalHeader.ImageBase + (ULONG)oldKernelBasePtr; } } imageBaseRelocationPtr = (PIMAGE_BASE_RELOCATION)((PUCHAR)imageBaseRelocationPtr + imageBaseRelocationPtr->SizeOfBlock); } //修复被重定位过的系统服务分发表(SSDT), 将其指回新内核对应分发函数入口 PSYSTEM_SERVICE_DESCRIPTOR_TABLE systemServiceDescriptorTable = (PSYSTEM_SERVICE_DESCRIPTOR_TABLE)(newKernelBasePtr + (ULONG)KeServiceDescriptorTable - (ULONG)oldKernelBasePtr); systemServiceDescriptorTable->NTOSKRNL.NumberOfService = KeServiceDescriptorTable->NTOSKRNL.NumberOfService; if (KeServiceDescriptorTable->NTOSKRNL.CounterTableBase) { systemServiceDescriptorTable->NTOSKRNL.CounterTableBase = (PULONG)(newKernelBasePtr + (ULONG)KeServiceDescriptorTable->NTOSKRNL.CounterTableBase - (ULONG)oldKernelBasePtr); } if (KeServiceDescriptorTable->NTOSKRNL.ParameterTableBase) { systemServiceDescriptorTable->NTOSKRNL.ParameterTableBase = (PUCHAR)(newKernelBasePtr + (ULONG)KeServiceDescriptorTable->NTOSKRNL.ParameterTableBase - (ULONG)oldKernelBasePtr); } if (KeServiceDescriptorTable->NTOSKRNL.ServiceTableBase) { systemServiceDescriptorTable->NTOSKRNL.ServiceTableBase = (PULONG)(newKernelBasePtr + (ULONG)KeServiceDescriptorTable->NTOSKRNL.ServiceTableBase - (ULONG)oldKernelBasePtr); for (int i = 0; i < systemServiceDescriptorTable->NTOSKRNL.NumberOfService; ++i) { systemServiceDescriptorTable->NTOSKRNL.ServiceTableBase[i] += (ULONG)newKernelBasePtr - (ULONG)oldKernelBasePtr; } } ExFreePoolWithTag(kernelFileContentPtr, 'TNTC'); *newKernelBasePtrPtr = newKernelBasePtr; *oldKernelBasePtrPtr = oldKernelBasePtr; return STATUS_SUCCESS; } //////////////////////////////////////////////////////////////////////////////////////////////////// // // 函数名称: FreeKernel // 函数作用: 释放加载的内核 // 参数: kernelBasePtr[IN]: 新内核基址 // //////////////////////////////////////////////////////////////////////////////////////////////////// VOID FreeKernel(IN PUCHAR kernelBasePtr) { ExFreePoolWithTag(kernelBasePtr, 'LNRK'); }
相关文章推荐
- 揭秘灰色产业链中掖着藏着的底层技术(牢骚篇)
- 腾讯TEG架构平台部总监冯亮:游戏内部云底层技术揭秘
- 揭秘微信灰色产业链:3人团队月赚500万
- 【PDF下载】双11技术峰会之揭秘阿里虚拟互动实验室
- [转]一文看懂区块链架构设计 - 从概念到底层技术
- (转载)警惕“番茄花园”灰色产业链
- Google Megastore分布式存储技术全揭秘
- (转载)警惕“番茄花园”灰色产业链
- 网络扫描技术揭秘读书笔记2--常用的网络编程-其它协议编程
- 从概念到底层技术,一文看懂区块链架构设计
- 区块链:从底层技术时代走向产品时代的跃进
- ATL布幔下的秘密之底层技术和汇编
- jQuery 技术揭秘
- 奥运票务网站崩溃之技术原因揭秘
- 【转】 纯技术帖:MMOG网络同步算法揭秘
- 技术揭秘12306改造(一):尖峰日PV值297亿下可每秒出票1032张
- 云计算和大数据时代网络技术揭秘(一)云计算的兴起
- Instagram 5位传奇工程师背后的技术揭秘(PPT)