Хакер писал(а):вся адресация съедет
Вот в этом и проблема и вопрос, как её правильно подправить?
Хакер писал(а):вся адресация съедет
Хакер писал(а):Причём тут другие члены?
Если у тебя в был большой метод CSomeClass::Foo с неким секретным кодом, и ты скомпилировался проект в первый раз, а затем подменил контент метода CSomeClass::Foo на маленькую заглушку, которая только подгружает код с сервера, то даже при том, что другие функции и процедуры в твоём проекте были не тронуты, вся адресация съедет.
The trick писал(а):Ну вызов методов идет посредством указателя, поэтому это не важно. Хотя для глобальных функций объявленых в стандартном модуле это создаст проблему.
djalex777 писал(а):от в этом и проблема и вопрос, как её правильно подправить?
The trick писал(а):Если код стандартных модулей будет располагаться вначале, то адресация не слетит на них.
Хакер писал(а):Не только.
Почему ты забыл обо всём, кроме членов классов?
Declare-функции — в пролёте.
Обычные модульные функции — в пролёте.
Функции, импортированные через TLB — в пролёте.
Рантаймовые функции, импортированные неявно, если они были использованы только в вырезаемой процедуре — в пролёте.
Обращения к глобальным переменным (если к ним обращение было только из вырезаемой процедуры) — в пролёте.
Обращение к вшитым в образ ресурсам (вроде RESDESCTBL), о существовании которых VB-программист даже не дагдывается — в пролёте.
Вырезать фрагментик перед отправкой бинарника клиенту нужно, естественно, затиранием кода секретного метода другим кодом — кодом подгрузки и мусором.
Писать исполняемый код метода на ассемблере (или любом другом языке отличном от VB6) не подходит.
The trick писал(а):Можно вставлять код прямо в места оригинала. Для этого компилируем финальный EXE с релокациями. И имеем глобальгную функцию для загрузки с сервера, которая будет загружать метод. При загрузке мы расширяем место для метода (мы это можем делать т.к. у нас есть релокации) и пишем туда код, релокации сразу поправляем с места откуда начали править код. Если не использовать оптимизации, т.е. никакой неиспользуемый код не будет удален из EXE то это должно работать.
The trick писал(а):Вот это как раз и вызывает проблему, т.к. чистым VB это не рашить (ну почти не решить).
Хакер писал(а):The trick писал(а):Можно вставлять код прямо в места оригинала. Для этого компилируем финальный EXE с релокациями. И имеем глобальгную функцию для загрузки с сервера, которая будет загружать метод. При загрузке мы расширяем место для метода (мы это можем делать т.к. у нас есть релокации) и пишем туда код, релокации сразу поправляем с места откуда начали править код. Если не использовать оптимизации, т.е. никакой неиспользуемый код не будет удален из EXE то это должно работать.
Нельзя.
Ещё раз повторюсь: можно записать скачанный код по оригинальному местоположению, но только при условии, что не были никаких двух компиляций.
Если была вторая компиляция, то вполне себе вероятно, что сущностей, на которые ссылался машинный код из первого билда, во втором билде нет вообще.
Допустим, секретный метод юзал функцию Foo из библиотеки SUPER.DLL.
Второй раз мы скомпилировали наш project.exe, и в нём нет даже дескриптора импорта для SUPER.DLL. Не то, что IAT-ячейки для функции Foo, а даже дескриптора импорта для самой библиотеки не будет. Так что толку с того, что ты будешь что-то расширять? Тебе придётся не только расширять, тебе придётся знать абсолютно все зависимости вырезанного кода от внешних сущностей, и правда в том, что эти зависимости не ограничиваются теми, которые явно подконтрольны программисту (вроде импортируемых через TLB функций), но включают и зависимости от рантаймовых функций и встраиваемых служебных структур.
Так что, повторяюсь, единственный реально работающий технический метод — это брать .obj-файл, внутри которого находится секретный метод, и на основе .obj генерировать либо .DLL (что не получится просто так), либо .LIB, а дальше во время выполнения подгружать и собственными силами долинковывать этот .LIB к своему EXE (или DLL — если секретный метод был частью ActiveX DLL проекта).
Либо отказаться от проекта в двумя компиляциями.
Хакер писал(а):Почему не решить?
The trick писал(а):Например все внешние зависимости метода запихать в одну функцию и экспортировать ее, либо вызвать ее где-нибудь, так чтобы она не вызывалась никогда, но и компилятор ее не отрезал.
Public Sub SecretMethod
MsgBox "The_Trick жжот"
End Sub
The trick писал(а):Да я немного не подумал. Можно просто оставить в оригинале вызов загрузчика, а далее оригинальную процедуру занулить. Загрузчик будет писать в зануленные данные и по возврату уже будет вызываться оригинальный метод, флагом контролировать чтобы повторно не загружался метод.
Да - это несомненно проще.
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
Хакер писал(а):Вот ты не думаешь глубоко, опять таки. А жаль.
Хакер писал(а):Куда логичнее использовать ключик линкера /INCLUDE:name, чтобы явно приказать линкеру включить сущность, нежели делать какую-то функцию, в которую ты предложил «запихать всё остальное».
Хакер писал(а):Самая критичная проблема, которая ставит крест на том, что ты описал, состоит в том, что ты позаботился только о зависимостях от сущностей, которые подконтрольны программисту. Но этим зависимости не ограничиваются (я об этом выше уже писал). Кроме зависимостей машинного кода от других функций и переменных, есть ещё зависимость от сущностей, неявно встраиваемых в состав бинарника.
The trick писал(а):Например в драйвере, для строк я использовал UDT с массивом, который не тянет никаких зависимостей, д
The trick писал(а):также если применить секцию релокации для финального EXE, то мой метод позволит иметь динамически изменяемые методы, т.е. могут иметь любой размер и встраиваться в код.
Хакер писал(а):Суть в том, что при старте приложение берёт vtable класса
Хакер писал(а):Использование UDT, если я не ошиююсь, само по себе вызывает зависимость кода от соответствующего данной UDT-шке дескриптора RESDESCTBL, который описывает для рантайма правила, по которым инициализируется и зачищается экземпляр UDT.
Хакер писал(а):И есть множество всяких рантаймовых функций, которым передаётся указатель на какую-нибудь структуру, вшитую в бинарник и содержающую служебную информацию. Например использование оператора New превращается в вызов __vbaNew, которой передаётся указатель как раз на такую вшитую в бинарник служебную структуру.
Хакер писал(а):Нет, не могут. Относительная адресация пострадает.
djalex777 писал(а):Ведь речь идет именно об vtable класса, а не об copy--of--vtable класса, создаваемого New. Верно?
Хакер писал(а):что при старте приложение берёт vtable класса и в vtable меняет содержимое соответствующей ячейки: туда, где был адрес метода SecretMethod записывается адрес метода SecretMethodPreload.
записывает их поверх соответствующих затёртых участков образа
The trick писал(а):Насколько я помню там идет просто выделение в стеке с занулением через REP STOS для типов с простыми полями (Long, Integer, Byte и т.д.). В коде внедряемом в другой процесс я мог спокойно создавать UDT-переменные внутри функций.
The trick писал(а):Может я опять что-то упустил. Все jmp'ы во вне обработаются релокациями, JE, JNE и т.п. не ссылаются вне метода т.к. относительны.
djalex777 писал(а):В целом нужно уметь получать "исходный" vtable, с исходным адресом, потому как по этому адресу и надо будет записать полученный кусочек кода. Вот и вопрос - как это сделать?
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
djalex777 писал(а):а по ней и твой кирпич viewtopic.php?f=28&t=43201. Пока не смотрел, сразу вопрос по структуре
djalex777 писал(а):The trick , lpMethods это указатель на что? SafeArray?
djalex777 писал(а):Ещё - как правильно по ним записывать код - VirtualLock -> CopyMemory?
djalex777 писал(а):Есть некий класс Class1 с непустым методом DoIt. Нужно, чтобы в самом исполняемом файле код метода DoIt отсутствовал, а подгружался в определенный момент. И затем уже при вызове метода, исполнялся. Причем, сам код метода надо чтобы в исходном файле существовал, а уже после компиляции брался из определенного места (файла и т.п.) и в скомпилированном файле отсутствовал.
Сейчас этот форум просматривают: Yandex-бот и гости: 66