I need to write a small service that runs an application (with gui, e.g. calc.exe) on the logon-screen.
I already found this question (and answer):
Running a process at the Windows 7 Welcome Screen
please read the code-comments if you don't understand how this works:
// grab the winlogon process
Process winLogon = null;
foreach (Process p in Process.GetProcesses())
{
if (p.ProcessName.Contains("winlogon"))
{
winLogon = p;
break;
}
}
// grab the winlogon's token
IntPtr userToken = IntPtr.Zero;
if (!OpenProcessToken(winLogon.Handle, TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE, out userToken))
{
log("ERROR: OpenProcessToken returned false - " + Marshal.GetLastWin32Error());
}
// create a new token
IntPtr newToken = IntPtr.Zero;
SECURITY_ATTRIBUTES tokenAttributes = new SECURITY_ATTRIBUTES();
tokenAttributes.nLength = Marshal.SizeOf(tokenAttributes);
SECURITY_ATTRIBUTES threadAttributes = new SECURITY_ATTRIBUTES();
threadAttributes.nLength = Marshal.SizeOf(threadAttributes);
// duplicate the winlogon token to the new token
if (!DuplicateTokenEx(userToken, 0x10000000, ref tokenAttributes, SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation,
TOKEN_TYPE.TokenImpersonation, out newToken))
{
log("ERROR: DuplicateTokenEx returned false - " + Marshal.GetLastWin32Error());
}
TOKEN_PRIVILEGES tokPrivs = new TOKEN_PRIVILEGES();
tokPrivs.PrivilegeCount = 1;
LUID seDebugNameValue = new LUID();
if (!LookupPrivilegeValue(null, SE_DEBUG_NAME, out seDebugNameValue))
{
log("ERROR: LookupPrivilegeValue returned false - " + Marshal.GetLastWin32Error());
}
tokPrivs.Privileges = new LUID_AND_ATTRIBUTES[1];
tokPrivs.Privileges[0].Luid = seDebugNameValue;
tokPrivs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// escalate the new token's privileges
if (!AdjustTokenPrivileges(newToken, false, ref tokPrivs, 0, IntPtr.Zero, IntPtr.Zero))
{
log("ERROR: AdjustTokenPrivileges returned false - " + Marshal.GetLastWin32Error());
}
PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
STARTUPINFO si = new STARTUPINFO();
si.cb = Marshal.SizeOf(si);
si.lpDesktop = "Winsta0\\Winlogon";
// start the process using the new token
if (!CreateProcessAsUser(newToken, "calc.exe", null, ref tokenAttributes, ref threadAttributes,
true, (uint)CreateProcessFlags.CREATE_NEW_CONSOLE | (uint)CreateProcessFlags.INHERIT_CALLER_PRIORITY, IntPtr.Zero,
"C:\\Windows\\System32", ref si, out pi))
{
log("ERROR: CreateProcessAsUser returned false - " + Marshal.GetLastWin32Error());
}
Process _p = Process.GetProcessById(pi.dwProcessId);
if (_p != null)
{
log("Process " + _p.Id + " Name " + _p.ProcessName);
}
else
{
log("Process not found");
}
It works with Windows 7. With XP I get error 1349 ERROR_BAD_TOKEN_TYPE while calling CreateProcessAsUser (MSDN: The type of the token is inappropriate for its attempted use.).
How to realize this in Windows XP? It does not have to be the code from above but it should work as a service (with system-account?).
Thanks for your support
Fluxer
This definitely has to do with privilege issues (Windows Vista and 7 have notable changes in security). Rather than trying to get token of winlogon.exe and impersonating it, try getting user token via WTSQueryUserToken like this:
WTSQueryUserToken (WTSGetActiveConsoleSessionId(), out userToken);
Replace the OpenProcessToken line which is used to get the token with the above statement.
Your new code should be like this:
// if (!OpenProcessToken(winLogon.Handle, TOKEN_QUERY | TOKEN_IMPERSONATE | //TOKEN_DUPLICATE, out userToken))
// {
// log("ERROR: OpenProcessToken returned false - " + //Marshal.GetLastWin32Error());
// }
WTSQueryUserToken (WTSGetActiveConsoleSessionId(), out userToken);
Do your dll import like this:
[DllImport("Kernel32.dll", SetLastError = true)]
[return:MarshalAs(UnmanagedType.U4)]
public static extern int WTSGetActiveConsoleSessionId ( );
You need only replace the part I commented out with this code.
Related
My program refers to Cjwdev.windowsApi to start the software, but now there is a software that must be run as an administrator, how can I do it?
The following is part of the code:
string appStartPath = #"D:\Program Files (x86)\tencent\QQ\Bin\QQScLauncher.exe";
IntPtr userTokenHandle = IntPtr.Zero;
ApiDefinitions.WTSQueryUserToken(ApiDefinitions.WTSGetActiveConsoleSessionId(), ref userTokenHandle);
ApiDefinitions.PROCESS_INFORMATION procInfo = new ApiDefinitions.PROCESS_INFORMATION();
ApiDefinitions.STARTUPINFO startInfo = new ApiDefinitions.STARTUPINFO();
startInfo.cb = (uint)System.Runtime.InteropServices.Marshal.SizeOf(startInfo);
// begin start
ApiDefinitions.CreateProcessAsUser(
userTokenHandle,
appStartPath,
"",
IntPtr.Zero,
IntPtr.Zero,
false,
0,
IntPtr.Zero,
null,
ref startInfo,
out procInfo);
if (userTokenHandle != IntPtr.Zero)
ApiDefinitions.CloseHandle(userTokenHandle);
int _currentAquariusProcessId = (int)procInfo.dwProcessId;
I am trying to start a process with CreateProcessAsUser and works fine BUT in case a command line arguments is present the function fails and the last error is set to ERROR_UNKNOWN_REVISION.
I have tried multiple combinations for command line with no luck.
Here is the code
var CMD_ARGS = Environment.GetCommandLineArgs();
string FILE_NAME = EntryPoint.PRCOESS_FILE_NAME;
string WORKING_DIRECTORY = EntryPoint.PROCESS_DIRECTORY;
string ARGUMENTS = CMD_ARGS.Skip(1).Aggregate((first,next)=> ' ' + first + ' ' + next);
IntPtr USER_TOKEN = IntPtr.Zero;
IntPtr ENVIRONMENT=IntPtr.Zero;
try
{
var consoleSession = Kernel32.WTSGetActiveConsoleSessionId();
if (consoleSession == 0xFFFFFFFF)
return;
if (!Wtsapi32.WTSQueryUserToken(consoleSession, out USER_TOKEN))
throw new Win32Exception();
if (!Userenv.CreateEnvironmentBlock(out ENVIRONMENT, USER_TOKEN, true))
throw new Win32Exception();
//initialize structures
SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
sa.nLength = Marshal.SizeOf(sa);
//initialize startup
STARTUPINFO si = new STARTUPINFO();
si.cb = Marshal.SizeOf(si);
//initialize process info
var PROCESS_INFO = new PROCESS_INFORMATION();
int dwCreationFlags = NORMAL_PRIORITY_CLASS | (int)(PROCESS_CREATE_FLAG.CREATE_NEW_CONSOLE | PROCESS_CREATE_FLAG.CREATE_UNICODE_ENVIRONMENT);
if (!AdvApi32.CreateProcessAsUser(USER_TOKEN,
FILE_NAME,
ARGUMENTS,
ref sa,
ref sa,
true,
dwCreationFlags,
ENVIRONMENT,
WORKING_DIRECTORY,
ref si,
out PROCESS_INFO))
throw new Win32Exception();
if (PROCESS_INFO.hThread != IntPtr.Zero)
{
ClientProcessId = PROCESS_INFO.dwProcessId;
ClientSessionId = consoleSession;
Trace.WriteLine($"{PROCESS_INFO.dwProcessId}");
}
}
catch(Exception ex)
{
throw;
}
finally
{
Userenv.DestroyEnvironmentBlock(ENVIRONMENT);
Kernel32.CloseHandle(USER_TOKEN);
}
Since Local User Group Management doesnt seem to be something I can query in C#, I figured I would do a down and dirty version of what I an trying to accomplish and I need some advice for best practices.
THE GOAL:
Essentially, I need to determine if the current local user's password is set to expire and display the result in a textbox. I have already written a text search so I dont mind that there will be extra data sitting on the output since I will distill the data down to a boolean check for one string.
The Problem:
Check out the code below. For some reason the error codes come through from CMD just fine, however, the output does not display in textbox2.
string userName = System.Security.Principal.WindowsIdentity.GetCurrent().Name.Split('\\').Last(); ;
user.Text = userName;
Process cmd = new Process();
cmd.StartInfo.FileName = "cmd.exe";
cmd.StartInfo.Arguments = "/c net user";
cmd.StartInfo.UseShellExecute = false;
cmd.StartInfo.RedirectStandardOutput = true;
cmd.StartInfo.RedirectStandardError = true;
cmd.Start();
//* Read the output (or the error)
string output = cmd.StandardOutput.ReadToEnd();
textBox2.Text = output;
string err = cmd.StandardError.ReadToEnd();
textBox2.Text = err;
cmd.WaitForExit();
First you're putting the output variable textBox2.Text, then you are replacing the textBox2.Text with err and I believe you're getting nothing from err variable, that's why TextBox2 is not displaying what you're expecting.
try to run the snippet below to check how output and err variable are getting:
string userName = System.Security.Principal.WindowsIdentity.GetCurrent().Name.Split('\\').Last(); ;
string text = userName;
Process cmd = new Process();
cmd.StartInfo.FileName = "cmd.exe";
cmd.StartInfo.Arguments = "/c net user";
cmd.StartInfo.UseShellExecute = false;
cmd.StartInfo.RedirectStandardOutput = true;
cmd.StartInfo.RedirectStandardError = true;
cmd.Start();
//* Read the output (or the error)
string output = cmd.StandardOutput.ReadToEnd();
string err = cmd.StandardError.ReadToEnd();
Console.WriteLine("Output: "+output );
Console.WriteLine("Err: "+err);
cmd.WaitForExit();
Console.ReadKey();
EDIT
USER_INFO_2
The USER_INFO_2 structure contains information about a user account, including the account name, password data, privilege level, the path to the user's home directory, and other user-related network statistics.
usri2_acct_expires
Specifies a DWORD value that indicates when the account expires. This value is stored as the number of seconds elapsed since 00:00:00, January 1, 1970, GMT. A value of TIMEQ_FOREVER indicates that the account never expires.
from USER_INFO_2 used with NetUserGetInfo.
Declared in Lmaccess.h; include Lm.h.
It is really poor practise to shell to a user commands to do simple things.
Your essential problem and your very silly conclusion that user management isn't available is wrong.
If another program can do something then so can your program.
If you don't know how you look at the API calls it calls (open it in notepad and look - they are alltogether in the file). .NET has it's own WMI class.
C# and C++ and C all have access to WMI. The command line for what you are doing via WMI is
wmic path Win32_Account get /format:list
wmic path Win32_Group get /format:list
wmic path Win32_GroupInDomain get /format:list
wmic path Win32_GroupUser get /format:list
wmic path Win32_SystemAccount get /format:list
wmic path Win32_SystemUsers get /format:list
wmic path Win32_UserAccount get /format:list
For Help
wmic /?
wmic UserAccount /?
wmic useraccount get /?
wmic useraccount set /?
wmic useraccount call /?
The same thing in vbscript is
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
Set colItems = objWMIService.ExecQuery("Select * From Win32_UserAccount")
For Each objItem in colItems
msgbox objitem.Caption & " " & objItem.Description
Next
A C++ example from WDK
#include "querysink.h"
int main(int argc, char **argv)
{
HRESULT hres;
// Step 1: --------------------------------------------------
// Initialize COM. ------------------------------------------
hres = CoInitializeEx(0, COINIT_MULTITHREADED);
if (FAILED(hres))
{
cout << "Failed to initialize COM library. Error code = 0x"
<< hex << hres << endl;
return 1; // Program has failed.
}
// Step 2: --------------------------------------------------
// Set general COM security levels --------------------------
// Note: If you are using Windows 2000, you need to specify -
// the default authentication credentials for a user by using
// a SOLE_AUTHENTICATION_LIST structure in the pAuthList ----
// parameter of CoInitializeSecurity ------------------------
hres = CoInitializeSecurity(
NULL,
-1, // COM authentication
NULL, // Authentication services
NULL, // Reserved
RPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication
RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation
NULL, // Authentication info
EOAC_NONE, // Additional capabilities
NULL // Reserved
);
if (FAILED(hres))
{
cout << "Failed to initialize security. Error code = 0x"
<< hex << hres << endl;
CoUninitialize();
return 1; // Program has failed.
}
// Step 3: ---------------------------------------------------
// Obtain the initial locator to WMI -------------------------
IWbemLocator *pLoc = NULL;
hres = CoCreateInstance(
CLSID_WbemLocator,
0,
CLSCTX_INPROC_SERVER,
IID_IWbemLocator, (LPVOID *) &pLoc);
if (FAILED(hres))
{
cout << "Failed to create IWbemLocator object."
<< " Err code = 0x"
<< hex << hres << endl;
CoUninitialize();
return 1; // Program has failed.
}
// Step 4: -----------------------------------------------------
// Connect to WMI through the IWbemLocator::ConnectServer method
IWbemServices *pSvc = NULL;
// Connect to the local root\cimv2 namespace
// and obtain pointer pSvc to make IWbemServices calls.
hres = pLoc->ConnectServer(
_bstr_t(L"ROOT\\CIMV2"),
NULL,
NULL,
0,
NULL,
0,
0,
&pSvc
);
if (FAILED(hres))
{
cout << "Could not connect. Error code = 0x"
<< hex << hres << endl;
pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
cout << "Connected to ROOT\\CIMV2 WMI namespace" << endl;
// Step 5: --------------------------------------------------
// Set security levels on the proxy -------------------------
hres = CoSetProxyBlanket(
pSvc, // Indicates the proxy to set
RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx
RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx
NULL, // Server principal name
RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx
RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
NULL, // client identity
EOAC_NONE // proxy capabilities
);
if (FAILED(hres))
{
cout << "Could not set proxy blanket. Error code = 0x"
<< hex << hres << endl;
pSvc->Release();
pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
// Step 6: --------------------------------------------------
// Use the IWbemServices pointer to make requests of WMI ----
// For example, get the name of the operating system.
// The IWbemService::ExecQueryAsync method will call
// the QuerySink::Indicate method when it receives a result
// and the QuerySink::Indicate method will display the OS name
QuerySink* pResponseSink = new QuerySink();
hres = pSvc->ExecQueryAsync(
bstr_t("WQL"),
bstr_t("SELECT * FROM Win32_OperatingSystem"),
WBEM_FLAG_BIDIRECTIONAL,
NULL,
pResponseSink);
if (FAILED(hres))
{
cout << "Query for operating system name failed."
<< " Error code = 0x"
<< hex << hres << endl;
pSvc->Release();
pLoc->Release();
pResponseSink->Release();
CoUninitialize();
return 1; // Program has failed.
}
// Step 7: -------------------------------------------------
// Wait to get the data from the query in step 6 -----------
Sleep(500);
pSvc->CancelAsyncCall(pResponseSink);
// Cleanup
// ========
pSvc->Release();
pLoc->Release();
CoUninitialize();
return 0; // Program successfully completed.
}
The following code is the header file code for the QuerySink class. The QuerySink class is used in the previous code.
// QuerySink.h
#ifndef QUERYSINK_H
#define QUERYSINK_H
#define _WIN32_DCOM
#include <iostream>
using namespace std;
#include <comdef.h>
#include <Wbemidl.h>
# pragma comment(lib, "wbemuuid.lib")
class QuerySink : public IWbemObjectSink
{
LONG m_lRef;
bool bDone;
CRITICAL_SECTION threadLock; // for thread safety
public:
QuerySink() { m_lRef = 0; bDone = false;
InitializeCriticalSection(&threadLock); }
~QuerySink() { bDone = true;
DeleteCriticalSection(&threadLock); }
virtual ULONG STDMETHODCALLTYPE AddRef();
virtual ULONG STDMETHODCALLTYPE Release();
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid,
void** ppv);
virtual HRESULT STDMETHODCALLTYPE Indicate(
LONG lObjectCount,
IWbemClassObject __RPC_FAR *__RPC_FAR *apObjArray
);
virtual HRESULT STDMETHODCALLTYPE SetStatus(
/* [in] */ LONG lFlags,
/* [in] */ HRESULT hResult,
/* [in] */ BSTR strParam,
/* [in] */ IWbemClassObject __RPC_FAR *pObjParam
);
bool IsDone();
};
#endif // end of QuerySink.h
The following code is an implementation of the QuerySink class:
// QuerySink.cpp
#include "querysink.h"
ULONG QuerySink::AddRef()
{
return InterlockedIncrement(&m_lRef);
}
ULONG QuerySink::Release()
{
LONG lRef = InterlockedDecrement(&m_lRef);
if(lRef == 0)
delete this;
return lRef;
}
HRESULT QuerySink::QueryInterface(REFIID riid, void** ppv)
{
if (riid == IID_IUnknown || riid == IID_IWbemObjectSink)
{
*ppv = (IWbemObjectSink *) this;
AddRef();
return WBEM_S_NO_ERROR;
}
else return E_NOINTERFACE;
}
HRESULT QuerySink::Indicate(long lObjectCount,
IWbemClassObject **apObjArray)
{
HRESULT hres = S_OK;
for (int i = 0; i < lObjectCount; i++)
{
VARIANT varName;
hres = apObjArray[i]->Get(_bstr_t(L"Name"),
0, &varName, 0, 0);
if (FAILED(hres))
{
cout << "Failed to get the data from the query"
<< " Error code = 0x"
<< hex << hres << endl;
return WBEM_E_FAILED; // Program has failed.
}
printf("Name: %ls\n", V_BSTR(&varName));
}
return WBEM_S_NO_ERROR;
}
HRESULT QuerySink::SetStatus(
/* [in] */ LONG lFlags,
/* [in] */ HRESULT hResult,
/* [in] */ BSTR strParam,
/* [in] */ IWbemClassObject __RPC_FAR *pObjParam
)
{
if(lFlags == WBEM_STATUS_COMPLETE)
{
printf("Call complete.\n");
EnterCriticalSection(&threadLock);
bDone = true;
LeaveCriticalSection(&threadLock);
}
else if(lFlags == WBEM_STATUS_PROGRESS)
{
printf("Call in progress.\n");
}
return WBEM_S_NO_ERROR;
}
bool QuerySink::IsDone()
{
bool done = true;
EnterCriticalSection(&threadLock);
done = bDone;
LeaveCriticalSection(&threadLock);
return done;
} // end of QuerySink.cpp
This question already has answers here:
C# accessing active directory with different user credentials
(4 answers)
Closed 9 years ago.
Just a quick question here. Does anyone how can I set the access a difference server folder with username and password in c# .net?
I have have the following code to upload a file into a folder in the other server. Somehow I need to use the username and password then I can be only able to access into this folder. Does anyone know the code to set the access username and password for the folder?
private void uploadFile()
{
DateTime dateTime = DateTime.Now;
string sDate = dateTime.ToString("yyyyMMdd") + "_" + dateTime.ToString("fffffff");
string fn = System.IO.Path.GetFileName(File1.PostedFile.FileName);
string SaveLocation = Server.MapPath("document") + "\\" + sDate + "_" + fn;
supportFileName = sDate + "_" + fn;
try
{
File1.PostedFile.SaveAs(SaveLocation);
}
catch (Exception ex)
{
err.Text = "Error: " + ex.Message;
}
}
for access the different server , and upload file into it.
first, you need to give correct rights to this user account, and impersonation this account.
The term "Impersonation" in a programming context refers to a technique that executes the code under another user context than the user who originally started an application, i.e. the user context is temporarily changed once or multiple times during the execution of an application.
here are two article, hope can help you, with the sample codes:
http://www.codeproject.com/Articles/4051/Windows-Impersonation-using-C
http://www.codeproject.com/Articles/10090/A-small-C-Class-for-impersonating-a-User
using ( new Impersonator( "myUsername", "myDomainname", "myPassword" ) )
{
...
<code that executes under the new context>
...
}
public WindowsImpersonationContext
ImpersonateUser(string sUsername, string sDomain, string sPassword)
{
// initialize tokens
IntPtr pExistingTokenHandle = new IntPtr(0);
IntPtr pDuplicateTokenHandle = new IntPtr(0);
pExistingTokenHandle = IntPtr.Zero;
pDuplicateTokenHandle = IntPtr.Zero;
// if domain name was blank, assume local machine
if (sDomain == "")
sDomain = System.Environment.MachineName;
try
{
string sResult = null;
const int LOGON32_PROVIDER_DEFAULT = 0;
// create token
const int LOGON32_LOGON_INTERACTIVE = 2;
//const int SecurityImpersonation = 2;
// get handle to token
bool bImpersonated = LogonUser(sUsername, sDomain, sPassword,
LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
ref pExistingTokenHandle);
// did impersonation fail?
if (false == bImpersonated)
{
int nErrorCode = Marshal.GetLastWin32Error();
sResult = "LogonUser() failed with error code: " +
nErrorCode + "\r\n";
// show the reason why LogonUser failed
MessageBox.Show(this, sResult, "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
// Get identity before impersonation
sResult += "Before impersonation: " +
WindowsIdentity.GetCurrent().Name + "\r\n";
bool bRetVal = DuplicateToken(pExistingTokenHandle,
(int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation,
ref pDuplicateTokenHandle);
// did DuplicateToken fail?
if (false == bRetVal)
{
int nErrorCode = Marshal.GetLastWin32Error();
// close existing handle
CloseHandle(pExistingTokenHandle);
sResult += "DuplicateToken() failed with error code: "
+ nErrorCode + "\r\n";
// show the reason why DuplicateToken failed
MessageBox.Show(this, sResult, "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
return null;
}
else
{
// create new identity using new primary token
WindowsIdentity newId = new WindowsIdentity
(pDuplicateTokenHandle);
WindowsImpersonationContext impersonatedUser =
newId.Impersonate();
// check the identity after impersonation
sResult += "After impersonation: " +
WindowsIdentity.GetCurrent().Name + "\r\n";
MessageBox.Show(this, sResult, "Success",
MessageBoxButtons.OK, MessageBoxIcon.Information);
return impersonatedUser;
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
// close handle(s)
if (pExistingTokenHandle != IntPtr.Zero)
CloseHandle(pExistingTokenHandle);
if (pDuplicateTokenHandle != IntPtr.Zero)
CloseHandle(pDuplicateTokenHandle);
}
}
I need to write a small tool that runs on every userdesktop or, if no one is logged in, directly on logon screen. Maybe a service with a form starting?
I already found this question (and answer):
Running a process at the Windows 7 Welcome Screen
// grab the winlogon process
Process winLogon = null;
foreach (Process p in Process.GetProcesses()) {
if (p.ProcessName.Contains("winlogon")) {
winLogon = p;
break;
}
}
// grab the winlogon's token
IntPtr userToken = IntPtr.Zero;
if (!OpenProcessToken(winLogon.Handle, TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE, out userToken)) {
log("ERROR: OpenProcessToken returned false - " + Marshal.GetLastWin32Error());
}
// create a new token
IntPtr newToken = IntPtr.Zero;
SECURITY_ATTRIBUTES tokenAttributes = new SECURITY_ATTRIBUTES();
tokenAttributes.nLength = Marshal.SizeOf(tokenAttributes);
SECURITY_ATTRIBUTES threadAttributes = new SECURITY_ATTRIBUTES();
threadAttributes.nLength = Marshal.SizeOf(threadAttributes);
// duplicate the winlogon token to the new token
if (!DuplicateTokenEx(userToken, 0x10000000, ref tokenAttributes, SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation,
TOKEN_TYPE.TokenImpersonation, out newToken)) {
log("ERROR: DuplicateTokenEx returned false - " + Marshal.GetLastWin32Error());
}
TOKEN_PRIVILEGES tokPrivs = new TOKEN_PRIVILEGES();
tokPrivs.PrivilegeCount = 1;
LUID seDebugNameValue = new LUID();
if (!LookupPrivilegeValue(null, SE_DEBUG_NAME, out seDebugNameValue)) {
log("ERROR: LookupPrivilegeValue returned false - " + Marshal.GetLastWin32Error());
}
tokPrivs.Privileges = new LUID_AND_ATTRIBUTES[1];
tokPrivs.Privileges[0].Luid = seDebugNameValue;
tokPrivs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// escalate the new token's privileges
if (!AdjustTokenPrivileges(newToken, false, ref tokPrivs, 0, IntPtr.Zero, IntPtr.Zero)) {
log("ERROR: AdjustTokenPrivileges returned false - " + Marshal.GetLastWin32Error());
}
PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
STARTUPINFO si = new STARTUPINFO();
si.cb = Marshal.SizeOf(si);
si.lpDesktop = "Winsta0\\Winlogon";
// start the process using the new token
if (!CreateProcessAsUser(newToken, process, process, ref tokenAttributes, ref threadAttributes,
true, (uint)CreateProcessFlags.CREATE_NEW_CONSOLE | (uint)CreateProcessFlags.INHERIT_CALLER_PRIORITY, IntPtr.Zero,
logInfoDir, ref si, out pi)) {
log("ERROR: CreateProcessAsUser returned false - " + Marshal.GetLastWin32Error());
}
Process _p = Process.GetProcessById(pi.dwProcessId);
if (_p != null) {
log("Process " + _p.Id + " Name " + _p.ProcessName);
} else {
log("Process not found");
}
But there are no dll-imports explained, so i can't build this.
Thanks for your effort
Fluxer