📜 ⬆️ ⬇️

Implementing code in Silverlight

image In my free time I develop Snoop . This is a great help for WPF developers, which does not have good free analogues in the world of Silverlight. Snoop injects its assembly into the WPF process and lays it out on the shelves.

I was curious: is it possible to embed an arbitrary assembly into a running silverlight process from outside the browser? (possible) This will be discussed under the cut.


')
As far as I know, all existing programs that embed code in silverlight do this by intercepting and modifying the .xap file before loading the application. This is a good way, but it has several disadvantages:

1. You can not connect to an already running application without reloading the page.
2. Intercepting the .xap file often limits the execution environment of the Internet Explorer plugin. For a universal interceptor, you need to use / write http-sniffer.

I want to suggest a method that allows you to connect to an already running application and integrate into it without reloading the page, without modifying the .xap file and without restricting the browser. Before we begin, let me introduce today's open-source guest:

slinject

This console program is the fruit of programmer curiosity. It allows you to select a process that executes the Silverlight and embed the Silverlight assembly into it (click for higher resolution):

Assembly injection example


Binaries can be downloaded here , and the source code in C # is available on github'e . Before you begin to be introduced, the program must be installed by running the command:

slinject --install

This is a one-time operation requiring administrative rights. After installing the injector can be implemented by any user.

Wait, don't leave! Or how it works

As is often the case, the idea is very simple. Connect with the debugger to the Silverlight process and execute the Assembly.Load () command. It was always possible to do it from the Visual Studio debugger, but can it be done from your program?

Silverlight is installed with a number of interesting libraries and tools that, unfortunately, have either disgusting documentation or none. One such library is dbgshim.dll . It is through this door that debuggers walk into the world of Silverlight. Visual Studio uses it, so why don't we take advantage of the loophole? True, why not? The absence of good documentation cannot be called a good argument. But a good challenge for the curious is possible.

So, after several nights of wandering around the realm of Morpheus, the ICorDebug namespace managed to write a console program that could be a simple Silverlight debugger of processes. She was able to react to the main events of the debugger, find the necessary functions, set bryakpoint and dwell on them. Sometimes she even knew how to do expression evaluation (aka function evaluation, FuncEval), to execute code, I mean. Alas, she never learned how to make coffee.

Problem

It was necessary to find a method in Silverlight, which would be guaranteed to be called in any Silverlight process in order to put a breakpoint in it. In the case of WPF / WinForms applications, everything is simple. We take handler of queue of Windows of messages and we put break point in it. But there is no Windows message queue in Silverlaite. Fortunately, it has a close analogue: the JoltHelper.FireEvent () method. This method is called even in an empty Silverlight application, you just need to move the mouse.

Remember, I said that the console debugger could do expression evaluation ... sometimes? In fact, to execute code during a breakpoint, the debugging infrastructure requires a number of conditions . If the method is optimized for any funceval, there can be no talk. JoltHelper.FireEvent () is, of course, optimized:

Optimized code disables FuncEval


Decision

It turns out Silverlight jitter, like its big brother from the .NET world, listens to .ini recommendations for optimizing the generated code. It is enough to create the following .INI file next to the assembly:

[.NET Framework Debugging Control]
GenerateTrackingInfo=1
AllowOptimize=0


Save it as “Assembly_No_D_D_DJ.INI”, and the next time during JIT compilation the generated code will be more friendly to the debugger. The biggest catch is in the .ini file encoding. If it is different from UTF-16 Little Endian, the file will be simply ignored.

To improve performance, Silverlight, during installation, generates machine code images for standard assemblies. In fact, the same ngen , only the utility is called coregen, and the result of the generation is put in the Silverlight folder. Coregen also takes into account the availability of .ini recommendations, and can generate debugged machine code.

When you speak:

slinject --install

The program creates a System.Windows.ini file with the necessary jitter recommendations. deletes the old precompiled System.Windows.ni.dll image, and asks the coregen to create a debugged image. And of course, to undo all these changes, you just need to perform

slinject --uninstall

So what?


Finally

So, are we getting a universal Silverlight assembly builder? Unfortunately no. Even killing a thread looks more innocuous than interrupting it in a random place with a request to execute a random code. Mike Stall in his blog tells why FuncEval is evil , but useful evil. In the end, this is how Watches / Locals / Immediate windows work in Visual Studio. Armed with this knowledge, using slinject, get ready for the crashes of Silverlight processes, browser crashes and deception of politicians.

Moreover, I am not an expert in COM'e / ICorDebug'e. Surely I have done a bunch of blunders in the code , but this is open source - I will be glad if you show / fix errors.

I hope you enjoyed this walk into the world of the Silverlight debugger - I will be happy for the reviews :).

Source: https://habr.com/ru/post/128189/


All Articles