C Helpdesk
0x01. Wstęp.
0x02. Funkcja DuplicateHandle.
0x03. Zastosowanie funkcji DuplicateHandle.
0x04. Zakończenie.
0x05. Bibliografia.
0x01. Wstęp
Niniejszy artykuł jest uzupełnieniem tekstu "Współużytkowanie obiektów jądra w systemie Windows". Demonstruje on mechanizm duplikowania uchwytów obiektów jądra, czyli jedną z metod ich współużytkowania.
Tekst jest przeznaczony dla osób znających WinAPI oraz język C/C++ w stopniu podstawowym.
0x02. Funkcja DuplicateHandle
Do duplikowania uchwytów obiektów służy funkcja o "zaskakującej" nazwie DuplicateHandle. Oto jej prototyp:
BOOL DuplicateHandle( HANDLE hSourceProcessHandle,
HANDLE hSourceHandle,
HANDLE hTargetProcessHandle,
PHANDLE phTargetHandle,
DWORD dwDesiredAccess,
BOOL bInheritHandle,
DWORD dwOptions );
* hSourceProcessHandle – ten parametr przekazuje uchwyt [obiektu] procesu-źródła, z którego pobierzemy wartość uchwytu obiektu. Proces-źródło jest właścicielem obiektu, którego uchwyt chcemy zduplikować.
* hSourceHandle – ten parametr wskazuje na uchwyt obiektu jądra i właśnie ten uchwyt jest duplikowany.
* hTargetProcessHandle – wartość uchwytu obiektu-procesu, do którego przekazywany jest duplikowany uchwyt.
* phTargetHandle – jest to adres zmiennej typu HANDLE, do której trafia indeks pozycji z kopią informacji o uchwycie źródłowym (chodzi o wartość uchwytu).
* dwDesiredAccess – flagi dostępu do obiektu jądra. (Parametr ten jest ignorowany, jeśli parametr dwOptions ma wartość DUPLICATE_SAME_ACCESS.
* bInheritHandle – określa, czy sklonowany uchwyt jest dziedziczny.
* dwOptions – ten parametr może mieć wartość 0 lub: DUPLICATE_SAME_ACCESS (uchwyt docelowy ma mieć taką samą maskę dostępu co uchwyt źródłowy) oraz DUPLICATE_CLOSE_SOURCE (powoduje zamknięcie uchwytu w procesie źródłowym).
0x03. Zastosowanie funkcji DuplicateHandle
Napiszemy teraz dwa programiki: source i target. Z procesu source przekażemy uchwyt obiektu-zdarzenia poprzez jego duplikację do procesu target.
source.cpp
#include <windows.h> #include <tlhelp32.h> #include <iostream> #include <fstream> using namespace std; int WINAPI WinMain(HINSTANCE hi,HINSTANCE,PSTR cmd,int show) { HANDLE uchwyt_zdarzenia_s=CreateEvent(NULL,TRUE,FALSE, NULL); HANDLE uchwyt_zdarzenia_t; HANDLE uchwyt_source = GetCurrentProcess(); HANDLE uchwyt_target; MessageBox(NULL, TEXT("Zanim wciśniesz OK, uruchom proces \"target\""), TEXT("Uwaga !"), MB_OK | MB_ICONINFORMATION); /*------------------------------------------------------------------------------- Wyszukanie procesu o nazwie ´target´ i przypisanie do zmiennej ´uchwyt_target´ jego uchwytu ---------------------------------------------------------------------------------*/ HANDLE snapshot; snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); PROCESSENTRY32 p32; p32.dwSize = sizeof(PROCESSENTRY32); do { if(lstrcmp(p32.szExeFile, "target.exe") == 0) uchwyt_target=OpenProcess(PROCESS_ALL_ACCESS, FALSE, p32.th32ProcessID); } while (Process32Next(snapshot, &p32)); /*-------------------------------------------------------------------------------*/ DuplicateHandle(uchwyt_source, uchwyt_zdarzenia_s, uchwyt_target, &uchwyt_zdarzenia_t, 0, FALSE, DUPLICATE_SAME_ACCESS); ofstream Strm("plik.txt"); Strm << uchwyt_zdarzenia_t; return 0; }
* Na samym początku tworzymy zdarzenie w stanie niesygnalizowanym i przypisujemy wartość uchwytu obiektu-zdarzenia do zmiennej uchwyt_zdarzenia_s. To właśnie ten uchwyt zdyplikujemy i przekażemy go do procesu target. Musimy jeszcze zainicjować zmienną uchwyt_zdarzenia_t, która będzie przechowywać wartość zduplikowanego uchwytu po wywołaniu funkcji DuplicteHandle.
* Następnie inicjalizujemy dwie zmienne typu HANDLE. uchwyt_source przechowuje wartość uchwytu bieżącego procesu. Funkcja GetCurrentProcess zwraca pseudouchwyt procesu, który ją wywołał. Zainicjalizowaliśmy jeszcze zmienną uchwyt_target, ponieważ będzie ona za chwilkę przechowywać uchwyt procesu docelowego. Jest to potrzebne do pomyślnego wywołania funkcji DuplicateHandle.
* Za pomocą funkcji MessageBox zatrzymamy nasz program, żeby uruchomić proces target.Jest to wymagane, ponieważ następny fragment kodu będzie przeszukiwał procesy w systemie w celu wyszukania procesu o nazwie target. Dzięki temu, możliwe będzie przypisanie uchwytu procesu docelowego do zmiennej uchwyt_target.
* Przeanalizujmy teraz wydzielony fragment kodu odpowiedzialny za wyszukanie w systemie procesu o nazwie target i przypisanie zmiennej uchwyt_target. Nie będę się teraz rozpisywał na temat tego fragmentu, ale opiszę w skrócie co on robi. Za pomocą funkcji CtreateToolhelp32Snapshot pobieramy obraz ("snapshot") wszystkich działających procesów w systemie (oczywiście funkcja ta ma też inne zastosowania). Następnie, w instrukcji warunkowej do...while szukamy procesu o nazwie target.exe (oczywiście musi on być wcześniej uruchomiony). Robimy to poprzez porównanie składowej szExeFile (składowa struktury PROCESSENTRY32) z nazwą procesu. Jeśli porównanie wypadnie pomyślnie, wywołujemy funkcję OpenProcess, która przypisze uchwyt znalezionego procesu do zmiennej uchwyt_target.
* Nareszcie możemy przystapić do duplikacji. Wywołujemy funkcję DuplicateHandle z odpowiednimi parametrami. Jej prototyp został opisany wcześniej, więc nie powinno być problemu ze zrozumieniem tego fragmentu kodu.
* Na koniec musimy jeszcze przekazać w jakiś sposób wartość zduplikowanego uchwytu. Robi się to za pomocą jednego z mechanizmów IPC (Inter-Process Communication). My posłużymy się plikiem o nazwie plik.txt, korzystając ze standardowej biblioteki C++. UWAGA: w tej wersji kodu, pliki source.exe i target.exe muszą znajdować się w tym samym katalogu, ponieważ korzystają z tego samego pliku *.txt.
target.cpp
#include <windows.h> #include <iostream> #include <fstream> using namespace std; int WINAPI WinMain(HINSTANCE hi,HINSTANCE, PSTR cmd, int show) { MessageBox(NULL, TEXT("Zanim wciśniesz OK tutaj, wciśnij OK w procesie \"source\""), TEXT("Uwaga!"), MB_OK | MB_ICONINFORMATION); ifstream Strm("plik.txt"); HANDLE uchwyt_zdarzenia; Strm >> uchwyt_zdarzenia; BOOL test = SetEvent(uchwyt_zdarzenia); if(test==TRUE) MessageBox(NULL, TEXT("Uchwyt został zduplikowany!"), TEXT("Sukces!"), MB_OK | MB_ICONINFORMATION); else MessageBox(NULL, TEXT("Uchwyt nie został zduplikowany!"), TEXT("Porażka!"), MB_OK | MB_ICONERROR); return 0; }
* No i w końcu proces, który przejmie zduplikowany uchwyt obiektu-zdarzenia. Na samym początku zatrzymujemy program za pomocą funkcji MessageBox. Teraz proces target działa i proces źródłowy source może spokojnie wykonać resztę kodu. Gdy to nastąpi, możemy kontynuować wykonywanie kodu procesu target.
* Odczytujemy zawartość pliku plik.txt gdzie proces źródłowy zapisał wartość zduplikowanego uchwytu. Używamy do tego standardowej biblioteki C++.
* Zmieniamy stan obiektu-zdarzenia na sygnalizowany za pomocą funkcji SetEvent i sprawdzamy, czy uchwyt został prawidłowo zduplikowany i przekazany do procesu docelowego.
0x04. Zakończenie
To wszystko, jeżeli chodzi o współużytkowanie obiektów. W przypadku problemów ze zrozumieniem pewnych elementów, można wrócić do mojego wcześniejszego artykułu: Współużytkowanie obiektów jądra w systemie Windows. Dobrym źródłem wiedzy o WinAPI jest też msdn.microsoft.com
0x05. Bibliografia
J. Richter, Programowanie aplikacji dla Windows, Warszawa 2002;
msdn.microsoft.com
Offline