В этой статье мы раз­берем прак­тичес­кое при­мене­ние потоко­вого шиф­ра 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. Что­бы тебе было про­ще разоб­рать­ся в этой высоко­науч­ной писани­не, поп­робую на паль­цах объ­яснить суть того, что мы ищем.

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

Материалы из последних выпусков становятся доступны по отдельности только через два месяца после публикации. Чтобы продолжить чтение, необходимо стать участником сообщества «Xakep.ru».

Присоединяйся к сообществу «Xakep.ru»!

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

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

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

    Подписаться

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