delphi 提升时以非管理用户身份运行应用程序

dbf7pr2w  于 2023-06-22  发布在  其他
关注(0)|答案(1)|浏览(137)

如何(如果可能)你-当你运行作为提升用户-启动一个程序与非管理权限,当你没有登录凭据。
场景:一个运行非提升状态的程序执行一个提升状态的子进程(通过ShellExecute和“runas”动词)。此应用程序需要执行一些需要管理权限的操作(替换ShellExecute的.EXE文件,而它位于ProgramFiles层次结构中),一旦完成,它应该执行原始程序,但没有提升的状态。
如何从提升的程序运行未提升的原始应用程序?它应该在与最初运行时相同的用户上下文下运行,但我没有提供凭据。我“只是”想在运行原始应用程序时从用户中剥离管理令牌。

tzcvj98z

tzcvj98z1#

Delphi 中有相当多的缺少导入/定义,所以我不得不自己定义它们。但下面是雷米提供的链接中的C++代码在 Delphi 中的完成实现:

FUNCTION GetShellWindow : HWND; EXTERNAL 'USER32.DLL';
FUNCTION InitializeProcThreadAttributeList(lpAttributeList : PProcThreadAttributeList ; dwAttributeCount,dwFlags : DWORD ; VAR lpSize : NativeUInt) : ByteBool; stdcall; EXTERNAL 'KERNEL32.DLL';
FUNCTION UpdateProcThreadAttribute(lpAttributeList : PProcThreadAttributeList ; dwFlags : DWORD ; Attribute : NativeUInt ; lpValue : Pointer ; cbSize : NativeUInt ; lpPreviousValue : POINTER = NIL ; lpReturnSize : PSIZE_T = NIL) : ByteBool; OVERLOAD; stdcall; EXTERNAL 'KERNEL32.DLL';
FUNCTION UpdateProcThreadAttribute(lpAttributeList : PProcThreadAttributeList ; dwFlags : DWORD ; Attribute : NativeUInt ; VAR Process : THandle ; lpPreviousValue : Pointer = NIL ; lpReturnSize : PSIZE_T = NIL) : ByteBool; OVERLOAD;
  BEGIN
    Result:=UpdateProcThreadAttribute(lpAttributeList,dwFlags,Attribute,@Process,SizeOf(THandle),lpPreviousValue,lpReturnSize)
  END;
PROCEDURE DeleteProcThreadAttributeList(lpAttributeList : PProcThreadAttributeList); stdcall; EXTERNAL 'KERNEL32.DLL';
CONST PROC_THREAD_ATTRIBUTE_PARENT_PROCESS = $0002000
CONST EXTENDED_STARTUPINFO_PRESENT = $00080000;
TYPE
  STARTUPINFOEXW        = PACKED RECORD
                            StartupInfo         : STARTUPINFOW;
                            lpAttributeList     : PProcThreadAttributeList
                          END;
  STARTUPINFOEX         = STARTUPINFOEXW;

FUNCTION TryRunUnelevated(CONST Prog : TFileName ; CONST Tail : STRING ; CONST StartupDir : STRING = '') : BOOLEAN;
  VAR
    H           : HWND;
    PID         : DWORD;
    Process     : THandle;
    Size        : SIZE_T;
    P           : PProcThreadAttributeList;
    SIEX        : STARTUPINFOEX;
    PI          : PROCESS_INFORMATION;

  BEGIN
    Result:=FALSE; H:=GetShellWindow;
    IF H=0 THEN EXIT;
    IF GetWindowThreadProcessID(H,PID)=0 THEN EXIT;
    Process:=OpenProcess(PROCESS_CREATE_PROCESS,FALSE,PID);
    IF Process=0 THEN EXIT;
    TRY
      InitializeProcThreadAttributeList(NIL,1,0,Size);
      GetMem(P,Size);
      TRY
        IF NOT InitializeProcThreadAttributeList(P,1,0,Size) THEN EXIT;
        TRY
          IF NOT UpdateProcThreadAttribute(P,0,PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,Process) THEN EXIT;
          FillChar(SIEX,SizeOf(STARTUPINFOEX),0);
          SIEX.lpAttributeList:=P;
          SIEX.StartupInfo.cb:=SizeOf(STARTUPINFOEX);
          IF NOT CreateProcess(PChar(Prog),PChar(Tail),NIL,NIL,FALSE,CREATE_NEW_CONSOLE OR EXTENDED_STARTUPINFO_PRESENT,NIL,POINTER(StartupDir),SIEX.StartupInfo,PI) THEN EXIT
        FINALLY
          DeleteProcThreadAttributeList(P)
        END;
        CloseHandle(PI.hProcess);
        CloseHandle(PI.hThread)
      FINALLY
        FreeMem(P)
      END
    FINALLY
      CloseHandle(Process)
    END;
    Result:=TRUE
  END;

PROCEDURE RunUnelevated(CONST Prog : TFileName ; CONST Tail : STRING ; CONST StartupDir : STRING = '');
  BEGIN
    IF NOT TryRunUnelevated(Prog,Tail,StartupDir) THEN RaiseLastOSError
  END;

有两个例程--一个简单地返回TRUE/FALSE来表示成功或失败,另一个在不能执行时引发异常。
编辑:DeleteProcThreadAttributeList的重新声明是因为这个例程在标准 Delphi 源代码中的声明是错误的-它使用了TProcThreadAttributeList而不是PProcThreadAttributeList。

相关问题