Автор: Сергей Чубченко. Дата публикации: 11.08.2008
Вступление
Опытным аналитикам кода и переводчикам программ на другие языки наверняка попадались файлы, написанные на Visual Basic 6.0. Что удивительно, про редактирование форм и контролов на них на данный момент вообще нет информации. Это надо исправлять, чем мы и займемся. Статья была написана мной в начале 2007 года, но с тех пор она долго ждала публикации.
Вообще переводчики программ и просто продвинутые пользователи давно привыкли использовать Restorator или Resource Hacker для редактирования интерфейса. К сожалению, эти утилиты никак не видят ресурсы VB программ. Формат, в котором хранятся нужные ресурсы, в принципе, не сложный, но кому охота писать отдельный редактор ресурсов чисто под бейсик? Что поделать, придется изучать этот формат самим. Для начала разберем, как найти эти самые ресурсы. Начнем с рассмотрения оригинальной точки входа в программу. Чтобы на нее перейти из HEX редактора HIEW, нам потребуется лишь загрузить EXE’шник в данный HEX редактор и нажать поочереди Enter, Enter, F8, F5. У кого хиев купленный знают как оптимизировать эту операцию до командной строки, но это так к слову. Нашему взгляду будет представлено примерно следующее:
Теперь считываем структуру VBHeader по адресу 0004042E8. Как бы это не было парадоксально - больше нам для исследования никакие сторонние структуры не потребуются - все нужное мы выцепим из VBHeader.
Структура VBHeader
Объемная структура. Правда в ней нам потребуется только FormCount для определения числа форм и указатель на структуры описывающие формы - aGUITable. Структура GUITable имеет вид:
Структура tGuiTable
Таких структур столько же, сколько форм в проекте и они идут одна за одной. Чтобы получить адрес начала формы, нужно к aFormPointer прибавить 93. Этот адрес должен указывать на длину информации о форме. Тут есть небольшая хитрость - он может занимать 2 либо 4 байта. Если считанный DWORD отANDить с &H80000000 то мы определим число байт информации. Если DWORD содержит флаг &H80000000 то длина записана в 4 байта, иначе в два. После длины идет собственно описание формы и лежащих на ней контролов. Наконец-то мы нашли то что нужно, пора бы разобраться с бинарным форматом форм и контролов.
Бинарный формат формы
Когда-то во времена VB 1.0 for DOS все формы по умолчанию сохранялись в бинарном формате и это не считалось ненормальным. Теперь же, когда мы привыкли что frm файлы можно редактировать в текстовом виде, трудно представить что эти же формы можно представить и в упакованном бинарном формате. Упакованным формат называется от того, что чтобы узнать информацию о последнем контроле на форме нужно последовательно пропарсить все предыдущие. Из этого следует, что для добавления нового свойства к контролу нам придется перепаковать всю структуру. То есть сначала декомпилировать ее, потом изменить и снова скомпилировать, как это делает Visual Basic 6.0. Сложно, не спорю, но что поделать. Если на форме лежит ActiveX или UserControl, то его нужно выделить, чтобы не изменить неизвестных его свойств. Все это оказало сильное впечатление на программистов, потому по сей день нет ни одного нормального редактора интерфеса VB программ (есть парочка, но они крайне нестабильны и могут выдать нерабочий файл). По этой же причине не делают и русификаторы к VB программам. Надеюсь Вы прочитав эту статью разберетесь как устроены формы VB и научитесь их разбирать и собирать! В бинарном упакованном виде каждый объект начинается со свойства Name и заканчивается идентификатором, по которому можно узнать идут ли дальше другие объекты, вложенность объектов и их завершение, а также меню. Свойства чередуются крайне просто. Сначала идет идентификатор свойства, потом само значение, затем следующий идентификатор. Идентификаторы FF00-FF05 зарезервированы. Вот их описание:
Теперь надо решить одну проблемку - откуда же нам брать идентификаторы всех свойств всех контролов? Все просто - я уже составил таблицу команд кодирования интерфейса Visual Basic программ, которая мной была получена путем анализирования TypeLib’ов VB и их многочисленными исправлениями.
0D указывает на то что имя формы содержит 0Dh символов. Далее идет имя "AC_ExDec_03_B", зевершающееся нулевым байтом, после которого опять стоит 0Dh. Следующий байт 01h определяем по таблице для формы - это Caption, следовательно после него должна идти длина строки и сама строка. Со строками у VB не все гладко - строки в некоторых свойствах объектов он хранит в ACIIZ формате, а в некоторых - в Unicode формате. Распознать формат нереально; единственный способ, просто запомнить те свойства которые имеют Unicode формат, а какие нет. К примеру Caption и Name всегда ASCII, а вот Tag, Connect и некоторые другие в Unicode формате. Вернемся к нашим данным. 03 - BackColor согласно нашей таблице, следовательно следующие 4 байта отвечают за 32 битный код цвета. Далее идет 19 - ScaleMode, следующий за ним Word определяет масштаб. 42 - WhatsThisButton, за ним 1 байт определяющий логическое True (FF) или False (0). Теперь рассмотрим самое интересное, что есть в формах - слудующий байт 23. Это Icon. Вообще, при программировании на VB, формы хранятся в файле Frm, а вот графика и прочие большие данные хранятся в Frx. Frm в свою очередь ссылается на определенный адрес в этом Frx, храня в котором все используемые данные просто один за другим. После компиляции содержимое Frx встраивается в форму, поэтому в рассматриваемом случае после байта 23 будет идти иконка в формате stdole.Picture. Если иконка берется дефолтная из MSVBVM60.DLL, то после 23 будет FFFFFFFF, иначе будет размер картинки. Именно столько байт мы должны считать после адреса, чтобы получить всю используемую иконку. 3E 04 00-00 = 43E = 1086 байт. Именно черз столько байт кончится иконка и продолжится форма, которую мы декомпилируем:
Теперь видим 24. Это LinkTopic, после которого идет строка, строки мы уже умеем достать потому продолжим. 35 - этого опкода в таблице нет, но я тебе расскажу - это всего лишь линейные размеры клиентской части формы. За байтом 35 идут 4 dword’а. Это соответственно ClientLeft, ClientTop, ClientWidth, ClientHeight. Затем видим 46 - StartUpPosition. Это один байт, определяющий позицию формы при запуске (в центре экрана, где получится или в центре Parent формы. Теперь мы дошли до самого интересного - FF01. Помните я говорил про константы определяющие конец одних контролов или начало других? Так вот FF01 - это vbFormNewChildControl определяет что далее идет контрол, контейнером для которого является форма. Сначала стандартно: dword размер информации о следующей контроле, затем имя контрола и пошли свойства. 01 - Caption, 03 - BackColor, 04 - ForeColor, 05 - линейные размеры, декомпилируются подобно линейным размерам клиентской части формы, с одной небольшой разницей - каждый из размеров занимает не 4, а 2 байта. Продолжим. 12 - TabIndex, индекс, используемый для перечисления контролов на формы при нажатии Tab. Многие программисты забывают его проставить после разработки программы, отсюда любители работать только с использованием клавиатуры плюются и ругают такой продукт, а главное кривизну рук автора. Причем я их в этом поддерживаю, это свойство программист обязан выставить - это правило профессиональной разработки интерфейсов. Так вот этот индекс определяется двумя байтами. Это значит, что более 65535 контролов на форму не поместить. Затем идет 1B. Это одно из самых интересных свойств - Font. В отличии от других оно описывается классом stdole.Font,который есть только в VB. Поэтому писать декомпилятор VB не на VB это большой геморрой именно из-за классов, зашитых в библиотеки Visual Basic 6.0. В конце всех контролов мы увидим FF0204 Как мы помним 02 это vbFormExistingChildControl, то есть надо закрыть контрол и 04 это vbFormEnd закрывает форму. Вот что получится если бы мы записывали то что декомпилировали в уме (листинг взят из декомпилятора VB Decompiler):
Теперь попробуем на конкретном примере изменить свойство меню и показать невидимую кнопку.
Редактирование свойств меню
Специально для демонстрации заблокированного меню я написал простенький пример.
В нем заблокирован пункт меню "Test". Попробуем его изменить. Для начала необходимо знать как можно сделать меню неактивным. Тут есть два способа. Первый - при проектировании поставить свойство Enabled у меню в False, второй - установить это свойство кодом при запуске формы. Представим что это свойство установлено при разработке меню. Тогда декомпилируем этот проект и посмотрим данные нашей формы. Для простоты не будем заново декомпилировать в уме, а возьмем VB Decompiler (Lite версия вполне подойдет). В разделе формы всего одна форма. Поищем там меню:
Как видим, свойство "Enabled = 0", это то что мы искали. Теперь подумаем как поправить. Откроем файл в hiew и перейдем по адресу 11F0:
Все стандартно: сначала Name, затем Caption (03) и 05 - Enabled. После него идет один байт 00, что означает False. Заменим на FF (True) и попробуем запустить. Меню разблокировано и при нажитии на него выводится MessageBox. Тем же способом можно изменять любые свойства контролов.
Показываем скрытые кнопки
Для рассмотрения вопроса я написал простой пример, который после запуска делает видимой кнопку "Test" через 3 секунды. Чтож, поглядим в декомпиляторе что у нас с кнопкой "Test":
Сразу бросается в глаза "Visible = 0", которое в таблице значится как 09. Переходим по смещению 1175 и проходим все свойства до 09. Видим 00, это False, меняем на FF (True). Но, давайте рассмотрим как реализуется показ кнопки через 3 секунды? Можно сделать цикл при запуске программы, но он на разных процессорах будет работать с разной скоростью. Можно использовать GetTickCount, но потребуется его проверять в While цикле, что тоже неудобно. Но в большинстве случаев для этого используются простые таймеры. Таймер - это невидимый контрол на форме, у которого событие срабатывает каждые Interval милисекунд. Поищем ка мы таймер в нашем проекте:
Так и есть! 3000 милисекунд это 3 секунды. Заменим ка мы их на 1. Но, так как я не сделал отключения таймера после установки свойства в кнопку - таймер будет срабатывать постоянно и замедлять код, потому лучше использовать предыдущий способ, а таймер просто отключить, поставив интервал в 0.
Добавление новый свойств
Читая статью Вы наверняка задались вопросом: а как же добавить новое свойство в упакованный контрол? Добавить можно только разбором, вставкой и последующей сборкой обратно всей формы. Ясное дело что уже на старое место данные не поместятся, поэтому придется создавать новую секцию в файле или расширять последнюю и редиректить данные туда. Кроме того адрес на новое расположение формы придется прописать в структуре информации о форме. При этом нужно учитывать, что если пользователь будет часто добавлять свойства, то нужно заранее в новой секции сделать запас в виде резервных байт под расширение каждой формы. Всю эту информацию о резерве байт и начале и длине каждой формы, вынесенной в новую секцию придется гдето сохранить чтобы использовать при следующих правках объектов. Для этого придется создать свою служебную структуру. Это все будет полезно только в том случае, если писать свой редактор ресурсов Visual Basic. Для анализа форм знаний из этой статьи вполне хватит. А вот автоматизировать это или нет - решать Вам.
Заключение
Надеюсь что у Вас не осталось вопросов по теме редактирования интерфейса VB программ. Если же они всеже есть - добро пожаловать на наш форум.
Искусство редактирования интерфейса программ на VB
Вступление
Опытным аналитикам кода и переводчикам программ на другие языки наверняка попадались файлы, написанные на Visual Basic 6.0. Что удивительно, про редактирование форм и контролов на них на данный момент вообще нет информации. Это надо исправлять, чем мы и займемся. Статья была написана мной в начале 2007 года, но с тех пор она долго ждала публикации.
Вообще переводчики программ и просто продвинутые пользователи давно привыкли использовать Restorator или Resource Hacker для редактирования интерфейса. К сожалению, эти утилиты никак не видят ресурсы VB программ. Формат, в котором хранятся нужные ресурсы, в принципе, не сложный, но кому охота писать отдельный редактор ресурсов чисто под бейсик? Что поделать, придется изучать этот формат самим. Для начала разберем, как найти эти самые ресурсы. Начнем с рассмотрения оригинальной точки входа в программу. Чтобы на нее перейти из HEX редактора HIEW, нам потребуется лишь загрузить EXE’шник в данный HEX редактор и нажать поочереди Enter, Enter, F8, F5. У кого хиев купленный знают как оптимизировать эту операцию до командной строки, но это так к слову. Нашему взгляду будет представлено примерно следующее:
push 0004042E8 ;’VB5!’
call ThunRTMain ;MSVBVM60 --?2
Теперь считываем структуру VBHeader по адресу 0004042E8. Как бы это не было парадоксально - больше нам для исследования никакие сторонние структуры не потребуются - все нужное мы выцепим из VBHeader.
Структура VBHeader
Поле Тип Описание
Signature String * 4 Сигнатура "VB5!"
RuntimeBuild Integer Показатель рантаймовости
LanguageDLL String * 14 Языковая библиотека
BackupLanguageDLL String * 14 Не влияет на работу EXE
RuntimeDLLVersion Integer Версия рантайм библиотеки
LanguageID Long Язык программы
BackupLanguageID Long Используется совместно с LanguageDLL
aSubMain Long Main процедура, запускаемая при старте EXE.
aProjectInfo Long Указатель на структуру ProjectInfo
fMDLIntObjs Long
fMDLIntObjs2 Long
ThreadFlags Long Флаги потока
ThreadCount Long Число потоков
(смысл малопонятен, так как VB не позволяет
создавать многопоточные программы)
FormCount Integer Число форм в данном файле
ExternalComponentCount Integer Число внешних OCX компонентов
ThunkCount Long
aGUITable Long Указатель на GUITable
aExternalComponentTable Long Указатель на ExternalComponentTable
aComRegisterData Long Указатель на ComRegisterData
oProjectExename Long Адрес строки с именем EXE файла
oProjectTitle Long Адрес строки с заголовком проекта
oHelpFile Long Адрес строки с именем Help файла
oProjectName Long Адрес строки с именем проекта
Объемная структура. Правда в ней нам потребуется только FormCount для определения числа форм и указатель на структуры описывающие формы - aGUITable. Структура GUITable имеет вид:
Структура tGuiTable
Поле Тип Описание
SectionHeader Long Адрес заголовка описывающего секции
unknown(59) Byte Неиспользуемый блок байт
FormSize Long Размер блока, описывающего форму и контролы, лежащие на ней
un1 Long Неиспользуемый DWORD
aFormPointer Long Указатель на блок, описывающий форму и контролы, лежащие на ней
un2 Long Неиспользуемый DWORD
Таких структур столько же, сколько форм в проекте и они идут одна за одной. Чтобы получить адрес начала формы, нужно к aFormPointer прибавить 93. Этот адрес должен указывать на длину информации о форме. Тут есть небольшая хитрость - он может занимать 2 либо 4 байта. Если считанный DWORD отANDить с &H80000000 то мы определим число байт информации. Если DWORD содержит флаг &H80000000 то длина записана в 4 байта, иначе в два. После длины идет собственно описание формы и лежащих на ней контролов. Наконец-то мы нашли то что нужно, пора бы разобраться с бинарным форматом форм и контролов.
Бинарный формат формы
Когда-то во времена VB 1.0 for DOS все формы по умолчанию сохранялись в бинарном формате и это не считалось ненормальным. Теперь же, когда мы привыкли что frm файлы можно редактировать в текстовом виде, трудно представить что эти же формы можно представить и в упакованном бинарном формате. Упакованным формат называется от того, что чтобы узнать информацию о последнем контроле на форме нужно последовательно пропарсить все предыдущие. Из этого следует, что для добавления нового свойства к контролу нам придется перепаковать всю структуру. То есть сначала декомпилировать ее, потом изменить и снова скомпилировать, как это делает Visual Basic 6.0. Сложно, не спорю, но что поделать. Если на форме лежит ActiveX или UserControl, то его нужно выделить, чтобы не изменить неизвестных его свойств. Все это оказало сильное впечатление на программистов, потому по сей день нет ни одного нормального редактора интерфеса VB программ (есть парочка, но они крайне нестабильны и могут выдать нерабочий файл). По этой же причине не делают и русификаторы к VB программам. Надеюсь Вы прочитав эту статью разберетесь как устроены формы VB и научитесь их разбирать и собирать! В бинарном упакованном виде каждый объект начинается со свойства Name и заканчивается идентификатором, по которому можно узнать идут ли дальше другие объекты, вложенность объектов и их завершение, а также меню. Свойства чередуются крайне просто. Сначала идет идентификатор свойства, потом само значение, затем следующий идентификатор. Идентификаторы FF00-FF05 зарезервированы. Вот их описание:
Public Const vbFormNewChildControl = &H1FF
Public Const vbFormExistingChildControl = &H2FF
Public Const vbFormChildControl = &H3FF
Public Const vbFormEnd = &H4FF
Public Const vbFormMenu = &H5FF
Теперь надо решить одну проблемку - откуда же нам брать идентификаторы всех свойств всех контролов? Все просто - я уже составил таблицу команд кодирования интерфейса Visual Basic программ, которая мной была получена путем анализирования TypeLib’ов VB и их многочисленными исправлениями.
00 00 00 00-00 00 00 00-00 00 04 00-00 00 0D 00 ?? ?? ?
41 43 5F 45-78 44 65 63-5F 30 33 5F-42 00 0D 01 AC_ExDec_03_B ??
27 00 43 72-61 63 6B 6D-65 20 66 6F-72 20 4A 6F ’ Crackme for Jo
73 65 70 68-43 6F 27 73-20 45 78 44-65 63 20 50 sephCo’s ExDec P
72 6F 67 72-61 6D 2E 2E-2E 00 03 08-00 00 80 19 rogram... ?? ??
01 00 42 00-23 3E 04 00-00 6C 74 00-00 36 04 00 ? B #>? lt 6?
00 00 00 01-00 02 00 20-20 10 00 00-00 00 00 E8 ? ? ? ?
02 00 00 26-00 00 00 10-10 10 00 00-00 00 00 28 ? & ??? (
01 00 00 0E-03 00 00 28-00 00 00 20-00 00 00 40 ? ?? ( @
00 00 00 01-00 04 00 00-00 00 00 80-02 00 00 00 ? ? ??
00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00
00 00 00 00-00 80 00 00-80 00 00 00-80 80 00 80 ? ? ?? ?
00 00 00 80-00 80 00 80-80 00 00 80-80 80 00 C0 ? ? ?? ??? +
C0 C0 00 00-00 FF 00 00-FF 00 00 00-FF FF 00 FF ++
00 00 00 FF-00 FF 00 FF-FF 00 00 FF-FF FF 00 00
0D указывает на то что имя формы содержит 0Dh символов. Далее идет имя "AC_ExDec_03_B", зевершающееся нулевым байтом, после которого опять стоит 0Dh. Следующий байт 01h определяем по таблице для формы - это Caption, следовательно после него должна идти длина строки и сама строка. Со строками у VB не все гладко - строки в некоторых свойствах объектов он хранит в ACIIZ формате, а в некоторых - в Unicode формате. Распознать формат нереально; единственный способ, просто запомнить те свойства которые имеют Unicode формат, а какие нет. К примеру Caption и Name всегда ASCII, а вот Tag, Connect и некоторые другие в Unicode формате. Вернемся к нашим данным. 03 - BackColor согласно нашей таблице, следовательно следующие 4 байта отвечают за 32 битный код цвета. Далее идет 19 - ScaleMode, следующий за ним Word определяет масштаб. 42 - WhatsThisButton, за ним 1 байт определяющий логическое True (FF) или False (0). Теперь рассмотрим самое интересное, что есть в формах - слудующий байт 23. Это Icon. Вообще, при программировании на VB, формы хранятся в файле Frm, а вот графика и прочие большие данные хранятся в Frx. Frm в свою очередь ссылается на определенный адрес в этом Frx, храня в котором все используемые данные просто один за другим. После компиляции содержимое Frx встраивается в форму, поэтому в рассматриваемом случае после байта 23 будет идти иконка в формате stdole.Picture. Если иконка берется дефолтная из MSVBVM60.DLL, то после 23 будет FFFFFFFF, иначе будет размер картинки. Именно столько байт мы должны считать после адреса, чтобы получить всю используемую иконку. 3E 04 00-00 = 43E = 1086 байт. Именно черз столько байт кончится иконка и продолжится форма, которую мы декомпилируем:
FF 00 00 35-FF 00 00 24-05 00 46 6F-72 6D 31 00 5 $? Form1
35 3C 00 00-00 59 01 00-00 CC 15 00-00 03 0C 00 5< Y? ¦§ ??
00 46 03 FF-01 55 00 00-00 01 06 00-46 72 61 6D F? ?U ?? Fram
65 31 00 03-01 11 00 42-75 74 74 6F-6E 20 69 73 e1 ??? Button is
20 69 6E 20-68 65 72 65-00 03 00 00-00 00 04 FF in here ? ?
FF FF 00 05-78 00 A0 05-AF 14 37 05-12 01 00 1B ?x ???¶7??? ?
01 00 00 00-BC 02 A4 2C-02 00 0E 43-65 6E 74 75 ? +??,? ?Centu
72 79 20 47-6F 74 68 69-63 FF 01 2B-00 00 00 03 ry Gothic ?+ ?
08 00 43 6F-6D 6D 61 6E-64 31 00 04-01 09 00 45 ? Command1 ??? E
6E 61 62 6C-65 20 4D 65-00 04 78 00-58 02 BF 13 nable Me ?x X?+?
EF 01 11 02-00 FF 02 03-AE 00 00 00-02 06 00 4C ???? ??? ?? L
61 62 65 6C-31 00 01 01-6A 00 41 63-69 64 5F 43 abel1 ??j Acid_C
6F 6F 6C 5F-31 37 38 27-73 20 45 78-44 65 63 20 ool_178’s ExDec
43 72 61 63-6B 6D 65 20-30 33 2E 42-2C 20 6A 75 Crackme 03.B, ju
73 74 20 65-6E 61 62 6C-65 20 74 68-65 20 62 75 st enable the bu
74 74 6F 6E-2E 2E 2E 20-4D 61 79 62-65 20 74 68 tton... Maybe th
69 73 6F 6E-65 20 69 73-20 61 62 69-74 20 65 61 isone is abit ea
73 69 65 72-20 74 68 61-6E 20 45 78-44 65 63 20 sier than ExDec
30 33 2E 41-00 03 00 00-00 00 04 FF-FF FF 00 05 03.A ? ? ?
78 00 78 00-AF 14 47 04-12 00 00 25-01 00 00 00 x x ?¶G?? %?
BC 02 A4 2C-02 00 0E 43-65 6E 74 75-72 79 20 47 +??,? ?Century G
6F 74 68 69-63 FF 02 04-50 00 00 00-2E F4 B5 01 othic ??P .?¦?
C9 42 34 4B-9A 3F 43 B2-41 04 7C 5E-00 00 00 00 +B4K??C¦A?|^
Теперь видим 24. Это LinkTopic, после которого идет строка, строки мы уже умеем достать потому продолжим. 35 - этого опкода в таблице нет, но я тебе расскажу - это всего лишь линейные размеры клиентской части формы. За байтом 35 идут 4 dword’а. Это соответственно ClientLeft, ClientTop, ClientWidth, ClientHeight. Затем видим 46 - StartUpPosition. Это один байт, определяющий позицию формы при запуске (в центре экрана, где получится или в центре Parent формы. Теперь мы дошли до самого интересного - FF01. Помните я говорил про константы определяющие конец одних контролов или начало других? Так вот FF01 - это vbFormNewChildControl определяет что далее идет контрол, контейнером для которого является форма. Сначала стандартно: dword размер информации о следующей контроле, затем имя контрола и пошли свойства. 01 - Caption, 03 - BackColor, 04 - ForeColor, 05 - линейные размеры, декомпилируются подобно линейным размерам клиентской части формы, с одной небольшой разницей - каждый из размеров занимает не 4, а 2 байта. Продолжим. 12 - TabIndex, индекс, используемый для перечисления контролов на формы при нажатии Tab. Многие программисты забывают его проставить после разработки программы, отсюда любители работать только с использованием клавиатуры плюются и ругают такой продукт, а главное кривизну рук автора. Причем я их в этом поддерживаю, это свойство программист обязан выставить - это правило профессиональной разработки интерфейсов. Так вот этот индекс определяется двумя байтами. Это значит, что более 65535 контролов на форму не поместить. Затем идет 1B. Это одно из самых интересных свойств - Font. В отличии от других оно описывается классом stdole.Font,который есть только в VB. Поэтому писать декомпилятор VB не на VB это большой геморрой именно из-за классов, зашитых в библиотеки Visual Basic 6.0. В конце всех контролов мы увидим FF0204 Как мы помним 02 это vbFormExistingChildControl, то есть надо закрыть контрол и 04 это vbFormEnd закрывает форму. Вот что получится если бы мы записывали то что декомпилировали в уме (листинг взят из декомпилятора VB Decompiler):
Begin VB.Form AC_ExDec_03_B ’Offset: 000010FA
Caption = "Crackme for JosephCo’s ExDec Program..."
BackColor = &H80000008&
ScaleMode = 1
WhatsThisButton = 0 ’False
Icon = "AC_ExDec_03_B.frx":0
LinkTopic = "Form1"
ClientLeft = 60
ClientTop = 345
ClientWidth = 5580
ClientHeight = 3075
StartUpPosition = 3 ’Windows Default
Begin VB.Frame Frame1 ’Offset: 000015A6
Caption = "Button is in here"
BackColor = &H0&
ForeColor = &HFFFFFF&
Left = 120
Top = 1440
Width = 5295
Height = 1335
TabIndex = 1
BeginProperty Font
Name = "Century Gothic"
Size = 14,25
Charset = 0
Weight = 700
Underline = 0 ’False
Italic = 0 ’False
Strikethrough = 0 ’False
EndProperty
... и так далее
Теперь попробуем на конкретном примере изменить свойство меню и показать невидимую кнопку.
Редактирование свойств меню
Специально для демонстрации заблокированного меню я написал простенький пример.
В нем заблокирован пункт меню "Test". Попробуем его изменить. Для начала необходимо знать как можно сделать меню неактивным. Тут есть два способа. Первый - при проектировании поставить свойство Enabled у меню в False, второй - установить это свойство кодом при запуске формы. Представим что это свойство установлено при разработке меню. Тогда декомпилируем этот проект и посмотрим данные нашей формы. Для простоты не будем заново декомпилировать в уме, а возьмем VB Decompiler (Lite версия вполне подойдет). В разделе формы всего одна форма. Поищем там меню:
Begin VB.Menu mnuFile ’Offset: 000011B3
Caption = "Файл"
Begin VB.Menu mnuTest ’Offset: 000011CF
Caption = "Test"
Enabled = 0 ’False
End
Begin VB.Menu Separator ’Offset: 000011F0
Caption = "-"
End
Begin VB.Menu mnuExit ’Offset: 0000120B
Caption = "Выход"
End
End
Как видим, свойство "Enabled = 0", это то что мы искали. Теперь подумаем как поправить. Откроем файл в hiew и перейдем по адресу 11F0:
00 00 02 07-00 6D 6E 75-54 65 78 74-00 13 03 09 O• mnuTest !¦0
00 54 65 78-74 00 05-00 FF 02 1A Test ¦ яO>
Все стандартно: сначала Name, затем Caption (03) и 05 - Enabled. После него идет один байт 00, что означает False. Заменим на FF (True) и попробуем запустить. Меню разблокировано и при нажитии на него выводится MessageBox. Тем же способом можно изменять любые свойства контролов.
Показываем скрытые кнопки
Для рассмотрения вопроса я написал простой пример, который после запуска делает видимой кнопку "Test" через 3 секунды. Чтож, поглядим в декомпиляторе что у нас с кнопкой "Test":
Begin VB.CommandButton cmdTest ’Offset: 00001175
Caption = "Test"
Left = 1680
Top = 1800
Width = 1335
Height = 375
Visible = 0 ’False
TabIndex = 1
End
Сразу бросается в глаза "Visible = 0", которое в таблице значится как 09. Переходим по смещению 1175 и проходим все свойства до 09. Видим 00, это False, меняем на FF (True). Но, давайте рассмотрим как реализуется показ кнопки через 3 секунды? Можно сделать цикл при запуске программы, но он на разных процессорах будет работать с разной скоростью. Можно использовать GetTickCount, но потребуется его проверять в While цикле, что тоже неудобно. Но в большинстве случаев для этого используются простые таймеры. Таймер - это невидимый контрол на форме, у которого событие срабатывает каждые Interval милисекунд. Поищем ка мы таймер в нашем проекте:
Begin VB.Timer Timer1 ’Offset: 00001155
Interval = 3000
Left = 2880
Top = 0
Width = 59400
Height = 8
End
Так и есть! 3000 милисекунд это 3 секунды. Заменим ка мы их на 1. Но, так как я не сделал отключения таймера после установки свойства в кнопку - таймер будет срабатывать постоянно и замедлять код, потому лучше использовать предыдущий способ, а таймер просто отключить, поставив интервал в 0.
Добавление новый свойств
Читая статью Вы наверняка задались вопросом: а как же добавить новое свойство в упакованный контрол? Добавить можно только разбором, вставкой и последующей сборкой обратно всей формы. Ясное дело что уже на старое место данные не поместятся, поэтому придется создавать новую секцию в файле или расширять последнюю и редиректить данные туда. Кроме того адрес на новое расположение формы придется прописать в структуре информации о форме. При этом нужно учитывать, что если пользователь будет часто добавлять свойства, то нужно заранее в новой секции сделать запас в виде резервных байт под расширение каждой формы. Всю эту информацию о резерве байт и начале и длине каждой формы, вынесенной в новую секцию придется гдето сохранить чтобы использовать при следующих правках объектов. Для этого придется создать свою служебную структуру. Это все будет полезно только в том случае, если писать свой редактор ресурсов Visual Basic. Для анализа форм знаний из этой статьи вполне хватит. А вот автоматизировать это или нет - решать Вам.
Заключение
Надеюсь что у Вас не осталось вопросов по теме редактирования интерфейса VB программ. Если же они всеже есть - добро пожаловать на наш форум.
Комментарии |
отсутствуют |
Добавление комментария |