I wrote
Killer and launched it on my computer.
After a few weeks of using it I came to a conclusion that turning
the service on and off all the time is quite annoying.
I figured that it would be good if
Killer was able to detect
whether the administrator is trying to mess up or is this a user.
As it is known every process in
Windows NT has its owner.
It can be seen best in
WinFrame and in
Windows NT TSE.
Processes which belong to different users may be launched simultaneously.
Thus it is sufficient to detect whether the process owner is the administrator and if so then
no action is taken.
I was thinking for a long time and finally I found a solution in MSDN.
It is a bit strange, but it doesn't matter ;-).
It consists on getting the SID of administrators group and check if process creator belongs
to that group.
I assume I already have the process handle at the moment. It is not its ID but its handle.
It can be retreived for the current process using
GetCurrentProcess function.
hProcess := GetCurrentProcess;
|
The first step is to take the token of that process using
OpenProcessToken function.
In order to read the information inside the token the above function ought to be called with
TOKEN_QUERY access.
OpenProcessToken(hProcess, TOKEN_QUERY, hToken);
|
That's the way to obtain token's handle. One may say that a token represents a user.
With the handle itself there is nothing to be done, because one needs to get information
about it.
The whole work can be done by means of
GetTokenInformation function.
Thanks to that function one may take any information about a user.
What we are interested in - these are the groups he or she belongs to.
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;
|
In the effect we get TTokenGroups structure, in which group table is placed.
Each table elements contains a SID to the particular group.
pGroupInfo^.Groups[i].Sid
|
Now it is sufficient to check if administrator group exists amongst all those
groups the user belongs to.
EqualSid.
But we still need administrator group SID.
It can be obtained using
AllocateAndInitializeSid function.
if not AllocateAndInitializeSid(SIDAuth, 2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
SID) then Exit;
|
Now one needs to compare SIDs and it is clear who was the process creator.
It is also good to see if the group being compared is not off.
if (pGroupInfo^.Groups[i].Attributes and SE_GROUP_ENABLED)<>0 then Exit;
|
That's all.
Of course it would be nice to free memory after allocated SID and the structure.
These are the functions that can proof to be helpful :-)
FreeSid and
GlobalFreePtr.
And now, I owe some
explanation.
If you try to copy this code it wouldn't be compiled.
And it is happening because Borland did not translate all the
Windows header files.
Therefore there is lack for many constants - especially those concerning
Windows NT.
The module with those constants is located in Killer which everyone can download from
Download cluster.
Michał B±kowski