*References:
http://stackoverflow.com/questions/4616281/unable-to-use-lvm-getitemtext-without-target-application-crashing-in-c
http://www.codeproject.com/Articles/5570/Stealing-Program-s-Memory
http://www.codeproject.com/Articles/5570/Stealing-Program-s-Memory
가끔 다른 프로세스의 SysListView32를 읽고싶을 때가 있다.
그런데 막상 해보니까 쉬울줄 알았던 일이 잘 안돼서 고생을 좀 하다가.. 검색을 통해 해결했다.
그런데 막상 해보니까 쉬울줄 알았던 일이 잘 안돼서 고생을 좀 하다가.. 검색을 통해 해결했다.
우선 다음과 같은 코드를 생각해보자.
#define WIN32_LEAN_AND_MEAN // compile faster #include <stdio.h> #include <locale.h> #include <windows.h> #include <commctrl.h> const int COLS(5), SZBUF(512); int main(void) { setlocale(LC_ALL, ""); // 한글 출력을 위해 기본 로케일 설정. HWND hParent = FindWindow(NULL, L"SW 찾기"); HWND hListView = FindWindowEx(hParent, NULL, L"SysListView32", NULL); int numItems=(int)SendMessage(hListView, LVM_GETITEMCOUNT, 0, 0); LVITEM lvi; wchar_t subItems[COLS][SZBUF] = {}; lvi.cchTextMax=SZBUF; // 텍스트 버퍼 사이즈를 설정 for(int i = 0; i < numItems; i++) { for (int j = 0; j < COLS; j++) { // j번째 column의 값을 얻는다. lvi.iSubItem = j; lvi.pszText = subItems[j]; wcscpy(subItems[j], L"끼야아앙"); SendMessage(hListView, LVM_GETITEMTEXTW, (WPARAM)i, (LPARAM)&lvi); printf("%s%ls", j > 0 ? ";" : "", subItems[j]); // column1;column2;column3 형식으로 한 줄씩 출력. } puts(""); } return 0; }
완벽해보이...지만 실행해보면?
C:\>a.exe |
실제로 버퍼에 아무것도 쓰이지 않은 것을 확인할 수 있다.
원인이 뭘까 고민해보다가 reference에서 그 답을 찾았다.
요약하자면 "ListView를 가진 프로세스는 a.exe의 메모리에 접근 권한이 없음!" 이라고..
그러므로 일단 ListView를 가진 프로세스에 메모리를 할당하고,
우리는 ReadProcessMemory/WriteProcessMemory를 이용해서 해당 메모리에 접근하면 된다.
덕분에 코드는 더 지저분해졌지만, 어쨌든 돌아는 간다 :D
최종 결과물
#define WIN32_LEAN_AND_MEAN // compile faster #include <stdio.h> #include <locale.h> #include <windows.h> #include <commctrl.h> const int COLS(5), SZBUF(512); int main(void) { setlocale(LC_ALL, ""); // 한글 출력을 위해 기본 로케일 설정. HWND hParent = FindWindow(NULL, L"SW 찾기"); HWND hListView = FindWindowEx(hParent, NULL, L"SysListView32", NULL); int numItems=(int)SendMessage(hListView, LVM_GETITEMCOUNT, 0, 0); LVITEM lvi, *_lvi = NULL; wchar_t subItems[COLS][SZBUF] = {}; wchar_t *_subItems[COLS] = {}; unsigned long pid = -1; HANDLE process = NULL; // hWnd로부터 pid를 얻는다. GetWindowThreadProcessId(hListView, &pid); // 해당 pid를 가진 프로세스에 대해 VM조작 권한을 얻는다. process=OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_READ| PROCESS_VM_WRITE|PROCESS_QUERY_INFORMATION, FALSE, pid); _lvi=(LVITEM*)VirtualAllocEx(process, NULL, sizeof(LVITEM), MEM_COMMIT, PAGE_READWRITE); // ListView를 가지고 있는 프로세스에 LVITEM 메모리를 할당한다. for (int i = 0; i < COLS; i++) { _subItems[i]=(wchar_t*)VirtualAllocEx(process, NULL, SZBUF * sizeof(wchar_t), MEM_COMMIT, PAGE_READWRITE); // ListView를 가지고 있는 프로세스에 wchar[] 메모리를 할당한다. } lvi.cchTextMax=SZBUF; // 텍스트 버퍼 사이즈를 설정 for(int i = 0; i < numItems; i++) { for (int j = 0; j < COLS; j++) { // j번째 column의 값을 얻는다. lvi.iSubItem = j; lvi.pszText = _subItems[j]; // 반환되는 텍스트는 타겟 프로세스의 wchar[] 버퍼에 써진다. WriteProcessMemory(process, _lvi, &lvi, sizeof(LVITEM), NULL); // 타겟 프로세스의 LVITEM에 lvi의 설정값을 쓴다(복사). SendMessage(hListView, LVM_GETITEMTEXTW, (WPARAM)i, (LPARAM)_lvi); ReadProcessMemory(process, _subItems[j], subItems[j], SZBUF, NULL); // 타겟 프로세스의 wchar[] 버퍼를 읽는다. printf("%s%ls", j > 0 ? ";" : "", subItems[j]); // column1;column2;column3 형식으로 한 줄씩 출력. } puts(""); } // 타겟 프로세스에 할당한 메모리를 해제한다. VirtualFreeEx(process, _lvi, 0, MEM_RELEASE); for (int j = 0; j < COLS; j++) { VirtualFreeEx(process, _subItems[j], 0, MEM_RELEASE); } return 0; }
'Computer' 카테고리의 다른 글
[Fedora] OpenVAS 설치 (0) | 2015.04.22 |
---|---|
Windows에서 PHP LDAP 이용하기 (0) | 2015.04.08 |
img2term: 터미널에서 이미지 보기 (0) | 2015.03.24 |
[Ubuntu] 유저에게 sudo 권한 주기. (0) | 2015.03.13 |
Advices for applying machine learning. (0) | 2015.03.11 |