開發一個名為 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 與防毒軟體可能需管理員權限執行。完整原始碼請下載本文附帶範例專案。