Napisałem
Killer'a i odpaliłem go na swoim kompie.
Po kilku tygodniach użytkowania doszedłem do wniosku,
że ciągłe włączanie i wyłączanie serwisu jest dosyć denerwujące.
Doszedłem do wniosku, że dobrze by było gdyby
Killer sam
rozpoznawał czy to administrator próbuje coś kombinować
czy użytkownik. Jak to zrobić?
Jak wiadomo każdy proces w
Windows NT ma swojego właściciela.
Najlepiej widać to w
WinFrame i w
Windows NT TSE.
Jednocześnie mogą tam być odpalone procesy należące do
różnych użytkowników. Tak więc wystarczy sprawdzić czy
właściciel procesu jest administratorem i
jeśli tak, to nie podejmować żadnej akcji.
Długo kombinowałem, aż wreszcie znalazłem rozwiązanie w MSDN.
Jest ono trochę dziwne, ale trudno ;-).
Polega to na tym, że pobieramy SID wbudowanej
grupy administratorów i sprawdzamy czy twórca procesu należy do tej grupy.
Zakładam, że już mam uchwyt procesu.
Nie jest to ID procesu, ale jego uchwyt.
Dla aktualnego procesu można go uzyskać za pomocą funkcji
GetCurrentProcess.
hProcess := GetCurrentProcess;
|
Pierwszym krokiem jest pobranie tokenu tego procesu za pomocą funkcji
OpenProcessToken.
Aby odczytać informacje zawarte w tokenie, należy uruchomić powyższą funkcję z
dostępem
TOKEN_QUERY.
OpenProcessToken(hProcess, TOKEN_QUERY, hToken);
|
W ten sposób otrzymujemy uchwyt tokenu. Można powiedzieć, że token reprezentuje użytkownika.
Z samym uchwytem nic się nie da zrobić, dlatego też trzeba pobrać informacje o nim.
Całą robotę wykonuje się za pomocą funkcji
GetTokenInformation.
Za pomocą tej funkcji można pobrać dowolne informacje o użytkowniku.
Nas interesują tylko grupy, do których on należy.
var
dwSize : Cardinal;
dwResult : LongBool;
dwError : Cardinal;
pGroupInfo : PTokenGroups;
hToken : THandle
SIDAuth : SID_IDENTIFIER_AUTHORITY;
{...}
SIDAuth := SECURITY_NT_AUTHORITY;
dwSize := 0;
dwResult := GetTokenInformation(hToken, TokenGroups, nil, dwSize, dwSize);
if not dwResult then
begin
dwError := GetLastError;
if dwError<>ERROR_INSUFFICIENT_BUFFER then Exit;
end;
pGroupInfo := GlobalAllocPtr(GPTR, dwSize);
if not GetTokenInformation(hToken, TokenGroups, pGroupInfo, dwSize, dwSize) then
Exit;
|
W wyniku otrzymujemy strukturę TTokenGroups, w której znajduje się tablica grup.
W każdym elemencie tej tablicy znajduje się SID danej grupy.
pGroupInfo^.Groups[i].Sid
|
Teraz wystarczy sprawdzić czy wśród wszystkich grup do jakich należy użytkownik znajduje się
wbudowana grupa administratorów.
Można to zrobić porównując SID'y za pomocą funkcji
EqualSid.
Ale potrzebujemy jeszcze SID'a wbudowanej grupy administratorów.
Możemy go uzyskać za pomocą funkcji
AllocateAndInitializeSid.
if not AllocateAndInitializeSid(SIDAuth, 2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
SID) then Exit;
|
Teraz wystarczy porównać SID'y i już wiemy czy twórcą procesu jest administrator.
Dobrze jest też sprawdzić, czy porównywana grupa nie jest wyłączona.
if (pGroupInfo^.Groups[i].Attributes and SE_GROUP_ENABLED)<>0 then Exit;
|
To wszystko.
Oczywiście na końcu wypadało by zwolnić pamięć po zaalokowanym SID'ie i strukturze.
Pomocne :-) mogą się okazać funkcje
FreeSid i
GlobalFreePtr.
A teraz
sprostowanie.
Jeśli będziecie próbowali przepisać ten kod to nie skompiluje się on.
A jest to spowodowane tym, że
Borland nie przetłumaczył wszystkich
plików nagłówkowych do
Windows.
Tak więc brak jest wielu stałych - zwłaszcza tych dotyczących
Windows NT.
Moduł z tymi stałymi jest zawarty w Killer'ze, którego możecie
ściągnąć z klastra
Download.
Michał Bąkowski
Tutaj znajdzie się twoje zdanie jeśli znajdziesz chwilkę, żeby je wklepać...