I am working on a "debug dispatcher" C# program that is a debug assistance tool. This is not a new application; it has been a part of this project and invaluable to debugging it for some time. However, it has some limitations, which I have been trying to address to enable a more complete debugging experience.
This debug dispatcher takes the place of a system service that accepts requests to launch applications, and its purpose is to permit an attached debugger to automatically interact with code that would ordinarily be launched in a child process. The child processes are themselves .NET applications.
When this tool was made (years ago), the first thing that was investigated was whether there might be any way to launch a child process with the current debugger already attached to it. None was found, and so instead the tool creates an independent AppDomain within which to launch each process, then loads the application as an assembly and calls its entry method. This is almost working perfectly, but the problem I'm running into is that if those child processes call Environment.GetCommandLineArgs, they get the debug dispatcher tool's command-line instead of the command-line intended to be passed into a child process.
I have been trying to find a way to override Environment.GetCommandLineArgs.
Based on the publicly-available source code, it looks like if my application were .NET Core, there would in fact be an internal method SetCommandLineArgs I could invoke via reflection. The fact that this is internal isn't particularly troubling to me as this tool is specifically a debug assistant; if it happens to break down the road because the implementation changed, so be it. It serves no purpose whatsoever outside of a debugging context and won't ever be on a non-dev machine. But... .NET Core and .NET 5 don't support AppDomains at all, and never will, so that's a non-starter.
I have tried using Ryder to redirect Environment.GetCommandLineArgs to my own implementation, but it doesn't seem to work, even with a .ini file specifying a [.NET Framework Debugging Control] section with AllowOptimize=0. It almost looks as though the JIT has special handling for this specific method, because even though the reference source shows it making an icall into a native method, when I request disassembly of the JIT output in the debugger, it shows no calls at all, simply loading a value directly from an inlined memory address.
I searched for ways to change the current process's command-line at the Win32 level, but that appears to be unmodifiable.
In the context of supporting multiple concurrent applications inside the same process by means of AppDomains (solely for assisting debugging), is there any way to intercept and/or override the return value of Environment.GetCommandLineArgs, so that I can support hosting applications that obtain their command-line arguments exclusively via that method?
Okay, well, I'm not sure what I did that changed it, but at some point redirecting Environment.GetCommandLineArgs using Ryder seemed to go from being unreliable (some calls would redirect, others wouldn't -- in some debug sessions, Ryder seemed to have no effect at all) to reliable (every call gets redirected). Ryder's redirection apparently doesn't automatically apply in all AppDomains, so I have to reinstall it each time I create an AppDomain, after which my experience has been that the process dies a messy death if I try to unload the AppDomain. But, for debug purposes... I think it's adequate.
Related
The title of my question might already give away the fact that I'm not sure about what I want, as it might not make sense.
For a project I want to be able to run executables within my application, while redirecting their standard in and out so that my application can communicate with them through those streams.
At the same time, I do not want to allow these executables to perform certain actions like use the network, or read/write outside of their own working directory (basically I only want to allow them to write and read from the standard in and out).
I read on different places on the internet that these permissions can be set with PermissionStates when creating an AppDomain in which you can then execute the executables. However, I did not find a way to then communicate with the executables through their standard in and out, which is essential. I can however do this when starting a new Process (Process.Start()), though then I cannot set boundaries as to what the executable is allowed to do.
My intuition tells me I should somehow execute the Process inside the AppDomain, so that the process kind of 'runs' in the domain, though I cannot see a way to directly do that.
A colleague of mine accomplished this by creating a proxy-application, which basically is another executable in which the AppDomain is created, in which the actual executable is executed. The proxy-application is then started by a Process in the main application. I think this is a cool idea, though I feel like I shouldn't need this step.
I could add some code containing what I've done so far creating a process and appdomain, though the question is pretty long already. I'll add it if you want me to.
The "proxy" application sounds like a very reasonable approach (given that you only ever want to run .NET assemblies).
You get the isolation of different processes which allows you to communicate via stdin/stdout and gives the additional robustness that the untrusted executable cannot crash your main application (which it could if it was running in an AppDomain inside your main application's process.
The proxy application would then setup a restricted AppDomain and execute the sandboxed code, similar to the approach described here:
How to: Run Partially Trusted Code in a Sandbox
In addition, you can make use of operation system level mechansims to reduce the attack surface of a process. This can be achieved e.g. by starting the proxy process with lowest integrity which removes write access to most resources (e.g. allow writing files only in AppData\LocalLow). See here for an example.
Of course, you need to consider whether this level of sandboxing is sufficient for you. Sandboxing, in general, is hard, and the level of isolation always will be to a certain degree only.
I have a ASP.NET (C#) website that uses a third party DLL to process the data that the users POST via a web form. The call is pretty straightforward:
string result = ThirdPartyLib.ProcessData(myString);
Once in a blue moon this library hangs and (according to my hosting provider logs) consumes 100% of CPU. The website is hosted on a shared hosting, so I have no access to the IIS or event logs. When this happens, my website is automatically stopped by the hosting provider performance monitor, and I have manually switch it back on.
Now, I know that the right thing to to is investigate the problem and fix (or replace) the DLL. But as it's third-party software, I am unuable to fix it, and their support is not helpful at all. Moreover, I can't reproduce the problem. Replacing the library is a pain too.
Is there a way in C# to detect when this DLL starts consuming 100%CPU and kill the process automatically from my ASP.NET code?
You cannot "detect" if the current process is hanging because as the caller of a method (third party or not) you're simply not in control until it returns.
What you can do is move the call to the third party library into a separate executable and have it output its result via the standard output (you can simply use Console.WriteLine(string) for this).
Once you've done that, you can start a separate Process that runs this executable, read the result via StandardOutput and use WaitForExit(int) to wait a certain amount of time (maybe a few seconds) for the process to finish. The return value of WaitForExit() tells you if the process actually exited. In case it didn't, you can Kill() it and move on without IIS worker process hanging as a whole.
I got a problem, i have accidentally left "Debugger.Launch();" code in my project, which was needed for the debugging as the application is a Windows Service.
Now, i'am done with the projects, it´s working as intended (Mostly) BUT, every time you start the service, it asks if you want to attach a debugger.
The Service has been packed to a MSI-package, and is more or less ready for delivery. And the guy who handles all the packaging and such is not at the office and none else know how to do it or has the authority to do it.
Enough with the backstory..
Can i in any way disable the debugger code without repackaging the
service? - Or do i have to repackage?
Is there any startup command or something to prevent it to ask for
debugger?
I have been searching alot about this, but the most of the existing questions/posts about this regards "Prebuild" solutions, but i'am looking for a "Postbuild" solution.
[EDIT]
Solution (Some kind of..)
I have still no idea if it is even possible to prevent attaching, but with the research i've done, it seems impossible. Therefore i had to recompile the service.
As many of you that commented suggested i implemented a key in the app.config, and a simple "if-case" around the "Debugger.Launch()", which work perfectly. Now i can simply choose to attach debugger or not.
Tamir Vereds solution worked on my local machine, and i did not even try on the customers server, because of the reason he also stated about base my code on this kind of tweaks.
I will accept this answer, as it partly could fix the initial problem.
Thank you all for answering.
Usually I would recommend recompiling the application and allowing it to be invoked with an argument or configuration cancelling the Debugger.Launch call, but since you don't want to recompile...
As for the documentation of Debugger.Launch() method:
If a debugger is already attached, nothing happens.
You can take advantage of that fact by making another small process that will "debug" your original process.
Since your process is a windows service you might need to use Auto-Debugger-Attach:
Open the registry editor by typing regedit in the cmd.
Navigate to: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options.
Add a key with your debugged application's .exe's name.
Add a string value to that key with the name Debugger when the value is your new "Debugger process" path.
With your fake debugger attached, the original process will return frm the Debugger.Launch method without invoking another debugger.
Also you might want your fake debugger to deattach itself somehow later on so you can still really debug your application when needed.
Note that this is sort of an tweak and you don't want to base your production code on this kind of stuff.
Over the months, I've developed a personal tool that I'm using to compile C# 3.5 Xaml projects online. Basically, I'm compiling with the CodeDom compiler. I'm thinking about making it public, but the problem is that it is -very-very- easy to do anything on the server with this tool.
The reason I want to protect my server is because there's a 'Run' button to test and debug the app (in screenshot mode).
Is this possible to run an app in a sandbox - in other words, limiting memory access, hard drive access and BIOS access - without having to run it in a VM? Or should I just analyze every code, or 'disable' the Run mode?
Spin up an AppDomain, load assemblies in it, look for an interface you control, Activate up the implementing type, call your method. Just don't let any instances cross that AppDomain barrier (including exceptions!) that you don't 100% control.
Controlling the security policies for your external-code AppDomain is a bit much for a single answer, but you can check this link on MSDN or just search for "code access security msdn" to get details about how to secure this domain.
Edit: There are exceptions you cannot stop, so it is important to watch for them and record in some manner the assemblies that caused the exception so you will not load them again.
Also, it is always better to inject into this second AppDomain a type that you will then use to do all loading and execution. That way you are ensured that no type (that won't bring down your entire application) will cross any AppDomain boundary. I've found it is useful to define a type that extends MarshalByRefObject that you call methods on that executes insecure code in the second AppDomain. It should never return an unsealed type that isn't marked Serializable across the boundary, either as a method parameter or as a return type. As long as you can accomplish this you are 90% of the way there.
The application in question is written in C#. We are late in the development cycle, close to launch on our application. One of my coworkers is seeing the following issue:
When he logs out of his Windows 7 session while the application is running, he gets a "csc.exe - Application Error" popup window that says "The application was unable to start correctly (0xc0000142). Click OK to close the application."
I believe that I have tracked this down to the fact that we update the application's XML config file on exit, and the code uses XmlSerializer. According to this question, XmlSerializer launches csc.exe to compile serialization assemblies dynamically on an as-needed basis, at run time. My suspicion is bolstered by the fact that, if I remove the update to the config file at exit time, then my coworker no longer sees the error message in question.
Can someone explain to me in more detail what is happening here? Why does csc.exe fail to start properly when executed at system logout? Is there some low-risk solution that I can put in place to mitigate the problem?
Things I have considered:
Use sgen to generate the serialization assemblies and deploy them with the application. This sounds promising, but my experiments with it were pretty dismal. It seems to only be able to generate a DLL either for an entire assembly or for a single class, no way to specify a list of classes. Also, when I point it to one of my assemblies, it starts complaining about classes in the assembly with duplicate names.
Use another means to read / write the XML. I'm not confident about implementing this at our current stage of development. We are hoping to launch soon, and this feels like too much of a risk.