驱动之路_枚举WIN32K.SYS,通过PDB解析

需要的模块有:
#pragma comment(lib , "DbgHelp.lib")
#pragma comment(lib , "ntdll.lib")

#include "DbgHelp.h" //这个是在C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Include

 

1.初始化符号
1.创建目录Symbols
2.创建symsrv.yes文件,不然的话他会弹一个对话框
3.设置搜索路径,开始下载PDB

2.获得win32k.sys的模块地址和基址

3.开始枚举,回调函数我们得自己写

 

 

 

代码:

 

// EnumSymbols.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <Windows.h>
#ifdef __cplusplus
extern "C"
{
#endif
#include "DbgHelp.h"//这里包含需要用C方式编译的头文件
#ifdef __cplusplus
}
#endif 
#pragma comment(lib , "DbgHelp.lib")
#pragma comment(lib , "ntdll.lib")
#define STATUS_UNSUCCESSFUL (0xC0000001L)
#define  SystemModuleInformation 11
#define STATUS_SUCCESS        0x00000000 
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)

extern "C" NTSTATUS __stdcall  ZwQuerySystemInformation(
    __in       ULONG SystemInformationClass,
    __inout    PVOID SystemInformation,
    __in       ULONG SystemInformationLength,
    __out_opt  PULONG ReturnLength
    );


typedef BOOL(__stdcall *IMAGEUNLOAD)(
                                     __in  PLOADED_IMAGE LoadedImage
                                     );
IMAGEUNLOAD pImageUnload;
int FuncCount=0;
typedef PLOADED_IMAGE(__stdcall *IMAGELOAD)(
    __in  PSTR DllName,
    __in  PSTR DllPath
    );
IMAGELOAD pImageLoad;


typedef BOOL(__stdcall *SYMGETSYMBOLFILE)(
    __in_opt HANDLE hProcess,
    __in_opt PCSTR SymPath,
    __in PCSTR ImageFile,
    __in DWORD Type,
    __out_ecount(cSymbolFile) PSTR SymbolFile,
    __in size_t cSymbolFile,
    __out_ecount(cDbgFile) PSTR DbgFile,
    __in size_t cDbgFile
    );
SYMGETSYMBOLFILE pSymGetSymbolFile;

typedef struct _SYSTEM_MODULE_INFORMATION  // 系统模块信息
{
    ULONG  Reserved[2];  
    ULONG  Base;        
    ULONG  Size;         
    ULONG  Flags;        
    USHORT Index;       
    USHORT Unknown;     
    USHORT LoadCount;   
    USHORT ModuleNameOffset;
    CHAR   ImageName[256];   
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;

PLOADED_IMAGE pli;
typedef struct _tagSysModuleList {          //模块链结构
    ULONG ulCount;
    SYSTEM_MODULE_INFORMATION smi[2];
} MODULES, *PMODULES;


//-------------------------------------------------------------------------
//保存所有内核函数的一个结构
//-------------------------------------------------------------------------
typedef struct _KERNELFUNC_ADDRESS_INFORMATION {
    ULONG ulAddress;
    CHAR FuncName[50];
}KERNELFUNC_ADDRESS_INFORMATION, *PKERNELFUNC_ADDRESS_INFORMATION;

typedef struct _WIN32KFUNCINFO {          //PNTOSFUNCINFO
    ULONG ulCount;
    KERNELFUNC_ADDRESS_INFORMATION Win32KFuncInfo[1];
} WIN32KFUNCINFO, *PWIN32KFUNCINFO;

PWIN32KFUNCINFO FuncAddressInfo;




HANDLE hProcess;
BOOLEAN InitSymHandler()
{
    HANDLE hfile;
    char Path[MAX_PATH]={0};
    char FileName[MAX_PATH]={0};
    char SymPath[MAX_PATH*2]={0};
    char* SymbolsUrl = "http://msdl.microsoft.com/download/symbols";


    if (!GetCurrentDirectoryA(MAX_PATH,Path))//获取当前目录
    {
        printf ("cannot get current directory \n");
        return FALSE;
    }

    strcat(Path,"\\Symbols");//比如:C:\Symbols
    CreateDirectoryA(Path,NULL);//创建目录

    //首先创建一个目录 symsrv.yes文件,symsrv.dll会检查,没有就会弹出一个对话框要求你点确认
    
    strcpy( FileName , Path);
    strcat(FileName ,"\\symsrv.yes");
    
    printf ("%s \n",FileName);

    hfile = CreateFileA ( FileName,
        FILE_ALL_ACCESS,
        FILE_SHARE_READ,
        NULL,
        OPEN_ALWAYS,
        FILE_ATTRIBUTE_NORMAL,
        NULL);
    
    if (hfile == INVALID_HANDLE_VALUE)
    {
        printf ("create or open file error: 0x%X \n",GetLastError());
        return FALSE;
    
    }
    CloseHandle (hfile);

    Sleep(3000);

    hProcess = GetCurrentProcess();//获取当前进程

    //设置搜索参数:
    //SYMOPT_CASE_INSENSITIVE 该选项使得所有对符号名的搜索区分大小写
    //

    SymSetOptions( SYMOPT_CASE_INSENSITIVE | SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME);

    //设置搜索路径
    //程序会把win32k的pdb符号文件下载到这个目录Path
    SymSetSearchPath(hProcess,Path);

    //这个是不是很眼熟?
    //SRV*d:\localsymbols*http://msdl.microsoft.com/download/symbols
    sprintf(SymPath,"SRV*%s*%s",Path,SymbolsUrl);

    //在这里初始化
    if (!SymInitialize( hProcess,
        SymPath,
        TRUE))
    {
        printf ("SymInitialize failed %d \n",GetLastError());
        return FALSE;
    }//初始化符号
    return TRUE;
}
ULONG GetKernelInfo(char *lpKernelName,ULONG *ulBase,ULONG *ulSize)
{
    DWORD    dwsize;
    DWORD    dwSizeReturn;
    PUCHAR    pBuffer    =    NULL;

    PMODULES    pSmi=NULL;
    NTSTATUS    ntStatus=STATUS_UNSUCCESSFUL;

    //明明是内核的api,怎么能在驱动层调用呢?
    //ntdll!ZwQuerySystemInformation 
    //ntdll!NtQuerySystemInformation
    //所以,我们在这里调用的是ntdll的函数,而不是ntoskrnel.exe
    ntStatus = ZwQuerySystemInformation(
        SystemModuleInformation,
        pSmi, 
        0, 
        &dwSizeReturn
        );
    if (ntStatus!=STATUS_INFO_LENGTH_MISMATCH)
    {
        return 0;
    }
    dwsize    =    dwSizeReturn*2;
    pSmi    =    (PMODULES)new char[dwsize];
    if (pSmi==NULL)
    {
        return 0;
    }

    ntStatus = ZwQuerySystemInformation(
        SystemModuleInformation, 
        pSmi,
        dwsize, 
        &dwSizeReturn
        );
    if (ntStatus!=STATUS_SUCCESS)
    {
        return 0;
    }
    for (int i=0;i<pSmi->ulCount;i++)
    {
        //循环从链表对比
        if (_stricmp(pSmi->smi[i].ImageName,lpKernelName) == 0)
        {
            printf("found %08X %X\,,%s,,,r\n",pSmi->smi[i].Base,pSmi->smi[i].Size,pSmi->smi[i].ImageName);
            *ulBase    = pSmi->smi[i].Base;
            *ulSize = pSmi->smi[i].Size;
            break;
        }
    }
    delete pSmi;

    return TRUE;
}


BOOLEAN LoadSymModule(
                      char* ImageName,
                      DWORD ModuleBase)
{
    DWORD64 tmp;
    char    SymFileName[MAX_PATH]={0};
    BOOL bRetOK = FALSE;

    HINSTANCE hmod = LoadLibraryA("Imagehlp.dll");
    if (!hmod)
        return FALSE;

    pImageLoad= (IMAGELOAD)GetProcAddress(hmod,"ImageLoad"); 
    pImageUnload= (IMAGEUNLOAD)GetProcAddress(hmod,"ImageUnload"); 
    if (!pImageLoad ||
        !pImageUnload)
        return FALSE;

    pli = pImageLoad( ImageName,NULL);
    if (pli == NULL)
    {
        printf ("cannot get loaded module of %s \n",ImageName);
        return FALSE;
    }
    printf ("ModuleName:%s:%08x\n",pli->ModuleName,pli->SizeOfImage);

    HINSTANCE hDbgHelp = LoadLibraryA("dbghelp.dll");
    if (!hDbgHelp)
        return FALSE;

    pSymGetSymbolFile = (SYMGETSYMBOLFILE)GetProcAddress(hDbgHelp,"SymGetSymbolFile"); 
    if (!pSymGetSymbolFile){
        printf("pSymGetSymbolFile() failed %X\r\n",pSymGetSymbolFile);
        return FALSE;
    }
    //欲解析符号前,使用SymGetSymbolFile来取得符号文件,如果搜索路径没有这个文件,那么将从微软服务器下载win32k的pdb,然后调用SymLoadModule64加载解析它咯
    if (pSymGetSymbolFile( hProcess,
        NULL,
        pli->ModuleName,
        sfPdb,
        SymFileName,
        MAX_PATH,
        SymFileName,
        MAX_PATH))
    {
        //然后调用SymLoadModule64加载它咯
        tmp =  SymLoadModule64( hProcess,
            pli->hFile,
            pli->ModuleName,
            NULL,
            (DWORD64)ModuleBase,
            pli->SizeOfImage);
        if (tmp)
        {
            bRetOK =  TRUE;
        }
    }
    //加载了,就要卸载
    //申请了内存,就要释放一样的道理
    //学java的同学要注意。
    pImageUnload(pli);
    return bRetOK;
}


BOOLEAN EnumSyms(
                 char* ImageName,
                 DWORD ModuleBase,
                 PSYM_ENUMERATESYMBOLS_CALLBACK EnumRoutine,
                 PVOID Context)
{
    BOOLEAN bEnum;

    //首先加载符号模块
    if ( !LoadSymModule( ImageName , ModuleBase) )
    {
        printf ("cannot load symbols ,error: %d \n",GetLastError());
        return FALSE;
    }
    //解析符号
    bEnum = SymEnumSymbols( hProcess,
        ModuleBase,
        NULL,
        EnumRoutine, //有一个回调
        Context);
    if (!bEnum)
    {
        printf ("cannot enum symbols ,error: %d \n",GetLastError());
    }
    return bEnum;
}


//这个就是回调函数
BOOLEAN CALLBACK EnumSymRoutine(
                                PSYMBOL_INFO psi,
                                ULONG     SymSize,
                                PVOID     Context)
{
    if (_stricmp(psi->Name,"NtUserFindWindowEx") == 0)
    {
        /*
            typedef struct _WIN32KFUNCINFO {          //PNTOSFUNCINFO
            ULONG ulCount;
            KERNELFUNC_ADDRESS_INFORMATION Win32KFuncInfo[1];
        } WIN32KFUNCINFO, *PWIN32KFUNCINFO;

        PWIN32KFUNCINFO FuncAddressInfo;
        */
        FuncAddressInfo->Win32KFuncInfo[FuncCount].ulAddress = (ULONG)psi->Address;
        strcat(FuncAddressInfo->Win32KFuncInfo[FuncCount].FuncName,psi->Name);
        FuncCount++;
    }
    if (_stricmp(psi->Name,"NtUserQueryWindow") == 0)
    {
        FuncAddressInfo->Win32KFuncInfo[FuncCount].ulAddress = (ULONG)psi->Address;
        strcat(FuncAddressInfo->Win32KFuncInfo[FuncCount].FuncName,psi->Name);
        FuncCount++;
    }
    FuncAddressInfo->ulCount = FuncCount;
    return TRUE;
}


int _tmain(int argc, _TCHAR* argv[])
{
    ULONG ulBase;
    ULONG ulSize;
    //先初始化符号
    if (InitSymHandler())
    {
        if (GetKernelInfo("\\SystemRoot\\System32\\win32k.sys",&ulBase,&ulSize))
        {

            FuncAddressInfo = (PWIN32KFUNCINFO)VirtualAlloc(0,(sizeof(WIN32KFUNCINFO)+sizeof(KERNELFUNC_ADDRESS_INFORMATION))*10,MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
            if (FuncAddressInfo)//分配成功的话
            {
                memset(FuncAddressInfo,0,(sizeof(WIN32KFUNCINFO)+sizeof(KERNELFUNC_ADDRESS_INFORMATION))*10);

                //到这里,开始枚举(并且保存到结构体)
                EnumSyms("win32k.sys",ulBase,(PSYM_ENUMERATESYMBOLS_CALLBACK)EnumSymRoutine,NULL);

                //要接触加载
                SymUnloadModule64(GetCurrentProcess(),ulBase);

                //清理
                SymCleanup(GetCurrentProcess());

                for (int i=0;i<FuncAddressInfo->ulCount;i++)
                {
                    //打印测试
                    printf("%s[0x%08X]\r\n",FuncAddressInfo->Win32KFuncInfo[i].FuncName,FuncAddressInfo->Win32KFuncInfo[i].ulAddress);
                }
                //传到内核(用到我们学到的通信了吧)
                //CallDriver(WIN32K_FUNCTION,FuncAddressInfo,(sizeof(WIN32KFUNCINFO)+sizeof(KERNELFUNC_ADDRESS_INFORMATION))*10);
            }
        }
    }
        getchar();
    return 0;
}

 

posted @ 2013-10-10 13:38  宝贝,我永远都在  阅读(1482)  评论(1)    收藏  举报