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());
}
}
}
}
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 have a form which I make click-through using the following function calls:
SetWindowLong(Handle, GWL_EXSTYLE, (IntPtr)(GetWindowLong(Handle, GWL_EXSTYLE) ^ WS_EX_LAYERED ^ WS_EX_TRANSPARENT));
SetLayeredWindowAttributes(Handle, 0, 0xFF, LWA_ALPHA);
This works fine, however when I try to fade that window using the System.Windows.Forms.Form.Opacity property I get the following exception:
System.ComponentModel.Win32Exception (0x80004005): The parameter is not valid
at System.Windows.Forms.Form.UpdateLayered()
at System.Windows.Forms.Form.set_Opacity(Double value)
How can I achieve both things at the same time?
The following works on a windows form
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace WindowsFormsApplication30
{
public partial class Form1 : Form
{
[DllImport("user32.dll", SetLastError = true)]
static extern System.UInt32 GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", EntryPoint = "SetWindowLong")]
private static extern int SetWindowLong32(IntPtr hWnd, int nIndex, uint dwNewLong);
[DllImport("user32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
static extern int SetLayeredWindowAttributes(IntPtr hWnd, int crKey, byte bAlpha, uint dwFlags);
public const int GWL_EXSTYLE = -20;
public const uint WS_EX_LAYERED = 0x80000;
public const uint LWA_ALPHA = 0x2;
public const uint LWA_COLORKEY = 0x1;
public Form1()
{
InitializeComponent();
IntPtr Handle = this.Handle;
UInt32 windowLong = GetWindowLong(Handle, GWL_EXSTYLE);
SetWindowLong32(Handle, GWL_EXSTYLE, (uint)(windowLong ^ WS_EX_LAYERED));
SetLayeredWindowAttributes(Handle, 0, 128, LWA_ALPHA);
}
}
}
I'm currently trying to inject a library into a program I made(for learning purpose, it's just curiosity). I think I managed to do it, but it seems the code i did is laking of entry point maybe ?
this is the code I wrote :
I used visual studio code to generate a kind of hello-world dll
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace InjectDll
{
public class Inject
{
[DllImport("kernel32")]
static extern bool AllocConsole();
public Inject()
{
AllocConsole();
Console.WriteLine("blablabla");
}
public string test()
{
AllocConsole();
return "dll is injected";
}
}
}
I then made a basic program I where wanted to test my injection =>
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace basicProgram
{
class Program
{
static void Main(string[] args)
{
while(true){
Thread.Sleep(1000);
Console.WriteLine("Hello world");
}
}
}
}
So now I have my dll and the program i wanted to try my injection.I just had to write the injector, and this is what I did =>
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace injectorTest.Inject
{
public enum DllInjectionResult
{
DllNotFound,
GameProcessNotFound,
InjectionFailed,
Success
}
class Injector
{
static readonly IntPtr INTPTR_ZERO = (IntPtr)0;
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr OpenProcess(uint dwDesiredAccess, int bInheritHandle, uint dwProcessId);
[DllImport("kernel32.dll", SetLastError = true)]
static extern int CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, uint flProtect);
[DllImport("kernel32.dll", SetLastError = true)]
static extern int WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] buffer, uint size, int lpNumberOfBytesWritten);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttribute, IntPtr dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
//[DllImport("InjectDll.dll", CallingConvention = CallingConvention.StdCall)]
private const string DLL_NAME = "hello.dll";
private Process myProcess;
private string myPath;
public Injector()
{
}
public Injector(Process myProcess)
{
this.myProcess = myProcess;
this.myPath = Path.GetDirectoryName(myProcess.MainModule.FileName);
}
private void checkDll()
{
if (!File.Exists(myPath + #"\hello.dll")) {
}
}
public DllInjectionResult inject()
{
if (!File.Exists(myPath + "\\hello.dll"))
{
return DllInjectionResult.DllNotFound;
}
Console.WriteLine("process id : " + myProcess.Id);
if (myProcess == null)
{
return DllInjectionResult.GameProcessNotFound;
}
if (!startInject((uint)myProcess.Id, myPath + "\\hello.dll"))
{
return DllInjectionResult.InjectionFailed;
}
return DllInjectionResult.Success;
}
private bool startInject(uint processId, string dllPath)
{
IntPtr handleProcess = OpenProcess((0x2 | 0x8 | 0x10 | 0x20 | 0x400), 1, processId);
if (handleProcess == INTPTR_ZERO)
{
return false;
}
IntPtr lpAddress = VirtualAllocEx(handleProcess, (IntPtr)null, (IntPtr)dllPath.Length, (0x1000 | 0x2000), 0X40);
Console.WriteLine("lpaddr: " + lpAddress);
if (lpAddress == INTPTR_ZERO)
{
return false;
}
byte[] bytes = Encoding.ASCII.GetBytes(dllPath);
if (WriteProcessMemory(handleProcess, lpAddress, bytes, (uint)bytes.Length, 0) == 0)
{
return false;
}
IntPtr lpLLAddress = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryW");
if (lpLLAddress == INTPTR_ZERO)
{
return false;
}
var remoteThread = CreateRemoteThread(handleProcess, (IntPtr)null, INTPTR_ZERO, lpLLAddress, lpAddress, 0, (IntPtr)null);
if (remoteThread == INTPTR_ZERO)
{
return false;
}
CloseHandle(handleProcess);
return true;
}
}
}
It doesn't seems to fail i can see via ida (watching the helloworld program i tried to inject) that LoadLibraryW is trigered when I launch my injector (I then can see the path of the dll injected but it doesn't seems to trigger smthg.
It seems like I missing something (like an entry point in my dll maybe ?).
A normal C/C++ DLL will have a DllMain which gets executed when LoadLibrary is called which then passes through to a switch statement, normally we put our code inside the DLL_PROCESS_ATTACH case which will get executed on injection.
This equivalent doesn't exist in C#/CLR but you can do something tricky to make the same effect by using static constructors.
Make a class and initialize an object of that class, this will in turn call the static constructor. Something like this:
class someClass
{
//Static constructor
static someClass()
{
Console.WriteLine("injected");
}
}
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);
}
}
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