I have a windows service and tried to map it using the pinvoke. The code works fine in a console application, but it has no effect in a windows service. According to this:
"net use" command in a Windows Service
I should drop the net use approach and instead give the appropriate privileges, so that my service can access the UNC path ( \server\share\file-path ). How do I set up these privileges? I assume it's basic Windows privileges that should be set somewhere. Any help is appreciated.
[DllImport("NetApi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern System.UInt32 NetUseAdd(string UncServerName, int Level, ref USE_INFO_2 Buf, out uint ParmError);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct USE_INFO_2
{
internal LPWSTR ui2_local;
internal LPWSTR ui2_remote;
internal LPWSTR ui2_password;
internal DWORD ui2_status;
internal DWORD ui2_asg_type;
internal DWORD ui2_refcount;
internal DWORD ui2_usecount;
internal LPWSTR ui2_username;
internal LPWSTR ui2_domainname;
}
and...
static void Main()
{
USE_INFO_2 useInfo = new USE_INFO_2();
useInfo.ui2_remote = #"\\xx.xx.xx.xx\E$"; // "\\xx.xx.xx.xx\E$"
useInfo.ui2_password = "********";
useInfo.ui2_asg_type = 0; //disk drive
useInfo.ui2_usecount = 1;
useInfo.ui2_username = "Admin";
useInfo.ui2_domainname = "rendering";
uint paramErrorIndex;
uint returnCode = NetUseAdd(String.Empty, 2, ref useInfo, out paramErrorIndex);
if (returnCode != 0)
{
throw new Win32Exception((int)returnCode);
}
...
You could launch your Windows service as a domain/windows user that does have access to this path.
Related
I would like to allow the user to connect to paired audio devices directly from the app instead of navigating to the bluetooth settings manually.
I am successfully listing all bluetooth devices using WinRT Apis:
var result = await DeviceInformation.FindAllAsync(BluetoothDevice.GetDeviceSelector());
// allow user to select a device
DeviceInfo d = await SelectDevice(result);
BluetoothDevice bluetoothDevice = await BluetoothDevice.FromIdAsync(d.Id);
As the WinRT-Apis do not expose any "Connect" interface (Remember, I want to connect the device as Windows would not communicate with it myself), I'm exploring using P/Invoke, so I use the following after reading this answer on superuser.com which suggests using BluetoothSetServiceState:
// Definitions
private const string bluetoothDll = "bthprops.cpl";
[DllImport(bluetoothDll, ExactSpelling = true, SetLastError = true)]
private static extern uint BluetoothSetServiceState(IntPtr hRadio, ref BLUETOOTH_DEVICE_INFO pbtdi, ref Guid pGuidService, uint dwServiceFlags);
[DllImport(bluetoothDll, SetLastError = true)]
private static extern IntPtr BluetoothFindFirstRadio(ref Bluetooth_Find_Radio_Params pbtfrp, out IntPtr phRadio);
[DllImport(bluetoothDll, SetLastError = true)]
private static extern bool BluetoothFindRadioClose(IntPtr findHandle);
[DllImport(bluetoothDll, SetLastError = true)]
private static extern uint BluetoothGetDeviceInfo(IntPtr hRadio, ref BLUETOOTH_DEVICE_INFO pbtdi);
private const uint BLUETOOTH_SERVICE_DISABLE = 0;
private const uint BLUETOOTH_SERVICE_ENABLE = 0x00000001;
// Code (using the bluetoothDevice obtained from the WinRT Api)
using(var pointer = GetRadioPointer())
{
BLUETOOTH_DEVICE_INFO deviceInfo = new BLUETOOTH_DEVICE_INFO
{
Address = bluetoothDevice.BluetoothAddress,
dwSize = (uint)Marshal.SizeOf<BLUETOOTH_DEVICE_INFO>()
};
uint result = BluetoothGetDeviceInfo(pointer.Handle, ref deviceInfo);
Guid serviceRef = InTheHand.Net.Bluetooth.BluetoothService.Handsfree;
result = BluetoothSetServiceState(pointer.Handle, ref deviceInfo, ref serviceRef, 1);
}
// I get the radio like this:
private RadioHandle GetRadioPointer()
{
Bluetooth_Find_Radio_Params pbtfrp = new Bluetooth_Find_Radio_Params();
pbtfrp.Initialize();
IntPtr findHandle = IntPtr.Zero;
try
{
findHandle = BluetoothFindFirstRadio(ref pbtfrp, out IntPtr phRadio);
return new RadioHandle(phRadio);
}
finally
{
if (findHandle != IntPtr.Zero)
{
BluetoothFindRadioClose(findHandle);
}
}
}
However, I cannot get it to work. BluetoothSetServiceState always returns 87, which is ERROR_INVALID_PARAMETER and nothing happens. Any idea on how to solve this? Using the command line tools referenced in the superuser-post, it works...
Thanks for your help.
I found it out by chance myself and it works now. Depending whether the service is already in the state (even if the device is disconnected), you will need to turn it off before. So turning it off and on again works:
BluetoothSetServiceState(pointer.Handle, ref deviceInfo, ref serviceRef, 0);
BluetoothSetServiceState(pointer.Handle, ref deviceInfo, ref serviceRef, 1);
So as it turns out, you can connect a device if you enumerate the services, turn all off and on again. Disconnecting works by turning all off. When the last one is off, Windows disconnects the device.
Why would you ever expect that the following line would work:
private const string bluetoothDll = "bthprops.cpl";
when MSDN's page states:
DLL: Bthprops.dll
?
I made a program which prints on a specific printer, but I have multiple printers to setup, so I thought that I will make the site from where they print, do it for me. I have tried to do it via. powershell etc., and it works, just not in my .net core api, but it works in my .net core console. I have given the IUSR rights to manage printers, ports etc. It can make the printer port, but not create the printer. When I used powershell, I got that "Add-Printer" didn't exist, and I tried putting it in powershell myself, and it worked perfectly.. Here is my code:
class Program
{
static void Main(string[] args)
{
IntPtr mystrptr = new IntPtr(0);
bool mysend;
IntPtr mysend2;
PRINTER_INFO_2 pi = new PRINTER_INFO_2();
string printer = "05_Vognmodtagelse_Label";
pi.pPrinterName = printer;
pi.pPortName = printer;
pi.pDriverName = "Brother PT-P950NW";
pi.pDevMode = mystrptr;
pi.pPrintProcessor = "WinPrint";
pi.pDatatype = "RAW";
pi.pSecurityDescriptor = mystrptr;
mysend2 = AddPrinter(null, 2, ref pi);
}
[DllImport("winspool.drv", CharSet = CharSet.Auto)]
static extern IntPtr AddPrinter(string pName, uint Level, [In] ref PRINTER_INFO_2 pPrinter);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
struct PRINTER_INFO_2
{
public string pServerName,
pPrinterName,
pShareName,
pPortName,
pDriverName,
pComment,
pLocation;
public IntPtr pDevMode;
public string pSepFile,
pPrintProcessor,
pDatatype,
pParameters;
public IntPtr pSecurityDescriptor;
public uint Attributes,
Priority,
DefaultPriority,
StartTime,
UntilTime,
Status,
cJobs,
AveragePPM;
}
}
Note: It is the code from the console app.
So I am trying to use C# and the ObRegisterCallbacks function to get notified about any calls to OpenProcess.
This is the code I have so far:
internal static class Win32SelfProtection
{
[DllImport("NtosKrnl.exe", SetLastError = true, PreserveSig = false)]
private static extern uint ObRegisterCallbacks(IntPtr callbackRegistration, out IntPtr registrationHandle);
[DllImport("NtosKrnl.exe", SetLastError = true, PreserveSig = false)]
private static extern void ObUnRegisterCallbacks(IntPtr registrationHandle);
[DllImport("kernel32.dll")]
internal static extern bool VirtualProtect(IntPtr lpAddress, uint dwSize, uint flNewProtect, out uint lpflOldProtect);
private const uint OB_OPERATION_HANDLE_CREATE = 0x00000001;
private const uint OB_OPERATION_HANDLE_DUPLICATE = 0x00000002;
private const uint PAGE_READWRITE = 0x04;
[StructLayout(LayoutKind.Sequential)]
internal struct OB_CALLBACK_REGISTRATION
{
internal ushort Version;
internal ushort OperationRegistrationCount; // 1
internal IntPtr Altitude;
internal IntPtr RegistrationContext; // NULL, probably
internal IntPtr OperationRegistration; // OB_OPERATION_REGISTRATION*
}
[StructLayout(LayoutKind.Sequential)]
internal struct OB_OPERATION_REGISTRATION
{
internal IntPtr ObjectType; // PsProcessType
internal uint Operations; // OB_OPERATION_HANDLE_CREATE
internal IntPtr PreOperation; // POB_PRE_OPERATION_CALLBACK
internal IntPtr PostOperation; // POB_POST_OPERATION_CALLBACK
}
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct UNICODE_STRING
{
internal ushort Length;
internal ushort MaximumLength;
internal IntPtr Buffer;
}
internal static unsafe void Protect()
{
PobPreOperationCallback preOperationCallback = PreOperationCallback;
IntPtr pPreOperationCallback = Marshal.GetFunctionPointerForDelegate(preOperationCallback);
PobPostOperationCallback postOperationCallback = PostOperationCallback;
IntPtr pPostOperationCallback = Marshal.GetFunctionPointerForDelegate(postOperationCallback);
OB_OPERATION_REGISTRATION operationRegistration = new OB_OPERATION_REGISTRATION
{
ObjectType = IntPtr.Zero, // I have no idea ... <-- Need pointer to PsProcessType
Operations = OB_OPERATION_HANDLE_CREATE,
PreOperation = pPreOperationCallback,
PostOperation = pPostOperationCallback
};
IntPtr pOperationRegistration = Marshal.AllocHGlobal(sizeof(OB_OPERATION_REGISTRATION));
Marshal.StructureToPtr(operationRegistration, pOperationRegistration, false);
const ushort buffersize = sizeof(ushort) * 64;
IntPtr buffer = Marshal.AllocHGlobal(buffersize);
// No idea what kind of string I should put in here :C just zero it for now ...
Marshal.Copy(new byte[buffersize], 0, buffer, buffersize);
UNICODE_STRING unicodeString = new UNICODE_STRING
{
Length = buffersize,
MaximumLength = buffersize,
Buffer = buffer
};
IntPtr pUnicodeString = Marshal.AllocHGlobal(sizeof(UNICODE_STRING));
Marshal.StructureToPtr(unicodeString, pUnicodeString, false);
OB_CALLBACK_REGISTRATION callbackRegistration = new OB_CALLBACK_REGISTRATION
{
Version = 0x0100,
OperationRegistrationCount = 1,
Altitude = pUnicodeString,
RegistrationContext = IntPtr.Zero,
OperationRegistration = pOperationRegistration
};
IntPtr pCallbackRegistration = Marshal.AllocHGlobal(sizeof(OB_CALLBACK_REGISTRATION));
Marshal.StructureToPtr(callbackRegistration, pCallbackRegistration, false);
uint status = ObRegisterCallbacks(pCallbackRegistration, out IntPtr hRegistration); // FAILS WITH: AccessViolationException
// yeah, yeah I'll remember to call Marshal.FreeHGlobal() later ... :D
}
public delegate uint PobPreOperationCallback(IntPtr registrationContext, IntPtr operationInformation);
// dummy method for now
internal static uint PreOperationCallback(IntPtr registrationContext, IntPtr operationInformation)
{
Console.WriteLine("PreOperationCallback!");
return 0x0;
}
public delegate void PobPostOperationCallback(IntPtr registrationContext, IntPtr operationInformation);
// dummy method for now
internal static void PostOperationCallback(IntPtr registrationContext, IntPtr operationInformation)
{
Console.WriteLine("PostOperationCallback!");
}
}
The ObRegisterCallbacks function takes an OB_CALLBACK_REGISTRATION struct (docs here) as parameter that itself consists of an array of OB_OPERATION_REGISTRATION structs (docs here).
This is where I'm stuck:
The OB_OPERATION_REGISTRATION's first member, "ObjectType", is documented as follows
ObjectType
A pointer to the object type that triggers the callback routine. Specify one of the following values:
PsProcessType for process handle operations
PsThreadType for thread handle operations
ExDesktopObjectType for desktop handle operations. This value is supported in Windows 10 and not in the earlier versions of the operating system.
After a few hour of searching I still have no clue how I'm supposed to specify PsProcessType and initialize my struct with it. PsProcessType seems to be defined in process.c in line 20.
However it literally just says
POBJECT_TYPE PsProcessType = NULL;
which isn't especially helpful, since when setting the ObjectType field to IntPtr.Zero when initializing the OB_OPERATION_REGISTRATION struct a System.AccessViolationException is triggered when calling ObRegisterCallbacks. (There's also a UNICODE_STRING in the OB_OPERATION_REGISTRATION struct called Altitude that has to be set to some value (but currently isn't lol :D), but that string is initialized and allocated, so it shouldn't be responsible for the access violation... right?)
This is my first time diving this deep into Windows kernel stuff, so it would be nice if someone could help me out with this or point me to some hidden resources I didn't manage to dig up :)
There's an article that uses ObRegisterCallbacks for similar things (in C++ though), however they don't really specify where they're getting PsProcessType from, or how it's defined. So there has to be documentation somewhere out there, if they can successfully use that "ObjectType" field, right?
PsProcessType is exported at ntoskrnl.exe and is the same as ObRegisterCallbacks, the difference between them is that one is an exported global variable and the other is an exported function.
In C, these global variables are declared in wdm.h:
extern POBJECT_TYPE *CmKeyObjectType;
extern POBJECT_TYPE *IoFileObjectType;
extern POBJECT_TYPE *ExEventObjectType;
extern POBJECT_TYPE *ExSemaphoreObjectType;
extern POBJECT_TYPE *TmTransactionManagerObjectType;
extern POBJECT_TYPE *TmResourceManagerObjectType;
extern POBJECT_TYPE *TmEnlistmentObjectType;
extern POBJECT_TYPE *TmTransactionObjectType;
extern POBJECT_TYPE *PsProcessType;
extern POBJECT_TYPE *PsThreadType;
extern POBJECT_TYPE *PsJobType;
extern POBJECT_TYPE *SeTokenObjectType;
#if (NTDDI_VERSION >= NTDDI_THRESHOLD)
extern POBJECT_TYPE *ExDesktopObjectType;
#endif
So you can just use these variables without having to do anything else.
But I'm not good at C#, and I'm not even sure if C# modules can be loaded into the kernel.
The most recommended approach is to use C/C++ for kernel programming, and I've never heard of anyone doing this with C#.
I have some code which retrieves the 128bit NTFS Ids from files at specific paths. Then I attempted to retrieve the file path using this ID. The code works as long as when retrieving the paths I run as admin. This is not going to be possible in production. Unfortunately I am unable to call Marshal.GetLastWin32Error() because the System.AccessViolationException causes the application to completely crash. Below is the code to retrieve the paths.
public const int NO_PERMISSION = 0;
[DllImportAttribute("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern SafeFileHandle CreateFile(
string lpFileName,
uint dwDesiredAccess,
uint dwShareMode,
[InAttribute()] System.IntPtr lpSecurityAttributes,
uint dwCreationDisposition,
uint dwFlagsAndAttributes,
[InAttribute()] System.IntPtr hTemplateFile
);
[DllImportAttribute("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern SafeFileHandle OpenFileById(
IntPtr hVolumeHint,
FILE_ID_DESCRIPTOR lpFileId,
uint dwDesiredAccess,
uint dwShareMode,
[InAttribute()] System.IntPtr lpSecurityAttributes,
uint dwFlagsAndAttributes
);
public enum _FILE_ID_TYPE
{
FileIdType = 0,
ObjectIdType,
ExtendedFileIdType,
MaximumFileIdType
}
[StructLayout(LayoutKind.Explicit)]
public struct FILE_ID_128
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
[FieldOffset(0)]
public byte[] Identifier;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct FILE_ID_DESCRIPTOR
{
public uint dwSize;
public _FILE_ID_TYPE Type;
public FILE_ID_128 ExtendedFileId;
}
public static string GetObjectPathFromId(string pathToSection, string hexId)
{
// We need a file handle to the drive we are looking in
using (SafeFileHandle handle = Methods.CreateFile(
pathToSection,
Constants.NO_PERMISSION,
Constants.NO_PERMISSION,
IntPtr.Zero,
Constants.OPEN_EXISTING,
0x02000000 | 0x00000080,
IntPtr.Zero))
{
// Build descriptor
FILE_ID_DESCRIPTOR descriptor = new FILE_ID_DESCRIPTOR();
descriptor.dwSize = (uint)Marshal.SizeOf(descriptor);
descriptor.Type = _FILE_ID_TYPE.ExtendedFileIdType;
descriptor.ExtendedFileId.Identifier = StringToByteArrayFastest(hexId);
using (SafeFileHandle actualFile = OpenFileById(handle.DangerousGetHandle(), descriptor,
Constants.NO_PERMISSION, Constants.NO_PERMISSION,
IntPtr.Zero, 0))
{
if (actualFile.IsInvalid)
return "";
// Buffer for the path, this should be way big enough
int sizeOfBuffer = 1024;
// Allocate a buffer
IntPtr pointer = Marshal.AllocHGlobal(sizeOfBuffer);
uint size = (uint)sizeOfBuffer;
uint returnValue = GetFinalPathNameByHandleW(actualFile.DangerousGetHandle(), pointer, size, 0);
// Copy it into a managed array
byte[] outPut = new byte[sizeOfBuffer];
Marshal.Copy(pointer, outPut, 0, (int)returnValue);
// Decode it
var str = Encoding.Unicode.GetString(outPut);
// Will be an empty string if the call fails
return str;
}
}
}
Again I want to specify - this code works perfectly when running as admin. The files are owned by the user, the user is able to delete, rename and move the files without any additional permissions.
Any help would be greatly appreciated thanks!
Edit1:
I implemented the answer found here How to handle AccessViolationException to successfully catch the exception. However even after doing this Marshal.GetLastWin32Error() returns 0. If anyone has any idea of how I can debug this type of issue please let me know.
Also it's still functioning when I run as admin, just not as a user.
Edit2:
Not sure if it's relevant - library with this code is building for .NET Standard 2.0 - Application using this library code is building for .NET Framework 4.6.2
I am trying to find the COM port assigned to a USB device, through the registry using Silverlight, and have tried the following:
dynamic WshShell = AutomationFactory.CreateObject("WScript.Shell");
string strRegKeyUSB = #"HKLM\HARDWARE\DEVICEMAP\SERIALCOMM\\Device\USB_COM";
string strCOMValue = WshShell.RegRead(strRegKeyUSB);
This approach usually works 100%, but all Value names under the DEVICEMAP Key is "\Device\XXX"
This causes the the "Path" to not be found, as the "\\" between SERIALCOMM and Device is not seen as valid (Throws Error: "Cannot find File Specified")
This, as far as I can see, only really leaves me with one option - P/Invoke, in Silverlight 5
I am using P/Invoke already for a SerialWrapper Class, to Open, Read, Write the COM Ports, and would like to include only the minimal needed to only read this one Key Value from the Registry - I have tried following some examples I have found, but not being strong in Interop, P/Invoke, etc. I am struggling to find only the portions I need.
If someone could please just give me a basic example, to only accomplish this (I do NOT need to write to the registry, or read QWORDS, or anything else - Only read this string value from only this specific key)
I have tried following the following post (Marshal.PtrToStructure in Silverlight) and it's answer, in relation to this (http://www.pinvoke.net/default.aspx/winspool.enumports), but have not been able to get this working, Most likely form a lack of REALLY understanding ;-)
Here's a simple desktop application that reads a REG_SZ value. It's crude and simple. It will read the value that you want. You may have to adapt it to Silverlight. I cannot help you there!
I hope this is useful:
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Text;
namespace ConsoleApplication1
{
internal static class NativeMethods
{
public const int ERROR_SUCCESS = 0;
public const uint HKEY_LOCAL_MACHINE = 0x80000002;
public const int KEY_READ = 0x20019;
[DllImport("advapi32.dll", CharSet = CharSet.Unicode)]
public static extern int RegOpenKeyEx(
UIntPtr hKey,
string subKey,
int ulOptions,
int samDesired,
out UIntPtr hkResult
);
[DllImport("advapi32.dll")]
public static extern int RegCloseKey(
UIntPtr hKey
);
[DllImport("advapi32.dll", CharSet = CharSet.Unicode)]
public static extern int RegQueryValueEx(
UIntPtr hKey,
string lpValueName,
int lpReserved,
IntPtr type,
IntPtr lpData,
ref int lpcbData
);
}
internal static class RegistryWrapper
{
private static void checkErrorCode(int errorCode)
{
if (errorCode != NativeMethods.ERROR_SUCCESS)
throw new Win32Exception(errorCode);
}
public static string ReadRegString(UIntPtr rootKey, string subKey, string name)
{
UIntPtr hkey;
checkErrorCode(NativeMethods.RegOpenKeyEx(rootKey, subKey, 0, NativeMethods.KEY_READ, out hkey));
try
{
int cbData = 0;
checkErrorCode(NativeMethods.RegQueryValueEx(hkey, name, 0, IntPtr.Zero, IntPtr.Zero, ref cbData));
IntPtr ptr = Marshal.AllocHGlobal(cbData);
try
{
checkErrorCode(NativeMethods.RegQueryValueEx(hkey, name, 0, IntPtr.Zero, ptr, ref cbData));
return Marshal.PtrToStringUni(ptr, cbData / sizeof(char)).TrimEnd('\0');
}
finally
{
Marshal.FreeHGlobal(ptr);
}
}
finally
{
checkErrorCode(NativeMethods.RegCloseKey(hkey));
}
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine(RegistryWrapper.ReadRegString((UIntPtr)NativeMethods.HKEY_LOCAL_MACHINE, #"HARDWARE\DEVICEMAP\SERIALCOMM", #"\Device\Serial0"));
}
}
}
Update
It seems that AllocHGlobal and FreeHGlobal are not available on Silverlight. You can p/invoke to LocalAlloc and LocalFree instead. Or you could use CoTaskMemAlloc and CoTaskMemFree. Here's what the former looks like:
[DllImport("kernel32.dll", SetLastError=true)]
static extern IntPtr LocalAlloc(uint uFlags, UIntPtr uBytes);
[DllImport("kernel32.dll", SetLastError=true)]
static extern IntPtr LocalFree(IntPtr hMem);
Define LMEM_FIXED like this:
const uint LMEM_FIXED = 0x0000;
Then replace the call to AllocHGlobal with this:
IntPtr ptr = LocalAlloc(LMEM_FIXED, cbData);
And replace the call to FreeHGlobal with this:
LocalFree(ptr);
A BIG thank you to #Dave Heffernan,
I got this to work FINALLY...
I Added the following code within the RegistryWrapper class in Dave's Answer:
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr LocalAlloc(uint uFlags, int size);
internal static IntPtr AllocHGlobal(int size)
{
uint LPTR = (uint)0x0040;
IntPtr hGlobal = LocalAlloc(LPTR, size);
if (hGlobal == IntPtr.Zero)
{
throw new OutOfMemoryException("Unmanaged memory was not allocated.");
}
return hGlobal;
}
This works around the limitation of Marshal.AllocHGlobal not being available in Silverlight.
I then also just changed the reference to Marshal.AllocHGlobal to the local AllocHGlobal method above.