I have built an adapter DS9097E and connected to it DS18B20 digital thermometer. On the internet you can find examples of applications in Delphi and C that reads the temperature from this device. I'm trying to write it in C#. At the beginning I was relying on .NET but it didn't work. I had problems with RESET AND PRESENCE PULSES, so I tried with kernel32.dll. Yesterday I found this library: OpenNETCF. Unfortunately there is no documentation for it. In the meantime, I tried to write my own library:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Activities;
using Microsoft.Win32.SafeHandles;
using System.IO;
using System.Collections.Specialized;
using System.IO.Ports;
namespace COMAPI
{
public class COMutils
{
private int hCOM = -1;
private DCB dcb = new DCB();
private COMMTIMEOUTS commtime = new COMMTIMEOUTS();
private int bufferSize = 128;
private byte[] ReceiveBytes;
#region STALE
private const int PURGE_TXABORT = 0x01;
private const int PURGE_RXABORT = 0x02;
private const int PURGE_TXCLEAR = 0x04;
private const int PURGE_RXCLEAR = 0x08;
private const int INVALID_HANDLE_VALUE = -1;
private const uint GENERIC_READ = 0x80000000;
private const uint GENERIC_WRITE = 0x40000000;
#endregion
#region KERNEL32
[DllImport("kernel32.dll")]
static extern bool PurgeComm(int hFile, int dwFlags);
[DllImport("kernel32.dll", SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CloseHandle(int hObject);
[DllImport("kernel32.dll")]
static extern bool FlushFileBuffers(int hFile);
[DllImport("kernel32.dll")]
static extern bool TransmitCommChar(int hFile, char cChar);
[DllImport("kernel32.dll")]
static extern bool WriteFile(int hFile, byte [] lpBuffer, int nNumberOfBytesToWrite, ref int lpNumberOfBytesWritten, int lpOverlapped);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool ReadFile(int hFile, [Out] byte[] lpBuffer, int nNumberOfBytesToRead, ref int lpNumberOfBytesRead, int lpOverlapped);
[DllImport("kernel32.dll")]
static extern bool GetCommState(int hFile, ref DCB lpDCB);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool GetCommTimeouts(int hFile, ref COMMTIMEOUTS lpCommTimeouts);
[DllImport("kernel32.dll")]
static extern bool SetCommState(int hFile, [In] ref DCB lpDCB);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern int CreateFile(
string lpFileName,
[MarshalAs(UnmanagedType.U4)] uint dwDesiredAccess,
[MarshalAs(UnmanagedType.U4)] int dwShareMode,
int lpSecurityAttributes,
[MarshalAs(UnmanagedType.U4)] int dwCreationDisposition,
[MarshalAs(UnmanagedType.U4)] int dwFlagsAndAttributes,
int hTemplateFile);
[DllImport("kernel32.dll")]
static extern int GetTickCount();
#endregion
#region DCB
[StructLayout(LayoutKind.Sequential)]
internal struct DCB
{
internal uint DCBLength;
internal uint BaudRate;
private BitVector32 Flags;
private ushort wReserved; // not currently used
internal ushort XonLim; // transmit XON threshold
internal ushort XoffLim; // transmit XOFF threshold
internal byte ByteSize;
internal Parity Parity;
internal StopBits StopBits;
internal sbyte XonChar; // Tx and Rx XON character
internal sbyte XoffChar; // Tx and Rx XOFF character
internal sbyte ErrorChar; // error replacement character
internal sbyte EofChar; // end of input character
internal sbyte EvtChar; // received event character
private ushort wReserved1; // reserved; do not use
private static readonly int fBinary;
private static readonly int fParity;
private static readonly int fOutxCtsFlow;
private static readonly int fOutxDsrFlow;
private static readonly BitVector32.Section fDtrControl;
private static readonly int fDsrSensitivity;
private static readonly int fTXContinueOnXoff;
private static readonly int fOutX;
private static readonly int fInX;
private static readonly int fErrorChar;
private static readonly int fNull;
private static readonly BitVector32.Section fRtsControl;
private static readonly int fAbortOnError;
static DCB()
{
// Create Boolean Mask
int previousMask;
fBinary = BitVector32.CreateMask();
fParity = BitVector32.CreateMask(fBinary);
fOutxCtsFlow = BitVector32.CreateMask(fParity);
fOutxDsrFlow = BitVector32.CreateMask(fOutxCtsFlow);
previousMask = BitVector32.CreateMask(fOutxDsrFlow);
previousMask = BitVector32.CreateMask(previousMask);
fDsrSensitivity = BitVector32.CreateMask(previousMask);
fTXContinueOnXoff = BitVector32.CreateMask(fDsrSensitivity);
fOutX = BitVector32.CreateMask(fTXContinueOnXoff);
fInX = BitVector32.CreateMask(fOutX);
fErrorChar = BitVector32.CreateMask(fInX);
fNull = BitVector32.CreateMask(fErrorChar);
previousMask = BitVector32.CreateMask(fNull);
previousMask = BitVector32.CreateMask(previousMask);
fAbortOnError = BitVector32.CreateMask(previousMask);
}
}
#endregion
#region COMMTIMEOUTS
struct COMMTIMEOUTS
{
public UInt32 ReadIntervalTimeout;
public UInt32 ReadTotalTimeoutMultiplier;
public UInt32 ReadTotalTimeoutConstant;
public UInt32 WriteTotalTimeoutMultiplier;
public UInt32 WriteTotalTimeoutConstant;
}
#endregion
#region METODY
public bool openCOM(int numer)
{
hCOM = CreateFile("COM" + numer, GENERIC_READ | GENERIC_WRITE, 0, 0, 3, 0, 0);
if (hCOM == INVALID_HANDLE_VALUE)
return false;
if (!GetCommState(hCOM, ref dcb))
return false;
if (!GetCommTimeouts(hCOM, ref commtime))
return false;
return true;
}
public bool closeCOM()
{
return CloseHandle(hCOM);
}
public bool setCOM(int baud, byte bsize, Parity par, StopBits sbits)
{
dcb.BaudRate = (uint)baud;
dcb.ByteSize = bsize;
dcb.Parity = par;
dcb.StopBits = sbits;
return SetCommState(hCOM, ref dcb);
}
public bool cleanCOM()
{
return PurgeComm(hCOM, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
}
public bool flushCOM()
{
return FlushFileBuffers(hCOM);
}
public bool TxByteCOM(byte dane)
{
return TransmitCommChar(hCOM, (char)dane);
}
public bool TxDataCOM(byte[] daneW)
{
int byteZap = 0;
return WriteFile(hCOM, daneW, daneW.Length, ref byteZap, 0);
}
public byte[] RxDataCOM(byte[] odebraneBytes, int ilosc, int odczytane)
{
if(ilosc == 0)
ilosc = bufferSize;
if(hCOM != INVALID_HANDLE_VALUE)
{
odczytane = 0;
bool stanOdczytu = true;
odebraneBytes = new byte[ilosc];
stanOdczytu = ReadFile (hCOM, odebraneBytes, ilosc, ref odczytane, 0);
if(stanOdczytu == false)
{
throw new ApplicationException("Błąd odczytu");
}
else
{
return odebraneBytes;
}
}
else
{
throw new ApplicationException ("Port nie został otwarty");
}
}
public int returnTime()
{
return GetTickCount();
}
private bool IsOdd(int value)
{
return value % 2 != 0;
}
public int sendByte(int X)
{
int D = 0;
int czas, temp;
byte[] B = new byte[1];
temp = X;
setCOM(115200, 8, Parity.None, StopBits.One);
cleanCOM();
czas = returnTime() + 50;
for (int n = 1; n <= 8; n++)
{
if (IsOdd(temp)) TxByteCOM(0xFF);
else TxByteCOM(0x00);
temp = temp << 1;
do
{
RxDataCOM(B, 1, D);
} while ((D > 1) | (czas < returnTime()));
if (D != 1) break;
if (IsOdd(B[0])) temp = (temp | 0x80);
}
return temp;
}
public bool sendCOM(byte[] WrByt)
{
int BytesWritten = 0;
bool writeState = false;
if (hCOM != INVALID_HANDLE_VALUE)
{
PurgeComm(hCOM, PURGE_RXCLEAR | PURGE_TXCLEAR);
writeState = WriteFile(hCOM, WrByt, WrByt.Length, ref BytesWritten, 0);
if (writeState == false)
{
throw new ApplicationException("Błąd zapisu do portu ");
}
}
else
{
throw new ApplicationException("Port nie został otwarty");
}
return writeState;
}
public byte[] receiveCOM (int NumBytes)
{
if(NumBytes == 0)
NumBytes = bufferSize;
if (hCOM != INVALID_HANDLE_VALUE)
{
int BytesRead = 0;
bool readState = true;
ReceiveBytes = new byte[NumBytes];
readState = ReadFile(hCOM, ReceiveBytes, NumBytes, ref BytesRead, 0);
if (readState == false)
{
throw new ApplicationException("Błąd odczytu");
}
else
{
return ReceiveBytes;
}
}
else
{
throw new ApplicationException("Port nie został otwarty");
}
}
public bool resetCOM()
{
int czasOd;
int D = 0;
byte[] baju = new byte[1];
byte[] lista = new byte[1];
setCOM(9600, 8, Parity.None, StopBits.One);
cleanCOM();
lista[0] = 0xF0;
sendCOM(lista);
czasOd = returnTime() + 50;
do
{
RxDataCOM(baju, 1, D);
}
while ((D == 1) | czasOd < returnTime());
if (D == 1)
return (baju[0] != 0xF0);
return true;
}
#endregion
}
}
This is code of my application:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using COMAPI;
namespace temp_3
{
class Program
{
static private COMutils util = new COMutils();
static void Main(string[] args)
{
int TH,TL;
int TEMP_READ;
double TEMP;
util.openCOM(1);
byte[] lista = new byte[1];
bool czy = util.resetCOM();
lista[0] = 0xCC;
czy = util.sendCOM(lista);
lista[0] = 0x44;
czy = util.sendCOM(lista);
Thread.Sleep(750);
czy = util.resetCOM();
lista[0] = 0xCC;
czy = util.sendCOM(lista);
lista[0] = 0xBE;
czy = util.sendCOM(lista);
TL = util.sendByte(0xFF);
Console.WriteLine(TL);
TH = util.sendByte(0xFF);
Console.WriteLine(TH);
czy = util.resetCOM();
Console.WriteLine(czy);
TEMP_READ = TL + 256 * TH;
TEMP = TEMP_READ / 16.0;
Console.WriteLine(TEMP);
Console.WriteLine(czy);
Console.ReadKey();
}
}
}
Unfortunately, based on this code, it reads the temperature of over 8000 degrees Celsius. Could someone point out where is the mistake? Any hint will be appreciated. Here are functions wrote in Delphi:
function Reset_COM:boolean;
var B:Byte;
D,time:DWord;
begin
Result := False;
//ustawienie portu RS232
Ustaw_COM(9600,8,NOPARITY,ONESTOPBIT);
//czyszczenie RS232
Result := Czysc_COM;
TransmitCommChar(hCom,Chr($F0));
time:=GetTickCount+50;
repeat
ReadFile(hCom,B,1,D,nil)
until (D=1) or (time<GetTickCount);
if D=1 then
Result:=(B<>$F0);
end;
function send_Bajt(X:Byte):Byte;
var
n:Integer;
B:Byte;
D,time:DWord;
begin
Result:=$FF;
Ustaw_Com(115200,8,NOPARITY,ONESTOPBIT);
Czysc_COM;
time:=GetTickCount+50;
for n:=1 to 8 do
begin
if Odd(X) then TransmitCommChar(hCom,Chr($FF)) else TransmitCommChar(hCom,Chr($00));
X:=X shr 1;
repeat ReadFile(hCom,B,1,D,nil)
until (D=1) or (time<GetTickCount);
if D<>1 then exit;
if Odd(B) then X:=X or $80;
if Odd(B xor CRC)
then CRC:=((CRC xor $18) shr 1) or $80
else CRC:=CRC shr 1;
end;
Result:=X;
end;
function Odczytaj_TEMP:real;
var TH,TL:Byte;
TEMP_READ: Smallint;
Temp: double;
begin
Resetuj_COM;
send_Bajt($CC); //Skip ROM
send_Bajt($44); //Start T Convert
Sleep(750);
Resetuj_COM;
send_Bajt($CC); //Skip ROM
send_Bajt($BE); //Read Scratchpad
TL:=send_Bajt($FF);
TH:=send_Bajt($FF);
Resetuj_COM;
TEMP_READ := TL + 256 * TH;
Temp := TEMP_READ / 16.0;
Result := Temp;
end;
Related
I have 2 programs written in c#, first one called "ScanMe" contains a string variable that contains value "FINDMEEEEEEE", and a double variable that has the value of 1546.22915487. And the other program called "MemoryScan" reads all the memory of the first program.
I want to get the memory address of the string variable of that process
When i execute "MemoryScan" and reads all the memory of "ScanMe" process, then i try to find the byte array of the string in all the data scanned and i get nothing. If i try to find the double i get the specific memory address and also i can change its value, but when i try to do that with the string variable i cant cause i dont even get the address of that string variable.
ScanMe and MemoryScan Code:
class Program
{
public static string FindMeString = "FINDMEEEEEEE";
public static double FindMeDouble = 1546.22915487;
static void Main(string[] args)
{
while (FindMeDouble == 1546.22915487)
{
System.Threading.Thread.Sleep(2000);
}
Console.WriteLine(FindMeDouble.ToString());
Console.ReadLine();
}
}
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace MemoryScan
{
class MemoryController
{
// REQUIRED CONSTS
const int PROCESS_QUERY_INFORMATION = 0x0400;
const int MEM_COMMIT = 0x00001000;
const int PAGE_READWRITE = 0x04;
const int PROCESS_WM_READ = 0x0010;
readonly Dictionary<IntPtr, byte[]> Regions = new Dictionary<IntPtr, byte[]>();
readonly List<SearchResult> _results = new List<SearchResult>();
// REQUIRED METHODS
[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
[DllImport("kernel32.dll")]
public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, uint dwSize, ref int lpNumberOfBytesRead);
[DllImport("kernel32.dll")]
static extern void GetSystemInfo(out SystemInfo lpSystemInfo);
[DllImport("kernel32.dll", SetLastError = true)]
static extern int VirtualQueryEx(IntPtr hProcess, IntPtr lpAddress, out MEMORY_BASIC_INFORMATION lpBuffer, int dwLength);
public enum ProcessorArchitecture
{
X86 = 0,
X64 = 9,
Arm = -1,
Itanium = 6,
Unknown = 0xFFFF
}
// REQUIRED STRUCTS
[StructLayout(LayoutKind.Sequential)]
public struct SystemInfo
{
public ProcessorArchitecture ProcessorArchitecture;
public uint PageSize;
public IntPtr MinimumApplicationAddress;
public IntPtr MaximumApplicationAddress;
public IntPtr ActiveProcessorMask;
public uint NumberOfProcessors;
public uint ProcessorType;
public uint AllocationGranularity;
public ushort ProcessorLevel;
public ushort ProcessorRevision;
}
[StructLayout(LayoutKind.Sequential)]
public struct MEMORY_BASIC_INFORMATION
{
public IntPtr BaseAddress;
public IntPtr AllocationBase;
public uint AllocationProtect;
public IntPtr RegionSize;
public uint State;
public uint Protect;
public uint Type;
}
public void FindProcessMemory(int processId)
{
// getting minimum & maximum address
SystemInfo sys_info;
GetSystemInfo(out sys_info);
uint max_Address = (uint)sys_info.MaximumApplicationAddress;
// opening the process with desired access level
IntPtr processHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_WM_READ, false, processId);
IntPtr current = IntPtr.Zero;
int bytesRead = 0; // number of bytes read with ReadProcessMemory
int dwLength = Marshal.SizeOf(typeof(MEMORY_BASIC_INFORMATION));
while ((uint)current < max_Address && VirtualQueryEx(processHandle, current, out MEMORY_BASIC_INFORMATION mem_basic_info, dwLength) != 0)
{
// if this memory chunk is accessible
if (mem_basic_info.Protect == PAGE_READWRITE && mem_basic_info.State == MEM_COMMIT)
{
byte[] buffer = new byte[(int)mem_basic_info.RegionSize];
// read everything in the buffer above
if (ReadProcessMemory(processHandle, mem_basic_info.BaseAddress, buffer, (uint)mem_basic_info.RegionSize, ref bytesRead))
{
Regions.Add(mem_basic_info.BaseAddress, buffer);
}
else
Console.WriteLine($"Error code: Marshal.GetLastWin32Error()");
}
// move to the next memory chunk
current = IntPtr.Add(mem_basic_info.BaseAddress, mem_basic_info.RegionSize.ToInt32());
}
byte[] data = System.Text.Encoding.Unicode.GetBytes("FINDMEEEEEEE");
foreach (IntPtr address in Regions.Keys)
{
foreach (int i in ByteSearch.AllIndexOf(Regions[address], data))
_results.Add(new SearchResult(IntPtr.Add(address, i), data));
}
Console.ReadLine();
}
}
public static class ByteSearch
{
static int[] createTable(byte[] pattern)
{
int[] table = new int[256];
for (int i = 0; i < table.Length; i++)
table[i] = pattern.Length;
for (int i = 0; i < pattern.Length - 1; i++)
table[Convert.ToInt32(pattern[i])] = pattern.Length - i - 1;
return table;
}
public static bool matchAtOffset(byte[] toSearch, byte[] pattern, int index)
{
if (index + pattern.Length > toSearch.Length)
return false;
for (int i = 0; i < pattern.Length; i++)
{
if (toSearch[i + index] != pattern[i])
return false;
}
return true;
}
public static bool Contains(byte[] toSearch, byte[] pattern)
{
return FirstIndexOf(toSearch, pattern) != -1;
}
public static int FirstIndexOf(byte[] toSearch, byte[] pattern)
{
int[] table = createTable(pattern);
int position = pattern.Length - 1;
while (position < toSearch.Length)
{
int i;
for (i = 0; i < pattern.Length; i++)
{
if (pattern[pattern.Length - 1 - i] != toSearch[position - i])
break;
if (i == pattern.Length - 1)
return position - i;
}
position += table[Convert.ToInt32(toSearch[position - i])];
}
return -1;
}
public static int LastIndexOf(byte[] toSearch, byte[] pattern)
{
int ret = -1;
int[] table = createTable(pattern);
int position = pattern.Length - 1;
while (position < toSearch.Length)
{
int i;
bool found = false;
for (i = 0; i < pattern.Length; i++)
{
if (pattern[pattern.Length - 1 - i] != toSearch[position - i])
break;
if (i == pattern.Length - 1)
{
ret = position - i;
found = true;
}
}
if (found)
position++;
else
position += table[Convert.ToInt32(toSearch[position - i])];
}
return ret;
}
public static int[] AllIndexOf(byte[] toSearch, byte[] pattern)
{
List<int> indices = new List<int>();
int[] table = createTable(pattern);
int position = pattern.Length - 1;
while (position < toSearch.Length)
{
int i;
bool found = false;
for (i = 0; i < pattern.Length; i++)
{
if (pattern[pattern.Length - 1 - i] != toSearch[position - i])
break;
if (i == pattern.Length - 1)
{
indices.Add(position - i);
found = true;
}
}
if (found)
position++;
else
position += table[Convert.ToInt32(toSearch[position - i])];
}
return indices.ToArray();
}
}
public class SearchResult
{
public SearchResult(IntPtr add, byte[] value)
{
Address = add;
Buffer = value;
}
public IntPtr Address { get; set; }
public byte[] Buffer { get; set; }
}
}
Why i cant find the string and when i try to find the double i find it with no problem and even also i can change its value with the extern writeprocessmemory?
Thanks.
I'm not sure I could reproduce your exact condition, since you didn't provide a minimal reproducible example. However, I got it up and running - with similar results. I then figured out the following:
You are not checking the return value of ReadProcessMemory. MSDN says
If the function fails, the return value is 0 (zero). To get extended error information, call GetLastError.
The 0 will be mapped to false, depending on the PInvoke signature you use.
To get the last error, use Marshal.GetLastWin32Error(). On my PC, the error code was 299 and
MSDN says
ERROR_PARTIAL_COPY
299 (0x12B)
Only part of a ReadProcessMemory or WriteProcessMemory request was completed.
At the same time, the number of bytes read (ref bytesRead) is 0, so it didn't read the process' memory.
See this related SO question about this error code.
I'd like to list out all CSP and CNG providers installed on a system, but I can't find a good method for doing so in C#. For CSP, I can enumerate a certain registry key (inelegant, but functional), but I've been unable to find any way to get a list of CNG providers.
Is there anything remotely like System.Security.Cryptography.Get[CSP/CNG]Providers() or similarly logical/straightforward in .NET that could be used? Thanks!
To my knowledge, there isn't anything like that in .NET Framework.
For CSP providers, enumerate the subkeys of:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Defaults\Provider
For CNG providers, enumerate the subkeys of:
HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Cryptography\Providers
Use this to enumerate CSP providers and containers:
using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Text;
namespace CspSample
{
struct Provider
{
public string Name { get; set; }
public int Type { get; set; }
}
class CspUtils
{
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool CryptEnumProviderTypes(
uint dwIndex,
uint pdwReserved,
uint dwFlags,
[In] ref uint pdwProvType,
StringBuilder pszTypeName,
[In] ref uint pcbTypeName);
[DllImport("Advapi32.dll")]
private static extern bool CryptEnumProviders(
int dwIndex,
IntPtr pdwReserved,
int dwFlags,
ref int pdwProvType,
StringBuilder pszProvName,
ref int pcbProvName);
public static List<Provider> ListAllProviders()
{
List<Provider> installedCSPs = new List<Provider>();
int cbName;
int dwType;
int dwIndex;
StringBuilder pszName;
dwIndex = 0;
dwType = 1;
cbName = 0;
while (CryptEnumProviders(dwIndex, IntPtr.Zero, 0, ref dwType, null, ref cbName))
{
pszName = new StringBuilder(cbName);
if (CryptEnumProviders(dwIndex++, IntPtr.Zero, 0, ref dwType, pszName, ref cbName))
{
installedCSPs.Add(new Provider { Name = pszName.ToString(), Type = dwType });
}
}
return installedCSPs;
}
const int PP_ENUMCONTAINERS = 2;
const int PROV_RSA_FULL = 1;
const int ERROR_MORE_DATA = 234;
const int ERROR_NO_MORE_ITEMS = 259;
const int CRYPT_FIRST = 1;
const int CRYPT_NEXT = 2;
//TODO: Find how to disable this flag (not machine keystore)
const int CRYPT_MACHINE_KEYSET = 0x20;
const int CRYPT_VERIFYCONTEXT = unchecked((int)0xF0000000);
public static IList<string> EnumerateKeyContainers(string providerName, int providerType)
{
ProvHandle prov;
if (!CryptAcquireContext(out prov, null, providerName, providerType, CRYPT_MACHINE_KEYSET | CRYPT_VERIFYCONTEXT))
throw new Win32Exception(Marshal.GetLastWin32Error());
List<string> list = new List<string>();
IntPtr data = IntPtr.Zero;
try
{
int flag = CRYPT_FIRST;
int len = 0;
if (!CryptGetProvParam(prov, PP_ENUMCONTAINERS, IntPtr.Zero, ref len, flag))
{
if (Marshal.GetLastWin32Error() != ERROR_MORE_DATA)
throw new Win32Exception(Marshal.GetLastWin32Error());
}
data = Marshal.AllocHGlobal(len);
do
{
if (!CryptGetProvParam(prov, PP_ENUMCONTAINERS, data, ref len, flag))
{
if (Marshal.GetLastWin32Error() == ERROR_NO_MORE_ITEMS)
break;
//throw new Win32Exception(Marshal.GetLastWin32Error());
}
list.Add(Marshal.PtrToStringAnsi(data));
flag = CRYPT_NEXT;
}
while (true);
}
finally
{
if (data != IntPtr.Zero)
{
Marshal.FreeHGlobal(data);
}
prov.Dispose();
}
return list;
}
private sealed class ProvHandle : SafeHandleZeroOrMinusOneIsInvalid
{
public ProvHandle()
: base(true)
{
}
protected override bool ReleaseHandle()
{
return CryptReleaseContext(handle, 0);
}
[DllImport("advapi32.dll")]
private static extern bool CryptReleaseContext(IntPtr hProv, int dwFlags);
}
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern bool CryptAcquireContext(out ProvHandle phProv, string pszContainer, string pszProvider, int dwProvType, int dwFlags);
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool CryptGetProvParam(ProvHandle hProv, int dwParam, IntPtr pbData, ref int pdwDataLen, int dwFlags);
}
}
I am working on an application that required reading the mifare card serial number, the language I am working with is C#.
I am new to mifare reader programming, so I am sorry for asking dumb question.
At first I would like to know if there is a different between Mifare UID and Mifare Serial number.
I have managed to get UID with the help of WinSCard library, but I cant figure it out how to get the card serial number which should be 10 digit numbers.
I do appreciate if you could point me to the right direction.
Thanks in advance for the help.
Regards
C# signature of SCardTransmit method
[StructLayout(LayoutKind.Sequential)]
public struct SCARD_IO_REQUEST
{
public int dwProtocol;
public int cbPciLength;
}
[DllImport("winscard.dll")]
public static extern int SCardTransmit(int hCard, ref SCARD_IO_REQUEST pioSendRequest, ref byte SendBuff, int SendBuffLen, ref SCARD_IO_REQUEST pioRecvRequest,
ref byte RecvBuff, ref int RecvBuffLen);
Code Example for read UID of mifare card
private SmartcardErrorCode GetUID(ref byte[] UID)
{
byte[] receivedUID = new byte[10];
UnsafeNativeMethods.SCARD_IO_REQUEST request = new UnsafeNativeMethods.SCARD_IO_REQUEST();
request.dwProtocol = 1; //SCARD_PROTOCOL_T1);
request.cbPciLength = System.Runtime.InteropServices.Marshal.SizeOf(typeof(UnsafeNativeMethods.SCARD_IO_REQUEST));
byte[] sendBytes = new byte[] { 0xFF, 0xCA, 0x00, 0x00, 0x04 }; //get UID command for Mifare cards
int outBytes = receivedUID.Length;
int status = SCardTransmit(_hCard, ref request, ref sendBytes[0], sendBytes.Length, ref request, ref receivedUID[0], ref outBytes);
UID = receivedUID.Take(8).ToArray();
return status;
}
The Selected answer doesn't work on x64 enviroments.
Here is a Full example code, tested and working on Windows 10 x64.
What this does:
Retrieve the List of Available Readers
Selects to use the First available Reader
Check if there is a Card in the reader and Connects to it.
Transmits to the card the Command to retrieve its UID
Converts the UID into a Hexadecimal string.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace DXCutcsa.VO.Common
{
public class SmartCardReader
{
#region Atributos
private bool _disposed = false;
private IntPtr _ReaderContext = IntPtr.Zero;
private string _ReaderName = string.Empty;
private List<string> _AvailableReaders = new List<string>();
#endregion
#region Win32 APIs
[DllImport("WinScard.dll")]
static extern int SCardEstablishContext(uint dwScope,
IntPtr notUsed1,
IntPtr notUsed2,
out IntPtr phContext);
[DllImport("WinScard.dll")]
static extern int SCardReleaseContext(IntPtr phContext);
[DllImport("WinScard.dll")]
static extern int SCardConnect(IntPtr hContext,
string cReaderName,
uint dwShareMode,
uint dwPrefProtocol,
ref IntPtr phCard,
ref IntPtr ActiveProtocol);
[DllImport("WinScard.dll")]
static extern int SCardDisconnect(IntPtr hCard, int Disposition);
[DllImport("WinScard.dll", EntryPoint = "SCardListReadersA", CharSet = CharSet.Ansi)]
static extern int SCardListReaders(
IntPtr hContext,
byte[] mszGroups,
byte[] mszReaders,
ref UInt32 pcchReaders);
[DllImport("winscard.dll")]
static extern int SCardStatus(
uint hCard,
IntPtr szReaderName,
ref int pcchReaderLen,
ref int pdwState,
ref uint pdwProtocol,
byte[] pbAtr,
ref int pcbAtrLen);
[DllImport("winscard.dll")]
static extern int SCardTransmit(
IntPtr hCard,
ref SCARD_IO_REQUEST pioSendRequest,
ref byte SendBuff,
uint SendBuffLen,
ref SCARD_IO_REQUEST pioRecvRequest,
byte[] RecvBuff,
ref uint RecvBuffLen);
[DllImport("winscard.dll", SetLastError = true)]
static extern int SCardGetAttrib(
IntPtr hCard, // Valor retornado en funcion ScardConnect
UInt32 dwAttrId, // Identificacion de atributos a obtener
byte[] pbAttr, // Puntero al vector atributos recividos
ref IntPtr pcbAttrLen // Tamaño del vector
);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct ReaderState
{
public ReaderState(string sName)
{
this.szReader = sName;
this.pvUserData = IntPtr.Zero;
this.dwCurrentState = 0;
this.dwEventState = 0;
this.cbATR = 0;
this.rgbATR = null;
}
internal string szReader;
internal IntPtr pvUserData;
internal uint dwCurrentState;
internal uint dwEventState;
internal uint cbATR; // count of bytes in rgbATR
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x24, ArraySubType = UnmanagedType.U1)]
internal byte[] rgbATR;
}
[StructLayout(LayoutKind.Sequential)]
public struct SCARD_IO_REQUEST
{
public UInt32 dwProtocol;
public UInt32 cbPciLength;
}
/*****************************************************************/
[DllImport("kernel32.dll", SetLastError = true)]
private extern static IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32.dll")]
private extern static void FreeLibrary(IntPtr handle);
[DllImport("kernel32.dll")]
private extern static IntPtr GetProcAddress(IntPtr handle, string procName);
#endregion
#region Error codes
public const uint S_SUCCESS = 0x00000000;
public const uint F_INTERNAL_ERROR = 0x80100001;
public const uint E_CANCELLED = 0x80100002;
public const uint E_INVALID_HANDLE = 0x80100003;
public const uint E_INVALID_PARAMETER = 0x80100004;
public const uint E_INVALID_TARGET = 0x80100005;
public const uint E_NO_MEMORY = 0x80100006;
public const uint F_WAITED_TOO_LONG = 0x80100007;
public const uint E_INSUFFICIENT_BUFFER = 0x80100008;
public const uint E_UNKNOWN_READER = 0x80100009;
public const uint E_TIMEOUT = 0x8010000A;
public const uint E_SHARING_VIOLATION = 0x8010000B;
public const uint E_NO_SMARTCARD = 0x8010000C;
public const uint E_UNKNOWN_CARD = 0x8010000D;
public const uint E_CANT_DISPOSE = 0x8010000E;
public const uint E_PROTO_MISMATCH = 0x8010000F;
public const uint E_NOT_READY = 0x80100010;
public const uint E_INVALID_VALUE = 0x80100011;
public const uint E_SYSTEM_CANCELLED = 0x80100012;
public const uint F_COMM_ERROR = 0x80100013;
public const uint F_UNKNOWN_ERROR = 0x80100014;
public const uint E_INVALID_ATR = 0x80100015;
public const uint E_NOT_TRANSACTED = 0x80100016;
public const uint E_READER_UNAVAILABLE = 0x80100017;
public const uint P_SHUTDOWN = 0x80100018;
public const uint E_PCI_TOO_SMALL = 0x80100019;
public const uint E_READER_UNSUPPORTED = 0x8010001A;
public const uint E_DUPLICATE_READER = 0x8010001B;
public const uint E_CARD_UNSUPPORTED = 0x8010001C;
public const uint E_NO_SERVICE = 0x8010001D;
public const uint E_SERVICE_STOPPED = 0x8010001E;
public const uint E_UNEXPECTED = 0x8010001F;
public const uint E_ICC_INSTALLATION = 0x80100020;
public const uint E_ICC_CREATEORDER = 0x80100021;
public const uint E_UNSUPPORTED_FEATURE = 0x80100022;
public const uint E_DIR_NOT_FOUND = 0x80100023;
public const uint E_FILE_NOT_FOUND = 0x80100024;
public const uint E_NO_DIR = 0x80100025;
public const uint E_NO_FILE = 0x80100026;
public const uint E_NO_ACCESS = 0x80100027;
public const uint E_WRITE_TOO_MANY = 0x80100028;
public const uint E_BAD_SEEK = 0x80100029;
public const uint E_INVALID_CHV = 0x8010002A;
public const uint E_UNKNOWN_RES_MNG = 0x8010002B;
public const uint E_NO_SUCH_CERTIFICATE = 0x8010002C;
public const uint E_CERTIFICATE_UNAVAILABLE = 0x8010002D;
public const uint E_NO_READERS_AVAILABLE = 0x8010002E;
public const uint E_COMM_DATA_LOST = 0x8010002F;
public const uint E_NO_KEY_CONTAINER = 0x80100030;
public const uint W_UNSUPPORTED_CARD = 0x80100065;
public const uint W_UNRESPONSIVE_CARD = 0x80100066;
public const uint W_UNPOWERED_CARD = 0x80100067;
public const uint W_RESET_CARD = 0x80100068;
public const uint W_REMOVED_CARD = 0x80100069;
public const uint W_SECURITY_VIOLATION = 0x8010006A;
public const uint W_WRONG_CHV = 0x8010006B;
public const uint W_CHV_BLOCKED = 0x8010006C;
public const uint W_EOF = 0x8010006D;
public const uint W_CANCELLED_BY_USER = 0x8010006E;
public const uint W_CARD_NOT_AUTHENTICATED = 0x8010006F;
#endregion
#region Constructor
public SmartCardReader()
{
}
#endregion
#region Metodos
public long GetUID(ref byte[] UID)
{
long _result = 0;
bool cardInserted = false;
IntPtr _CardContext = IntPtr.Zero;
IntPtr ActiveProtocol = IntPtr.Zero;
// Establish Reader context:
if (this._ReaderContext == IntPtr.Zero)
{
_result = SCardEstablishContext(2, IntPtr.Zero, IntPtr.Zero, out this._ReaderContext);
#region Get List of Available Readers
uint pcchReaders = 0;
int nullindex = -1;
char nullchar = (char)0;
// First call with 3rd parameter set to null gets readers buffer length.
_result = SCardListReaders(this._ReaderContext, null, null, ref pcchReaders);
byte[] mszReaders = new byte[pcchReaders];
// Fill readers buffer with second call.
_result = SCardListReaders(this._ReaderContext, null, mszReaders, ref pcchReaders);
// Populate List with readers.
string currbuff = new ASCIIEncoding().GetString(mszReaders);
int len = (int)pcchReaders;
if (len > 0)
{
while (currbuff[0] != nullchar)
{
nullindex = currbuff.IndexOf(nullchar); // Get null end character.
string reader = currbuff.Substring(0, nullindex);
this._AvailableReaders.Add(reader);
len = len - (reader.Length + 1);
currbuff = currbuff.Substring(nullindex + 1, len);
}
}
#endregion
// Select the first reader:
this._ReaderName = this._AvailableReaders[0];
}
try
{
//Check if there is a Card in the reader:
//dwShareMode: SCARD_SHARE_SHARED = 0x00000002 - This application will allow others to share the reader
//dwPreferredProtocols: SCARD_PROTOCOL_T0 - Use the T=0 protocol (value = 0x00000001)
if (this._ReaderContext != IntPtr.Zero)
{
_result = SCardConnect(this._ReaderContext, this._ReaderName, 0x00000002, 0x00000001, ref _CardContext, ref ActiveProtocol);
if (_result == 0)
{
cardInserted = true;
SCARD_IO_REQUEST request = new SCARD_IO_REQUEST()
{
dwProtocol = (uint)ActiveProtocol,
cbPciLength = (uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(SCARD_IO_REQUEST))
};
byte[] sendBytes = new byte[] { 0xFF, 0xCA, 0x00, 0x00, 0x00 }; //<- get UID command for iClass cards
byte[] ret_Bytes = new byte[33];
uint sendLen = (uint)sendBytes.Length;
uint ret_Len = (uint)ret_Bytes.Length;
_result = SCardTransmit(_CardContext, ref request, ref sendBytes[0], sendLen, ref request, ret_Bytes, ref ret_Len);
if (_result == 0)
{
UID = ret_Bytes.Take(4).ToArray(); //only take the first 8, the last 2 bytes are not part of the UID of the card
string dataOut = byteToHexa(UID, UID.Length, true).Trim(); //Devolver la respuesta en Hexadecimal
}
}
}
}
finally
{
SCardDisconnect(_CardContext, 0);
SCardReleaseContext(this._ReaderContext);
}
return _result;
}
private string byteToHexa(byte[] byReadBuffer, int leng, bool bSpace)
{
string text2 = "";
for (short num1 = 0; num1 < leng; num1 = (short)(num1 + 1))
{
short num2 = byReadBuffer[num1];
text2 = text2 + System.Convert.ToString(num2, 16).PadLeft(2, '0');
if (bSpace)
{
text2 = text2 + " ";
}
}
return text2.ToUpper();
}
//Get the address of Pci from "Winscard.dll".
private IntPtr GetPciT0()
{
IntPtr handle = LoadLibrary("Winscard.dll");
IntPtr pci = GetProcAddress(handle, "g_rgSCardT0Pci");
FreeLibrary(handle);
return pci;
}
#endregion
}// Fin de la Clase
}
PInvoke docs helped a lot: https://www.pinvoke.net/default.aspx/winscard.scardtransmit
Using the topic Overview - Handle Enumeration, number 5, the attempt Close mutex of another process and and information from Mutex analysis, the canary in the coal mine and discovering new families of malware/, I have came up with:
Attempt 1: http://pastebin.com/QU0WBgE5
You must open Notepad first. Needless to say, this is not working for me. I need better error checking to figure out what's going on. I don't know how to get mutex pointers in the format I see them in Process Explorer.
My goal is to be able to delete/kill of the mutex handles created by a process so more than one instance can be open. I can do this manually using Process Explorer, but I want to do it programmatically.
(Based on Yahia's notes, I need more permissions.)
Attempt 2: http://pastebin.com/yyQLhesP
At least now I have some sort of error checking, most of the time DuplicateHandle returns 6 or 5, which is an invalid handle and access denied respectfully.
Working attempt (kind of):
I actually didn't require anything Yahia stated in the end. I was getting a "local" handle when I needed a remote one. Basically, what I mean is that you have to find the HandleValue using NtQuerySystemInformation and use that handle, not the one returned by OpenMutex / CreateMutex.
Granted, I can't get it to work on some applications (osk.exe -- on screen keyboard), but it worked for the application I was going for, posting code in case someone wants to take it further.
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Text;
using System.Threading;
using System.Security.AccessControl;
using System.Security.Principal;
namespace FileLockInfo
{
public class Win32API
{
[DllImport("ntdll.dll")]
public static extern int NtQueryObject(IntPtr ObjectHandle, int
ObjectInformationClass, IntPtr ObjectInformation, int ObjectInformationLength,
ref int returnLength);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern uint QueryDosDevice(string lpDeviceName, StringBuilder lpTargetPath, int ucchMax);
[DllImport("ntdll.dll")]
public static extern uint NtQuerySystemInformation(int
SystemInformationClass, IntPtr SystemInformation, int SystemInformationLength,
ref int returnLength);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr OpenMutex(UInt32 desiredAccess, bool inheritHandle, string name);
[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, int dwProcessId);
[DllImport("kernel32.dll")]
public static extern int CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DuplicateHandle(IntPtr hSourceProcessHandle,
ushort hSourceHandle, IntPtr hTargetProcessHandle, out IntPtr lpTargetHandle,
uint dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwOptions);
[DllImport("kernel32.dll")]
public static extern IntPtr GetCurrentProcess();
public enum ObjectInformationClass : int
{
ObjectBasicInformation = 0,
ObjectNameInformation = 1,
ObjectTypeInformation = 2,
ObjectAllTypesInformation = 3,
ObjectHandleInformation = 4
}
[Flags]
public enum ProcessAccessFlags : uint
{
All = 0x001F0FFF,
Terminate = 0x00000001,
CreateThread = 0x00000002,
VMOperation = 0x00000008,
VMRead = 0x00000010,
VMWrite = 0x00000020,
DupHandle = 0x00000040,
SetInformation = 0x00000200,
QueryInformation = 0x00000400,
Synchronize = 0x00100000
}
[StructLayout(LayoutKind.Sequential)]
public struct OBJECT_BASIC_INFORMATION
{ // Information Class 0
public int Attributes;
public int GrantedAccess;
public int HandleCount;
public int PointerCount;
public int PagedPoolUsage;
public int NonPagedPoolUsage;
public int Reserved1;
public int Reserved2;
public int Reserved3;
public int NameInformationLength;
public int TypeInformationLength;
public int SecurityDescriptorLength;
public System.Runtime.InteropServices.ComTypes.FILETIME CreateTime;
}
[StructLayout(LayoutKind.Sequential)]
public struct OBJECT_TYPE_INFORMATION
{ // Information Class 2
public UNICODE_STRING Name;
public int ObjectCount;
public int HandleCount;
public int Reserved1;
public int Reserved2;
public int Reserved3;
public int Reserved4;
public int PeakObjectCount;
public int PeakHandleCount;
public int Reserved5;
public int Reserved6;
public int Reserved7;
public int Reserved8;
public int InvalidAttributes;
public GENERIC_MAPPING GenericMapping;
public int ValidAccess;
public byte Unknown;
public byte MaintainHandleDatabase;
public int PoolType;
public int PagedPoolUsage;
public int NonPagedPoolUsage;
}
[StructLayout(LayoutKind.Sequential)]
public struct OBJECT_NAME_INFORMATION
{ // Information Class 1
public UNICODE_STRING Name;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct UNICODE_STRING
{
public ushort Length;
public ushort MaximumLength;
public IntPtr Buffer;
}
[StructLayout(LayoutKind.Sequential)]
public struct GENERIC_MAPPING
{
public int GenericRead;
public int GenericWrite;
public int GenericExecute;
public int GenericAll;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct SYSTEM_HANDLE_INFORMATION
{ // Information Class 16
public int ProcessID;
public byte ObjectTypeNumber;
public byte Flags; // 0x01 = PROTECT_FROM_CLOSE, 0x02 = INHERIT
public ushort Handle;
public int Object_Pointer;
public UInt32 GrantedAccess;
}
public const int MAX_PATH = 260;
public const uint STATUS_INFO_LENGTH_MISMATCH = 0xC0000004;
public const int DUPLICATE_SAME_ACCESS = 0x2;
public const int DUPLICATE_CLOSE_SOURCE = 0x1;
}
public class Win32Processes
{
const int CNST_SYSTEM_HANDLE_INFORMATION = 16;
const uint STATUS_INFO_LENGTH_MISMATCH = 0xc0000004;
public static string getObjectTypeName(Win32API.SYSTEM_HANDLE_INFORMATION shHandle, Process process)
{
IntPtr m_ipProcessHwnd = Win32API.OpenProcess(Win32API.ProcessAccessFlags.All, false, process.Id);
IntPtr ipHandle = IntPtr.Zero;
var objBasic = new Win32API.OBJECT_BASIC_INFORMATION();
IntPtr ipBasic = IntPtr.Zero;
var objObjectType = new Win32API.OBJECT_TYPE_INFORMATION();
IntPtr ipObjectType = IntPtr.Zero;
IntPtr ipObjectName = IntPtr.Zero;
string strObjectTypeName = "";
int nLength = 0;
int nReturn = 0;
IntPtr ipTemp = IntPtr.Zero;
if (!Win32API.DuplicateHandle(m_ipProcessHwnd, shHandle.Handle,
Win32API.GetCurrentProcess(), out ipHandle,
0, false, Win32API.DUPLICATE_SAME_ACCESS))
return null;
ipBasic = Marshal.AllocHGlobal(Marshal.SizeOf(objBasic));
Win32API.NtQueryObject(ipHandle, (int)Win32API.ObjectInformationClass.ObjectBasicInformation,
ipBasic, Marshal.SizeOf(objBasic), ref nLength);
objBasic = (Win32API.OBJECT_BASIC_INFORMATION)Marshal.PtrToStructure(ipBasic, objBasic.GetType());
Marshal.FreeHGlobal(ipBasic);
ipObjectType = Marshal.AllocHGlobal(objBasic.TypeInformationLength);
nLength = objBasic.TypeInformationLength;
while ((uint)(nReturn = Win32API.NtQueryObject(
ipHandle, (int)Win32API.ObjectInformationClass.ObjectTypeInformation, ipObjectType,
nLength, ref nLength)) ==
Win32API.STATUS_INFO_LENGTH_MISMATCH)
{
Marshal.FreeHGlobal(ipObjectType);
ipObjectType = Marshal.AllocHGlobal(nLength);
}
objObjectType = (Win32API.OBJECT_TYPE_INFORMATION)Marshal.PtrToStructure(ipObjectType, objObjectType.GetType());
if (Is64Bits())
{
ipTemp = new IntPtr(Convert.ToInt64(objObjectType.Name.Buffer.ToString(), 10) >> 32);
}
else
{
ipTemp = objObjectType.Name.Buffer;
}
strObjectTypeName = Marshal.PtrToStringUni(ipTemp, objObjectType.Name.Length >> 1);
Marshal.FreeHGlobal(ipObjectType);
return strObjectTypeName;
}
public static string getObjectName(Win32API.SYSTEM_HANDLE_INFORMATION shHandle, Process process)
{
IntPtr m_ipProcessHwnd = Win32API.OpenProcess(Win32API.ProcessAccessFlags.All, false, process.Id);
IntPtr ipHandle = IntPtr.Zero;
var objBasic = new Win32API.OBJECT_BASIC_INFORMATION();
IntPtr ipBasic = IntPtr.Zero;
IntPtr ipObjectType = IntPtr.Zero;
var objObjectName = new Win32API.OBJECT_NAME_INFORMATION();
IntPtr ipObjectName = IntPtr.Zero;
string strObjectName = "";
int nLength = 0;
int nReturn = 0;
IntPtr ipTemp = IntPtr.Zero;
if (!Win32API.DuplicateHandle(m_ipProcessHwnd, shHandle.Handle, Win32API.GetCurrentProcess(),
out ipHandle, 0, false, Win32API.DUPLICATE_SAME_ACCESS))
return null;
ipBasic = Marshal.AllocHGlobal(Marshal.SizeOf(objBasic));
Win32API.NtQueryObject(ipHandle, (int)Win32API.ObjectInformationClass.ObjectBasicInformation,
ipBasic, Marshal.SizeOf(objBasic), ref nLength);
objBasic = (Win32API.OBJECT_BASIC_INFORMATION)Marshal.PtrToStructure(ipBasic, objBasic.GetType());
Marshal.FreeHGlobal(ipBasic);
nLength = objBasic.NameInformationLength;
ipObjectName = Marshal.AllocHGlobal(nLength);
while ((uint)(nReturn = Win32API.NtQueryObject(
ipHandle, (int)Win32API.ObjectInformationClass.ObjectNameInformation,
ipObjectName, nLength, ref nLength))
== Win32API.STATUS_INFO_LENGTH_MISMATCH)
{
Marshal.FreeHGlobal(ipObjectName);
ipObjectName = Marshal.AllocHGlobal(nLength);
}
objObjectName = (Win32API.OBJECT_NAME_INFORMATION)Marshal.PtrToStructure(ipObjectName, objObjectName.GetType());
if (Is64Bits())
{
ipTemp = new IntPtr(Convert.ToInt64(objObjectName.Name.Buffer.ToString(), 10) >> 32);
}
else
{
ipTemp = objObjectName.Name.Buffer;
}
if (ipTemp != IntPtr.Zero)
{
byte[] baTemp2 = new byte[nLength];
try
{
Marshal.Copy(ipTemp, baTemp2, 0, nLength);
strObjectName = Marshal.PtrToStringUni(Is64Bits() ?
new IntPtr(ipTemp.ToInt64()) :
new IntPtr(ipTemp.ToInt32()));
return strObjectName;
}
catch (AccessViolationException)
{
return null;
}
finally
{
Marshal.FreeHGlobal(ipObjectName);
Win32API.CloseHandle(ipHandle);
}
}
return null;
}
public static List<Win32API.SYSTEM_HANDLE_INFORMATION>
GetHandles(Process process = null, string IN_strObjectTypeName = null, string IN_strObjectName = null)
{
uint nStatus;
int nHandleInfoSize = 0x10000;
IntPtr ipHandlePointer = Marshal.AllocHGlobal(nHandleInfoSize);
int nLength = 0;
IntPtr ipHandle = IntPtr.Zero;
while ((nStatus = Win32API.NtQuerySystemInformation(CNST_SYSTEM_HANDLE_INFORMATION, ipHandlePointer,
nHandleInfoSize, ref nLength)) ==
STATUS_INFO_LENGTH_MISMATCH)
{
nHandleInfoSize = nLength;
Marshal.FreeHGlobal(ipHandlePointer);
ipHandlePointer = Marshal.AllocHGlobal(nLength);
}
byte[] baTemp = new byte[nLength];
Marshal.Copy(ipHandlePointer, baTemp, 0, nLength);
long lHandleCount = 0;
if (Is64Bits())
{
lHandleCount = Marshal.ReadInt64(ipHandlePointer);
ipHandle = new IntPtr(ipHandlePointer.ToInt64() + 8);
}
else
{
lHandleCount = Marshal.ReadInt32(ipHandlePointer);
ipHandle = new IntPtr(ipHandlePointer.ToInt32() + 4);
}
Win32API.SYSTEM_HANDLE_INFORMATION shHandle;
List<Win32API.SYSTEM_HANDLE_INFORMATION> lstHandles = new List<Win32API.SYSTEM_HANDLE_INFORMATION>();
for (long lIndex = 0; lIndex < lHandleCount; lIndex++)
{
shHandle = new Win32API.SYSTEM_HANDLE_INFORMATION();
if (Is64Bits())
{
shHandle = (Win32API.SYSTEM_HANDLE_INFORMATION)Marshal.PtrToStructure(ipHandle, shHandle.GetType());
ipHandle = new IntPtr(ipHandle.ToInt64() + Marshal.SizeOf(shHandle) + 8);
}
else
{
ipHandle = new IntPtr(ipHandle.ToInt64() + Marshal.SizeOf(shHandle));
shHandle = (Win32API.SYSTEM_HANDLE_INFORMATION)Marshal.PtrToStructure(ipHandle, shHandle.GetType());
}
if (process != null)
{
if (shHandle.ProcessID != process.Id) continue;
}
string strObjectTypeName = "";
if (IN_strObjectTypeName != null){
strObjectTypeName = getObjectTypeName(shHandle, Process.GetProcessById(shHandle.ProcessID));
if (strObjectTypeName != IN_strObjectTypeName) continue;
}
string strObjectName = "";
if (IN_strObjectName != null){
strObjectName = getObjectName(shHandle, Process.GetProcessById(shHandle.ProcessID));
if (strObjectName != IN_strObjectName) continue;
}
string strObjectTypeName2 = getObjectTypeName(shHandle, Process.GetProcessById(shHandle.ProcessID));
string strObjectName2 = getObjectName(shHandle, Process.GetProcessById(shHandle.ProcessID));
Console.WriteLine("{0} {1} {2}", shHandle.ProcessID, strObjectTypeName2, strObjectName2);
lstHandles.Add(shHandle);
}
return lstHandles;
}
public static bool Is64Bits()
{
return Marshal.SizeOf(typeof(IntPtr)) == 8 ? true : false;
}
}
class Program
{
static void Main(string[] args)
{
String MutexName = "MSCTF.Asm.MutexDefault1";
String ProcessName = "notepad";
try
{
Process process = Process.GetProcessesByName(ProcessName)[0];
var handles = Win32Processes.GetHandles(process, "Mutant", "\\Sessions\\1\\BaseNamedObjects\\" + MutexName);
if (handles.Count == 0) throw new System.ArgumentException("NoMutex", "original");
foreach (var handle in handles)
{
IntPtr ipHandle = IntPtr.Zero;
if (!Win32API.DuplicateHandle(Process.GetProcessById(handle.ProcessID).Handle, handle.Handle, Win32API.GetCurrentProcess(), out ipHandle, 0, false, Win32API.DUPLICATE_CLOSE_SOURCE))
Console.WriteLine("DuplicateHandle() failed, error = {0}", Marshal.GetLastWin32Error());
Console.WriteLine("Mutex was killed");
}
}
catch (IndexOutOfRangeException)
{
Console.WriteLine("The process name '{0}' is not currently running", ProcessName);
}
catch (ArgumentException)
{
Console.WriteLine("The Mutex '{0}' was not found in the process '{1}'", MutexName, ProcessName);
}
Console.ReadLine();
}
}
}
You need elevated privileges for that - especially DEBUG privilege.
See:
Manipulate Privileges in Managed Code Reliably, Securely, and Efficiently (MSDN)
Debug Privilege (MSDN)
The Windows Access Control Model Part 3
Simon Mourier's answer to Stack Overflow question How to enable the SeCreateGlobalPrivilege in .NET without resorting to P/Invoke or reflection?
ObjectSecurity Methods (MSDN)
I want to read the environment variables of process B from C# code in process A. I have seen some solutions for this in C++ but haven't tried adapting these to C#.
Is this possible from C#, and if not, has anyone wrapped a C++ solution yet?
I've skimmed through the links provided by Isalamon and Daniel Hilgarth, and also the code in CLR Profiler's GetServicesEnvironment() method which seems to be doing the same thing, and after a bit of testing found that the most reliable solution is Oleksiy's code (pure C# with P/Invoke) which he published in this blog post. It still has the limitation, where you have to be a 64bit process to read the env vars of another 64bit process.
Windows solution (32 bit CLR, can access 32 and 64 bit processes),
slightly modified from https://stackoverflow.com/a/46006415 :
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
// Slightly modified from
// https://stackoverflow.com/questions/2633628/can-i-get-command-line-arguments-of-other-processes-from-net-c
// https://stackoverflow.com/a/46006415
public static class ProcessCommandLine
{
private static class Win32Native
{
public const uint PROCESS_BASIC_INFORMATION = 0;
[Flags]
public enum OpenProcessDesiredAccessFlags : uint
{
PROCESS_VM_READ = 0x0010,
PROCESS_QUERY_INFORMATION = 0x0400,
}
[StructLayout(LayoutKind.Sequential)]
public struct ProcessBasicInformation
{
public IntPtr Reserved1;
public IntPtr PebBaseAddress;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public IntPtr[] Reserved2;
public IntPtr UniqueProcessId;
public IntPtr ParentProcessId;
}
[StructLayout(LayoutKind.Sequential)]
public struct ProcessBasicInformation64
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public IntPtr[] Reserved1;
public UInt64 PebBaseAddress;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public IntPtr[] Reserved2;
public IntPtr UniqueProcessId;
public IntPtr Reserved3;
public IntPtr ParentProcessId;
public IntPtr Reserved4;
}
[StructLayout(LayoutKind.Sequential)]
public struct UnicodeString
{
public ushort Length;
public ushort MaximumLength;
public IntPtr Buffer;
}
[StructLayout(LayoutKind.Sequential)]
public struct UnicodeString64
{
public ushort Length;
public ushort MaximumLength;
public UInt32 __padding;
public UInt64 Buffer;
}
// This is not the real struct!
// I faked it to get ProcessParameters address.
// Actual struct definition:
// https://learn.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-peb
[StructLayout(LayoutKind.Sequential)]
public struct PEB
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public IntPtr[] Reserved;
public IntPtr ProcessParameters;
}
[StructLayout(LayoutKind.Sequential)]
public struct PEB64
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public IntPtr[] Reserved;
public UInt64 ProcessParameters;
}
/*
* https://stackoverflow.com/a/63222041
Left: Right:
32-bit struct 64-bit struct
0
ULONG MaximumLength; 0
ULONG Length; 4
ULONG Flags; 8
ULONG DebugFlags; 0c
10
PVOID ConsoleHandle; 10
ULONG ConsoleFlags; 18 +4
PVOID StdInputHandle; 20
PVOID StdOutputHandle; 28
20
PVOID StdErrorHandle; 30
UNICODE_STRING CurrentDirectoryPath; 38
PVOID CurrentDirectoryHandle; 48
30
UNICODE_STRING DllPath; 50
UNICODE_STRING ImagePathName; 60
40
UNICODE_STRING CommandLine 70
PVOID Environment; 80
ULONG StartingPositionLeft;
50
ULONG StartingPositionTop;\
ULONG Width;\
ULONG Height;\
ULONG CharWidth;\
60
ULONG CharHeight;\
ULONG ConsoleTextAttributes;\
ULONG WindowFlags;\
ULONG ShowWindowFlags;\
70
UNICODE_STRING WindowTitle; b0
UNICODE_STRING DesktopName; c0
80
UNICODE_STRING ShellInfo; d0
UNICODE_STRING RuntimeData; e0
90
RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[32];\
ULONG EnvironmentSize;\
*/
[StructLayout(LayoutKind.Sequential)]
public struct RtlUserProcessParameters
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public byte[] Reserved1;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public IntPtr[] Reserved2;
public UnicodeString ImagePathName;
public UnicodeString CommandLine;
public IntPtr Environment;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)]
public IntPtr[] Reserved3; // StartingPositionLeft, -Top, Width, Height, CharWidth, -Height, ConsoleTextAttributes, WindowFlags, ShowWindowFlags
public UnicodeString WindowTitle;
public UnicodeString DesktopName;
public UnicodeString ShellInfo;
public UnicodeString RuntimeData;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32 * 4)]
public IntPtr[] Reserved4;
public uint EnvironmentSize;
}
[StructLayout(LayoutKind.Sequential)]
public struct RtlUserProcessParameters64
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public byte[] Reserved1;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public IntPtr[] Reserved2;
public UnicodeString64 CurrentDirectoryPath;
public UnicodeString64 DllPath;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public IntPtr[] Reserved2b;
public UnicodeString64 ImagePathName;
public UnicodeString64 CommandLine;
public UInt64 Environment;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)]
public IntPtr[] Reserved3; // StartingPositionLeft, -Top, Width, Height, CharWidth, -Height, ConsoleTextAttributes, WindowFlags, ShowWindowFlags
public UnicodeString64 WindowTitle;
public UnicodeString64 DesktopName;
public UnicodeString64 ShellInfo;
public UnicodeString64 RuntimeData;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32 * 6)]
public IntPtr[] Reserved4;
public uint EnvironmentSize;
}
[DllImport("ntdll.dll")]
public static extern uint NtQueryInformationProcess(
IntPtr ProcessHandle,
uint ProcessInformationClass,
IntPtr ProcessInformation,
uint ProcessInformationLength,
out uint ReturnLength);
[DllImport("ntdll.dll")]
public static extern uint NtWow64QueryInformationProcess64(
IntPtr ProcessHandle,
uint ProcessInformationClass,
IntPtr ProcessInformation,
uint ProcessInformationLength,
out uint ReturnLength);
[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(
OpenProcessDesiredAccessFlags dwDesiredAccess,
[MarshalAs(UnmanagedType.Bool)] bool bInheritHandle,
uint dwProcessId);
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ReadProcessMemory(
IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer,
uint nSize, out uint lpNumberOfBytesRead);
[DllImport("ntdll.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool NtWow64ReadVirtualMemory64(
IntPtr hProcess, UInt64 lpBaseAddress, IntPtr lpBuffer,
UInt64 nSize, out UInt64 lpNumberOfBytesRead);
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CloseHandle(IntPtr hObject);
[DllImport("shell32.dll", SetLastError = true,
CharSet = CharSet.Unicode, EntryPoint = "CommandLineToArgvW")]
public static extern IntPtr CommandLineToArgv(string lpCmdLine, out int pNumArgs);
}
private static bool ReadProcessMemory(IntPtr hProcess, UInt64 lpBaseAddress, IntPtr mem, UInt32 sz, bool force64)
{
if (!force64 && (ulong)0x100000000 > lpBaseAddress)
return Win32Native.ReadProcessMemory(hProcess, (IntPtr)lpBaseAddress, mem, sz, out UInt32 read) && read == sz;
Win32Native.NtWow64ReadVirtualMemory64(hProcess, lpBaseAddress, mem, sz, out UInt64 len64);
return len64 == sz;
}
private static bool ReadStructFromProcessMemory<TStruct>(
IntPtr hProcess, IntPtr lpBaseAddress, out TStruct val, bool bit64 = false)
{
return ReadStructFromProcessMemory<TStruct>(hProcess, (UInt64)lpBaseAddress, out val, bit64);
}
private static bool ReadStructFromProcessMemory<TStruct>(
IntPtr hProcess, UInt64 lpBaseAddress, out TStruct val, bool bit64 = false)
{
val = default;
var structSize = Marshal.SizeOf<TStruct>();
var mem = Marshal.AllocHGlobal(structSize);
try
{
bool ret = ReadProcessMemory(hProcess, lpBaseAddress, mem, (UInt32)structSize, bit64);
if (ret)
{
val = Marshal.PtrToStructure<TStruct>(mem);
return true;
}
}
finally
{
Marshal.FreeHGlobal(mem);
}
return false;
}
public static string ErrorToString(int error) =>
new string[]
{
"Success",
"Failed to open process for reading",
"Failed to query process information",
"PEB address was null",
"Failed to read PEB information",
"Failed to read process parameters",
"Failed to read command line from process",
"Failed to read environment from process",
}[Math.Abs(error)];
public static int Retrieve(Process process, out string commandLine, out List<string> environment)
{
int rc = 0;
commandLine = null;
environment = null;
var hProcess = Win32Native.OpenProcess(
Win32Native.OpenProcessDesiredAccessFlags.PROCESS_QUERY_INFORMATION |
Win32Native.OpenProcessDesiredAccessFlags.PROCESS_VM_READ, false, (uint)process.Id);
if (hProcess != IntPtr.Zero)
{
try
{
var sizePBI = Marshal.SizeOf<Win32Native.ProcessBasicInformation>();
var sizePBI64 = Marshal.SizeOf<Win32Native.ProcessBasicInformation64>();
var memPBI = Marshal.AllocHGlobal(sizePBI64);
try
{
bool bit64;
var ret = Win32Native.NtQueryInformationProcess(
hProcess, Win32Native.PROCESS_BASIC_INFORMATION, memPBI,
(uint)sizePBI, out var len);
if (0 == ret)
{
var pbiInfo64 = new Win32Native.ProcessBasicInformation64();
var pbiInfo = Marshal.PtrToStructure<Win32Native.ProcessBasicInformation>(memPBI);
if (pbiInfo.PebBaseAddress != IntPtr.Zero)
{
bit64 = false;
}
else
{
bit64 = true;
ret = Win32Native.NtWow64QueryInformationProcess64(
hProcess, Win32Native.PROCESS_BASIC_INFORMATION, memPBI,
(uint)sizePBI64, out len);
pbiInfo64 = Marshal.PtrToStructure<Win32Native.ProcessBasicInformation64>(memPBI);
}
if (pbiInfo64.PebBaseAddress != (UInt64)0)
{
Win32Native.PEB64 pebInfo64;
Win32Native.PEB pebInfo;
pebInfo.ProcessParameters = (IntPtr)0; pebInfo64.ProcessParameters = (UInt64)0;
bool ok;
if (bit64)
ok = ReadStructFromProcessMemory<Win32Native.PEB64>(hProcess, pbiInfo64.PebBaseAddress, out pebInfo64, bit64);
else
ok = ReadStructFromProcessMemory<Win32Native.PEB>(hProcess, pbiInfo.PebBaseAddress, out pebInfo, bit64);
if (ok)
{
UInt32 CommandLineSize = 0;
UInt64 CommandLineBuf = 0;
UInt32 EnvironmentSize = 0;
UInt64 EnvironmentBuf = 0;
if (bit64)
{
ok = ReadStructFromProcessMemory<Win32Native.RtlUserProcessParameters64>(hProcess, pebInfo64.ProcessParameters, out var ruppInfo64, bit64);
CommandLineSize = (UInt32)ruppInfo64.CommandLine.MaximumLength;
CommandLineBuf = ruppInfo64.CommandLine.Buffer;
EnvironmentSize = (UInt32)ruppInfo64.EnvironmentSize;
EnvironmentBuf = ruppInfo64.Environment;
}
else
{
ok = ReadStructFromProcessMemory<Win32Native.RtlUserProcessParameters>(hProcess, (UInt64)pebInfo.ProcessParameters, out var ruppInfo, bit64);
CommandLineSize = ruppInfo.CommandLine.MaximumLength;
CommandLineBuf = (UInt64)ruppInfo.CommandLine.Buffer;
EnvironmentSize = ruppInfo.EnvironmentSize;
EnvironmentBuf = (UInt64)ruppInfo.Environment;
}
if (ok)
{
var memCL = Marshal.AllocHGlobal((IntPtr)CommandLineSize);
try
{
if (ReadProcessMemory(hProcess, CommandLineBuf, memCL, CommandLineSize, bit64))
{
commandLine = Marshal.PtrToStringUni(memCL);
rc = 0;
}
else
{
// couldn't read command line buffer
rc = -6;
}
}
finally
{
Marshal.FreeHGlobal(memCL);
}
memCL = Marshal.AllocHGlobal((IntPtr)EnvironmentSize);
try
{
if (ReadProcessMemory(hProcess, EnvironmentBuf, memCL, EnvironmentSize, bit64))
{
environment = new List<string>(40);
IntPtr readPtr = memCL;
while (EnvironmentSize > 0 && Marshal.ReadInt16(readPtr) != 0)
{
string slice = Marshal.PtrToStringUni(readPtr);
environment.Add(slice);
uint size = 0;
do
{
size += 2;
readPtr += 2;
}
while (Marshal.ReadInt16(readPtr) != 0);
size += 2;
readPtr += 2;
EnvironmentSize -= size;
}
rc = 0;
}
else
{
// couldn't read command line buffer
rc = -7;
}
}
finally
{
Marshal.FreeHGlobal(memCL);
}
}
else
{
// couldn't read ProcessParameters
rc = -5;
}
}
else
{
// couldn't read PEB information
rc = -4;
}
}
else
{
// PebBaseAddress is null
rc = -3;
}
}
else
{
// NtQueryInformationProcess failed
rc = -2;
}
}
finally
{
Marshal.FreeHGlobal(memPBI);
}
}
finally
{
Win32Native.CloseHandle(hProcess);
}
}
else
{
// couldn't open process for VM read
rc = -1;
}
return rc;
}
public static IReadOnlyList<string> CommandLineToArgs(string commandLine)
{
if (string.IsNullOrEmpty(commandLine)) { return new string[] { }; }
var argv = Win32Native.CommandLineToArgv(commandLine, out var argc);
if (argv == IntPtr.Zero)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
try
{
var args = new string[argc];
for (var i = 0; i < args.Length; ++i)
{
var p = Marshal.ReadIntPtr(argv, i * IntPtr.Size);
args[i] = Marshal.PtrToStringUni(p);
}
return args.ToList().AsReadOnly();
}
finally
{
Marshal.FreeHGlobal(argv);
}
}
}
Linux solution (32 and 64 bit can be freely mixed):
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
public static class ProcessCommandLine
{
public static int Retrieve(Process process, out string commandLine, out List<string> environment)
{
int pid = process.Id;
try
{
commandLine = File.ReadAllText("/proc/" + pid + "/cmdline").Replace('\0', ' ');
environment = File.ReadAllText("/proc/" + pid + "/environ").Split('\0').ToList();
return 0;
}
catch (Exception e)
{
commandLine = null; environment = null;
Console.WriteLine("ProcessCommandLine: Cannot read file - maybe you have to 'sudo mount -t procfs none /proc'? Maybe you have insufficient rights?");
Console.WriteLine("ProcessCommandLine: Exception was: " + e.GetType() + ": " + e.Message);
}
return -11;
}
}