• 1412阅读
  • 1回复

ring0-内核重载详解(NTOS) [复制链接]

上一主题 下一主题
离线天道酬勤
 

只看楼主 倒序阅读 使用道具 楼主  发表于: 2016-02-11
— 本帖被 天道酬勤 从 驱动保护 移动到本区(2016-05-19) —
1.取得NTOS原始的地址:
这个可以通过遍历系统模块,找到第一个被加载的模块(NTOS),获得NTOS的路径,基地址,大小:
基本思路为:
1.1 ZwQuerySystemInformation查询到所有模块
1.2 获得NTOS的路径,基地址,大小
代码如下:



[cpp] view plain copy

  1. NTSTATUS GetNtosModuleInfo(WCHAR *pNtosPath,ULONG nSize,  
  2.                            PULONG_PTR pNtosModBase,  
  3.                            PULONG_PTR pNtosModSize  
  4.                            )  
  5. {  
  6.     NTSTATUS                        ntStatus = STATUS_UNSUCCESSFUL;  
  7.     PRTL_PROCESS_MODULES            psmi = NULL;  
  8.     ULONG                           ulSize = 0;  
  9.     ULONG                          ulIndex = 0;  
  10.   
  11.     // 转换  
  12.     PCHAR                          pszNtosName = NULL;  
  13.     ANSI_STRING                     Ansi_szNtosName;  
  14.     UNICODE_STRING                Unicode_szNtosName;  
  15.   
  16.     __try  
  17.     {  
  18.         do  
  19.         {  
  20.             ntStatus = ZwQuerySystemInformation(SystemModuleInformation, NULL, 0, &ulSize);  
  21.             if (STATUS_INFO_LENGTH_MISMATCH != ntStatus)  
  22.             {  
  23.                 break;  
  24.             }  
  25.   
  26.             psmi = (PRTL_PROCESS_MODULES)ExAllocatePoolWithTag(NonPagedPool, ulSize, '0YGH');  
  27.             if (NULL == psmi)  
  28.             {  
  29.                 break;  
  30.             }  
  31.   
  32.             ntStatus = ZwQuerySystemInformation(SystemModuleInformation,  
  33.                 psmi, ulSize, &ulSize);  
  34.             if (STATUS_SUCCESS != ntStatus)  
  35.             {  
  36.                 break;  
  37.             }  
  38.   
  39.             //遍历打印:  
  40.             //for (ulIndex = 0; ulIndex<psmi->NumberOfModules; ulIndex++)  
  41.             //{  
  42.             //  KdPrint(("[ModInfo]-nIndex:%u--base:%p--size:%p--name:%s\n", ulIndex, psmi->Modules[ulIndex].ImageBase, psmi->Modules[ulIndex].ImageSize, psmi->Modules[ulIndex].FullPathName));  
  43.             //}  
  44.   
  45.             if (pNtosPath)  
  46.             {  
  47.                 memset(pNtosPath, 0, sizeof(WCHAR)*nSize);  
  48.                 wcscpy(pNtosPath, L"\\SystemRoot\\system32\\");  
  49.                 pszNtosName = psmi->Modules[0].FullPathName+psmi->Modules[0].OffsetToFileName;  
  50.                 RtlInitAnsiString(&Ansi_szNtosName, pszNtosName);  
  51.                 RtlAnsiStringToUnicodeString( &Unicode_szNtosName, &Ansi_szNtosName, TRUE);  
  52.                 wcsncpy(pNtosPath+wcslen(pNtosPath), Unicode_szNtosName.Buffer,Unicode_szNtosName.Length);  
  53.                 RtlFreeUnicodeString(&Unicode_szNtosName);  
  54.             }  
  55.   
  56.             if (pNtosModBase  
  57.                 &&MmIsAddressValid(pNtosModBase))  
  58.             {  
  59.                 *pNtosModBase = psmi->Modules[0].ImageBase;  
  60.             }  
  61.   
  62.             if (pNtosModSize  
  63.                 &&MmIsAddressValid(pNtosModSize))  
  64.             {  
  65.                 *pNtosModSize = psmi->Modules[0].ImageSize;  
  66.             }  
  67.   
  68.         } while (FALSE);  
  69.   
  70.     }  
  71.     __except(EXCEPTION_EXECUTE_HANDLER)  
  72.     {  
  73.   
  74.     }  
  75.   
  76.     if (NULL != psmi)  
  77.     {  
  78.         ExFreePool(psmi);  
  79.         psmi = NULL;  
  80.     }  
  81.   
  82.     return ntStatus;  
  83. }  

2.通过路径读取文件内容



[cpp] view plain copy

  1. NTSTATUS ReadFileToBuf(WCHAR *pFilePath, PVOID *ppBuf, PULONG_PTR pulSize)  
  2. {  
  3.     NTSTATUS                        ntStatus = STATUS_UNSUCCESSFUL;  
  4.     HANDLE                        hFile = NULL;  
  5.     OBJECT_ATTRIBUTES              obj;  
  6.     UNICODE_STRING                  Unicode_FilePath;  
  7.     IO_STATUS_BLOCK              iosb = {0};  
  8.     IO_STATUS_BLOCK              io_readsb = {0};  
  9.     FILE_STANDARD_INFORMATION      fInfo = {0};  
  10.     ULONG_PTR                      ulSize = 0;  
  11.     PVOID                          pBuf = NULL;  
  12.   
  13.     do  
  14.     {  
  15.         RtlInitUnicodeString(&Unicode_FilePath, pFilePath);  
  16.         InitializeObjectAttributes(&obj, &Unicode_FilePath, OBJ_CASE_INSENSITIVE, NULL, NULL);  
  17.   
  18.         ntStatus = ZwOpenFile(&hFile, SYNCHRONIZE, &obj, &iosb, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT);  
  19.         if (STATUS_SUCCESS != ntStatus)  
  20.         {  
  21.             break;  
  22.         }  
  23.   
  24.         ntStatus = ZwQueryInformationFile(hFile,  
  25.             &iosb,  
  26.             &fInfo,  
  27.             sizeof(FILE_STANDARD_INFORMATION),  
  28.             FileStandardInformation  
  29.             );  
  30.         if (STATUS_SUCCESS != ntStatus)  
  31.         {  
  32.             break;  
  33.         }  
  34.   
  35.         ulSize = fInfo.EndOfFile.LowPart;  
  36.         pBuf = ExAllocatePoolWithTag(PagedPool, ulSize+1024, '0YHG');  
  37.         if (NULL == pBuf)  
  38.         {  
  39.             break;  
  40.         }  
  41.   
  42.         ntStatus = ZwReadFile(hFile,  
  43.             NULL,  
  44.             NULL,  
  45.             NULL,  
  46.             &io_readsb,  
  47.             pBuf,  
  48.             ulSize,  
  49.             0,  
  50.             NULL);  
  51.         if (STATUS_SUCCESS != ntStatus)  
  52.         {  
  53.             break;  
  54.         }  
  55.   
  56.         if (io_readsb.Information != ulSize)  
  57.         {  
  58.             ntStatus = STATUS_UNSUCCESSFUL;  
  59.             break;  
  60.         }  
  61.   
  62.         // 赋值  
  63.         if (pulSize)  
  64.         {  
  65.             *pulSize = ulSize;  
  66.         }  
  67.         if (ppBuf)  
  68.         {  
  69.             *ppBuf = pBuf;  
  70.         }  
  71.   
  72.     } while (FALSE);  
  73.   
  74.     if (hFile)  
  75.     {  
  76.         ZwClose(hFile);  
  77.         hFile = NULL;  
  78.     }  
  79.   
  80.     if (STATUS_SUCCESS != ntStatus)  
  81.     {  
  82.         if (pBuf)  
  83.         {  
  84.             ExFreePool(pBuf);  
  85.             pBuf = NULL;  
  86.         }  
  87.     }  
  88.   
  89.     return ntStatus;  
  90. }  

3.按镜像大小分配内存,一般建议分 配多一点,并映射MDL得到虚拟地址可读可写可执行


[cpp] view plain copy

  1. NTSTATUS MemoryMapMdl(PVOID pBase, ULONG ulSize, PMDL* ppMdl, PVOID* ppMapBase)  
  2. {  
  3.     NTSTATUS                        ntStatus = STATUS_UNSUCCESSFUL;  
  4.     PMDL                            pMdl = NULL;  
  5.     PVOID                          pMdlVA = NULL;  
  6.   
  7.     do  
  8.     {  
  9.         pMdl = IoAllocateMdl(pBase, ulSize, FALSE, FALSE, NULL);  
  10.         if (NULL == pMdl)  
  11.         {  
  12.             break;  
  13.         }  
  14.   
  15.         __try  
  16.         {  
  17.             // 锁住,避免被page out,直接会导致MmGetSystemAddressForMdl蓝屏  
  18.             MmProbeAndLockPages(pMdl, KernelMode, IoModifyAccess);  
  19.             //MmBuildMdlForNonPagedPool(pMdl);//如果是非分页内存,可以使用这个,使用这个就不需要MmUnmapLockedPages&MmUnlockPages了  
  20.         }  
  21.         __except(EXCEPTION_EXECUTE_HANDLER)  
  22.         {  
  23.             IoFreeMdl(pMdl);  
  24.             break;  
  25.         }  
  26.   
  27.         pMdlVA = MmMapLockedPagesSpecifyCache(pMdl, KernelMode, MmCached, NULL, FALSE, NormalPagePriority);  
  28.         if (NULL == pMdlVA)  
  29.         {  
  30.             MmUnlockPages(pMdl);  
  31.             IoFreeMdl(pMdl);  
  32.             break;  
  33.         }  
  34.   
  35.         ntStatus = MmProtectMdlSystemAddress(pMdl, PAGE_EXECUTE_READWRITE);  
  36.         if (STATUS_SUCCESS != ntStatus)  
  37.         {  
  38.             MmUnmapLockedPages(pMdlVA, pMdl);  
  39.             MmUnlockPages(pMdl);  
  40.             IoFreeMdl(pMdl);  
  41.             break;  
  42.         }  
  43.   
  44.         // 赋值  
  45.         if (ppMapBase && MmIsAddressValid(ppMapBase))  
  46.         {  
  47.             *ppMapBase = pMdlVA;  
  48.         }  
  49.   
  50.         if (ppMdl && MmIsAddressValid(ppMdl))  
  51.         {  
  52.             *ppMdl = pMdl;  
  53.         }  
  54.   
  55.     } while (FALSE);  
  56.   
  57.     return ntStatus;  
  58. }  

4.对MDL映射出来的内存清0,再复制Header,复制section


NTSTATUS CopySections(PVOID pBase, PVOID pData, PIMAGE_NT_HEADERS pNtHdr){ULONG                           ulIndex = 0;PIMAGE_SECTION_HEADER            pSectionHdr = IMAGE_FIRST_SECTION(pNtHdr); for (ulIndex=0; ulIndex<pNtHdr->FileHeader.NumberOfSections; ulIndex++){RtlCopyMemory((PUCHAR)pBase+pSectionHdr->VirtualAddress, (PUCHAR)pData+pSectionHdr->PointerToRawData, pSectionHdr->SizeOfRawData);pSectionHdr++;} return STATUS_SUCCESS;}5.修复IAT
5.1 像查找NTOS一样查找到依赖的dll的基地址
5.2 根据函数名搜索依赖的dll的导出表,找到函数地址,填充
5.3 在校验NTOS时,注意原始NTOS的导入表为init的,所以不存在了,需查看IAT表(12序号)



[cpp] view plain copy

  1. NTSTATUS BuildNtosImportTable(PVOID pBase)  
  2. {  
  3.     PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pBase;  
  4.     PIMAGE_NT_HEADERS pNt = NULL;  
  5.     PIMAGE_IMPORT_DESCRIPTOR pImport = NULL;  
  6.     PIMAGE_THUNK_DATA pOrigThunk = NULL;  
  7.     PIMAGE_THUNK_DATA pFirstThunk = NULL;  
  8.     PIMAGE_IMPORT_BY_NAME pName = NULL;  
  9.     ULONG_PTR FunctionAddr = 0;  
  10.     ULONG_PTR ModBase = 0;  
  11.   
  12.     if (NULL == pDos  
  13.         || IMAGE_DOS_SIGNATURE != pDos->e_magic)  
  14.     {  
  15.         return STATUS_INVALID_IMAGE_FORMAT;  
  16.     }  
  17.   
  18.     pNt = (PIMAGE_NT_HEADERS)((PUCHAR)pBase+pDos->e_lfanew);  
  19.     if (IMAGE_NT_SIGNATURE != pNt->Signature)  
  20.     {  
  21.         return STATUS_INVALID_IMAGE_FORMAT;  
  22.     }  
  23.   
  24.     if (0 == pNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size)  
  25.     {  
  26.         return STATUS_SUCCESS;  
  27.     }  
  28.   
  29.     pImport = (PIMAGE_IMPORT_DESCRIPTOR)((PUCHAR)pBase+pNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);  
  30.   
  31.     while (NULL !=pImport  
  32.         && MmIsAddressValid(pImport)  
  33.         &&pImport->Name != 0)  
  34.     {  
  35.         // 获得模块基地址  
  36.         if (STATUS_SUCCESS != GetModuleInfo((PCHAR)((PUCHAR)pBase+pImport->Name), &ModBase))  
  37.         {  
  38.             return STATUS_UNSUCCESSFUL;  
  39.         }  
  40.         KdPrint(("[BuildNtosImportTable]-ModName:%s, ModBase:%p\n",(PCHAR)((PUCHAR)pBase+pImport->Name), ModBase));  
  41.   
  42.         if (pImport->OriginalFirstThunk)  
  43.         {  
  44.             pOrigThunk = (PIMAGE_THUNK_DATA)((PUCHAR)pBase+pImport->OriginalFirstThunk);  
  45.             pFirstThunk = (PIMAGE_THUNK_DATA)((PUCHAR)pBase+pImport->FirstThunk);  
  46.         }  
  47.         else  
  48.         {  
  49.             pOrigThunk = (PIMAGE_THUNK_DATA)((PUCHAR)pBase+pImport->FirstThunk);  
  50.             pFirstThunk = (PIMAGE_THUNK_DATA)((PUCHAR)pBase+pImport->FirstThunk);  
  51.         }  
  52.   
  53.         while (pOrigThunk->u1.Ordinal)  
  54.         {  
  55.             // 序号导入  
  56.             if (IMAGE_SNAP_BY_ORDINAL(pOrigThunk->u1.Ordinal))  
  57.             {  
  58.                 FunctionAddr = GetExportFunAddr(ModBase,FALSE, NULL, pOrigThunk->u1.Ordinal& ~IMAGE_ORDINAL_FLAG32);  
  59.             }  
  60.             else  
  61.             {  
  62.                 pName = (PIMAGE_IMPORT_BY_NAME)((PUCHAR)pBase+pOrigThunk->u1.Ordinal);  
  63.                 FunctionAddr = GetExportFunAddr(ModBase, TRUE, pName->Name, 0);  
  64.                 KdPrint(("[BuildNtosImportTable]-Mod:%s, Fun:%s[%p]\r\n",(PCHAR)((PUCHAR)pBase+pImport->Name), pName->Name, FunctionAddr));  
  65.             }  
  66.   
  67.             if (FunctionAddr)  
  68.             {  
  69.                 pFirstThunk->u1.Function = FunctionAddr;  
  70.             }  
  71.             else  
  72.             {  
  73.                 KdPrint(("[BuildNtosImportTable]-Function fail\n"));  
  74.             }  
  75.   
  76.             pOrigThunk++;  
  77.             pFirstThunk++;  
  78.         }  
  79.   
  80.         pImport++;  
  81.     }  
  82.   
  83.     return STATUS_SUCCESS;  
  84. }  

6.修复重定位表,其目的是使用同一份全局变量,所以重定位差值一定要是原始NTOS-0X400000(OptionalHeader.ImageBase)


[cpp] view plain copy

  1. NTSTATUS BuildNtosRelocTable(PVOID pBase,PVOID pSysBase)  
  2. {  
  3.     PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pBase;  
  4.     PIMAGE_NT_HEADERS pNt = NULL;  
  5.     PIMAGE_BASE_RELOCATION pBaseReloc = NULL;  
  6.   
  7.     ULONG_PTR ulDiff = 0;  
  8.   
  9.   
  10.     if (NULL == pDos  
  11.         || IMAGE_DOS_SIGNATURE != pDos->e_magic)  
  12.     {  
  13.         return STATUS_INVALID_IMAGE_FORMAT;  
  14.     }  
  15.   
  16.     pNt = (PIMAGE_NT_HEADERS)((PUCHAR)pBase+pDos->e_lfanew);  
  17.     if (IMAGE_NT_SIGNATURE != pNt->Signature)  
  18.     {  
  19.         return STATUS_INVALID_IMAGE_FORMAT;  
  20.     }  
  21.   
  22.     if (0 == pNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size)  
  23.     {  
  24.         return STATUS_SUCCESS;  
  25.     }  
  26.   
  27.     pBaseReloc = (PIMAGE_BASE_RELOCATION)((PCHAR)pBase+pNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);  
  28.     if (NULL == pBaseReloc)  
  29.     {  
  30.         return STATUS_SUCCESS;  
  31.     }  
  32.   
  33.     ulDiff = (ULONG_PTR)pSysBase - (ULONG_PTR)pNt->OptionalHeader.ImageBase;  
  34.   
  35.     if (pBaseReloc->SizeOfBlock>sizeof(IMAGE_BASE_RELOCATION))  
  36.     {  
  37.         do  
  38.         {  
  39.             ULONG ulCount = (pBaseReloc->SizeOfBlock-sizeof(IMAGE_BASE_RELOCATION))/sizeof(USHORT);  
  40.             PUSHORT pItem = (PUSHORT)((PCHAR)pBaseReloc+sizeof(IMAGE_BASE_RELOCATION));  
  41.             PULONG_PTR pRelocTarget = NULL;  
  42.             ULONG ulIndex = 0;  
  43.             for (ulIndex = 0; ulIndex<ulCount; ulIndex++)  
  44.             {  
  45.                 //高四位类型:  
  46.                 // IMAGE_REL_BASED_ABSOLUTE:无具体含义,仅是让每个段4字节对齐  
  47.                 // IMAGE_REL_BASED_HIGHLOW:重定位指向的整个地址都要被修正,基本是这个情况  
  48.                 // IMAGE_REL_BASED_DIR64:出现在64位PE文件中,对指向的整个地址修正.  
  49.                 ULONG ulType = pItem[ulIndex]>>12;// 高4位  
  50.                 ULONG ulOffset = pItem[ulIndex] & 0xFFF;// 低12位  
  51.                 switch (ulType)  
  52.                 {  
  53.                 case IMAGE_REL_BASED_HIGHLOW:  
  54.                 case IMAGE_REL_BASED_DIR64:  
  55.                     {  
  56.                         pRelocTarget = (PULONG_PTR)((PCHAR)pBase+ulOffset+pBaseReloc->VirtualAddress);  
  57.                         *pRelocTarget += ulDiff;// 跳转到原始的全局变量  
  58.   
  59.                     }  
  60.                     break;  
  61.   
  62.                 default:  
  63.                     break;  
  64.                 }  
  65.   
  66.             }  
  67.   
  68.             pBaseReloc = (PIMAGE_BASE_RELOCATION)((PCHAR)pBaseReloc+pBaseReloc->SizeOfBlock);  
  69.         } while (pBaseReloc->SizeOfBlock);//Vista的内核下,最后一个的VirtualAddress有可能不为0!  
  70.     }  
  71.   
  72.     return STATUS_SUCCESS;  
  73. }  

7.修复SSDT表(仅X86下适用)
7.1 这时可以用.reload /i 来再加载一份NT的pdb,可以看到,新的NT的SSDT对象内容全为0,所以需要重建:


[cpp] view plain copy

  1. // 仅在X86下使用  
  2. void SetNewSSDT(PVOID pNewBase,PVOID pSysBase)  
  3. {  
  4.     //禁止写保护,不然蓝屏  
  5.   
  6.     ULONG ulOffset = (ULONG)pNewBase - (ULONG)pSysBase;  
  7.     ULONG ulIndex = 0;  
  8.   
  9.     DisablePageWriteProtection  
  10.     g_pNewSSDT = (PKSERVICE_TABLE_DESCRIPTOR)((PCHAR)KeServiceDescriptorTable+ulOffset);  
  11.     if (!MmIsAddressValid(g_pNewSSDT))  
  12.     {  
  13.         g_pNewSSDT = NULL;  
  14.         return;  
  15.     }  
  16.   
  17.   
  18.     g_pNewSSDT->TableSize = KeServiceDescriptorTable->TableSize;  
  19.     g_pNewSSDT->ServiceTableBase = (PULONG)((PCHAR)KeServiceDescriptorTable->ServiceTableBase+ulOffset);  
  20.     g_pNewSSDT->ArgumentTable = (PUCHAR)((PCHAR)KeServiceDescriptorTable->ArgumentTable+ulOffset);  
  21.     if (!MmIsAddressValid(g_pNewSSDT->ServiceTableBase)  
  22.         ||!MmIsAddressValid(g_pNewSSDT->ArgumentTable))  
  23.     {  
  24.         g_pNewSSDT = NULL;  
  25.         return;  
  26.     }  
  27.   
  28.     for (ulIndex=0; ulIndex<g_pNewSSDT->TableSize; ulIndex++)  
  29.     {  
  30.         // 函数偏移要变  
  31.         g_pNewSSDT->ServiceTableBase[ulIndex] += ulOffset;  
  32.     }  
  33.   
  34.     // 参数不变  
  35.     memcpy(g_pNewSSDT->ArgumentTable, KeServiceDescriptorTable->ArgumentTable, KeServiceDescriptorTable->TableSize);  
  36.   
  37.     //恢复写保护  
  38.     EnablePageWriteProtection  
  39. }  


8.hook管家的函数,实现SSDT分发


[cpp] view plain copy

  1. ULONG __stdcall KiFastCallEntry_Filter(ULONG ulSyscallId,  
  2.                                        ULONG ulSyscallAddr,  
  3.                                        PULONG pulSyscallTable)  
  4. {  
  5.     ULONG ulRet = 0;  
  6.     pfn_KiFastCallEntry_Filter pfn = (pfn_KiFastCallEntry_Filter)QQHookZone;  
  7.     //KdPrint(("[KiFastCallEntry_Filter]-ulSyscallId:%d,ulSyscallAddr:0x%08x,pulSyscallTable:0x%08x\n",ulSyscallId, ulSyscallAddr, pulSyscallTable));  
  8.     ulRet = pfn(ulSyscallId, ulSyscallAddr, pulSyscallTable);  
  9.   
  10.     if (pulSyscallTable == KeServiceDescriptorTable->ServiceTableBase)  
  11.     {  
  12.         if (g_pNewSSDT)  
  13.         {  
  14.             if (!_strnicmp((char*)PsGetCurrentProcess()+0x174,"cheatengine-", 10))  
  15.             {  
  16.                 ulRet = g_pNewSSDT->ServiceTableBase[ulSyscallId];  
  17.             }  
  18.         }  
  19.     }  
  20.   
  21.     return ulRet;  
  22. }  

注意:比如只针对CE,那么 CE必须先关闭,再释放驱动,不然极可能蓝屏掉(蓝屏在重载 的NTOS中)
以下代 码 在装了QQ管家+CE下,可以查看被保护的内存(如NP)
离线v2680267313

只看该作者 沙发  发表于: 2016-04-30
用户被禁言,该主题自动屏蔽!
快速回复
限100 字节
如果您提交过一次失败了,可以用”恢复数据”来恢复帖子内容
 
上一个 下一个