Проект ropp.dll под линукс. Лекция о портировании func56.asm

Весёлые истории, картинки и анекдоты.

Модератор: 4epT

k0ka
Новичок
Сообщения: 7
Зарегистрирован: Вс фев 04, 2007 4:34 pm
Контактная информация:

Проект ropp.dll под линукс. Лекция о портировании func56.asm

Сообщение k0ka »

Портирование func5 из Асма в Си онлайн =)

<k0ka> здравствуйте, дорогие фанаты и фанатки Милен Фармер =)
<k0ka> сегодня мы с вами будем портировать func5 и func6 под Си
<k0ka> в этих функциях применяется хэш алгоритм Safer. Как известно, их существует четыре вида: K-64, K-128, SK-64 и SK-128. Какой именно применили гениальные гравитевские программеры мы сегодня и узнаем
<k0ka> просмотрев поцедуру func5 из файла func56.asm можно легко понять, что запускается 3 внеших функции (это операнд CALL)
<k0ka> теперь посмотрим, со сколькими параметрами запускаются эти функции. Для этого надо следить за операндами PUSH. Самый первый - PUSH EBP не имеет к параметрам отношения, это просто сохранение регистра. Посмотрим на остальные:
<k0ka> перед первым вызовом - CALL @Ragexe_e_00503650 - нету других операндов PUSH, значит эта функция вызывается без параметров
<k0ka> перед вторым вызовм - CALL @Ragexe_e_00503690 - целых 5 операндов PUSH, то есть в ней 5 параметров. Нихуйовая такая функция =)
<k0ka> наконец, перед третьим вызовзом - CALL @Ragexe_e_00503800 - 3 операнда PUSH
<k0ka> теперь пора заглянуть в то, что для нас приготовил глубокоуважаемый KLabMouse в папочке draft/func56/
<k0ka> просмотрев файлы safer128.c и safer64.c мы, к сожалению, не обнаруживаем мега-функцию с 5ью параметрами
<k0ka> но давайте заглянем в safer.h. Что же мы там видим? В комментариях описываются три функции
<k0ka> первая функция - без параметров - Safer_Init_Module, вторая - с 5ью параметрами - Safer_Expand_UserKey, и далее ещё две функции - Safer_Encrypt_Block и Safer_Decrypt_Block - с тремя параметрами
<k0ka> очеть похоже, что наши корейские друзья тоже читали этот файлик =)
<k0ka> ещё мы замечаем, что func6 вызывает те же самые первые две функции и третью функцию - другую, но также с 3 параметрами
<k0ka> можно предположить, что они использовали для func5 - Safer_Encrypt_Block, а для func6 - Safer_Decrypt_Block. Конечно, они могли схитрить и использовать наоборот, но давайте не будем переоценивать их интеллект =)
<k0ka> итак, safer64.c и safer128.c - в топку. Надо найти C-файл, который соотвествует safer.h. Для этого мы используем гугль, где ищем по имени функции с 5ью параметрами - Safer_Expand_UserKey
<k0ka> итак, в гугле вторая ссылка - архив openldap c файликом safer.c. OpenLdap - достаточно авторитетная программа и фигню там писать не будут, поэтому скачиваем этот файлик и подцепляем к нашему проекту
<k0ka> тем более, поле AUTHOR этого Си-файла и нашего safer.h совпадают
<k0ka> к сожалению, мы замечаем, что в этом safer.c нету функции инициализации модуля с нулём параметров, поэтому мы качаем полностью исходники модуля и пытаемся выдрать из него необходимые функции
<k0ka> в связи с тем, что делать это долго, лучше попробывать поискать другие варианты реализации. И мы находим нужный нам в четвёртой ссылке в гугле - fresh.t-systems-sfr.com/unix/src/misc/des-1.2.0.tar.gz:b/des/1.2.0/cryptlib.199/safer/safer.h
<k0ka> заменив safer.h на safer.c мы легко скачиваем safer.c с необходимыми нам функциями без всяких extern-функций и переменных
<k0ka> подключаем это к проекту. Пробуем скомпилироваться... и оно успешно компилируется и линкуется
<k0ka> чтож. Теперь надо выдирать из asm-кода параметры, которые передаются в эти функции
<k0ka> смотрим опять в файл func56.asm на процедуру func5. Первые три строчки - PUSH EBP, MOV EBP,ESP и SUB ESP,018h - это стандартная работа со стэком, на которую можно забить
<Вопрос> короче обьясни тупому, где можно нарыть што эта хня есть стандартная работа
<k0ka> следующая строчка - MOV AL,BYTE PTR [d068AAD6h] - говорит о том, что в регистр AL засовывается байт по адресу 0х068AAD6. Смотрим вверх на сегмент dataseg и видим, что там этот байт заполняется нулём
<k0ka> Вопрос из зала, ну йопта =). PUSH EBP - сохраняет в стэке EBP; MOV EBP, ESP - засовывает в EBP регистр ESP, который является указателем на следующий пустой элемент стэка
<k0ka> SUB ESP, 18h - переносит стэк на 0x18=24 байта, оставляя 24 свободных байта для работы внутри функции
<k0ka> в конце функции он делает MOV ESP, EBP - восстанавливая первоначальный стэк и PUP EBP - восстанавливая начальное значение EBP из стэка (то, что было туда занесено командой PUSH EBP)
<k0ka> а дальше в этих 24байтах создаются дополнительные структуры, для передачи их в функции (но об этом ниже)
<k0ka> итак, после строчки MOV AL,BYTE PTR [d068AAD6h] идут строчки: TEST AL,AL и JZ @Ragexe_e_004206B4. Вдаваться в подробности TEST AL,AL не буду. Достаточно знать, что это быстрое сравнение регистра AL с нулём. JZ = Jump if Zero = переходит по указаному адресу, если предыдущее сравнение с нулём было успешным
<k0ka> кстати, посмотрев вверх на байт 068AAD6h повнимательнее, можно заметить, что он инициализируется не нулём, а еденицей
<k0ka> вот та самая строчка: d068AAD6h db 1
<k0ka> то есть, вначале этот JZ точно не срабатывает и программа идёт своим чередом
<k0ka> но давайте посмотрим, куда же прыгнет программа, если AL вдруг станет равным нулю? А прыгает он немного ниже (строчка @Ragexe_e_004206B4:), проскакивая при этом вызов первых двух функций
<k0ka> при этом предыдущая команда до @Ragexe_e_004206B4: - MOV BYTE PTR [d068AAD6h],0 - устанавливает этот байт в ноль. То есть, блок от "JZ @Ragexe_e_004206B4" до "@Ragexe_e_004206B4:" будет пройден только один раз
<k0ka> Эврика! так это просто инициализация той функции для хэширования. Она вызывается при первом запуске func5 и больше не запускается
<k0ka> теперь мы точно уверены, что CALL @Ragexe_e_00503650 - это Safer_Init_Module. а CALL @Ragexe_e_00503690 - это Safer_Expand_Userkey, которые запускаются только один раз
<k0ka> но давайте посмотрим на func6. Там очень похожая структура. Но если Safer_Expand_Userkey запускается с немного отличными параметрами, то Safer_Init_Module - с совершенно такими же. Ха-ха. Похоже тупые корейцы при создании func6 просто скопировали её из func5 и вызывают Safer_Init_Module два раза (оди раз в func5, второй раз в func6). Им повезло, что это работает, ибо иногда запуск инициализации второй раз может похерить всё, что было сделано после первой инициализации
<k0ka> может написать в гравити письмо и посоветовать им, как улучшить код?.. =)
<Вопрос> Кока..
<Вопрос> стоп стоп
<Вопрос> иногда это когда ?
<Вопрос> лучше давай подумаем как это крякнуть
<Вопрос> или крешнуть
<k0ka> иногда - это в других модулях =). В этом модуле Safer_Init_Module просто инициализирует несколько внешних перменных, которые read-only для оставшейся части программы. Если бы они были read-write, то пизда пришла бы этому методу )
<k0ka> итак, на этой положительной ноте можно сделать перерыв, сходить забить кальян и поставить вариться пельмени =)
<k0ka> кстати, внимательное изучение Safer_Init_Module показало, что второй раз он не запускает свою внутренюю начинку, а просто выходит. Защита от корейского дурака успешно сработала =)
<k0ka> итак, кальян есть, вода для пельменей греется.
<k0ka> переводим в Си то, что мы уже поняли
<k0ka> создаём вненюю статическую переменную static unsigned char func5configured = 0;
<k0ka> в функции dword func5( dword key )
<k0ka> пишем:
<k0ka> if (!func5configured)
<k0ka> {
<k0ka> Safer_Init_Module();
<k0ka> func5configured = 1;
<k0ka> }
<k0ka> теперь надо разобраться со вторым вызовом - Safer_Expand_Userkey
<k0ka> сразу после вызова первой функции (CALL @Ragexe_e_00503650) идёт PUSH offset d06E1D24h
<k0ka> так как стэк действует по принципу LIFO (Last Input - First Output), то мы понимаем, что это последний параметр вызова Safer_Expand_Userkey
<k0ka> судя по safer.h последний параметр - это: safer_key_t key - contains the expanded key
<k0ka> сюда он возвращает созданный ключ
<k0ka> там же видим, что safer_key_t - это ни что иное, как typedef unsigned char safer_key_t[SAFER_KEY_LEN]; - то есть просто массив байт
<k0ka> SAFER_KEY_LEN можно высчитать на основании других констант, написаных в том же файле ещё выше. Это значение равно 217
<k0ka> поэтому создаём для него внешнюю статическую перменную, инициализированную на всякий случай нулями: static safer_key_t key5 = {0};
<k0ka> итак, с последним параметром определились - это key5. Смотрим на следующие параметры:
<k0ka> PUSH 0 и PUSH 8. Это просто числовые константы. Кому интересно - могут залезть в safer.h и почитать, за что они отвечают
<k0ka> итак, посмотрим на последние два параметра: PUSH EAX и PUSH ECX. Нужно узнать, а какие значения у этих регистров. Выше мы видим команды LEA EAX,DWORD PTR [EBP-8] и такую же команду для ECX.
<k0ka> LEA EAX,DWORD PTR [EBP-8] - это быстрый аналог команды MOV (он быстрее на 1 такт процессора, насколько я помню). Эта команад просто загружает в EAХ значение EBP-8. А это как раз адрес той памяти в стэке, которая резервировалась для работы этой процедуры (см выше про 24 байта)
<k0ka> то есть, первые два параметра - это указатель на массив, созданые динамически в стэке
<k0ka> но чем же он заполняется? на это мы можем легко ответить, если посмотим дальше на серию команд MOV BYTE PTR [EBP-8],09Ch; MOV BYTE PTR [EBP-7],056h и т.д.
<k0ka> таким образом мы можем дописать в начало нашей Си-функции объявление этого массива: unsigned char s_key[8] = { 0x9C, 0x56, 0xD1, 0x12, 0x23, 0xC0, 0xB4, 0x37 };
<k0ka> и со спокойной душой вызывать Safer_Expand_Userkey(s_key, s_key, 8, 0, key5); после вызова Safer_Init_Module();
<k0ka> тут мы понимаем, что вода уже кипит и пора бросать пельмени
<k0ka> а пока пельмени варятя и я слежу за ними, вы можете посмотреть, с какими параметрами вызывается третья функция (CALL @Ragexe_e_00503800) которая и является собственно шифрованием
<k0ka> вы наверное уже посмотрели на те три параметра, которые передаются в последнюю функцию - это PUSH ECX; PUSH offset d06E1D24h и PUSH EDX
<k0ka> во втром параметре можно сразу узнать тот самый ключ (key5), который мы передавали для заполнения во второй функции
<k0ka> Посмотрев на safer.h можно увидеть, что третий параметр в функции - это адрес, куда будет записана зашифрованная строка.
<k0ka> этот параметр - PUSH ECX. Посмотрев выше видим, что же туда заносится - LEA ECX,DWORD PTR [EBP-018h]
<k0ka> то есть, эта строка создаётся в стэке и никак не инициализируется. А это и не надо, ибо её полностью заполняет Safer_Encrypt_Block
<k0ka> со вторым параметром мы уже разобрались. Посмотрим на первый - PUSH EDX
<k0ka> выше видим, что заносится в этот регист - LEA EDX,DWORD PTR [EBP-010h]. Это также массив, созданный внутри стэка
<k0ka> посмотрим, как же он инициализируется. Инициализируется он очень сильно через жопу. Для этого используются строки: MOV DWORD PTR [EBP-0Fh],EDX; MOV WORD PTR [ EBP-0Bh],DX; MOV BYTE PTR [EBP-9],DL
<k0ka> этими командами массив заполняется от 1го до 7го элемента нулями. Но что же с нулевым элементом?
<k0ka> оказывается, что он инициализируется ниже, вместе с ним затираются нули в 1-3 элементах массива
<k0ka> вот строчка, отвечающая за это - MOV DWORD PTR [EBP-010h],EAX. Смотрим, что в EAX: MOV EAX,DWORD PTR [EBP+8] - но по адресу EBP+8 как раз лежит первый (и в нашем случае единственный) параметр, который передаётся функции.
<k0ka> Таким образом вырисовывается Си-код: dword input[2] = {0}; dword output[2] = {0}; - это создание тех двух массивов
<k0ka> на всякий случай, инициализируем оба в нули. ключ, который нам передаётся надо запихать в начало input-массива и вызвать с ними функцию. Конечно, всё это надо сделать после блока if(), в котором инициализируется модуль: input[0] = key; Safer_Encrypt_Block( input, key5, output );
<k0ka> посмотрим, что возвращает наша доблестная функция. Возвращаемое значение должно находится в регистре EAX. И мы видим,что прямо за вызовом третьей функции (CALL @Ragexe_e_00503800) стоит команда (MOV EAX,DWORD PTR [EBP-018h]), которая заносит в EAX первое четырёхбайтовое слово из результата выполнения Safer_Encrypt_Block.
<k0ka> Таким образом в конце нашей Си-функции пишем return output[0];
<k0ka> компилируем, прогоняем тесты и видим, что функция работает как надо
<k0ka> фсйо
<k0ka> задача на дом - спортировать func6.
Аватара пользователя
piroJOKE
Модератор
Сообщения: 8205
Зарегистрирован: Сб ноя 04, 2006 2:20 am
Сервер RO:: localhost
Откуда: Molvania

Сообщение piroJOKE »

шо та букав многа и не все знакомые
в общем ниасилил
ждем втарой части про функ-6, тока
если можна с картинками
Use brain against brain, ai against ai... · как правильно задавать вопросы · faq · download
Аватара пользователя
kLabMouse
Профессионал
Сообщения: 4776
Зарегистрирован: Вс ноя 05, 2006 4:32 pm

Сообщение kLabMouse »

Дык.Буков действительно много. Думаю Афтар знал о чём писал. И ему крупно повезло что Гравити не напартачило в середине функций, как например с теми что уже переделаны на С.

Надеюсь что Войну и мир писать не будем, в случае если гравити напороло как всегда косяков внутри. Лучше готовое изделие выставить, проверим, закомитим.


ЗЫ: Дя. Ответь на Анонс в офф Форуме Опенкора, надеюсь найдеш где.
ЗыЗы. Для затравки. Вот список функций которые гравити вообще использовало:
mcg_init(void)
mcg_keyset(uchar *,mcg_key *)
mcg_block_encrypt(uchar *,mcg_key *)
mcg_block_decrypt(uchar *,mcg_key *)
HashN(ulong *,ulong *)
Hash512(ulong *,ulong *)
MDinit(ulong *)
compress(ulong *,ulong *)
MDfinish(ulong *,uchar *,ulong,ulong)
Safer_Init_Module(void)
Safer_Expand_Userkey(uchar * const,uchar * const,uint,int,uchar * const)
Safer_Encrypt_Block(uchar * const,uchar * const,uchar * const)
Safer_Decrypt_Block(uchar * const,uchar * const,uchar * const)
cast_encrypt(cast_key *,uchar *,uchar *)
cast_decrypt(cast_key *,uchar *,uchar *)
cast_setkey(cast_key *,uchar *,int)
gen_tab(void)
crypton_set_key(ulong const * const,ulong)
crypton_encrypt(ulong const * const,ulong * const)
crypton_decrypt(ulong const * const,ulong * const)
turtle_encrypt(uchar *,TK *)
turtle_decrypt(uchar *,TK *)
turtle_key(uchar *,int,TK *,int)
hare_stream(HK *)
hare_key(uchar *,int,HK *)
tiger_compress(ulong *,ulong * const)
tiger(ulong *,ulong,ulong * const)
gamma(uchar *,int)
sub_5AC3C0
seal_init(seal_ctx *,uchar *)
seal(seal_ctx *,ulong,ulong *)
seal_refill_buffer(seal_ctx *)
seal_key(seal_ctx *,uchar *)
seal_encrypt(seal_ctx *,ulong *,int)
seal_decrypt(seal_ctx *,ulong *,int)
seal_resynch(seal_ctx *,ulong)
feal8_Decrypt(uchar *,uchar *)
DissH1(ulong,uchar *)
DissQ1(uint,uchar *)
feal8_Encrypt(uchar *,uchar *)
f(ulong,uint)
FK(ulong,ulong)
MakeH1(uchar *)
MakeH2(uint *)
Rot2(uchar)
S0(uchar,uchar)
S1(uchar,uchar)
feal8_SetKey(uchar *)
fi(ulong,ulong)
fo(ulong *,ulong,uchar)
fl(ulong *,ulong,uchar)
flinv(ulong *,ulong,uchar)
misty1_encrypt_block(ulong *,ulong * const,ulong * const)
misty1_decrypt_block(ulong *,ulong * const,ulong * const)
misty1_keyinit(ulong *,ulong *)
misty1_key_destroy(ulong *)
_compress2
_compress
_compressBound
_uncompress
_deflateInit_
_deflateInit2_
_deflateSetDictionary
_deflateReset
_deflatePrime
_deflateParams
_deflateBound
_deflate
_deflateEnd
_deflateCopy

(Выдрано с ПДБшки на 10.4 Аегис)
Аватара пользователя
Jerry
Профессионал
Сообщения: 1047
Зарегистрирован: Сб ноя 04, 2006 12:26 pm
Контактная информация:

Re: Проект ropp.dll под линукс.

Сообщение Jerry »

k0ka писал(а): <k0ka> ещё мы замечаем, что func6 вызывает те же самые первые две функции и третью функцию - другую, но также с 3 параметрами
<k0ka> можно предположить, что они использовали для func5 - Safer_Encrypt_Block, а для func6 - Safer_Decrypt_Block. Конечно, они могли схитрить и использовать наоборот, но давайте не будем переоценивать их интеллект =)

<k0ka> кстати, посмотрев вверх на байт 068AAD6h повнимательнее, можно заметить, что он инициализируется не нулём, а еденицей
<k0ka> вот та самая строчка: d068AAD6h db 1
<k0ka> то есть, вначале этот JZ точно не срабатывает и программа идёт своим чередом
<k0ka> но давайте посмотрим, куда же прыгнет программа, если AL вдруг станет равным нулю? А прыгает он немного ниже (строчка @Ragexe_e_004206B4:), проскакивая при этом вызов первых двух функций
<k0ka> при этом предыдущая команда до @Ragexe_e_004206B4: - MOV BYTE PTR [d068AAD6h],0 - устанавливает этот байт в ноль. То есть, блок от "JZ @Ragexe_e_004206B4" до "@Ragexe_e_004206B4:" будет пройден только один раз
<k0ka> Эврика! так это просто инициализация той функции для хэширования. Она вызывается при первом запуске func5 и больше не запускается
Эээ боян. По такому шаблону построена половина уже известных функций, можно было и не распинаться так долго по этому поводу :) Предлагаю изучить call16_funcs.c.
Последний раз редактировалось Jerry Чт фев 08, 2007 9:33 am, всего редактировалось 1 раз.
Аватара пользователя
Jerry
Профессионал
Сообщения: 1047
Зарегистрирован: Сб ноя 04, 2006 12:26 pm
Контактная информация:

Сообщение Jerry »

зы вапрос афтару - как проверялась корректность полученной функции?
Аватара пользователя
kLabMouse
Профессионал
Сообщения: 4776
Зарегистрирован: Вс ноя 05, 2006 4:32 pm

Сообщение kLabMouse »

Jerry
Думаю что тупо компильнулось. Встроеного тестера у нас пока нед.
k0ka
Новичок
Сообщения: 7
Зарегистрирован: Вс фев 04, 2007 4:34 pm
Контактная информация:

Сообщение k0ka »

Jerry писал(а):зы вапрос афтару - как проверялась корректность полученной функции?
ropp/src/test/howto.txt
Аватара пользователя
Jerry
Профессионал
Сообщения: 1047
Зарегистрирован: Сб ноя 04, 2006 12:26 pm
Контактная информация:

Сообщение Jerry »

ты гляди, шарит :)
Исходники то дашь, ы ?
k0ka
Новичок
Сообщения: 7
Зарегистрирован: Вс фев 04, 2007 4:34 pm
Контактная информация:

Сообщение k0ka »

Jerry, так я в лекции написал весь код =)

Код: Выделить всё

#include "safer.h"

static unsigned char func5configured = 0;
static safer_key_t key5 = {0}; 

dword func5( dword key ) 
{
   unsigned char s_key[8] = { 0x9C, 0x56, 0xD1, 0x12, 0x23, 0xC0, 0xB4, 0x37 };
   dword input[2] = {0};
   dword output[2] = {0};

   if (!func5configured)
   {
      Safer_Init_Module();
      Safer_Expand_Userkey( s_key, s_key, 8, 0, key5 );
      func5configured = 1;
   }

   input[0] = key;
   Safer_Encrypt_Block( input, key5, output ); 
   return output[0];
}
солюшен под msvs2005, в котором это всё бегает и тестируется позже могу выложить.
Аватара пользователя
Jerry
Профессионал
Сообщения: 1047
Зарегистрирован: Сб ноя 04, 2006 12:26 pm
Контактная информация:

Сообщение Jerry »

да там многабукф ппц, ты в след раз столько не пиши. :) Код и ссылку на исходник достаточно

зы а шестую чего не асилил ?
Аватара пользователя
Jerry
Профессионал
Сообщения: 1047
Зарегистрирован: Сб ноя 04, 2006 12:26 pm
Контактная информация:

Сообщение Jerry »

закамител пять и шэсть!
Аватара пользователя
kLabMouse
Профессионал
Сообщения: 4776
Зарегистрирован: Вс ноя 05, 2006 4:32 pm

Сообщение kLabMouse »

Jerry
:) Уря. Ещё бы всё остальное.
k0ka
Новичок
Сообщения: 7
Зарегистрирован: Вс фев 04, 2007 4:34 pm
Контактная информация:

Сообщение k0ka »

Jerry, 6ую я осилил - там же внизу написано, что это домашнее задание =).
Также я осилил 3ью и 4ую, но не писал это онлайн =)
Аватара пользователя
kLabMouse
Профессионал
Сообщения: 4776
Зарегистрирован: Вс ноя 05, 2006 4:32 pm

Сообщение kLabMouse »

k0ka
3я уже давно зделана. А вот к 4ой руки не дошли.
Аватара пользователя
Jerry
Профессионал
Сообщения: 1047
Зарегистрирован: Сб ноя 04, 2006 12:26 pm
Контактная информация:

Сообщение Jerry »

k0ka пеши ищо!
Ответить