Собственный эвристик на коленке [Начало]
Каждый раз, проходя по опубликованным (в различных аналитических отчетах антивирусных лабораторий) ссылкам на репорты VirusTotal обнаруживаю для себя, что там прибавляется по нескольку антивирусов с периодичностью в месяц-два.
"Ну и дела" подумал я в очередной раз и решил собрать применяемые мной методы при ресерче малварных и криптованных семплов.
Возможно название для статьи слишком громкое, но потихоньку расширяя её методами автоматической аналитики по различным расширенным признакам PE формата и другим второстепенным признакам мы сможем добиться некого эффекта. Не будем питать иллюзий, что мы делаем очередной (недо)антивирус, а просто определимся целью определять факт того, что перед нами закриптованный семпл.
В этой статье я не буду отсылать вас к википедии при каждом встречающимся здесь определении, таком как: энтропия, частотная характеристика n-gramm, и прочие, т.к. предполагается, что читающий обладает некими знаниями, достаточными для понимая изложенного в статье. В противном случае бегом в википедию и вычитываем значения незнакомых для вас слов и определений.
Для начала давайте окунемся в текущие реалии на этом поприще.
Крипторы скрывают, антивирусы стараются вовремя (
) обнаружить закриптованные семплы, до того, как они будут распространены в миру (англ. in the wild). Борьба меча и щита с вирусов плавно перешла в борьбу крипторов и антивирусов.
Не лишним будет отметить, что сегодняшняя индустрия крипта исполняемых файлов очень широка и разнообразна. До сих пор можно встретить крипторы на VisualBasic 6, но в то же время уже редко встречаются криптованные семплы на ассемблере, скомпилированные на MASM или FASM. И всё таки основная часть проанализированных мной криптованных семплов выпадает на компиляторы C++. Вероятно этот язык и код, генерируемый компилятором наиболее похож на код обычных безвредных программ.
Для антивирусов это означает то, что они с бОльшей вероятностью не смогут установить сигнатуре по маске генерируемого кода, как в случае с крипторами на ассемблере, в которых так или иначе можно выделить некие комбинации (шаблоны кода), по которым рано или поздно начинает определяться всё семейство. Некоторое время назад антивирусы поняли, что на одних сигнатурных (по вайлд-карте, по маске, шаблонные сигнатуры или как бы вы там их не называли) анализаторах им не охватить нужно процента обнаружения и начали вводиться повсеместно всякие интересные технологии, такие как эмуляция кода и среды, эвристика, хипсы (проактивные системы) и т.д.
:: Интересный факт:
Как ни странно, но только недавно некоторые антивирусы поняли, что можно использовать старые добрые сигнатурные движки, но уже на новый лад. Теперь сканирование происходит в памяти, после того, как основное тело вредоноса расшифровывается в памяти и находится там в своем оригинальном первоначальном состоянии.
Каждая из технологий имеет весомый фактор в определении доминирующей части криптованных семплов, но на каждую технологию крипторы используют технологии в противовес. Например против сигнатурного детекта используется полиморфизм, морфинг и мусорная кодогенерация. Против эвристика используются определенные связки кода, размазывание энтропии, фэйковый импорт и другие техники, не позволяющие эвристическому анализатору набить баллов для однозначного определения того факта, что данный файл криптованный, шифрованный или упакованный.
Против проактивных систем используются инжекты в доверенные процессы и другие техники.
Ну думаю достаточно для вступительной речи, пожалуй-с перейдем к действам.
Первый делом будет рассматривать наиважнейший для антивирусов на сегодняшний день метод обнаружения: детект эвристиком.
И так, допустим, что перед нами стоит задача: с максимальной достоверностью определить, что перед нами криптованный файл.
Есть такое понятие как "Zero Value тест", так называемый тест на процентное соотношение кол-ва нулевых байт к остальным 224 байтам.
Перед нами скриншот Exe-Info pe, на котором мы можем видеть диаграмму и процентное соотношение байт (выделено красным)
Собственно теор. часть я определил выше, настало время собственной реализации данной тенхик. (В принципе мне одинаково близки как паскаль, так и си, но конкретно в данном случае решил писать на паскале.) Приступим-с.
На вход в функцию подаем считанный буфер файлы и его размер.
На выходе значение в double.
Тут всё очень просто и думаю даже нет смысла комментить строки, т.к. выше суть уже описал.
И пример использования:
Всё достаточно прозрачно: читаем файл, узнаем его размер, высчитываем с помощью нашей функции соотношение нулевых байт к остальным байтам и сравниваем с эталонной таблицей, как результат выводим диагноз: Strong packed, Packed, Crypted, Not Packed. Антивирусы, при положительном результате поставили бы на такой файл +1 балл подозрительности.
Пульнем тот же файлик, который кормили Exe-Info pe, в нашу утилитку, видим:
Еще один очень важный момент при сканировании файла эвристиком, это проверка энтропии (степени эффективности хранения информации). Проверяется значение энтропии как всего файла, так и каждой секции отдельно.
Данная функция рассчитывает значение энтропии для нашего буфера. На скриншоте выше показан результат работы данной функции.
Пример использования:
Ну что-ж, для начала пищи для размышления думаю вам хватит. В сл. частях разберем обнаружение по частотным характеристикам n-gramms, а также обнаружение по энтропии каждой отдельной секции.
Если кому интересно потыкать, могу пульнуть готовый сурс и скомпилированный бинарь.
Заметки на полях от TrueMind, специально для xss.pro/ и panteon.nl ©.
Спасибо за внимание!
Каждый раз, проходя по опубликованным (в различных аналитических отчетах антивирусных лабораторий) ссылкам на репорты VirusTotal обнаруживаю для себя, что там прибавляется по нескольку антивирусов с периодичностью в месяц-два.
"Ну и дела" подумал я в очередной раз и решил собрать применяемые мной методы при ресерче малварных и криптованных семплов.
Возможно название для статьи слишком громкое, но потихоньку расширяя её методами автоматической аналитики по различным расширенным признакам PE формата и другим второстепенным признакам мы сможем добиться некого эффекта. Не будем питать иллюзий, что мы делаем очередной (недо)антивирус, а просто определимся целью определять факт того, что перед нами закриптованный семпл.
В этой статье я не буду отсылать вас к википедии при каждом встречающимся здесь определении, таком как: энтропия, частотная характеристика n-gramm, и прочие, т.к. предполагается, что читающий обладает некими знаниями, достаточными для понимая изложенного в статье. В противном случае бегом в википедию и вычитываем значения незнакомых для вас слов и определений.
Для начала давайте окунемся в текущие реалии на этом поприще.
Крипторы скрывают, антивирусы стараются вовремя (
Не лишним будет отметить, что сегодняшняя индустрия крипта исполняемых файлов очень широка и разнообразна. До сих пор можно встретить крипторы на VisualBasic 6, но в то же время уже редко встречаются криптованные семплы на ассемблере, скомпилированные на MASM или FASM. И всё таки основная часть проанализированных мной криптованных семплов выпадает на компиляторы C++. Вероятно этот язык и код, генерируемый компилятором наиболее похож на код обычных безвредных программ.
Для антивирусов это означает то, что они с бОльшей вероятностью не смогут установить сигнатуре по маске генерируемого кода, как в случае с крипторами на ассемблере, в которых так или иначе можно выделить некие комбинации (шаблоны кода), по которым рано или поздно начинает определяться всё семейство. Некоторое время назад антивирусы поняли, что на одних сигнатурных (по вайлд-карте, по маске, шаблонные сигнатуры или как бы вы там их не называли) анализаторах им не охватить нужно процента обнаружения и начали вводиться повсеместно всякие интересные технологии, такие как эмуляция кода и среды, эвристика, хипсы (проактивные системы) и т.д.
:: Интересный факт:
Как ни странно, но только недавно некоторые антивирусы поняли, что можно использовать старые добрые сигнатурные движки, но уже на новый лад. Теперь сканирование происходит в памяти, после того, как основное тело вредоноса расшифровывается в памяти и находится там в своем оригинальном первоначальном состоянии.
Каждая из технологий имеет весомый фактор в определении доминирующей части криптованных семплов, но на каждую технологию крипторы используют технологии в противовес. Например против сигнатурного детекта используется полиморфизм, морфинг и мусорная кодогенерация. Против эвристика используются определенные связки кода, размазывание энтропии, фэйковый импорт и другие техники, не позволяющие эвристическому анализатору набить баллов для однозначного определения того факта, что данный файл криптованный, шифрованный или упакованный.
Против проактивных систем используются инжекты в доверенные процессы и другие техники.
Ну думаю достаточно для вступительной речи, пожалуй-с перейдем к действам.
Первый делом будет рассматривать наиважнейший для антивирусов на сегодняшний день метод обнаружения: детект эвристиком.
И так, допустим, что перед нами стоит задача: с максимальной достоверностью определить, что перед нами криптованный файл.
Есть такое понятие как "Zero Value тест", так называемый тест на процентное соотношение кол-ва нулевых байт к остальным 224 байтам.
Перед нами скриншот Exe-Info pe, на котором мы можем видеть диаграмму и процентное соотношение байт (выделено красным)
Собственно теор. часть я определил выше, настало время собственной реализации данной тенхик. (В принципе мне одинаково близки как паскаль, так и си, но конкретно в данном случае решил писать на паскале.) Приступим-с.
На вход в функцию подаем считанный буфер файлы и его размер.
На выходе значение в double.
Код:
function CalcZeroFreq(pBuffer:string; buf_size:integer):double;
var
zero_count:integer;
i:integer;
begin
zero_count:=0;
for i:=0 to buf_size do begin
if pBuffer[i]=#0 then inc(zero_count);
end;
result := zero_count/buf_size;
end;
И пример использования:
Код:
procedure TForm1.Button1Click(Sender: TObject);
var
FileHandle:Thandle;
Size:cardinal;
Buffer:string;
BytesRead:dword;
iNullPercentage:double;
iEntroTest:double;
begin
label1.caption := '';
label2.caption := '';
if ((edit1.Text <> '....') and (edit1.Text <> '')) then begin
FileHandle := CreateFile(PChar(od.filename), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
Size := GetFileSize(FileHandle, nil);
SetLength(Buffer, Size);
ReadFile(FileHandle, Buffer[1], Size, BytesRead,nil);
CloseHandle(FileHandle);
//////////////////////////
// zero value test //
iNullPercentage := CalcZeroFreq(Buffer, size);
if iNullPercentage <= 0.0250 then
label1.caption := '[*] Zero Value Test: Strong packed';
if ((iNullPercentage > 0.0250) and (iNullPercentage <= 0.055)) then
label1.caption := '[*] Zero Value Test: Packed';
if ((iNullPercentage > 0.055) and (iNullPercentage <= 0.150)) then
label1.caption := '[*] Zero Value Test: Crypted';
if ((iNullPercentage > 0.150) and (iNullPercentage <= 0.255)) then
label1.caption := '[*] Zero Value Test: Not Packed';
if (iNullPercentage > 0.255) then
label1.caption := '[*] Zero Value Test: Very Not Packed';
Пульнем тот же файлик, который кормили Exe-Info pe, в нашу утилитку, видим:
Еще один очень важный момент при сканировании файла эвристиком, это проверка энтропии (степени эффективности хранения информации). Проверяется значение энтропии как всего файла, так и каждой секции отдельно.
Код:
function CalcEntropyForBuffer(Buffer:Pointer; BufferSize:DWORD):Double;
const
DbLog: Double = 1.4426950408889634073599246810023;
var
Entropy: Double;
Entries: array[0..255] of DWORD;
i: DWORD;
Temp: Double;
begin
Entropy := 0.00;
ZeroMemory(@Entries, SizeOf(Entries));
for i := 0 to (BufferSize - 1) do
Inc(Entries[PByte(DWORD(Buffer) + i)^]);
for i := 0 to 255 do
begin
Temp := Entries[i] / BufferSize;
if (Temp > 0) then
Entropy := Entropy + Temp * (Ln(Temp) * DbLog);
end;
Result := Entropy;
end;
Пример использования:
Код:
//////////////////////////
// entropy test //
iEntroTest := CalcEntropyForBuffer(@Buffer[1], size);
if ((iEntroTest > 6)) then
label2.caption := '[*] Entropy Test: Packed : '+FloatToStr(iEntroTest)
else
label2.caption := '[*] Entropy Test: Not Packed : '+FloatToStr(iEntroTest);
end;
Ну что-ж, для начала пищи для размышления думаю вам хватит. В сл. частях разберем обнаружение по частотным характеристикам n-gramms, а также обнаружение по энтропии каждой отдельной секции.
Если кому интересно потыкать, могу пульнуть готовый сурс и скомпилированный бинарь.
Заметки на полях от TrueMind, специально для xss.pro/ и panteon.nl ©.
Спасибо за внимание!