Метод шифрования пароля ICQ в DAT-файле

Author: Feathery (icq: 755883)

Среди множества способов уволочь чужой UIN (Unique Icq Number) не последнее место занимает банальная кража DAT-файла. В этом, конечно, есть свои преимущества: можно сразу вместе с паролем поиметь Contact List жертвы да и всю History заодно. Однако, наверняка, не раз, получив доступ к диску какого-нибудь несчастного диалапщика и открыв каталог с аськой, ты обламывался многомегабайтным размером DATа, теряя надежду выкачать этого слона сквозь неустойчивый диалап и ругая про себя болтливого <клиента>. Обидно выкачивать мегабайты мусора, чтоб потом вытащить из них восемь байт, которые нас интересуют.

Итак, господа троянотворцы, эта статья по вашу душу, сегодня мы пишем модуль нашей лошадки, вытаскивающий асечный пароль и Contact List. Согласно исходным документам, аськи версии до 99b вообще пароль не шифровали, а хранили его в DAT- файле в открытом виде, а искать его надо было в строчке, которая начиналась с "iUserSound". Я сам старой версией аськи никогда не пользовался, а проверять эти факты мне не охота. Думаю, это и не к чему, так как любимый наш АОЛ уже почти не поддерживает старый протокол, на котором работала Ася-98:

Да. Говорим про файлы, а где они лежат, не сказали.
Версия аськи Каталог с DAT-файлами
До 99a \Program Files\ICQ\DB\
99a \Program Files\ICQ\NewDB\
99b \Program Files\ICQ\DB99b\
2000b \Program Files\ICQ\2000b\
2001a \Program Files\ICQ\2001a\

Для 2000a не знаю, вероятнее всего, аналогично, просто не работал с ней никогда, а описаний не нашёл

Теперь, что касается младших Асиных сестрёнок, начиная с 99b. Просто так, невооружённым глазом пароля там не видно, так что придётся его дешифровать. Но, сначала теория, а именно - как точно найти то место в DAT-файле, где лежит пароль.

Придётся поработать ручками, так что нам понадобится Hex-редактор. Наверняка у тебя есть своя любимая программа такого рода, ну а я возьму то, к чему привык - HexWorkshop От BreakPoint Software ( http://www.bpsoft.com/), старенькую проверенную версию 2.54 от далёкого 1997 года.

Мирабилис, надо сказать, существенно облегчил нам задачу, воспользовавшись симметричным алгоритмом шифрования. Это значит, что для того, чтобы расшифровать пароль нам нужно проделать в точности те же действия, что и для того, что его зашифровать. В нескольких словах, алгоритм таков: берём пароль и накладываем на него побитным XOR'ом некоторую строчку. Эта строчка зависит от UIN, в чьём файле лежит пароль и значения непонятного параметра CryptIV, которое также хранится в DAT-файле. Ясно, что, повторно накладывая ту же строку, мы придём к исходному паролю, то есть расшифруем его. Забегая немного вперёд, могу сказать, что основная трудность дешифрования заключается именно в генерации накладываемой строки.



Обратный порядок хранения слов.

В памяти IBM PC-совместимых машин каждое 16-битовое слово (WORD) хранится в двух смежных 8-мибитовых байтах. Менее значащий байт слова хранится в ячейке памяти с младшим адресом, более значащий - в ячейке памяти со старшим адресом. Скорее всего, хранение слова таким образом противоречит твоим представлениям. Из-за хранения "задом наперёд" способ носит название "обратный порядок хранения".
В памяти. Адреса растут вправо. Значения
60 F2 Слово равно F260h
5E 50 D1 7C Двойное слово равно 7CD1505Eh

Аналогичная ситуация и с 32-хбитовыми двойными словами (DWORD). Путаница возникает из-за того, как мы привыкли записывать данные. Например, мы записываем значение 16-битового слова обычно следующим образом ABCD. Порядок значимости цифр такой же, как и для 10-тичных чисел: старшая по значимости цифра пишется первой. Однако, в памяти слово хранится, начиная с ячейки с младшим адресом. Из-за этого в памяти число будет выглядеть как CDAB, с переставленными старшим и младшим байтами.

После неё идёт нулевой байт и символ . Пропускаем эти два байта и смотрим на следующие четыре. В моём случае это 10 00 00 00. Это есть ничто иное, как наше значение CryptIV. Внутри самой аськи оно имеет тип двойного слова (DWORD) и в DAT-файле хранится в точности в том же виде, как и в памяти. Таким образом, более привычная его запись 00 00 00 10 в 16-ричной системе. И равно это число в нашем случае десятичному 16.

Теперь немножко пройдём вперёд по содержимому DAT-файла. Очень скоро, миновав некоторые служебные поля (в частности, кстати, дополнительное мыло, прописанное в аськином инфо), мы наткнёмся на строчку . Пропустим четыре байта (в моём случае это были 00 6B 11 00) и увидим строчку (чаще всего длиной 16), состоящую из цифр и букв от a до f. Это и есть зашифрованный пароль, уже заботливо переведённый аськой в 16-ричную систему. Вот как он выглядит у меня:

00 e8 6d 7c 68 34 c4 7f

Последнее, что нам нужно, чтоб приступить к дешифрованию - наш UIN, то есть имя DAT-файла. Это 891636. Вот и всё. Теперь начинается самое сложное. Нам нужно сгенерировать из UIN и CryptIV строчку, которую мы будем накладывать на зашифрованый пароль. Назовём её XORKey. Отсюда можно взять исходный текст модуля программы на Паскале/Дельфи, который генерирует XORKey и заодно накладывает его на зашифрованный пароль.

Из модуля экспортируется только одна процедура:

XORPass(UIN, CryptIV:longint; var Pass: array of byte);

Входные параметры: UIN - исходный UIN типа longint. CryptIV - зачение параметра CryptIV типа longint. Pass - зашифрованный пароль побайтно, начиная с младшего адреса. Тип - открытый массив байт, нижний индекс = 0, верхний, вообще говоря может быть любой больше или равный количеству байт в зашифрованном пароле минус один, но делать его больше 15 смысла не имеет. Параметр передаётся по ссылке, так как в процедуре он изменяется.

Пример вызова процедуры для нашего случая:

Var P: array of byte;
Begin
// Наш зашифрованный пароль 00 e8 6d 7c 68 34 c4 7f
// имеет длину восемь байт, поэтому SetLength(P, 8);
//Заносим байты зашифрованного пароля, начиная с младшего адреса

P[0]:=$00;
P[1]:=$e8;
P[2]:=$6d;
P[3]:=$7c;
P[4]:=$68;
P[5]:=$34;
P[6]:=$c4;
P[0]:=$7f;
//Сейчас P равно 0, 232, 109, 124, 104, 52, 196, 127
XORPass(891636, 16, P);
// Теперь ключ наложен и P равно 6, 0, 88, 97, 107, 101, 112, 0

Это уже почти наш расшифрованный пароль. Первое число - длина пароля, учитывая последний нулевой байт, который знаменует собой конец строки. Сама аська писалась на С, поэтому и формат строк соответствующий (так называемые Zero-Terminated строки). Второе - просто разделитель - нулевой байт. И, наконец, шесть оставшихся байт - открытый пароль и нулевой байт (конец строки). Осталось перевести эти числа в ASCII-символы.

#88 = "X", #97 = "a", #107 = "k", #101 = "e", #112 = "r". Наш пароль . Всё.

Остаётся дать ещё некоторые комментарии. Во-первых, в DAT-файле может встретиться несколько таких пар CryptIV - Password, которые, вообще говоря, могут давать разные пароли. Скорее всего, более поздний пароль находится ближе к хвосту файла, однако это не факт, и придётся отлавливать все такие пары, чтоб найти правильный пароль (если он вообще есть, так как можно же и не сохранять его в DAT-файле). Зачастую находится две-три пары, дающие один и тот же пароль.

Во-вторых, не известно точно с каким смещением после CryptIV нужно искать строку Password. Так как это смещение зависит, как мы увидели от длины прописанной почты (а возможно, и их количества). Я не могу дать точных рекомендаций, как лучше искать пары. Сам я в своей программе пошёл наиболее простым путём. Я ищу сначала CryptIV, если он есть, пытаюсь в следующих за ним 512 байтах найти подстроку Password. Надо сказать, это не самая удачная реализация, и бывают случаи, когда программа не находит пароль, хотя он есть.

В третьих, возможно, стоит искать не строку , а <99BCryptIV>, а то и вообще байты 39 39 42 43 72 79 70 74 49 56 00 68. Это <99BCryptIV> с последующими нулевым символом и буквой . У меня реализован последний вариант. Теоретически, это должно отсечь некоторые ложные срабатывания и слегка уменьшить время поиска.

В начале статьи я обещал, что мы будем знать ещё и Contact List. Раз ты дочитал до этого места, теперь будет совсем просто. На самом деле, мы получим даже больше, чем список контактов. У нас будут почти все UINы, которых клиент хоть раз добавлял к себе в список, просившие его авторизации или от которых пришло оповещение о добавлении (You Were Added). <Почти> - потому, что я этого точно не проверял, но думаю, что это так. И, разумеется, это всё может быть справедливо, только если не установлена опция в настройках аськи.

Формат хранения чужих уинов в DAT-файле очень прост. Это 9-тибайтовые поля следующего формата.
55h 49h 4eh 00h 69h Байтa Байтb Байтc Байтd

Как описывалось выше, уин вычисляется следующим образом:

UIN=( БайтA + БайтB * 256 + БайтC * 65536 + БайтD * 16777216 )

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

Кроме того, зная этот формат, можно легко подделать свою или чужую хистори. Для этого достаточно лишь заменить один уин на другой. Можно устроить диалог с самим собой, запустив две аськи одновременно, а затем заменить у себя в DAT-файле свой второй уин, например, на приятельский. ;) Вот пример: допустим, мы хотим заменить уин 123456 на 654321.

Переводим номера в шестнадцатеричный формат:

123456[10] =1E240[16]

654321[10]= 9FBF1[16]

Так как уины хранятся в формате DWORD (4 байта), то дополняем слева нулями чтоб получить восьмизначное число: 0001E240 и 0009FBF1.

Разбиваем на пары: 00 01 E2 40 и 00 09 FB F1. В соответствии с обратным порядком хранения слов, переставляем байты: 40 E2 01 00 и F1 FB 09 00.

Теперь осталось найти все строки

55 49 4E 00 69 40 E2 01 00

и заменить их на

55 49 4E 00 69 F1 FB 09 00.

А можно сделать и вот так

Я сам проверял это на билдах 3281 (2000) и 3659 (2001). Всем спасибо, все свободны ;)

Благодарности и ссылки на первоисточники.

Самое большое спасибо - мистеру << X-PL0Si0N >> с сайта http://8th-wonder.org/ за ответы на мои вопросы и огромную помощь в поиске материала.

ICQ Security Tutorial, который положил начал моим изысканиям, я нашёл здесь http://blacksun.box.sk/. Мистер R a v e N, автор сего произведения, в свою очередь, ссылается на http://www.wangproducts.co.uk/. Основная часть алгоритма была описана мистером covertD.