В этой статье мы раз­берем прак­тичес­кое при­мене­ние потоко­вого шиф­ра Rabbit на при­мере реаль­ного при­ложе­ния: опоз­наем алго­ритм по коду, прос­ледим поток чте­ние → обра­бот­ка → запись, най­дем про­цеду­ру ини­циали­зации, а потом напишем собс­твен­ный модуль для шиф­рования и дешиф­ровки фай­лов.

Я уже неод­нократ­но писал про из­вес­тные и не очень крип­тоал­горит­мы. На этот раз хочу обра­тить вни­мание на потоко­вый шифр Rabbit. Этот шифр был соз­дан в качес­тве более шус­трой аль­тер­нативы клас­сичес­ким крип­торам типа AES, его даже отправ­ляли на кон­курс eStream, но пока без­резуль­тат­но. Впро­чем, про то, как и кем он был соз­дан и почему счи­тает­ся быс­трым, а так­же всю теорию и лирику, каса­ющуюся это­го крип­тоал­горит­ма, ты и сам на досуге можешь про­читать в Википе­дии. А я, как обыч­но, раз­беру прак­тичес­кие аспекты его при­мене­ния и ревер­са на при­мере кон­крет­ного при­ложе­ния.

Итак, на этот раз пос­танов­ка задачи сле­дующая. Име­ется некое узкоспе­циали­зиро­ван­ное при­ложе­ние, наз­вание которо­го мы по понят­ным при­чинам называть не будем. Одна из его спе­цифи­чес­ких фун­кций — кон­верти­рова­ние дан­ных в ред­кий экзо­тичес­кий фор­мат, тре­бует­ся его ревер­сировать и по воз­можнос­ти написать собс­твен­ный кон­вертер по получен­ным дан­ным. По счастью, при­ложе­ние ничем не защище­но, написа­но на C с лег­ким налетом Qt, а его код открыт для иссле­дова­ния.

Фай­лы дан­ных, которые нам пред­сто­ит иссле­довать, очень объ­емные и совер­шенно нес­жима­емые, энтро­пия прос­то заш­калива­ет, и, на пер­вый взгляд, запол­нены они исклю­читель­но белым шумом. Поп­робу­ем оце­нить динами­ку блоч­ной записи в них при помощи прог­раммы Process Monitor. Ста­вим филь­тр на фай­ловые опе­рации и имя нашего при­ложе­ния, затем вклю­чаем про­цесс экспор­та. В логе Procmon вид­но, что файл пишет­ся пос­ледова­тель­ными бло­ками раз­мером по 0x40000 байт, при­чем перед каж­дой записью блок при­мер­но такой же дли­ны счи­тыва­ется из вход­ного фай­ла.

То есть никакой ком­прес­сии фор­мат не исполь­зует, исклю­читель­но шиф­рование. Поп­робу­ем прос­ледить, что имен­но про­исхо­дит с бло­ком дан­ных меж­ду чте­нием из исходно­го фай­ла и записью в иссле­дуемый. Для это­го мы сно­ва дей­ству­ем по схе­ме, которую я уже неод­нократ­но опи­сывал: откры­ваем прог­рамму в нашем любимом отладчи­ке x64dbg и непос­редс­твен­но перед опе­раци­ей сох­ранения ста­вим точ­ку оста­нова на фун­кцию kernel32.ReadFile. На вся­кий слу­чай пос­тавив усло­вие для оста­нова — филь­тр по дли­не, рав­ной 4096=0x1000, пос­коль­ку мы обра­тили вни­мание, что бло­ки такого раз­мера час­тень­ко чита­ются из вход­ного фай­ла дан­ных. Даль­нейшую пос­ледова­тель­ность дей­ствий, я думаю, ты уже выучил наизусть по моим пре­дыду­щим стать­ям — как толь­ко прог­рамма оста­нав­лива­ется для чте­ния оче­ред­ного бло­ка дан­ных, мы смот­рим стек вызовов и опре­деля­ем мес­то вызова текуще­го fread из основной прог­раммы. В IDA это мес­то выг­лядит так.

Место вызова fread
Мес­то вызова fread

Код похож имен­но на то, что мы иска­ли, — цикл чте­ния/сох­ранения дан­ных бло­ками 0x40000 байт. Поп­робу­ем прос­ледить, какие манипу­ляции про­исхо­дят с бло­ком дан­ных меж­ду fread и fwrite.

Манипуляции с блоком данных
Ма­нипу­ляции с бло­ком дан­ных

Лег­ко видеть, что счи­тан­ные в буфер v21 дан­ные из него же и сох­раня­ются, одна­ко побывав перед этим в про­цеду­ре sub_1402CBAA0. Внут­ри нее нас ожи­дает ужас­ная мешани­на голово­лом­ного кода со мно­жес­твом битовых опе­раций и «вол­шебных» кон­стант.

Силь­но похоже на крип­тоал­горитм, при­чем не шиб­ко популяр­ный. Нав­скид­ку загуг­лив пер­вую же встре­тив­шуюся кон­стан­ту из него — 749914925=0x2CB2CB2D, с огор­чени­ем видим, что Гугл с его искусс­твен­ным интеллек­том ничего вра­зуми­тель­ного под­ска­зать не может. По счастью, у нас есть более дей­ствен­ные инс­тру­мен­ты. К при­меру, заг­рузив нашу иссле­дуемую прог­рамму в Krypto analyzer, мы убеж­даем­ся в том, что име­ем дело имен­но с Rabbit.

Поп­робу­ем теперь разоб­рать­ся в том, каким боком этот алго­ритм прик­ручен к решению нашей задачи и как реали­зовать его фун­кци­они­рова­ние в собс­твен­ной прог­рамме. Для это­го нам все‑таки при­дет­ся слег­ка ныр­нуть в теорию. Бег­ло про­чита­ем опи­сание алго­рит­ма, статью из Википе­дии и для боль­шей наг­ляднос­ти — спе­цифи­кацию от авто­ров Rabbit. Что­бы тебе было про­ще разоб­рать­ся в этой высоко­науч­ной писани­не, поп­робую на паль­цах объ­яснить суть того, что мы ищем.

Продолжение доступно только участникам

Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте

Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее

Вариант 2. Открой один материал

Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.


  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    1 Комментарий
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии