I am receiving an AccessViolationException when calling the ReadFile API. I have looked at all of the entries on StackOverflow dealing with similar issues and have not had any success deciphering what is wrong.
Here is the relevant code in question:
INVOKES
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr CreateFile([MarshalAs(UnmanagedType.LPTStr)] string filename, UInt32 desiredaccess, UInt32 sharemode, IntPtr securityattributes, UInt32 creationdisposition, UInt32 flagsandattributes, IntPtr templatefile);
[DllImport("kernel32.dll", BestFitMapping = true, CharSet = CharSet.Ansi, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ReadFile(IntPtr hFile, out byte[] lpbuffer, UInt32 nNumberofBytesToRead, out UInt32 lpNumberofBytesRead, IntPtr lpOverlapped);
[DllImport("kernel32.dll", BestFitMapping = true, CharSet = CharSet.Ansi, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool WriteFile(IntPtr hFile, byte[] lpBuffer, UInt32 nNumberOfBytesToWrite, out UInt32 lpNumberOfBytesWritten, IntPtr lpOverlapped);
CREATE FILE FUNCTION CALL
private IntPtr OpenPort(string port)
{
IntPtr printerhandle = IntPtr.Zero;
printerhandle = CreateFile(port,
(UInt32)(FileAccess.GENERIC_READ | FileAccess.GENERIC_WRITE),
(UInt32)(FileShare.FILE_SHARE_READ | FileShare.FILE_SHARE_WRITE),
IntPtr.Zero,
(UInt32)FileMode.OPEN_EXISTING,
(UInt32)(FileAttribute.FILE_ATTRIBUTE_NORMAL),
IntPtr.Zero);
return (printerhandle);
}
READFILE FUNCTION CALL
private bool WriteToPort(IntPtr printer, ref byte[] data)
{
bool success = true;
byte[] data2 = new byte[64];
byte[] dataread = new byte[64];
int index = 0;
int length = 64;
uint written = 0;
uint read = 0;
while ((index + length) <= data.Length)
{
Array.Copy(data, index, data2, 0, length);
success &= WriteFile(printer, data2, (uint)length, out written, IntPtr.Zero);
index += 64;
}
if ((index < data.Length) &&
((index + length) > data.Length))
{
length = data.Length - index;
Array.Copy(data, index, data2, 0, length);
success &= WriteFile(printer, data2, (uint)length, out written, IntPtr.Zero);
}
success &= ReadFile(printer, out dataread, 64, out read, IntPtr.Zero);
return success;
}
The exception occurs when the success &= ReadFile(printer, out dataread, 64, out read, IntPtr.Zero); line is executed.
Here is the relevant stack trace as reported by VS2013:
StackTrace:
at System.StubHelpers.MngdNativeArrayMarshaler.ClearNative(IntPtr pMarshalState, IntPtr pNativeHome, Int32 cElements)
at APP_NET.Main.ReadFile(IntPtr hFile, Byte[]& lpbuffer, UInt32 nNumberofBytesToRead, UInt32& lpNumberofBytesRead, IntPtr lpOverlapped)
at APP_NET.Main.WriteToPort(IntPtr printer, Byte[]& data) in Main.cs:line 770
Any thoughts on what might be happening?
Because you have a wrong declaration of the ReadFile function. Remove out from the lpbuffer argument.
Import of the ReadFile:
[DllImport("kernel32.dll", BestFitMapping = true, CharSet = CharSet.Ansi, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ReadFile(IntPtr hFile, byte[] lpbuffer, UInt32 nNumberofBytesToRead, out UInt32 lpNumberofBytesRead, IntPtr lpOverlapped);
Reading a file:
success &= ReadFile(printer, dataread, 64, out read, IntPtr.Zero);
Related
I'm trying to modify some code that dumps a specific file and I want to modify the first bytes of the dumped file.
I've already done it in a C equivalent program like this :
[...]
SetFilePointer(hDmpFile, 0, 0, FILE_BEGIN);
WriteFile(hDmpFile, "AA", 2, NULL, NULL);
I want to do the same thing in C# but I got some error regarding the WriteFile() function.
Here's what I've done so far :
[...]
public enum EMoveMethod : uint
{
Begin = 0,
Current = 1,
End = 2
}
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern uint SetFilePointer(
[In] SafeFileHandle hFile,
[In] int lDistanceToMove,
[Out] out int lpDistanceToMoveHigh,
[In] EMoveMethod dwMoveMethod);
[DllImport("kernel32.dll", BestFitMapping = true, CharSet = CharSet.Ansi)]
public static extern bool WriteFile(
IntPtr hFile,
System.Text.StringBuilder lpBuffer,
uint nNumberOfBytesToWrite,
out uint lpNumberOfBytesWritten,
[In] ref System.Threading.NativeOverlapped lpOverlapped);
[...]
int moveDistanceHighBits = 0;
uint test = SetFilePointer(hDmpFile, 0, out moveDistanceHighBits, EMoveMethod.Begin);
uint test2 = WriteFile(hDmpFile, "AA", 2, null, null);
hDmpFile.Dispose();
[...]
Here's the error I got when executing the file :
Unhandled Exception: System.NotImplementedException: The method or operation is not implemented.
at Foo.Program.WriteFile(SafeFileHandle hDmpFile, String v1, Int32 v2, Object value1, Object value2)
at Foo.Program.Execute(String[] args)
at Foo.Program.Main(String[] args)
For the record, I'm an absolute disaster when it comes to coding and I've never done C#...
I have an application that monitors file and folder changes. I get an error when a new file is created, deleted or modified. I have the following code and have no idea why the Marshal.PtrToStringAuto throw "Attempted to read or write protected memory. This is often an indication that other memory is corrupt.".
Why am I getting this error when I try to get the filename?
Can someone please help me on what to look for to resolve this error...
error image
[DllImport("kernel32.dll", EntryPoint = "FindFirstChangeNotification")]
static extern System.IntPtr FindFirstChangeNotification(string lpPathName, bool bWatchSubtree, uint dwNotifyFilter);
[DllImport("kernel32.dll", EntryPoint = "FindNextChangeNotification")]
static extern bool FindNextChangeNotification(IntPtr hChangedHandle);
[DllImport("kernel32.dll", EntryPoint = "FindCloseChangeNotification")]
static extern bool FindCloseChangeNotification(IntPtr hChangedHandle);
[DllImport("kernel32.dll", EntryPoint = "WaitForSingleObject")]
static extern uint WaitForSingleObject(IntPtr handle, uint dwMilliseconds);
[DllImport("kernel32.dll", EntryPoint = "ReadDirectoryChangesW")]
static extern bool ReadDirectoryChangesW(IntPtr hDirectory, IntPtr lpBuffer, uint nBufferLength, bool bWatchSubtree, uint dwNotifyFilter, out uint lpBytesReturned, uint lpOverlapped, uint lpCompletionRoutine);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
public static extern int ReadDirectoryChangesW(uint hDirectory, out FILE_NOTIFY_INFORMATION finfo, uint nBufferLength,uint bWatchSubtree, uint dwNotifyFilter, out uint lpbytesReturned,uint PassZero1, uint PassZero2);
[DllImport("kernel32.dll", EntryPoint = "CreateFile")]
public static extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess, uint dwShareMode, IntPtr SecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile);
private const int MaxChanges = 4096;
public async Task ReadChangesAsyncNew()
{
var token = _cancellationTokenSource.Token;
await Task.Run(() =>
{
unsafe
{
var directoryHandle = CreateFile(_path, 0x80000000, 0x00000007, IntPtr.Zero, 3, 0x02000000, IntPtr.Zero);
var fileCreatedDeletedOrUpdated = FileSystemNotifications.FileNameChanged | FileSystemNotifications.FileModified;
var waitable = FindFirstChangeNotification(_path, true, (uint)fileCreatedDeletedOrUpdated);
var notifySize = Marshal.SizeOf(typeof(FileNotifyInformation));
do
{
var changes = new FileNotifyInformation[MaxChanges];
var pinnedArray = GCHandle.Alloc(changes, GCHandleType.Pinned);
var buffer = pinnedArray.AddrOfPinnedObject();
uint bytesReturned = 0;
if (!ReadDirectoryChangesW(directoryHandle, buffer, (uint)(notifySize * MaxChanges), true, (uint)fileCreatedDeletedOrUpdated, out bytesReturned, 0, 0))
throw Win32Error.GetLastError().GetException();
var result = new List<FileEvent>();
for (var i = 0; i < bytesReturned / notifySize; i += 1)
{
var change = Marshal.PtrToStructure<FileNotifyInformation>(new IntPtr(buffer.ToInt64() + i * notifySize));
if (((int)change.Action) == (int)FileActions.FileAdded)
{
result.Add(new FileEvent(Marshal.PtrToStringAuto(change.FileName, change.FileNameLength), FileEventType.FileAdded));
}
else if (((int)change.Action) == (int)FileActions.FileRemoved)
{
result.Add(new FileEvent(Marshal.PtrToStringAuto(change.FileName, change.FileNameLength), FileEventType.FileDeleted));
}
else if (((int)change.Action) == (int)FileActions.FileModified)
{
result.Add(new FileEvent(Marshal.PtrToStringAuto(change.FileName, change.FileNameLength), FileEventType.FileChanged));
}
else if (((int)change.Action) == (int)FileActions.FileRenamedNew)
{
result.Add(new FileEvent(Marshal.PtrToStringAuto(change.FileName, change.FileNameLength), FileEventType.FileRenamed));
}
}
pinnedArray.Free();
} while (FindNextChangeNotification(waitable));
FindCloseChangeNotification(waitable);
}
}, token);
}
I have a simple C driver that accepts a ULONG parameter. In C language I use:
unsigned long ip = atoll(argv[1]);
if (!DeviceIoControl(
DeviceHandle,
0x10,
&ip,
sizeof(ip),
NULL,
0,
&BytesReturned,
NULL
))
It works well, but when I do it in C#,
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool DeviceIoControl([In] IntPtr hDevice,
[In] int dwIoControlCode, [In] IntPtr lpInBuffer,
[In] int nInBufferSize, [Out] IntPtr lpOutBuffer,
[In] int nOutBufferSize, out int lpBytesReturned,
[In] IntPtr lpOverlapped);
...
Int64 ip = ip2long(ipstr);
if (! Win32.DeviceIoControl(
hDevice, 0x10,
(IntPtr) ip, Marshal.SizeOf(ip),
IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero))
{
throw new Exception("DeviceIoControl(): " + Marshal.GetLastWin32Error());
}
It always result in 998 error: Invalid memory access.
From DbgView, the call never reached the driver. What was wrong here?
Interesting, you can't convert uint to IntPtr directly. You must allocate memory to do that:
IntPtr ipPtr = Marshal.AllocHGlobal(Marshal.SizeOf(ip));
Marshal.WriteInt64(ipPtr, ip);
I am using in my program "Kernel32.dll" functionality to access raw disk sectors on WinXP SP3 OS (external HDD).
Everything works fine till the program reaches sector number 8388607 - which means the bytes offset in SetFilePointer exceeds 32 bit (uint!).
But my code, as below, uses all variables as "long". What I am doing wrong?
The code (on "Dump" button click):
int drive = DRV.SelectedIndex; // DRV is the drive combo box
long bps = BytesPerSector(drive), spt = GetTotalSectors(drive);
string dr = DRV.SelectedItem.ToString();
int moveToHigh, read = 0;
uint GENERIC_READ = 0x80000000;
uint OPEN_EXISTING = 3;
SafeFileHandle handleValue = CreateFile(dr, GENERIC_READ, 0, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
if (handleValue.IsInvalid)
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
// idx = Loop starting index
// FS = The starting sector index
// TS = The final sector index
long idx = (FS == -1) ? 0 : FS, tot = (TS == -1) ? spt : TS;
for ( ; idx < tot; idx++)
{
byte[] b = new byte[bps];
// HERE IS THE ISSUE!!!
SetFilePointer(handleValue, idx*bps), out moveToHigh, EMoveMethod.Current);
if (ReadFile(handleValue, b, bps, out read, IntPtr.Zero) == 0)
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
if (this.IsDisposed == true) { handleValue.Close(); break; }
Application.DoEvents();
}
handleValue.Close();
The kernel32.dll external functions:
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern uint SetFilePointer(
[In] SafeFileHandle hFile,
[In] long lDistanceToMove,
[Out] out int lpDistanceToMoveHigh,
[In] EMoveMethod dwMoveMethod);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern SafeFileHandle CreateFile(string lpFileName, uint dwDesiredAccess,
uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition,
uint dwFlagsAndAttributes, IntPtr hTemplateFile);
[DllImport("kernel32", SetLastError = true)]
internal extern static int ReadFile(SafeFileHandle handle, byte[] bytes,
int numBytesToRead, out int numBytesRead, IntPtr overlapped_MustBeZero);
I have tried many things, but no idea what is wrong, application just ending up with a fatal exception asking to send bug report
Thanks a lot
Your P/Invoke definition is wrong. The function takes a 32bit value in but you defined it as a 64bit value. It won't work properly and definitely not past the value range of 32bit variables.
See the definition and example on how to use at pinvoke.net:
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern int SetFilePointer(IntPtr handle, int lDistanceToMove, out int lpDistanceToMoveHigh, uint dwMoveMethod);
int lo = (int)(offset & 0xffffffff);
int hi = (int)(offset >> 32);
lo = SetFilePointer(handle, lo, out hi, moveMethod);
So you need to split the 64bit value in two and provide both parts for the function.
Also don't use doubles for integers. You will get into trouble when the accuracy ends and there is no reason to use them.
The Idea is that I have 4 byte[512] arrays that I derive a key from, and encrypt some info with AES256 in C#. Than my colleague, having the exact same 4 byte arrays, using the same key derivation process, decrypts the message.
Except first, it's throwing "Bad data" exception in C++, and, unlike what I' would expect, the encrypted output in C# is different every time. Why is this happening?
constants:
const uint ALG_CLASS_DATA_ENCRYPT = (3 << 13);
const uint ALG_TYPE_BLOCK = (3 << 9);
const uint ALG_SID_AES_256 = 16;
const uint CALG_AES_256 = (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_AES_256);
const uint KEYLENGTH = 0x01000000;
const uint CRYPT_EXPORTABLE = 0x00000001;
const uint ALG_CLASS_HASH = (4 << 13);
const uint ALG_TYPE_ANY = 0;
const uint ALG_SID_SHA_256 = 12;
const uint CALG_SHA_256 = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256);
const uint ENCRYPT_HASH_ALG = CALG_SHA_256;
const uint PROV_RSA_AES = 24;
const uint CRYPT_VERIFYCONTEXT = 0xF0000000;
const string MS_ENH_RSA_AES_PROV = #"Microsoft Enhanced RSA and AES Cryptographic Provider";
const uint CRYPT_MODE_CBC = 1;
const uint KP_MODE = 4;
const uint KP_IV = 1;
my code:
IntPtr _hProv = new IntPtr();
IntPtr _phHash = new IntPtr();
IntPtr _phKey = new IntPtr();
bool result = CryptAcquireContext(ref _hProv, null, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, CRYPT_VERIFYCONTEXT);
result = CryptCreateHash(_hProv, ENCRYPT_HASH_ALG, IntPtr.Zero, 0, ref _phHash);
byte[] bbb = new ASCIIEncoding().GetBytes("Test hash!");
result = CryptHashData(_phHash, bbb, (uint)bbb.Length, 0);
result = CryptDeriveKey(_hProv, CALG_AES_256, _phHash, KEYLENGTH, ref _phKey);
byte[] cryptMode = BitConverter.GetBytes(CRYPT_MODE_CBC);
result = SetXKeyParamKey(_phKey, KP_MODE, cryptMode);
byte[] ivBuff = new byte[16]{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
result = SetXKeyParamKey(_phKey, KP_IV, ivBuff);
uint lenght = (uint)data.Length;
byte[] cln = new byte[data.Length + 128];
Array.Copy(data, cln, data.Length);
result = CryptEncrypt(_phKey, IntPtr.Zero, 1, 0, cln, ref lenght, (uint)(cln.Length + 128));
data = new byte[lenght];
Array.Copy(cln, data, lenght);
result = CryptReleaseContext(_hProv, 0);
return lenght;
signatures:
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CryptAcquireContext(ref IntPtr hProv, string pszContainer, string pszProvider, UInt32 dwProvType, UInt32 dwFlags);
[DllImport("Advapi32.dll", EntryPoint = "CryptReleaseContext", CharSet = CharSet.Unicode, SetLastError = true)]
static extern bool CryptReleaseContext(IntPtr hProv, Int32 dwFlags); //dwFlags Reserved. Must be 0.
[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 CryptHashData(IntPtr hHash, byte[] pbData, uint dataLen, uint flags);
[DllImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptDeriveKey(IntPtr hProv, uint Algid, IntPtr hBaseData, uint flags, ref IntPtr phKey);
[DllImport(#"advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptEncrypt(IntPtr hKey, IntPtr hHash, int Final, uint dwFlags, byte[] pbData, ref uint pdwDataLen, uint dwBufLen);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool CryptGetHashParam(IntPtr hHash, uint dwParam, [Out] IntPtr pbData, [In, Out] uint pdwDataLen, uint dwFlags);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptSetKeyParam(IntPtr Key, uint Param, IntPtr Data, uint Flags);
private static bool SetXKeyParamKey(IntPtr Key, uint KeyParam, byte[] Data)
{
bool Result = false;
if (Data == null) // special case, e.g. for KP_X
{
Result = CryptSetKeyParam(Key, KeyParam, IntPtr.Zero, 0);
return Result;
}
IntPtr holder = Marshal.AllocHGlobal(12); // the same as DATA_BLOB
Marshal.WriteInt32(holder, 0, Data.Length); // first 4 bytes is the length of the buffer
IntPtr buffPtr = Marshal.AllocHGlobal(Data.Length); // ptr to buffer
Marshal.Copy(Data, 0, buffPtr, Data.Length); // copy real data to a newly-allocated buffer
Marshal.WriteInt64(holder, 4, (Int64)buffPtr); // holder now contains both size and ptr; assume that ptr takes 4 bytes
Result = CryptSetKeyParam(Key, KeyParam, holder, 0); // instead of real buffer, we must pass the holder
Marshal.FreeHGlobal(buffPtr); Marshal.FreeHGlobal(holder);
return Result;
}