I have a very old VB6 code that is used to generate the hash for the password. The code uses CryptAcquireContext function along with advapi32.dll to generate the Hash. There is so much code with variables having hex values etc. The code will take forever to migrate to ASP.NET.
We have lots of data encrypted using this Hash code and we don't have a way to decrypt it back to plain text.
I need to write similar code in ASP.NET C# that generates the same hash as the VB6 code does.
Example: Look at the picture below on how it generates HASH from plaintext:
Working C# Code in Windows forms only with exception that CryptAcquireContext returns false when the program is run second time:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Security;
using System.Web;
using System.Security.Cryptography;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace CryptoGraphicHash
{
public partial class Form1 : Form
{
static uint CRYPT_NEWKEYSET = 0x8;
static uint CRYPT_MACHINE_KEYSET = 0x20;
static uint ALG_CLASS_HASH = 32768;
// Algorithm types
static uint ALG_TYPE_ANY = 0;
static uint PROV_RSA_FULL = 1;
static uint ALG_SID_SHA = 4;
static string MS_DEF_PROV = "Microsoft Base Cryptographic Provider v1.0";
static uint CALG_SHA = ALG_CLASS_HASH + ALG_TYPE_ANY + ALG_SID_SHA;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var test = GenerateHash(textBox1.Text);
textBox2.Text = test;
}
private string GenerateHash(string plaintext)
{
string sContainer = string.Empty;
string sProvider = MS_DEF_PROV;
IntPtr hProv = new IntPtr();
IntPtr hKey = new IntPtr(0);
IntPtr phHash = new IntPtr();
try
{
bool res = Crypt32.CryptAcquireContext(out hProv, sContainer, sProvider, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET);
if (!res)
{
bool res1 = Crypt32.CryptAcquireContext(out hProv, sContainer, sProvider, PROV_RSA_FULL, CRYPT_NEWKEYSET);
if (!res1)
{
MessageBox.Show("CryptAcquireContext is false for second time so exiting the hash.");
var error = Marshal.GetLastWin32Error();
Win32Exception test = new Win32Exception(error);
MessageBox.Show("Last Win32 error code: " + error);
MessageBox.Show("Last Win32 error msg: " + test.Message);
return string.Empty;
}
}
MessageBox.Show("hProv handle value is: " + hProv.ToString());
//Once we have received the context, next we create hash object
bool hashCreateResponse = Crypt32.CryptCreateHash(hProv, CALG_SHA, hKey, 0, ref phHash);
if (!hashCreateResponse)
{
MessageBox.Show("CryptCreateHash is false so exiting with last win32 error: " + Marshal.GetLastWin32Error());
return string.Empty;
}
//Hash the data
byte[] pbData = Encoding.ASCII.GetBytes(plaintext);
bool hashDataResponse = Crypt32.CryptHashData(phHash, pbData, (uint)plaintext.Length, 0);
if (!hashDataResponse)
{
MessageBox.Show("CryptHashData is false so exiting.");
return string.Empty;
}
uint paramLen = 0;
byte[] paramValue = new byte[0];
bool getHashParamResponse = Crypt32.CryptGetHashParam(phHash, 0x0002, paramValue, ref paramLen, 0);
if (234 == Marshal.GetLastWin32Error())
{
paramValue = new byte[paramLen];
bool getHashParamResponse1 = Crypt32.CryptGetHashParam(phHash, 0x0002, paramValue, ref paramLen, 0);
}
//destroy the key
Crypt32.CryptDestroyKey(hKey);
//Destroy the hash object
Crypt32.CryptDestroyHash(phHash);
//Release provider handle
Crypt32.CryptReleaseContext(hProv, 0);
var sb = new StringBuilder();
foreach(var item in paramValue)
{
sb.Append(Microsoft.VisualBasic.Strings.Chr(item));
}
return sb.ToString();
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
MessageBox.Show(ex.InnerException.StackTrace);
throw ex;
}
}
}
public class Crypt32
{
public enum HashParameters
{
HP_ALGID = 0x0001, // Hash algorithm
HP_HASHVAL = 0x2, // Hash value
HP_HASHSIZE = 0x0004 // Hash value size
}
[DllImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptAcquireContext(
out IntPtr phProv,
string pszContainer,
string pszProvider,
uint dwProvType,
uint dwFlags);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool CryptCreateHash(IntPtr hProv, uint algId, IntPtr hKey, uint dwFlags, ref IntPtr phHash);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool CryptDestroyHash(IntPtr hHash);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool CryptDestroyKey(IntPtr phKey);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool CryptHashData(IntPtr hHash, byte[] pbData, uint dataLen, uint flags);
[DllImport("Advapi32.dll", EntryPoint = "CryptReleaseContext", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool CryptReleaseContext(IntPtr hProv,Int32 dwFlags);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool CryptGetHashParam(IntPtr hHash,
uint dwParam,
Byte[] pbData,
ref uint pdwDataLen,
uint dwFlags);
//public static extern bool CryptGetHashParam(IntPtr hHash, uint dwParam, [Out] byte[] pbData, [In, Out] uint pdwDataLen, uint dwFlags);
}
}
You might consider using Platform Invoke Services (PInvoke) to call advapi32.dll functions from .NET. This might speed up the migration process.
You can find signatures on http://pinvoke.net
So finally with help of Joe's suggestion, PInvoke documentation and some code tweaks found on stack over flow, I was able to create a successful working windows form application that has 2 textboxes and a button. Enter plaintext in first textbox and click the button to get hash value in the second textbox. The complete code is:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Security;
using System.Web;
using System.Security.Cryptography;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace CryptoGraphicHash
{
public partial class Form1 : Form
{
static uint CRYPT_NEWKEYSET = 0x8;
static uint CRYPT_MACHINE_KEYSET = 0x20;
static uint ALG_CLASS_HASH = 32768;
// Algorithm types
static uint ALG_TYPE_ANY = 0;
static uint PROV_RSA_FULL = 1;
static uint ALG_SID_SHA = 4;
static string MS_DEF_PROV = "Microsoft Base Cryptographic Provider v1.0";
static uint CALG_SHA = ALG_CLASS_HASH + ALG_TYPE_ANY + ALG_SID_SHA;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var test = GenerateHash(textBox1.Text);
textBox2.Text = test;
}
private void HandleWin32Error()
{
var error = Marshal.GetLastWin32Error();
Win32Exception ex = new Win32Exception(error);
MessageBox.Show("Last Win32 error code: " + error);
MessageBox.Show("Last Win32 error msg: " + ex.Message);
}
private string GenerateHash(string plaintext)
{
string sContainer = string.Empty;
string sProvider = MS_DEF_PROV;
IntPtr hProv = new IntPtr();
IntPtr hKey = new IntPtr(0);
IntPtr phHash = new IntPtr();
try
{
bool res = Crypt32.CryptAcquireContext(out hProv, sContainer, sProvider, PROV_RSA_FULL, 0);
if (!res)
{
MessageBox.Show("CryptAcquireContext is false for first time so will try again with CRYPT_NEWKEYSET.");
HandleWin32Error();
bool res1 = Crypt32.CryptAcquireContext(out hProv, sContainer, sProvider, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET + CRYPT_NEWKEYSET);
if (!res1)
{
MessageBox.Show("CryptAcquireContext is false for second time so exiting the hash.");
HandleWin32Error();
return string.Empty;
}
}
MessageBox.Show("hProv handle value is: " + hProv.ToString());
//Once we have received the context, next we create hash object
bool hashCreateResponse = Crypt32.CryptCreateHash(hProv, CALG_SHA, hKey, 0, ref phHash);
if (!hashCreateResponse)
{
MessageBox.Show("CryptCreateHash is false so exiting with last win32 error: " + Marshal.GetLastWin32Error());
return string.Empty;
}
//Hash the data
byte[] pbData = Encoding.ASCII.GetBytes(plaintext);
bool hashDataResponse = Crypt32.CryptHashData(phHash, pbData, (uint)plaintext.Length, 0);
if (!hashDataResponse)
{
MessageBox.Show("CryptHashData is false so exiting.");
return string.Empty;
}
uint paramLen = 0;
byte[] paramValue = new byte[0];
bool getHashParamResponse = Crypt32.CryptGetHashParam(phHash, 0x0002, paramValue, ref paramLen, 0);
if (234 == Marshal.GetLastWin32Error())
{
paramValue = new byte[paramLen];
bool getHashParamResponse1 = Crypt32.CryptGetHashParam(phHash, 0x0002, paramValue, ref paramLen, 0);
}
//destroy the key
Crypt32.CryptDestroyKey(hKey);
//Destroy the hash object
Crypt32.CryptDestroyHash(phHash);
//Release provider handle
Crypt32.CryptReleaseContext(hProv, 0);
var sb = new StringBuilder();
foreach(var item in paramValue)
{
sb.Append(Microsoft.VisualBasic.Strings.Chr(item));
}
return sb.ToString();
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
MessageBox.Show(ex.InnerException.StackTrace);
throw ex;
}
}
}
public class Crypt32
{
public enum HashParameters
{
HP_ALGID = 0x0001, // Hash algorithm
HP_HASHVAL = 0x2, // Hash value
HP_HASHSIZE = 0x0004 // Hash value size
}
[DllImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptAcquireContext(
out IntPtr phProv,
string pszContainer,
string pszProvider,
uint dwProvType,
uint dwFlags);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool CryptCreateHash(IntPtr hProv, uint algId, IntPtr hKey, uint dwFlags, ref IntPtr phHash);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool CryptDestroyHash(IntPtr hHash);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool CryptDestroyKey(IntPtr phKey);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool CryptHashData(IntPtr hHash, byte[] pbData, uint dataLen, uint flags);
[DllImport("Advapi32.dll", EntryPoint = "CryptReleaseContext", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool CryptReleaseContext(IntPtr hProv,Int32 dwFlags);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool CryptGetHashParam(IntPtr hHash,
uint dwParam,
Byte[] pbData,
ref uint pdwDataLen,
uint dwFlags);
//public static extern bool CryptGetHashParam(IntPtr hHash, uint dwParam, [Out] byte[] pbData, [In, Out] uint pdwDataLen, uint dwFlags);
}
}
Related
I'm creating a windows service app in visual studio and I want to get the currently active window title.
below is the code I have tried but the function GetForegroundWindow() returns 0 every time.
Is it okay to use win32api in windows services?
public partial class My_Service: ServiceBase
{
Timer timer = new Timer();
[DllImport("User32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("User32.dll")]
static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
public My_Service()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
WriteToFile("Service is started at " + DateTime.Now);
timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);
timer.Interval = 10000; //number in milisecinds
timer.Enabled = true;
}
protected override void OnStop()
{
WriteToFile("Service is stopped at " + DateTime.Now);
}
private void OnElapsedTime(object source, ElapsedEventArgs e)
{
string title = GetActivewindow();
WriteToFile("Service is recall at " + title + DateTime.Now);
}
public void WriteToFile(string Message)
{
....
}
public string GetActivewindow()
{
const int nChars = 256;
StringBuilder buff = new StringBuilder(nChars);
string title = "- ";
IntPtr handle;
handle = GetForegroundWindow();
if( GetWindowText(handle,buff,nChars) > 0)
{
title = buff.ToString();
}
return title;
}
}
As comments, and also according to the document: About Window Stations and Desktops - Window Station and Desktop Creation.
Your service may be running under Service-0x0-3e7$\default, but the foreground window you want to retrieve is in the default desktop of the interactive window station (Winsta0\default)
The interactive window station is the only window station that can
display a user interface or receive user input. It is assigned to the
logon session of the interactive user, and contains the keyboard,
mouse, and display device. It is always named "WinSta0". All other
window stations are noninteractive, which means they cannot display a
user interface or receive user input.
That means you cannot use GetForegroundWindow directly from the service. You could create a child process in Winsta0\default and redirect its output. Then call GetForegroundWindow in the child process and output.
Sample(removed error checking):
Child:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.IO;
using System.Threading;
namespace ConsoleApp1
{
class Program
{
[DllImport("User32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("User32.dll")]
static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
static void Main(string[] args)
{
const int nChars = 256;
StringBuilder buff = new StringBuilder(nChars);
string title = "- ";
IntPtr handle;
handle = GetForegroundWindow();
if (GetWindowText(handle, buff, nChars) > 0)
{
title = buff.ToString();
}
Console.WriteLine(title);
return;
}
}
}
Service:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.IO;
using System.Diagnostics.Tracing;
namespace WindowsService3
{
public partial class MyNewService : ServiceBase
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct STARTUPINFO
{
public Int32 cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public Int32 dwX;
public Int32 dwY;
public Int32 dwXSize;
public Int32 dwYSize;
public Int32 dwXCountChars;
public Int32 dwYCountChars;
public Int32 dwFillAttribute;
public Int32 dwFlags;
public Int16 wShowWindow;
public Int16 cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public Int32 dwProcessId;
public Int32 dwThreadId;
}
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public int nLength;
public IntPtr lpSecurityDescriptor;
public int bInheritHandle;
}
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool CreateProcessAsUser(
IntPtr hToken,
string lpApplicationName,
string lpCommandLine,
IntPtr lpProcessAttributes,
IntPtr lpThreadAttributes,
bool bInheritHandles,
uint dwCreationFlags,
IntPtr lpEnvironment,
IntPtr lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool CreatePipe(
ref IntPtr hReadPipe,
ref IntPtr hWritePipe,
ref SECURITY_ATTRIBUTES lpPipeAttributes,
uint nSize);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool ReadFile(
IntPtr hFile,
byte[] lpBuffer,
uint nNumberOfBytesToRead,
out uint lpNumberOfBytesRead,
IntPtr lpOverlapped);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern uint WTSGetActiveConsoleSessionId();
[DllImport("Wtsapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool WTSQueryUserToken(UInt32 SessionId, out IntPtr hToken);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern uint WaitForSingleObject(IntPtr hProcess, uint dwMilliseconds);
public MyNewService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
System.Diagnostics.Debugger.Launch();
using (StreamWriter sw = File.CreateText("Path\\Log.txt"))
{
IntPtr read = new IntPtr();
IntPtr write = new IntPtr();
IntPtr read2 = new IntPtr();
IntPtr write2 = new IntPtr();
SECURITY_ATTRIBUTES saAttr = new SECURITY_ATTRIBUTES();
saAttr.nLength = Marshal.SizeOf(typeof(SECURITY_ATTRIBUTES));
saAttr.bInheritHandle = 1;
saAttr.lpSecurityDescriptor = IntPtr.Zero;
CreatePipe(ref read, ref write, ref saAttr, 0);
CreatePipe(ref read2, ref write2, ref saAttr, 0);
uint CREATE_NO_WINDOW = 0x08000000;
int STARTF_USESTDHANDLES = 0x00000100;
STARTUPINFO si = new STARTUPINFO();
si.cb = Marshal.SizeOf(typeof(STARTUPINFO));
si.hStdOutput = write;
si.hStdError = write;
si.hStdInput = read2;
si.lpDesktop = "Winsta0\\default";
si.dwFlags = STARTF_USESTDHANDLES;
PROCESS_INFORMATION pi;
IntPtr hToken;
bool err = WTSQueryUserToken(WTSGetActiveConsoleSessionId(), out hToken);
string path = "Path\\ConsoleApp1.exe";
if (CreateProcessAsUser(hToken, path, null, IntPtr.Zero, IntPtr.Zero, true, CREATE_NO_WINDOW, IntPtr.Zero, IntPtr.Zero, ref si, out pi))
{
uint ret = WaitForSingleObject(pi.hProcess, 2000); //wait for the child process exit.
if (ret == 0)
{
byte[] title = new byte[200];
uint reads = 0;
CloseHandle(write);
err = ReadFile(read, title, 200, out reads, IntPtr.Zero);
string result = System.Text.Encoding.UTF8.GetString(title).Replace("\0","").Replace("\r", "").Replace("\n", "");
sw.WriteLine(result);
}
}
CloseHandle(read2);
CloseHandle(write2);
CloseHandle(read);
}
}
protected override void OnStop()
{
}
}
}
I've been trying to set the user and password for the IE proxies for a while without having good results, I try with WebProxy, WebClient and now i'm trying with InternetSetOption from Wininnet.dll, the idea behind this is to avoid the input of the user and password each time a user open a browser. Here is the code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Principal;
using System.Runtime.InteropServices;
using System.Net;
using System.ComponentModel;
namespace Proxy.Core
{
public class ProxyImpersonator
{
private const int INTERNET_OPTION_PROXY_USERNAME = 43;
private const int INTERNET_OPTION_PROXY_PASSWORD = 44;
private const int INTERNET_OPEN_TYPE_PRECONFIG = 0; // use registry configuration
private const int INTERNET_OPEN_TYPE_DIRECT = 1; // direct to net
private const int INTERNET_OPEN_TYPE_PROXY = 3; // via named proxy
private const int INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY = 4; // prevent using java/script/INS
[DllImport("wininet.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool InternetSetOption(IntPtr hInternet, int
dwOption, string lpBuffer, int dwBufferLength);
[DllImport("wininet.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern IntPtr InternetConnect(
IntPtr hInternet, string lpszServerName, short nServerPort,
string lpszUsername, string lpszPassword, int dwService,
int dwFlags, IntPtr dwContext);
[DllImport("wininet.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern IntPtr InternetOpen(
string lpszAgent, int dwAccessType, string lpszProxyName,
string lpszProxyBypass, int dwFlags);
public static void Impersonate(Proxy Config)
{
IntPtr hOpen = InternetOpen("Proxy Connection", INTERNET_OPEN_TYPE_PROXY,Config.Address.ToString(),String.Empty, 0);
IntPtr hInternet = InternetConnect(hOpen, Config.Address.URL, short.Parse(Config.Address.Port.ToString()), Config.UserID, Config.UserPwd, 3, 0, IntPtr.Zero);
if (!InternetSetOption(hInternet,INTERNET_OPTION_PROXY_USERNAME,Config.UserID,Config.UserID.Length+1))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
if (!InternetSetOption(hInternet, INTERNET_OPTION_PROXY_PASSWORD, Config.UserPwd, Config.UserPwd.Length + 1))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
}
}
I would like to add a string resource to an executable file programmatically. Just for example purposes, let's say I am trying to add a string named "String SO" which holds the value of "stringVal"
If this helps anyone - if I were to do this through VS.net I could just right click on my Project => Resources => Add New String Resource etc..
I am using the following Win32 API's:
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr BeginUpdateResource(string pFileName,
[MarshalAs(UnmanagedType.Bool)]bool bDeleteExistingResources);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool UpdateResource(IntPtr hUpdate, uint lpType, uint lpName, ushort wLanguage, byte[] lpData, uint cbData);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool EndUpdateResource(IntPtr hUpdate, bool fDiscard);
So, I have found a couple of pages online but none of them seem to help me in what I am trying to do. If any of you are able to find anything I would be very grateful.
Otherwise, I would greatly appreciate any snippets that may help.
Thank you,
Evan
There is a very helpful library for many resource-tasks at github.
Many classes and function do wrap those window-api-calls around UpdateResource(...), etc.
Hope that helps.
I'm injecting an application byte[] as a resource to execute it on runtime. Here's my piece of code, hope it helps:
class AddResource
{
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool UpdateResource(IntPtr hUpdate, string lpType, string lpName, ushort wLanguage, IntPtr lpData, uint cbData);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr BeginUpdateResource(string pFileName,
[MarshalAs(UnmanagedType.Bool)]bool bDeleteExistingResources);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool EndUpdateResource(IntPtr hUpdate, bool fDiscard);
private static IntPtr ToPtr(object data)
{
GCHandle h = GCHandle.Alloc(data, GCHandleType.Pinned);
IntPtr ptr;
try
{
ptr = h.AddrOfPinnedObject();
}
finally
{
h.Free();
}
return ptr;
}
public static bool InjectResource(string filename, byte[] bytes, string resourceName)
{
try
{
IntPtr handle = BeginUpdateResource(filename, false);
byte[] file1 = bytes;
IntPtr fileptr = ToPtr(file1);
bool res = UpdateResource(handle, resourceName,
//"RT_RCDATA",
"0", 0, fileptr, Convert.ToUInt32(file1.Length));
EndUpdateResource(handle, false);
}
catch
{
return false;
}
return true;
}
public static void CopyStream(Stream input, Stream output,long sz)
{
// Insert null checking here for production
byte[] buffer = new byte[sz];
int bytesRead;
while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write(buffer, 0, bytesRead);
}
}
}
Here is how I use it:
using (Stream input = Assembly.GetExecutingAssembly().GetManifestResourceStream("AppLicensing.Resources.SAppStarter.exe"))
using (Stream output = File.Create(outputFilePath))
{
long sz = input.Length;
AddResource.CopyStream(input, output, sz);
}
//inject crypted bytes
AddResource.InjectResource(outputFilePath, Encryptor.cryptedbytes, "RT_RCDATA");
And here is how I extract the resource (notice the "RT_RCDATA" -> that s the name of the resource):
class ReadResource
{
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr FindResource(IntPtr hModule, string lpName, string lpType);
[DllImport("Kernel32.dll", EntryPoint = "SizeofResource", SetLastError = true)]
private static extern uint SizeofResource(IntPtr hModule, IntPtr hResource);
[DllImport("Kernel32.dll", EntryPoint = "LoadResource", SetLastError = true)]
private static extern IntPtr LoadResource(IntPtr hModule, IntPtr hResource);
public static byte[] GetFromResource(String resourceName)
{
try
{
IntPtr hModule = GetModuleHandle(System.Diagnostics.Process.GetCurrentProcess().MainModule.ModuleName);
IntPtr loc = FindResource(hModule, "0", resourceName);
uint size = SizeofResource(hModule, loc);
IntPtr x = LoadResource(hModule, loc);
byte[] bPtr = new byte[size];
Marshal.Copy(x, bPtr, 0, (int)(size));
return bPtr;
}
catch (Exception e)
{
System.Windows.Forms.MessageBox.Show(e.ToString());
System.Environment.Exit(0);
return null;
}
}
}
byte[] encryptedData = ReadResource.GetFromResource("RT_RCDATA");
The code gets a bit messy... hope this helps.
Although the author is dealing with his own issue right now, the SO question UpdateResource function fails has code snippet for using these calls.
The code from Samson work with String lpType, that mean you can't actually add RT_RCDATA resource either reading from it, it's only create and read lpType named "RT_RCDATA" only. If you want it to read real RT data you'll need to modify lpType from string to uint and this is RT API table:
private const uint RT_CURSOR = 0x00000001;
private const uint RT_BITMAP = 0x00000002;
private const uint RT_ICON = 0x00000003;
private const uint RT_MENU = 0x00000004;
private const uint RT_DIALOG = 0x00000005;
private const uint RT_STRING = 0x00000006;
private const uint RT_FONTDIR = 0x00000007;
private const uint RT_FONT = 0x00000008;
private const uint RT_ACCELERATOR = 0x00000009;
private const uint RT_RCDATA = 0x0000000a;
private const uint RT_MESSAGETABLE = 0x0000000b;
Trying to start process with another access token, without success, it runs as the non-impersonated user.
using (WindowsIdentity identity = new WindowsIdentity(token))
using (identity.Impersonate())
{
Process.Start("blabla.txt");
}
How to make this work properly?
You need to set the ProcessStartInfo.UserName and Password properties. With UseShellExecute set to false. If you only have a token then pinvoke CreateProcessAsUser().
Try this example from http://msdn.microsoft.com/en-us/library/w070t6ka.aspx
private static void ImpersonateIdentity(IntPtr logonToken)
{
// Retrieve the Windows identity using the specified token.
WindowsIdentity windowsIdentity = new WindowsIdentity(logonToken);
// Create a WindowsImpersonationContext object by impersonating the
// Windows identity.
WindowsImpersonationContext impersonationContext =
windowsIdentity.Impersonate();
Console.WriteLine("Name of the identity after impersonation: "
+ WindowsIdentity.GetCurrent().Name + ".");
//Start your process here
Process.Start("blabla.txt");
Console.WriteLine(windowsIdentity.ImpersonationLevel);
// Stop impersonating the user.
impersonationContext.Undo();
// Check the identity name.
Console.Write("Name of the identity after performing an Undo on the");
Console.WriteLine(" impersonation: " +
WindowsIdentity.GetCurrent().Name);
}
You can also use CreateProcessAsUser windows function.
http://www.pinvoke.net/default.aspx/advapi32/createprocessasuser.html
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.Common;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Security.Principal;
using System.Security.Permissions;
using Microsoft.Win32.SafeHandles;
using System.Runtime.ConstrainedExecution;
using System.ComponentModel;
public static class ImpersonationUtils
{
private const int SW_SHOW = 5;
private const int TOKEN_QUERY = 0x0008;
private const int TOKEN_DUPLICATE = 0x0002;
private const int TOKEN_ASSIGN_PRIMARY = 0x0001;
private const int STARTF_USESHOWWINDOW = 0x00000001;
private const int STARTF_FORCEONFEEDBACK = 0x00000040;
private const int CREATE_UNICODE_ENVIRONMENT = 0x00000400;
private const int TOKEN_IMPERSONATE = 0x0004;
private const int TOKEN_QUERY_SOURCE = 0x0010;
private const int TOKEN_ADJUST_PRIVILEGES = 0x0020;
private const int TOKEN_ADJUST_GROUPS = 0x0040;
private const int TOKEN_ADJUST_DEFAULT = 0x0080;
private const int TOKEN_ADJUST_SESSIONID = 0x0100;
private const int STANDARD_RIGHTS_REQUIRED = 0x000F0000;
private const int TOKEN_ALL_ACCESS =
STANDARD_RIGHTS_REQUIRED |
TOKEN_ASSIGN_PRIMARY |
TOKEN_DUPLICATE |
TOKEN_IMPERSONATE |
TOKEN_QUERY |
TOKEN_QUERY_SOURCE |
TOKEN_ADJUST_PRIVILEGES |
TOKEN_ADJUST_GROUPS |
TOKEN_ADJUST_DEFAULT |
TOKEN_ADJUST_SESSIONID;
[StructLayout(LayoutKind.Sequential)]
private struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
}
[StructLayout(LayoutKind.Sequential)]
private struct SECURITY_ATTRIBUTES
{
public int nLength;
public IntPtr lpSecurityDescriptor;
public bool bInheritHandle;
}
[StructLayout(LayoutKind.Sequential)]
private struct STARTUPINFO
{
public int cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public int dwX;
public int dwY;
public int dwXSize;
public int dwYSize;
public int dwXCountChars;
public int dwYCountChars;
public int dwFillAttribute;
public int dwFlags;
public short wShowWindow;
public short cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
private enum SECURITY_IMPERSONATION_LEVEL
{
SecurityAnonymous,
SecurityIdentification,
SecurityImpersonation,
SecurityDelegation
}
private enum TOKEN_TYPE
{
TokenPrimary = 1,
TokenImpersonation
}
enum LogonTypes : uint
{
Interactive = 2,
Network = 3,
Batch = 4,
Service = 5,
NetworkCleartext = 8,
NewCredentials = 9
}
enum LogonProvider
{
LOGON32_PROVIDER_DEFAULT = 0,
LOGON32_PROVIDER_WINNT35 = 1,
LOGON32_PROVIDER_WINNT40 = 2,
LOGON32_PROVIDER_WINNT50 = 3
}
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool CreateProcessAsUser(
IntPtr hToken,
string lpApplicationName,
string lpCommandLine,
ref SECURITY_ATTRIBUTES lpProcessAttributes,
ref SECURITY_ATTRIBUTES lpThreadAttributes,
bool bInheritHandles,
int dwCreationFlags,
IntPtr lpEnvironment,
string lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool DuplicateTokenEx(
IntPtr hExistingToken,
int dwDesiredAccess,
ref SECURITY_ATTRIBUTES lpThreadAttributes,
int ImpersonationLevel,
int dwTokenType,
ref IntPtr phNewToken);
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool OpenProcessToken(
IntPtr ProcessHandle,
int DesiredAccess,
ref IntPtr TokenHandle);
[DllImport("userenv.dll", SetLastError = true)]
private static extern bool CreateEnvironmentBlock(
ref IntPtr lpEnvironment,
IntPtr hToken,
bool bInherit);
[DllImport("userenv.dll", SetLastError = true)]
private static extern bool DestroyEnvironmentBlock(
IntPtr lpEnvironment);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool CloseHandle(
IntPtr hObject);
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken);
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
public static void LaunchProcessAsUser(string cmdLine, IntPtr token, IntPtr envBlock, int sessionId)
{
var pi = new PROCESS_INFORMATION();
var saProcess = new SECURITY_ATTRIBUTES();
var saThread = new SECURITY_ATTRIBUTES();
saProcess.nLength = Marshal.SizeOf(saProcess);
saThread.nLength = Marshal.SizeOf(saThread);
var si = new STARTUPINFO();
si.cb = Marshal.SizeOf(si);
si.lpDesktop = #"WinSta0\Default";
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_FORCEONFEEDBACK;
si.wShowWindow = SW_SHOW;
if (!CreateProcessAsUser(
token,
null,
cmdLine,
ref saProcess,
ref saThread,
false,
CREATE_UNICODE_ENVIRONMENT,
envBlock,
null,
ref si,
out pi))
{
throw new Win32Exception(Marshal.GetLastWin32Error(), "CreateProcessAsUser En Echec");
}
}
private static IDisposable Impersonate(IntPtr token)
{
var identity = new WindowsIdentity(token);
return identity.Impersonate();
}
private static IntPtr GetPrimaryToken(Process process)
{
var token = IntPtr.Zero;
var primaryToken = IntPtr.Zero;
if (OpenProcessToken(process.Handle, TOKEN_DUPLICATE, ref token))
{
var sa = new SECURITY_ATTRIBUTES();
sa.nLength = Marshal.SizeOf(sa);
if (!DuplicateTokenEx(
token,
TOKEN_ALL_ACCESS,
ref sa,
(int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation,
(int)TOKEN_TYPE.TokenPrimary,
ref primaryToken))
{
throw new Win32Exception(Marshal.GetLastWin32Error(), "DuplicateTokenEx failed");
}
CloseHandle(token);
}
else
{
throw new Win32Exception(Marshal.GetLastWin32Error(), "OpenProcessToken failed");
}
return primaryToken;
}
public static IntPtr GetEnvironmentBlock(IntPtr token)
{
var envBlock = IntPtr.Zero;
if (!CreateEnvironmentBlock(ref envBlock, token, false))
{
throw new Win32Exception(Marshal.GetLastWin32Error(), "CreateEnvironmentBlock failed");
}
return envBlock;
}
public static void LaunchAsCurrentUser(string cmdLine)
{
var process = Process.GetProcessesByName("explorer").FirstOrDefault();
if (process != null)
{
var token = GetPrimaryToken(process);
if (token != IntPtr.Zero)
{
var envBlock = GetEnvironmentBlock(token);
if (envBlock != IntPtr.Zero)
{
LaunchProcessAsUser(cmdLine, token, envBlock, process.SessionId);
if (!DestroyEnvironmentBlock(envBlock))
{
throw new Win32Exception(Marshal.GetLastWin32Error(), "DestroyEnvironmentBlock failed");
}
}
CloseHandle(token);
}
}
}
//Methode de lancement de commande impersonatée avec un user typé Domain
public static void LaunchAsDomainUser(string cmdLine, String UserName, String Password, String Domain)
{
SafeTokenHandle safeTokenHandle;
bool returnValue = LogonUser(UserName, Domain, Password,
(int)LogonTypes.Interactive, (int)LogonProvider.LOGON32_PROVIDER_DEFAULT,
out safeTokenHandle);
using (WindowsIdentity newId = new WindowsIdentity(safeTokenHandle.DangerousGetHandle()))
{
using (WindowsImpersonationContext impersonatedUser = newId.Impersonate())
{
LaunchAsCurrentUser(cmdLine);
}
}
}
//Methode de lancement de commande impersonatée avec un user typé Local
public static void LaunchAsLocalUser(string cmdLine, String UserName, String Password)
{
var envBlock = IntPtr.Zero;
var token = IntPtr.Zero;
bool returnValue = LogonUser(UserName, ".", Password,
(int)LogonTypes.Batch, (int)LogonProvider.LOGON32_PROVIDER_DEFAULT,
ref token);
envBlock = ImpersonationUtils.GetEnvironmentBlock(token);
var process = Process.GetProcessesByName("explorer").FirstOrDefault();
LaunchProcessAsUser(cmdLine, token, envBlock, process.SessionId);
CloseHandle(token);
}
//Classe de génération de handle typé SafeTokenHandle
public sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
{
private SafeTokenHandle()
: base(true)
{
}
[DllImport("kernel32.dll")]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[SuppressUnmanagedCodeSecurity]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle(IntPtr handle);
protected override bool ReleaseHandle()
{
return CloseHandle(handle);
}
}
public static IDisposable ImpersonateCurrentUser()
{
var process = Process.GetProcessesByName("explorer").FirstOrDefault();
if (process != null)
{
var token = GetPrimaryToken(process);
if (token != IntPtr.Zero)
{
return Impersonate(token);
}
}
throw new Exception("Could not find explorer.exe");
}
}
After this, from your page code, you can run :
For Domain accounts :
ImpersonationUtils.LaunchAsDomainUser("BlaBla cmd code", UserName, Password, Domain);
For Local Accounts :
ImpersonationUtils.LaunchAsLocalUser("BlaBla cmd code", UserName, Password);
I hope it will help
I'm trying to build some code that will switch between the old CAPI or the new CNG-based Diffie-Hellman algorithms.
(Despite documentation, the new ECC-based DH algorithm, as part of CNG, is not supported on Windows XP).
Anyway, I've begun exposing the Win32 CAPI, as follows:
public static class CAPI
{
private static int ALG_CLASS_KEY_EXCHANGE = 5 << 13;
private static int ALG_TYPE_DH = 5 << 9;
private static int ALG_SID_DH_EPHEM = 2;
public static int CALG_DH_EPHEM = (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_DH | ALG_SID_DH_EPHEM);
public static uint CRYPT_VERIFYCONTEXT = 0xF0000000;
public static uint CRYPT_SILENT = 0x00000040;
public static uint PROV_DSS_DH = 13;
public static uint CRYPT_EXPORTABLE = 0x00000001;
public static uint CRYPT_PREGEN = 0x00000040;
public static uint KEY_SIZE = 0x00000400;
public static string MS_ENH_DSS_DH_PROV = "Microsoft Enhanced DSS and Diffie-Hellman Cryptographic Provider";
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool CryptAcquireContext(ref IntPtr hProv, string pszContainer, string pszProvider, uint dwProvType, uint dwFlags);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool CryptReleaseContext(IntPtr hProv, uint dwFlags);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool CryptGenKey(IntPtr hProv, int Algid, uint dwFlags, ref IntPtr phKey);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool CryptDestroyKey(IntPtr key);
}
and I have begun building a .NET DH class ontop of this:
public sealed class CAPIDiffieHellman : IDisposable
{
private IntPtr _publicKeyPointer = new IntPtr();
private IntPtr _hProv = new IntPtr();
private uint _contextFlags = CAPI.CRYPT_VERIFYCONTEXT | CAPI.CRYPT_SILENT;
private uint _keyGenerationFlags = CAPI.CRYPT_EXPORTABLE | CAPI.CRYPT_PREGEN;
public CAPIDiffieHellman()
{
if (!CAPI.CryptAcquireContext(
ref this._hProv,
null,
CAPI.MS_ENH_DSS_DH_PROV,
CAPI.PROV_DSS_DH,
this._contextFlags))
{
throw new ApplicationException(string.Format("Unable to acquire cryptographic context. Error Code: {0}", Marshal.GetLastWin32Error()));
}
}
public byte[] GeneratePublicKey()
{
if (!CAPI.CryptGenKey(this._hProv, CAPI.CALG_DH_EPHEM, this._keyGenerationFlags, ref this._publicKeyPointer))
{
throw new ApplicationException(string.Format("Unable to generate cryptographic key. Error Code: {0}", Marshal.GetLastWin32Error()));
}
var publicKey = new byte[128];
Marshal.Copy(this._publicKeyPointer, publicKey, 0, publicKey.Length);
return publicKey;
}
public byte[] DerivePrivateKey(byte[] publicKey)
{
return null;
}
public void Dispose()
{
CAPI.CryptReleaseContext(this._hProv, 0);
CAPI.CryptDestroyKey(this._publicKeyPointer);
}
}
I am working from this documentation
However, I'm realising that I'm not sure what the process I need to follow is; what I'm calling the 'public key' probably isn't!
So, a step-by-step guide for how to use the CAPI to perform a DH key exchange would be greatly appreciated!
thanks.
Use this method to acquire either public or private keys by passing correspondent isPublicKey value:
public static bool ExportCryptKey(IntPtr cryptKey, out byte[] outData, ref uint outDataSize, bool isPublicKey)
{
uint keyType = isPublicKey ? 0x6u : 0x7u;
outData = null;
if (!CryptExportKey(cryptKey, IntPtr.Zero, keyType, 0, null, ref outDataSize))
{
var err = Marshal.GetLastWin32Error();
Debug.Print(new Win32Exception(err).Message);
return false;
}
outData = new byte[outDataSize];
if (!CryptExportKey(cryptKey, IntPtr.Zero, keyType, 0, outData, ref outDataSize))
return false;
return true;
}