Внедрение кода в Silverlight

    imageВ свободное время я занимаюсь разработкой Snoop'a. Это отличное подспорье WPF разработчикам, которое не имеет хороших бесплатных аналогов в мире Silverlight. Snoop внедряет свою сборку в WPF процесс и раскладывает его по полочкам.

    Мне стало любопытно: можно ли внедрить произвольную сборку в исполняющийся сильверлайт процесс извне браузера? (можно) Об этом и пойдет речь под катом.



    Насколько мне известно, все существующие программы, внедряющие код в сильверлайт, делают это посредством перехвата и модификации .xap файла до загрузки приложения. Это неплохой способ, однако он обладает рядом недостатков:

    1. Нельзя подключиться к уже запущенному приложению без перезагрузки страницы
    2. Перехват .xap файла зачастую ограничивает среду выполнения плагина Internet Explorer'ом. Для универсального перехватчика нужно использовать/писать http-сниффер.

    Я же хочу предложить способ, который позволяет подключиться к уже запущенному приложению и внедриться в него без перезагрузки страницы, без модификации .xap файла и без ограничений на браузер. Прежде чем мы начнем, позвольте представить сегодняшнего open-source гостя:

    slinject

    Эта консольная программа — плод программистского любопытства. Она позволяет выбрать исполняющийся Silverlight процесс и внедрить в него Silverlight сборку (тыкните для большего разрешения):

    Assembly injection example


    Бинарники можно скачать здесь, а исходный код на C# доступен на github'e. Прежде чем вы начнете внедряться, программу нужно установить, выполнив команду:

    slinject --install

    Это одноразовая операция, требующая администраторских прав. После установки инжектора внедряться можно под любым пользователем.

    Подождите, не уходите! Или как это работает

    Как это часто бывает, идея очень простая. Подключиться отладчиком к Silverlight процессу и выполнить команду Assembly.Load(). Это всегда было можно сделать из отладчика Visual Studio, но можно ли это сделать из своей программы?

    Сильверлайт устанавливается с рядом интересных библиотек и инструментов, которые, к сожалению, имеют либо отвратительную документацию, либо никакой. Одна из таких библиотек — dbgshim.dll. Именно через эту дверь ходят отладчики в мир Silverlight'a. Visual Studio использует ее, так почему бы и нам не воспользоваться лазейкой? Правда, почему бы и нет? Отстутвие хорошей документации нельзя назвать хорошим аргументом. А вот хорошим вызовом для любопытных — можно.

    Итак, после нескольких ночей блуждания по царству Морфея пространству имен ICorDebug мне удалось написать консольную программу, которая умела быть простым отладчиком Silverlight процессов. Она умела реагировать на основные события отладчика, находить нужные функции, устанавливать брякпоинты и останавливаться на них. Иногда она даже умела делать expression evaluation (ака function evaluation, FuncEval), исполнять код то бишь. Увы, готовить кофе она так и не научилась.

    Проблема

    Нужно было найти метод в Silverlight, который бы гарантированно вызывался в любом Silverlight процессе, чтобы поставить брякпоинт в нем. В случае с WPF/WinForms приложениям — все просто. Берем обработчик очереди Windows сообщений и ставим точку останова в нем. Но в Сильверлайте нет очереди Windows сообщений. К счастью, в нем есть близкий аналог: метод JoltHelper.FireEvent(). Этот метод вызывается даже в пустом Silverlight приложении, достаточно лишь пошевелить мышку.

    Помните, я сказал, что консольный отладчик умел делать expression evaluation… иногда? На самом деле, чтобы выполнить код во время точки останова инфраструктура отладки требует ряда условий. Если метод оптимизирован ни о каком funceval'e и речи быть не может. JoltHelper.FireEvent(), конечно, оптимизирован:

    Optimized code disables FuncEval


    Решение

    Оказывается Silverlight jitter, как и его большой брат из мира .NET, прислушивается к .ini рекомендациям по оптимизации генерируемого кода. Достаточно создать следующий .INI файл рядом со сборкой:

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


    Сохранить его как «Имя_сборки_без_dll.ini», и в следующий раз во время JIT-компиляции генерируемый код будет более дружелюбен к отладчику. Самый большой подвох заключается в кодировке .ini файла. Если она отличается от UTF-16 Little Endian — файл будет просто проигнорирован.

    Для улучшения производительности, Silverlight, во время установки, генерирует образы в машинных кодах для стандартных сборок. По сути, тот же самый ngen, только утилита называется coregen, и результат генерации кладется в папку Silverlight'a. Coregen также принимает во внимание наличие .ini рекомендаций, и может генерировать пригодный для отладки машинный код.

    Когда вы говорите:

    slinject --install

    Программа создает System.Windows.ini файл с нужными рекомендациями jitter'у. удаляет старый прекомпилированный образ System.Windows.ni.dll, и просит coregen создать отлаживабельный образ. Ну и конечно, чтобы отменить все эти изменения, достаточно выполнить

    slinject --uninstall

    So what?


    В заключение

    Итак, мы получили универсальный внедритель сборок в Silverlight? Увы, нет. Даже убийство потока выглядит более безобидно, чем прерывание его в случайном месте с просьбой выполнить случайный код. Mike Stall в своем блоге рассказывает почему FuncEval — зло, но полезное зло. В конце концов, именно так работают окна Watches/Locals/Immediate в Visual Studio. Вооружившись этими знаниями, используя slinject, будьте готовы к падениям Silverlight процессов, крешам браузеров и обманам политиков.

    Более того, я не эксперт в COM'e/ICorDebug'e. Наверняка я наделал кучу ляпов в коде, но ведь это открытый код — буду рад если вы покажете/исправите ошибки.

    Надеюсь, вам понравилась эта прогулка в мир отладчика Silverlight — буду рад отзывам :).

    Похожие публикации

    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 6

      0
      Как понимаю большинство построено на MDbg?
        0
        Из MDbg я взял лишь парсинг метаданных и определение COM интерфейсов. В последний раз когда я пробовал его скомпилировать — пришлось долго колдовать над проектом. В этот раз не рискнул, решил написать лишь минимально необходимый набор оберток над интерфейсами.

        Для общественности: MDbg — это open source пример отладчика CLR, построенный на CLR Debugging Services APIs (ICorDebug). Скачать можно здесь: www.microsoft.com/download/en/details.aspx?displaylang=en&id=19621
          0
          Вообще забавно получилось. Жаль, что и по аналогии с MDbg никаких комментов, трудновато сразу было читать.
            0
            Спасибо! Посыпаю голову пеплом. Я обязательно добавлю коментарии.
        0
        Епрст… чувствую себя школьником, когда такие статьи читаю
          0
          Либо я все запутанно написал, либо материал просто новый :) — не отчаивайтесь. Узнавать новое — это всегда здорово

        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

        Самое читаемое