Pull to refresh

Rich сигнатура, или что скрывает MS компилятор

Reading time 5 min
Views 1.6K
Вступление
Наверное многие программисты, да и просто любопытные люди сталкивались с тем что в некоторых exe/dll/sys и тому подобных файлах присутствуют непонятные данные между MZ и PE заголовком, которые заканчивались словом Rich.

Многие не обращали на них внимания, некоторые же по ним могли сказать что данный файл был создан с использованием компилятора от Microsoft. Также были люди кто считали что там спрятаны какие-то данные нужные для работы программы. И это лишь только одна сторона данного факта.

Другая сторона — эта то, что многие знают о том, что Microsoft специальным образом помечает исполняемые файлы, созданные с помощью их компиляторов (С\С++\MASM) и что якобы это сделано для того, чтобы вычислить создателей вредоносных программ.
Многие полагают что при линковке вписывается информация о компьютере или пользователе.

Объединяя оба этих факта можно с уверенностью сказать что Rich данные — это возможно и есть тот идентификатор по которому можно определить человека / компьютер где была создана вредоносная программа. Справедливость данного факта и будет проверяться.

Rich в подробностях
Из основных особенностей этих данных которые могли бы быть найдены при визуальном осмотре можно выделить следующие:
  • Они всегда идут после MZ заголовка, но перед PE заголовком.
  • Чаще всего их положение относительно начала файла = 80h = 128.
  • Программа скомпилированная на одном и том же компьютере имеет одинаковые Rich данные.

Пример RICH данных (отмечены розовым):
image

т.е. структура её примерно такая:
XXXXXXXX - YYYYYYYY - YYYYYYYY - YYYYYYYY
XXXXXXXX - XXXXXXXX - XXXXXXXX - XXXXXXXX
XXXXXXXX - XXXXXXXX - XXXXXXXX - XXXXXXXX
[Rich сигнатура] - YYYYYYYY

где YYYYYYYY — Повторяющиеся 32-х битные значения
XXXXXXXX — Постоянно разные 32-х битные значения
[Rich сигнатура] — 4 байта образующие слово Rich

Что скрывает Rich?
Было потрачено много времени на то, чтобы узнать что хотя бы какую нибудь информацию и том, что за данные там хранятся и в итоге был найден зарубежный сайт, где была расположена статья (http://ntcore.com/files/richsign.htm) человека под именем Daniel Pistelli в которой он исследовал данную сигнатуру, а также то, как она формируется и еще очень много полезных данных.

Как было выяснено в вышеуказанной статье число, помеченное нами как YYYYYYYY — это есть ключ шифрования / дешифрования. Если говорить более подробно об этом, то это всего лишь маска для XOR операции (которая как раз и представляет собой шифрование)

Расшифровка:
  • Берем двойное слово после сигнатуры Rich — это наш ключ.
  • Каждое двойное слово Rich данных расшифровываем XOR`ом с использованием ключа и так до тех пор пока не дойдем до сигнатуры Rich (расшифровывать не надо).

В результате получаем что-то типа такого:
DanS-00000000 - 00000000 - 00000000
XXXXXXXX - XXXXXXXX - XXXXXXXX - XXXXXXXX
XXXXXXXX - XXXXXXXX - XXXXXXXX - XXXXXXXX
Rich-YYYYYYYY

где, XXXXXXXX — расшифрованные данные
00000000 — число XOR на само себя = 0.

Сигнатура DanS скорее всего была вписана для того, чтобы проверить что это точно Rich данные и что они не подделаны простым генератором псевдослучайных чисел.

Далее автор той статьи прогнал компилятор через IDA чтобы более детально изучить то, что записано в Rich данных. Как оказалось их формат такой:
XXXX00YY ZZZZZZZZ XXXX00YY ZZZZZZZZ
XXXX00YY ZZZZZZZZ XXXX00YY ZZZZZZZZ

где, XXXX — старшая версия
YYYY — младшая версия
ZZZZZZZZ — что-то типа версия билда.

Из этого можно смело говорить то, что Rich данные — это всего-лишь версии библиотек и компилятора, которые были использованы при создании программы.

Практическая реализация:
Всё бы то хорошо, но всегда лучше увидеть своими глазами что за версии там находятся. Да и хотелось бы автоматизировать данный процесс.
По этому напишем на Delphi небольшую функцию которая будут выводить версии библиотек зашитые в Rich данных.
// на входе имя и путь до файла
procedure PrintRichData(FileName : string);
var
Lib : DWORD; // адрес файла в памяти
Data : DWORD; // данные
Key : DWORD; // ключ шифрования
x : integer;
cnt : integer; // кол-во элементов в данных
MinVer, MajVer : WORD; // версия
Times : DWORD;// доп инфо.
Msg : string;
begin
Msg := '';
// загрузим в память подопытную прогу
Lib := LoadLibrary(PAnsiChar(FileName));
if Lib <> 0 then // если загрузили
begin
cnt := 0;
while true do // перебираем Rich данные чтобы найти конец и кол-во их
begin
// получаем текущую запись
Data := DWORD(pointer(Lib + $80 + (cnt shl 2))^);
if Data = 0 then break; // если пустое значение значит нету данных
if Data = $68636952 then break; // проверим на конец данных - сигнатура Rich
inc(cnt); // переходим на следующую запись
end;

if cnt <> 0 then // если есть Rich данные
begin
// считаем маску шифрования
Key := DWORD(pointer(Lib + $80 + ((cnt+1) shl 2))^);
x := 4; // Так как первый элемент это DanS а потом 3 повтора ключа, то начинаем сразу с 4-го элемента
while x < cnt-1 do // перебираем все элементы
begin
Data := DWORD(pointer(Lib + $80 + (x shl 2))^) xor Key; // расшифровываем
MinVer := Data and $FFFF; // младшая версия
MajVer := (Data shr 16) and $0F; // старшая
inc(x);
Times := DWORD(pointer(Lib + $80 + (x shl 2))^) xor Key; // доп. инфа.
Msg := Msg + `Ver: ` + inttostr(MajVer) + `.0.` + inttostr(MinVer) + ` Times:` + inttostr(Times) + #13#10;
inc(x); // следующий элемент
end;

MessageBox(0, PAnsiChar(Msg), `INFO`, 0);
end;

FreeLibrary(Lib);
end;
end;


В результате выполнения данной функции можно получить данные о версиях. В моём случае подопытный файлы имел следующие версии библиотек
Ver: 1.0.0 Times:44
Ver: 9.0.9210 Times:5
Ver: 0.0.9210 Times:1
Ver: 12.0.9178 Times:8
Ver: 13.0.9210 Times:1


Чем это нам грозит:
По выше описанных данных можно сказать, что никакой уж важной и тем-более конфиденциальной информации Rich данные не хранят, по этому не стоит волноваться по поводу того что они будут присутствовать в ваших программах.

Хотя на деле можно выявить следующие ключевые моменты:
  • Можно узнать какая версия компилятора использовалась.
  • Одна и та же версия компилятора на разных компьютерах, для одной и той же программы будет давать одинаковые Rich данные. Так что по этим данным нельзя на прямую доказать что данная программа создана на этом компьютере и тем более вами.
  • Маска шифрования вычисляется исходя из данных PE заголовка, по этому антивирусы могут использовать её как сигнатуру при анализе вредоносной программы
  • Удаление этой сигнатуры — может вызвать больший интерес антивируса к вашей программе.
  • Случайные значения в данных о версиях тоже могут привлечь внимания антивирусов.
  • При написании систем защиты файлов, если используются вообще полностью случайные Rich данные, то антивирусы сразу могут понять что файл был изменен т.е. провалится проверка по второй сигнатуре (DanS). Так что лучше если генерировать самому эти данные, то желательно иметь набор самых распространенных версий библиотек.


Литература:
1) Daniel Pistelli (http://ntcore.com/files/richsign.htm) — Подробное описание Rich данных, метода генерации ключа и патча компилятора с целью отключения создания Rich данных.
2) Vovane (http://www.wasm.ru/forum/viewtopic.php?id=8572) — Программка подделки и проверки Rich данных.
Tags:
Hubs:
+70
Comments 8
Comments Comments 8

Articles