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

跨進程讀取 ListView 內容:VirtualAllocEx + WriteProcessMemory + LVM_GETITEMTEXT 實戰

     編輯:VC 教學

核心挑戰

目標進程的 `ListView` 記憶體空間不在當前進程,需跨進程配置緩衝區、寫入 `LVITEM` 結構、發送訊息、讀回文字。

關鍵步驟

  1. `GetWindowThreadProcessId` → `OpenProcess(PROCESS_ALL_ACCESS)` 取得進程句柄。
  2. `VirtualAllocEx` 在目標進程配置兩塊記憶體:
    • 文字緩衝區(如 1024 bytes)
    • `LVITEM` 結構體
  3. 迴圈 `ListView_GetItemCount` 次:
    • `WriteProcessMemory` 寫入初始化的 `LVITEM`(`pszText` 指向遠端文字緩衝區)。
    • `SendMessage(hWnd, LVM_GETITEMTEXT, i, 遠端LVITEM指標)` 觸發目標進程填充文字。
    • `ReadProcessMemory` 讀回本地緩衝區。
  4. 清理:`VirtualFreeEx` 釋放遠端記憶體、`CloseHandle` 關閉進程句柄。

完整封裝函式


void MyGetListViewItem(HWND hWindow, TStrings *strlist)
{
    const int nMaxLen = 1023;
    char szBuf[nMaxLen+1];
    DWORD dwProcessID;
    HANDLE hProcess = NULL;
    LVITEM lvItemLocal;
    LPVOID lpTextRemote = NULL, lpListItemRemote = NULL;
    DWORD dwBytesRead, dwBytesWrite;
    bool bSuccess, bWriteOK;

    GetWindowThreadProcessId(hWindow, &dwProcessID);
    hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessID);
    if (!hProcess) return;

    lpTextRemote = VirtualAllocEx(hProcess, NULL, nMaxLen+1, MEM_COMMIT, PAGE_READWRITE);
    lpListItemRemote = VirtualAllocEx(hProcess, NULL, sizeof(LVITEM), MEM_COMMIT, PAGE_READWRITE);
    if (!lpTextRemote || !lpListItemRemote) goto Cleanup;

    int nCount = ListView_GetItemCount(hWindow);
    strlist->Add("ListView 項目總數: " + IntToStr(nCount));

    for (int i = 0; i < nCount; i++) {
        ZeroMemory(szBuf, nMaxLen+1);
        bWriteOK = WriteProcessMemory(hProcess, lpTextRemote, szBuf, nMaxLen+1, &dwBytesWrite);
        if (!bWriteOK) break;

        lvItemLocal.iItem = i;
        lvItemLocal.iSubItem = 0;
        lvItemLocal.mask = LVIF_TEXT;
        lvItemLocal.cchTextMax = nMaxLen;
        lvItemLocal.pszText = (LPTSTR)lpTextRemote;

        bWriteOK = WriteProcessMemory(hProcess, lpListItemRemote, &lvItemLocal, sizeof(LVITEM), &dwBytesWrite);
        if (!bWriteOK) break;

        SendMessage(hWindow, LVM_GETITEMTEXT, (WPARAM)i, (LPARAM)lpListItemRemote);

        bSuccess = ReadProcessMemory(hProcess, lpTextRemote, szBuf, nMaxLen+1, &dwBytesRead);
        if (!bSuccess) break;

        strlist->Add(AnsiString(szBuf));
    }

Cleanup:
    if (lpListItemRemote) VirtualFreeEx(hProcess, lpListItemRemote, 0, MEM_RELEASE);
    if (lpTextRemote) VirtualFreeEx(hProcess, lpTextRemote, 0, MEM_RELEASE);
    if (hProcess) CloseHandle(hProcess);
}

進階:報表檢視

若 `ViewStyle = vsReport`,需額外讀取 `LVM_GETCOLUMN` 取得標題,並對每個 `iSubItem` 呼叫 `LVM_GETITEMTEXT`。

權限提示

  • 目標進程若以較高權限執行(如系統服務),需啟用 `SeDebugPrivilege` 或以管理員身分執行讀取端。
  • 64 位元進程無法被 32 位元讀取器讀取,必須編譯為 64 位元。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved