Получение кода метода класса

Программирование на Visual Basic, главный форум. Обсуждение тем программирования на VB 1—6.
Даже если вы плохо разбираетесь в VB и программировании вообще — тут вам помогут. В разумных пределах, конечно.
Правила форума
Темы, в которых будет сначала написано «что нужно сделать», а затем просьба «помогите», будут закрыты.
Читайте требования к создаваемым темам.
djalex777
Постоялец
Постоялец
 
Сообщения: 461
Зарегистрирован: 23.03.2006 (Чт) 16:02

Re: Получение кода метода класса

Сообщение djalex777 » 14.11.2015 (Сб) 14:12

Хакер писал(а):вся адресация съедет

Вот в этом и проблема и вопрос, как её правильно подправить?

The trick
Постоялец
Постоялец
 
Сообщения: 781
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: Получение кода метода класса

Сообщение The trick » 14.11.2015 (Сб) 14:12

Хакер писал(а):Причём тут другие члены?

Если у тебя в был большой метод CSomeClass::Foo с неким секретным кодом, и ты скомпилировался проект в первый раз, а затем подменил контент метода CSomeClass::Foo на маленькую заглушку, которая только подгружает код с сервера, то даже при том, что другие функции и процедуры в твоём проекте были не тронуты, вся адресация съедет.

Ну вызов методов идет посредством указателя, поэтому это не важно. Хотя для глобальных функций объявленых в стандартном модуле это создаст проблему.
Можно просто модули добавить в проект до классов. Насколько я знаю код модулей располагается в порядке добавления в проект. Если код стандартных модулей будет располагаться вначале, то адресация не слетит на них. Для методов, придется для каждого метода компилировать отдельно и переписывать релокации. Но это гемор, еще тот. Если для одного раза и методов немного то пойдет.
UA6527P

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Получение кода метода класса

Сообщение Хакер » 14.11.2015 (Сб) 14:19

The trick писал(а):Ну вызов методов идет посредством указателя, поэтому это не важно. Хотя для глобальных функций объявленых в стандартном модуле это создаст проблему.


Не только.

Почему ты забыл обо всём, кроме членов классов?

Declare-функции — в пролёте.
Обычные модульные функции — в пролёте.
Функции, импортированные через TLB — в пролёте.
Рантаймовые функции, импортированные неявно, если они были использованы только в вырезаемой процедуре — в пролёте.
Обращения к глобальным переменным (если к ним обращение было только из вырезаемой процедуры) — в пролёте.
Обращение к вшитым в образ ресурсам (вроде RESDESCTBL), о существовании которых VB-программист даже не дагдывается — в пролёте.

djalex777 писал(а):от в этом и проблема и вопрос, как её правильно подправить?

Да очень просто. Вернее офигеть как сложно.

Тебе придётся, как я написал в самом первом своём посте, заново изобрести формат, аналогичный DLL.

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

Придётся либо каждый раз эту таблицу составлять вручную, либо анализировать obj-файл на этапе между компиляцией и линковкой.

При этом придётся ещё и подсовывать спец. ключи линкеру, чтобы на этапе компиляции оболваленной версии исполняемого файла сущности, к которым теперт нет ни одного обращения (если обращения были только из вырезанного тела секретного метола) не были выброшены на этапе линковки.

_______


Либо нужно записывать код именно туда, откуда он был взят. Хранимый на сервере фрагментик должен один-в-один соответствовать файлу, из которого фрагмент был вырезан. Если предполагается, что продукт будет перекомпилироваться более 1 раза за всю историю существования, после каждого перекомпилирования и получения каждой новой версии файла на сервер надо загрузать новый фрагментик именно для этой версии.

Запись загруженного с сервера фрагментика именно туда, откуда он был вырезан освобождает от необходимости корректировать адреса вообще. Но необходимо будет сверять файл, который мы собираемся патчить и фрагментик, скачиваемый с сервера, по хэшу.

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

Это самый простой выход из положения, если не отказываться от идеи подобного механизма защиты, который, повторюсь, супер-убогий и не стоит того, чтобы тратить на него столько сил.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Получение кода метода класса

Сообщение Хакер » 14.11.2015 (Сб) 14:21

The trick писал(а):Если код стандартных модулей будет располагаться вначале, то адресация не слетит на них.

Слетит. Если модуль содержит процедуру, к которой было обращение только из вырезаемого метода, то при компиляции оболваленной версии код подобных процедур будет выброшен.

Мой фирменный трюк определения Debug-режима, который, я не сомневаюсь, тебе известен, как раз использует эту особенность линковки — служебная функция MakeTrue в release-версию не попадает.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

The trick
Постоялец
Постоялец
 
Сообщения: 781
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: Получение кода метода класса

Сообщение The trick » 14.11.2015 (Сб) 14:36

Хакер писал(а):Не только.

Почему ты забыл обо всём, кроме членов классов?

Declare-функции — в пролёте.
Обычные модульные функции — в пролёте.
Функции, импортированные через TLB — в пролёте.
Рантаймовые функции, импортированные неявно, если они были использованы только в вырезаемой процедуре — в пролёте.
Обращения к глобальным переменным (если к ним обращение было только из вырезаемой процедуры) — в пролёте.
Обращение к вшитым в образ ресурсам (вроде RESDESCTBL), о существовании которых VB-программист даже не дагдывается — в пролёте.

Да, Вы правы, уж слишком много "если" чтобы обойти все эти проблемы. Хотя если есть желание можно обюходить это так или иначе, но все будет валидно только для единственного билда + нужны знания ассемблера, отладчика и работы VB.
Я немного подумал, как альтернатива, можно сделать даже немного проще (может не прав, т.к. не анализировал глубоко). Можно вставлять код прямо в места оригинала. Для этого компилируем финальный EXE с релокациями. И имеем глобальгную функцию для загрузки с сервера, которая будет загружать метод. При загрузке мы расширяем место для метода (мы это можем делать т.к. у нас есть релокации) и пишем туда код, релокации сразу поправляем с места откуда начали править код. Если не использовать оптимизации, т.е. никакой неиспользуемый код не будет удален из EXE то это должно работать. Обеспечить наличие всех функций после компиляции.
Вырезать фрагментик перед отправкой бинарника клиенту нужно, естественно, затиранием кода секретного метода другим кодом — кодом подгрузки и мусором.

Вот это как раз и вызывает проблему, т.к. чистым VB это не рашить (ну почти не решить). Если автор имеет возможность использовать ассемблерные вставки, то проблем конечно никаких нет (вставить код метода загрузки с сервера после компиляции на ассемблере), но в том то и дело что он первым постом написал:
Писать исполняемый код метода на ассемблере (или любом другом языке отличном от VB6) не подходит.
Последний раз редактировалось The trick 14.11.2015 (Сб) 14:47, всего редактировалось 1 раз.
UA6527P

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Получение кода метода класса

Сообщение Хакер » 14.11.2015 (Сб) 14:45

The trick писал(а):Можно вставлять код прямо в места оригинала. Для этого компилируем финальный EXE с релокациями. И имеем глобальгную функцию для загрузки с сервера, которая будет загружать метод. При загрузке мы расширяем место для метода (мы это можем делать т.к. у нас есть релокации) и пишем туда код, релокации сразу поправляем с места откуда начали править код. Если не использовать оптимизации, т.е. никакой неиспользуемый код не будет удален из EXE то это должно работать.


Нельзя.

Ещё раз повторюсь: можно записать скачанный код по оригинальному местоположению, но только при условии, что не было никаких двух компиляций.

Если была вторая компиляция, то вполне себе вероятно, что сущностей, на которые ссылался машинный код из первого билда, во втором билде нет вообще.

Допустим, секретный метод юзал функцию Foo из библиотеки SUPER.DLL.

Второй раз мы скомпилировали наш project.exe, и в нём нет даже дескриптора импорта для SUPER.DLL. Не то, что IAT-ячейки для функции Foo, а даже дескриптора импорта для самой библиотеки не будет. Так что толку с того, что ты будешь что-то расширять? Тебе придётся не только расширять, тебе придётся знать абсолютно все зависимости вырезанного кода от внешних сущностей, и правда в том, что эти зависимости не ограничиваются теми, которые явно подконтрольны программисту (вроде импортируемых через TLB функций), но включают и зависимости от рантаймовых функций и встраиваемых служебных структур.

Так что, повторяюсь, единственный реально работающий технический метод — это брать .obj-файл, внутри которого находится секретный метод, и на основе .obj генерировать либо .DLL (что не получится просто так), либо .LIB, а дальше во время выполнения подгружать и собственными силами долинковывать этот .LIB к своему EXE (или DLL — если секретный метод был частью ActiveX DLL проекта). Или же, если .DLL/.LIB не устраивают, придумывать свой собственный велосипед контейнер для кода с сохранением метаданных о зависимостях и писать собственный генератор подобных контейнеров на основе .obj-файлов и собственный механизм отложенной долинковки (то есть по сути свой собственный примитивный линкер).

Либо отказаться от подхода с двухпроходной компиляцией.

The trick писал(а):Вот это как раз и вызывает проблему, т.к. чистым VB это не рашить (ну почти не решить).

Почему не решить? Рассказать тебе, как решить?
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

The trick
Постоялец
Постоялец
 
Сообщения: 781
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: Получение кода метода класса

Сообщение The trick » 14.11.2015 (Сб) 15:01

Хакер писал(а):
The trick писал(а):Можно вставлять код прямо в места оригинала. Для этого компилируем финальный EXE с релокациями. И имеем глобальгную функцию для загрузки с сервера, которая будет загружать метод. При загрузке мы расширяем место для метода (мы это можем делать т.к. у нас есть релокации) и пишем туда код, релокации сразу поправляем с места откуда начали править код. Если не использовать оптимизации, т.е. никакой неиспользуемый код не будет удален из EXE то это должно работать.


Нельзя.

Ещё раз повторюсь: можно записать скачанный код по оригинальному местоположению, но только при условии, что не были никаких двух компиляций.

Если была вторая компиляция, то вполне себе вероятно, что сущностей, на которые ссылался машинный код из первого билда, во втором билде нет вообще.

Допустим, секретный метод юзал функцию Foo из библиотеки SUPER.DLL.

Второй раз мы скомпилировали наш project.exe, и в нём нет даже дескриптора импорта для SUPER.DLL. Не то, что IAT-ячейки для функции Foo, а даже дескриптора импорта для самой библиотеки не будет. Так что толку с того, что ты будешь что-то расширять? Тебе придётся не только расширять, тебе придётся знать абсолютно все зависимости вырезанного кода от внешних сущностей, и правда в том, что эти зависимости не ограничиваются теми, которые явно подконтрольны программисту (вроде импортируемых через TLB функций), но включают и зависимости от рантаймовых функций и встраиваемых служебных структур.

Так что, повторяюсь, единственный реально работающий технический метод — это брать .obj-файл, внутри которого находится секретный метод, и на основе .obj генерировать либо .DLL (что не получится просто так), либо .LIB, а дальше во время выполнения подгружать и собственными силами долинковывать этот .LIB к своему EXE (или DLL — если секретный метод был частью ActiveX DLL проекта).

Либо отказаться от проекта в двумя компиляциями.

Как я думаю так или иначе можно обеспечить оставление кода, все зависит от самого кода. Например все внешние зависимости метода запихать в одну функцию и экспортировать ее, либо вызвать ее где-нибудь, так чтобы она не вызывалась никогда, но и компилятор ее не отрезал. Хотя динамическая линковка COFF-файла проще наверное.
Хакер писал(а):Почему не решить?

Можно решить :D
Да я немного не подумал. Можно просто оставить в оригинале вызов загрузчика, а далее оригинальную процедуру занулить. Загрузчик будет писать в зануленные данные и по возврату уже будет вызываться оригинальный метод, флагом контролировать чтобы повторно не загружался метод.
Да - это несомненно проще.
UA6527P

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Получение кода метода класса

Сообщение Хакер » 14.11.2015 (Сб) 15:16

The trick писал(а):Например все внешние зависимости метода запихать в одну функцию и экспортировать ее, либо вызвать ее где-нибудь, так чтобы она не вызывалась никогда, но и компилятор ее не отрезал.


Вот ты не думаешь глубоко, опять таки. А жаль.

Это всё мимо, и аж по трём наслаивающимся друг на друга причинам. Пойду от менее критичного к более критичному:

  1. Проблема такой «одной функции» (в которую ты собрался запихать все внешние зависимости) в том, что кто будет следить за актуальностью содержимого подобной функции? Какой механизм? Либо придётся писать такой механизм, который анализирует код проекта и вставляет в эту волшебную функцию фиктивные обращения ко всем остальным сущностям, которые важно сохранить в итоговом бинарнике. Либо придётся заставлять заниматься этим человека, а это ад, потому что человек обязательно рано или поздно забудет что-то туда добавить в пылу активной разработки, когда всё внимание будет затрачено на бизнес-логику.

  2. Небольшая токность: вообще-то сложновато поддерживать такую волшебную функцию, потому что если там должен быть вызов какой-то процедуры, принимающей 10 структур, то придётся внутри этой волшебной функции объявлять 10 переменных, чтобы передать эти 10 UDT. Куда логичнее использовать ключик линкера /INCLUDE:name, чтобы явно приказать линкеру включить сущность, нежели делать какую-то функцию, в которую ты предложил «запихать всё остальное». Но если бы на этом проблемы заканчивались...

  3. Самая критичная проблема, которая ставит крест на том, что ты описал, состоит в том, что ты позаботился только о зависимостях от сущностей, которые подконтрольны программисту. Но этим зависимости не ограничиваются (я об этом выше уже писал). Кроме зависимостей машинного кода от других функций и переменных, есть ещё зависимость от сущностей, неявно встраиваемых в состав бинарника.

    В качестве наиболее простого примера таких сущностей, неподконтрольных программисту, приведу как пример строки. Но строками, естественно, это не ограничивается.

    Допустим твой секретный метод выглядел так:
    Код: Выделить всё
    Public Sub SecretMethod
        MsgBox "The_Trick жжот"
    End Sub


    Надо ли объяснять, что при компиляции этого кода в бинарник попадут: отдельно код самого метода и отдельно строковая константа «The_Trick жжот»? Причём в машинном коде метода SecretMethod будет стоять абсолютный адрес строковой константы.

    Но при втором компиляции, когда контент секретного метода будет выброшен, строка в бинарник не попадёт. И форсировать включение строки в бинарник ни с помощью ключика /INCLUDE, ни с помощью своей одной мусорной функции, в которую запихиваются все обращения к прочим сущностям, которые надо включить в бинарник — не получится.

    Повторяюсь, строками это не ограничивается.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Получение кода метода класса

Сообщение Хакер » 14.11.2015 (Сб) 15:31

The trick писал(а):Да я немного не подумал. Можно просто оставить в оригинале вызов загрузчика, а далее оригинальную процедуру занулить. Загрузчик будет писать в зануленные данные и по возврату уже будет вызываться оригинальный метод, флагом контролировать чтобы повторно не загружался метод.
Да - это несомненно проще.


Флаг не обязательно нужен.

Делается это так.

Допустим, у нас есть «защищаемый» (хотелось бы поставить 10 пар вложенных кавычек, чтобы подчеркнуть показушность и бесполезность самого процесса, ну да ладно) метод SecretMethod:

Код: Выделить всё
Private Function SecretMethod(A, B, C) As SomeType
   ' Some cool stuff
   ' Some cool stuff
   ' Some cool stuff
End Function


То, что мы делаем, это заводим ещё один метод:
Код: Выделить всё
Private Function SecretMethodPreload(A, B, C) As SomeType
    LoadSecuredCode
    SecretMethodPreload = SecretMethod(A, B, C)
End Function


Суть в том, что при старте приложение берёт vtable класса и в vtable меняет содержимое соответствующей ячейки: туда, где был адрес метода SecretMethod записывается адрес метода SecretMethodPreload.

Во время выполнения все обращения к SecretMethod поведут на самом деле на метод SecretMethodPreload. Вернее, не все обращения, а любое первое обращение.

Метод SecretMethodPreload загружает с сервера код всех «защищаемых» методов, сверяет хеш текущего бинарника и хеш загруженных фрагментиков и записывает их поверх соответствующих затёртых участков образа, а после этого корректирует vtable обратно, исправляя адрес: там, куда был записан адрес SecretMethodPreload будет вновь записан адрес SecretMethod.

А после этого идёт вызов SecretMethod.

Последующие же вызовы SecretMethod сразу ведут на соответствующий код, минуя SecretMethodPreload.

Массовое автоматическое затирание реализируется легко: в проект добавляется опция LinkSwitches, добавляющая ключик /MAP. Линкер при компиляции генерирует MAP-файл, откуда становится известным VA/RVA каждого метода. Пишется (хоть на том же VB) утилитка, которая становится частью toolchain'а для проекта, которая берёт map-файл, находит в нём нужные методы и бинарнике по известным (полученным из map-файла) адресам затирает код NOP-ами или INT3-инструкциями или мусором.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

The trick
Постоялец
Постоялец
 
Сообщения: 781
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: Получение кода метода класса

Сообщение The trick » 14.11.2015 (Сб) 15:38

Хакер писал(а):Вот ты не думаешь глубоко, опять таки. А жаль.

Это моя вечная проблема. Если бы я делал подобную задачу для себя, не сомневайтесь, я решил бы ее так или иначе.
Хакер писал(а):Куда логичнее использовать ключик линкера /INCLUDE:name, чтобы явно приказать линкеру включить сущность, нежели делать какую-то функцию, в которую ты предложил «запихать всё остальное».

Спасибо за полезный ключик, я не знал о нем.
Хакер писал(а):Самая критичная проблема, которая ставит крест на том, что ты описал, состоит в том, что ты позаботился только о зависимостях от сущностей, которые подконтрольны программисту. Но этим зависимости не ограничиваются (я об этом выше уже писал). Кроме зависимостей машинного кода от других функций и переменных, есть ещё зависимость от сущностей, неявно встраиваемых в состав бинарника.

Опять-таки скажу, если бы я писал такой код, я бы написал его так, чтобы ничего этого не было. Например в драйвере, для строк я использовал UDT с массивом, который не тянет никаких зависимостей, для других каких-либо зависимостей я бы что-то другое сделал, предварительно посмотрев в отладчике, что да как.
Я согласен, мой метод содержит кучу недостатков и очень трудный для реализации и для серийного использования - Ваши два метода несомненно проще. Но мой метод также будет работать если подойти к этому "с головой", также если применить секцию релокации для финального EXE, то мой метод позволит иметь динамически изменяемые методы, т.е. могут иметь любой размер и встраиваться в код.
UA6527P

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Получение кода метода класса

Сообщение Хакер » 14.11.2015 (Сб) 15:42

The trick писал(а):Например в драйвере, для строк я использовал UDT с массивом, который не тянет никаких зависимостей, д

Использование UDT, если я не ошиююсь, само по себе вызывает зависимость кода от соответствующего данной UDT-шке дескриптора RESDESCTBL, который описывает для рантайма правила, по которым инициализируется и зачищается экземпляр UDT.

И есть множество всяких рантаймовых функций, которым передаётся указатель на какую-нибудь структуру, вшитую в бинарник и содержающую служебную информацию. Например использование оператора New превращается в вызов __vbaNew, которой передаётся указатель как раз на такую вшитую в бинарник служебную структуру.

К тому же одно дело драйвер, а писать бизнес-логику обычного прикладного приложения, укладываясь во все эти ограничения и по каждому чиху проверяя код в отладчике на предмет того, не появилась ли какая-нибудь внешняя зависимость — это пытка.

The trick писал(а):также если применить секцию релокации для финального EXE, то мой метод позволит иметь динамически изменяемые методы, т.е. могут иметь любой размер и встраиваться в код.

Нет, не могут. Относительная адресация пострадает.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

djalex777
Постоялец
Постоялец
 
Сообщения: 461
Зарегистрирован: 23.03.2006 (Чт) 16:02

Re: Получение кода метода класса

Сообщение djalex777 » 14.11.2015 (Сб) 16:17

Хакер писал(а):Суть в том, что при старте приложение берёт vtable класса

Вот тут можно подробнее. Ведь речь идет именно об vtable класса, а не об copy--of--vtable класса, создаваемого New. Верно?

The trick
Постоялец
Постоялец
 
Сообщения: 781
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: Получение кода метода класса

Сообщение The trick » 14.11.2015 (Сб) 16:26

Хакер писал(а):Использование UDT, если я не ошиююсь, само по себе вызывает зависимость кода от соответствующего данной UDT-шке дескриптора RESDESCTBL, который описывает для рантайма правила, по которым инициализируется и зачищается экземпляр UDT.

Насколько я помню там идет просто выделение в стеке с занулением через REP STOS для типов с простыми полями (Long, Integer, Byte и т.д.). В коде внедряемом в другой процесс я мог спокойно создавать UDT-переменные внутри функций.
Хакер писал(а):И есть множество всяких рантаймовых функций, которым передаётся указатель на какую-нибудь структуру, вшитую в бинарник и содержающую служебную информацию. Например использование оператора New превращается в вызов __vbaNew, которой передаётся указатель как раз на такую вшитую в бинарник служебную структуру.

Да это проблема, даже перекомпилировав код один в один адреса разные, тут только отказаться от New.
Хакер писал(а):Нет, не могут. Относительная адресация пострадает.

Не хочу показаться наглым, но можно поподробней? Может я опять что-то упустил. Все jmp'ы во вне обработаются релокациями, JE, JNE и т.п. не ссылаются вне метода т.к. относительны.
UA6527P

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Получение кода метода класса

Сообщение Хакер » 14.11.2015 (Сб) 16:28

djalex777 писал(а):Ведь речь идет именно об vtable класса, а не об copy--of--vtable класса, создаваемого New. Верно?

Верно.

Собственно, первую часть задачи:
Хакер писал(а):что при старте приложение берёт vtable класса и в vtable меняет содержимое соответствующей ячейки: туда, где был адрес метода SecretMethod записывается адрес метода SecretMethodPreload.

можно делать не при старте приложения, а сделать это той же утилитой, которая затирает код «защищаемых» методов.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

djalex777
Постоялец
Постоялец
 
Сообщения: 461
Зарегистрирован: 23.03.2006 (Чт) 16:02

Re: Получение кода метода класса

Сообщение djalex777 » 14.11.2015 (Сб) 16:38

записывает их поверх соответствующих затёртых участков образа

Предыдущий вопрос, собственно, складывается и из это части тоже. В целом нужно уметь получать "исходный" vtable, с исходным адресом, потому как по этому адресу и надо будет записать полученный кусочек кода. Вот и вопрос - как это сделать?

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Получение кода метода класса

Сообщение Хакер » 14.11.2015 (Сб) 16:42

The trick писал(а):Насколько я помню там идет просто выделение в стеке с занулением через REP STOS для типов с простыми полями (Long, Integer, Byte и т.д.). В коде внедряемом в другой процесс я мог спокойно создавать UDT-переменные внутри функций.

Для простых — да. Но если там будет массив, либо объектная ссылка, либо строка, либо Variant-поле, либо вложенная UDT с чем-либо из ранее перечисленного, это уже будет описываемый случай. Например, для зачистки такой UDT будет вызвана __vbaRecDestruct, которой будет передан RESDESCTBL для этой UDT-шки.

The trick писал(а):Может я опять что-то упустил. Все jmp'ы во вне обработаются релокациями, JE, JNE и т.п. не ссылаются вне метода т.к. относительны.

Подчёркнутое неверно. Относительные джампы не охватываются релокациями (ибо когда весь образ перемещается целиком, править нечего, относительные смещения остаются неизменными). А вот если разрезать образ на две части и раздвигать их (или сдвигать), то относительные джампы из одной части в другую становятся невалидными.

Кстати, именно в том и суть jmp-thunk-ов: снизить число релоков, потому что хотя бы один наложенный на страницу кода релок переводит страницу из image-backed (copy-on-write) в pagefile-backed.

Это значит, если есть 40 процессов, в каждый из которых подгружена одна и та же DLL, пусть даже по одному и тому же адресу (отличного от задуманного), то все страницы, подвергшиеся хоть одной релок-коррекции, будут занимать пейдж-фрейм в файле подкачки. А если страниц 40? Это будет 40 × 40 × 4 кб = 6,25 Мб перерасхода ресурсов на ровном месте.

Поэтому для тех же импортов в образе идёт IAT, после IAT идёт серия jmp-thunk'ов вида jmp dword [iat_cell_N], а уже на thunk'и идут относительные джампы вида jmp thunk_for_func_N.

Релоки охватывают только сам набор jmp-thunk'ов, а не тысячи обращений к импортируемым функциям, раскиданным по всему коду.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

The trick
Постоялец
Постоялец
 
Сообщения: 781
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: Получение кода метода класса

Сообщение The trick » 14.11.2015 (Сб) 16:49

Спасибо за разъяснения.
UA6527P

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Получение кода метода класса

Сообщение Хакер » 14.11.2015 (Сб) 17:03

djalex777 писал(а):В целом нужно уметь получать "исходный" vtable, с исходным адресом, потому как по этому адресу и надо будет записать полученный кусочек кода. Вот и вопрос - как это сделать?


Алгоритм прост.

Утилита-патчер получает на вход MAP-файл и текстовый файл со списком методов, которые надо извлечь и затереть, и методов предзагрузчиков для них (или методы предзагрузчики могут отсутствовать в этом списке, предполагая, что предзагрузчик для метода X будет называться XPreload — на твой выбор).

Собственно, адреса нужных методов известны сразу (даны в MAP-файле) — можно сохранять код во внешний файл (для последующего размещения на сервере) и затирать мусором.

Собираем все имена методов, которые нуждаются в обработке и группируем их по имени класса. Дальше ищем VTable для каждого класса. Как искать VTable напишу потом, если сам не разберёшься. Уж больно много букв будет.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

djalex777
Постоялец
Постоялец
 
Сообщения: 461
Зарегистрирован: 23.03.2006 (Чт) 16:02

Re: Получение кода метода класса

Сообщение djalex777 » 14.11.2015 (Сб) 17:17

Хакер , спасибо, но я это понимаю всё итак ) Я только про vtable тебя спросил. Нашел свой старый код обфускатора, затем вспомнил что писал тут об этом, нашел тему, а по ней и твой кирпич http://bbs.vbstreets.ru/viewtopic.php?f=28&t=43201. Пока не смотрел, сразу вопрос по структуре
Код: Выделить всё
Private Type MODDESCRTBL_ENTRY
    lpObjectInfo                    As Long
    FullBits                        As Long
    Placeholder0(0 To 15)           As Byte
    lpszName                        As Long
    MethodsCount                    As Long
    lpMethodNamesArray              As Long
    Placeholder1                    As Long
    ModuleType                      As MODFLAGS
    Placeholder2                    As Long
End Type


lpObjectInfo указатель на что?

The trick
Постоялец
Постоялец
 
Сообщения: 781
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: Получение кода метода класса

Сообщение The trick » 14.11.2015 (Сб) 18:46

Зная VBHeader можно получить так (в скобках смещение поля):
VBHeader.lpProjectData{0x30}->lpObjectTable{0x04}->lpPubObjArray{0x30}
Это массив структур VbPublicObjectDescriptor их количество можно получить из lpObjectTable.wTotalObjects{0x2A} а размер равен 0x30.
Каждый объект представляет модуль, где для класса поле lpPubObjArray->fObjectType{0x28} установлен бит 1 и не установлены 7, 11, 18 и 19 биты.
Для каждого класса смотришь lpPubObjArray[index]->lpObjectInfo{0x00}->wMethCount{0x60} это количество методов, а lpPubObjArray[index]->lpObjectInfo{0x00}->lpMethods{0x68} их адреса. Отсюда при загрузке берутся значения для создания копии виртуальной таблицы.
Для EXE можно получить VBHeader считав DWORD по адресу EntryPoint+1
UA6527P

djalex777
Постоялец
Постоялец
 
Сообщения: 461
Зарегистрирован: 23.03.2006 (Чт) 16:02

Re: Получение кода метода класса

Сообщение djalex777 » 14.11.2015 (Сб) 20:24

The trick , lpMethods это указатель на что? SafeArray?

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Получение кода метода класса

Сообщение Хакер » 15.11.2015 (Вс) 1:45

djalex777 писал(а):а по ней и твой кирпич viewtopic.php?f=28&t=43201. Пока не смотрел, сразу вопрос по структуре

Правильно смотришь.

djalex777 писал(а):The trick , lpMethods это указатель на что? SafeArray?

На массив в стиле Си.

К слову, эти адреса нельзя использовать для затирования, потому что они ведут не на сами методы, а на adjustor-ы для них. Реальные адреса методов (для изъятия кода и затирания) получишь из того же MAP-файла.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

djalex777
Постоялец
Постоялец
 
Сообщения: 461
Зарегистрирован: 23.03.2006 (Чт) 16:02

Re: Получение кода метода класса

Сообщение djalex777 » 15.11.2015 (Вс) 1:56

Я планировал использовать эти адреса для подмены в процессе выполнения на кусочек кода с сервера. Или они и не для этого? Ещё - как правильно по ним записывать код - VirtualLock -> CopyMemory?

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Получение кода метода класса

Сообщение Хакер » 15.11.2015 (Вс) 2:00

Какие «эти»?

В map-файле — истинные адреса методов.
В vtable — указатели на переходнички в составе Adjustor-ов.

vtable нужно править на этапе затирания (в прото-vtable) или при старте проекта (в настоящей vtable), а затем — из функции LoadSecuredCode восстанавливать оригинальные значения (всегда в настоящей vtable).

И пост-компиляционное затирание, и запись скачанного фрагмента поверх затёртых инструкций нужно производить по адресу, взятому из MAP-файла.

djalex777 писал(а):Ещё - как правильно по ним записывать код - VirtualLock -> CopyMemory?

VirtualLock тут вообще мимо. VirtualProtect для добавление W-флага, затем запись, затем VirtualProtect для присвоения изначальных атрибутов.

И ещё раз напомню, что если патчингу подвергается не EXE, а DLL, то нужно самостоятельно обработать релоки после записи.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

djalex777
Постоялец
Постоялец
 
Сообщения: 461
Зарегистрирован: 23.03.2006 (Чт) 16:02

Re: Получение кода метода класса

Сообщение djalex777 » 15.11.2015 (Вс) 12:00

Хакер, The trick Спасибо.

jangle
Википедик
Википедик
Аватара пользователя
 
Сообщения: 3013
Зарегистрирован: 03.06.2005 (Пт) 12:02
Откуда: Нидерланды

Re: Получение кода метода класса

Сообщение jangle » 15.11.2015 (Вс) 12:16

djalex777 писал(а):Есть некий класс Class1 с непустым методом DoIt. Нужно, чтобы в самом исполняемом файле код метода DoIt отсутствовал, а подгружался в определенный момент. И затем уже при вызове метода, исполнялся. Причем, сам код метода надо чтобы в исходном файле существовал, а уже после компиляции брался из определенного места (файла и т.п.) и в скомпилированном файле отсутствовал.


На PB можно скомпилировать COM DLL, в ней твой класс. Затем выгрузить на диск машинный код содержащийся в нужной функции. Повторно скомпилировать COM DLL закоментировав выгруженный код, затем загружать бинарник с диска, и заполнив параметры функции передавать управление этому коду.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Получение кода метода класса

Сообщение Хакер » 15.11.2015 (Вс) 16:21

jangle, такое впечатление, что ты в внезапно упал с Луны и написал сюда первую пришедшую в голову мысль, не удосужившись почитать.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Пред.

Вернуться в Visual Basic 1–6

Кто сейчас на конференции

Сейчас этот форум просматривают: Yandex-бот и гости: 66

    TopList