According the function description in "http://msdn.microsoft.com/en-us/library/cc196998%28v=VS.85%29.aspx", I wrote the following code to try to get IE protected cookies:
public static string GetProtectedModeCookie(string lpszURL, string lpszCookieName, uint dwFlags)
{
var size = 255;
var sb = new System.Text.StringBuilder(size);
var acturalSize = sb.Capacity;
var code = IEGetProtectedModeCookie(lpszURL, lpszCookieName, sb, ref acturalSize, dwFlags);
if ((code & 0x80000000) > 0) return string.Empty;
if (acturalSize > size)
{
sb.EnsureCapacity(acturalSize);
IEGetProtectedModeCookie(lpszURL, lpszCookieName, sb, ref acturalSize, dwFlags);
}
return sb.ToString();
}
[DllImport("ieframe.dll", SetLastError = true)]
public static extern uint IEGetProtectedModeCookie(string lpszURL, string lpszCookieName, System.Text.StringBuilder pszCookieData, ref int pcchCookieData, int dwFlags);
to test this function:
var cookies = GetProtectedModeCookie("http://bbs.pcbeta.com/", null, 0);
But the api IEGetProtectedModeCookie always return 0x80070057 which indicates that one or more arguments are invalid.
I was confused, after a lot of try finally failed, only get this result. Can anybody help me?
IEGetProtectedModeCookie will return E_INVALIDARG if it thinks that the URL isn't meant to open in Protected Mode. It determines this using the IEIsProtectedModeURL API. So if you've put that URL in the Trusted Zone or whatnot, then you'll hit this error. The underlying InternetGetCookie API will return E_INVALIDARG if you fail to pass a URL or fail to pass a pointer to an integer for the size of the buffer.
Also note that the IEGetProtectedModeCookie API will not work from a high integrity (e.g. Admin) process; it will return ERROR_INVALID_ACCESS (0x8000000C).
Here's the code I use:
[DllImport("ieframe.dll", CharSet = CharSet.Unicode, EntryPoint = "IEGetProtectedModeCookie", SetLastError = true)]
public static extern int IEGetProtectedModeCookie(String url, String cookieName, StringBuilder cookieData, ref int size, uint flag);
private void GetCookie_Click(object sender, EventArgs e)
{
int iSize = 4096;
StringBuilder sbValue = new StringBuilder(iSize);
int hResult = IEAPI.IEGetProtectedModeCookie("http://www.google.com", "PREF", sbValue, ref iSize, 0);
if (hResult == 0)
{
MessageBox.Show(sbValue.ToString());
}
else
{
MessageBox.Show("Failed to get cookie. HRESULT=0x" + hResult.ToString("x") + "\nLast Win32Error=" + Marshal.GetLastWin32Error().ToString(), "Failed");
}
}
Charset parameter must be exist in DllImport attribute. Change the API declartion to follow will works well:
[DllImport("ieframe.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern uint IEGetProtectedModeCookie(string lpszURL, string lpszCookieName, System.Text.StringBuilder pszCookieData, ref int pcchCookieData, uint dwFlags);
If Charset parameter missed, this API will always return 0x80070057 which indicates one or more arguments are invalid.
Related
I have a service that makes use of MemoryMappedFiles for interprocess communication. It has worked great for many years and was developed in .NET Framework 4.6.1. Now comes the time to port the code to .NET 6. I've gotten the bulk of it to work correctly except for one issue: the security ACL for the memory mapped file. That argument seems to have disappeared in .NET 6.
Here is a snippet from the 4.6.1 Framework version
fs = new FileStream(FileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
FileSecurity fSec = File.GetAccessControl(FileName);
fSec.AddAccessRule(new FileSystemAccessRule("everyone", FileSystemRights.FullControl, AccessControlType.Allow));
File.SetAccessControl(FileName, fSec);
if (fs.Length == 0)
fs.SetLength(_SectionSize);
long fLen = fs.Length;
MemoryMappedFileSecurity security = new MemoryMappedFileSecurity();
security.AddAccessRule(new AccessRule<MemoryMappedFileRights>("everyone", MemoryMappedFileRights.FullControl, AccessControlType.Allow));
//Name = #"Global\DCCCache"; // "Global\" when running as a service so session 0 stuff available to everyone
_MMFHandle = MemoryMappedFile.CreateFromFile(fs, Name, _SectionSize, MemoryMappedFileAccess.ReadWrite, security, HandleInheritability.Inheritable, false);
_VAHandle = _MMFHandle.CreateViewAccessor();
This all works and allows non-admin user processes access to the memory mapped file.
.NET 6 drops the security argument from the .CreateFromFile method. As a result, only processes running with Administrator privileges have access to the memory mapped file. An "Access Denied" IO exception is thrown from the OpenExisting method of MemoryMappedFile for non-admin processes.
Is there a way to modify the security when I create a memory mapped file so non-admin processes have access?
I did a workaround. Put together the call I needed to create the memory mapped file with the correct security and call it once in the service that owns it. I changed the mainline code to use OpenExisting after the call to the routine below so the remainder of the code can use the .NET 6 library as intended. Not ideal, but it fixed the issue.
using System.ComponentModel;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
namespace MMFService {
internal class MMFNet6Shim : IDisposable {
private bool win32Result = false;
private int cbSid = SECURITY_MAX_SID_SIZE;
private SECURITY_ATTRIBUTES securityAttributes = new SECURITY_ATTRIBUTES();
private SafeMemoryMappedFileHandle hFile;
private const int SDDL_REVISION_1 = 1;
private const int SECURITY_MAX_SID_SIZE = 68;
private const int PAGE_READWRITE = 0x04;
private const int FILE_MAP_WRITE = 0X02;
public MMFNet6Shim(FileStream fs, string DBName) {
win32Result = ConvertStringSecurityDescriptorToSecurityDescriptor("D:(A;OICI;GA;;;WD)", SDDL_REVISION_1, out securityAttributes.lpSecurityDescriptor, IntPtr.Zero);
if (!win32Result)
throw new Exception("ConvertStringSecurityDescriptorToSecurityDescriptor", new Win32Exception(Marshal.GetLastWin32Error()));
securityAttributes.nLength = Marshal.SizeOf(securityAttributes);
securityAttributes.bInheritHandle = false;
long fLen = fs.Length;
hFile = CreateFileMapping(fs.SafeFileHandle, ref securityAttributes, PAGE_READWRITE, 0, Convert.ToInt32(fLen), DBName);
if (hFile.IsInvalid)
throw new Exception("CreateFileMapping", new Win32Exception(Marshal.GetLastWin32Error()));
}
public void Dispose() {
if(!hFile.IsInvalid)
hFile.Close();
}
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES {
public int nLength;
public IntPtr lpSecurityDescriptor;
public bool bInheritHandle;
}
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool ConvertStringSecurityDescriptorToSecurityDescriptor
(
[In] string StringSecurityDescriptor,
[In] int StringSDRevision,
[Out] out IntPtr SecurityDescriptor,
[Out] IntPtr SecurityDescriptorSize
);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr LocalFree([In] IntPtr hMem);
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern SafeMemoryMappedFileHandle CreateFileMapping(
[In] SafeFileHandle hFile,
[In][Optional] ref SECURITY_ATTRIBUTES lpAttributes,
[In] int flProtect,
[In] int dwMaximumSizeHigh,
[In] int dwMaximumSizeLow,
[In][Optional] string lpName
);
}
}
The easiest way is to set access for Everyone:
using System.Runtime.InteropServices;
[DllImport("advapi32.dll", EntryPoint = "SetSecurityInfo", CallingConvention = CallingConvention.Winapi,
SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
private static extern uint SetSecurityInfoByHandle(SafeHandle handle, uint objectType, uint securityInformation,
byte[]? owner, byte[]? group, byte[]? dacl, byte[]? sacl);
then
mmfile = MemoryMappedFile.CreateNew("Global\\jdfghdfghsd", requiredsize, MemoryMappedFileAccess.ReadWrite);
if (SetSecurityInfoByHandle(mmfile.SafeMemoryMappedFileHandle, 1, 4, null, null, null, null) != 0)
throw new Exception("MemoryMappedFile set security failed");
Set customized access rights if required, look at SetSecurityInfo help
So, sample apps:
App1:
using System.IO.MemoryMappedFiles;
using System.Runtime.InteropServices;
[DllImport("advapi32.dll", EntryPoint = "SetSecurityInfo", CallingConvention = CallingConvention.Winapi,
SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
static extern uint SetSecurityInfoByHandle(SafeHandle handle, uint objectType, uint securityInformation,
byte[]? owner, byte[]? group, byte[]? dacl, byte[]? sacl);
var mmfile = MemoryMappedFile.CreateNew("Global\\dsfgsdfsdf", 4, MemoryMappedFileAccess.ReadWrite);
if (SetSecurityInfoByHandle(mmfile.SafeMemoryMappedFileHandle, 1, 4, null, null, null, null) != 0)
throw new Exception("Access rights set up failed");
mmfile.CreateViewAccessor(0, 4).Write(0, 234);
Console.ReadLine();
App2:
using System.IO.MemoryMappedFiles;
Console.WriteLine(MemoryMappedFile.OpenExisting("Global\\dsfgsdfsdf", MemoryMappedFileRights.ReadWrite).CreateViewAccessor(0, 4).ReadInt32(0));
Console.ReadLine();
Run app1, then app2. It should emit 234. Then press Enter for app1.
Be sure the user runs app1 is able to create the global objects (by default only administrators and services are allowed)
strange behaviour in our production environment, these days.
I have the following:
try {
var sourcePath = ... // my source path
var destinationPath = ... // guess what? You're right, my destination path
File.Copy(sourcePath, destinationPath);
Log.Debug(string.Format("Image {0} copied successfully", imagename));
}
catch(Exception e) {
// exception handling
}
Both source and destination path are on a network share, a folder on an other (virtual) machine with a large number of files (> 500k).
From the last 2 days, the code above runs, logs the last line (the one stating that image have been copied), but if I check in the destination folder, the supposed destination file does not exist.
I thought that for any I/O error File.Copy would raise an exception, so this thing is driving me mad.
Please note that other code parts that write files in that folder are working correctly. Also, note that all files names are unique (business code not included for brevity is making sure of that), and I think an exception would be thrown or the file would be at least overwritten, in that case.
Has anyone faced the same problem? Possible causes? Any solution?
EDIT 2016-07-01 15:12 (GMT+0200)
Ok, folks, apparently files aren't being deleted at all... simply for apparently no reason at all, after they are copied they're left open in read+write mode from the client connected user.
I found this trying running the reader application on my computer, in debug mode, and trying to open one of the files i knew that were copied recently.
I got an exception stating that the file was opened by someone else, and that seemed weird to me.
Opening Computer Management in the remote server (the one which stores the files), then going to Shared Folders > Open Files, I found that the file was left open in read+write mode from the impersonated user that the web application that copies the files is impersonating to do that job.
Also a whole bunch of other files where in the same conditions, and many others where open in read mode.
I found also in Shared Folders > Sessions, an astronomical long list of session of the impersonated user, all with long idle time.
Since impersonation is used only to copy the files, and then is disposed, I shouldn't expect that, right?
I think maybe there is a problem in the way we impersonate the user during file copy, linked to the large number of files in the destination folder.
I'll check that.
END EDIT
Thanks,
Claudio Valerio
Found a solution, I think.
My problem was the code used for impersonating the user with write permissions on the destination folder.
(In my defence, all this project have been inherited from previous software company, and it's pretty massive, so keeping an eye on everything isn't that easy)
The impersonation process was wrapped in a class implementing IDisposable
public class Impersonator :
IDisposable
{
public Impersonator()
{
string userName = // get username from config
string password = // get password from config
string domainName = // get domain from config
ImpersonateValidUser(userName, domainName, password);
}
public void Dispose()
{
UndoImpersonation();
}
[DllImport("advapi32.dll", SetLastError = true)]
private static extern int LogonUser(
string lpszUserName,
string lpszDomain,
string lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int DuplicateToken(
IntPtr hToken,
int impersonationLevel,
ref IntPtr hNewToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool RevertToSelf();
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern bool CloseHandle(
IntPtr handle);
private const int LOGON32_LOGON_INTERACTIVE = 2;
private const int LOGON32_PROVIDER_DEFAULT = 0;
private void ImpersonateValidUser(
string userName,
string domain,
string password)
{
WindowsIdentity tempWindowsIdentity = null;
IntPtr token = IntPtr.Zero;
IntPtr tokenDuplicate = IntPtr.Zero;
try
{
if (RevertToSelf())
{
if (LogonUser(
userName,
domain,
password,
LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT,
ref token) != 0)
{
if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
{
tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
impersonationContext = tempWindowsIdentity.Impersonate();
}
else
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
else
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
else
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
finally
{
if (token != IntPtr.Zero)
{
CloseHandle(token);
}
if (tokenDuplicate != IntPtr.Zero)
{
CloseHandle(tokenDuplicate);
}
}
}
private void UndoImpersonation()
{
if (impersonationContext != null)
{
impersonationContext.Undo();
}
}
private WindowsImpersonationContext impersonationContext = null;
}
This class is used this way:
using(new Impersonator())
{
// do stuff with files in here
}
My suspect was that closing the handlers of the impersonated user, somehow, it could break something in the way that windows handles file open by the impersonated user through a network share, as in my case, leaving shared files open in read+write mode, preventing any other process/user to open them.
I modified the Impersonator class as follows:
public class Impersonator :
IDisposable
{
public Impersonator()
{
string userName = // get username from config
string password = // get password from config
string domainName = // get domain from config
ImpersonateValidUser(userName, domainName, password);
}
public void Dispose()
{
UndoImpersonation();
impersonationContext.Dispose();
}
[DllImport("advapi32.dll", SetLastError = true)]
private static extern int LogonUser(
string lpszUserName,
string lpszDomain,
string lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int DuplicateToken(
IntPtr hToken,
int impersonationLevel,
ref IntPtr hNewToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool RevertToSelf();
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern bool CloseHandle(
IntPtr handle);
private const int LOGON32_LOGON_INTERACTIVE = 2;
private const int LOGON32_PROVIDER_DEFAULT = 0;
private void ImpersonateValidUser(
string userName,
string domain,
string password)
{
WindowsIdentity tempWindowsIdentity = null;
token = IntPtr.Zero;
tokenDuplicate = IntPtr.Zero;
try
{
if (RevertToSelf())
{
if (LogonUser(
userName,
domain,
password,
LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT,
ref token) != 0)
{
if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
{
tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
impersonationContext = tempWindowsIdentity.Impersonate();
}
else
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
else
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
else
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
finally
{
}
}
private void UndoImpersonation()
{
try
{
if (impersonationContext != null)
{
impersonationContext.Undo();
}
}
finally
{
if (token != IntPtr.Zero)
{
CloseHandle(token);
}
if (tokenDuplicate != IntPtr.Zero)
{
CloseHandle(tokenDuplicate);
}
}
}
private WindowsImpersonationContext impersonationContext = null;
private IntPtr token;
private IntPtr tokenDuplicate;
}
Basically I moved the handlers closing in the UndoImpersonation method. Also I had a doubt about leaving the impersonationContext not explicitly disposed, si I disposed it in the Dispose method of the Impersonator class.
Since I put in production this update, I hadn't any other issue with this code, and not any other shared file left open in read+write mode on the destination server.
Maybe not the optimal solution (I still have a whole bunch of sessions in Computer Management > Shared Folders > Sessions, but this seems not harming the system, for now.
If anyone have some additional comment, suggestion or depth study about this situation, I will be please to read.
Thanks,
Claudio
I want to change the text that shows when invoking CryptoApi operation that requires smart card PIN. Current prompt is pretty generic (and in system's language), "Please enter your authentication PIN":
This dialog shows when calling CryptSignMessage in COM object, but the call is made from C# WPF desktop app (.NET 4.5). How can I customize the dialog? I've found PP_PIN_PROMPT_STRING parameter for CryptSetProvParam function, but the function requires HCRYPTPROV and I don't have that handle. All I have is reader's name and signing certificate. Just can't wrap my head around it.
Is it possible to customize PIN dialog from either C++ or C# (preferably C#)?
I believe the following should work. As I don't have anything setup to test collecting the information I can't verify.
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptAcquireContext(out IntPtr phProv, string pszContainer, string pszProvider, uint dwProvType, uint dwFlags);
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CryptSetProvParam(IntPtr hProv, uint dwParam, [In] byte[] pbData, uint dwFlags);
[DllImport("advapi32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptReleaseContext(IntPtr hProv, uint dwFlags);
const string MS_DEF_PROV = "Microsoft Base Cryptographic Provider v1.0";
const uint NTE_BAD_KEYSET = 0x80090016;
const uint PROV_RSA_FULL = 1;
const uint CRYPT_VERIFYCONTEXT = 0xF0000000;
const uint CRYPT_NEWKEYSET = 0x00000008;
const uint PP_PIN_PROMPT_STRING = 0x2C;
public void SetPinText(string text)
{
byte[] data = Encoding.UTF8.GetBytes(text);
IntPtr hCryptProv = IntPtr.Zero;
try
{
if (!CryptAcquireContext(out hCryptProv, null, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
{
if (Convert.ToUInt32(Marshal.GetLastWin32Error()) == NTE_BAD_KEYSET)
{
if (!CryptAcquireContext(out hCryptProv, null, null, PROV_RSA_FULL, CRYPT_NEWKEYSET))
throw new Exception("Unable to acquire crypt context.");
}
else
{
throw new Exception("Unable to acquire crypt context.");
}
}
if (!CryptSetProvParam(hCryptProv, PP_PIN_PROMPT_STRING, data, 0))
throw new Exception("Unable to set prompt string.");
}
finally
{
if (hCryptProv != IntPtr.Zero)
{
CryptReleaseContext(hCryptProv, 0);
}
}
}
I am trying to upgrade to the MS .NET Framework 4 and I am encountering an error with a dllimport function (see below). When the code reaches the dllimport, the program just exits with error code 0x80000003. I have tried changing it so the input and output are StringBuilder and I also tried setting the charset by both changing the charset (to either unicode or ansi) and setting a EntryPoint (either PathGetArgsA or PathGetArgsW). This code works fine in v3.5 but not in v4.
[DllImport("Shlwapi.dll", SetLastError = true, CharSet = CharSet.Auto)] public static extern string PathGetArgs([In] string path);
[DllImport("Shlwapi.dll", SetLastError = true, CharSet = CharSet.Auto)] public static extern void PathRemoveArgs([In, Out] StringBuilder path);
public static bool ExtractArguments(string cmdLine, out string filePath, out string fileArgs)
{
StringBuilder strCmdLine = new StringBuilder(cmdLine.ToLower().Trim());
filePath = fileArgs = "";
if (strCmdLine.Length <= 0)
throw new ArgumentNullException("cmdLine");
fileArgs = string.Copy(PathGetArgs(strCmdLine.ToString())); // Error occurs here
PathRemoveArgs(strCmdLine);
filePath = string.Copy(strCmdLine.ToString());
if (!string.IsNullOrEmpty(filePath))
if (Utils.FileExists(filePath))
return true;
return false;
}
Thanks!
I'm not sure what the native dll retuns in the PathGetArgs however, the Marshal Class could help.
[DllImport("Shlwapi.dll")]
public static extern IntPtr PathGetArgs([In] string path);
fileArgs = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(PathGetArgs(strCmdLine.ToString()));
1.)
How do Load, Edit and Save binary Hive files for registry from C#?
I found this Win32 api.
http://msdn.microsoft.com/en-us/library/ee210770%28VS.85%29.aspx
This guy shared the code to dump the content of binary Hive files to text.
http://www.codeproject.com/KB/recipes/RegistryDumper.aspx
2.)
In addition to manipulating the Hive files, I also search for a method to load the Hive file into registry at runtime using C#
(similar to the Load Hive and Unload Hive commands on the File many in regedit)
/Thanks
Have you looked at the Registry and RegistryKey classes in Microsoft.Win32?
http://msdn.microsoft.com/en-us/library/microsoft.win32.aspx
It sounds like you may need to create your own representation to read the hive file and either queue up or immediately make the corresponding registry changes. Likewise you would need to write your own converter back to disk.
The article below explains how to analyze the registry file without using WinAPI (advapi32.dll). In this particular case the guy is using Mono:
http://volatile-minds.blogspot.com/2011/01/analyzing-windows-nt-registry-without.html
using (FileStream fs = File.OpenRead (path)) {
var data = new byte[checked((int)fs.Length)];
int i = 0;
int read;
using (var ms = new MemoryStream (checked((int)fs.Length))) {
while ((read = fs.Read (data, 0, data.Length)) > 0) {
ms.Write (data, 0, read);
i += read;
}
byte[] hive = ms.ToArray ();
char[] cList = new char[fs.Length];
i = 0;
foreach (byte b in hive)
cList[i++] = (char)b;
string d = new string (cList);
int all = 0;
foreach (Match mx in lf.Matches (d)) { //you can change out the regex you want here.
byte[] bb = new byte[mx.Value.Length];
char[] cb = new char[mx.Value.Length];
for (int k = 0; k < mx.Value.Length; k++) {
bb[k] = (byte)mx.Value[k];
cb[k] = (char)bb[k];
}
all++;
//Console.WriteLine (new string (cb));
}
Console.WriteLine (all.ToString ());
all = 0;
}
}
This is 9 years old, but I figured this could help someone else. I wrote this class that allows you to do something like this:
Hive.AcquirePrivileges() // Acquires the privileges necessary for loading the hive
Hive myregistryhive = Hive.LoadFromFile("hivepathhere") // Loads the hive
// use myregistryhive.RootKey (a RegistryKey), read and/or write to it and its sub keys
myregistryhive.SaveAndUnload() // Unloads the hive
Hive.ReturnPrivileges() // De-elevate back to normal privileges.
The code for the class:
class Hive
{
[DllImport("advapi32.dll", SetLastError = true)]
static extern int RegLoadKey(IntPtr hKey, string lpSubKey, string lpFile);
[DllImport("advapi32.dll", SetLastError = true)]
static extern int RegSaveKey(IntPtr hKey, string lpFile, uint securityAttrPtr = 0);
[DllImport("advapi32.dll", SetLastError = true)]
static extern int RegUnLoadKey(IntPtr hKey, string lpSubKey);
[DllImport("ntdll.dll", SetLastError = true)]
static extern IntPtr RtlAdjustPrivilege(int Privilege, bool bEnablePrivilege, bool IsThreadPrivilege, out bool PreviousValue);
[DllImport("advapi32.dll")]
static extern bool LookupPrivilegeValue(string lpSystemName, string lpName, ref UInt64 lpLuid);
[DllImport("advapi32.dll")]
static extern bool LookupPrivilegeValue(IntPtr lpSystemName, string lpName, ref UInt64 lpLuid);
private RegistryKey parentKey;
private string name;
private string originalPath;
public RegistryKey RootKey;
private Hive() { }
public static Hive LoadFromFile(string Path)
{
Hive result = new Hive();
result.parentKey = RegistryKey.OpenBaseKey(RegistryHive.Users, RegistryView.Default);
result.name = Guid.NewGuid().ToString();
result.originalPath = Path;
IntPtr parentHandle = result.parentKey.Handle.DangerousGetHandle();
RegLoadKey(parentHandle, result.name, Path);
//Console.WriteLine(Marshal.GetLastWin32Error());
result.RootKey = result.parentKey.OpenSubKey(result.name, true);
return result;
}
public static void AcquirePrivileges()
{
ulong luid = 0;
bool throwaway;
LookupPrivilegeValue(IntPtr.Zero, "SeRestorePrivilege", ref luid);
RtlAdjustPrivilege((int)luid, true, false, out throwaway);
LookupPrivilegeValue(IntPtr.Zero, "SeBackupPrivilege", ref luid);
RtlAdjustPrivilege((int)luid, true, false, out throwaway);
}
public static void ReturnPrivileges()
{
ulong luid = 0;
bool throwaway;
LookupPrivilegeValue(IntPtr.Zero, "SeRestorePrivilege", ref luid);
RtlAdjustPrivilege((int)luid, false, false, out throwaway);
LookupPrivilegeValue(IntPtr.Zero, "SeBackupPrivilege", ref luid);
RtlAdjustPrivilege((int)luid, false, false, out throwaway);
}
public void SaveAndUnload()
{
RootKey.Close();
RegUnLoadKey(parentKey.Handle.DangerousGetHandle(), name);
parentKey.Close();
}
}
Edit: Note that this requires administrator privileges.
please see: https://github.com/brandonprry/volatile_reader
It reads offline hives in C# with a GTK interface. No write support yet though.