Автор: Сергей Чубченко. Дата публикации: 15.09.2004
[Вступление]
Многие почему-то считают, что Visual Basic самый плохой язык программирования, который не может компилировать программы в машинный код, не может работать с адресами переменных в памяти и не позволяюет вставлять ассемблерные процедуры в высокоуровневый код программы. Так вот, все это неправда. Начиная с версии 5.0 данный язык позволяет компилировать программы в машинный Native Code, а также имеется возможность работы с адресами переменных в оперативной памяти (для этого существуют функции VarPtr и StrPtr). Ассемблерные процедуры вставлять тоже можно, но не так просто. Для этого я написал уже 2 части статьи по вставке ассемблерных процедур в код на Visual Basic. Первая статья размещена здесь: Ассемблер в VB6 часть 1, вторая тут: Ассемблер в VB6 часть 2. Как видите, недостатков у VB не так уж и много, а преимуществ настолько много, что я расскажу лишь о самых очевидных и важных:
- Полноценная компиляция и маленький размер получаемых exe файлов. Несмотря на то, что программы требуют библиотеку MSVBVM60.DLL, это не является недостатком, так как эта библиотека интегрирована во все новые операционные системы и таскать ее вместе с приложением не нужно.
- Простота написания кода. Все удобно и наглядно. Даже начинающий может писать неоптимизированные, но рабочие программы. Как говорится, умеешь писать качественно - пиши, от этого программы будут только лучше. Не умеешь - можешь писать неоптимизированные программы (переменные объявлять не обязательно, преобразовывать типы данных тоже не обязательно). Но постепенно приходят более глубокие познания и можно писать крупные проекты, не уступающие аналогам на C++ или Delphi.
Так вот, исследователи программ почему-то считают, что программы, написанные на Visual Basic'е невозможно анализировать. Если программа скомпилирована в P-Code - их частично можно понять, но даже для этого вида компиляции уже написано пара отладчиков, способных понимать псевдокодовые инструкции. Что же касается Native Code, то тут все исследуется так же, как и любой x86 программный код, написанный например на C++ или Delphi. Но есть ряд особенностей. Все операции, которые выполняет программа выполняются с использованием узкоспециализированных функций из библиотеки MSVBVM60.DLL. Имена этих функций напоминают операторы Visual Basic'а, поэтому глядя на названия большинства из них, можно понять, какие операции они позволяют выполнять. Но есть и такие, которые не поддаются логике. О них я и расскажу в данной статье.
[Функции]
Самые непонятные аналитикам функции - функции для преобразования данных из одного типа в другой. Чуть ниже я для удобства приведу существующие типы данных, используемых в Visual Basic 6.0 и функции для работы с ними.
bool - boolean
str - string
i2 - integer (2 байтный integer)
ui2 - unsigned integer (2 байтный unsigned integer)
i4 - long (4 байтный integer)
r4 - single (4 байтный float)
r8 - double (8 байтный float)
cy - currency
var - variant (VB) или variable (OLEAUT)
Названия части функций:
fp - работа с float данными, переданными через st регистры или сохраняемые туда командами сопроцессора
cmp - сравнение аргументов
comp - сравнение аргументов
- Функции ля преобразования типов данных:
__vbaI2Str 'преобразует String в Integer
__vbaI4Str 'преобразует String в Long
__vbar4Str 'преобразует String в Single
__vbar8Str 'преобразует String в Double
VarCyFromStr 'преобразует String в Currency
VarBstrFromI2 'преобразует Integer в String
- Перенос данных
__vbaStrCopy 'копирует строку в память - аналог API функции HMEMCPY
__vbaVarCopy 'копирует переменный тип (variant) в память
__vbaVarMove 'копирует переменный тип (variant) в память
- Математические функции
__vbavaradd 'сложение двух переменных типа Variant
__vbavarsub 'деление двух переменных типа Variant
__vbavarmul 'умножение двух переменных типа Variant
__vbavaridiv 'сложение двух переменных типа Variant
'с выводом результата в переменную типа Integer
__vbavarxor 'XOR
- Другие функции
__vbavarfornext 'используется в конструкциях For... Next... (Loop)
__vbafreestr 'удаление переменной
__vbafreeobj 'удаление объекта
__vbastrvarval 'получения численного значения из строки
multibytetowidechar 'преобразование кодировки
rtcMsgBox 'показывает сообщение - аналог API messagebox/a/exa
__vbavarcat 'объединяет две переменные типа Variant
__vbafreevar 'удаляет переменную типа Variant
__vbaobjset 'создает объект
__vbaLenBstr 'определяет длину строки
rtcInputBox 'показывает форму с полем ввода (используются также API функции getwindowtext/a, GetDlgItemtext/a)
__vbaNew 'аналог API функции Dialogbox
__vbaNew2 'аналог API функции Dialogboxparam/a
rtcTrimBstr 'удаляет пробелы вначале и в конце строки
- Функции сравнения
__vbastrcomp 'сравнивает 2 строковые переменные - аналог API функции lstrcmp
__vbastrcmp 'сравнивает 2 строковые переменные - аналог API функции lstrcmp
__vbavartsteq 'сравнивает 2 Variant переменные
__vbaFpCmpCy 'сравнивает значение с плавающей точкой с Currency значением
[Разблокирование элементов управления]
Любой элемент управления на форме может быть видимым или невидимым, доступным или заблокированным. Для установки свойств объектов существует функция __vbaObjSet. Именно с помощью нее можно заблокировать или разблокировать элемент управления и изменить любое из его свойств. Поэтому нам необходимо отлавливать вызов именно этой функции. Откроем например Olly Debugger, найдем эту функцию среди вызываемых анализируемым файлом и поставим на нее breakpoint нажав кнопку F2. Затем запустим исследуемый файл. Когда breakpoint сработает - посмотрите окружающий код. Если он напоминает
то Вы на верном пути. Как вы думаете, что это за "push 00"? 00h в VB означает FALSE, а FFh TRUE, из этого следует, что данная команда устанавливает свойство в FALSE, то, возможно, это и есть блокировка элемента управления на форме. Но это может быть и установка любого другого свойства формы в TRUE. Так как синтаксис один и тот же, то принадлежность данной команды к изменению свойства блокировки можно установить только анализом окружающего кода. Но думаю с этой мелочью Вы справитесь сами.
[Методика анализа простейших проверок строковых данных]
Нижеследующий текст - мой вольный перевод статьи How to Research Visual Basic с одного из зарубежных сайтов infonegocio.com. За английскую версию текста спасибо ее авторам.
Что нам может понадобиться? Любой дизассемблер/отладчик. Подойдет Win32Dasm или Olly Debugger Если вы используете W32Dasm, то функции, используемые программой вы можете посмотреть в меню "Functions" -> "Imports".
Если вы будете исследовать базу данных Jet, то помните, что названия функции не говорят сами за себя и вам будет трудно узнать действие, которое выполняет та или иная функция. В данном случае Вам остается только смотреть названия функций, которые любезно оставлены программистами. Дыр же в этих драйверах практически нет, поэтому исследовать код для работы с базами данных довольно сложно.
Рассмотрим пример блокировки работы кода проверкой строки. Для удобства поиска нужного кода поставим MessageBox. Откройте Visual Basic, добавьте на форму текстовое поле и кнопку, затем в обработчике щелчка по кнопке напишите следующий код:
Теперь откроем Olly Debugger, загрузим в него файл (предварительно откомпилируем его в VB6) и ищем вызов функции rtcMsgBox.
Чтобы отключить проверку значения - нужно изменить переход по адресу 00401FF9 с условного на безусловный. Для этого меняем JE на JMP (то есть 74h на EBh). Как видите - такие простенькие проверки в VB коде также малоэффективны, как и их аналоги на С++.
[Анализ значений в виде разных типов данных]
Нижеследующий текст - мой вольный перевод статей с уже указанного выше сайта: infonegocio.com. За английские версии этих статей спасибо их авторам.
- Получение данных, если они лежат строкой в открытом виде
Когда VB копирует строку в память - Вы ее можете отловить.
Для этого нужно поставить breakpoint на функцию __vbaStrCopy и когда он у Вас сработает, посмотрите код после je 66047B00 (он содержится в библиотеке и един для всех программ). Затем нужно посмотреть содержимое edx-04 (в SoftICE нужно ввести команду d edx-04). При этом вы увидите строчку, с которой работает в данный момент функция.
- Получение строки, если она сравнивается с введенной
Поставьте breakpoint на функцию __vbaStrComp и чуть выше ее вызова будут два push'а - они заносят в стек две Variant переменные для сравнения. Посмотрите содержимое EAX чтобы узнать адрес текста. Глянем что лежит по этому адресу, наверняка это нужная строка.
- Получение данных, если происходит сравнение 4х байтовых числовых переменных
Поставьте breakpoint на функцию __vbai4str. Эта функция используется программой для перевода введенной текстовой строки в 4х байтовое число. Когда breakpoint сработает - посмотрите код ниже - там наверняка будет процедура сравнения строк. Но значение нужное нам будет в HEX виде (например десятичное число 987654321 равно шестнадцатеричному 3ADE68B1).
Тут мы можем узнать верное значение или отключить проверку вовсе (для этого нужно JNZ заменить на NOP). То есть в данном случае менять нужно байты по адресу 00401B97 с 7520 на 9090)
- Получение правильных данных при сравнивании 2х байтовых чисел
Отличие от предыдущего примера в том, что нужно ставить breakpoint на функцию __vbaI2Str. Но иногда предварительно производится преобразование строки сначала в 4х байтовое число посредством функции __vbaI2I4, а затем 4х байтовое число преобразуется в двухбайтовое.
- Обход сравнения двух переменных типа Single
Эту проверку обойти довольно просто. Ставьте breakpoint на функцию __vbaR4Str и когда он сработает - пролистните код вниз. Вы увидите переход после проверки. Просто измените условие перехода на обратное.
Замените инструкцию по адресу 00401C38 на 9090 (чтобы в данном месте не выполнялось никаких операций) или измените условный переход на противоположный. На Visual Basic нельзя проверить то, что вы заменили эти байты на два NOP'а (9090). Если у Вас все же возникают опасения, что код перестанет работать при отсутствии команд, просто введите команды, которые ничего не поменяют, например:
Эти команды однобайтовые и как раз впишутся на место условного перехода
- Обход проверки значений с плавающей точкой (double).
Это также сделать очень просто. Ставьте breakpoint на функцию __vbaR8Str и пролистните код чуть ниже останова на breakpoint'е, Вы увидите процедуру сравнения (FCOMP REAL8 PTR [Address]), после нее идет test и jmp. Измените условие перехода на противоположное.
Замените инструкцию по адресу 00401C78 на 9090 (чтобы в данном месте не выполнялось никаких операций) или измените условный переход на противоположный. На Visual Basic нельзя проверить то, что вы заменили эти байты на два NOP'а (9090). Если у Вас все же возникают опасения, что код перестанет работать при отсутствии команд, просто введите команды, которые ничего не поменяют, например:
Эти команды однобайтовые и как раз впишутся на место условного перехода.
- Получение строки, если она поXORена.
Алгоритм работы бейсиковской процедуры таков. Введенная строка посимвольно переводится в ASCII коды, которые по очереди XORятся. Затем производится обратный перевод, возможно с предварительными математическими манипуляциями с ASCII кодами. ANSI коды могут XORиться со случайным или фиксированным числом.
Ставим breakpoint на 00401E8A 51 PUSH ECX и отслеживаем изменение содержимого регистра ECX при прохождении цикла. Когда программа пройдет весь цикл - вы получите расшифрованную строку.
В этом случае ниже скорее всего будет сравнение и переход, при этом CALL [MSVBVM60!__vbaStrComp] может быть использован для сравнения строк. Если не производится обращение к MSVBVM60!rtcBstrFromAnsi тогда со строкой производятся определенные математические манипуляции, при этом она может быть представлена как 2х или 4х байтное число или число с плавающей точкой. Об этих случаях было сказано выше.
[Заключение]
Надеюсь, что прочитав данную статью Вас уже больше не пугает анализ VB кода. Чтобы посмотреть как выглядить VB код вживую - советую посмотреть мои примеры (лежат на данном сайте в разделе "Разное").
Еще раз благодарю авторов сайта infonegocio.com, так как если бы не их туториалы на английском, то этой статьи возможно и не было бы.
Удачи и спасибо за то, что дочитали статью до конца.
Руководство по исследованию программ, написанных на Visual Basic 6.0
[Вступление]
Многие почему-то считают, что Visual Basic самый плохой язык программирования, который не может компилировать программы в машинный код, не может работать с адресами переменных в памяти и не позволяюет вставлять ассемблерные процедуры в высокоуровневый код программы. Так вот, все это неправда. Начиная с версии 5.0 данный язык позволяет компилировать программы в машинный Native Code, а также имеется возможность работы с адресами переменных в оперативной памяти (для этого существуют функции VarPtr и StrPtr). Ассемблерные процедуры вставлять тоже можно, но не так просто. Для этого я написал уже 2 части статьи по вставке ассемблерных процедур в код на Visual Basic. Первая статья размещена здесь: Ассемблер в VB6 часть 1, вторая тут: Ассемблер в VB6 часть 2. Как видите, недостатков у VB не так уж и много, а преимуществ настолько много, что я расскажу лишь о самых очевидных и важных:
- Полноценная компиляция и маленький размер получаемых exe файлов. Несмотря на то, что программы требуют библиотеку MSVBVM60.DLL, это не является недостатком, так как эта библиотека интегрирована во все новые операционные системы и таскать ее вместе с приложением не нужно.
- Простота написания кода. Все удобно и наглядно. Даже начинающий может писать неоптимизированные, но рабочие программы. Как говорится, умеешь писать качественно - пиши, от этого программы будут только лучше. Не умеешь - можешь писать неоптимизированные программы (переменные объявлять не обязательно, преобразовывать типы данных тоже не обязательно). Но постепенно приходят более глубокие познания и можно писать крупные проекты, не уступающие аналогам на C++ или Delphi.
Так вот, исследователи программ почему-то считают, что программы, написанные на Visual Basic'е невозможно анализировать. Если программа скомпилирована в P-Code - их частично можно понять, но даже для этого вида компиляции уже написано пара отладчиков, способных понимать псевдокодовые инструкции. Что же касается Native Code, то тут все исследуется так же, как и любой x86 программный код, написанный например на C++ или Delphi. Но есть ряд особенностей. Все операции, которые выполняет программа выполняются с использованием узкоспециализированных функций из библиотеки MSVBVM60.DLL. Имена этих функций напоминают операторы Visual Basic'а, поэтому глядя на названия большинства из них, можно понять, какие операции они позволяют выполнять. Но есть и такие, которые не поддаются логике. О них я и расскажу в данной статье.
[Функции]
Самые непонятные аналитикам функции - функции для преобразования данных из одного типа в другой. Чуть ниже я для удобства приведу существующие типы данных, используемых в Visual Basic 6.0 и функции для работы с ними.
bool - boolean
str - string
i2 - integer (2 байтный integer)
ui2 - unsigned integer (2 байтный unsigned integer)
i4 - long (4 байтный integer)
r4 - single (4 байтный float)
r8 - double (8 байтный float)
cy - currency
var - variant (VB) или variable (OLEAUT)
Названия части функций:
fp - работа с float данными, переданными через st регистры или сохраняемые туда командами сопроцессора
cmp - сравнение аргументов
comp - сравнение аргументов
- Функции ля преобразования типов данных:
__vbaI2Str 'преобразует String в Integer
__vbaI4Str 'преобразует String в Long
__vbar4Str 'преобразует String в Single
__vbar8Str 'преобразует String в Double
VarCyFromStr 'преобразует String в Currency
VarBstrFromI2 'преобразует Integer в String
- Перенос данных
__vbaStrCopy 'копирует строку в память - аналог API функции HMEMCPY
__vbaVarCopy 'копирует переменный тип (variant) в память
__vbaVarMove 'копирует переменный тип (variant) в память
- Математические функции
__vbavaradd 'сложение двух переменных типа Variant
__vbavarsub 'деление двух переменных типа Variant
__vbavarmul 'умножение двух переменных типа Variant
__vbavaridiv 'сложение двух переменных типа Variant
'с выводом результата в переменную типа Integer
__vbavarxor 'XOR
- Другие функции
__vbavarfornext 'используется в конструкциях For... Next... (Loop)
__vbafreestr 'удаление переменной
__vbafreeobj 'удаление объекта
__vbastrvarval 'получения численного значения из строки
multibytetowidechar 'преобразование кодировки
rtcMsgBox 'показывает сообщение - аналог API messagebox/a/exa
__vbavarcat 'объединяет две переменные типа Variant
__vbafreevar 'удаляет переменную типа Variant
__vbaobjset 'создает объект
__vbaLenBstr 'определяет длину строки
rtcInputBox 'показывает форму с полем ввода (используются также API функции getwindowtext/a, GetDlgItemtext/a)
__vbaNew 'аналог API функции Dialogbox
__vbaNew2 'аналог API функции Dialogboxparam/a
rtcTrimBstr 'удаляет пробелы вначале и в конце строки
- Функции сравнения
__vbastrcomp 'сравнивает 2 строковые переменные - аналог API функции lstrcmp
__vbastrcmp 'сравнивает 2 строковые переменные - аналог API функции lstrcmp
__vbavartsteq 'сравнивает 2 Variant переменные
__vbaFpCmpCy 'сравнивает значение с плавающей точкой с Currency значением
[Разблокирование элементов управления]
Любой элемент управления на форме может быть видимым или невидимым, доступным или заблокированным. Для установки свойств объектов существует функция __vbaObjSet. Именно с помощью нее можно заблокировать или разблокировать элемент управления и изменить любое из его свойств. Поэтому нам необходимо отлавливать вызов именно этой функции. Откроем например Olly Debugger, найдем эту функцию среди вызываемых анализируемым файлом и поставим на нее breakpoint нажав кнопку F2. Затем запустим исследуемый файл. Когда breakpoint сработает - посмотрите окружающий код. Если он напоминает
50 push eax
52 push edx
FFD7 call edi
8BD8 mov ebx, eax
6A00 push 00
53 push ebx
8B03 mov eax, dword ptr [ebx]
то Вы на верном пути. Как вы думаете, что это за "push 00"? 00h в VB означает FALSE, а FFh TRUE, из этого следует, что данная команда устанавливает свойство в FALSE, то, возможно, это и есть блокировка элемента управления на форме. Но это может быть и установка любого другого свойства формы в TRUE. Так как синтаксис один и тот же, то принадлежность данной команды к изменению свойства блокировки можно установить только анализом окружающего кода. Но думаю с этой мелочью Вы справитесь сами.
[Методика анализа простейших проверок строковых данных]
Нижеследующий текст - мой вольный перевод статьи How to Research Visual Basic с одного из зарубежных сайтов infonegocio.com. За английскую версию текста спасибо ее авторам.
Что нам может понадобиться? Любой дизассемблер/отладчик. Подойдет Win32Dasm или Olly Debugger Если вы используете W32Dasm, то функции, используемые программой вы можете посмотреть в меню "Functions" -> "Imports".
Если вы будете исследовать базу данных Jet, то помните, что названия функции не говорят сами за себя и вам будет трудно узнать действие, которое выполняет та или иная функция. В данном случае Вам остается только смотреть названия функций, которые любезно оставлены программистами. Дыр же в этих драйверах практически нет, поэтому исследовать код для работы с базами данных довольно сложно.
Рассмотрим пример блокировки работы кода проверкой строки. Для удобства поиска нужного кода поставим MessageBox. Откройте Visual Basic, добавьте на форму текстовое поле и кнопку, затем в обработчике щелчка по кнопке напишите следующий код:
Private Sub Command1_Click()
Dim X&
X = 43690
MsgBox "Checking value"
If CLng(Trim$(Text1.Text)) = X Then MsgBox ("Complete")
End Sub
Теперь откроем Olly Debugger, загрузим в него файл (предварительно откомпилируем его в VB6) и ищем вызов функции rtcMsgBox.
00401F54 FF1520104000 CALL [MSVBVM60!rtcMsgBox] ;MsgBox "Checking value"
00401F5A 8D459C LEA EAX,[EBP-64]
00401F5D 8D4DAC LEA ECX,[EBP-54]
00401F60 50 PUSH EAX
00401F61 8D55BC LEA EDX,[EBP-44]
00401F64 51 PUSH ECX
00401F65 8D45CCLEA EAX,[EBP-34]
00401F68 52 PUSH EDX
00401F69 50 PUSH EAX
00401F6A 6A04 PUSH 04
00401F6C FF1508104000 CALL [MSVBVM60!__vbaFreeVarList]
00401F72 8B0E MOV ECX,[ESI]
00401F74 83C414 ADD ESP,14
00401F77 56 PUSH ESI
00401F78 FF9104030000 CALL [ECX+00000304]
00401F7E 8D55DCLEA EDX,[EBP-24]
00401F81 50 PUSH EAX
00401F82 52 PUSH EDX
00401F83 FF1524104000 CALL [MSVBVM60!__vbaObjSet]
00401F89 8BF0 MOV ESI,EAX
00401F8B 8D4DE4LEA ECX,[EBP-1C]
00401F8E 51 PUSH ECX
00401F8F 56 PUSH ESI
00401F90 8B06 MOV EAX,[ESI]
00401F92 FF90A0000000 CALL [EAX+000000A0]
00401F98 3BC7 CMP EAX,EDI
00401F9A DBE2 FCLEX
00401F9C 7D12 JGE 00401FB0
00401F9E 68A0000000 PUSH 000000A0
00401FA3 6804184000 PUSH 00401804
00401FA8 56 PUSH ESI
00401FA9 50 PUSH EAX
00401FAA FF1518104000 CALL [MSVBVM60!__vbaHresultCheckObj] ;получение содержимого Text1.Text
00401FB0 8B55E4MOV EDX,[EBP-1C]
00401FB3 52 PUSH EDX
00401FB4 FF1514104000 CALL [MSVBVM60!rtcTrimBstr] ;Trim$
00401FBA 8BD0 MOV EDX,EAX
00401FBC 8D4DE0 LEA ECX,[EBP-20]
00401FBF FF1584104000 CALL [MSVBVM60!__vbaStrMove]
00401FC5 50 PUSH EAX
00401FC6 FF1568104000 CALL [MSVBVM60!__vbaI4Str] ;CLng
00401FCC 33C9 XOR ECX,ECX
00401FCE 3DAAAA0000 CMP EAX,0000AAAA ;Число 43690 в HEX виде
00401FD3 8D55E0LEA EDX,[EBP-20]
00401FD6 8D45E4LEA EAX,[EBP-1C]
00401FD9 0F94C1 SETZ CL
00401FDC 52 PUSH EDX
00401FDD 50 PUSH EAX
00401FDE F7D9 NEG ECX
00401FE0 6A02 PUSH 02
00401FE2 8BF1 MOV ESI,ECX
00401FE4 FF156C104000 CALL [MSVBVM60!__vbaFreeStrList]
00401FEA 83C40C ADD ESP,0C
00401FED 8D4DDC LEA ECX,[EBP-24]
00401FF0 FF1594104000 CALL [MSVBVM60!__vbaFreeObj]
00401FF6 663BF7 CMP SI,DI
00401FF9 7463 JZ 0040205E ;переход на Complete код (MsgBox "Complete")
00401FFB B804000280 MOV EAX,80020004
00402000 8D558C LEA EDX,[EBP-74]
00402003 8D4DCCLEA ECX,[EBP-34]
00402006 8945A4 MOV [EBP-5C],EAX
00402009 895D9C MOV [EBP-64],EBX
0040200C 8945B4 MOV [EBP-4C],EAX
0040200F 895DAC MOV [EBP-54],EBX
00402012 8945C4 MOV [EBP-3C],EAX
00402015 895DBC MOV [EBP-44],EBX
00402018 C7459418184000 MOV DWORD PTR [EBP-6C],00401818
0040201F C7458C08000000 MOV DWORD PTR [EBP-74],00000008
00402026 FF157C104000 CALL [MSVBVM60!__vbaVarDup]
0040202C 8D4D9C LEA ECX,[EBP-64]
Чтобы отключить проверку значения - нужно изменить переход по адресу 00401FF9 с условного на безусловный. Для этого меняем JE на JMP (то есть 74h на EBh). Как видите - такие простенькие проверки в VB коде также малоэффективны, как и их аналоги на С++.
[Анализ значений в виде разных типов данных]
Нижеследующий текст - мой вольный перевод статей с уже указанного выше сайта: infonegocio.com. За английские версии этих статей спасибо их авторам.
- Получение данных, если они лежат строкой в открытом виде
Когда VB копирует строку в память - Вы ее можете отловить.
Для этого нужно поставить breakpoint на функцию __vbaStrCopy и когда он у Вас сработает, посмотрите код после je 66047B00 (он содержится в библиотеке и един для всех программ). Затем нужно посмотреть содержимое edx-04 (в SoftICE нужно ввести команду d edx-04). При этом вы увидите строчку, с которой работает в данный момент функция.
Exported fn(): __vbaStrCopy - Ord:008Ah
:66024532 56 PUSH ESI
:66024533 57 PUSH EDI
:66024534 85D2 TEST EDX, EDX
:66024536 8BF9 MOV EDI, ECX
:66024538 0F84C2350200 JE 66047B00
:6602453E FF72FC PUSH [EDX-04] ;по этому адресу лежит строка
:66024541 52 PUSH EDX
- Получение строки, если она сравнивается с введенной
Поставьте breakpoint на функцию __vbaStrComp и чуть выше ее вызова будут два push'а - они заносят в стек две Variant переменные для сравнения. Посмотрите содержимое EAX чтобы узнать адрес текста. Глянем что лежит по этому адресу, наверняка это нужная строка.
00401BC7 50 PUSH EAX ;то что Вы ввели
00401BC8 6880174000 PUSH 00401780 ;верная строка
00401BCD FF1530104000 CALL [MSVBVM60!__vbaStrComp]
- Получение данных, если происходит сравнение 4х байтовых числовых переменных
Поставьте breakpoint на функцию __vbai4str. Эта функция используется программой для перевода введенной текстовой строки в 4х байтовое число. Когда breakpoint сработает - посмотрите код ниже - там наверняка будет процедура сравнения строк. Но значение нужное нам будет в HEX виде (например десятичное число 987654321 равно шестнадцатеричному 3ADE68B1).
00401B77 FF155C104000 CALL [MSVBVM60!__vbaI4Str]
00401B7D 8D4DE0 LEA ECX, [EBP-20]
00401B80 8BF8 MOV EDI, EAX
00401B82 FF157C104000 CALL [MSVBVM60!__vbaFreeStr]
00401B88 8D4DDC LEA ECX, [EBP-24]
00401B8B FF1580104000 CALL [MSVBVM60!__vbaFreeObj]
00401B91 81FFB168DE3A CMP EDI, 3ADE68B1 ; 3ADE68B1 - это нужное значение
00401B97 7520 JNZ 00401BB9 ;функция вернет ноль если введенное
;и сравниваемое значения равны
;следовательно этот переход сработает только если
;сравниваемые данные отличны друг от друга
Тут мы можем узнать верное значение или отключить проверку вовсе (для этого нужно JNZ заменить на NOP). То есть в данном случае менять нужно байты по адресу 00401B97 с 7520 на 9090)
- Получение правильных данных при сравнивании 2х байтовых чисел
Отличие от предыдущего примера в том, что нужно ставить breakpoint на функцию __vbaI2Str. Но иногда предварительно производится преобразование строки сначала в 4х байтовое число посредством функции __vbaI2I4, а затем 4х байтовое число преобразуется в двухбайтовое.
- Обход сравнения двух переменных типа Single
Эту проверку обойти довольно просто. Ставьте breakpoint на функцию __vbaR4Str и когда он сработает - пролистните код вниз. Вы увидите переход после проверки. Просто измените условие перехода на обратное.
00401C0C FF153C104000 CALL [MSVBVM60!_vbaR4Str]
00401C12 D95DE4 FSTP REAL4 PTR [EBP-1C]
00401C15 8D4DDC LEA ECX, [EBP-24]
00401C18 8D55E0 LEA EDX, [EBP-20]
00401C1B 51 PUSH ECX
00401C1C 52 PUSH EDX
00401C1D 6A02 PUSH 02
00401C1F FF1570104000 CALL [MSVBVM60!__vbaFreeStrList]
00401C25 83C40C ADD ESP, 0C
00401C28 8D4DD8 LEA ECX, [EBP-28]
00401C2B FF1594104000 CALL [MSVBVM60!__vbaFreeObj]
00401C31 817DE43A92FC42 CMP DWORD PTR [EBP-1C], 42FC923A
00401C38 7520 JNZ 00401C5A ;если ноль, то введенно неверное значение
Замените инструкцию по адресу 00401C38 на 9090 (чтобы в данном месте не выполнялось никаких операций) или измените условный переход на противоположный. На Visual Basic нельзя проверить то, что вы заменили эти байты на два NOP'а (9090). Если у Вас все же возникают опасения, что код перестанет работать при отсутствии команд, просто введите команды, которые ничего не поменяют, например:
inc eax
dec eax
Эти команды однобайтовые и как раз впишутся на место условного перехода
- Обход проверки значений с плавающей точкой (double).
Это также сделать очень просто. Ставьте breakpoint на функцию __vbaR8Str и пролистните код чуть ниже останова на breakpoint'е, Вы увидите процедуру сравнения (FCOMP REAL8 PTR [Address]), после нее идет test и jmp. Измените условие перехода на противоположное.
00401C55 FF1510104000 CALL [MSVBVM60!rtcTrimBstr]
00401C5B 8BD0 MOV EDX, EAX
00401C5D 8D4DD8 LEA ECX, DWORD PTR [EBP-28]
00401C60 FF1580104000 CALL [MSVBVM60!__vbaStrMove]
00401C66 50 PUSH EAX
00401C67 FF1560104000 CALL [MSVBVM60!__vbaR8Str]
00401C6D DC1DD8104000 FCOMP REAL8 PTR [004010D8] ;сравнение значений
00401C73 DFE0 FSTSW AX ;обработка сопроцессором
00401C75 F6C440 TEST AH, 40 ;проверка правильности значений
00401C78 7409 JE 00401C83 ;переход
Замените инструкцию по адресу 00401C78 на 9090 (чтобы в данном месте не выполнялось никаких операций) или измените условный переход на противоположный. На Visual Basic нельзя проверить то, что вы заменили эти байты на два NOP'а (9090). Если у Вас все же возникают опасения, что код перестанет работать при отсутствии команд, просто введите команды, которые ничего не поменяют, например:
inc eax
dec eax
Эти команды однобайтовые и как раз впишутся на место условного перехода.
- Получение строки, если она поXORена.
Алгоритм работы бейсиковской процедуры таков. Введенная строка посимвольно переводится в ASCII коды, которые по очереди XORятся. Затем производится обратный перевод, возможно с предварительными математическими манипуляциями с ASCII кодами. ANSI коды могут XORиться со случайным или фиксированным числом.
00401E6C 50 PUSH EAX
00401E6D FF1544104000 CALL [MSVBVM60!rtcMidCharBstr]
00401E73 8BD0 MOV EDX, EAX
00401E75 8D4DC8 LEA ECX, [EBP-38]
00401E78 FFD6 CALL ESI
00401E7A 50 PUSH EAX
00401E7B FF1518104000 CALL [MSVBVM60!rtcAnsiValueBstr]
00401E81 0FBFC8 MOVSX ECX, AX
00401E84 81F191000000 XOR ECX, 00000091 ;ANSI XOR 91
00401E8A 51 PUSH ECX ;результат XOR'а
00401E8B FF1570104000 CALL [MSVBVM60!rtcBstrFromAnsi]
Ставим breakpoint на 00401E8A 51 PUSH ECX и отслеживаем изменение содержимого регистра ECX при прохождении цикла. Когда программа пройдет весь цикл - вы получите расшифрованную строку.
CALL [MSVBVM60!rtcMidCharBstr] ;получает один символ из строки
CALL [MSVBVM60!rtcAnsiValueBstr] ;получает из символа Ansi код
CALL [MSVBVM60!rtcBstrFromAnsi] ;преобразует Ansi код в строку
В этом случае ниже скорее всего будет сравнение и переход, при этом CALL [MSVBVM60!__vbaStrComp] может быть использован для сравнения строк. Если не производится обращение к MSVBVM60!rtcBstrFromAnsi тогда со строкой производятся определенные математические манипуляции, при этом она может быть представлена как 2х или 4х байтное число или число с плавающей точкой. Об этих случаях было сказано выше.
[Заключение]
Надеюсь, что прочитав данную статью Вас уже больше не пугает анализ VB кода. Чтобы посмотреть как выглядить VB код вживую - советую посмотреть мои примеры (лежат на данном сайте в разделе "Разное").
Еще раз благодарю авторов сайта infonegocio.com, так как если бы не их туториалы на английском, то этой статьи возможно и не было бы.
Удачи и спасибо за то, что дочитали статью до конца.
Комментарии |
отсутствуют |
Добавление комментария |