Hi all,
I am testing, executing, a process, using the Token, of another process already in memory. The problem is, in function, CreateProcessWithTokenW. It does not end, to execute, the new process.
This same code, on VB.net, if it works.
Code ASM:
This procedure is in a DLL.
.Const
.Data?
.Data
RunProg DB "D:\MFTRead.exe", 0
PtrRutaNombre DWord 0
.Code
ElavarPrvilegios Proc
Local Shell:DWord
Local ShellProcessId:DWord
Local hShellProcess:DWord
Local hShellToken:DWord
Local Security:SECURITY_ATTRIBUTES
Local MSi:STARTUPINFO
Local Pinf:PROCESS_INFORMATION
Local hToken:DWord
;Get window handle representing the desktop shell. This might not work if there is no shell window, or when
;using a custom shell. Also note that we' re assuming that the Shell is NOT running elevated.
Invoke GetShellWindow
Mov Shell, Eax
.If Eax != 0
;Get the ID of the desktop shell process.
Invoke GetWindowThreadProcessId, Shell, Addr ShellProcessId
;Open the desktop shell process in order to get the process token.
Invoke OpenProcess, PROCESS_QUERY_INFORMATION, FALSE, ShellProcessId
Mov hShellProcess, Eax
.If Eax != 0
;Get the process token of the desktop shell.
Invoke OpenProcessToken, hShellProcess, TOKEN_DUPLICATE, Addr hShellToken
.If Eax != 0
;Duplicate the shell's process token to get a primary token.
Invoke DuplicateTokenEx, hShellToken, TOKEN_QUERY + TOKEN_ASSIGN_PRIMARY + TOKEN_DUPLICATE + TOKEN_ADJUST_DEFAULT + TOKEN_ADJUST_SESSIONID, 0, 2, 1, Addr hToken
.If Eax != 0
Mov Eax, SizeOf MSi
Mov MSi.cb, Eax
; Invoke GetStartupInfo, Addr MSi
; Mov MSi.dwFlags, STARTF_USESHOWWINDOW
; Mov MSi.wShowWindow, 1
; Invoke GlobalAlloc, GMEM_FIXED, 1024 ; Reservamos un buffer de memoria para nombre de programa a ejecutar.
; Mov PtrRutaNombre, Eax
;;
; Invoke MoverDatos, Offset RunProg, Addr PtrRutaNombre, 0, 0, SizeOf RunProg
;Invoke MessageBox, NULL, Addr PtrRutaNombre, NULL, MB_OK
Invoke CreateProcessWithTokenW, hToken, 0, Offset RunProg, NULL, 0, NULL, NULL, Addr MSi, Addr Pinf
Invoke PasarADecimal, Eax
; Invoke GlobalUnlock, PtrRutaNombre
; Invoke GlobalFree, PtrRutaNombre
.EndIf
.EndIf
.EndIf
.EndIf
Xor Eax, Eax
Ret
ElavarPrvilegios EndP
Code VB.NET:
Imports System.Runtime.InteropServices
Public Class Form1
<DllImport("advapi32.dll", SetLastError:=True)> _
Private Shared Function OpenProcessToken(ByVal ProcessHandle As IntPtr, ByVal DesiredAccess As Integer, ByRef TokenHandle As IntPtr) As Boolean
End Function
<DllImport("advapi32.dll", SetLastError:=True)> _
Public Shared Function GetTokenInformation(ByVal TokenHandle As IntPtr, ByVal TokenInformationClass As TOKEN_INFORMATION_CLASS, _
ByVal TokenInformation As IntPtr, ByVal TokenInformationLength As System.UInt32, _
ByRef ReturnLength As System.UInt32) As Boolean
End Function
<DllImport("User32.dll", SetLastError:=True)> _
Public Shared Function GetShellWindow() As IntPtr
End Function
<DllImport("user32.dll", SetLastError:=True)> _
Private Shared Function GetWindowThreadProcessId(ByVal hwnd As IntPtr, _
ByRef lpdwProcessId As IntPtr) As Integer
End Function
<DllImport("kernel32.dll")> _
Private Shared Function OpenProcess(ByVal dwDesiredAccess As UInteger, <MarshalAs(UnmanagedType.Bool)> ByVal bInheritHandle As Boolean, ByVal dwProcessId As Integer) As IntPtr
End Function
<DllImport("advapi32.dll", SetLastError:=True)> _
Private Shared Function DuplicateTokenEx( _
ByVal ExistingTokenHandle As IntPtr, _
ByVal dwDesiredAccess As UInt32, _
ByRef lpThreadAttributes As SECURITY_ATTRIBUTES, _
ByVal ImpersonationLevel As Integer, _
ByVal TokenType As Integer, _
ByRef DuplicateTokenHandle As System.IntPtr) As Boolean
End Function
<DllImport("advapi32.dll", SetLastError:=True)> _
Private Shared Function LookupPrivilegeValue(ByVal lpSystemName As String, _
ByVal lpName As String, ByRef lpLuid As LUID) As Boolean
End Function
' Use this signature if you want the previous state information returned
<DllImport("advapi32.dll", SetLastError:=True)> _
Private Shared Function AdjustTokenPrivileges( _
ByVal TokenHandle As IntPtr, _
ByVal DisableAllPrivileges As Boolean, _
ByRef NewState As TOKEN_PRIVILEGES, _
ByVal BufferLengthInBytes As Integer, _
ByRef PreviousState As TOKEN_PRIVILEGES, _
ByRef ReturnLengthInBytes As Integer _
) As Boolean
End Function
<DllImport("advapi32", SetLastError:=True, CharSet:=CharSet.Unicode)>
Public Shared Function CreateProcessWithTokenW(ByVal hToken As IntPtr, ByVal dwLogonFlags As Integer, ByVal lpApplicationName As String, ByVal lpCommandLine As String, ByVal dwCreationFlags As Integer, ByVal lpEnvironment As IntPtr, ByVal lpCurrentDirectory As IntPtr, ByRef lpStartupInfo As STARTUPINFO, ByRef lpProcessInformation As PROCESS_INFORMATION) As Boolean
End Function
<StructLayout(LayoutKind.Sequential)> _
Structure SECURITY_ATTRIBUTES
Public nLength As Integer
Public lpSecurityDescriptor As IntPtr
Public bInheritHandle As Integer
End Structure
Public Enum TOKEN_INFORMATION_CLASS
TokenUser = 1
TokenGroups
TokenPrivileges
TokenOwner
TokenPrimaryGroup
TokenDefaultDacl
TokenSource
TokenType
TokenImpersonationLevel
TokenStatistics
TokenRestrictedSids
TokenSessionId
TokenGroupsAndPrivileges
TokenSessionReference
TokenSandBoxInert
TokenAuditPolicy
TokenOrigin
TokenElevationType
TokenLinkedToken
TokenElevation
TokenHasRestrictions
TokenAccessInformation
TokenVirtualizationAllowed
TokenVirtualizationEnabled
TokenIntegrityLevel
TokenUIAccess
TokenMandatoryPolicy
TokenLogonSid
MaxTokenInfoClass
End Enum
Structure TOKEN_PRIVILEGES
Public PrivilegeCount As Integer
Public TheLuid As LUID
Public Attributes As Integer
End Structure
Structure LUID
Public LowPart As UInt32
Public HighPart As UInt32
End Structure
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)> _
Structure STARTUPINFO
Public cb As Integer
Public lpReserved As String
Public lpDesktop As String
Public lpTitle As String
Public dwX As Integer
Public dwY As Integer
Public dwXSize As Integer
Public dwYSize As Integer
Public dwXCountChars As Integer
Public dwYCountChars As Integer
Public dwFillAttribute As Integer
Public dwFlags As Integer
Public wShowWindow As Short
Public cbReserved2 As Short
Public lpReserved2 As Integer
Public hStdInput As Integer
Public hStdOutput As Integer
Public hStdError As Integer
End Structure
Structure PROCESS_INFORMATION
Public hProcess As IntPtr
Public hThread As IntPtr
Public dwProcessId As Integer
Public dwThreadId As Integer
End Structure
Public Const SE_PRIVILEGE_ENABLED = &H2L
Public Const PROCESS_QUERY_INFORMATION = &H400
Public Const TOKEN_ASSIGN_PRIMARY = &H1
Public Const TOKEN_DUPLICATE = &H2
Public Const TOKEN_IMPERSONATE = &H4
Public Const TOKEN_QUERY = &H8
Public Const TOKEN_QUERY_SOURCE = &H10
Public Const TOKEN_ADJUST_PRIVILEGES = &H20
Public Const TOKEN_ADJUST_GROUPS = &H40
Public Const TOKEN_ADJUST_DEFAULT = &H80
Public Const TOKEN_ADJUST_SESSIONID = &H100
Public Const SecurityImpersonation = 2
Public Const TokenPrimary = 1
Public Const SE_INCREASE_QUOTA_NAME = "SeIncreaseQuotaPrivilege"
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim currentProcess As Process = Process.GetCurrentProcess
'Enable SeIncreaseQuotaPrivilege in this process. (This requires administrative privileges.)
Dim hProcessToken As IntPtr = Nothing
'OpenProcessToken(currentProcess.Handle, TOKEN_ADJUST_PRIVILEGES, hProcessToken)
Dim tkp As TOKEN_PRIVILEGES
'tkp.PrivilegeCount = 1
'LookupPrivilegeValue(Nothing, SE_INCREASE_QUOTA_NAME, tkp.TheLuid)
'tkp.Attributes = SE_PRIVILEGE_ENABLED
'AdjustTokenPrivileges(hProcessToken, False, tkp, 0, Nothing, Nothing)
'Get window handle representing the desktop shell. This might not work if there is no shell window, or when
'using a custom shell. Also note that we're assuming that the shell is not running elevated.
Dim hShellWnd As IntPtr = GetShellWindow()
'Get the ID of the desktop shell process.
Dim dwShellPID As IntPtr
GetWindowThreadProcessId(hShellWnd, dwShellPID)
'Open the desktop shell process in order to get the process token.
Dim hShellProcess As IntPtr = OpenProcess(PROCESS_QUERY_INFORMATION, False, dwShellPID)
Dim hShellProcessToken As IntPtr = Nothing
Dim hPrimaryToken As IntPtr = Nothing
'Get the process token of the desktop shell.
OpenProcessToken(hShellProcess, TOKEN_DUPLICATE, hShellProcessToken)
'Duplicate the shell's process token to get a primary token.
Dim dwTokenRights As Integer = TOKEN_QUERY Or TOKEN_ASSIGN_PRIMARY Or TOKEN_DUPLICATE Or TOKEN_ADJUST_DEFAULT Or TOKEN_ADJUST_SESSIONID
DuplicateTokenEx(hShellProcessToken, dwTokenRights, Nothing, SecurityImpersonation, TokenPrimary, hPrimaryToken)
Dim si As STARTUPINFO = Nothing
Dim pi As PROCESS_INFORMATION = Nothing
si.cb = Marshal.SizeOf(si)
CreateProcessWithTokenW(hPrimaryToken, 0, "D:\MFTRead.exe", Nothing, 0, Nothing, Nothing, si, pi)
Console.WriteLine(pi.dwProcessId)
End Sub
<DllImport("kernel32.dll")> _
Shared Function CreateProcess(ByVal lpApplicationName As IntPtr, _
ByVal lpCommandLine As IntPtr, ByRef lpProcessAttributes As SECURITY_ATTRIBUTES, _
ByRef lpThreadAttributes As SECURITY_ATTRIBUTES, ByVal bInheritHandles As Boolean, _
ByVal dwCreationFlags As UInt32, ByVal lpEnvironment As IntPtr, ByVal lpCurrentDirectory As String, _
<[In]()> ByRef lpStartupInfo As STARTUPINFO, _
<[Out]()> ByRef lpProcessInformation As PROCESS_INFORMATION) As Boolean
End Function
Private Sub Button2_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button2.Click
Dim p As Process = New Process
p.StartInfo.FileName = "D:\MFTRead.exe"
p.StartInfo.Arguments = ""
p.Start()
Console.WriteLine(p.Id)
End Sub
End Class
The error may happen even before, namely on the DuplicateTokenEx .
You can't simply drop every access right you have in mind and hope the function will comply.
You have not enabled SE_ASSIGNPRIMARYTOKEN_NAME privilege and you don't hold the SE_TCB_NAME privilege.
Surprisingly, from your listing it is not causing errors. :rolleyes:
So, specifically for the CreateProcessWithTokenW, names have to be in UNICODE, not what you are doing.
Hello AW, thank you very much for your contribution. Could you tell me how I put the name in unicode ?. Some example.
When we talk about Unicode here we are talking about word size characters.
So, it should be:
RunProg DW "D",":","\","M","F","T","R","e","a","d",".","e","x","e", 0
Note that there are macros in the Masm32 SDK that do this automatically (not to talk about many other alternatives).
I tried it, but it still fails in the same place. Attachment asm, complete. It's treated with EasyCode.
if in the example, of VB.net, in the definition of the library
<DllImport ("advapi32", SetLastError: = True, CharSet: = CharSet.Unicode)>
Public Shared Function CreateProcessWithTokenW (ByVal hToken As IntPtr, ByVal dwLogonFlags As Integer, ByVal lpApplicationName As String, ByVal lpCommandLine As String, ByVal dwCreationFlags As Integer, ByVal lpEnvironment As IntPtr, ByVal lpCurrentDirectory As IntPtr, ByRef lpStartupInfo As STARTUPINFO, ByRef lpProcessInformation As PROCESS_INFORMATION) Ace Boolean
End function
I delete, CharSet: = CharSet.Unicode. So, it happens the same as with the asm code, it doesn't work.
Aw is right, but I don't know how to apply unicode to the CreateProcessWithTokenW function.
I already showed you how to produce the Unicode, but there is also the problem of "ERROR_PRIVILEGE_NOT_HELD" which you can verify looking at GetLastError.
The elevated administrator account has a number of privileges that need to be Enabled before being used. You are not doing anything to enable the ones that are required.
Here are are the privileges the elevated Administrator account has:
(https://www.dropbox.com/s/ibbjc9hhagick58/privileges.png?dl=1)
I am not going to fix it for you after this stage.
BTW, try to learn true MASM to produce the examples unless you are in the specialized forum. Remember there are literally hundreds of editors, EasyCode is just another one.
Ok AW, I really appreciate your help. I do not understand, because in vb.net if it works and the same code in asm, no ?. Well I'll keep trying ...
Again, thank you very much.
If the error says that privileges are not enabled, then enable them.
I see code in the VB section that you commented out to enable the privileges, so it is necessary. Of course once the privileges are enabled they will remain enabled on that window that's why you believe it is not necessary. It is necessary, you had already enabled them.
ok,ok, I'll try. Thanks a lot.
The SeTcbPirivilege by default is not available to Administrators, you will need to change Local Security Policy. But since you say it works in VB so you have already done that.
Have fun then, :thumbsup:
I already have it. I leave the code in case someone can reuse it.
Code:
ElavarPrvilegios Proc
Local Shell:DWord
Local ShellProcessId:DWord
Local hShellProcess:DWord
Local hShellToken:DWord
Local Security:SECURITY_ATTRIBUTES
Local hToken:DWord
Local MSi:STARTUPINFO
Local Pinf:PROCESS_INFORMATION
Local TP:TOKEN_PRIVILEGES
Local Ph:DWord
Invoke GetCurrentProcess
Mov Ph, Eax
Invoke OpenProcessToken, Ph, TOKEN_ADJUST_PRIVILEGES, Addr hToken
;
;Invoke PasarADecimal, hToken
;
;
Mov TP.PrivilegeCount, 1
Invoke LookupPrivilegeValue, NULL, Offset SEShutName, Addr TP.Privileges
- .Luid
Mov TP.Privileges - .Attributes, SE_PRIVILEGE_ENABLED
;;
Invoke AdjustTokenPrivileges, hToken, FALSE, Addr TP, NULL, NULL, NULL
; Invoke GetCurrentProcessId
; Mov Ph, Eax
; Invoke OpenProcessToken, Ph, TOKEN_ADJUST_PRIVILEGES, Addr hToken
;
;Invoke PasarADecimal, Eax
;
;
; Mov TP.PrivilegeCount, 1
; Invoke LookupPrivilegeValue, NULL, Offset SEShutName, Addr TP.Privileges - .Luid
; Mov TP.Privileges - .Attributes, SE_PRIVILEGE_ENABLED
;;
; Invoke AdjustTokenPrivileges, hToken, FALSE, Addr TP, NULL, NULL, NULL
;
;Invoke PasarADecimal, Eax
;Get window handle representing the desktop shell. This might not work if there is no shell window, or when
;using a custom shell. Also note that we' re assuming that the Shell is NOT running elevated.
Invoke GetShellWindow
Mov Shell, Eax
.If Eax != 0
;Get the ID of the desktop shell process.
Invoke GetWindowThreadProcessId, Shell, Addr ShellProcessId
;Open the desktop shell process in order to get the process token.
Invoke OpenProcess, PROCESS_QUERY_INFORMATION, FALSE, ShellProcessId
Mov hShellProcess, Eax
.If Eax != 0
;Get the process token of the desktop shell.
Invoke OpenProcessToken, hShellProcess, TOKEN_DUPLICATE, Addr hShellToken
.If Eax != 0
;Duplicate the shell's process token to get a primary token.
Invoke DuplicateTokenEx, hShellToken, TOKEN_QUERY + TOKEN_ASSIGN_PRIMARY + TOKEN_DUPLICATE + TOKEN_ADJUST_DEFAULT + TOKEN_ADJUST_SESSIONID, 0, 2, 1, Addr hToken
.If Eax != 0
Invoke RtlZeroMemory, Addr MSi, SizeOf MSi
Invoke RtlZeroMemory, Addr Pinf, SizeOf Pinf
Mov Eax, SizeOf MSi
Mov MSi.cb, Eax
Invoke CreateProcessWithTokenW, hToken, LOGON_WITH_PROFILE, 0, TextAddrW("D:\MFTRead.exe"), 0, 0, 0, Addr MSi, Addr Pinf
.EndIf
;
.EndIf
;
.EndIf
.EndIf
Xor Eax, Eax
Ret
ElavarPrvilegios EndP
For a moment, I thought, I could inherit privileges, from another application. no need to run the latter, as administrator. aw, you were right, trying it is a lot of fun .... :thumbsup:
In your case you are using CreateProcessWithTokenW to launch an application in Medium Integrity Level (Windows Explorer.exe IL) from an application with High Integrity Level (i.e. your app elevated to Administrator).
This is mostly done to reduce security risks. You can play further and reduce the IL to low, the level at which internet browsers run.
But you can also use CreateProcessWithTokenW to create a Local System Service (http://masm32.com/board/index.php?topic=8259.0). This is not really an escalation because Local System accounts are always created from an Elevated Administrator account. It is simply a different way of doing it.
interesting reflection. :eusa_pray: