Windows xp 重载内核(使用Irp进行文件操作)

一、前言

  最近在阅读A盾代码A盾电脑防护(原名 3600safe)anti-rootkit开放源代码,有兴趣的可以去看雪论坛下载,本文代码摘自其中的重载内核。

二、实现步骤

  1.ZwQuerySystemInformation大法获得系统模块信息 NtosKrnl.exe 这里第一模块名称是根据单核、多核、开启PAE、未开启PAE变化的
  2.自己Reload一个内核模块,打开、获得文件大小、读入内存,这里都用到Irp的操作
      irpSp->Parameters.MountVolume.Vpb->RealDevice卷设备
      VPB是Volume parameter block一个数据结构,把实际存储媒介设备对象和文件系统上的卷设备对象联系起来。
      利用Irp请求对文件进行操作是防止Hook一些文件读取、查询的函数,除非是Hook了IoCallDriver函数,不过也会对这个函数进行监测,具体可以看<寒江独钓><文件系统开发教程>(楚狂人 谭文)
  3.将读入的内存按照内存中的位置放置。VirtualAglin = 0x1000对齐
  4.根据DriverSection枚举内核模块,修复Reload的导入信息
  5.修复重定位表信息
  6.根据重定位表中的偏移比较获得 , 在Reload中的SSDT地址的偏移
  7.将Reload的SSDT函数地址写入我们的全局变量 SSDT中
  8.MmGetSystemRoutine获得Reload中函数的地址

三、代码实现

  1.获得模块信息

  通过ZwQuerySystemInformation函数传入宏SystemModuleInformation,返回内核模块信息。

/*ZwQuerySystemInformation大法 枚举模块信息  获得第一模块  Ntos..*/
BOOLEAN GetSystemKernelModuleInfo(WCHAR **SystemKernelModulePath,PDWORD SystemKernelModuleBase,PDWORD SystemKernelModuleSize)
{
    NTSTATUS status;
    ULONG ulSize,i;
    PMODULES pModuleList;
    char *lpszKernelName=NULL;
    ANSI_STRING AnsiKernelModule;
    UNICODE_STRING UnicodeKernelModule;
    BOOLEAN bRet=TRUE;

    __try
    {
        status=ZwQuerySystemInformation(
            SystemModuleInformation,
            NULL,
            0,
            &ulSize
            );
        if (status!=STATUS_INFO_LENGTH_MISMATCH)
        {
            return NULL;
        }
        pModuleList=(PMODULES)ExAllocatePool(NonPagedPool,ulSize);
        if (pModuleList)
        {
            status=ZwQuerySystemInformation(
                SystemModuleInformation,
                pModuleList,
                ulSize,
                &ulSize
                );
            if (!NT_SUCCESS(status))
            {
                bRet = FALSE;
            }
        }
        if (!bRet)
        {
            if (pModuleList)
                ExFreePool(pModuleList);
            return NULL;
        }
        *SystemKernelModulePath=ExAllocatePool(NonPagedPool,260*2);
        if (*SystemKernelModulePath==NULL)
        {
            *SystemKernelModuleBase=0;
            *SystemKernelModuleSize=0;
            return NULL;
        }

        lpszKernelName = pModuleList->smi[0].ModuleNameOffset+pModuleList->smi[0].ImageName;  //第一模块名称
        RtlInitAnsiString(&AnsiKernelModule,lpszKernelName);
        RtlAnsiStringToUnicodeString(&UnicodeKernelModule,&AnsiKernelModule,TRUE);

        RtlZeroMemory(*SystemKernelModulePath,260*2);
        wcscat(*SystemKernelModulePath,L"\SystemRoot\system32\");

        memcpy(
            *SystemKernelModulePath+wcslen(L"\SystemRoot\system32\"),    //第一模块路径
            UnicodeKernelModule.Buffer,
            UnicodeKernelModule.Length
            );

        *SystemKernelModuleBase=(DWORD)pModuleList->smi[0].Base;   //获得第一模块地址
        *SystemKernelModuleSize=(DWORD)pModuleList->smi[0].Size;   //获得第一模块大小
        ExFreePool(pModuleList);
        RtlFreeUnicodeString(&UnicodeKernelModule);

    }__except(EXCEPTION_EXECUTE_HANDLER){

    }
    return TRUE;
}

  

  2.Reload Pe

/*
system32//NtosKrnl.exe .. 
*/
BOOLEAN PeLoad(
    WCHAR *FileFullPath,
    BYTE **ImageModeleBase,
    PDRIVER_OBJECT DeviceObject,
    DWORD ExistImageBase
    )
{
    NTSTATUS Status;
    HANDLE hFile;
    LARGE_INTEGER FileSize;
    DWORD Length;
    BYTE *FileBuffer;
    BYTE *ImageBase;
    IO_STATUS_BLOCK IoStatus;
    //SystemRootsystem32
tkrnlpa.exe
    Status=KernelOpenFile(FileFullPath,&hFile,0x100020,0x80,1,1,0x20);  //自己创建文件对象, 并返回文件句柄,irp
    if (!NT_SUCCESS(Status))
    {
        return FALSE;
    }

    Status=KernelGetFileSize(hFile,&FileSize);  //读取irp信息,返回filesize
    if (!NT_SUCCESS(Status))
    {
        ZwClose(hFile);
        return FALSE;
    }
    Length=FileSize.LowPart;
    FileBuffer=ExAllocatePool(PagedPool,Length);
    if (FileBuffer==NULL)
    {
        ZwClose(hFile);
        return FALSE;
    }

    Status=KernelReadFile(hFile,NULL,Length,FileBuffer,&IoStatus); //传入文件句柄、文件大小 通过irp请求,读取文件到内存中
    if (!NT_SUCCESS(Status))
    {
        ZwClose(hFile);
        ExFreePool(FileBuffer);
        return FALSE;
    }
    ZwClose(hFile);


    if(!ImageFile(FileBuffer,&ImageBase))   //修复FileBuffer中的偏移  按照VirtualAglin  对齐    得到全局ImageModuleBase
    {
        ExFreePool(FileBuffer);
        return FALSE;
    }
    ExFreePool(FileBuffer);

    //2k3下MiFindExportedRoutine调用失败
    if(!FixImportTable(ImageBase,ExistImageBase,DeviceObject)) //修复导入表
    {
        ExFreePool(ImageBase);
        return FALSE;
    }
    if(!FixBaseRelocTable(ImageBase,ExistImageBase))  //修复重定位表
    {
        ExFreePool(ImageBase);
        return FALSE;
    }

    *ImageModeleBase=ImageBase; //得到最后的基地址   就是 和 原来内存中格式一样的 一块ntos

    return TRUE;
}

  3.按VirtualAglin对齐

/*
修复FileBuffer中的偏移  按照VirtualAglin  对齐  
filebuffer 为读取的内存  ,ImageModuleBase为系统中的模块地址
*/
BOOLEAN ImageFile(BYTE *FileBuffer,BYTE **ImageModuleBase)
{
    PIMAGE_DOS_HEADER ImageDosHeader;
    PIMAGE_NT_HEADERS ImageNtHeaders;
    PIMAGE_SECTION_HEADER ImageSectionHeader;
    DWORD FileAlignment,SectionAlignment,NumberOfSections,SizeOfImage,SizeOfHeaders;
    DWORD Index;
    BYTE *ImageBase;
    DWORD SizeOfNtHeaders;
    ImageDosHeader=(PIMAGE_DOS_HEADER)FileBuffer;
    if (ImageDosHeader->e_magic!=IMAGE_DOS_SIGNATURE)
    {
        return FALSE;
    }
    ImageNtHeaders=(PIMAGE_NT_HEADERS)(FileBuffer+ImageDosHeader->e_lfanew);
    if (ImageNtHeaders->Signature!=IMAGE_NT_SIGNATURE)
    {
        return FALSE;
    }
    FileAlignment=ImageNtHeaders->OptionalHeader.FileAlignment;//0x200
    SectionAlignment=ImageNtHeaders->OptionalHeader.SectionAlignment;//0x1000
    NumberOfSections=ImageNtHeaders->FileHeader.NumberOfSections;//0x16
    SizeOfImage=ImageNtHeaders->OptionalHeader.SizeOfImage;//0x412000
    SizeOfHeaders=ImageNtHeaders->OptionalHeader.SizeOfHeaders;//0x800

    SizeOfImage=AlignSize(SizeOfImage,SectionAlignment);//0x412000

    ImageBase=ExAllocatePool(NonPagedPool,SizeOfImage);
    if (ImageBase==NULL)
    {
        return FALSE;
    }
    RtlZeroMemory(ImageBase,SizeOfImage);
    //0xf8
    SizeOfNtHeaders=sizeof(ImageNtHeaders->FileHeader) + sizeof(ImageNtHeaders->Signature)+ImageNtHeaders->FileHeader.SizeOfOptionalHeader;
    ImageSectionHeader=(PIMAGE_SECTION_HEADER)((DWORD)ImageNtHeaders+SizeOfNtHeaders);
    for (Index=0;Index<NumberOfSections;Index++)
    {
        ImageSectionHeader[Index].SizeOfRawData=AlignSize(ImageSectionHeader[Index].SizeOfRawData,FileAlignment);
        ImageSectionHeader[Index].Misc.VirtualSize=AlignSize(ImageSectionHeader[Index].Misc.VirtualSize,SectionAlignment);
    }
    if (ImageSectionHeader[NumberOfSections-1].VirtualAddress+ImageSectionHeader[NumberOfSections-1].SizeOfRawData>SizeOfImage)
    {//no in
        ImageSectionHeader[NumberOfSections-1].SizeOfRawData = SizeOfImage-ImageSectionHeader[NumberOfSections-1].VirtualAddress;
    }
    RtlCopyMemory(ImageBase,FileBuffer,SizeOfHeaders);

    for (Index=0;Index<NumberOfSections;Index++)
    {
        DWORD FileOffset=ImageSectionHeader[Index].PointerToRawData;
        DWORD Length=ImageSectionHeader[Index].SizeOfRawData;
        DWORD ImageOffset=ImageSectionHeader[Index].VirtualAddress;
        RtlCopyMemory(&ImageBase[ImageOffset],&FileBuffer[FileOffset],Length);
    }
    *ImageModuleBase=ImageBase;

    return TRUE;


}

ULONG AlignSize(ULONG nSize, ULONG nAlign)
{
    return ((nSize + nAlign - 1) / nAlign * nAlign);
}

  4.修复导入表,这里利用DriverObject->DriverSection遍历内核模块,找出导入表相等的模块,根据序号或者名称修复导入表

//修复导入表
BOOLEAN FixImportTable(BYTE *ImageBase,DWORD ExistImageBase,PDRIVER_OBJECT DriverObject)
{
    PIMAGE_IMPORT_DESCRIPTOR ImageImportDescriptor=NULL;
    PIMAGE_THUNK_DATA ImageThunkData,FirstThunk;
    PIMAGE_IMPORT_BY_NAME ImortByName;
    DWORD ImportSize;
    PVOID ModuleBase;
    char ModuleName[260];
    DWORD FunctionAddress;
    //得到导入表地址
    ImageImportDescriptor=(PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData(ImageBase,TRUE,IMAGE_DIRECTORY_ENTRY_IMPORT,&ImportSize);
    if (ImageImportDescriptor==NULL)
    {
        return FALSE;
    }
    while (ImageImportDescriptor->OriginalFirstThunk&&ImageImportDescriptor->Name)
    {
        strcpy(ModuleName,(char*)(ImageBase+ImageImportDescriptor->Name));  //导入信息名称

        //ntoskrnl.exe(NTKRNLPA.exe、ntkrnlmp.exe、ntkrpamp.exe):
        if (_stricmp(ModuleName,"ntkrnlpa.exe")==0||
            _stricmp(ModuleName,"ntoskrnl.exe")==0||
            _stricmp(ModuleName,"ntkrnlmp.exe")==0||
            _stricmp(ModuleName,"ntkrpamp.exe")==0)
        {//no in
            ModuleBase=GetKernelModuleBase(DriverObject,"ntkrnlpa.exe");  //通过DriverObject->DriverSection 遍历内核模块
            if (ModuleBase==NULL)
            {
                ModuleBase=GetKernelModuleBase(DriverObject,"ntoskrnl.exe");
                if (ModuleBase==NULL)
                {
                    ModuleBase=GetKernelModuleBase(DriverObject,"ntkrnlmp.exe");
                    if (ModuleBase==NULL)
                    {
                        ModuleBase=GetKernelModuleBase(DriverObject,"ntkrpamp.exe");

                    }

                }
            }

        }
        else
        {
            ModuleBase=GetKernelModuleBase(DriverObject,ModuleName);

        }
        if (ModuleBase==NULL)
        {
            FirstThunk=(PIMAGE_THUNK_DATA)(ImageBase+ImageImportDescriptor->FirstThunk);
            InsertOriginalFirstThunk((DWORD)ImageBase,ExistImageBase,FirstThunk);
            ImageImportDescriptor++;
            continue;
        }
        //PSHED.dll
        ImageThunkData=(PIMAGE_THUNK_DATA)(ImageBase+ImageImportDescriptor->OriginalFirstThunk);
        FirstThunk=(PIMAGE_THUNK_DATA)(ImageBase+ImageImportDescriptor->FirstThunk);
        while(ImageThunkData->u1.Ordinal)
        {
            //序号导入
            if(IMAGE_SNAP_BY_ORDINAL32(ImageThunkData->u1.Ordinal))
            {
                //通过系统内核的导出表   名称- 获得 函数地址
                FunctionAddress=(DWORD)MiFindExportedRoutine(ModuleBase,FALSE,NULL,ImageThunkData->u1.Ordinal & ~IMAGE_ORDINAL_FLAG32);
                if (FunctionAddress==0)
                {
                    return FALSE;
                }
                FirstThunk->u1.Function=FunctionAddress;
            }
            //函数名导入
            else
            {
                //
                ImortByName=(PIMAGE_IMPORT_BY_NAME)(ImageBase+ImageThunkData->u1.AddressOfData);
                FunctionAddress=(DWORD)MiFindExportedRoutine(ModuleBase,TRUE,ImortByName->Name,0);
                if (FunctionAddress==0)
                {
                    return FALSE;
                }
                FirstThunk->u1.Function=FunctionAddress;
            }
            FirstThunk++;
            ImageThunkData++;
        }
        ImageImportDescriptor++;
    }
    return TRUE;
}

  5.修复重定位表

/*
重定位表  修复
*/
BOOLEAN
    FixBaseRelocTable (
    PVOID NewImageBase,
    DWORD ExistImageBase
    )
{
    LONGLONG Diff;
    ULONG TotalCountBytes = 0;
    ULONG_PTR VA;
    ULONGLONG OriginalImageBase;
    ULONG SizeOfBlock;
    PUCHAR FixupVA;
    USHORT Offset;
    PUSHORT NextOffset = NULL;
    PIMAGE_NT_HEADERS NtHeaders;
    PIMAGE_BASE_RELOCATION NextBlock;


    NtHeaders = RtlImageNtHeader( NewImageBase );
    if (NtHeaders == NULL) 
    {
        return FALSE;
    }

    switch (NtHeaders->OptionalHeader.Magic) {

    case IMAGE_NT_OPTIONAL_HDR32_MAGIC:

        OriginalImageBase =
            ((PIMAGE_NT_HEADERS32)NtHeaders)->OptionalHeader.ImageBase;
        break;

    case IMAGE_NT_OPTIONAL_HDR64_MAGIC:

        OriginalImageBase =
            ((PIMAGE_NT_HEADERS64)NtHeaders)->OptionalHeader.ImageBase;
        break;

    default:
        return FALSE;
    }

    //
    // Locate the relocation section.
    //

    NextBlock = (PIMAGE_BASE_RELOCATION)RtlImageDirectoryEntryToData(
        NewImageBase, TRUE, IMAGE_DIRECTORY_ENTRY_BASERELOC, &TotalCountBytes);

    //
    // It is possible for a file to have no relocations, but the relocations
    // must not have been stripped.
    //

    if (!NextBlock || !TotalCountBytes) 
    {

        if (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) 
        {
            DbgPrint("Image can't be relocated, no fixup information.
");
            return FALSE;

        }
        else 
        {
            return TRUE;
        }

    }

    //
    // If the image has a relocation table, then apply the specified fixup
    // information to the image.
    //
    Diff = (ULONG_PTR)ExistImageBase - OriginalImageBase;
    while (TotalCountBytes)
    {
        SizeOfBlock = NextBlock->SizeOfBlock;
        TotalCountBytes -= SizeOfBlock;
        SizeOfBlock -= sizeof(IMAGE_BASE_RELOCATION);
        SizeOfBlock /= sizeof(USHORT);
        NextOffset = (PUSHORT)((PCHAR)NextBlock + sizeof(IMAGE_BASE_RELOCATION));

        VA = (ULONG_PTR)NewImageBase + NextBlock->VirtualAddress;

        if ( !(NextBlock = LdrProcessRelocationBlockLongLong( VA,
            SizeOfBlock,
            NextOffset,
            Diff)) ) 
        {

            DbgPrint("%s: Unknown base relocation type
");
            return FALSE;

        }
    }

    return TRUE;
}



/*修复重定位表*/
PIMAGE_BASE_RELOCATION
    LdrProcessRelocationBlockLongLong(
    IN ULONG_PTR VA,
    IN ULONG SizeOfBlock,
    IN PUSHORT NextOffset,
    IN LONGLONG Diff
    )
{
    PUCHAR FixupVA;
    USHORT Offset;
    LONG Temp;
    ULONG Temp32;
    ULONGLONG Value64;
    LONGLONG Temp64;



    while (SizeOfBlock--) {

        Offset = *NextOffset & (USHORT)0xfff;
        FixupVA = (PUCHAR)(VA + Offset);

        //
        // Apply the fixups.
        //

        switch ((*NextOffset) >> 12) {

        case IMAGE_REL_BASED_HIGHLOW :
            //
            // HighLow - (32-bits) relocate the high and low half
            //      of an address.
            //
            *(LONG UNALIGNED *)FixupVA += (ULONG) Diff;
            break;

        case IMAGE_REL_BASED_HIGH :
            //
            // High - (16-bits) relocate the high half of an address.
            //
            Temp = *(PUSHORT)FixupVA << 16;
            Temp += (ULONG) Diff;
            *(PUSHORT)FixupVA = (USHORT)(Temp >> 16);
            break;

        case IMAGE_REL_BASED_HIGHADJ :
            //
            // Adjust high - (16-bits) relocate the high half of an
            //      address and adjust for sign extension of low half.
            //

            //
            // If the address has already been relocated then don't
            // process it again now or information will be lost.
            //
            if (Offset & LDRP_RELOCATION_FINAL) {
                ++NextOffset;
                --SizeOfBlock;
                break;
            }

            Temp = *(PUSHORT)FixupVA << 16;
            ++NextOffset;
            --SizeOfBlock;
            Temp += (LONG)(*(PSHORT)NextOffset);
            Temp += (ULONG) Diff;
            Temp += 0x8000;
            *(PUSHORT)FixupVA = (USHORT)(Temp >> 16);

            break;

        case IMAGE_REL_BASED_LOW :
            //
            // Low - (16-bit) relocate the low half of an address.
            //
            Temp = *(PSHORT)FixupVA;
            Temp += (ULONG) Diff;
            *(PUSHORT)FixupVA = (USHORT)Temp;
            break;

        case IMAGE_REL_BASED_IA64_IMM64:

            //
            // Align it to bundle address before fixing up the
            // 64-bit immediate value of the movl instruction.
            //

            FixupVA = (PUCHAR)((ULONG_PTR)FixupVA & ~(15));
            Value64 = (ULONGLONG)0;

            //
            // Extract the lower 32 bits of IMM64 from bundle
            //


            EXT_IMM64(Value64,
                (PULONG)FixupVA + EMARCH_ENC_I17_IMM7B_INST_WORD_X,
                EMARCH_ENC_I17_IMM7B_SIZE_X,
                EMARCH_ENC_I17_IMM7B_INST_WORD_POS_X,
                EMARCH_ENC_I17_IMM7B_VAL_POS_X);
            EXT_IMM64(Value64,
                (PULONG)FixupVA + EMARCH_ENC_I17_IMM9D_INST_WORD_X,
                EMARCH_ENC_I17_IMM9D_SIZE_X,
                EMARCH_ENC_I17_IMM9D_INST_WORD_POS_X,
                EMARCH_ENC_I17_IMM9D_VAL_POS_X);
            EXT_IMM64(Value64,
                (PULONG)FixupVA + EMARCH_ENC_I17_IMM5C_INST_WORD_X,
                EMARCH_ENC_I17_IMM5C_SIZE_X,
                EMARCH_ENC_I17_IMM5C_INST_WORD_POS_X,
                EMARCH_ENC_I17_IMM5C_VAL_POS_X);
            EXT_IMM64(Value64,
                (PULONG)FixupVA + EMARCH_ENC_I17_IC_INST_WORD_X,
                EMARCH_ENC_I17_IC_SIZE_X,
                EMARCH_ENC_I17_IC_INST_WORD_POS_X,
                EMARCH_ENC_I17_IC_VAL_POS_X);
            EXT_IMM64(Value64,
                (PULONG)FixupVA + EMARCH_ENC_I17_IMM41a_INST_WORD_X,
                EMARCH_ENC_I17_IMM41a_SIZE_X,
                EMARCH_ENC_I17_IMM41a_INST_WORD_POS_X,
                EMARCH_ENC_I17_IMM41a_VAL_POS_X);

            EXT_IMM64(Value64,
                ((PULONG)FixupVA + EMARCH_ENC_I17_IMM41b_INST_WORD_X),
                EMARCH_ENC_I17_IMM41b_SIZE_X,
                EMARCH_ENC_I17_IMM41b_INST_WORD_POS_X,
                EMARCH_ENC_I17_IMM41b_VAL_POS_X);
            EXT_IMM64(Value64,
                ((PULONG)FixupVA + EMARCH_ENC_I17_IMM41c_INST_WORD_X),
                EMARCH_ENC_I17_IMM41c_SIZE_X,
                EMARCH_ENC_I17_IMM41c_INST_WORD_POS_X,
                EMARCH_ENC_I17_IMM41c_VAL_POS_X);
            EXT_IMM64(Value64,
                ((PULONG)FixupVA + EMARCH_ENC_I17_SIGN_INST_WORD_X),
                EMARCH_ENC_I17_SIGN_SIZE_X,
                EMARCH_ENC_I17_SIGN_INST_WORD_POS_X,
                EMARCH_ENC_I17_SIGN_VAL_POS_X);
            //
            // Update 64-bit address
            //

            Value64+=Diff;

            //
            // Insert IMM64 into bundle
            //

            INS_IMM64(Value64,
                ((PULONG)FixupVA + EMARCH_ENC_I17_IMM7B_INST_WORD_X),
                EMARCH_ENC_I17_IMM7B_SIZE_X,
                EMARCH_ENC_I17_IMM7B_INST_WORD_POS_X,
                EMARCH_ENC_I17_IMM7B_VAL_POS_X);
            INS_IMM64(Value64,
                ((PULONG)FixupVA + EMARCH_ENC_I17_IMM9D_INST_WORD_X),
                EMARCH_ENC_I17_IMM9D_SIZE_X,
                EMARCH_ENC_I17_IMM9D_INST_WORD_POS_X,
                EMARCH_ENC_I17_IMM9D_VAL_POS_X);
            INS_IMM64(Value64,
                ((PULONG)FixupVA + EMARCH_ENC_I17_IMM5C_INST_WORD_X),
                EMARCH_ENC_I17_IMM5C_SIZE_X,
                EMARCH_ENC_I17_IMM5C_INST_WORD_POS_X,
                EMARCH_ENC_I17_IMM5C_VAL_POS_X);
            INS_IMM64(Value64,
                ((PULONG)FixupVA + EMARCH_ENC_I17_IC_INST_WORD_X),
                EMARCH_ENC_I17_IC_SIZE_X,
                EMARCH_ENC_I17_IC_INST_WORD_POS_X,
                EMARCH_ENC_I17_IC_VAL_POS_X);
            INS_IMM64(Value64,
                ((PULONG)FixupVA + EMARCH_ENC_I17_IMM41a_INST_WORD_X),
                EMARCH_ENC_I17_IMM41a_SIZE_X,
                EMARCH_ENC_I17_IMM41a_INST_WORD_POS_X,
                EMARCH_ENC_I17_IMM41a_VAL_POS_X);
            INS_IMM64(Value64,
                ((PULONG)FixupVA + EMARCH_ENC_I17_IMM41b_INST_WORD_X),
                EMARCH_ENC_I17_IMM41b_SIZE_X,
                EMARCH_ENC_I17_IMM41b_INST_WORD_POS_X,
                EMARCH_ENC_I17_IMM41b_VAL_POS_X);
            INS_IMM64(Value64,
                ((PULONG)FixupVA + EMARCH_ENC_I17_IMM41c_INST_WORD_X),
                EMARCH_ENC_I17_IMM41c_SIZE_X,
                EMARCH_ENC_I17_IMM41c_INST_WORD_POS_X,
                EMARCH_ENC_I17_IMM41c_VAL_POS_X);
            INS_IMM64(Value64,
                ((PULONG)FixupVA + EMARCH_ENC_I17_SIGN_INST_WORD_X),
                EMARCH_ENC_I17_SIGN_SIZE_X,
                EMARCH_ENC_I17_SIGN_INST_WORD_POS_X,
                EMARCH_ENC_I17_SIGN_VAL_POS_X);
            break;

        case IMAGE_REL_BASED_DIR64:

            *(ULONGLONG UNALIGNED *)FixupVA += Diff;

            break;

        case IMAGE_REL_BASED_MIPS_JMPADDR :
            //
            // JumpAddress - (32-bits) relocate a MIPS jump address.
            //
            Temp = (*(PULONG)FixupVA & 0x3ffffff) << 2;
            Temp += (ULONG) Diff;
            *(PULONG)FixupVA = (*(PULONG)FixupVA & ~0x3ffffff) |
                ((Temp >> 2) & 0x3ffffff);

            break;

        case IMAGE_REL_BASED_ABSOLUTE :
            //
            // Absolute - no fixup required.
            //
            break;

        case IMAGE_REL_BASED_SECTION :
            //
            // Section Relative reloc.  Ignore for now.
            //
            break;

        case IMAGE_REL_BASED_REL32 :
            //
            // Relative intrasection. Ignore for now.
            //
            break;

        default :
            //
            // Illegal - illegal relocation type.
            //

            return (PIMAGE_BASE_RELOCATION)NULL;
        }
        ++NextOffset;
    }
    return (PIMAGE_BASE_RELOCATION)NextOffset;
}

  6.获得ssdt在Reload中的偏移

//通过KeServiceDescriptorTable的RVA与重定位表项解析的地址RVA比较,一致则取出其中的SSDT表地址
BOOLEAN GetOriginalKiServiceTable(BYTE *NewImageBase,DWORD ExistImageBase,DWORD *NewKiServiceTable)
{
    PIMAGE_DOS_HEADER ImageDosHeader;
    PIMAGE_NT_HEADERS ImageNtHeaders;
    DWORD KeServiceDescriptorTableRva;
    PIMAGE_BASE_RELOCATION ImageBaseReloc=NULL;
    DWORD RelocSize;
    int ItemCount,Index;
    int Type;
    PDWORD RelocAddress;
    DWORD RvaData;
    DWORD count=0;
    WORD *TypeOffset;


    ImageDosHeader=(PIMAGE_DOS_HEADER)NewImageBase;
    if (ImageDosHeader->e_magic!=IMAGE_DOS_SIGNATURE)
    {
        return FALSE;
    }
    ImageNtHeaders=(PIMAGE_NT_HEADERS)(NewImageBase+ImageDosHeader->e_lfanew);
    if (ImageNtHeaders->Signature!=IMAGE_NT_SIGNATURE)
    {
        return FALSE;
    }
    KeServiceDescriptorTableRva=(DWORD)MiFindExportedRoutine(NewImageBase,TRUE,"KeServiceDescriptorTable",0);
    if (KeServiceDescriptorTableRva==0)
    {
        return FALSE;
    }

    KeServiceDescriptorTableRva=KeServiceDescriptorTableRva-(DWORD)NewImageBase;
    ImageBaseReloc=RtlImageDirectoryEntryToData(NewImageBase,TRUE,IMAGE_DIRECTORY_ENTRY_BASERELOC,&RelocSize);
    if (ImageBaseReloc==NULL)
    {
        return FALSE;
    }

    while (ImageBaseReloc->SizeOfBlock)
    {  
        count++;
        ItemCount=(ImageBaseReloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION))/2;
        TypeOffset=(WORD*)((DWORD)ImageBaseReloc+sizeof(IMAGE_BASE_RELOCATION));
        for (Index=0;Index<ItemCount;Index++)
        {
            Type=TypeOffset[Index]>>12;  //高4位是类型   低12位位页内偏移 4k  
            if (Type==3)
            {
                //Base + Virtual 定位到页   + 低12位  = RelocAddress 需要修复的地址
                RelocAddress=(PDWORD)((DWORD)(TypeOffset[Index]&0x0fff)+ImageBaseReloc->VirtualAddress+(DWORD)NewImageBase);
                RvaData=*RelocAddress-ExistImageBase;
                
                if (RvaData==KeServiceDescriptorTableRva)  //重定位表中的rva 是 KeServiceDescriptorTable 表项的
                {
                    if(*(USHORT*)((DWORD)RelocAddress-2)==0x05c7)
                    {
                        /*
                    1: kd> dd 0x89651c12   RelocAddress - 2
                    89651c12       79c005c7 bd9c83f8 

                    1: kd> dd KeServiceDescriptorTable           
                    83f879c0       83e9bd9c 00000000 00000191 83e9c3e4
                    83f879d0       00000000 00000000 00000000 00000000
                
                    1: kd> dd 0x89651c14        RelocAddress
                    89651c14       83f879c0 83e9bd9c 79c41589 c8a383f8
                    89651c24       c783f879 f879cc05 e9c3e483 d8158983
                        */
                        //RelocAddress 里面存放着 KeServiceDesriptorTable地址  
                        //RelocAddress + 4 存放着 KeServiceDesriptorTable第一成员也就是SSDT基址
                        *NewKiServiceTable=*(DWORD*)((DWORD)RelocAddress+4)-ExistImageBase+(DWORD)NewImageBase;
                        return TRUE;
                    }
                }

            }

        }
        ImageBaseReloc=(PIMAGE_BASE_RELOCATION)((DWORD)ImageBaseReloc+ImageBaseReloc->SizeOfBlock);
    }

    return FALSE;
}

  7.修复SSDT

VOID FixOriginalKiServiceTable(PDWORD OriginalKiServiceTable,DWORD ModuleBase,DWORD ExistImageBase)
{
    DWORD FuctionCount;
    DWORD Index;
    FuctionCount=KeServiceDescriptorTable->TableSize; //函数个数
    
    KdPrint(("ssdt funcion count:%X---KiServiceTable:%X
",FuctionCount,KeServiceDescriptorTable->ServiceTable));    
    for (Index=0;Index<FuctionCount;Index++)
    {
        OriginalKiServiceTable[Index]=OriginalKiServiceTable[Index]-ExistImageBase+ModuleBase; //修复SSDT函数地址
    }
}

  8.提供获取函数地址的函数 

/*
输入FuncName  、 原来Ntos地址  、自己重载 Ntos地址
//第一次都是通过  系统的原来偏移 + NewBase 获得函数地址  
//然后通过自己的RMmGetSystemRoutineAddress获得 偏移+NewBase 获得函数地址
还不能找到则遍历导出表
*/
ULONG ReLoadNtosCALL(WCHAR *lpwzFuncTion,ULONG ulOldNtosBase,ULONG ulReloadNtosBase)
{
    UNICODE_STRING UnicodeFunctionName;
    ULONG ulOldFunctionAddress;
    ULONG ulReloadFunctionAddress;
    int index=0;
    PIMAGE_DOS_HEADER pDosHeader;
    PIMAGE_NT_HEADERS NtDllHeader;

    IMAGE_OPTIONAL_HEADER opthdr;
    DWORD* arrayOfFunctionAddresses;
    DWORD* arrayOfFunctionNames;
    WORD* arrayOfFunctionOrdinals;
    DWORD functionOrdinal;
    DWORD Base, x, functionAddress,position;
    char* functionName;
    IMAGE_EXPORT_DIRECTORY *pExportTable;
    ULONG ulNtDllModuleBase;

    UNICODE_STRING UnicodeFunction;
    UNICODE_STRING UnicodeExportTableFunction;
    ANSI_STRING ExportTableFunction;
    //第一次都是通过  系统的原来偏移 + NewBase 获得函数地址  
    //然后通过自己的RMmGetSystemRoutineAddress获得 偏移+NewBase 获得函数地址
    __try
    {
        if (RRtlInitUnicodeString &&
            RRtlCompareUnicodeString &&
            RMmGetSystemRoutineAddress &&
            RMmIsAddressValid)
        {
            RRtlInitUnicodeString(&UnicodeFunctionName,lpwzFuncTion);
            ulOldFunctionAddress = (DWORD)RMmGetSystemRoutineAddress(&UnicodeFunctionName);
            ulReloadFunctionAddress = ulOldFunctionAddress - ulOldNtosBase + ulReloadNtosBase; //获得重载的FuncAddr
            if (RMmIsAddressValid(ulReloadFunctionAddress)) //如果无效就从 导出表  获取?  应该不会无效
            {
                return ulReloadFunctionAddress;
            }
            //从导出表里获取
            ulNtDllModuleBase = ulReloadNtosBase;
            pDosHeader = (PIMAGE_DOS_HEADER)ulReloadNtosBase;
            if (pDosHeader->e_magic!=IMAGE_DOS_SIGNATURE)
            {
                KdPrint(("failed to find NtHeader
"));
                return NULL;
            }
            NtDllHeader=(PIMAGE_NT_HEADERS)(ULONG)((ULONG)pDosHeader+pDosHeader->e_lfanew);
            if (NtDllHeader->Signature!=IMAGE_NT_SIGNATURE)
            {
                KdPrint(("failed to find NtHeader
"));
                return NULL;
            }
            opthdr = NtDllHeader->OptionalHeader;
            pExportTable =(IMAGE_EXPORT_DIRECTORY*)((BYTE*)ulNtDllModuleBase + opthdr.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT]. VirtualAddress); //得到导出表
            arrayOfFunctionAddresses = (DWORD*)( (BYTE*)ulNtDllModuleBase + pExportTable->AddressOfFunctions);  //地址表
            arrayOfFunctionNames = (DWORD*)((BYTE*)ulNtDllModuleBase + pExportTable->AddressOfNames);         //函数名表
            arrayOfFunctionOrdinals = (WORD*)((BYTE*)ulNtDllModuleBase + pExportTable->AddressOfNameOrdinals);

            Base = pExportTable->Base;

            for(x = 0; x < pExportTable->NumberOfFunctions; x++) //在整个导出表里扫描
            {
                functionName = (char*)( (BYTE*)ulNtDllModuleBase + arrayOfFunctionNames[x]);
                functionOrdinal = arrayOfFunctionOrdinals[x] + Base - 1; 
                functionAddress = (DWORD)((BYTE*)ulNtDllModuleBase + arrayOfFunctionAddresses[functionOrdinal]);
                RtlInitAnsiString(&ExportTableFunction,functionName);
                RtlAnsiStringToUnicodeString(&UnicodeExportTableFunction,&ExportTableFunction,TRUE);

                RRtlInitUnicodeString(&UnicodeFunction,lpwzFuncTion);
                if (RRtlCompareUnicodeString(&UnicodeExportTableFunction,&UnicodeFunction,TRUE) == 0)
                {
                    RtlFreeUnicodeString(&UnicodeExportTableFunction);
                    return functionAddress;
                }
                RtlFreeUnicodeString(&UnicodeExportTableFunction);
            }
            return NULL;
        }
        RtlInitUnicodeString(&UnicodeFunctionName,lpwzFuncTion);
        ulOldFunctionAddress = (DWORD)MmGetSystemRoutineAddress(&UnicodeFunctionName);
        ulReloadFunctionAddress = ulOldFunctionAddress - ulOldNtosBase + ulReloadNtosBase;

        //KdPrint(("%ws:%08x:%08x",lpwzFuncTion,ulOldFunctionAddress,ulReloadFunctionAddress));

        if (MmIsAddressValid(ulReloadFunctionAddress))
        {
            return ulReloadFunctionAddress;
        }
        //         

    }__except(EXCEPTION_EXECUTE_HANDLER){
        KdPrint(("EXCEPTION_EXECUTE_HANDLER"));
    }
    return NULL;
}

四、代码下载

  https://github.com/LycorisGuard/Windows-Rootkits/tree/master/ReloadKernel-XP

原文地址:https://www.cnblogs.com/aliflycoris/p/5450080.html