2016-06-11 98 views
1

如何通過Delphi中的SYSTEM NT Authority賬戶創建進程? 是否有API,例如CreateProcessAsUser函數。通過delphi系統創建進程

+1

這是超強大的本地系統帳戶。最佳做法是你不這樣做。 –

+0

@DavidHeffernan僅用於測試目的。 –

+0

你想測試什麼? –

回答

5
  1. 您需要創建安裝&開始在運行時由 本身的服務。
  2. 服務執行程序調用CreateProcessAsUserW令牌爲winlogon.exe進程。

  1. ,如果你想在新proccess在同一主叫會話呼叫運行 WTSQueryUserTokenWtsGetActiveConsoleSessionID得到 當前活動的用戶令牌隨後致電CreateEnvironmentBlock與 令牌,並assinge收到指針CreateProcessAsUserW
  2. 爲該 服務設置一個隨機Name & DisplayName(創建時間)。如果您想要使用相同的 serevice運行多個SYSTEM進程。

這裏我用的

uSysAccount.pas

unit uSysAccount; 

interface 

uses 
    WinSvc, 
    SvcMgr, 
    Winapi.Windows, 
    System.SysUtils, 
    TlHelp32, 
    System.Classes; 

type 
    TsSysAccount = class(TService) 
    procedure ServiceExecute(Sender: TService); 
    private 
    lpApplicationName, 
    lpCommandLine, 
    lpCurrentDirectory: PWideChar; 
    public 
    function GetServiceController: TServiceController; override; 
    end; 

procedure CreateProcessAsSystem(const lpApplicationName: PWideChar; 
           const lpCommandLine:PWideChar = nil; 
           const lpCurrentDirectory: PWideChar = nil); 
var 
    sSysAccount: TsSysAccount; 

implementation 

{$R *.dfm} 

function WTSQueryUserToken(SessionId: ULONG; var phToken: THandle): BOOL; stdcall; external 'Wtsapi32.dll'; 


type 
    TServiceApplicationEx = class(TServiceApplication) 
    end; 
    TServiceApplicationHelper = class helper for TServiceApplication 
    public 
     procedure ServicesRegister(Install, Silent: Boolean); 
    end; 

function IsUserAnAdmin: BOOL; stdcall; external 'shell32.dll' name 'IsUserAnAdmin'; 

function CreateEnvironmentBlock(var lpEnvironment: Pointer; hToken: THandle; 
            bInherit: BOOL): BOOL; 
            stdcall; external 'Userenv.dll'; 

function DestroyEnvironmentBlock(pEnvironment: Pointer): BOOL; stdcall; external 'Userenv.dll'; 


function _GetIntegrityLevel() : DWORD; 
type 
    PTokenMandatoryLabel = ^TTokenMandatoryLabel; 
    TTokenMandatoryLabel = packed record 
    Label_ : TSidAndAttributes; 
    end; 
var 
    hToken : THandle; 
    cbSize: DWORD; 
    pTIL : PTokenMandatoryLabel; 
    dwTokenUserLength: DWORD; 
begin 
    Result := 0; 
    dwTokenUserLength := MAXCHAR; 
    if OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, hToken) then begin 
     pTIL := Pointer(LocalAlloc(0, dwTokenUserLength)); 
     if pTIL = nil then Exit; 
     cbSize := SizeOf(TTokenMandatoryLabel); 
     if GetTokenInformation(hToken, TokenIntegrityLevel, 
            pTIL, dwTokenUserLength, cbSize) then 
     if IsValidSid((pTIL.Label_).Sid) then 
      Result := GetSidSubAuthority((pTIL.Label_).Sid, GetSidSubAuthorityCount((pTIL.Label_).Sid)^ - 1)^; 
     if hToken <> INVALID_HANDLE_VALUE then 
     CloseHandle(hToken); 
     LocalFree(Cardinal(pTIL)); 
    end; 
end; 

function IsUserAnSystem(): Boolean; 
const 
    SECURITY_MANDATORY_SYSTEM_RID = $00004000; 
begin 
    Result := (_GetIntegrityLevel = SECURITY_MANDATORY_SYSTEM_RID); 
end; 

function StartTheService(Service:TService): Boolean; 
var 
    SCM: SC_HANDLE; 
    ServiceHandle: SC_HANDLE; 
begin 
    Result:= False; 
    SCM:= OpenSCManager(nil, nil, SC_MANAGER_ALL_ACCESS); 
    if (SCM <> 0) then 
    begin 
     try 
      ServiceHandle:= OpenService(SCM, PChar(Service.Name), SERVICE_ALL_ACCESS); 
      if (ServiceHandle <> 0) then 
      begin 
       Result := StartService(ServiceHandle, 0, pChar(nil^)); 
       CloseServiceHandle(ServiceHandle); 
      end; 
     finally 
      CloseServiceHandle(SCM); 
     end; 
    end; 
end; 

procedure SetServiceName(Service: TService); 
begin 
    if Assigned(Service) then begin 
     Service.DisplayName := 'Run as system service created ' + DateTimeToStr(Now); 
     Service.Name  := 'RunAsSystem' + FormatDateTime('ddmmyyyyhhnnss', Now); 
    end; 
end; 

procedure CreateProcessAsSystem(const lpApplicationName: PWideChar; 
           const lpCommandLine:PWideChar = nil; 
           const lpCurrentDirectory: PWideChar = nil); 
begin 
    if not (IsUserAnAdmin) then begin 
     SetLastError(ERROR_ACCESS_DENIED); 
     Exit(); 
    end; 

    if not (FileExists(lpApplicationName)) then begin 
     SetLastError(ERROR_FILE_NOT_FOUND); 
     Exit(); 
    end; 

    if (IsUserAnSystem) then 
    begin 
     SvcMgr.Application.Initialize; 
     SvcMgr.Application.CreateForm(TsSysAccount, sSysAccount); 
     sSysAccount.lpApplicationName := lpApplicationName; 
     sSysAccount.lpCommandLine  := lpCommandLine; 
     sSysAccount.lpCurrentDirectory := lpCurrentDirectory; 
     SetServiceName(sSysAccount); 
     SvcMgr.Application.Run; 
    end 
    else begin 
     SvcMgr.Application.Free; 
     SvcMgr.Application := TServiceApplicationEx.Create(nil); 
     SvcMgr.Application.Initialize; 
     SvcMgr.Application.CreateForm(TsSysAccount, sSysAccount); 
     SetServiceName(sSysAccount); 
     SvcMgr.Application.ServicesRegister(True, True); 
     try 
      StartTheService(sSysAccount); 
     finally 
      SvcMgr.Application.ServicesRegister(False, True); 
     end; 
    end; 
end; 

procedure TServiceApplicationHelper.ServicesRegister(Install, Silent: Boolean); 
begin 
    RegisterServices(Install, Silent); 
end; 

procedure ServiceController(CtrlCode: DWord); stdcall; 
begin 
    sSysAccount.Controller(CtrlCode); 
end; 

function TsSysAccount.GetServiceController: TServiceController; 
begin 
    Result := ServiceController; 
end; 

Function ProcessIDFromAppname32(szExeFileName: String): DWORD; 
var 
    Snapshot: THandle; 
    ProcessEntry: TProcessEntry32; 
Begin 
     Result := 0; 
     szExeFileName := UpperCase(szExeFileName); 
     Snapshot := CreateToolhelp32Snapshot(
        TH32CS_SNAPPROCESS, 
        0); 
    If Snapshot <> 0 Then 
     try 
      ProcessEntry.dwSize := Sizeof(ProcessEntry); 
      If Process32First(Snapshot, ProcessEntry) Then 
      Repeat 
        If Pos(szExeFileName, 
         UpperCase(ExtractFilename(
         StrPas(ProcessEntry.szExeFile))) 
        ) > 0 
        then Begin 
         Result:= ProcessEntry.th32ProcessID; 
        Break; 
        end; 
     until not Process32Next(Snapshot, ProcessEntry); 
    finally 
       CloseHandle(Snapshot); 
    end; 
    End; 

function TerminateProcessByID(ProcessID: Cardinal): Boolean; 
var 
    hProcess : THandle; 
begin 
    Result := False; 
    hProcess := OpenProcess(PROCESS_TERMINATE,False,ProcessID); 
    if hProcess > 0 then 
    try 
     Result := Win32Check(TerminateProcess(hProcess,0)); 
    finally 
     CloseHandle(hProcess); 
    end; 
end; 

procedure TsSysAccount.ServiceExecute(Sender: TService); 
var 
    hToken, hUserToken: THandle; 
    StartupInfo : TStartupInfoW; 
    ProcessInfo : TProcessInformation; 
    P : Pointer; 
begin 
    if NOT WTSQueryUserToken(WtsGetActiveConsoleSessionID, hUserToken) then exit; 

    if not OpenProcessToken(
          OpenProcess(PROCESS_ALL_ACCESS, False, 
          ProcessIDFromAppname32('winlogon.exe')) 
          , 
          MAXIMUM_ALLOWED, 
          hToken) then exit; 

    if CreateEnvironmentBlock(P, hUserToken, True) then 
    begin 
      ZeroMemory(@StartupInfo, sizeof(StartupInfo)); 
      StartupInfo.lpDesktop := ('winsta0\default'); 
      StartupInfo.wShowWindow := SW_SHOWNORMAL; 
      if CreateProcessAsUserW(
       hToken, 
       lpApplicationName, 
       lpCommandLine, 
       nil, 
       nil, 
       False, 
       CREATE_UNICODE_ENVIRONMENT, 
       P, 
       lpCurrentDirectory, 
       StartupInfo, 
       ProcessInfo) then 
      begin 

      end; 
      CloseHandle(ProcessInfo.hProcess); 
      CloseHandle(ProcessInfo.hThread); 
      DestroyEnvironmentBlock(P); 
    end; 

    CloseHandle(hToken); 
    CloseHandle(hUserToken); 

    TerminateProcessByID(GetCurrentProcessId); 
end; 

end. 

uSysAccount.dfm

object sSysAccount: TsSysAccount 
    OldCreateOrder = False 
    DisplayName = 'sSysAccount' 
    OnExecute = ServiceExecute 
    Height = 150 
    Width = 215 
end 

用法如下(必須運行作爲管理的程序或)

program Project7; 

uses 
    uSysAccount; 
{$R *.res} 

begin 
    CreateProcessAsSystem('c:\windows\system32\cmd.exe'); 
end.