Cannot copy pointer (IntPtr) to byte[] from method CryptGetHashParam - c#

Ive been working on this the whole day, and im still stuck
i ported this code from c/c++ to c# im so close but i get these exceptions
Exception of type 'System.ExecutionEngineException' was thrown.
and
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
here is the code, the code is not cleaned up/optimized yet cause im still testing it
public unsafe static void GetHash(string data, byte[] hash)
{
byte[] input = System.Text.UnicodeEncoding.Unicode.GetBytes(data);
hash = new byte[128];
IntPtr hProv = IntPtr.Zero;
IntPtr hHash = IntPtr.Zero;
Crypto.CryptAcquireContext(ref hProv, string.Empty, string.Empty, Crypto.PROV_RSA_FULL, 0);
if (Crypto.CryptCreateHash(hProv, Crypto.CALG_SHA1, IntPtr.Zero, 0, ref hHash))
{
if (Crypto.CryptHashData(hHash, input, ((input.Length) + 1) * 2, 0))
{
byte[] buffer = new byte[20];
IntPtr pBuffer = IntPtr.Zero;
int length = 20;
if (Crypto.CryptGetHashParam(hHash, Crypto.HP_HASHVAL, ref pBuffer, ref length, 0))
{
Crypto.CryptDestroyHash(hHash);
Crypto.CryptReleaseContext(hProv, 0);
byte tail = 0;
unsafe
{
//no matter what i do it stops here!!!!! :(
//one error is "Exception of type 'System.ExecutionEngineException' was thrown."
//the other is "System.AccessViolationException crossed a native/managed boundary
//Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
try
{
//-------------------------- This is where the exepctions starts
//I have commented the code, cause im kinda getting tired of this Exception
//I tried 2 ways of getting a byte[] from a pointer
//the 1e way, does not work
//for (int i = 0; i < length; i++)
//buffer[i] = (byte)Marshal.ReadByte(pBuffer, i);
//the 2e way does not work
//System.Runtime.InteropServices.Marshal.Copy(pBuffer,buffer, 0, 20);
//--------------------------
}
catch (Exception ex)
{
}
}
//there is more code here, but i removed
//since i only want till where code goes sofare
}
}
}
}
hope anybody can help me out here,
Thnx in advance
JB

I fixed it without the use of unsafe or the fixed statement, what i did was 2 simple like most of the codings tmp issues
i have this class Crypto where i have all advapi.dll functions in and the function returned a pointer to the byte array in memory and this is what the function needed before my change.
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool CryptGetHashParam(
IntPtr hHash,
Int32 dwParam,
ref IntPtr pbData, // this is where my problem was!!!!
ref Int32 pdwDataLen,
Int32 dwFlags
i changed the function to
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool CryptGetHashParam(
IntPtr hHash,
Int32 dwParam,
Byte[] pbData, //i changed it from IntPtr to byte array
ref Int32 pdwDataLen,
Int32 dwFlags
and that solved my corrupt memory issue
Hope this issue helps some body else working with CryptGetHashParam
i ported this code from c/c++ cause there where no c# sample on the net, so here is one of the first.
thnx all for trying to help me out, but i fixed it myself
JB

I'm not certain, but it's likely because your .Net objects aren't pinned in memory. See this: http://dotnet.dzone.com/news/net-memory-control-use-gchandl. The gist of it is that .Net objects can be moving around in memory after you've passed them through interop, and when that happens stuff starts getting crazy.
Unfortunately I'm on a netbook at the moment and can't try it myself. Does that help?

Related

Pinvoke: passing a new struct pointer to a function which outs the size of the struct

I have a prototype of the following function: https://learn.microsoft.com/en-us/windows/win32/api/wininet/nf-wininet-GetUrlCacheGroupAttributeA
Which looks like this:
[DllImport("wininet", SetLastError = true, CharSet = CharSet.Auto, EntryPoint = "GetUrlCacheGroupAttributeA", CallingConvention = CallingConvention.StdCall)]
private static extern bool GetUrlCacheGroupAttribute(
long gid,
uint dwFlags,
uint dwAttributes,
IntPtr lpGroupInfo,
ref uint lpcbGroupInfo,
IntPtr lpReserved);
The lpdwGroupInfo might make more sense as out instead of ref but otherwise, I think this is correct.
What I don't understand is how I am expected to pass in a pointer for the INTERNET_CACHE_GROUP_INFO struct lpGroupInfo(which I have also defined/prototyped along with this function). I know how everything else is passed in, just this pointer confuses me.
The function states for the pointer the following:
lpGroupInfo - Pointer to an INTERNET_CACHE_GROUP_INFO structure that receives the requested information.
lpcbGroupInfo - Pointer to a variable that contains the size of the lpGroupInfo buffer. When the function returns, the variable contains the number of bytes copied to the buffer, or the required size of the buffer, in bytes.
Do I need to allocate memory via Marshal.AllocHGlobal or something? This seems to suggest I will only get the size of the struct after passing it in but how can I pass it in if it isn't first defined? I'm not at all clear on how to create the initial pointer and then how I am expected to Marshal.PtrToStructure it.
Simon's comment answered my question:
for functions where a struct buffer pointer is passed in as a parameter(intended to be modified by the function) and where it also outs the size of the buffer needed when it fails due to insufficient buffer size, the proper way to use these functions is to pass in these values initialized to the default values(IntPtr.Zero and 0), then when the function fails(you can confirm the error was due to buffer size), it will have set the buffer size required and you can call the function again after allocating memory to the pointer.
Here is a sample snippet:
private static void ClearUrlCacheGroups()
{
IntPtr enumHandle = FindFirstUrlCacheGroup(0, CACHEGROUP_SEARCH_ALL, IntPtr.Zero, 0, out long lpGroupId, IntPtr.Zero);
if (enumHandle != IntPtr.Zero)
{
bool foundNextGroup;
bool isDeleted;
uint cacheGroupInfoBufferSize = 0;
IntPtr cacheGroupInfoBuffer = Marshal.AllocHGlobal((IntPtr)cacheGroupInfoBufferSize);
do
{
bool getAttributeSucceeded = GetUrlCacheGroupAttribute(lpGroupId, 0, CACHEGROUP_ATTRIBUTE_GET_ALL, cacheGroupInfoBuffer, ref cacheGroupInfoBufferSize, IntPtr.Zero);
if (!getAttributeSucceeded && Marshal.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER)
{
cacheGroupInfoBuffer = Marshal.ReAllocHGlobal(cacheGroupInfoBuffer, (IntPtr)cacheGroupInfoBufferSize);
getAttributeSucceeded = GetUrlCacheGroupAttribute(lpGroupId, 0, CACHEGROUP_ATTRIBUTE_GET_ALL, cacheGroupInfoBuffer, ref cacheGroupInfoBufferSize, IntPtr.Zero);
}
if (getAttributeSucceeded)
{
INTERNET_CACHE_GROUP_INFOA internetCacheEntry = (INTERNET_CACHE_GROUP_INFOA)Marshal.PtrToStructure(cacheGroupInfoBuffer, typeof(INTERNET_CACHE_GROUP_INFOA));
}
isDeleted = DeleteUrlCacheGroup(lpGroupId, CACHEGROUP_FLAG_FLUSHURL_ONDELETE, IntPtr.Zero);
foundNextGroup = FindNextUrlCacheGroup(enumHandle, ref lpGroupId, IntPtr.Zero);
}
while (foundNextGroup);
Marshal.FreeHGlobal(cacheGroupInfoBuffer);
}
}

Using pointers and address

I have the following C# code:
(Updating the code/question)
The code and the project are marked as unsafe
private struct MEMORY_BASIC_INFORMATION
{
internal uint BaseAddress;
internal uint AllocationBase;
internal uint AllocationProtect;
internal uint RegionSize;
internal uint State;
internal uint Protect;
internal uint Type;
}
public unsafe static bool CheckForSufficientStack(long bytes)
{
MEMORY_BASIC_INFORMATION stackInfo = new MEMORY_BASIC_INFORMATION();
// originally was
// IntPtr currentAddr = new IntPtr((uint)&stackInfo - 4096);
GCHandle gh = GCHandle.Alloc(stackInfo, GCHandleType.Pinned);
IntPtr p = gh.AddrOfPinnedObject();
//now - this line passes compilation
IntPtr currentAddr = new IntPtr((uint)p - 4096);
// build error in the below line
VirtualQuery(currentAddr, ref stackInfo, sizeof(MEMORY_BASIC_INFORMATION));
return ((uint)currentAddr.ToInt64() - stackInfo.AllocationBase) >
(bytes + STACK_RESERVED_SPACE);
}
and when I compile it I get the error:
Cannot take the address of, get the size of, or declare a pointer to a managed type
This is a code I copied and I was actually surprised to know there is '&' in c# but then build failed.
Any idea how to resolve this?
The error is now for the last line when we do a sizeof(MEMORY_BASIC_INFORMATION)
You must "pin" the object in memory first, to make sure that theGC won't move it while you use it:
GCHandle gh = GCHandle.Alloc(stackInfo, GCHandleType.Pinned);
IntPtr p = gh.AddrOfPinnedObject();
Get the size of the struct with:
Marshal.SizeOf(typeof(MEMORY_BASIC_INFORMATION))
In order to make it work you have to indicate you are using unsafe code in C# (since a miscalculation for example could end you up with an invalid address). This is enforced by the unsafe keyword.
unsafe
{
IntPtr currentAddr = new IntPtr((uint)&stackInfo - 4096);
}
Also make sure your project settings have Unsafe code enabled.
The original code from here http://joeduffyblog.com/2006/07/15/checking-for-sufficient-stack-space/ passed compilation when I wrote it inside a new class and not inside an existing class I already have...
I have no idea why it passed....

Arithmetic operation resulted in an overflow c#

I am getting the following error when unlocking a file
Arithmetic operation resulted in an overflow
System.IntPtr.ToInt32
I suspect it is the following line to pBuffer.ToInt32() :
IntPtr iPtr = new IntPtr(pBuffer.ToInt32() + (i * Marshal.SizeOf(fi3)));
I am unable to reproduce the error myself and the error is not displaying the correct line number. I am looking for a way to reproduce this or any feedback on the possible cause. Thanks
public void Close()
{
const int MAX_PREFERRED_LENGTH = -1;
int readEntries;
int totalEntries;
IntPtr pBuffer = IntPtr.Zero;
FILE_INFO_3 fi3 = new FILE_INFO_3();
int iStatus = NetFileEnum(this.HostName, this.HostPathToShare + this.FileNameFromShare, null, 3, ref pBuffer, MAX_PREFERRED_LENGTH, out readEntries, out totalEntries, pBuffer);
if (iStatus == 0)
{
for (int i = 0; i < readEntries; i++)
{
IntPtr iPtr = new IntPtr(pBuffer.ToInt32() + (i * Marshal.SizeOf(fi3)));
fi3 = (FILE_INFO_3)Marshal.PtrToStructure(iPtr, typeof(FILE_INFO_3));
NetFileClose(this.HostName, fi3.fi3_id);
}
}
NetApiBufferFree(pBuffer);
}
[DllImport("netapi32.dll", SetLastError=true, CharSet = CharSet.Unicode)]
static extern int NetFileClose(
string servername,
int id);
[DllImport("Netapi32.dll", SetLastError=true)]
static extern int NetApiBufferFree(IntPtr Buffer);
[DllImport("netapi32.dll", SetLastError=true, CharSet=CharSet.Unicode)]
static extern int NetFileEnum(
string servername,
string basepath,
string username,
int level,
ref IntPtr bufptr,
int prefmaxlen,
out int entriesread,
out int totalentries,
IntPtr resume_handle
);
Update
I added the win32 apis code.
The below answers look correct and the machine is 64 bit. But I am unable to reproduce it on the dev server despite the dev environment being 64 bit. Any ideas to reproduce the error?
The error is caused by your code running in a 64 bit context and returning a pointer address that lies outside the range addressable with 32 bits, so .ToInt32() throws.
Call Environment.Is64BitProcess to detect whether your process is running in 32 or 64 bit, and convert the address accordingly:
long pointerAddress;
if (Environment.Is64BitProcess)
{
pointerAddress = pBuffer.ToInt64();
}
else
{
pointerAddress = pBuffer.ToInt32();
}
var fileInfoPointer = new IntPtr(pointerAddress + (i * Marshal.SizeOf(fi3)));
I see two errors in the code right off:
You set your pBuffer to 0, and never actually allocate it. It should error when you pass it to NetFileEnum, although that is a Win32 API function, so it may not notice.
You convert pBuffer .ToInt32(), which should work when compiled for x86 specifically, but if you have Any CPU or x64 as your target platform, this is going to be a problem also.

C# Streamline memory reading of multi-pointer

I have made a method that will read a multi-pointer by providing the wanted offsets + the start adress. (Code below). To summarize, Im trying to streamline this method and below I will explain my problem.
I have been strugling around with the conversion. The parameter is an IntPtr and the output of a read adress is an byte array, my first idea was: "Convert Byte array to IntPtr, reprocess it and finally convert the last read adress into a int32 (since the last adress is not a pointer it will never be read so converting here to Int32 should be allright)",
However that did not give a nice result. So currently Im stuck with the solution of converting Byte array to Int32, then Int32 to IntPtr. People do say that the bitconverter is a bad approach because it might cause issues on 64-bit platforms and I do also believe there is an approach that may give a better performence (since Im converting an object 2 times).
Finally if anyone think it would be possible to make a similar function in C++ and then P/Invoke it in C# (I guess it would be more efficient that way?) please tell me. (Im trying to adapt my programming knowledges. And find combination of languages very interesting)
[DllImport("kernel32.dll", EntryPoint = "ReadProcessMemory")]
public static extern Int32 ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress,
[In, Out] byte[] buffer, Int32 sizeout, out IntPtr lpNumberOfBytesRead);
public Int32 ReadBytes(IntPtr Handle, IntPtr Address, int[] Offsets, int BytesToRead = 4)
{
IntPtr ptrBytesRead;
byte[] value = new byte[BytesToRead];
ReadProcessMemory(Handle, Address, value, BytesToRead, out ptrBytesRead);
//Read Offsets
for (int i = 0; i < Offsets.Length; i++)
{
ReadProcessMemory(Handle,
new IntPtr(BitConverter.ToInt32(value, 0) + Offsets[i]),
value,
BytesToRead,
out ptrBytesRead);
}
return BitConverter.ToInt32(value, 0);
}
Any ideas to streamline this method would be very well appreciated! Thanks on advance!
As #usr stated, the performance of the code will be entirely dominated by the calls to ReadProcessMemory. You should not expect to improve the performance from its current level.
However, you can make the code much easier to read by avoiding byte arrays and BitConverter. Like this:
[DllImport("kernel32.dll", SetLastError = true)]
public static extern int ReadProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
out IntPtr lpBuffer,
IntPtr nSize,
out IntPtr lpNumberOfBytesRead
);
private static IntPtr ReadProcessPointer(IntPtr hProcess, IntPtr Address)
{
IntPtr result;
IntPtr NumberOfBytesRead;
if (ReadProcessMemory(hProcess, Address, out result, (IntPtr)IntPtr.Size, out NumberOfBytesRead) == 0)
throw new Win32Exception();
return result;
}
public static IntPtr FollowPointers(IntPtr hProcess, IntPtr Address, int[] Offsets)
{
IntPtr ptr = ReadProcessPointer(hProcess, Address);
for (int i = 0; i < Offsets.Length; i++)
ptr = ReadProcessPointer(hProcess, ptr + Offsets[i]);
return ptr;
}

C# ReadProcessMemory - Accessing/Reading Pointers

I have the code to read a value from Memory which works when the memory address points to a static 4 byte value, but i'm trying to access a 4 byte value which is in a dynamic location and so need to search for the pointer first then search again to get the 4 byte value.
Below is the code I have which should return the address of the Pointer but it just outputs 0...
bAddr = (IntPtr)0x0017C370; // Base address to find the Pointer (Currently: 0x00267A50)
ReadProcessMemory(hProc, bAddr, buffer, 4, out bytesRW);
output = BitConverter.ToInt32(buffer, 0);
txtOutput.Text = output.ToString();
Pseudo code I see working as:
bAddr = (IntPtr)0x0017C370; // Base address to find the Pointer (Currently: 0x00267A50)
ReadProcessMemory(hProc, bAddr, buffer, 4, out bytesRW);
output = BitConverter.ToInt32(buffer, 0);
bAddr = (IntPtr)output; // Should now contain the address 0x00267A50
ReadProcessMemory(hProc, bAddr, buffer, 4, out bytesRW);
output = BitConverter.ToInt32(buffer, 0);
txtOutput.Text = output.ToString();
Can anyone shed any light on to what I need to be doing to find an address and then search for that address to find a value?
This is a pretty classical mistake when using pinvoke to execute Win32 functions, you are not doing any error checking. So any failure is undiagnosable. First make sure you declared it properly:
[DllImport("user32.dll", SetLastError = true)]
static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress,
[In, Out] byte[] buffer, IntPtr size, out IntPtr lpNumberOfBytesRead);
Then execute it like this:
bool ok = ReadProcessMemory(...);
if (!ok) throw new System.ComponentModel.Win32Exception();
Now you'll know why it doesn't work. We can't otherwise help you figure out what goes wrong until you've at least tested it this way. The most basic problem is guessing the address wrong of course. And not having enough privileges, ReadProcessMemory is a highly privileged function for obvious reasons.

Categories

Resources