Жив еще Visual Basic: программы еще живы. Байт-код VB выполняется виртуальной машиной msvbvm60.dll , которая до сих пор живет в каталоге C:\Windows .
Задача - разгадать алгоритм проверки ключей.
zira's ZittoKeygenme https://crackmes.one/crackme/648b452233c5d4393891390d
Борьба с упаковщиком
Первое препятствие - программа упакована. Слабость такой защиты - программа при каждом запуске сама себя распаковывает. Наша задача - найти место перехода к точке входа программы.
ASPack мешает дизассемблеру распознавать команды. Дизассемблер читает байты последовательно, но, когда встречает команду call, встает перед выбором:
Пойти по адресу вызова, дизассемблировать процедуру, вернуться и продолжить работу после call
Оставить разбор процедуры на потом и дизассемблировать следующую за call команду
IDA оставляет разбор процедуры на потом, поэтому следующей командой прочтет E9 EB 04 5D 45 jmp. Процессор же сперва выполнит call, а за ним и другой код: 5D pop ebp.
Команда call толкает в стек адрес следующей инструкции .aspack:00405007 и передает управление loc_40500A. Код снимает со стека адрес, увеличивает на 1 и возвращает управление на .aspack:00405008: jmp short loc_40500E. Вот так лишний байт E9 в потоке инструкций ослепляет дизассемблер.
Распаковщик вычисляет ImageBase - адрес начала кода в памяти, а затем и точку входа программы, записывает адрес OEP в инструкцию push. Теперь знаем, где остановить отладчик, чтобы сделать снимок программы.
Дизассемблирование Visual Basic кода
Отладчик показывает, что программа передает управление msvbvm60.ThunRTMain - запускает виртуальную машину Visual Basic. Программа передает msvbvm60.ThunRTMain структуру VBHeader, что описывает проект Visual Basic. Visual Basic компилируется в P-код, который исполняется виртуальной машиной, либо в Native машинный код процессора, который обращается к некоторым API виртуальной машины. VBDec помогает разметить структуры, объекты и процедуры Visual Basic в IDA.
Размер обработчиков Form1_Command1_Click и Form1_Command2_Click подсказывает, что Command1 - кнопка Register. Form1_Command1_Click обращается и к строкам "Thank you for registering this keygenme" и "Incorrect registration information", что выдает и защитный механизм.
Упаковщик скрыл импорты функций из msvbvm60.dll , поэтому дизассемблер вместо имен функций показывает call ds:dword_*** . Отладчик сохранил адреса DLL-функций в памяти на момент взятия снимка программы, а по адресам найдем имена.
Последовательность вызовов __vbaI4Var, rtcMidCharVar, rtcUpperCaseVar, rtcAnsiValueBstr подсказывает что цикл работает с каждой буквой строки. Отладчик подтверждает: строка - UserName.
Интуиция подсказывает, что следующие __vbaVarMul и __vbaVarAdd работают с кодом символа, однако в дизассемблере следы переменной var_E0 с кодом символа к этим функциям не ведут. Отладчик показывает, что __vbaVarMul принимает значения 2 и 2, а возвращает 3. Что за...
Арифметические функции 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;
/*...*/
Среди стандартных структур в 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/