.NET Runtime Error 80131506 - Passing Lambda to Native Function - c#

So I'm getting this error that looks as though it's a corrupted garbage collection:
Application Crashes With "Internal Error In The .NET Runtime"
The full error is:
The process was terminated due to an internal error in the .NET Runtime at IP 71C571C8 (71B20000) with exit code 80131506.
It's running on:
Framework Version: v4.0.30319
This occurs inconsistently when running this function repeatedly:
public static int GetMdiTitledChildWindows(IntPtr parentWindow)
{
IntPtr mdiClient = FindWindowEx(parentWindow, IntPtr.Zero, MdiClient, "");
List<IntPtr> handles = new List<IntPtr>();
EnumChildWindows(mdiClient, (hwnd, param) =>
{
handles.Add(hwnd);
return true;
}, IntPtr.Zero);
int counter = 0;
foreach (IntPtr handle in handles)
{
StringBuilder builder = new StringBuilder();
GetWindowText(handle, builder, GetWindowTextLength(handle)+1);
if (builder.Length > 0)
{
counter++;
}
}
return counter;
}
Where FindWindowEx(), EnumChildWindows() and GetWindowText() are all p/invoke signatures defined similarly to this:
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam);
The error only seems to occur after I've run the method many times, however, this doesn't happen consistently. Sometimes it works, sometimes it doesn't.
Any suggestions on how to fix this?

So I solved my issue with the help of a generous benefactor on Discord.
The problem was that I was passing a lambda to a p/invoke as a delegate:
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam);
So every time the unmanaged WinAPI call called-back into my delegate, the GC had the opportunity to run, if it did, it collected my lambda causing this crash. This wouldn't necessarily happen, hence why my method worked most of the time and crashed inconsistently.
The solution was to add a reference to the lambda that would prevent the GC from collecting it (although I went whole-hog and made it a local function because belt and braces):
public static int GetMdiTitledChildWindows(IntPtr parentWindow)
{
IntPtr mdiClient = FindWindowEx(parentWindow, IntPtr.Zero, MdiClient, "");
List<IntPtr> handles = new List<IntPtr>();
bool addToList(IntPtr hwnd, IntPtr param)
{
handles.Add(hwnd);
return true;
}
EnumWindowsProc gcHolder = addToList;
EnumChildWindows(mdiClient, gcHolder, IntPtr.Zero);
int counter = 0;
foreach (IntPtr handle in handles)
{
int textLength = GetWindowTextLength(handle) + 1;
StringBuilder builder = new StringBuilder(textLength);
GetWindowText(handle, builder, textLength);
if (builder.Length > 0)
{
counter++;
}
}
return counter;
}
The application now works as expected.

Related

Visual Studio hangs on GetThreadWaitChain WCT call

I am trying out WCT and I want to call GetThreadWaitChain, I had some previous questions on this topic, but I've got recently strange behavior. As I am calling GetThreadWaitChain fuction my Visual Studio hangs with prompt message:
vhost32.exe has stopped working
Output windows message:
The program '[9068] testWCT.vshost.exe' has exited with code -1073740940 (0xc0000374).
Every time I am getting to that function my visual studio hangs...
GetThreadWaitChain documentation:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms679364(v=vs.85).aspx
This is my code:
internal void CollectWaitInformation(ClrThread thread)
{
var g_WctHandle = OpenThreadWaitChainSession(0, 0);
uint threadID = thread.OSThreadId;
WAITCHAIN_NODE_INFO[] NodeInfoArray = new WAITCHAIN_NODE_INFO[16];
int isCycle = 0;
int count = 16;
// Make a synchronous WCT call to retrieve the wait chain.
bool result = GetThreadWaitChain(g_WctHandle,
IntPtr.Zero,
WCTP_GETINFO_ALL_FLAGS,
threadID, ref count, NodeInfoArray, out isCycle);
if (!result)
{
//error
}
//Finaly ...
CloseSession(g_WctHandle);
}
[DllImport("Advapi32.dll")]
public static extern IntPtr OpenThreadWaitChainSession(OpenThreadChainFlags Flags, DWORD callback);
[DllImport("Advapi32.dll")]
public static extern bool GetThreadWaitChain(
IntPtr WctHandle,
IntPtr Context,
UInt32 Flags,
uint ThreadId,
ref int NodeCount,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)]
[In, Out]
WAITCHAIN_NODE_INFO[] NodeInfoArray,
out int IsCycle
);
[StructLayout(LayoutKind.Sequential)]
public struct WAITCHAIN_NODE_INFO
{
public WCT_OBJECT_TYPE ObjectType;
public WCT_OBJECT_STATUS ObjectStatus;
public struct LockObject
{
string ObjectName;
LARGE_INTEGER Timeout;
BOOL Alertable;
}
public struct ThreadObject
{
DWORD ProcessId;
DWORD ThreadId;
DWORD WaitTime;
DWORD ContextSwitches;
}
}
}
I've tried to run C++ code on the same process, which I took from MSDN:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms681418(v=vs.85).aspx
And all I've got is: 0x57 error on all threads as a result. Which is ERROR_INVALID_PARAMETER accordingly to MSDN:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx
Which is weird cause I didn't changed the C++ code..
Previous question on the same topic:
WCT GetThreadWaitChain call allways return false
I declared the WAITCHAIN_NODE_INFO struct in a wrong way (my union was wrong) this is the original structure:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms681422(v=vs.85).aspx
As soon as I declared it right, the heap corruption stopped and everything worked...

Windows API DiInstallDevices causes Exception

I am trying to access Win32 APIs to install a driver on a device. I am using a bunch of functions from the setupapi.h, all of which work well. In this piece of code, I am using those to get the parameters (i.e. names of/pointers to device and driver) that are needed to call this install function (which is not part of the setupapi.h but of the newdev.h).
Following is my P/Invoke and the actual method call. I have used the debugger to investigate and I am pretty sure that the information I get from the SetupAPI is correct. (I.e., the parameters are fine, by which I mean that they do contain the desired information.)
IntPtr deviceInfoSet;
Win32SetupApi.SP_DEVINFO_DATA devInfoData;
GetDeviceHandleFromMatch(deviceInfo, out deviceInfoSet, out devInfoData);
Win32SetupApi.SP_DRVINFO_DATA drvInfoData;
GetDriverHandleFromMatch(driverInstance, deviceInfoSet, devInfoData, out drvInfoData);
try
{
bool needReboot = false;
Win32SetupApi.DiInstallDevice(
IntPtr.Zero,
deviceInfoSet,
devInfoData,
drvInfoData,
0,
ref needReboot);
}
catch (Exception ex)
{
throw;
}
[DllImport("newdev.dll", SetLastError = true)]
public static extern bool DiInstallDevice(
IntPtr hParent,
IntPtr lpInfoSet,
SP_DEVINFO_DATA DeviceInfoData,
SP_DRVINFO_DATA DriverInfoData,
UInt32 Flags,
[MarshalAs(UnmanagedType.Bool)] ref bool NeedReboot);
The exception I get is "Attempt to read/write protected memory", there is no information available via LastWin32Error.
Any thought on what might blow up here ist greatly appreciated!
Got it!
[DllImport("newdev.dll", SetLastError = true)]
public static extern bool DiInstallDevice(
IntPtr hParent,
IntPtr lpInfoSet,
ref SP_DEVINFO_DATA DeviceInfoData,
ref SP_DRVINFO_DATA DriverInfoData,
UInt32 Flags,
ref bool NeedReboot);
The structs have to be passed by reference as descrided here. Not sure whether the Bool marshalling was wrong, but I removed that, too.
Can't believe this took hours to figure out again, gotta love P/Invoke. Hope this will help somebody else, too.

How to hook an application?

I'm trying to hook the creation of a windows in my C# app.
static IntPtr hhook = IntPtr.Zero;
static NativeMethods.HookProc hhookProc;
static void Main(string[] args)
{
// Dummy.exe is a form with a button that opens a MessageBox when clicking on it.
Process dummy = Process.Start(#"Dummy.exe");
try
{
hhookProc = new NativeMethods.HookProc(Hook);
IntPtr hwndMod = NativeMethods.GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);
hhook = NativeMethods.SetWindowsHookEx(HookType.WH_CBT, hhookProc, hwndMod, (uint)AppDomain.GetCurrentThreadId());
Console.WriteLine("hhook valid? {0}", hhook != IntPtr.Zero);
while (!dummy.HasExited)
dummy.WaitForExit(500);
}
finally
{
if(hhook != IntPtr.Zero)
NativeMethods.UnhookWindowsHookEx(hhook);
}
}
static int Hook(int nCode, IntPtr wParam, IntPtr lParam)
{
Console.WriteLine("Hook()");
return NativeMethods.CallNextHookEx(hhook, nCode, wParam, lParam);
}
Problem is, when clicking on my button (in Dummy.exe), I never enter in my Hook, what am I doing wrong?
Thanks.
EDIT
Program.cs
using System;
using System.Diagnostics;
namespace Hooker
{
class Program
{
static IntPtr hhook = IntPtr.Zero;
static NativeMethods.HookProc hhookProc;
static void Main(string[] args)
{
Process dummy = Process.Start(#"Dummy.exe");
try
{
hhookProc = new NativeMethods.HookProc(Hook);
hhook = NativeMethods.SetWindowsHookEx(HookType.WH_CBT, hhookProc, IntPtr.Zero, 0);
Console.WriteLine("hhook valid? {0}", hhook != IntPtr.Zero);
while (!dummy.HasExited)
dummy.WaitForExit(500);
}
finally
{
if(hhook != IntPtr.Zero)
NativeMethods.UnhookWindowsHookEx(hhook);
}
}
static int Hook(int nCode, IntPtr wParam, IntPtr lParam)
{
Console.WriteLine("Hook()");
return NativeMethods.CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam);
}
}
}
NativeMethods.cs
namespace Hooker
{
using System;
using System.Runtime.InteropServices;
internal static class NativeMethods
{
public delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr SetWindowsHookEx(HookType hookType, HookProc lpfn, IntPtr hMod, int dwThreadId);
[DllImport("user32.dll")]
public static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", SetLastError = true)]
public static extern int GetWindowThreadProcessId(IntPtr hwnd, ref int pid);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
}
}
For dummy, do a new Form with :
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show("CONTENT", "TITLE");
}
Like most SetWindowsHookEx hooks, WH_CBT hooks require that the hook callback lives in a separate Win32 DLL that will get loaded into the target process. This essentially requires that the hook is written in C/C++, C# won't work here.
(Low-level mouse and keyboard hooks are two exceptions to this rule. It might also be possible to use other hooks in C# but only if you are hooking one of your own threads, so dwThreadId is the id of a thread in the current process, not 0. I haven't confirmed this, though. And you need to make sure you're using the Win32 threadid, so using GetCurrentThreadId is probably the best bet here.)
If you want to watch for new windows appearing from another app, an alternative C#-friendly approach is to use the SetWinEventHook API instead, specify WINEVENT_OUTOFCONTEXT (which is the magic flag that gets the events delivered to your own process, removing the need for a DLL and making C# usable here) and hook for the EVENT_OBJECT_CREATE and EVENT_OBJECT_SHOW events. You can listen to either your own process/thread's events, or to all processes/threads on the current desktop.
This will get you all sorts of "create" and show notifications, including those for child HWNDs within dialog, and even items within listboxes and similar; so you'll need to filter to extract only those for top-level HWNDs: eg. check that idObject==OBJID_WINDOW and idChild==0; that hwnd is visible (IsVisible()) and is top-level.
Note that using WinEvents requires that the thread that calls SetWinEventHook is pumping messages - which is typically the case anyway if it's a thread with UI. If not, you may need to add a message loop (GetMessage/TranslateMessage) manually. And you'll also want to use GC.KeepAlive() with the callback here also to prevent it from getting collected until after you call UnhookWinEvents.
One issue with your code is that hhookProc can be garbage collected while your native code still needs it. Use GC.KeepAlive or put in in a static variable.
The hMod param should probably be null, since you specified a thread in your own process:
hMod [in]
Type: HINSTANCE
A handle to the DLL containing the hook procedure pointed to by the lpfn parameter. The hMod parameter must be set to NULL if the dwThreadId parameter specifies a thread created by the current process and if the hook procedure is within the code associated with the current process.
But I think this only works for windows on the thread you specify.
In theory you can specify threads in other applications or even a global hook. The specified callback then gets called on the corresponding thread, even if that thread is in another process, in which case your dll gets injected into that process(that's the reason you need to specify the module handle in the first place).
But I believe that's not possible with .net code, because the mechanism for injecting into other processes and calling the hook method over there doesn't work with JIT compiled code.
This won't work in C#
Scope: Thread
If the application installs a hook procedure for a thread of a different application, the procedure must be in a DLL.
(Documentation of SetWindowsHookEx)
Scope: Global
To install a global hook, a hook must have a native DLL export to inject itself in another process that requires a valid, consistent function to call into. This behavior requires a DLL export. The .NET Framework does not support DLL exports.
(Source)
I'm not familiar with the NativeMethod class you are referencing, but I'll make some assumptions and try to make some ground.
My guess this has to do with what handle you are hooking. The
dummy.MainWindowHandle
represents the front most window's handle, which is usually what you are looking for. However, in this case, you are opening a MessageBox.Show() which likely has a different handle than the one you have hooked to.
I'd assume that
IntPtr hwndMod = NativeMethods.GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);
is probably going to return the same result as
dummy.Refresh();
IntPtr hwndMod = dummy.MainWindowHandle;
So I think it's safe to say that they might be giving you the handle you aren't looking for.
Perhaps try to make a test WinForm application. That way you can grab the proper handle. Just make sure to use
dummy.WaitForInputIdle();
dummy.Refresh();
before grabbing the handle to make sure you are grabbing the right handle at launch time.
I see it is a console application , so console application doesn't enter a windows messages loop.
simple solution is to include system.windows.forms
and simply type application.start() in your main
and things will be fine :)

Calling GetGUIThreadInfo via P/Invoke

I want to send keyboard input to a window in another process, without bringing that window to the foreground. I can use PostMessage to fake the WM_KEYDOWN and WM_KEYUP; all I need to know is which window handle should receive the keyboard input -- i.e., something like GetFocus, but for another, non-active application.
The GetGUIThreadInfo API looks promising -- it returns an hwndFocus for another app. But I've had no luck getting it to work from C# on my 64-bit OS. I've copied (and then further tweaked) the declarations from pinvoke.net, but all I ever get back is a generic error code (more details below).
I am setting cbSize before I call GetGUIThreadInfo, so I've avoided the most obvious potential problem.
I'm running 64-bit Vista, so I don't know whether the problem is that I'm not using the API correctly, or that it works differently in 64-bit -- I have yet to find a code sample that specifically says it works successfully in Win64.
Here's sample code. I'm using GetWindowThreadProcessId as recommended, so I don't think the problem has to do with mixing thread IDs with thread handles:
[StructLayout(LayoutKind.Sequential)]
internal struct Rect
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[StructLayout(LayoutKind.Sequential)]
internal class GuiThreadInfo
{
public int cbSize;
public uint flags;
public IntPtr hwndActive;
public IntPtr hwndFocus;
public IntPtr hwndCapture;
public IntPtr hwndMenuOwner;
public IntPtr hwndMoveSize;
public IntPtr hwndCaret;
public Rect rcCaret;
}
[DllImport("user32.dll")]
internal static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool GetGUIThreadInfo(uint idThread, ref GuiThreadInfo lpgui);
IntPtr GetFocusedHandleFromProcessWithWindow(IntPtr window)
{
var threadId = GetWindowThreadProcessId(window, IntPtr.Zero);
var info = new GuiThreadInfo();
info.cbSize = Marshal.SizeOf(info);
if (!GetGUIThreadInfo(threadId, ref info))
throw new Win32Exception();
return info.hwndFocus;
}
window is a valid window handle; GetWindowThreadProcessId returns a nonzero thread handle. But the call to GetGUIThreadInfo always returns false, and the exception message is always "The parameter is incorrect".
Just in case the problem was that GetGUIThreadInfo somehow doesn't have a 64-bit version, I tried changing all the 8-byte IntPtrs in the GuiThreadInfo declaration to 4-byte ints, but I still got the same error.
Does anyone have a working C# sample of GetGUIThreadInfo on Win64? Or, is there another way to find what the focused child-window handle would be in another app, without making that app active?
I haven't looked at it too closely but one thing jumps out. In your GetGUIThreadInfo call you pass the GUIThreadInfo structure by ref but you've defined it as a class so you are sending a reference by ref, in other words a pointer to a pointer. Either change your GUIThreadInfo to a struct or remove the ref on the parameter and add [In, Out] attributes.

Suspend Process in C#

How do I suspend a whole process (like the Process Explorer does when I click Suspend) in C#.
I'm starting the Process with Process.Start, and on a certain event, I want to suspend the process to be able to do some investigation on a "snapshot" of it.
Here's my suggestion:
[Flags]
public enum ThreadAccess : int
{
TERMINATE = (0x0001),
SUSPEND_RESUME = (0x0002),
GET_CONTEXT = (0x0008),
SET_CONTEXT = (0x0010),
SET_INFORMATION = (0x0020),
QUERY_INFORMATION = (0x0040),
SET_THREAD_TOKEN = (0x0080),
IMPERSONATE = (0x0100),
DIRECT_IMPERSONATION = (0x0200)
}
[DllImport("kernel32.dll")]
static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId);
[DllImport("kernel32.dll")]
static extern uint SuspendThread(IntPtr hThread);
[DllImport("kernel32.dll")]
static extern int ResumeThread(IntPtr hThread);
[DllImport("kernel32", CharSet = CharSet.Auto,SetLastError = true)]
static extern bool CloseHandle(IntPtr handle);
private static void SuspendProcess(int pid)
{
var process = Process.GetProcessById(pid); // throws exception if process does not exist
foreach (ProcessThread pT in process.Threads)
{
IntPtr pOpenThread = OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)pT.Id);
if (pOpenThread == IntPtr.Zero)
{
continue;
}
SuspendThread(pOpenThread);
CloseHandle(pOpenThread);
}
}
public static void ResumeProcess(int pid)
{
var process = Process.GetProcessById(pid);
if (process.ProcessName == string.Empty)
return;
foreach (ProcessThread pT in process.Threads)
{
IntPtr pOpenThread = OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)pT.Id);
if (pOpenThread == IntPtr.Zero)
{
continue;
}
var suspendCount = 0;
do
{
suspendCount = ResumeThread(pOpenThread);
} while (suspendCount > 0);
CloseHandle(pOpenThread);
}
}
Thanks to Magnus
After including the Flags, I modified the code a bit to be an extension method in my project. I could now use
var process = Process.GetProcessById(param.PId);
process.Suspend();
Here is the code for those who might be interested.
public static class ProcessExtension
{
[DllImport("kernel32.dll")]
static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId);
[DllImport("kernel32.dll")]
static extern uint SuspendThread(IntPtr hThread);
[DllImport("kernel32.dll")]
static extern int ResumeThread(IntPtr hThread);
public static void Suspend(this Process process)
{
foreach (ProcessThread thread in process.Threads)
{
var pOpenThread = OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)thread.Id);
if (pOpenThread == IntPtr.Zero)
{
break;
}
SuspendThread(pOpenThread);
}
}
public static void Resume(this Process process)
{
foreach (ProcessThread thread in process.Threads)
{
var pOpenThread = OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)thread.Id);
if (pOpenThread == IntPtr.Zero)
{
break;
}
ResumeThread(pOpenThread);
}
}
}
I have a utility done which I use to generally suspend/kill/list a process. Full source is on Git
So really, what the other answer's are showing is suspending thread's in the process, there is no way to really suspend the process (i.e. in one call)....
A bit of a different solution would be to actually debug the target process which you are starting, see Mike Stall's blog for some advice how to implement this from a managed context.
If you implement a debugger, you will be able to scan memory or what other snap-shotting you would like.
However, I would like to point out, that technically, there is now way to really do this. Even if you do debugbreak a target debuggee process, another process on your system may inject a thread and will be given some ability to execute code regardless of the state of the target process (even let's say if it's hit a breakpoint due to an access violation), if you have all thread's suspended up to a super high suspend count, are currently at a break point in the main process thread and any other such presumed-frozen status, it is still possible for the system to inject another thread into that process and execute some instructions. You could also go through the trouble of modifying or replacing all of the entry point's the kernel usually calls and so on, but you've now entered the viscous arm's race of MALWARE ;)...
In any case, using the managed interfaces for debugging seems' a fair amount easier than p/invoke'ng a lot of native API call's which will do a poor job of emulating what you probably really want to be doing... using debug api's ;)
See this CodeProject article for the win32 basics : http://www.codeproject.com/KB/threads/pausep.aspx. This sample code makes use of the ToolHelp32 library from the SDK, so I would recommend turning this sample code into an unmanaged C++/CLI library with a simple interface like "SuspendProcess(uint processID).
Process.Start will return you a Process object, from which you can get the process id, and then pass this to your new library based on the above.
Dave
[DllImport("ntdll.dll", PreserveSig = false)]
public static extern void NtSuspendProcess(IntPtr processHandle);
static IntPtr handle;
string p = "";
foreach (Process item in Process.GetProcesses())
{
if (item.ProcessName == "GammaVPN")
{
p = item.ProcessName;
handle = item.Handle;
NtSuspendProcess(handle);
}
}
Console.WriteLine(p);
Console.WriteLine("done");

Categories

Resources