Process Hacker and Windows discussion

 
Zorkov Igor
Member
Posts: 113
OS: Windows 7, 10
Location: Великая Русь
Contact:

OpenProcessToken for a protected process in Windows 7

22 Mar 2011, 04:08

Open process token for System (PID: 4) process in user mode:

[delphi]

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ComCtrls, StdCtrls, ExtCtrls, AccCtrl, AclAPI, TlHelp32, XPMan;

type
TForm1 = class(TForm)
ListView1: TListView;
Button2: TButton;
Timer1: TTimer;
XPManifest1: TXPManifest;
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure ListView1CustomDrawItem(Sender: TCustomListView;
Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

type
NTSTATUS = Integer;

const
STATUS_SUCCESS = NTSTATUS($00000000);
STATUS_INFO_LENGTH_MISMATCH = NTSTATUS($C0000004);

PROCESS_QUERY_LIMITED_INFORMATION = $1000;

type
UNICODE_STRING = packed record
Length,
MaximumLength: WORD;
Buffer: PWideChar;
end;
TUnicodeString = UNICODE_STRING;
PUnicodeString = ^TUnicodeString;

CLIENT_ID = packed record
UniqueProcess: Cardinal;
UniqueThread: Cardinal;
end;

_VM_COUNTERS = packed record
PeakVirtualSize: ULONG;
VirtualSize: ULONG;
PageFaultCount: ULONG;
PeakWorkingSetSize: ULONG;
WorkingSetSize: ULONG;
QuotaPeakPagedPoolUsage: ULONG;
QuotaPagedPoolUsage: ULONG;
QuotaPeakNonPagedPoolUsage: ULONG;
QuotaNonPagedPoolUsage: ULONG;
PageFileUsage: ULONG;
PeakPageFileUsage: ULONG;
end;

_IO_COUNTERS = packed record
ReadOperationCount: Int64;
WriteOperationCount: Int64;
OtherOperationCount: Int64;
ReadTransferCount: Int64;
WriteTransferCount: Int64;
OtherTransferCount: Int64;
end;

SYSTEM_THREADS = packed record
KernelTime: LARGE_INTEGER;
UserTime: LARGE_INTEGER;
CreateTime: LARGE_INTEGER;
WaitTime: ULONG;
StartAddress: Pointer;
ClientId: CLIENT_ID;
Priority: Integer;
BasePriority: Integer;
ContextSwitchCount: ULONG;
State: Integer;
WaitReason: Integer;
Reserved: ULONG;
end;

SYSTEM_THREADS_ARRAY = array[0..1024] of SYSTEM_THREADS;
PSYSTEM_THREADS_ARRAY = ^SYSTEM_THREADS_ARRAY;

SYSTEM_PROCESS_INFORMATION = packed record
NextEntryDelta: ULONG;
ThreadCount: ULONG;
Reserved1: array[0..5] of ULONG;
CreateTime: FILETIME;
UserTime: FILETIME;
KernelTime: FILETIME;
ProcessName: UNICODE_STRING;
BasePriority: Integer;
ProcessId: ULONG;
InheritedFromProcessId: ULONG;
HandleCount: ULONG;
Reserved2: array[0..1] of ULONG;
VmCounters: _VM_COUNTERS;
PrivatePageCount: ULONG;
IoCounters: _IO_COUNTERS;
Threads: array[0..1024] of SYSTEM_THREADS;
end;
PSYSTEM_PROCESS_INFORMATION = ^SYSTEM_PROCESS_INFORMATION;

type
TNtQuerySystemInformation = function(SystemInformationClass: LongInt;
SystemInformation: Pointer;
SystemInformationLength: ULONG;
ReturnLength: PDWORD): Integer; stdcall;

TGetTokenInformation = function(TokenHandle: Cardinal;
TokenInformationClass: Cardinal; TokenInformation: Pointer;
TokenInformationLength: DWORD; var ReturnLength: DWORD): BOOL; stdcall;

var
ImpersonateToken: Cardinal;
NtQuerySystemInformation: TNtQuerySystemInformation;
_GetTokenInformation: TGetTokenInformation;

implementation

{$R *.dfm}

function _GetWinlogonProcessId: Cardinal;
var
hProcSnap: Cardinal;
pe32: TProcessEntry32;
i: Cardinal;
begin
Result:= 0;
hProcSnap:= CreateToolHelp32SnapShot(TH32CS_SNAPPROCESS, 4);
if hProcSnap = INVALID_HANDLE_VALUE then
Exit;
pe32.dwSize:= SizeOf(ProcessEntry32);
while Process32Next(hProcSnap, pe32) = True do
begin
if (LowerCase(pe32.szExeFile) = 'winlogon.exe') then
begin
Result:= pe32.th32ProcessID;
end;
end;
CloseHandle(hProcSnap);
end;

function _GetImpersonateToken: Boolean;
var
ProcessHandle, TokenHandle: Cardinal;
PSD: PPSECURITY_DESCRIPTOR;
ppDacl: PACL;
begin
Result:= False;
ProcessHandle:= 0;
ProcessHandle:= OpenProcess(MAXIMUM_ALLOWED, False, _GetWinlogonProcessId);
if ProcessHandle <> 0 then
begin
try
if OpenProcessToken(ProcessHandle, MAXIMUM_ALLOWED, TokenHandle) then
begin
try
if not DuplicateTokenEx(TokenHandle, MAXIMUM_ALLOWED, nil, SecurityImpersonation, TokenPrimary, ImpersonateToken) then
begin
if GetSecurityInfo(TokenHandle, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, nil, nil, @ppDacl, nil, PSD) = ERROR_SUCCESS then
begin
if SetSecurityInfo(TokenHandle, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, nil, nil, nil, nil) = ERROR_SUCCESS then
begin
if OpenProcessToken(ProcessHandle, MAXIMUM_ALLOWED, TokenHandle) then
if DuplicateTokenEx(TokenHandle, MAXIMUM_ALLOWED, nil, SecurityImpersonation, TokenPrimary, ImpersonateToken) then
Result:= True;
SetSecurityInfo(TokenHandle, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, nil, nil, ppDacl, nil);
end;
LocalFree(DWORD(ppDacl));
LocalFree(DWORD(PSD));
end;
end
else
Result:= True;
finally
CloseHandle(TokenHandle);
end;
end;
finally
CloseHandle(ProcessHandle);
end;
end;
end;

function _GetCurrentProcessPrivilege(PrivilegeName: WideString): Boolean;
var
TokenHandle: Cardinal;
TokenPrivileges: TTokenPrivileges;
ReturnLength: Cardinal;
begin
Result:= False;
if Windows.OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, TokenHandle) then
begin
try
LookupPrivilegeValueW(nil, PWideChar(PrivilegeName), TokenPrivileges.Privileges[0].Luid);
TokenPrivileges.PrivilegeCount:= 1;
TokenPrivileges.Privileges[0].Attributes:= SE_PRIVILEGE_ENABLED;
if AdjustTokenPrivileges(TokenHandle, False, TokenPrivileges, 0, nil, ReturnLength) then
Result:= True;
finally
CloseHandle(TokenHandle);
end;
end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
hLibrary: Cardinal;
begin
Font:= Screen.HintFont;
_GetCurrentProcessPrivilege('SeDebugPrivilege');
_GetImpersonateToken;
hLibrary:= LoadLibrary('ntdll.dll');
if hLibrary <> 0 then
begin
@NtQuerySystemInformation:= GetProcAddress(hLibrary, 'NtQuerySystemInformation');
hLibrary:= 0;
end;
hLibrary:= LoadLibrary('Advapi32.dll');
if hLibrary <> 0 then
begin
@_GetTokenInformation:= GetProcAddress(hLibrary, 'GetTokenInformation');
hLibrary:= 0;
end;
end;

type
TProcess = record
Process: WideString;
ProcessId: Integer;
end;
TProcessList = array of TProcess;

function GetProcessList(var ProcessList: TProcessList): Cardinal;
var
SystemInformation: Pointer;
SystemInformationLength: Integer;
ReturnLength: DWORD;
ReturnStatus: NTSTATUS;
PSPI: PSYSTEM_PROCESS_INFORMATION;
begin
Result:= 0;
if (@NtQuerySystemInformation = nil) then
Exit;
Finalize(ProcessList);
SystemInformationLength:= $1000;
GetMem(SystemInformation, SystemInformationLength);
ReturnStatus:= NtQuerySystemInformation(5, SystemInformation, SystemInformationLength, @ReturnLength);
while (ReturnStatus = STATUS_INFO_LENGTH_MISMATCH) do
begin
FreeMem(SystemInformation);
SystemInformationLength:= SystemInformationLength * 2;
try
GetMem(SystemInformation, SystemInformationLength);
except
Exit;
end;
ReturnStatus:= NtQuerySystemInformation(5, SystemInformation, SystemInformationLength, @ReturnLength);
end;
try
if ReturnStatus = STATUS_SUCCESS then
begin
PSPI:= PSYSTEM_PROCESS_INFORMATION(SystemInformation);
repeat
SetLength(ProcessList, Length(ProcessList) + 1);
if PSPI^.ProcessId = 0 then
ProcessList[Result].Process:= 'System Idle Process'
else
ProcessList[Result].Process:= WideString(PSPI^.ProcessName.Buffer);
ProcessList[Result].ProcessId:= PSPI^.ProcessId;
Inc(Result);
if PSPI^.NextEntryDelta = 0 then
Break;
PSPI:= PSYSTEM_PROCESS_INFORMATION(PAnsiChar(PSPI) + PSPI^.NextEntryDelta);
until
False;
end;
finally
FreeMem(SystemInformation);
SystemInformation:= nil;
end;
end;

type
TTokenUser = record
User: WideString;
Domain: WideString;
end;

function _GetTokenUser(TokenHandle: DWORD; var TokenUser: TTokenUser): Boolean;
var
ReturnLength: DWORD;
peUse: SID_NAME_USE;
SIDAndAttributes: PSIDAndAttributes;
Name: PWideChar;
DomainName: PWideChar;
begin
TokenUser.User:= '';
TokenUser.Domain:= '';
Result:= False;
if (@_GetTokenInformation = nil) then
Exit;
_GetTokenInformation(TokenHandle, 1, nil, 0, ReturnLength);
try
GetMem(SIDAndAttributes, ReturnLength);
except
Exit;
end;
try
if _GetTokenInformation(TokenHandle, 1 {TokenUser}, SIDAndAttributes, ReturnLength, ReturnLength) then
begin
ReturnLength:= MAX_PATH;
try
GetMem(Name, ReturnLength);
GetMem(DomainName, ReturnLength);
except Exit;
end;
try
if LookupAccountSidW(nil, SIDAndAttributes.Sid, Name, ReturnLength, DomainName, ReturnLength, peUse) then
begin
TokenUser.User:= WideString(Name);
TokenUser.Domain:= WideString(DomainName);
Result:= True;
end;
finally
FreeMem(Name);
FreeMem(DomainName);
end;
end;
finally
FreeMem(SIDAndAttributes, ReturnLength);
end;
end;

function GetTokenUser_Impersonate(ProcessId: DWORD; var TokenUser: TTokenUser): Boolean;
var
ProcessHandle: Cardinal;
TokenHandle: Cardinal;
begin
Result:= False;
try

ImpersonateLoggedOnUser(ImpersonateToken);

try
ProcessHandle:= 0;
ProcessHandle:= OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, True, ProcessId);
if ProcessHandle <> 0 then
begin
try
if OpenProcessToken(ProcessHandle, TOKEN_QUERY, TokenHandle) then
Result:= _GetTokenUser(TokenHandle, TokenUser);
finally
CloseHandle(TokenHandle);
end;
end;
finally
CloseHandle(ProcessHandle);
end;

RevertToSelf;

except
RevertToSelf;
Exit;
end;
end;

function GetTokenUser(ProcessId: DWORD; var TokenUser: TTokenUser): Boolean;
var
ProcessHandle: Cardinal;
TokenHandle: Cardinal;
begin
Result:= False;
try
try
ProcessHandle:= 0;
ProcessHandle:= OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, True, ProcessId);
if ProcessHandle <> 0 then
begin
try
if OpenProcessToken(ProcessHandle, TOKEN_QUERY, TokenHandle) then
Result:= _GetTokenUser(TokenHandle, TokenUser);
finally
CloseHandle(TokenHandle);
end;
end;
finally
CloseHandle(ProcessHandle);
end;
except
Exit;
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
i, ProcessCount: Cardinal;
ProcessList: TProcessList;
TokenUser: TTokenUser;
begin
ProcessCount:= GetProcessList(ProcessList);
ListView1.Items.BeginUpdate;
ListView1.Items.Clear;
if ProcessCount > 0 then
begin
for i:= 0 to ProcessCount - 1 do
begin
with ListView1.Items.Add do
begin
Data:= Pointer(RGB(255, 255, 255));
Caption:= ProcessList.Process;
SubItems.Add(IntToStr(ProcessList.ProcessId));
if ProcessList.ProcessId > 0 then
begin
if GetTokenUser(ProcessList.ProcessId, TokenUser) then
SubItems.Add(TokenUser.Domain + '\' + TokenUser.User);
end;
end;
end;
end;
ListView1.Items.EndUpdate;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
i, ProcessCount: Cardinal;
ProcessList: TProcessList;
TokenUser: TTokenUser;
begin
ProcessCount:= GetProcessList(ProcessList);
ListView1.Items.BeginUpdate;
ListView1.Items.Clear;
if ProcessCount > 0 then
begin
for i:= 0 to ProcessCount - 1 do
begin
with ListView1.Items.Add do
begin
Data:= Pointer(RGB(255, 255, 255));
Caption:= ProcessList.Process;
SubItems.Add(IntToStr(ProcessList.ProcessId));
if ProcessList.ProcessId > 0 then
begin
if GetTokenUser_Impersonate(ProcessList.ProcessId, TokenUser) then
begin
if ProcessList.ProcessId = 4 then //System Process
Data:= Pointer(RGB(170, 204, 255));
SubItems.Add(TokenUser.Domain + '\' + TokenUser.User);
end;
end;
end;
end;
end;
ListView1.Items.EndUpdate;
end;

procedure TForm1.ListView1CustomDrawItem(Sender: TCustomListView;
Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
begin
Sender.Canvas.Brush.Color:= TColor(Item.Data);
end;

end.[/delphi]

[attachment=1]TEST.zip[/attachment]
Last edited by Zorkov Igor on 31 Mar 2011, 19:31, edited 1 time in total.
 
User avatar
wj32
Founder
Posts: 948
OS: Windows
Location: Australia
Contact:

Re: OpenProcessToken for a protected process in Windows 7

22 Mar 2011, 05:20

Thanks for the code samples, Zorkov Igor. :thumbup:
 
Zorkov Igor
Member
Posts: 113
OS: Windows 7, 10
Location: Великая Русь
Contact:

Re: OpenProcessToken for a protected process in Windows 7

22 Mar 2011, 11:21

wj32 wrote:
Thanks for the code samples, Zorkov Igor. :thumbup:
And what do you think about this method?

Set security info for winlogon to null
 
DdgdGhht
New User
Posts: 1
OS: Windows 8

Re: OpenProcessToken for a protected process in Windows 7

21 Mar 2017, 17:39

Good share

Who is online

Users browsing this forum: Bing and 6 guests