Binary500 является исполняемым ELF'ом для SPARC V9. Дизассемблированный листинг на первый взгляд похож на смесь IA32 + ESA/390 в синтаксисе AT&T. После знакомства с архитектурой и используемыми соглашениями, все становится на свои места:
Процессор имеет 32 64-х битных регистров общего назначения: global %g0-%g7, out %o0-%o7, local %l0-%l7, in %i0-%i7, 32 регистра FPU и систему быстрых, но простых команд длиной 32 бита каждая. Некоторые регистры имеют особое назначение: %g0 всегда содержит ноль, %o6 также известен как %sp (stack pointer), %i6 - %fp (frame pointer), %o7 содержит адрес текущей инструкции при выполнении вызова подпрограммы и используется для определения адреса возврата. Регистры %o0-%o5 используются для передачи аргументов в процедуры, команда, save сохраняет и меняет mapping регистров в процедуре, и %i0-%i5 будут содержать значения из %o, то есть, переданные аргументы. %o0 содержит возвращаемое значение из процедуры.
Также стоит отметить специфику выполнения циклов: инструкция, следующая за командой условного перехода исполняется всегда. Но если условный переход не был выполнен, ее результат аннулируется.
Можно приступать к разбору.
Так как команды имеют длину всего 4 байта (кроме т.н. синтетических инструкций), а адреса - 8 байт, то одной командой адрес не загрузить, и используются конструкции вида (! обозначает комментарий)
set 0x100000, %l1
sllx %l1, 12, %l1
bset 0xFE0, %l1 ! 100000FE0
Анализ неизвестного кода (тем более на не очень знакомой архитектуре) начинают с рассмотрения функций стандартных библиотек или системных вызовов. У нас таких функций (SUNW_C_GetMechSession, C_CreateObject, C_EncryptInit,..., fopen, fprintf,...) в избытке. Если погуглить по первым двум, то приходим на Symmetric Encryption Example, что почти один-в-один с исследуемой программой. Осталось разобрать, где какие значения лежат в нашем коде. Также пригодится этот заголовочный файл для определения констант.
В функции main практически в самом начале (адрес 100000C5C) видим вычисление адреса 100000FE0 и копирования 8 байт оттуда в стековую переменную. Ее значение становится 0xDEADBEEFBAADF00D. Затем идет вычисление адреса 100000FE8 и копирование оттуда 0x78 байт в стек. Причем адрес приемника вычисляется как sethi %hi(0x3800), %g5 + btog -0x101, %g5. Запомним это.
Далее - формирование параметров для SUNW_C_GetMechSession. Из примера от SUN мы знаем, что должно быть что-то вроде
mechanism.mechanism = CKM_DES_CBC_PAD;
mechanism.pParameter = des_cbc_iv;
mechanism.ulParameterLen = 8;
SUNW_C_GetMechSession(mechanism.mechanism, &hSession);
В листинге видим число 8, видим константу 0x125 = CKM_DES_CBC_PAD. Переименовываем стековые переменные
mechanism.mechanism= 0x7CF
arg_7D7 = 0x7D7
mechanism.ulParameterLen= 0x7DF
Это значит, что arg_7D7 = mechanism.pParameter, а des_cbc_iv = 0xDEADBEEFBAADF00D - что скопировали в самом начале main. SUNW_C_GetMechSession возвращает в %o1 идентификатор hSession.
Пропускаем открытие файла и доходим до вызова C_CreateObject, именно здесь указывается ключ шифрования, как видно из примера от SUN:
CK_ATTRIBUTE template[] = {
{CKA_CLASS, &class, sizeof (class) },
{CKA_KEY_TYPE, &keyType, sizeof (keyType) },
{CKA_TOKEN, &falsevalue, sizeof (falsevalue) },
{CKA_ENCRYPT, &truevalue, sizeof (truevalue) },
{CKA_VALUE, &des_key, sizeof (des_key) } };
C_CreateObject(hSession, template, sizeof (template) / sizeof (CK_ATTRIBUTE), &hKey);
В листинге видим, что значение %o1 вычисляется как sethi %hi(0x3800), %g5 + btog -0x101, %g5. Это значит, что template был сформирован в начале main и находился по адресу 100000FE8 до копирования в стек, и выглядит следующим образом (5 элеметов по 3 quad в каждом):
.quad 0
.quad 0x100101678
.quad 8
.quad 0x100
.quad 0x100101680
.quad 8
.quad 1
.quad 0x100101671
.quad 1
.quad 0x104
.quad 0x100101670
.quad 1
.quad 0x11
.quad 0x100101668
.quad 8
С помощью файла констант можно восстановить исходную структуру:
{ {CKA_CLASS, 0x100101678, 8}, /* value 4 = CKO_SECRET_KEY */
{CKA_KEY_TYPE, 0x100101680, 8}, /* value 0x13 = CKK_DES */
{CKA_TOKEN, 0x100101671, 1}, /* value 0 = FALSE */
{CKA_ENCRYPT, 0x100101670, 1}, /* value 1 = TRUE */
{CKA_VALUE, 0x100101668, 8} } /* value 0xDD73CC7FDD7ECC7F */
Далее идет чтение данных из файла и шифрование в цикле.
Итак, имеем алгоритм, паддинг, ключ и шифротекст, осталось написать процедуру расшифрования. Берем pyDes, пишем скрипт и получаем ответ allthatworkanditsjustDES!?!
Leave a comment