diddom 发表于 2012-5-18 16:10:51

简洁有力的纯win32的SSDT List

本帖最后由 diddom 于 2012-5-23 01:45 编辑

很棒的入门款式

纯win32的唷,有ListView且双色item

Hook地方还用红色字标示


// SystemTool.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "resource.h"
#include <stdio.h>
#include <windows.h>   
#include <winnt.h>   
#include <WindowsX.h>   
#include <commctrl.h>   

#pragma comment(lib,"comctl32")

typedef ULONG NTSTATUS;
#define MAX_LOADSTRING 100
#define SystemModuleInformation 11   
#define ibaseDD *(PDWORD)&ibase   
      
HINSTANCE g_hInst;   
HWND hWinMain;
HWND hList;
#define ID_LISTVIEW 1001

#define RVATOVA(base,offset) ((PVOID)((DWORD)(base)+(DWORD)(offset)))   
#define ibaseDD *(PDWORD)&ibase   
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)   
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)   
      
typedef struct
{   
        WORD    offset:12;   
        WORD    type:4;   
} IMAGE_FIXUP_ENTRY, *PIMAGE_FIXUP_ENTRY;   
      
      
typedef
ULONG
(WINAPI *ZWQUERYSYSTEMINFORMATION)
(   
        DWORD    SystemInformationClass,   
        PVOID    SystemInformation,   
        ULONG    SystemInformationLength,   
        PULONG   ReturnLength
);   

ZWQUERYSYSTEMINFORMATION ZwQuerySystemInformation = NULL;   
      
typedef enum _SYSDBG_COMMAND {   
      SysDbgReadVirtualMemory = 8,   
      SysDbgWriteVirtualMemory = 9,   
} SYSDBG_COMMAND, *PSYSDBG_COMMAND;   
      
typedef struct _MEMORY_CHUNKS
{   
        ULONG Address;
        PVOID Data;
        ULONG Length;
} MEMORY_CHUNKS, *PMEMORY_CHUNKS;   
      
typedef
NTSTATUS
(NTAPI * ZWSYSTEMDEBUGCONTROL)
(
        SYSDBG_COMMAND ControlCode,   
        PVOID InputBuffer,   
        ULONG InputBufferLength,   
        PVOID OutputBuffer,   
        ULONG OutputBufferLength,   
        PULONG ReturnLength
);   
      
ZWSYSTEMDEBUGCONTROL ZwSystemDebugControl = NULL;   
      
typedef struct _SYSTEM_MODULE_INFORMATION { //Information Class 11   
        ULONG    Reserved;   
        PVOID    Base;   
        ULONG    Size;   
        ULONG    Flags;   
        USHORT   Index;   
        USHORT   Unknown;   
        USHORT   LoadCount;   
        USHORT   ModuleNameOffset;   
        CHAR   ImageName;   
} SYSTEM_MODULE_INFORMATION,*PSYSTEM_MODULE_INFORMATION;   
      
      
typedef struct   
{   
        CHAR fname;   
        ULONG address1;   
        ULONG address2;   
} SSDT_LIST_ENTRY;   
      
SSDT_LIST_ENTRY ssdt_list;

//ssdt_list = new SSDT_LIST_ENTRY;

// Global Variables:
HINSTANCE hInst;                                                                // current instance
TCHAR szTitle;                                        // The title bar text
TCHAR szWindowClass;                        // The title bar text

// Foward declarations of functions included in this code module:
ATOM                                MyRegisterClass(HINSTANCE hInstance);
BOOL                                InitInstance(HINSTANCE, int);
LRESULT CALLBACK        WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK        About(HWND, UINT, WPARAM, LPARAM);

BOOL LocateNtdllEntry();
BOOL DebugPrivilege(TCHAR *PName,BOOL bEnable);
void InitListView();
void GetSSDT();
void FindExport();

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR   lpCmdLine,
                     int       nCmdShow)
{
        // TODO: Place code here.
        MSG msg;
        HACCEL hAccelTable;

        // Initialize global strings
        LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
        LoadString(hInstance, IDC_SYSTEMTOOL, szWindowClass, MAX_LOADSTRING);
        MyRegisterClass(hInstance);

        // Perform application initialization:
        if (!InitInstance (hInstance, nCmdShow))
        {
                return FALSE;
        }

        hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_SYSTEMTOOL);

        // Main message loop:
        while (GetMessage(&msg, NULL, 0, 0))
        {
                if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
                {
                        TranslateMessage(&msg);
                        DispatchMessage(&msg);
                }
        }

        //delete [] ssdt_list;
        return msg.wParam;
}



//
//FUNCTION: MyRegisterClass()
//
//PURPOSE: Registers the window class.
//
//COMMENTS:
//
//    This function and its usage is only necessary if you want this code
//    to be compatible with Win32 systems prior to the 'RegisterClassEx'
//    function that was added to Windows 95. It is important to call this function
//    so that the application will get 'well formed' small icons associated
//    with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
        WNDCLASSEX wcex;

        wcex.cbSize = sizeof(WNDCLASSEX);

        wcex.style                        = CS_HREDRAW | CS_VREDRAW;
        wcex.lpfnWndProc        = (WNDPROC)WndProc;
        wcex.cbClsExtra                = 0;
        wcex.cbWndExtra                = 0;
        wcex.hInstance                = hInstance;
        wcex.hIcon                        = LoadIcon(hInstance, (LPCTSTR)IDI_SYSTEMTOOL);
        wcex.hCursor                = LoadCursor(NULL, IDC_ARROW);
        wcex.hbrBackground        = (HBRUSH)(COLOR_WINDOW+1);
        wcex.lpszMenuName        = (LPCSTR)IDC_SYSTEMTOOL;
        wcex.lpszClassName        = szWindowClass;
        wcex.hIconSm                = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);

        return RegisterClassEx(&wcex);
}

//
//   FUNCTION: InitInstance(HANDLE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//      In this function, we save the instance handle in a global variable and
//      create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
        HWND hWnd;

        hInst = hInstance; // Store instance handle in our global variable

        hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
                                                CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
                                                NULL, NULL, hInstance, NULL);

        if (!hWnd)
        {
                return FALSE;
        }

        hWinMain = hWnd;

        ShowWindow(hWnd, nCmdShow);
        UpdateWindow(hWnd);
        return TRUE;
}

//
//FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
//
//PURPOSE:Processes messages for the main window.
//
//WM_COMMAND        - process the application menu
//WM_PAINT        - Paint the main window
//WM_DESTROY        - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
        int wmId, wmEvent;
        PAINTSTRUCT ps;
        HDC hdc;
        TCHAR szHello;
        LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);

        switch (message)
        {
                case WM_NOTIFY:   
            switch (LOWORD(wParam))   
            {   
            case ID_LISTVIEW:
                                //LPNMHDR pnm = (LPNMHDR)lParam;   
                                //if(pnm->hwndFrom != m_hWnd)   
                                        //SendMessage(pnm->hwndFrom,msg,wParam,lParam);

                                //LPNMHDR pnm = (LPNMHDR) lParam;   
                                //if(pnm->code == NM_CUSTOMDRAW)
                                if(((LPNMHDR)lParam)->code == NM_CUSTOMDRAW)
                {                  
                                        //LPNMLVCUSTOMDRAW lpLVCD = (LPNMLVCUSTOMDRAW) lParam;
                                        //switch(lpLVCD->nmcd.dwDrawStage)
                                        switch(((LPNMLVCUSTOMDRAW)lParam)->nmcd.dwDrawStage)
                  {   
                  case CDDS_PREPAINT:   
                        return CDRF_NOTIFYITEMDRAW;

                  case CDDS_ITEMPREPAINT:   
                        {   //設置不同顏色
                            LPNMLVCUSTOMDRAW customDraw = (LPNMLVCUSTOMDRAW) lParam;
                            customDraw->clrTextBk=customDraw->nmcd.dwItemSpec%2?RGB(250, 250, 250):RGB(0xFF, 0xFF, 0xFF);   
                                                        if (ssdt_list.address1 != ssdt_list.address2) customDraw->clrText = RGB(255, 0, 0) ;   
                            else customDraw->clrText = RGB(0, 0, 0) ;   
                            return CDRF_NEWFONT;   
                        }   
                        break;   
                  default:   
                        return CDRF_DODEFAULT;   
                  }   
                }

                                if(((LPNMHDR)lParam)->code == WM_ERASEBKGND)   
                {
                                        int ii;
                                        ii = 0;
                                }

                break;

                               

            }   
            break;   

                case WM_COMMAND:
                        wmId    = LOWORD(wParam);
                        wmEvent = HIWORD(wParam);
                        // Parse the menu selections:
                        switch (wmId)
                        {
                                case IDM_ABOUT:
                                   DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
                                   break;
                                case IDM_EXIT:
                                   DestroyWindow(hWnd);
                                   break;
                                default:
                                   return DefWindowProc(hWnd, message, wParam, lParam);
                        }
                        break;
               
                case WM_ERASEBKGND:
                        //return TRUE;
                        break;
               
                case WM_SIZE:
            MoveWindow(hList, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
                        break;

                case WM_CREATE:   
            hWinMain = hWnd;   
            InitListView();   
            LocateNtdllEntry();
            FindExport();
            DebugPrivilege(SE_DEBUG_NAME,TRUE);   
            GetSSDT();   
            return 0;   
                        break;

                case WM_PAINT:
                        hdc = BeginPaint(hWnd, &ps);
                        // TODO: Add any drawing code here...
                        RECT rt;
                        GetClientRect(hWnd, &rt);
                        DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER);
                        EndPaint(hWnd, &ps);
                        break;

                case WM_DESTROY:
                        PostQuitMessage(0);
                        break;

                default:
                        return DefWindowProc(hWnd, message, wParam, lParam);
   }
   return 0;
}

// Mesage handler for about box.
LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
        switch (message)
        {
                case WM_INITDIALOG:
                                return TRUE;

                case WM_COMMAND:
                        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
                        {
                                EndDialog(hDlg, LOWORD(wParam));
                                return TRUE;
                        }
                        break;
        }
    return FALSE;
}


//////////////////////////////////////////////////////////////////////////
//
//
BOOL LocateNtdllEntry()   
{   
    HMODULE ntdll_dll   = NULL;   
   
    if (!(ntdll_dll = GetModuleHandle("ntdll.dll"))) return FALSE;

    if (!( ZwQuerySystemInformation = (ZWQUERYSYSTEMINFORMATION)GetProcAddress(ntdll_dll, "ZwQuerySystemInformation" )))   
      return FALSE;

    if (!( ZwSystemDebugControl = (ZWSYSTEMDEBUGCONTROL)GetProcAddress(ntdll_dll, "ZwSystemDebugControl" )))   
      return FALSE;   
      
    return TRUE;   
}

   
//////////////////////////////////////////////////////////////////////////
//
//
BOOL DebugPrivilege(TCHAR *PName,BOOL bEnable)   
{   
    BOOL            fOk = FALSE;   
    HANDLE            hToken;   
    TOKEN_PRIVILEGEStp;   
   
    if(OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,&hToken))   
    {         
      tp.PrivilegeCount         = 1;   
      tp.Privileges.Attributes = bEnable ? SE_PRIVILEGE_ENABLED : 0;   
      LookupPrivilegeValue(NULL,PName,&tp.Privileges.Luid);   
      AdjustTokenPrivileges(hToken,FALSE,&tp,sizeof(TOKEN_PRIVILEGES),NULL,NULL);   
      fOk=(GetLastError() == ERROR_SUCCESS);         
      CloseHandle(hToken);   
    }   
    return fOk;   
}   


//////////////////////////////////////////////////////////////////////////
//
//
DWORD GetHeaders(PCHAR ibase,   
               PIMAGE_FILE_HEADER *pfh,   
               PIMAGE_OPTIONAL_HEADER *poh,   
               PIMAGE_SECTION_HEADER *psh)   
   
{   
    PIMAGE_DOS_HEADER mzhead = (PIMAGE_DOS_HEADER)ibase;   
   
    if ((mzhead->e_magic != IMAGE_DOS_SIGNATURE) || (ibaseDD != IMAGE_NT_SIGNATURE))   
      return FALSE;   
   
    *pfh = (PIMAGE_FILE_HEADER)&ibase;

    if (((PIMAGE_NT_HEADERS)*pfh)->Signature != IMAGE_NT_SIGNATURE)   
      return FALSE;

    *pfh = (PIMAGE_FILE_HEADER)((PBYTE)*pfh + sizeof(IMAGE_NT_SIGNATURE));   
   
    *poh = (PIMAGE_OPTIONAL_HEADER)((PBYTE)*pfh + sizeof(IMAGE_FILE_HEADER));

    if ((*poh)->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)   
      return FALSE;
   
    *psh = (PIMAGE_SECTION_HEADER)((PBYTE)*poh + sizeof(IMAGE_OPTIONAL_HEADER));   
       
        return TRUE;

}   
   
   
//////////////////////////////////////////////////////////////////////////
//
//
void FindExport()
{   
    PIMAGE_FILE_HEADER                        pfh;   
    PIMAGE_OPTIONAL_HEADER                poh;   
    PIMAGE_SECTION_HEADER                psh;   
    PIMAGE_EXPORT_DIRECTORY                ped;

    DWORD*        arrayOfFunctionNames;   
    DWORD*        arrayOfFunctionAddresses;   
    WORD*        arrayOfFunctionOrdinals;   
    DWORD        functionOrdinal;
        DWORD        functionAddress;   

    HMODULE hNtdll = GetModuleHandle(TEXT("ntdll.dll"));

    GetHeaders((PCHAR)hNtdll, &pfh, &poh, &psh);

    if (poh->DataDirectory.VirtualAddress)   
    {   
      ped = (PIMAGE_EXPORT_DIRECTORY)(poh->DataDirectory.VirtualAddress + (BYTE*)hNtdll);   
      
                arrayOfFunctionNames = (DWORD*)(ped->AddressOfNames + (BYTE*)hNtdll);

      arrayOfFunctionAddresses = (DWORD*)((BYTE*)hNtdll + ped->AddressOfFunctions);

      arrayOfFunctionNames = (DWORD*)((BYTE*)hNtdll + ped->AddressOfNames);

      arrayOfFunctionOrdinals = (WORD*)((BYTE*)hNtdll + ped->AddressOfNameOrdinals);   
                  
      for (int i=0; i < ped->NumberOfNames; i++)   
      {   
            char* fun_name = (char*)((BYTE*)hNtdll + arrayOfFunctionNames);
                       
            functionOrdinal = arrayOfFunctionOrdinals + ped->Base - 1;
                       
            functionAddress = (DWORD)((BYTE*)hNtdll + arrayOfFunctionAddresses);
                       
            if (fun_name == 'N' && fun_name == 't')   
            {   
                WORD number = *((WORD*)(functionAddress + 1));
                               
                if (number>ped->NumberOfNames) continue;
                               
                lstrcpy(ssdt_list.fname, fun_name);   
            }   
      }   
    }   
}   


//////////////////////////////////////////////////////////////////////////
//
//
DWORD FindKiServiceTable(HMODULE hModule, DWORD dwKSDT)   
{   
    PIMAGE_FILE_HEADER                        pfh;   
    PIMAGE_OPTIONAL_HEADER                poh;   
    PIMAGE_SECTION_HEADER                psh;   
    PIMAGE_BASE_RELOCATION                pbr;   
    PIMAGE_FIXUP_ENTRY                        pfe;   
      
    DWORD    dwFixups = 0, i, dwPointerRva, dwPointsToRva, dwKiServiceTable;   
    BOOL   bFirstChunk;   
      
    GetHeaders((PCHAR)hModule, &pfh, &poh, &psh);   
      
    // loop thru relocs to speed up the search   
    if ((poh->DataDirectory.VirtualAddress) &&   
      (!((pfh->Characteristics)&IMAGE_FILE_RELOCS_STRIPPED)))
        {   
         
      pbr = (PIMAGE_BASE_RELOCATION) RVATOVA(poh->DataDirectory.VirtualAddress, hModule);   
         
      bFirstChunk = TRUE;
               
      // 1st IMAGE_BASE_RELOCATION.VirtualAddress of ntoskrnl is 0   
      while (bFirstChunk || pbr->VirtualAddress)
                {   
            bFirstChunk = FALSE;   
               
            pfe=(PIMAGE_FIXUP_ENTRY)((DWORD)pbr+sizeof(IMAGE_BASE_RELOCATION));   
               
            for (i=0; i < (pbr->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) >> 1; i++, pfe++)
                        {   
                if (pfe->type == IMAGE_REL_BASED_HIGHLOW)
                                {   
                  dwFixups++;

                  dwPointerRva = pbr->VirtualAddress + pfe->offset;

                  // DONT_RESOLVE_DLL_REFERENCES flag means relocs aren't fixed   
                  dwPointsToRva = *(PDWORD)((DWORD)hModule+dwPointerRva)-(DWORD)poh->ImageBase;   
                     
                  // does this reloc point to KeServiceDescriptorTable.Base?   
                  if (dwPointsToRva == dwKSDT)
                                        {   
                        // check for mov ,imm32. we are trying to find   
                        // "mov ds:_KeServiceDescriptorTable.Base, offset _KiServiceTable"   
                        // from the KiInitSystem.   
                        if (*(PWORD)((DWORD)hModule + dwPointerRva-2) == 0x05c7)
                                                {   
                            // should check for a reloc presence on KiServiceTable here   
                            // but forget it   
                            dwKiServiceTable = *(PDWORD)((DWORD)hModule + dwPointerRva + 4) - poh->ImageBase;   
                            return dwKiServiceTable;   
                        }   
                  }   
                     
                }   
                        // should never get here   
            }

            *(PDWORD)&pbr += pbr->SizeOfBlock;   
      }   
    }      
      
    return 0;   
}   
   
DWORD    dwKSDT;            // rva of KeServiceDescriptorTable   
DWORD    dwKiServiceTable;    // rva of KiServiceTable   
DWORD    dwKernelBase, dwServices = 0;   

//////////////////////////////////////////////////////////////////////////
//
//
void GetSSDT()   
{      
    HMODULE                                        hKernel;   
    PCHAR                                        pKernelName;   
    PDWORD                                        pService;   
    PIMAGE_FILE_HEADER                pfh;   
    PIMAGE_OPTIONAL_HEADERpoh;   
    PIMAGE_SECTION_HEADER   psh;
    ULONG n;   
      

    // get system modules - ntoskrnl is always first there   
    ZwQuerySystemInformation(SystemModuleInformation, &n, 0, &n);
       
    PULONG p = new ULONG;

    ZwQuerySystemInformation(SystemModuleInformation, p, n * sizeof(*p), 0);
       
    PSYSTEM_MODULE_INFORMATION module = PSYSTEM_MODULE_INFORMATION(p+1);   
   
    // imagebase   
    dwKernelBase = (DWORD)module->Base;
       
        USHORT ofs = module->ModuleNameOffset;

        char* imgName = (char*)module->ImageName;

        pKernelName = ofs + imgName;
    // filename - it may be renamed in the boot.ini   
    pKernelName = module->ModuleNameOffset + module->ImageName;   
      
    // map ntoskrnl - hopefully it has relocs   
    hKernel = LoadLibraryEx(pKernelName, 0, DONT_RESOLVE_DLL_REFERENCES);
       
    if(!hKernel) {   
      return;   
    }   
      
    // our own export walker is useless here - we have GetProcAddress :)   
    if (!(dwKSDT = (DWORD)GetProcAddress(hKernel, "KeServiceDescriptorTable"))) {   
      return;   
    }   
      
    // get KeServiceDescriptorTable rva   
    dwKSDT -= (DWORD)hKernel;

    // find KiServiceTable   
    if (!(dwKiServiceTable = FindKiServiceTable(hKernel, dwKSDT))) {
      return;   
    }   
      
    // let's dump KiServiceTable contents   
      
    // MAY FAIL!!!   
    // should get right ServiceLimit here, but this is trivial in the kernel mode   
    GetHeaders((PCHAR)hKernel, &pfh, &poh, &psh);

    dwServices = 0;   
   
    for (pService = (PDWORD)((DWORD)hKernel+dwKiServiceTable);
                *pService - poh->ImageBase < poh->SizeOfImage;   
                pService++, dwServices++)   
    {   
      ssdt_list.address1 = *pService - poh->ImageBase + dwKernelBase;   
    }

    FreeLibrary(hKernel);

    MEMORY_CHUNKS QueryBuff;

    DWORD *address2 = new DWORD;

    QueryBuff.Address = dwKernelBase+dwKiServiceTable;

    QueryBuff.Data = address2;

    QueryBuff.Length = sizeof(DWORD)*dwServices;
       
    DWORD ReturnLength;

    ZwSystemDebugControl(
                SysDbgReadVirtualMemory,   
      &QueryBuff, sizeof(MEMORY_CHUNKS), NULL,   
      0, &ReturnLength);   
      
    LV_ITEM lvi;

    lvi.mask = LVIF_TEXT;

    char tmp;

    ListView_DeleteAllItems(hList);

    for (int j=0; j < dwServices; j++)   
    {   
      lvi.iItem = j;   
      lvi.iSubItem = 0;   
      lvi.pszText = tmp;

      wsprintf(tmp, "0x%02X", j);

      ListView_InsertItem(hList, &lvi);

      ListView_SetItemText(hList, j, 1, ssdt_list.fname);

      wsprintf(tmp, "0x%08X", ssdt_list.address1);

      ListView_SetItemText(hList, j, 2, tmp);

      wsprintf(tmp,"0x%08X", address2);

      ssdt_list.address2 = address2;

      ListView_SetItemText(hList, j, 3, tmp);

      for(int i=0; i < *p; i++)
      {   
            if (ssdt_list.address2 > (DWORD)module.Base&&ssdt_list.address2 < (DWORD)module.Base+module.Size)   
            {   
                ListView_SetItemText(hList, j, 4, module.ImageName);   
                break;   
            }   
      }   
    }   
      
    delete [] p;   
    delete [] address2;   
}


void InitListView()   
{
        INITCOMMONCONTROLSEX iex;
        iex.dwSize = sizeof(iex);   
        iex.dwICC=ICC_LISTVIEW_CLASSES;   
        InitCommonControlsEx(&iex);

    hList = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTVIEW, NULL,   
      WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_SINGLESEL | LVS_SHAREIMAGELISTS,   
      0, 0, 0, 0, hWinMain, (HMENU)ID_LISTVIEW, g_hInst, NULL);

    SendMessage(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP | LVS_EX_GRIDLINES);   

        LV_COLUMN lvc;

    lvc.mask = LVCF_TEXT | LVCF_WIDTH ;   
    lvc.fmt = LVCFMT_RIGHT;   

        lvc.pszText = "No.";
        lvc.cx = 50;   
        SendMessage(hList, LVM_INSERTCOLUMN, 0, (LPARAM)&lvc);   
         
        lvc.mask |= LVCF_FMT;
        lvc.fmt = LVCFMT_LEFT;
         
        lvc.pszText = "Function Name";
        lvc.cx = 350;   
        SendMessage(hList, LVM_INSERTCOLUMN, 1, (LPARAM)&lvc);

        lvc.pszText = "OrgAddr";
        lvc.cx = 100;   
        SendMessage(hList, LVM_INSERTCOLUMN, 2, (LPARAM)&lvc);   

        lvc.pszText = "HookAddr";   
        lvc.cx = 100;   
        SendMessage(hList, LVM_INSERTCOLUMN, 3, (LPARAM)&lvc);   

        lvc.pszText = "Module";
        lvc.cx = 200;
        SendMessage(hList, LVM_INSERTCOLUMN, 4, (LPARAM)&lvc);
}   
      
页: [1]
查看完整版本: 简洁有力的纯win32的SSDT List