首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

跨行程取得 ListView 控制項文字:LVM_GETITEMTEXT 實戰

     編輯:關於VC++

開發一個名為 CallFI 的小工具,搭配 Windows 2000/XP 的工作管理器,能取得指定行程的完整路徑並呼叫 FileInfo 分析工具。核心難點在於:跨行程向 SysListView32 發送 LVM_GETITEMTEXT 訊息時,無法直接取得回傳字串。

問題根源與解決方案

Google 搜尋發現 Cory Nelson 的《Stealing Program's Memory》一文:關鍵在於使用 WriteProcessMemory() 將 LVITEM 結構寫入目標行程記憶體空間,再發送訊息,最後用 ReadProcessMemory() 讀回結果。

完整實作程式碼

//////////////////////////////////////////////////////////////////////////////////
// Send_LGT
// 版權所有 (C) 2004 趙春生
// 適用:Win2K SP4 [TaskMgr 5.0.2195.6620] / WinXP SP1 [TaskMgr]
// 測試環境:Win2000 SP4 + VC6 SP5
//////////////////////////////////////////////////////////////////////////////////
#include <windows.h>
#include <commctrl.h>

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    HWND hwnd;
    int iItem = 0;
    LVITEM lvitem, *plvitem;
    char ItemBuf[512], *pItem;
    DWORD PID;
    HANDLE hProcess;

    // 尋找工作管理員的 ListView 視窗
    hwnd = FindWindow("#32770", "Windows 任務管理器");
    hwnd = FindWindowEx(hwnd, 0, "#32770", 0);
    hwnd = FindWindowEx(hwnd, 0, "SysListView32", 0);
    
    if (!hwnd)
        MessageBox(NULL, "[Windows 任務管理器] 尚未啟動!", "錯誤!", NULL);
    else
    {
        // 取得目前選取項目索引
        iItem = SendMessage(hwnd, LVM_GETNEXTITEM, -1, LVNI_SELECTED);
        if (iItem == -1)
            MessageBox(NULL, "沒有指定目標行程!", "錯誤!", NULL);
        else
        {
            GetWindowThreadProcessId(hwnd, &PID);
            hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);
            if (!hProcess)
                MessageBox(NULL, "取得行程控制代碼失敗!", "錯誤!", NULL);
            else
            {
                // 在目標行程配置記憶體
                plvitem = (LVITEM*)VirtualAllocEx(hProcess, NULL, sizeof(LVITEM), MEM_COMMIT, PAGE_READWRITE);
                pItem = (char*)VirtualAllocEx(hProcess, NULL, 512, MEM_COMMIT, PAGE_READWRITE);
                
                if ((!plvitem) || (!pItem))
                    MessageBox(NULL, "無法配置記憶體!", "錯誤!", NULL);
                else
                {
                    lvitem.cchTextMax = 512;
                    lvitem.iSubItem = 0;  // 0 = 行程名稱, 1 = PID
                    lvitem.pszText = pItem;
                    
                    // 寫入 LVITEM 結構到目標行程
                    WriteProcessMemory(hProcess, plvitem, &lvitem, sizeof(LVITEM), NULL);
                    // 發送訊息
                    SendMessage(hwnd, LVM_GETITEMTEXT, (WPARAM)iItem, (LPARAM)plvitem);
                    // 讀回結果
                    ReadProcessMemory(hProcess, pItem, ItemBuf, 512, NULL);
                    MessageBox(NULL, ItemBuf, "ItemBuf", NULL);
                }
            }
        }
    }
    
    // 釋放資源
    CloseHandle(hProcess);
    VirtualFreeEx(hProcess, plvitem, 0, MEM_RELEASE);
    VirtualFreeEx(hProcess, pItem, 0, MEM_RELEASE);
    return 0;
}

關鍵點總結

  • 必須在目標行程虛擬位址空間配置 LVITEM 結構與字串緩衝區。
  • 使用 WriteProcessMemory 寫入參數,SendMessage 觸發,ReadProcessMemory 讀回。
  • iSubItem = 0 取行程名稱,1 取 PID,依此類推。
  • 需具備 PROCESS_ALL_ACCESS 權限,受限於 UAC 與防毒軟體可能需管理員權限執行。

完整原始碼請下載本文附帶範例專案。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved