So, der Florian hat mich breitgeschlagen nochmal zu gucken. Und obwohl wir erstmal den Admin nicht davon abhalten können unseren Prozeß zu killen (resistance is futile?
), hier mal die aktuelle Lösung.
Die Kernfunktion ist folgende:
Delphi-Quellcode:
function ForbidProcessAccess(hProcess: THandle): Boolean;
var
lpSecDesc: PSECURITY_DESCRIPTOR;
lpACL: PACL;
dwAclLength: DWORD;
lpWorldSid: Pointer;
begin
// Default result is FALSE
Result := False;
// Allocate memory for the security descriptor
lpSecDesc := PSECURITY_DESCRIPTOR(GlobalAlloc(GPTR, SECURITY_DESCRIPTOR_MIN_LENGTH));
// Sanity check
if (Assigned(lpSecDesc))
then
try
// Init the structure
InitializeSecurityDescriptor(lpSecDesc, SECURITY_DESCRIPTOR_REVISION);
// Sanity check the creation of the World/Everyone SID
if (AllocateAndInitializeSid(SECURITY_WORLD_SID_AUTHORITY, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, lpWorldSid))
then
try
// Calculate the ACL size required
dwAclLength := sizeof(
ACL) + sizeof(ACCESS_DENIED_ACE) * 1 +
{number of ACEs} GetLengthSid(lpWorldSid);
// Allocate a buffer for the ACL
lpACL := PACL(GlobalAlloc(GPTR, dwAclLength));
// Sanity check
if (Assigned(lpACL))
then
try
// Initialize it, telling the size available
InitializeACL(lpAcl^, dwAclLength, ACL_REVISION);
// Add a "Deny ACE" to it
if (AddAccessDeniedAce(lpAcl^, ACL_REVISION, PROCESS_ALL_ACCESS, lpWorldSid))
then
// Set the ACL as part of the SD
if (SetSecurityDescriptorDacl(lpSecDesc, True, lpACL, False))
then
begin
// Set the new SD
// OWNER_SECURITY_INFORMATION should be given in the flags if the owner was set
// using SetSecurityDescriptorOwner()
Result := SetKernelObjectSecurity(hProcess, DACL_SECURITY_INFORMATION, lpSecDesc);
end;
finally
// Clean up after us
GlobalFree(HGLOBAL(lpACL));
end;
finally
// Clean up after us
FreeSid(lpWorldSid);
end;
finally
// Clean up after us
GlobalFree(HGLOBAL(lpSecDesc));
end;
end;
Man sieht wiedermal meine Vorliebe für GlobalAlloc (das nullt mir nämlich den Puffer auch gleich aus
... und ich mag es richtig schön ausgenullt). Aus Globalisierungsgründen wie immer auf Englisch dokumentiert
So, diese Funktion ruft man nun auf und schon kann der unprivilegierte Benutzer den Prozess nicht mehr killen. Allerdings sollte vermutlich am Owner noch gefeilt werden?!
Im Anhang das komplette Projekt (getestet auf BDS2K6) als
DPR. Es enthält auch die benötigten und nicht von Delphi bereitgestellten Typendeklarationen usw.!
Daß es funzt kann man hier nachvollziehen:
http://assarbad.net/de/stuff/temp/KillMeSoftly/
Es existiert auch noch eine weitere Funktion, die ursprünglich dazu gedacht war das Problem zu lösen, aber das Weglassen von "Allow ACEs" hat es eben nicht gebracht, so daß wir auf "Deny ACEs" ausweichen mußten.
Lizenz: keine! (PUBLIC DOMAIN, keine Garantien oder Haftung meinerseits) - Namensnennung erwünscht.
License: none! (PUBLIC DOMAIN, no guarantees or liability from my side) - Attribution appreciated.
Guten Rutsch (nur nicht auf der Straße, so wie ich vor zwei Wochen -> Gehirnerschütterung),