Using SCardGetStatusChange to be notified of card insert/remove without polling - c#

I'm trying to detect when a card has been inserted into a reader.
If I do a nasty polling loop like this:
public struct SCARD_READERSTATE
{
[MarshalAs(UnmanagedType.LPWStr)]
public string szReader;
public byte[] pvUserData;
public byte[] rgbAtr;
public uint dwCurrentState;
public uint dwEventState;
public uint cbAtr;
}
byte[] atr = null;
SCARD_READERSTATE[] rs = new SCARD_READERSTATE[1];
rs[0].szReader = readersList[0];
rs[0].dwCurrentState = SCARD_STATE_UNAWARE;
rs[0].dwEventState = SCARD_STATE_PRESENT;
int hctx = hContext.ToInt32();
var cardResult = SCardGetStatusChange(hctx, 100, rs, 1);
if (cardResult == 0 && rs[0].cbAtr > 0 && rs[0].rgbAtr != null)
{
atr = new byte[rs[0].cbAtr];
Array.Copy(rs[0].rgbAtr, atr, rs[0].cbAtr);
}
while ( (rs[0].dwCurrentState & SCARD_STATE_PRESENT) == 0)
{
rs = new SCARD_READERSTATE[1];
rs[0].szReader = readersList[0];
//rs[0].dwCurrentState = SCARD_STATE_PRESENT;
//rs[0].dwEventState = SCARD_STATE_PRESENT;
SCardGetStatusChange(hctx, 100000000, rs, 1);
System.Threading.Thread.Sleep(1000);
}
it works, but it has a nasty thread sleep in it. Ideally I'd like to make a blocking call to SCardGetStatusChange on a background thread and then surface up the events.
Apparently by setting the szReader to the value "\\?PnP?\Notification" it should block, as long as everything else in the struct is 0.
I've changed the code to
rs[0].szReader = "\\\\?PnP?\\Notification";
rs[0].cbAtr = 0;
rs[0].dwCurrentState = 0;
rs[0].dwEventState = 0;
rs[0].pvUserData = new byte[0];
rs[0].rgbAtr = new byte0];
SCardGetStatusChange(hctx, 100000000, rs, 1);
but it just returns a success result immediately. Can any pInvoke masters out there see what's wrong?

In your sample the second call to SCardGetStatusChange should block if you copy dwEventState into dwCurrentState and then reset dwEventState, so there's no need for the sleep.
The "\\?PnP?\Notification" struct is to tell you when a new smart card reader has been attached, not when a card has been inserted. From the MSDN page on SCardGetStatusChange:
To be notified of the arrival of a new smart card reader, set the szReader member of a SCARD_READERSTATE structure to "\\?PnP?\Notification", and set all of the other members of that structure to zero.
When using the "\\?PnP?\Notification" struct:
the pvUserData and rgbAttr fields should be set to null
a new byte[0] is a valid pointer to a zero length array, but what the API needs here is null pointers or zero values)
the high 16 bits of dwCurrentState should contain the current reader count
i.e. rs[0].dwCurrentState = (readerCount << 16);
the MSDN page is currently inaccurate on this point.

Related

Using the same function yields different results?

Going from Framework 4.5 to Net 6.0 for an old project, there is an function that has broken immensely. When using the function for the 1st time, it returns the value 1651. Running the same function for a 2nd time, it returns a 0 value. This has caused an issue where our program cannot open the PKG file properly (it fails reading the 2nd value count.). I am wondering if there's a quick fix to be done?
The File Check (The code using the broken function): Github ArkPackage.cs
private void readNewFileTable(Stream header, bool readHash = false)
{
uint numFiles = header.ReadUInt32LE();
var files = new OffsetFile[numFiles];
for (var i = 0; i < numFiles; i++)
{
// Version 3 uses 32-bit file offsets
long arkFileOffset = header.ReadInt64LE();
string path = header.ReadLengthPrefixedString(System.Text.Encoding.UTF8);
var flags = header.ReadInt32LE();
uint size = header.ReadUInt32LE();
if (readHash) header.Seek(4, SeekOrigin.Current); // Skips checksum
var finalSlash = path.LastIndexOf('/');
var fileDir = path.Substring(0, finalSlash < 0 ? 0 : finalSlash);
var fileName = path.Substring(finalSlash < 0 ? 0 : (finalSlash + 1));
var parent = makeOrGetDir(fileDir);
var file = new OffsetFile(fileName, parent, contentFileMeta, arkFileOffset, size);
file.ExtendedInfo["id"] = i;
file.ExtendedInfo["flags"] = flags;
files[i] = file;
parent.AddFile(file);
}
var numFiles2 = header.ReadUInt32LE();
if(numFiles != numFiles2)
throw new Exception("Ark header appears invalid (file count mismatch)");
for(var i = 0; i < numFiles2; i++)
{
files[i].ExtendedInfo["flags2"] = header.ReadInt32LE();
}
The Broken Function (L154 is a variation that uses 161-171): Github StreamExtensions.cs
public static uint ReadUInt32LE(this Stream s) => unchecked((uint)s.ReadInt32LE());
/// <summary>
/// Read a signed 32-bit little-endian integer from the stream.
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static int ReadInt32LE(this Stream s)
{
int ret;
byte[] tmp = new byte[4];
s.Read(tmp, 0, 4);
ret = tmp[0] & 0x000000FF;
ret |= (tmp[1] << 8) & 0x0000FF00;
ret |= (tmp[2] << 16) & 0x00FF0000;
ret |= (tmp[3] << 24);
return ret;
}
Before (Framework 4.5):
After (Net 6.0):
Starting in .Net 5, I believe it was, FileStream.Read doesn't block until the entire amount of data requested is available, it instead reads at most as many characters as instructed. Check the return value to see how much it read
If you want to read exactly as many characters as you want, either use a loop or use BinaryReader.ReadBytes which implements the loop for you.
Also that bit of code speaks volumes about the general quality of whatever library that is. You shouldn't be allocating arrays like that anymore, this isn't the 90's.

How to get port a process is listening on in .net?

As several blogposts and Stackoverflow answers suggest, it is trivial to get this information via a combination of get-process and Get-NetTCPConnection commandlets. It is possible to execute these commands via .net code, parse the output and retrieve the information.
Is it not possible to get the port number a process is listening on in pure .net code using just the .net libraries? System.Diagnostics.Process.GetProcesByName returns a ton of information via the Process object, except for the port the process is listening on.
Any leads highly appreciated.
Unfortunately, IPGlobalProperties.GetIPGlobalProperties() does not return any information on which process is holding the socket, as it uses GetTcpTable not GetTcpTable2.
You would need to code it yourself. The below code works for TCP over IPv4. You would need similar code for UDP and IPv6.
[DllImport("Iphlpapi.dll", ExactSpelling = true)]
static extern int GetTcpTable2(
IntPtr TcpTable,
ref int SizePointer,
bool Order
);
[StructLayout(LayoutKind.Sequential)]
struct MIB_TCPTABLE
{
public int dwNumEntries;
}
[StructLayout(LayoutKind.Sequential)]
struct MIB_TCPROW2
{
public MIB_TCP_STATE dwState;
public int dwLocalAddr;
public byte localPort1;
public byte localPort2;
// Ports are only 16 bit values (in network WORD order, 3,4,1,2).
// There are reports where the high order bytes have garbage in them.
public byte ignoreLocalPort3;
public byte ignoreLocalPort4;
public int dwRemoteAddr;
public byte remotePort1;
public byte remotePort2;
// Ports are only 16 bit values (in network WORD order, 3,4,1,2).
// There are reports where the high order bytes have garbage in them.
public byte ignoreremotePort3;
public byte ignoreremotePort4;
public int dwOwningPid;
public TCP_CONNECTION_OFFLOAD_STATE dwOffloadState;
}
public enum MIB_TCP_STATE
{
Closed = 1,
Listen,
SynSent,
SynRcvd,
Established,
FinWait1,
FinWait2,
CloseWait,
Closing,
LastAck,
TimeWait,
DeleteTcb
}
enum TCP_CONNECTION_OFFLOAD_STATE
{
TcpConnectionOffloadStateInHost,
TcpConnectionOffloadStateOffloading,
TcpConnectionOffloadStateOffloaded,
TcpConnectionOffloadStateUploading,
TcpConnectionOffloadStateMax
}
static List<IPEndPoint> GetSocketsForProcess(int pid, MIB_TCP_STATE state = MIB_TCP_STATE.Established)
{
const int ERROR_INSUFFICIENT_BUFFER = 0x7A;
var size = 0;
var result = GetTcpTable2(IntPtr.Zero, ref size, false);
if (result != ERROR_INSUFFICIENT_BUFFER)
throw new Win32Exception(result);
var ptr = IntPtr.Zero;
try
{
ptr = Marshal.AllocHGlobal(size);
result = GetTcpTable2(ptr, ref size, false);
if (result != 0)
throw new Win32Exception(result);
var list = new List<IPEndPoint>();
var count = Marshal.ReadInt32(ptr);
var curPtr = ptr + Marshal.SizeOf<MIB_TCPTABLE>();
var length = Marshal.SizeOf<MIB_TCPROW2>();
for(var i = 0; i < count; i++)
{
var row = Marshal.PtrToStructure<MIB_TCPROW2>(curPtr);
if(row.dwOwningPid == pid && row.dwState == state)
list.Add(new IPEndPoint(row.dwLocalAddr, row.localPort1 << 8 | row.localPort2));
curPtr += length;
}
return list;
}
finally
{
Marshal.FreeHGlobal(ptr);
}
}
I had similar task not long ago. Here is complete .NET 6 code that you should be able to adopt for your particular needs:
public static int CheckConnection(string[] servers)
{
try
{
var srvs = servers.ToDictionary(k => k.Split("/", StringSplitOptions.RemoveEmptyEntries)[1], v => false);
IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
IPEndPoint[] endPoints = ipProperties.GetActiveTcpListeners();
TcpConnectionInformation[] tcpConnections = ipProperties.GetActiveTcpConnections();
var count = 0;
foreach (var info in tcpConnections)
{
var ep = string.Format("{0}:{1}", info.RemoteEndPoint.Address, info.RemoteEndPoint.Port);
if (info.State.ToString().ToUpper() != "ESTABLISHED")
continue;
if (srvs.ContainsKey(ep))
{
count++;
srvs[ep] = true;
}
}
var sb = new StringBuilder();
foreach (var kvp in srvs)
{
sb.AppendFormat("{0,-21}: {1}", kvp.Key, kvp.Value ? "OK" : "FAIL");
sb.AppendLine();
}
Program.logger.Trace($"ZMQF. Connection check:\n{sb}");
return count;
}
catch (Exception ex)
{
Program.logger.Fatal(ex, $"ZMQF. CheckConnection exception. Servers: {(string.Join(",", servers))}");
return -1;
}
}

C# dictionary Value is changing unintentionally, just when I thought I knew how dictionary worked

I created a dictionary in C# in an attempt to store the latest value from a serial device. The serial device continuously sends strings of values and each string contains an ID. There are only about 7 IDs and they repeat. The dictionary is meant to capture the current string of values and store based on the ID so the latest values can be retrieved by ID. I am only interested in the latest values. A timer tic (10mS) keeps the serial buffer empty and the data is processed by other methods randomly (once > 1 sec).
The issue I am having is the dictionary value of the key,value pair is a struct:
public struct Frame
{
public bool echoMsg;
public uint pgnID;
public byte can_dlc;
public byte[] data;
public uint timestamp_us;
}
Thanks in advance for any helping me understand this issue.
All the values above are being saved with the dictPGN.Add() and if I break during runtime and inspect the dictionary I can see that everything is correct. However during runtime several more messages come in and processed and when the dictionary is read at a later time the byte[] data valves have been overwritten by strings with different IDs. I am guessing it is the way I am declaring the byte[] array as the other values in the dictionary remain valid. Ii've tried several things and searched with Google but have not found an answer.
My code looks something like this:
class SerialHardware
{
public SerialHardware(int hardwareIndexParm)
{
hardwareIndex = hardwareIndexParm;
mySerialFrame = new SerialFrame();
mySerialFrame.data = new byte[8];
}
private static UsbSerialThing MySerialControl = new UsbSerialThing();
private static int hardwareIndex;
private static SerialDeviceThing canID = new SerialDeviceTHing();
private static UsbSerialThing.frame frameBuffer = new UsbSerialThing.frame();
private static SerialFrame mySerialFrame = new SerialFrame();
private static Dictionary <UInt32, SerialFrame> dictPGN = new Dictionary<UInt32, SerialFrame>(); //saves entire frame by PGN
public struct Frame
{
public bool echoMsg;
public uint pgnID;
public byte can_dlc;
public byte[] data;
public uint timestamp_us;
}
public SerialFrame GetPNGFromBuffer( UInt32 pgnIDValue)
{
SerialFrame returnFrame;// = new SerialFrame(); <-Just some of the things I've tried
//returnFrame.data = new byte[8];
if (dictPGN.ContainsKey(pgnIDValue))
{
//returnFrame.data appears to have been updated by other buffer reads**
returnFrame = dictPGN[pgnIDValue];
return returnFrame;
}
else
{
return new SerialFrame(); //return blank frame
}
}
private static bool ReadCANDevice()
{
bool result = false;
int bufferSize = System.Runtime.InteropServices.Marshal.SizeOf(frameBuffer);
byte[] buffer = new byte[bufferSize];
int readCount = 0; //return var how many bytes in buffer
int mSTimeout = 100; //time in mSec before timeout
SerialFrame localSerialFrame = new SerialFrame();
localSerialFrame.data = new byte[8];
//Read the device
result = MySerialControl.DeviceBuf(canID, buffer, bufferSize, readCount, mSTimeout);
if (result)
{
mySerialFrame.pgnID = 0x7fffffff & (BitConverter.ToUInt32(buffer, 4));
mySerialFrame.can_dlc = buffer[8];
mySerialFrame.data[0] = buffer[12];
mySerialFrame.data[1] = buffer[13];
mySerialFrame.data[2] = buffer[14];
mySerialFrame.data[3] = buffer[15];
mySerialFrame.data[4] = buffer[16];
mySerialFrame.data[5] = buffer[17];
mySerialFrame.data[6] = buffer[18];
mySerialFrame.data[7] = buffer[19];
mySerialFrame.timestamp_us = BitConverter.ToUInt32(buffer, 20); //(uint)buffer[20] | ((uint)buffer[21] << 8) | ((uint)buffer[22] << 16) | ((uint)buffer[23] << 24);
//save message by PGN_ID
if (dictPGN.ContainsKey(mySerialFrame.pgnID))
{
//dictPGN[mySerialFrame.pgnID] = mySerialFrame;
}
else
{
//byte buffer looks good here! When I break during runtime
dictPGN.Add(mySerialFrame.pgnID, mySerialFrame);
}
}
else
{
//nothing to read, buffer empty
initDevice();
}
return result;
}
//timer event triggers read from serial device
private static void OnTimedEvent(object source, System.Timers.ElapsedEventArgs e)
{
while (ReadCANDevice())
{
//empty the buffer
}
}
}
In your code, you are creating a static variable mySerialFrame and setting the reference field data to point to an allocated array in the constructor.
In the ReadCANDevice method you are re-using that buffer every time you process a message. When you store the struct in the Dictionary, the fields are copied since a struct is a value type, but the value of the data field is a pointer to the allocated array from the constructor. So all the entries in the Dictionary share the same single array you overwrite each time.
Remove all instances of mySerialFrame from the class and only using localSerialFrame should fix the issue, since you allocate a new array each time you process a message for the data field of localSerialFrame.

check in realtime an external process when open a file

I need to check in realtime if a specific process try to read a wav of flac file.
I hare created a routine with 2 parameters: the process name, and the file that try to open:
public static bool Scan(string ProcessName,string TextToFind)
{
// getting minimum & maximum address
SYSTEM_INFO sys_info = new SYSTEM_INFO();
GetSystemInfo(out sys_info);
int MatchCount=0;
IntPtr proc_min_address = sys_info.minimumApplicationAddress;
IntPtr proc_max_address = sys_info.maximumApplicationAddress;
// saving the values as long ints so I won't have to do a lot of casts later
long proc_min_address_l = (long)proc_min_address;
long proc_max_address_l = (long)proc_max_address;
Process[] Arrprocess = Process.GetProcessesByName(ProcessName);
if (Arrprocess.Length == 0) return false;
// notepad better be runnin'
Process process = Arrprocess[0];
// opening the process with desired access level
IntPtr processHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_WM_READ, false, process.Id);
// this will store any information we get from VirtualQueryEx()
MEMORY_BASIC_INFORMATION mem_basic_info = new MEMORY_BASIC_INFORMATION();
int bytesRead = 0; // number of bytes read with ReadProcessMemory
// long milliseconds_start = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
while (proc_min_address_l < proc_max_address_l)
{
// 28 = sizeof(MEMORY_BASIC_INFORMATION)
VirtualQueryEx(processHandle, proc_min_address, out mem_basic_info, 28);
// if this memory chunk is accessible
if (mem_basic_info.Protect == PAGE_READWRITE && mem_basic_info.State == MEM_COMMIT && (mem_basic_info.lType == MEM_MAPPED || mem_basic_info.lType == MEM_PRIVATE))
{
byte[] buffer = new byte[mem_basic_info.RegionSize];
// read everything in the buffer above
ReadProcessMemory((int)processHandle, mem_basic_info.BaseAddress, buffer, mem_basic_info.RegionSize, ref bytesRead);
string result = System.Text.Encoding.ASCII.GetString(buffer);
if (result.Contains(TextToFind))
return true;
}
// move to the next memory chunk
proc_min_address_l += mem_basic_info.RegionSize;
proc_min_address = new IntPtr(proc_min_address_l);
}
return false;
}
this code work only the first time, because when the process close the flac file, the string keep in memory until the process will close.
I need to check every time (with precision of milliseconds) the process try to load the file that I pass as parameter.
I don't known if i'am in the right way ...
Can someone suggest me a code (in c# or c++) that detect in realtime if a process x try to read a file name y ?
Thank you !
Windows provides methods to let you know when files are opened/edited/renamed/etc.
https://learn.microsoft.com/en-us/windows/win32/projfs/file-system-operation-notifications

Searching Memory For Specific Values C# (Xbox 360)

EDIT: I think I have an idea of a possible solution for the actual searching of values. By making sure the user input ends in 0 the issue should be resolved. This would involve subtracting the last digit from the uint (which I do not know how to get, unless I go the convert to string, trim end back to uint method which is ugly but I guess it could work) and then subtracting it. If anyone has any tips on how to do this please help me out!
I've been working on a program to search memory on the Xbox 360 for specific values, if you are familiar, it is similar to "Cheat Engine". I've gotten the basics down, but I just ran into an issue. My method to search memory is dependent on starting your search at an address that will line up with your value. If that doesn't make sense to you here is the code:
private void searchInt32(int Value, uint Address, uint BytesToSearch)
{
for (uint i = 0; i <= BytesToSearch; i+=4)
{
int recoveredMem = XboxSupport.littleEndtoInt(XboxSupport.GetMem(Address + i, 4), 0);
//Recover Memory (As Bytes) and convert to integer from address (incremented based on for loop)
if (recoveredMem == Value) //Check if recovered mem = search value
{
writeToFile(Address + i, Convert.ToString(Value)); //If recovered mem = search value, write to a text file
}
siStatus.Caption = String.Format("Searching Bytes {0} out of {1}...", i, BytesToSearch); //Update status caption
}
}
As you can see, the code is kept to a minimum and it's also about as fast as possible when it comes to recovering memory from a console. But, if the 4 bytes it recovers don't line up with the value, it will never return what you want. That's obviously a serious issue because the user won't know where their value is or what address to start at to return the correct value. I then attempted to use the following code to fix the issue:
private void searchUInt32(uint Value, uint Address, uint BytesToSearch)
{
siStatus.Caption = String.Format("Recovering Memory...");
byte[] data = XboxSupport.GetMem(Address, BytesToSearch); //Dump Console Memory
FileStream output = new FileStream("SearchData.dat", FileMode.Create);
BinaryWriter writer = new BinaryWriter(output);
writer.Write(data); //Write dump to file
writer.Close();
output = new FileStream("SearchData.dat", FileMode.Open);
BinaryReader reader = new BinaryReader(output); //Open dumped file
for (uint i = 0; i *4 < reader.BaseStream.Length; i++)
{
byte[] bytes = reader.ReadBytes(4); //Read the 4 bytes
Array.Reverse(bytes);
uint currentValue = BitConverter.ToUInt32(bytes, 0); //Convert to UInt
if(currentValue == Value) //Compare
writeToFile(Address + i * 4, Convert.ToString(Value));
siStatus.Caption = String.Format("Searching Bytes {0} out of {1}...", i * 4, BytesToSearch);
}
reader.Close();
File.Delete("SearchData.dat");
}
There is a lot more code, but essentially it does the same thing, just using a file. My original goal was to have users be able to input their own memory blocks to be searched, but right now it seems that just won't work. I do not really want to have the program search all of the memory because that might end up being a slow process (depending on the size of the process being dumped) and often times the values being looked for can be narrowed down to areas of writeable code, removing junk addresses from the executable portion of the process. I am just looking to see if anyone has any suggestions, I was thinking I could possibly get the entry address from the process (I have a function for it) and using a little math correct user input addresses to work properly but I wasn't entirely sure how to do it. If anyone has any suggestions or solutions I'd appreciate any help I can get. If any of my post needs to be clarified/cleaned up please let me know, I'll be glad to do anything that might help me to an answer.
Thanks!
Edit: Temporary (hopefully) Solution:
When I load addresses into the tool they are loaded as strings from a text file, then a conversion to uint is attempted. I solved the not even issue using the following code:
sA[0] = sA[0].Remove(sA[0].Length - 1) + "0"; //Remove last character and replace w/ 0
//Add 16 to the search length
Instead of dumping memory to disk and reading every iteration, scan the target process' memory in chunks, and then marshal the data to leverage the efficiency of pointer arithmetic.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace MemoryScan {
internal class Program {
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] lpBuffer, int dwSize, out int lpNumberOfBytesRead);
private static unsafe void Main(string[] args) {
Process process = Process.GetProcessesByName("notepad")[0]; //example target process
int search = 100; //search value
int segment = 0x10000; //avoid the large object heap (> 84k)
int range = 0x7FFFFFFF - segment; ; //32-bit example
int bytesRead;
List<int> addresses = new List<int>();
DateTime start = DateTime.Now;
for (int i = 0; i < range; i += segment) {
byte[] buffer = new byte[segment];
if (!ReadProcessMemory(process.Handle, new IntPtr(i), buffer, segment, out bytesRead)) {
continue;
}
IntPtr data = Marshal.AllocHGlobal(bytesRead);
Marshal.Copy(buffer, 0, data, bytesRead);
for (int j = 0; j < bytesRead; j++) {
int current = *(int*)(data + j);
if (current == search) {
addresses.Add(i + j);
}
}
Marshal.FreeHGlobal(data);
}
Console.WriteLine("Duration: {0} seconds", (DateTime.Now - start).TotalSeconds);
Console.WriteLine("Found: {0}", addresses.Count);
Console.ReadLine();
}
}
}
Test Results
Duration: 1.142 seconds
Found: 3204
Create a generic class to make type marshaling easier, like so:
public static class MarshalHelper
{
public unsafe static T Read<T>(IntPtr address)
{
object value;
switch (Type.GetTypeCode(typeof(T)))
{
case TypeCode.Int16:
value = *(short*)address;
break;
case TypeCode.Int32:
value = *(int*)address;
break;
case TypeCode.Int64:
value = *(long*)address;
break;
default:
throw new ArgumentOutOfRangeException();
}
return (T)value;
}
}

Categories

Resources