![](https://habrastorage.org/getpro/habr/upload_files/679/30a/730/67930a7309506a5de4a1c7f328f45287.png)
Жив еще Visual Basic: программы еще живы. Байт-код VB выполняется виртуальной машиной msvbvm60.dll , которая до сих пор живет в каталоге C:\Windows .
Задача - разгадать алгоритм проверки ключей.
zira's ZittoKeygenme https://crackmes.one/crackme/648b452233c5d4393891390d
Борьба с упаковщиком
![](https://habrastorage.org/getpro/habr/upload_files/3b4/6f8/f1b/3b46f8f1bdc67ce82b91d23d5a025503.png)
Первое препятствие - программа упакована. Слабость такой защиты - программа при каждом запуске сама себя распаковывает. Наша задача - найти место перехода к точке входа программы.
ASPack мешает дизассемблеру распознавать команды. Дизассемблер читает байты последовательно, но, когда встречает команду call, встает перед выбором:
![](https://habrastorage.org/getpro/habr/upload_files/a19/ed6/a42/a19ed6a42f629e6d5196bfa143f57b7b.png)
Пойти по адресу вызова, дизассемблировать процедуру, вернуться и продолжить работу после call
Оставить разбор процедуры на потом и дизассемблировать следующую за call команду
IDA оставляет разбор процедуры на потом, поэтому следующей командой прочтет E9 EB 04 5D 45 jmp. Процессор же сперва выполнит call, а за ним и другой код: 5D pop ebp.
![](https://habrastorage.org/getpro/habr/upload_files/e93/1cf/df0/e931cfdf0e2fe80d44a4139dfb6f0d34.png)
Команда call толкает в стек адрес следующей инструкции .aspack:00405007 и передает управление loc_40500A. Код снимает со стека адрес, увеличивает на 1 и возвращает управление на .aspack:00405008: jmp short loc_40500E. Вот так лишний байт E9 в потоке инструкций ослепляет дизассемблер.
![](https://habrastorage.org/getpro/habr/upload_files/9b3/49b/04b/9b349b04b71a7a54a2af41457840b755.png)
Распаковщик вычисляет ImageBase - адрес начала кода в памяти, а затем и точку входа программы, записывает адрес OEP в инструкцию push. Теперь знаем, где остановить отладчик, чтобы сделать снимок программы.
![](https://habrastorage.org/getpro/habr/upload_files/a72/f40/2fd/a72f402fdb267a9892e442fe566e8d9c.png)
Дизассемблирование Visual Basic кода
![](https://habrastorage.org/getpro/habr/upload_files/b5e/dc7/b6f/b5edc7b6f8b7107231bb2142e147e1e2.png)
Отладчик показывает, что программа передает управление msvbvm60.ThunRTMain - запускает виртуальную машину Visual Basic. Программа передает msvbvm60.ThunRTMain структуру VBHeader, что описывает проект Visual Basic. Visual Basic компилируется в P-код, который исполняется виртуальной машиной, либо в Native машинный код процессора, который обращается к некоторым API виртуальной машины. VBDec помогает разметить структуры, объекты и процедуры Visual Basic в IDA.
![](https://habrastorage.org/getpro/habr/upload_files/dc3/81d/c2c/dc381dc2cd4c5d859b5276ecf10b2369.png)
![](https://habrastorage.org/getpro/habr/upload_files/05b/e64/5fd/05be645fdb7420445829a45773bf817a.png)
Размер обработчиков Form1_Command1_Click и Form1_Command2_Click подсказывает, что Command1 - кнопка Register. Form1_Command1_Click обращается и к строкам "Thank you for registering this keygenme" и "Incorrect registration information", что выдает и защитный механизм.
![](https://habrastorage.org/getpro/habr/upload_files/cb5/672/4a4/cb56724a4769b514255752120a217842.png)
Упаковщик скрыл импорты функций из msvbvm60.dll , поэтому дизассемблер вместо имен функций показывает call ds:dword_*** . Отладчик сохранил адреса DLL-функций в памяти на момент взятия снимка программы, а по адресам найдем имена.
![](https://habrastorage.org/getpro/habr/upload_files/464/987/eaf/464987eaf925d9463cf0b7383f692c64.png)
Последовательность вызовов __vbaI4Var, rtcMidCharVar, rtcUpperCaseVar, rtcAnsiValueBstr подсказывает что цикл работает с каждой буквой строки. Отладчик подтверждает: строка - UserName.
![](https://habrastorage.org/getpro/habr/upload_files/987/67d/e3e/98767de3eb8be4a0b7dc473ae6d549d1.png)
Интуиция подсказывает, что следующие __vbaVarMul и __vbaVarAdd работают с кодом символа, однако в дизассемблере следы переменной var_E0 с кодом символа к этим функциям не ведут. Отладчик показывает, что __vbaVarMul принимает значения 2 и 2, а возвращает 3. Что за...
![](https://habrastorage.org/getpro/habr/upload_files/3d5/6cc/8a9/3d56cc8a909755fa8834f4e9dbf5b05b.png)
Арифметические функции msvbvm60.dll работают со структурами типа VARIANT и передают работу библиотеке oleaut32.dll . __vbaVarMul вызывает oleaut32.VarMul . Документация к oleaut32.dll говорит: VarMul работает с аргументами типа VARIANT. "OAIdl.h" из Windows SDK описывает структуру VARIANT, а "wtypes.h" определяет константы VT_I2 = 2, VT_I4 = 3 для VARTYPE vt. Умножение двух VARIANT типа VT_I2 дает VARIANT типа VT_I4.
struct tagVARIANT
{
union
{
struct __tagVARIANT
{
VARTYPE vt;
WORD wReserved1;
WORD wReserved2;
WORD wReserved3;
union
{
LONGLONG llVal;
LONG lVal;
BYTE bVal;
/*...*/
![](https://habrastorage.org/getpro/habr/upload_files/f04/2b6/c92/f042b6c92ffd835c02c1975fc10011f8.png)
![](https://habrastorage.org/getpro/habr/upload_files/115/3b5/399/1153b539996bab08fbbfa9b45c7b8b5c.png)
Среди стандартных структур в IDA найдем VARIANT и объединим переменные dword на стеке.
Программа вычисляет хеш User Name так:
int32_t accum = 0;
int32_t hash = 0;
for (char c: name) {
accum += (0x1749 * toupper(c));
hash = accum - name.length();
}
а за ним - ключ регистрации:
string reg_number = "Zitto - "s + to_string(hash);
Ссылки
http://sandsprite.com/vbdec/
https://learn.microsoft.com/en-us/windows/win32/api/oleauto/nf-oleauto-varmul
https://hex-rays.com/products/ida/support/tutorials/unions/