首页
论坛
课程
招聘
[原创]寻找原始表,恢复 ssdt 表
2007-8-17 19:28 27410

[原创]寻找原始表,恢复 ssdt 表

dummy 活跃值
23
2007-8-17 19:28
27410
// 只贴 ring3 部分,这也是最主要的代码,驱动只是负责把得到的原始值写到 ssdt,其他啥也不做
// 简单说一下,找 KiServiceTable 表过程, 是直接读取原始内核文件,寻找输出符号,然后结合重定位信息,谁向 KeServiceDescriptorTable 赋值,从而确定 KiServiceTable 的位置。
// 这是第一写驱动相关的代码,写的很挫,高手就不用看了。

#include <tchar.h>
#include <Windows.h>
#include <winioctl.h>
#include "RSSDT.h"
/*
// RSSDT.h

typedef struct _tagSST_ENTRY
{
        ULONG cbSize;
        ULONG Index;
        ULONG OrgValue;                // 类型 RVA, 传给驱动的时做 Set Value
        ULONG NowValue; // 类型 RVA, 传给驱动做 get value
} SST_ENTRY, *PSST_ENTRY;
#define IOCTL_RSSDT_ENTRY_SET        CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
*/

ULONG Rav2Raw(PVOID pFileData, ULONG rav)
{
        PIMAGE_DOS_HEADER pDosH;
        PIMAGE_NT_HEADERS pNtH;
        PIMAGE_SECTION_HEADER pSectH;
        ULONG Index;

        pDosH = (PIMAGE_DOS_HEADER)pFileData;
        pNtH = (PIMAGE_NT_HEADERS)((ULONG)pFileData + pDosH->e_lfanew);
        pSectH = IMAGE_FIRST_SECTION(pNtH);

        if ( rav >= 0 && rav < pSectH->VirtualAddress )
                return rav;

        for ( Index = 0; Index < pNtH->FileHeader.NumberOfSections; Index++ )
        {
                if ( rav >= pSectH->VirtualAddress && rav < pSectH->VirtualAddress + pSectH->Misc.VirtualSize )
                        return rav - pSectH->VirtualAddress + pSectH->PointerToRawData;
                pSectH++;
        }

        return (ULONG)-1;
}
PVOID NTAPI
GetImageDirEntry(
        IN ULONG ImageBase,
        IN ULONG DirIndex,
        OUT OPTIONAL PIMAGE_NT_HEADERS* ppNtH,
        OUT OPTIONAL PIMAGE_DATA_DIRECTORY* ppDataDir
        )
{
        PIMAGE_DOS_HEADER pDosH;
        PIMAGE_NT_HEADERS pNtH;
        PIMAGE_DATA_DIRECTORY pDataDir;

        pDosH = (PIMAGE_DOS_HEADER)ImageBase;
        if ( pDosH->e_magic != IMAGE_DOS_SIGNATURE )
        {
                return NULL;
        }
       
        pNtH = (PIMAGE_NT_HEADERS)(ImageBase + pDosH->e_lfanew);
        if ( pNtH->Signature != IMAGE_NT_SIGNATURE )
        {
                return NULL;
        }

        if ( ppNtH != NULL )
        {
                *ppNtH = pNtH;
        }
       
        pDataDir = &pNtH->OptionalHeader.DataDirectory[DirIndex];

        if ( pDataDir->VirtualAddress == 0 )
        {
                return NULL;
        }

        if ( ppDataDir != NULL )
        {
                *ppDataDir = pDataDir;
        }
       
        return (PVOID)(ImageBase + Rav2Raw((PVOID)ImageBase, pDataDir->VirtualAddress));
}

typedef BOOLEAN (NTAPI* LOOPUPXREF_CALLBACK)(PULONG RefAddr, PVOID Param);

ULONG NTAPI // 返回找到的引用个数
pLookupImageXRef(
        IN ULONG ImageBase, // 参考地址
        IN PIMAGE_DATA_DIRECTORY pBrDir,
        IN PIMAGE_BASE_RELOCATION pBr,
        IN ULONG SymAddr,
        IN LOOPUPXREF_CALLBACK LookupXRefCallback, // 回调
        IN PVOID pParam
        )
{
        ULONG nRefCount = 0;

        __try
        {
                ULONG Size = 0;
                while ( pBr->SizeOfBlock != 0 && Size < pBrDir->Size )
                {
                        PWORD pRelItem = (PWORD)(pBr + 1);
                        PIMAGE_BASE_RELOCATION pNextBr = (PIMAGE_BASE_RELOCATION)((ULONG)pBr + pBr->SizeOfBlock);

                        while ( (ULONG)pRelItem < (ULONG)pNextBr )
                        {
                                ULONG RefBlock = Rav2Raw((PVOID)ImageBase, pBr->VirtualAddress);

                                if ( (pRelItem[0] >> 12) == 3 )
                                {
                                        PULONG RefAddr = (PULONG)(ImageBase + RefBlock + (pRelItem[0] & 0x0FFF));

                                        // 验证内存是否有效
                                        if ( !IsBadReadPtr(RefAddr, 1) && RefAddr[0] == SymAddr )
                                        {
                                                nRefCount++;
                                                if ( LookupXRefCallback(RefAddr, pParam)  )
                                                        break;
                                        }
                                }
                               
                                pRelItem++;
                        }
                       
                        Size += pBr->SizeOfBlock;
                        pBr = pNextBr;
                }
        }
        __except ( EXCEPTION_EXECUTE_HANDLER )
        {
        //        DbgPrint("pLookupImageXRef: Found a Exception!\n");
        }
       
        return nRefCount;
}

ULONG NTAPI
LookupImageXRef(
        IN ULONG ImageBase, // 有效地址
        IN ULONG SymAddr,
        IN LOOPUPXREF_CALLBACK LookupXRefCallback, // 回调
        IN PVOID Param
        )
{
        if ( LookupXRefCallback != NULL )
        {
                PIMAGE_DATA_DIRECTORY pBrDir;
                PIMAGE_BASE_RELOCATION pBr;
               
                pBr = GetImageDirEntry(ImageBase, IMAGE_DIRECTORY_ENTRY_BASERELOC, NULL, &pBrDir);
                if ( pBr != NULL )
                {
                        return pLookupImageXRef(ImageBase, pBrDir, pBr, SymAddr, LookupXRefCallback, Param);
                }
        }

        return 0;
}

typedef struct tag_SYSTEM_SERVICE_TABLE {
        PULONG        ServiceTable;        // array of entry points
        PULONG        CounterTable;        // array of usage counters
        ULONG        ServiceLimit;                // number of table entries
        PCHAR        ArgumentTable;        // array of argument counts
} SYSTEM_SERVICE_TABLE, *PSYSTEM_SERVICE_TABLE, **PPSYSTEM_SERVICE_TABLE;

BOOLEAN WINAPI LookXRefCallback(PULONG pRefAddr, PVOID pParam)
{
        USHORT OpCode = *((PUSHORT)pRefAddr - 1);
        if ( OpCode == 0x05C7 ) // mov     ds:_KeServiceDescriptorTable, offset _KiServiceTable
        {
                if ( pParam != NULL )
                {
                        *(PULONG)pParam = pRefAddr[1]; // KiServiceTable
                }

                return FALSE;
        }

        return TRUE;
}

BOOL GetSSTEntry(PCTSTR pszServiceName, PSST_ENTRY pSSTEntry)
{
        HANDLE hFile, hFileMap;
        LPVOID pFileData;
        HMODULE hNtdll;
        FARPROC pfnService;
        BOOL bResult;
        TCHAR szNtoskrnlPath[MAX_PATH];
       
        hNtdll = GetModuleHandle(_T("ntdll.dll"));
        pfnService = GetProcAddress(hNtdll, pszServiceName);
        if ( pfnService == NULL || *(PBYTE)pfnService != 0xB8 )
                return FALSE;

        // mov eax, ??
        pSSTEntry->Index = *(PULONG)((PBYTE)pfnService + 1);

        GetSystemDirectory(szNtoskrnlPath, MAX_PATH);
        _tcscat(szNtoskrnlPath, _T("\\ntoskrnl.exe")); // or ntkrnlpa.exe
       
        hFile = CreateFile(szNtoskrnlPath, GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ,
                NULL, OPEN_EXISTING, 0, NULL);
        if ( hFile == INVALID_HANDLE_VALUE )
                return FALSE;

        hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
        CloseHandle(hFile);

        if ( hFileMap == NULL )
                return FALSE;
       
        pFileData = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0);
        CloseHandle(hFileMap);
       
        if ( NULL == pFileData )
                return FALSE;
       
        bResult = FALSE;
        __try
        {
                PIMAGE_DOS_HEADER pDosH;
                PIMAGE_NT_HEADERS pNtH;
                PIMAGE_EXPORT_DIRECTORY pExpDir;
                PULONG pFunName, pFunAddr;
                PUSHORT pFunNameOrd;
                ULONG Index;
               
                pDosH = (PIMAGE_DOS_HEADER)pFileData;
                pNtH = (PIMAGE_NT_HEADERS)((ULONG)pFileData + pDosH->e_lfanew);
                pExpDir = (PIMAGE_EXPORT_DIRECTORY)((ULONG)pFileData + pNtH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);

                pFunName = (PULONG)((ULONG)pFileData + Rav2Raw(pFileData, pExpDir->AddressOfNames));
                pFunNameOrd = (PUSHORT)((ULONG)pFileData + Rav2Raw(pFileData, pExpDir->AddressOfNameOrdinals));
                pFunAddr = (PULONG)((ULONG)pFileData + Rav2Raw(pFileData, pExpDir->AddressOfFunctions));

                for ( Index = 0; Index < pExpDir->NumberOfNames; Index++ )               
                {
                        PCSTR pName = (PCSTR)((ULONG)pFileData + Rav2Raw(pFileData, pFunName[Index]));
                        if ( strcmp(pName, "KeServiceDescriptorTable") == 0 )
                        {
                                ULONG _KiServiceTable, _KeServiceDescriptorTable; // 类型都是 va
                               
                                _KiServiceTable = 0;
                                _KeServiceDescriptorTable = pNtH->OptionalHeader.ImageBase + pFunAddr[pFunNameOrd[Index]];
       
                                LookupImageXRef((ULONG)pFileData, _KeServiceDescriptorTable, LookXRefCallback, &_KiServiceTable);
                                if ( _KiServiceTable != 0 )
                                {
                                        PULONG ServiceTable;
                                        _KiServiceTable -= pNtH->OptionalHeader.ImageBase;

                                        ServiceTable = (PULONG)((ULONG)pFileData + Rav2Raw(pFileData, _KiServiceTable));
                                        pSSTEntry->OrgValue = ServiceTable[pSSTEntry->Index] - pNtH->OptionalHeader.ImageBase;
                                }

                                bResult = TRUE;
                                break;
                        }
                }
        }
        __except ( EXCEPTION_EXECUTE_HANDLER )
        {
                bResult = FALSE;
        }

        UnmapViewOfFile(pFileData);
        return bResult;

}

HANDLE GetServiceByName(IN PCTSTR pszServiceName, OUT OPTIONAL SC_HANDLE* pScManager)
{
        SC_HANDLE hScManager, hScService;
       
        hScService = NULL;
        hScManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
       
        if ( pScManager != NULL )
                *pScManager = hScManager;

        if ( hScManager != NULL )
        {
                hScService = OpenService(hScManager, pszServiceName, SERVICE_ALL_ACCESS);
                if ( pScManager == NULL )
                        CloseServiceHandle(hScManager);
        }

        return hScService;
}

SC_HANDLE InstallDriver(IN PCTSTR pszServiceName, IN PCTSTR pszDriverFile)
{
        SC_HANDLE hScManager, hScService;
       
        hScManager = NULL;
        hScService = GetServiceByName(pszServiceName, &hScManager);

        if ( hScService == NULL && hScManager != NULL )
        {
                hScService = CreateService(hScManager, pszServiceName, pszServiceName, SERVICE_ALL_ACCESS,
                        SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, pszDriverFile, NULL,
                        NULL, NULL, NULL, NULL
                        );
//                GetLastError();
        }

        if ( hScManager != NULL )
                CloseServiceHandle(hScManager);
       
        return hScService;
}

BOOL UninstallDriver(SC_HANDLE hScService)
{
        SERVICE_STATUS Status;
       
        if ( ControlService(hScService, SERVICE_CONTROL_STOP, &Status) )
        {
                DeleteService(hScService);
                CloseServiceHandle(hScService);

                return TRUE;
        }
//        GetLastError();

        return FALSE;
}

BOOL ResetSSTEntry(PCSTR lpServiceName)
{
        SC_HANDLE hScService;
        HANDLE hDevice;
        SST_ENTRY SstEntry;
        ULONG cbReturn;
        TCHAR szDriverPath[MAX_PATH];
        PTSTR pszDriverName;
        BOOL bResult;

        SstEntry.cbSize = sizeof (SST_ENTRY);
        if ( !GetSSTEntry(lpServiceName, &SstEntry) )
                return FALSE;
       
        GetModuleFileName(NULL, szDriverPath, MAX_PATH);
        pszDriverName = _tcsrchr(szDriverPath, _T('\\'));
        _tcscpy(pszDriverName, _T("\\RSSDT.sys"));
       
        hScService = GetServiceByName(_T("RSSDT"), NULL);
        if ( hScService == NULL )
        {
                hScService = InstallDriver(_T("RSSDT"), szDriverPath);
                if ( hScService == NULL )
                        return FALSE;
        }

        bResult = FALSE;
        if ( StartService(hScService, 0, NULL) || GetLastError() == ERROR_ALREADY_EXISTS )
        {
                hDevice = CreateFile(_T("\\\\.\\RSSDT"),
                        GENERIC_READ,
                        FILE_SHARE_READ | FILE_SHARE_WRITE,
                        NULL,
                        OPEN_EXISTING,
                        0,
                        NULL
                        );
                GetLastError();

                if ( hDevice != INVALID_HANDLE_VALUE )
                {
                        bResult = DeviceIoControl(hDevice, IOCTL_RSSDT_ENTRY_SET, &SstEntry, sizeof (SstEntry),
                                &SstEntry, sizeof (SstEntry), &cbReturn, NULL);

                        CloseHandle(hDevice);
                }
        }

        UninstallDriver(hScService);
        return bResult;
}

#if 1
int __cdecl main()
{
        ResetSSTEntry("NtCreateKey");
        ResetSSTEntry("NtCreatePagingFile");
        ResetSSTEntry("NtEnumerateValueKey");
        ResetSSTEntry("NtOpenKey");
        ResetSSTEntry("NtQueryKey");
        ResetSSTEntry("NtQueryValueKey");
        ResetSSTEntry("NtSetSystemPowerState");

        return 0;
}

#endif

[招生]科锐逆向工程师培训46期预科班将于 2023年02月09日 正式开班

收藏
点赞0
打赏
分享
最新回复 (14)
雪    币: 326
活跃值: 活跃值 (15)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
快雪时晴 活跃值 4 2007-8-17 20:31
2
0
我太菜,不懂驱动
雪    币: 38
活跃值: 活跃值 (16)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
炉子 活跃值 3 2007-8-17 23:46
3
0
直接让驱动读KeServiceDescriptorTable的内容来获取KiServiceTable的偏移,然后dump硬盘文件的表,基本就完成了。。恩。。。。不过这样得到的KiServiceTable并非总是可靠。

以前写的ssdtviewer代码给扔掉了。汗-。-
雪    币: 244
活跃值: 活跃值 (121)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xicao 活跃值 2007-8-19 09:25
4
0
如何判断系统当前用的是ntoskrnl.exe、ntkrnlpa.exe或者其他的?
雪    币: 38
活跃值: 活跃值 (16)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
炉子 活跃值 3 2007-8-19 12:21
5
0
用ZwQuerySystemInformation查询SystemModuleInformation 第一个模块就是ntxxxxxx.exe的文件地址
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
sheeee 活跃值 2007-8-19 12:25
6
0
我怎么看不懂这个
雪    币: 235
活跃值: 活跃值 (27)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zhtjia 活跃值 2007-8-24 11:10
7
0
把RING0的也贴上来吧
雪    币: 203
活跃值: 活跃值 (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
herotheo 活跃值 2009-4-30 20:05
8
0
哎。。。ring0 下的ssdt  让我号难过
雪    币: 732
活跃值: 活跃值 (284)
能力值: ( LV9,RANK:200 )
在线值:
发帖
回帖
粉丝
房有亮 活跃值 3 2009-10-1 13:03
9
0
帖子虽然好 但是没有注释 令我们这些新手看的好难呀
雪    币: 732
活跃值: 活跃值 (284)
能力值: ( LV9,RANK:200 )
在线值:
发帖
回帖
粉丝
房有亮 活跃值 3 2009-10-1 13:06
10
0
我现在查找原始表的 方法是用特征码定位函头后的地址,然后减去长度 一般都能成功。
雪    币: 96
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
收破烂的 活跃值 2010-1-8 16:18
11
0
很好。谢谢楼主的建议。。下来试试
雪    币: 32
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
godmans 活跃值 2010-1-30 19:16
12
0
经实测,LZ的代码在我电脑上不行,要把
    pExpDir = (PIMAGE_EXPORT_DIRECTORY)((ULONG)pFileData + pNtH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
改成
        pExpDir = (PIMAGE_EXPORT_DIRECTORY)ImageRvaToVa(pNtH,pDosH,pNtH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress,0);
就可以了。
雪    币: 75
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lastshoot 活跃值 2010-4-9 11:09
13
0
#include <tchar.h>
#include <Windows.h>
#include <winioctl.h>
#include "RSSDT.h"
/*
// RSSDT.h

typedef struct _tagSST_ENTRY
{
  ULONG cbSize;
  ULONG Index;
  ULONG OrgValue;    // 类型 RVA, 传给驱动的时做 Set Value
  ULONG NowValue; // 类型 RVA, 传给驱动做 get value
} SST_ENTRY, *PSST_ENTRY;
#define IOCTL_RSSDT_ENTRY_SET  CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
*/

ULONG Rav2Raw(PVOID pFileData, ULONG rav) //  重定位 RAV转raw:内存相对偏移转数据在文件中相对偏移 、第一个参数为文件指针

{
  PIMAGE_DOS_HEADER pDosH;
  PIMAGE_NT_HEADERS pNtH;
  PIMAGE_SECTION_HEADER pSectH;
  ULONG Index;

  pDosH = (PIMAGE_DOS_HEADER)pFileData;  //dos头地址
  pNtH = (PIMAGE_NT_HEADERS)((ULONG)pFileData + pDosH->e_lfanew);//PE文件头地址
  pSectH = IMAGE_FIRST_SECTION(pNtH); //节表第一个元素地址

  if ( rav >= 0 && rav < pSectH->VirtualAddress )  //  如果该内存地址相对偏移落在节表第一个元素地址的相对偏移之前表示不是节表里的东西,地址不需要重定位
    return rav;

  for ( Index = 0; Index < pNtH->FileHeader.NumberOfSections; Index++ )
  {
    if ( rav >= pSectH->VirtualAddress && rav < pSectH->VirtualAddress + pSectH->Misc.VirtualSize )  //  地址落在该节表之内
      return rav - pSectH->VirtualAddress + pSectH->PointerToRawData; //   节表头文件相对偏移+该内存地址相对偏移-节表头内存相对偏移

   
    pSectH++;
  }

  return (ULONG)-1;
}
PVOID NTAPI
GetImageDirEntry(
  IN ULONG ImageBase,
  IN ULONG DirIndex,
  OUT OPTIONAL PIMAGE_NT_HEADERS* ppNtH,
  OUT OPTIONAL PIMAGE_DATA_DIRECTORY* ppDataDir
  ) //  根据数组索引找到PE文件可选头内的数据目录结构数组元素指针(ppDataDir)和指针所指数据块的文件地址(返回值)
{
  PIMAGE_DOS_HEADER pDosH;
  PIMAGE_NT_HEADERS pNtH;
  PIMAGE_DATA_DIRECTORY pDataDir;

  pDosH = (PIMAGE_DOS_HEADER)ImageBase;
  if ( pDosH->e_magic != IMAGE_DOS_SIGNATURE )
  {
    return NULL;
  }
  
  pNtH = (PIMAGE_NT_HEADERS)(ImageBase + pDosH->e_lfanew);
  if ( pNtH->Signature != IMAGE_NT_SIGNATURE )
  {
    return NULL;
  }

  if ( ppNtH != NULL )
  {
    *ppNtH = pNtH;
  }
  
  pDataDir = &pNtH->OptionalHeader.DataDirectory[DirIndex];

  if ( pDataDir->VirtualAddress == 0 )
  {
    return NULL;
  }

  if ( ppDataDir != NULL )
  {
    *ppDataDir = pDataDir;
  }
  
  return (PVOID)(ImageBase + Rav2Raw((PVOID)ImageBase, pDataDir->VirtualAddress));
}

typedef BOOLEAN (NTAPI* LOOPUPXREF_CALLBACK)(PULONG RefAddr, PVOID Param);

ULONG NTAPI // 返回找到的引用个数
pLookupImageXRef(
  IN ULONG ImageBase, // 参考地址
  IN PIMAGE_DATA_DIRECTORY pBrDir,//数据目录结构数组元素内存指针
  IN PIMAGE_BASE_RELOCATION pBr, //指针所指数据块的文件地址
  IN ULONG SymAddr,//要查找的地址
  IN LOOPUPXREF_CALLBACK LookupXRefCallback, // 回调
  IN PVOID pParam
  )
{
  ULONG nRefCount = 0;

  __try
  {
    ULONG Size = 0;
    while ( pBr->SizeOfBlock != 0 && Size < pBrDir->Size )

//单重定位块的长度如果=0表示读到所有重定位块的最后 如果长度超过整个大块的总长度也结束

   {
      PWORD pRelItem = (PWORD)(pBr + 1);

//IMAGE_BASE_RELOCATION结构后的实际重定位项(十六位)、因为pBr本身是IMAGE_BASE_RELOCATION类型的、指针+1=指针地址+sizeof(IMAGE_BASE_RELOCATION)
      PIMAGE_BASE_RELOCATION pNextBr = (PIMAGE_BASE_RELOCATION)((ULONG)pBr + pBr->SizeOfBlock); //下一个单重定位块

      while ( (ULONG)pRelItem < (ULONG)pNextBr )
      {
        ULONG RefBlock = Rav2Raw((PVOID)ImageBase, pBr->VirtualAddress);根据单个重定位内存块的起始RVA得到重定位内存块的文件相对偏移地址
        if ( (pRelItem[0] >> 12) == 3 )  //十六位偏移中的4位用于重定位种类、只有值0和3可用
        {
          PULONG RefAddr = (PULONG)(ImageBase + RefBlock + (pRelItem[0] & 0x0FFF));//将具体需要重定位的代码地址转为该代码所在实际文件地址

          // 验证内存是否有效
          if ( !IsBadReadPtr(RefAddr, 1) && RefAddr[0] == SymAddr )
          {
            nRefCount++;
            if ( LookupXRefCallback(RefAddr, pParam)  ) //在文件里找需要重定位Keservi**地址的语句,并把实际Ki***地址写进pParam并中断
              break;
          }
        }
        
        pRelItem++;
      }
      
      Size += pBr->SizeOfBlock;
      pBr = pNextBr;
    }
  }
  __except ( EXCEPTION_EXECUTE_HANDLER )
  {
  //  DbgPrint("pLookupImageXRef: Found a Exception!\n");
  }
  
  return nRefCount;
}

ULONG NTAPI
LookupImageXRef(
  IN ULONG ImageBase, // 有效地址
  IN ULONG SymAddr,//要查找的地址keservicede***
  IN LOOPUPXREF_CALLBACK LookupXRefCallback, // 回调
  IN PVOID Param //最终ki***的地址写回这个参数
  )
{
  if ( LookupXRefCallback != NULL )
  {
    PIMAGE_DATA_DIRECTORY pBrDir;
    PIMAGE_BASE_RELOCATION pBr;
   
    pBr = GetImageDirEntry(ImageBase, IMAGE_DIRECTORY_ENTRY_BASERELOC, NULL, &pBrDir);
    if ( pBr != NULL )
    {
      return pLookupImageXRef(ImageBase, pBrDir, pBr, SymAddr, LookupXRefCallback, Param);
    }
  }

  return 0;
}

typedef struct tag_SYSTEM_SERVICE_TABLE {
  PULONG  ServiceTable;  // array of entry points
  PULONG  CounterTable;  // array of usage counters
  ULONG  ServiceLimit;    // number of table entries
  PCHAR  ArgumentTable;  // array of argument counts
} SYSTEM_SERVICE_TABLE, *PSYSTEM_SERVICE_TABLE, **PPSYSTEM_SERVICE_TABLE;

BOOLEAN WINAPI LookXRefCallback(PULONG pRefAddr, PVOID pParam)
{
  USHORT OpCode = *((PUSHORT)pRefAddr - 1);
  if ( OpCode == 0x05C7 ) // 0x05C7:mov指令     ds:_KeServiceDe  script  orTable, offset _KiServiceTable
  {
    if ( pParam != NULL )
    {
      *(PULONG)pParam = pRefAddr[1]; // KiServiceTable
    }

    return FALSE;
  }

  return TRUE;
}

BOOL GetSSTEntry(PCTSTR pszServiceName, PSST_ENTRY pSSTEntry)     //根据函数名查找 函数在SSDT表入口地址

{
  HANDLE hFile, hFileMap;
  LPVOID pFileData;
  HMODULE hNtdll;
  FARPROC pfnService;
  BOOL bResult;
  TCHAR szNtoskrnlPath[MAX_PATH];
  
  hNtdll = GetModuleHandle(_T("ntdll.dll"));
  pfnService = GetProcAddress(hNtdll, pszServiceName);  //得到NTDLL导出的相应函数内存地址
  if ( pfnService == NULL || *(PBYTE)pfnService != 0xB8 ) //第一个字符必然是MOV

    return FALSE;

  // mov eax, ??
  pSSTEntry->Index = *(PULONG)((PBYTE)pfnService + 1); //第2个必然是在SSDT表中的服务号、也就是说NTDLL下的导出函数NT***、开始第一句话类似mov     eax,7Ah           函数服务号

  GetSystemDirectory(szNtoskrnlPath, MAX_PATH);
  _tcscat(szNtoskrnlPath, _T("\\ntoskrnl.exe")); // or ntkrnlpa.exe
  
  hFile = CreateFile(szNtoskrnlPath, GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ,
    NULL, OPEN_EXISTING, 0, NULL);
  if ( hFile == INVALID_HANDLE_VALUE )
    return FALSE;

  hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
  CloseHandle(hFile);

  if ( hFileMap == NULL )
    return FALSE;
  
  pFileData = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0);
  CloseHandle(hFileMap);   //ntoskrnl.exe建立内存映射文件
  
  if ( NULL == pFileData )
    return FALSE;
  
  bResult = FALSE;
  __try
  {
    PIMAGE_DOS_HEADER pDosH;
    PIMAGE_NT_HEADERS pNtH;
    PIMAGE_EXPORT_DIRECTORY pExpDir;
    PULONG pFunName, pFunAddr;
    PUSHORT pFunNameOrd;
    ULONG Index;
   
    pDosH = (PIMAGE_DOS_HEADER)pFileData;
    pNtH = (PIMAGE_NT_HEADERS)((ULONG)pFileData + pDosH->e_lfanew);
    pExpDir = (PIMAGE_EXPORT_DIRECTORY)((ULONG)pFileData + pNtH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);  //ntoskrnl.exe文件中导出函数的地址

    pFunName = (PULONG)((ULONG)pFileData + Rav2Raw(pFileData, pExpDir->AddressOfNames)); //导出函数名表的地址
    pFunNameOrd = (PUSHORT)((ULONG)pFileData + Rav2Raw(pFileData, pExpDir->AddressOfNameOrdinals)); //函数名序号表的地址

    pFunAddr = (PULONG)((ULONG)pFileData + Rav2Raw(pFileData, pExpDir->AddressOfFunctions)); //导出函数地址表的地址

    for ( Index = 0; Index < pExpDir->NumberOfNames; Index++ )   
    {
      PCSTR pName = (PCSTR)((ULONG)pFileData + Rav2Raw(pFileData, pFunName[Index]));
      if ( strcmp(pName, "KeServiceDe  script  orTable") == 0 ) //如果符合记住在字符串地址表中的索引、然后在addressofnameordinals指向的数组中用同样的索引值取出数组项的值,再以这个值为索引找AddressOfFunctions,就是函数入口地址
      {
        ULONG _KiServiceTable, _KeServiceDe  script  orTable; // 类型都是 va
        
        _KiServiceTable = 0;
        _KeServiceDe  script  orTable = pNtH->OptionalHeader.ImageBase + pFunAddr[pFunNameOrd[Index]];
  
        LookupImageXRef((ULONG)pFileData, _KeServiceDe  script  orTable, LookXRefCallback, &_KiServiceTable);//在文件中找KiServiceTable的地址,因为KiServiceTable没有导出
        if ( _KiServiceTable != 0 )
        {
          PULONG ServiceTable;
          _KiServiceTable -= pNtH->OptionalHeader.ImageBase;//RVA

          ServiceTable = (PULONG)((ULONG)pFileData + Rav2Raw(pFileData, _KiServiceTable));//实际文件地址
          pSSTEntry->OrgValue = ServiceTable[pSSTEntry->Index] - pNtH->OptionalHeader.ImageBase;//  实际处理函数地址RVA
        }

        bResult = TRUE;
        break;
      }
    }
  }
  __except ( EXCEPTION_EXECUTE_HANDLER )
  {
    bResult = FALSE;
  }

  UnmapViewOfFile(pFileData);
  return bResult;

}

HANDLE GetServiceByName(IN PCTSTR pszServiceName, OUT OPTIONAL SC_HANDLE* pScManager)
{
  SC_HANDLE hScManager, hScService;
  
  hScService = NULL;
  hScManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  
  if ( pScManager != NULL )
    *pScManager = hScManager;

  if ( hScManager != NULL )
  {
    hScService = OpenService(hScManager, pszServiceName, SERVICE_ALL_ACCESS);
    if ( pScManager == NULL )
      CloseServiceHandle(hScManager);
  }

  return hScService;
}

SC_HANDLE InstallDriver(IN PCTSTR pszServiceName, IN PCTSTR pszDriverFile)
{
  SC_HANDLE hScManager, hScService;
  
  hScManager = NULL;
  hScService = GetServiceByName(pszServiceName, &hScManager);

  if ( hScService == NULL && hScManager != NULL )
  {
    hScService = CreateService(hScManager, pszServiceName, pszServiceName, SERVICE_ALL_ACCESS,
      SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, pszDriverFile, NULL,
      NULL, NULL, NULL, NULL
      );
//    GetLastError();
  }

  if ( hScManager != NULL )
    CloseServiceHandle(hScManager);
  
  return hScService;
}

BOOL UninstallDriver(SC_HANDLE hScService)
{
  SERVICE_STATUS Status;
  
  if ( ControlService(hScService, SERVICE_CONTROL_STOP, &Status) )
  {
    DeleteService(hScService);
    CloseServiceHandle(hScService);

    return TRUE;
  }
//  GetLastError();

  return FALSE;
}

BOOL ResetSSTEntry(PCSTR lpServiceName)
{
  SC_HANDLE hScService;
  HANDLE hDevice;
  SST_ENTRY SstEntry;
  ULONG cbReturn;
  TCHAR szDriverPath[MAX_PATH];
  PTSTR pszDriverName;
  BOOL bResult;

  SstEntry.cbSize = sizeof (SST_ENTRY);
  if ( !GetSSTEntry(lpServiceName, &SstEntry) )
    return FALSE;
  
  GetModuleFileName(NULL, szDriverPath, MAX_PATH);
  pszDriverName = _tcsrchr(szDriverPath, _T('\\'));
  _tcscpy(pszDriverName, _T("\\RSSDT.sys"));
  
  hScService = GetServiceByName(_T("RSSDT"), NULL);
  if ( hScService == NULL )
  {
    hScService = InstallDriver(_T("RSSDT"), szDriverPath);
    if ( hScService == NULL )
      return FALSE;
  }

  bResult = FALSE;
  if ( StartService(hScService, 0, NULL) || GetLastError() == ERROR_ALREADY_EXISTS )
  {
    hDevice = CreateFile(_T("\\\\.\\RSSDT"),
      GENERIC_READ,
      FILE_SHARE_READ | FILE_SHARE_WRITE,
      NULL,
      OPEN_EXISTING,
      0,
      NULL
      );
    GetLastError();

    if ( hDevice != INVALID_HANDLE_VALUE )
    {
      bResult = DeviceIoControl(hDevice, IOCTL_RSSDT_ENTRY_SET, &SstEntry, sizeof (SstEntry),
        &SstEntry, sizeof (SstEntry), &cbReturn, NULL);

      CloseHandle(hDevice);
    }
  }

  UninstallDriver(hScService);
  return bResult;
}

#if 1
int __cdecl main()
{
  ResetSSTEntry("NtCreateKey");
  ResetSSTEntry("NtCreatePagingFile");
  ResetSSTEntry("NtEnumerateValueKey");
  ResetSSTEntry("NtOpenKey");
  ResetSSTEntry("NtQueryKey");
  ResetSSTEntry("NtQueryValueKey");
  ResetSSTEntry("NtSetSystemPowerState");

  return 0;
}

#endif
雪    币: 104
活跃值: 活跃值 (11)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
huyongtq 活跃值 2010-4-14 10:41
14
0
这个到底是应用层的代码还是RING0的代码呀? 看得我云里雾里了,

#if 1
int __cdecl main()
{
  ResetSSTEntry("NtCreateKey");
  ResetSSTEntry("NtCreatePagingFile");
  ResetSSTEntry("NtEnumerateValueKey");
  ResetSSTEntry("NtOpenKey");
  ResetSSTEntry("NtQueryKey");
  ResetSSTEntry("NtQueryValueKey");
  ResetSSTEntry("NtSetSystemPowerState");

  return 0;
}

#endif

最后出现 这个 #endif 我就蒙了
雪    币: 24
活跃值: 活跃值 (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
shinck 活跃值 2013-8-6 15:23
15
0
[QUOTE=godmans;754756]经实测,LZ的代码在我电脑上不行,要把
    pExpDir = (PIMAGE_EXPORT_DIRECTORY)((ULONG)pFileData + pNtH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Virtu...[/QUOTE]

我也是这种情况
游客
登录 | 注册 方可回帖
返回