The code provided by Jon in the following thread seems to illustrate exactly what I want to do
Running a process at the Windows 7 Welcome Screen
Unfortunately it's in C#, a language I don't know at all. I'm trying to translate the code to Pascal (a recent version of Lazarus on Windows 7). From reading between the lines, I think I may have got a lot of it - however, I'll only know if I've got it wrong when it fails to do its job. At the moment it is failing to compile at the following point.
if (!DuplicateTokenEx(userToken, 0x10000000, ref tokenAttributes,
SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, TOKEN_TYPE.TokenImpersonation,
out newToken)) {
log("ERROR: DuplicateTokenEx returned false - "
My Pascal version:
If Not DuplicateTokenEx(UserToken, MAXIMUM_ALLOWED, tokenAttributes,
SecurityImpersonation, TokenPrimary, newToken) then
Writeln(DLog, 'Failed to duplicate security token');
Lazarus throws an error on the fifth of the six parameters.
dmain.pas(189,110) Error: Incompatible type for arg no. 5: Got "TOKEN_TYPE", expected "_TOKEN_TYPE" - which indicates I haven't understood what the parameters are doing. (Changing parameter 5 to TokenImpersonation throws the same error.)
Further down, I get even more lost:
tokPrivs.Privileges = new LUID_AND_ATTRIBUTES[1];
tokPrivs.Privileges[0].Luid = seDebugNameValue;
tokPrivs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
I can see that the structure type LUID_AND_ATTRIBUTES is in the Windows API but it seems it's not recognised by Lazarus.
In short, I'm groping around in the dark. I've tried Googling for "C# for Pascal programmers" but didn't find anything helpful. Learning C# isn't a trivial undertaking, so I be would really grateful for any hints on the differences between it and Object Pascal, and how to translate this code.
Edit: Unfinished code as requested.
function RunOurProcess(ProgramName: String): Boolean;
var
StartInfo: TStartupInfo;
ProcInfo: TProcessInformation;
NewToken, Token, UserToken: THandle;
WPID: DWord;
ThreadAttributes, TokenAttributes: TSecurityAttributes;
TOKPrivs: TTokenPrivileges;
begin
FillChar(StartInfo, SizeOf(TStartupInfo), #0);
FillChar(ProcInfo, SizeOf(TProcessInformation), #0);
StartInfo.cb:= SizeOf(TStartupInfo);
{ Insert handle of current desktop - without this, GUI app is not visible!
To appear before logon, lpDesktop value should be 'winsta0\WinLogon' }
StartInfo.lpDesktop:= PChar('winsta0\WinLogon');
// Save the process ID of the WinLogon process
WPID:= FindInProcesses('Winlogon.exe');
// Get the handle of this
Token:= OpenProcess(TOKEN_QUERY or TOKEN_IMPERSONATE or TOKEN_DUPLICATE, False, WPID);
// Open a process token using the handle above
If OpenProcessToken(Token, TOKEN_QUERY or TOKEN_IMPERSONATE or TOKEN_DUPLICATE, UserToken) then
Writeln(DLog, 'Opened process token for WinLogon')
else
Writeln(DLog, 'Failed to open process token for WinLogon');
// Create a new token
NewToken:= 0;
tokenAttributes.nLength:= SizeOf(tokenAttributes);
threadAttributes.nLength:= SizeOf(threadAttributes);
If Not DuplicateTokenEx(UserToken, MAXIMUM_ALLOWED, tokenAttributes, SecurityImpersonation, TokenImpersonation, newToken) then
Writeln(DLog, 'Failed to duplicate security token');
// Elevate the privileges of the token
AdjustTokenPrivileges(NewToken, False, {NewState, BufferLength, PreviousState, ReturnLength});
// LogOnUser
// If successful, CreateProcessAsUser
// In progress - code below needs to go before 'CreateProcessAsUser'
StartInfo.cb:= SizeOf(TStartupInfo);
// Insert handle of current desktop - without this, GUI app is not visible!
StartInfo.lpDesktop:= PChar('winsta0\WinLogon');
end; // RunOurProcess
I notice now that I get the following error if I try to find the declaration for "DuplicateTokenEx"
C:\lazarus\fpc\2.6.1\source\packages\winunits-jedi\src\jwawindows.pas(366,5) Error: include file not found "JwaLmErr.pp"
Here's how to solve the compilation problems.
The call to DuplicateTokenEx actually fails on the third parameter. Looking at the declaration, it is LPSECURITY_ATTRIBUTES which is ^TSecurityAttributes. Now, tokenAttributes is of type TSecurityAttributes so you need to pass its address:
If Not DuplicateTokenEx(..., #tokenAttributes, ...) then
And similarly in the call to AdjustTokenPrivileges. The C# code is:
AdjustTokenPrivileges(newToken, false, ref tokPrivs, 0, IntPtr.Zero, IntPtr.Zero)
Translated to Pascal that would be:
AdjustTokenPrivileges(NewToken, False, #TOKPrivs, 0, nil, nil)
I've no idea whether or not the code will solve your problem. I think that's beyond the remit of this question – at least that's my excuse and I'm sticking to it!
Related
Ok, first of all: my task is, to map a network drive programmatically from a C# program that runs as administrator.
I managed to map a drive as my normal admin user without elevated privileges and it was still visible after logoff/reboot (even though it didn't reconnect, but that's a different story). I did this with the WNetAddConnection2 WinApi function and also with the net use command in cmd, just to check.
Sadly, both didn't work with elevated privileges. In this case the drive is added as it schould, but after a reboot it is completely gone.
Is it even possible to achieve this with elevated privileges or is there some Windows account magical stuff I don't know about that prevents that?
Here is the Code I used, setting all flags that should usually make the drive be remembered and also reconnected:
uint flags = (uint)(Flags.CONNECT_CMD_SAVECRED |
Flags.CONNECT_INTERACTIVE |
Flags.CONNECT_COMMANDLINE |
Flags.CONNECT_UPDATE_PROFILE);
NETRESOURCE NetworkResource = new NETRESOURCE();
oNetworkResource.dwType = ResourceType.RESOURCETYPE_DISK;
oNetworkResource.lpLocalName = Console.ReadLine() + ":";
oNetworkResource.lpRemoteName = #"\\[Server]\foo";
oNetworkResource.lpProvider = null;
Console.WriteLine(WNetAddConnection2(NetworkResource, "[Password]", #"[Domain]\[Username]", flags));
it was still visible after logoff/reboot
this is because, when CONNECT_UPDATE_PROFILE flag used - called exported, but undocumented function I_MprSaveConn (from mpr.dll) which save in registry, under HKEY_CURRENT_USER\Network\<lpLocalName> information which you pass to WNetAddConnection2. but I_MprSaveConn at very begin call function bool IsElevatedCaller(PLUID ) and if function return true - it just exit, without saving in registry. so you absolute correct - when you call WNetAddConnection2 from elevated process (without impersonation) - this connection not persist (info not saved in registry)
solution: you need got not elevated token (say from explorer) - open/duplicate (for TokenImpersonation type) and call SetThreadToken. in this case IsElevatedCaller (can) return false (it first try open thread token (only if it not exist - process token) ) and query opened token for TokenElevationType (and return true if TokenElevationTypeFull )
so this of course not documented, but current (i test) if you impersonate self thread with not elevated token (how you got it separate question) flag CONNECT_UPDATE_PROFILE will be worked well
I'm trying to simulate a keypress into another window, which is a game. The things that don't work are:
SendKey - Send the input as strings like some text or something but doesn't go for ENTER TAB or other critical keys
InputSimulator - Complete waste of time
SendInput - Have some problems with this as well. It doesn't compile, and I've never used it before
PostMessage - it seems these 2 are pretty much the same and again they do send text but again no other keys such as ENTER TAB or other. Also couldn't figure out the value for wParam if i wanna hold down the key for a number of seconds. It is a 32bit Hex value in which seems the last 16 are repetition number.
SendMessage - See PostMessage
AUTOIT or AHK it seems that they have troubles being incorporated into C# if anyone knows how to do that, it would help immensely, this meaning I'd be able to write AHK script in the C# .cs file so it would compile. COM, ref, or anything.
Having problems with DirectInput
public void Test_KeyDown()
{
INPUT[] InputData = new INPUT[2];
Key ScanCode = Microsoft.DirectX.DirectInput.Key.W;
InputData[0].type = 1; //INPUT_KEYBOARD
InputData[0].ki.wScan = (short)VirtualKeyCode.NUMPAD2 ; //ScanCode;
InputData[0].ki.dwFlags = (int)KEYEVENTF.SCANCODE;
InputData[1].type = 1; //INPUT_KEYBOARD
InputData[1].ki.wScan = (short)VKeys.VK_W;
InputData[1].ki.dwFlags = (int)(KEYEVENTF.KEYUP | KEYEVENTF.UNICODE);
// send keydown
if (SendInput(2, InputData, Marshal.SizeOf(InputData[1])) == 0)
{
System.Diagnostics.Debug.WriteLine("SendInput failed with code: " +
Marshal.GetLastWin32Error().ToString());
}
}
It gives this error:
Could not load file or assembly 'Microsoft.DirectX.DirectInput.dll' or one of
its dependencies. is not a valid Win32 application.
(Exception from HRESULT: 0x800700C1)
I've referenced it from DirectX SDK tool kit 2007
I'm trying to send a key to another instance or handle. C++ or C# anything that works is fine, too.
Looks like you are trying to load a 32bit dll in a 64 bit solution, so please use the 64bit dll
I am trying to access a webpage through ASP.NET using the NetworkCredential class. However I keep getting an exception with the following message System.Security.Cryptography.CryptographicException: The handle is invalid
Below is my code on how I am trying to call the function. Any help is greatly appreciated.
C#:
System.Net.WebClient client = new System.Net.WebClient();
client.Credentials = new System.Net.NetworkCredential("Admin", "Nimda");
Stack Trace
[CryptographicException: The handle is invalid.
]
System.Security.SecureString.ProtectMemory() +154
System.Security.SecureString.InitializeSecureString(Char* value, Int32 length) +170
System.Security.SecureString..ctor(Char* value, Int32 length) +65
System.Net.SecureStringHelper.CreateSecureString(String plainString) +6181188
System.Net.NetworkCredential..ctor(String userName, String password) +64
I've just hit this same problem. I was happening locally under the ASP.NET Development Server in VS 2010. When I executed the app under my Windows 7 / IIS 7, it worked just fine. Hope this helps!
Ok this is a bit awkward - I've had a look and the error is down to your windows configuration .... somewhere.
The part of the code that's throwing an Exception is actually an interop call to a function in advapi32.dll, specifically:
int status = Win32Native.SystemFunction040(this.m_buffer, (uint) (this.m_buffer.Length * 2), 0);
if (status < 0)
{
throw new CryptographicException(Win32Native.LsaNtStatusToWinError(status));
}
this.m_encrypted = true;
Calls:
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success), DllImport("advapi32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
internal static extern int SystemFunction040([In, Out] SafeBSTRHandle pDataIn, [In] uint cbDataIn, [In] uint dwFlags);
That's returning an error code, causing your exception.
If you're in a workplace, you might want to talk with your sysadmin/network guys to see if there's anything in your local policies that might cause a failure.
Otherwise, I'd see what happens if you disable your Anti-virus/disable firewall/turn of any 3rd party proxy software.
Basically, anything that overrides default network functionality.
Also, might be worth checking you have all the latest windows updates and that you dont have any virus or malware infection.
Sorry I can't be more specific, but I don't believe this is a .Net/programming error.
This should work in a standard powershell console:
Add-Type -AssemblyName System.Net
$client = New-Object System.Net.WebClient
$netc = New-Object System.Net.NetworkCredential("Admin", "Nimda")
$client.Credentials = $netc
Will be interesting to see if this generates the same invalid handle error.
Edit: Apologies, there was a typo in the 2nd line.
Hi i have the following code which i would like to convert to C#. Could you share some light here how can i convert those to C#? i am not well familiar with C++. Especially on the function DeviceIoControl which it is calling the WinBase API. In C#, what function should i use to replace DeviceIOCOntrol?
shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
accessMode = GENERIC_READ | GENERIC_WRITE;
sprintf(ff, "\\\\.\\%s", device);
hFile = CreateFile(ff, accessMode, shareMode, NULL, OPEN_EXISTING, 0, NULL);
if(hFile == INVALID_HANDLE_VALUE) {
*response = -1;
sprintf((response + 1), "Failed to open device %s", device);
return;
}
status = DeviceIoControl(hFile,
IOCTL_SCSI_GET_ADDRESS,
NULL,
0,
inquiry_data,
sizeof(inquiry_data),
&returned,
FALSE);
You must use P/Invoke interop to access DeviceIoControl. Here is a link that has similar calls and should be a good starting point: Defrag API C# wrappers
This is retrieving the SCSI bus #, ID # on that bus, and LUN on that ID. You'll probably need to figure out what's being done with that to figure out how to translate/replace it meaningfully. If memory serves, you can retrieve some of the same information via WMI, but there's a pretty fair chance that won't do a lot of good -- the primary uses for this information is to pass it back when making other DeviceIoControl calls.
I am trapping for the execution of some old 16-bit applications that our internal folks should no longer be using. They are 1985 DOS apps, so trapping for them was easy... capture any process that launches under NTVDM.exe
Now, the problem is finding out which program NTVDM is actually running under the hood. Apparently there are a coupleof the 1985 programs that they SHOULD be allowed to run, so I need to see the actual EXE name that is hiding under NTVDM.
WqlEventQuery query =
new WqlEventQuery("__InstanceCreationEvent",
new TimeSpan(0, 0, 1),
"TargetInstance isa \"Win32_Process\"");
ManagementEventWatcher watcher = new ManagementEventWatcher(query);
watcher.EventArrived += new EventArrivedEventHandler(watcher_EventArrived);
watcher.Start();
...
static void watcher_EventArrived(object sender, EventArrivedEventArgs e)
{
ManagementBaseObject instance = (ManagementBaseObject)e.NewEvent["TargetInstance"];
ProcessInfo PI = new ProcessInfo();
PI.ProcessID = int.Parse(instance["ProcessID"].ToString());
PI.ProcessName = instance["Name"].ToString();
PI.ProcessPath = instance["ExecutablePath"].ToString();
// Here's the part I need...
PI.ActualEXE = ???;
// ... do the magic on the PI class ...
instance.Dispose();
}
When I capture the instance information, I can get the command line, but the arguments are "-f -i10" ... There is no EXE name on the command line. Is there any other method/property I should be looking at to determine the EXE name of the 16-bit application that's actually running?
UPDATE: Let me refine the question: If I can find the NTVDM process, how can I -- programatically -- know the actual path to the EXE that is being executed underneath?
Thanks.
The trick is not to use VDMEnumProcessWOW (which gives the VDMs), but to use VDMEnumTasksWOW. The enumerator function that you pass to this function will be called for each 16 bit task in the specified VDM.
I haven't checked it myself, but according to the documentation, this library of CodeProject does exactly that, if you pass in the PROC16 enum value. It's C++, if you need help compiling that code and calling it from C#, let me know and I'll give you an example.
A program that uses this technique is Process Master, it comes with full source. I suggest you run it to find out whether it gives the info you need, and if so, you can apply this method to your own application (it doesn't run on Windows Vista or 7, it uses old VB5 code, apparently it's not compatible. It should run on XP).
If things with these functions do not go as planned, you may be on Vista and may need the hotfix described in this StackOverflow question, which points to downloading a hotfix, which is in turn described here:
"An application that uses the
VDMEnumProcessWOW function to
enumerate virtual DOS machines returns
no output or incorrect output on a
computer that is running a 32-bit
version of Windows Vista"
Update: while this seems promising, I applied the patch, ran several versions of the code, including Microsoft's, and while they all work on XP, they fail silently (no error, or wrong return value) on Vista.
The "kinda" working code
Update: I experimented with (amongst others) with the following code, which compiles fine in C# (and can be written simpler, but I didn't want to run a marshal-mistake risk). When you add these functions, you can call Enum16BitProcesses, which will write the filenames of the EXE files of the 16 bit processes to the Console.
I can't run it on Vista 32 bit. But perhaps others can try and compile it, or find the error in the code. It would be nice to know whether it works on other systems:
public class YourEnumerateClass
{
public static void Enum16BitProcesses()
{
// create a delegate for the callback function
ProcessTasksExDelegate procTasksDlgt =
new ProcessTasksExDelegate(YourEnumerateClass.ProcessTasksEx);
// this part is the easy way of getting NTVDM procs
foreach (var ntvdm in Process.GetProcessesByName("ntvdm"))
{
Console.WriteLine("ntvdm id = {0}", ntvdm.Id);
int apiRet = VDMEnumTaskWOWEx(ntvdm.Id, procTasksDlgt, IntPtr.Zero);
Console.WriteLine("EnumTaskWOW returns {0}", apiRet);
}
}
// declaration of API function callback
public delegate bool ProcessTasksExDelegate(
int ThreadId,
IntPtr hMod16,
IntPtr hTask16,
IntPtr ptrModName,
IntPtr ptrFileName,
IntPtr UserDefined
);
// the actual function that fails on Vista so far
[DllImport("VdmDbg.dll", SetLastError = false, CharSet = CharSet.Auto)]
public static extern int VDMEnumTaskWOWEx(
int processId,
ProcessTasksExDelegate TaskEnumProc,
IntPtr lparam);
// the actual callback function, on Vista never gets called
public static bool ProcessTasksEx(
int ThreadId,
IntPtr hMod16,
IntPtr hTask16,
IntPtr ptrModName,
IntPtr ptrFileName,
IntPtr UserDefined
)
{
// using PtrToStringAnsi, based on Matt's comment, if it fails, try PtrToStringAuto
string filename = Marshal.PtrToStringAnsi(ptrFileName);
Console.WriteLine("Filename of WOW16 process: {0}", filename);
return false; // false continues enumeration
}
}
Update: Intriguing read by the renown Matt Pietrek. Mind the sentence, somewhere near the end:
"For starters, MS-DOS-based programs
seem to always run in separate NTVDM
sessions. I was never able to get an
MS-DOS-based program to run in the
same session as a 16-bit Windows-based
program. Nor was I able to get two
independently started MS-DOS-based
programs to run in the same NTVDM
session. In fact, NTVDM sessions
running MS-DOS programs don't show up
in VDMEnumProcessWOW enumerations."
Seems that, to find out what processes are loaded, you'll need to write a hook into NTVDM or write a listener that monitors access to the file. When the application that tries to read a certain DOS file is NTVDM.exe, it's bingo. You may want to write a DLL that's only attached to NTVDM.exe, but now we're getting a bit ahead of ourselves. Long story short: this little ride into NTVDM has shown "possibilities" that appeared real hoaxes in the end.
There's one other way, but time is too short to create an example. You can poke around in the DOS memory segments and the EXE is usually loaded at the same segment. But I'm unsure if that eventually will lead to the same result and whether it's worth the effort.
This works for me:
Follow the instructions at Description of the Software Restriction Policies in Windows XP to open the local or domain policy editor.
Under Software Restriction Policies -> Additional Rules, right click and select New Hash Rule.
Browse to (for example) edit.com. Make sure Security Level is set to Disallowed. Click OK.
Now,
C:\>edit
The system cannot execute the specified program.
(I get the same results from command.com and cmd.exe -- under Win XP)
From this link about VDMDBG functions, you may be able to P/Invoke "VDMEnumProcessWOW()", then enumerate modules within the process using PSAPI.
Note Regarding 16-bit DOS Applications:
None of the VDMDBG functions work with
16-bit DOS applications. To enumerate
DOS VDMs, you need to use another
method. First, you could use
VDMEnumProcessWOW() to make a list of
all Win16 VDMs, and then enumerate all
instances of NTVDM.exe using some
other scheme (such as PSAPI). Any
NTVDM.exe from the full enumeration
that was not in the Win16 list is a
DOS VDM. You can create and terminate
16-bit DOS applications with
CreateProcess() and
TerminateProcess().
Hope that helps...