Showing posts with label ring3. Show all posts
Showing posts with label ring3. Show all posts

Saturday, September 24, 2011

[Text Vesion]Document-ize of ring3 api list diriver listing

Author:benyanwk
Code:
/*++
Module Name:
  ListDrvCon.cpp

Enviroment:
  All Windows NT Platfrom;Console

Abstract:
  List all the driver's name & baseaddr & fileaddr

Note:
  Using documented API in psapi.h

Revision:
  23-Nov-2008 Created.

--*/

//
// directives
//
#define MAXNUM 255
#define UNICODE  // to support chinese
#include <windows.h>
#include <psapi.h>
#include <stdio.h>
#pragma comment(lib,"psapi.lib")

//
// strcut defintion
//

typedef struct _DRIVER_INFO {
  WCHAR BaseName[MAX_PATH];
  WCHAR FileName[MAX_PATH];
  DWORD BaseAddr;
} DRIVER_INFO,*PDRIVER_INFO ;

typedef struct _ALL_DRIVER_INFO {
  DWORD cbNum;
  DRIVER_INFO DrvInfo[1];  // define variable length structure
} ALL_DRIVER_INFO,*PALL_DRIVER_INFO;

//
// function declaration
//
int main();
int myGetDriverInfo(
  IN PVOID &pDrvInfo,
  IN BOOLEAN bAlloc
  );

//
// function definition
//
int myGetDriverInfo(
  IN PALL_DRIVER_INFO* pDrvInfo, 
  IN BOOLEAN bAlloc
  )
{
/*++
Arguments:
  pDrvInfo-->the buffer to store the driver information
  bAlloc-->alloc the global memory by the function or not
  return 0 indicate success otherwise error
--*/
  DWORD cbNum = 0;
  PDWORD pBaseAddr = NULL ;
  PWCHAR pFileName = NULL;
  PWCHAR pBaseName = NULL;
  PALL_DRIVER_INFO pAllDrvInfo;

   
  pBaseAddr = (PDWORD)GlobalAlloc( GMEM_FIXED, sizeof(DWORD)*MAXNUM );


  if( EnumDeviceDrivers( (LPVOID*)pBaseAddr, sizeof(DWORD)*MAXNUM, &cbNum ) != TRUE )
  {
    //
    // indicate EnumDeviceDriver failed!
    //
    wprintf( L"EnumDeviceDriver failed! ErrorCode = %8x\n", GetLastError() );
    return 1;
  }
 
  cbNum /=4; // cbNum return the bytes

  if( bAlloc == TRUE )
    pAllDrvInfo = (PALL_DRIVER_INFO)GlobalAlloc( GMEM_FIXED, sizeof(DRIVER_INFO)*cbNum + 4 );
  else
    pAllDrvInfo = (PALL_DRIVER_INFO)pDrvInfo;

  pAllDrvInfo->cbNum = cbNum;

  for( int i = 0; i < cbNum; i++ )
  {
    pAllDrvInfo->DrvInfo[i].BaseAddr = *pBaseAddr;

    GetDeviceDriverBaseName( (LPVOID)*pBaseAddr, (LPWSTR)&pAllDrvInfo->DrvInfo[i].BaseName, MAX_PATH );
    GetDeviceDriverFileName( (LPVOID)*pBaseAddr, (LPWSTR)&pAllDrvInfo->DrvInfo[i].FileName, MAX_PATH );

    pBaseAddr++;
  }

  *pDrvInfo = pAllDrvInfo; // return the drv info buffer pointer
  return 0;  // indicate success
}

int main()
{
  PALL_DRIVER_INFO pDrvInfo = NULL;
  myGetDriverInfo(
    (PALL_DRIVER_INFO*)&pDrvInfo,
    TRUE
    );
  wprintf(L"=====the list of driver as follows === \n");
  wprintf(L"Order\tBaseAddr \t BaseName \t FileName \t \n");
  for( int i = 0; i<pDrvInfo->cbNum; i++ )
  {
    wprintf(L"%d\t%8x\t%s\t%s\n",
        i,
        pDrvInfo->DrvInfo[i].BaseAddr,
        pDrvInfo->DrvInfo[i].BaseName,
        pDrvInfo->DrvInfo[i].FileName
        );
  }
  return 0;
}

Friday, July 29, 2011

Read file for get original SSDT Shadow on ring3

Author:kalrey
The way is not original,but code really write  by me.

Reference:http://hi.baidu.com/robin_dev/blog/item/5a593fca5449ec18be09e6cf.html
Thanks.

I package the class,That is simple.


Class declare:

code:
//file:SDTShadowRestore.h

#ifndef SDTSHADOWRESTORE_H

#define SDTSHADOWRESTORE_H

#include <windows.h>
#include <Tchar.h>

typedef struct _SYSTEM_SERVICE_TABLE
{
   PVOID   ServiceTableBase;
   PULONG   ServiceCounterTableBase;
   ULONG   NumberOfService;
   ULONG   ParamTableBase;
}SYSTEM_SERVICE_TABLE,*PSYSTEM_SERVICE_TABLE;

typedef struct _SERVICE_DESCRIPTOR_TABLE
{
  PVOID KiServiceTabe;
  PVOID W32pServiceTable;
  PVOID Reserved_1;
  PVOID Reserved_2;
}SERVICE_DESCRIPTOR_TABLE,*PSERVICE_DESCRIPTOR_TABLE;


class SDTShadowRestore
{
public:
  SDTShadowRestore(void)
  {
    m_dwWin32kBase = 0;
    m_dwW32pServiceTable = 0;
    m_KeServiceDescriptorTableShadow = 0;
    this->Init();
  }
  ~SDTShadowRestore(void)
  {
    if(m_pKernelName)
    {
      ::GlobalFree(m_pKernelName);
    }
  }
  bool Init();           //
  DWORD FindW32pServiceTable();     //get original W32pServiceTable's memory address
  DWORD GetAddressSSDTShadow();            //get KeServiceDescriptorTableShadow'smemory address in kernel
  DWORD GetServiceAddressById(DWORD ServiceId);        //Get Service's original Address
private:
  void AnsiToPTSTR(PTSTR DesStr, char *SourceStr, DWORD cbDesStr);
 
  DWORD GetProcFromIAT(LPCTSTR szProcName);      //find function's address at Iat by function's name
private:
  PIMAGE_OPTIONAL_HEADER m_pWin32kOptionalHeader;           //OptionalHeader,non RVA
  HMODULE m_hWin32kModule;              //Win32k.sys kernel module handle load by oneself   LPTSTR m_pKernelName;           //kernel module
  HMODULE m_hKernelModule;            //ntoskrnl.exe or ntkrnlpa.exe module
  DWORD m_dwKernelBase;         //kernel base address
  DWORD m_dwWin32kBase;         //Win32k.sys base address
  PSERVICE_DESCRIPTOR_TABLE m_KeServiceDescriptorTableShadow;         //in kernel SSDT Shadow really memory address
  DWORD m_dwW32pServiceTable;      //original W32pServiceTaable really address
};

#endif 

Class implements:
#include "SDTShadowRestore.h"

typedef struct _SYSTEM_MODULE_INFORMATION  // Information Class 11
{
  ULONG  Reserved[2];  //+0
  PVOID  Base;         //+08h
  ULONG  Size;         //+0ch
  ULONG  Flags;        //+10h
  USHORT Index;        //+14h
  USHORT Unknown;      //+16h
  USHORT LoadCount;    //+18h
  USHORT ModuleNameOffset; //+1Ah
  CHAR   ImageName[256];   //+1Ch
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;



typedef struct _tagSysModuleList
{
  ULONG ulCount;
  SYSTEM_MODULE_INFORMATION smi;
} SYSMODULELIST, *PSYSMODULELIST;


typedef DWORD SYSTEM_INFORMATION_CLASS;

#define   STATUS_INFO_LEN_MISMATCH   0xc0000004

typedef LONG (_stdcall *pFnZwQuerySystemInformation )
( IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
 IN OUT PVOID SystemInformation,
 IN ULONG SystemInformationLength,
 OUT PULONG ReturnLength  );






void SDTShadowRestore::AnsiToPTSTR(PTSTR DesStr, char *SourceStr, DWORD cbDesStr)
{
#ifndef _UNICODE
  lstrcpy(DesStr, SourceStr);
#else
  MultiByteToWideChar(CP_ACP, 0, SourceStr, -1, DesStr, cbDesStr);
#endif

}

bool SDTShadowRestore::Init()
{
  pFnZwQuerySystemInformation ZwQuerySystemInformation = (pFnZwQuerySystemInformation)::GetProcAddress(::LoadLibrary(_T("ntdll.dll")), "ZwQuerySystemInformation");
  PSYSMODULELIST pSysModuleList = NULL;
  DWORD ReturnLength = 0, dwRet = 0;
  TCHAR ModuleName[MAX_PATH];
  dwRet = ZwQuerySystemInformation(11, (PVOID)pSysModuleList, 0, &ReturnLength);
  if(dwRet == STATUS_INFO_LEN_MISMATCH)
  {
    pSysModuleList = (PSYSMODULELIST)::GlobalAlloc(GPTR, ReturnLength);
    ZwQuerySystemInformation(11, (PVOID)pSysModuleList, ReturnLength, NULL);            //获取系统加载模块信息
    PSYSTEM_MODULE_INFORMATION pSystemModuleInformation = &(pSysModuleList->smi);
    m_dwKernelBase = (DWORD)(pSystemModuleInformation->Base);              //获取系统内核核心模块ntoskrnl.exe加载基址,PAE模式为ntkrnlpa.exe
    char* pAnsiKernelName = pSystemModuleInformation->ModuleNameOffset + pSystemModuleInformation->ImageName;
    m_pKernelName = (PTSTR)::GlobalAlloc(GPTR, sizeof(TCHAR)*(strlen(pAnsiKernelName)+1));            
    this->AnsiToPTSTR(m_pKernelName, pAnsiKernelName, sizeof(TCHAR)*(strlen(pAnsiKernelName)+1));    //获取内核核心模块名称(以此判定是否为PAE模式)
    this->m_hKernelModule = ::LoadLibraryEx(m_pKernelName, 0, DONT_RESOLVE_DLL_REFERENCES);      //在用户态加载内核核心模块
    this->m_hWin32kModule = ::LoadLibraryEx(_T("Win32k.sys"), 0, DONT_RESOLVE_DLL_REFERENCES);   //在用户态加载Win32k.sys模块
    for(DWORD index = 0; index < pSysModuleList->ulCount; index++)               //通过循环获取Win32k.sys在内核加载的基址,后面重定位Shadow SSDT中函数地址用到
    {
      TCHAR szModuleName[50];
      AnsiToPTSTR(szModuleName, (pSystemModuleInformation->ImageName + pSystemModuleInformation->ModuleNameOffset), 50);
      if(lstrcmp(_tcsupr(szModuleName), _T("WIN32K.SYS")) == 0)
      {
        this->m_dwWin32kBase = (DWORD)(pSystemModuleInformation->Base);
        break;
      }
      pSystemModuleInformation++;
    }
    if(pSysModuleList)
    {
      ::GlobalFree(pSysModuleList);
    }
  }
  this->m_pWin32kOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)m_hWin32kModule + ((PIMAGE_DOS_HEADER)m_hWin32kModule)->e_lfanew + 0x18);     //Win32k.sys可选头
  return true;
}


DWORD SDTShadowRestore::GetAddressSSDTShadow()         //得到KeServiceDescriptorTableShadow在内核中的内存地址
{
  if(m_dwWin32kBase)
  {
    DWORD dwKeAddSystemServiceTable = (DWORD)GetProcAddress(m_hKernelModule, "KeAddSystemServiceTable");
    for(DWORD dwCurAddress = dwKeAddSystemServiceTable; dwCurAddress < dwKeAddSystemServiceTable + 0x100; dwCurAddress++)
    {
      /*通过定位
      8d8840355580    lea     ecx,nt!KeServiceDescriptorTableShadow (80553540)[eax]
      833900          cmp     dword ptr [ecx],0
      */
      if(*(PWORD)dwCurAddress == 0x888d && *(PWORD)(dwCurAddress + 6) == 0x3983)
      {
        m_KeServiceDescriptorTableShadow = (PSERVICE_DESCRIPTOR_TABLE)(*(PDWORD)(dwCurAddress + 2) - (DWORD)m_hKernelModule + m_dwKernelBase);
        return (DWORD)m_KeServiceDescriptorTableShadow;         //该地址位于内核空间不可访问
      }
    }
  }
  return NULL;
}



DWORD SDTShadowRestore::FindW32pServiceTable()     //得到原始W32pServiceTable内存地址
{
  //获取Win32k.sys得DriverEntry地址
  DWORD dwEntryPoint = this->m_pWin32kOptionalHeader->AddressOfEntryPoint + (DWORD)m_hWin32kModule;
  //从IAT中获取KeAddSystemServiceTable的地址
  DWORD dwKeAddSystemServiceTable = GetProcFromIAT(_T("KeAddSystemServiceTable"));
  /*IDA反汇编结果:
  68 80 A2 99 BF          push    offset off_BF99A280
  FF 15 58 D4 98 BF       call    ds:KeAddSystemServiceTable
  */
  //通过call    ds:KeAddSystemServiceTable的定位,该定位应该比较准确
  for(DWORD dwCurAddress = dwEntryPoint; dwCurAddress < dwEntryPoint + 0x1000; dwCurAddress++)
  {
    if(*(PWORD)dwCurAddress == 0x15ff )
    { 
      //计算出加载后的ds:KeAddSystemServiceTable地址,然后该地址中存放的即是KeAddSystemServiceTable真实入口地址
      DWORD dwFunAddress = *(PDWORD)(*(PULONG)(dwCurAddress + 2) - m_pWin32kOptionalHeader->ImageBase + (DWORD)m_hWin32kModule);
      if(dwKeAddSystemServiceTable == dwFunAddress)
      {
        //将该地址结合内核中Win32k的加载地址进行重定位
        m_dwW32pServiceTable = *(PDWORD)(dwCurAddress - 4) - m_pWin32kOptionalHeader->ImageBase + (DWORD)m_hWin32kModule;
        return m_dwW32pServiceTable;
      }
    }
  }
  return 0;
}


DWORD SDTShadowRestore::GetServiceAddressById(DWORD ServiceId)       //获取服务原始地址
{
  if(!m_dwW32pServiceTable)
  {
    FindW32pServiceTable();
  }
  if(m_dwW32pServiceTable)
  {
    return *(PDWORD)(m_dwW32pServiceTable + ServiceId * 4) - m_pWin32kOptionalHeader->ImageBase + m_dwWin32kBase;
  }
}

DWORD SDTShadowRestore::GetProcFromIAT(LPCTSTR szProcName)      //根据函数名在IAT中查找函数地址
{
  PIMAGE_IMPORT_DESCRIPTOR pImageTable = (PIMAGE_IMPORT_DESCRIPTOR)(m_pWin32kOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + (DWORD)m_hWin32kModule);
 
  TCHAR szDllName[20];
  while(pImageTable->Name || pImageTable->FirstThunk || pImageTable->OriginalFirstThunk)
  {
    AnsiToPTSTR(szDllName, (char*)(pImageTable->Name + (DWORD)m_hWin32kModule), 20);
    if(lstrcmp(_tcsupr(szDllName), _T("NTOSKRNL.EXE")) == 0)
    {
      break;
    }
    pImageTable++;
  }
  PIMAGE_THUNK_DATA pOrgFirstThunk = (PIMAGE_THUNK_DATA)(pImageTable->OriginalFirstThunk + (DWORD)m_hWin32kModule);
  PIMAGE_THUNK_DATA pFirstThunk = (PIMAGE_THUNK_DATA)(pImageTable->FirstThunk + (DWORD)m_hWin32kModule);
  TCHAR szFunName[30];
  for(DWORD index = 0; &(pOrgFirstThunk[index]); index++)
  {
    if(!(pOrgFirstThunk[index].u1.Ordinal & IMAGE_ORDINAL_FLAG32 ))
    {
      PIMAGE_IMPORT_BY_NAME pFunName = (PIMAGE_IMPORT_BY_NAME)(pOrgFirstThunk[index].u1.ForwarderString + (DWORD)m_hWin32kModule); 
      AnsiToPTSTR(szFunName, (char*)(pFunName->Name), 30);
      if(lstrcmp(szFunName, szProcName) == 0)
      {
        return pFirstThunk[index].u1.Function;
      }
    }
  }
  return 0; 
}

ShadowSSDT position use hard code
We can find function' name to copy it by IDA.XP SP2 use 667,I write a little software to analysis function's name:
#include <windows.h>
#include <iostream>

using namespace std;

int main()
{
CHAR SrcFileName[MAX_PATH],DesFileName[MAX_PATH];
cout << "please input the file name of src:" <<endl;
cin >> SrcFileName;
cout << "please input the file name of des:" <<endl;
cin >> DesFileName;
HANDLE hSrcFile = ::CreateFileA(SrcFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

if(!hSrcFile)
{
   return 1;
}
HANDLE hSrcMap = ::CreateFileMappingA(hSrcFile, NULL, PAGE_READONLY, 0, 0, NULL);

if(!hSrcMap)
{
   return 1;
}
LPVOID lpSrcMapAddress = ::MapViewOfFile(hSrcMap, FILE_MAP_READ, 0, 0, 0);
char* pSrc = (char*)lpSrcMapAddress;
HANDLE hDesFile = ::CreateFileA(DesFileName, GENERIC_WRITE|GENERIC_READ, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD dwFileSizeHigh = 0;
DWORD dwFileSizeLow = ::GetFileSize(hSrcFile, &dwFileSizeHigh);
HANDLE hDesMap = ::CreateFileMappingA(hDesFile, NULL, PAGE_READWRITE, dwFileSizeHigh, dwFileSizeLow, NULL);
DWORD a = ::GetLastError();
LPVOID lpDesMapAddress = ::MapViewOfFile(hDesMap, FILE_MAP_WRITE, 0, 0, 0);
char* pDes = (char*)lpDesMapAddress;
bool bFlag = false;
while(pSrc - lpSrcMapAddress < dwFileSizeLow )
{
   //加上*(pSrc - 1) == ' '(此处不是空,是空格字符)是为了防止对此类中间存在'_'符号的错误解析,_NtGdiHT_Get8BPPFormatPalette@16
   if(*pSrc == '_' && *(pSrc - 1) == ' ')
   {
    bFlag = true;
    *pDes = 'L';
    pDes++;
    *pDes = '"';
    pDes++;
   }
   else if(*pSrc == '@')
   {
    bFlag = false;
    *pDes = '"';
    pDes++;
    *pDes = ',';
    pDes++;
    *pDes = 13;
    pDes++;
    *pDes = 10;
    pDes++;
   }
   else
   {
    if(bFlag)
    {
     *pDes = *pSrc;
     pDes++;
    }
   }
   pSrc++;
}
::UnmapViewOfFile(lpSrcMapAddress);
::UnmapViewOfFile(lpDesMapAddress);
::CloseHandle(hSrcMap);
::CloseHandle(hDesMap);
::CloseHandle(hSrcFile);
::CloseHandle(hDesFile);
return 0;
}
Hope to be useful for pleople in need.