• XSS.stack #1 – первый литературный журнал от юзеров форума

Криптор. Методика выживания

1. Возьмет из своего файла. Зевс, Айс, Цита прекрасно находят свой оверлей в криптованном файле.
Каким интересно способом он найдет свой оверлей? Если он понятия не имеет ни о самом крипторе, ни об алгоритме шифрования. Под моми криптором, почему то не находит, что я не так делаю?
2. Нет не пробовал по причине того что ушел от детекта более простым путем без шифрования(избавления от) оверлея.
Как долго продержится ваш файл без шифрования?
3. Читайте внимательнее вопросы адресованные к вам на которые вы ответили вопросами. А ведь вопросы не просто так задаются. Если избавиться от оверлея нужно тогда да, другого пути, кроме предложенного вами нет. Если уйти от детекта, а иначе зачем его криптовать\подменять, то все решается элементарным способом без всех этих перехватов\заглушек.
Речь идет об обработке оверлея, для сохранения работоспособности программы. Я показал вполне реальный способ, который работает. Заголовок читали? Саму статью? Покажите мне хоть слово про удаление оверлея или об уходе от детекта. А с вашей стороны я вижу лишь общие слова, без единого упоминания о самом алгоритме. Или это коммерческая тайна?
 
А у меня все работает. Не буду разводить писанину. Опишу вкратце. Оверлей отрезаю. Криптую файл. Добавляю оверлей. Добавляю чуток мусора в конец оверлея. Все работает. Детектов 0. Очевидно потому что зевс и пр. писали программисты выше классом, которые знают как найти оверлей в файле независимо от того был он покриптован или нет. Расписывать это я уже не буду. Все остальное - коммерческая тайна. Чищу свое изделие раз в неделю. Пиковые нагрузки 60-70к загрузок в день. Очевидно потому не пользуюсь столь гениальной хитростью
Еще одна хитрость в том, что
мы специально оставляем место в декрипторе, которое будут детектить (чтобы легче было чистить, и чтобы ав сильно не ковырялись в файле)

Добавлено в [time]1402927795[/time]
P.S. Swizzor это то к чему стремлюсь я, 8 лет имения всех АВ во все дыры это вам не хухры-мухры ;)
 
Добавляю оверлей
Вот с этого и надо было начинать. У меня оверлея не видно, даже если он и был. И опять же возникает вопрос, а если к вам обратится человек, у которго софт не настолько продвинутый, чтобы самому найти оверлей? Как быть в этом случае? Получается мой метод более универсальный.
Еще одна хитрость в том, что
мы специально оставляем место в декрипторе, которое будут детектить (чтобы легче было чистить, и чтобы ав сильно не ковырялись в файле)
Ну личную переписку выкладывать некрасиво. И ошибки не совершает лишь тот, кто ничего не делает. От такого я уже давно отказался.
 
А точно, я уже и забыл про что писал. Извини за наезд)
Ну от такого я отказался, и так найдут как задетектить.
Но на начальном уровне, неплохо спасало.
 
Бывает ;) А вообще у тебя вполне нормальный криптор, я видел сэмпл. Вангую - скоро придется улучшать генератор мусора, чтобы проскакивать спектральные анализаторы а-ля битдеф ;) Если сбудется гугли CLET shellcode engine и SETG by Z0mbie.
 
SETG != ETG != Mistfall != xTG
Могу предположить исходя из вашей логики, ассеблер устарел, си устарел, си плюс плюс устарело, да что там говорить - даже кириллица устарела ;)
Топик стартер, мне кажется, уже вкурил, что к чему, как готовить и с чем кушать, чтобы не чистить ручками ежедневно всякую автоересь наподобие Kazy, Zusi, Symmi, Graftor, Boigy, Jaik и т.п.
А Зомба крут. Дальше него никто не пошел. По сути все то что сейчас ново, его идеи его разработки. Некоторые остались еще нереализованы.
 
его работам около 10 лет) нет смысла останавливаться на его трудах, когда есть гораздо совершеннее

https://www.dropbox.com/s/n8i0n1ac1d7xrvx/irpev10.zip
полиморфный двигатель, созданный на базе xTG v2.1.1 (мультидекрипторность; инструкции, их расположение и вызовы, регистры и т.п. - всё это меняется).
 
Копипастерская логика какая-то получается ;) xTG это улучшенная реализация идеи SETG. У меня своя реализация этой идеи. Работает уже много лет. Миром правят идеи. Вы же смотрите на конкретные реализации, рецепты. Поднимитесь на другой уровень абстракции и увидите, что по сути нового ничего не изобрели со времен Зомбы. Зомба был первым кто предугадал будущее. И даже алгоритмы детектирования которые в обиход вошли год-два назад были озвучены именно им. Я человек идей, конкретная реализация работает краткий период времени, по сравнению с идеей, которые актуальны десятилетиями.
Вот к примеру частная реализация все той же идеи http://www.cs.wm.edu/~hnw/paper/ccs10.pdf
 
Интересные заметки ТС, пиши еще.

На эксплойте с опроса видно, что ежегодно преимущество берут системы с x64. Есть смысл копать крипт под данную разрядность? Кто пробовал/крипт -ует -овал PE64? В принципе техники одни и те же..
 
Расскажу свой опыт.

Использовал более 2 лет паблик криптеры. Но всегда билд жил после крипта до 5 часов, вне зависимости был ли он в работе.

После чего решили сделать свой(около полутра лет назад)
Результат:
- Криптер полностью приват ни разу не был использованный никем кроме нас.
- Файлы остаюсь чистые по 2-3 дня и более елси не были в работе.
- Если нормальные люди его юзали то билд жил 12-24 часа уже когда его грузили.
- перекриптовка помогает в течении 1 недели. тоесть чистить сам криптер приходить не чаще чем раз в неделю.
- объемы за эти полтора года перевалили за 1 кк лоадов.

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

Всем удачного биза!!!
 
Девелоп и поддержка своего криптора безусловно крутая штука, НО нужно понимать, что написание кошерного криптора с нуля и его поддержка это:
1. серъезные временные затраты человекочасов.
2. приличные бютжетные затраты вкупе со стабильной ежемесячной ЗП кодеру(ам).
3. круглосуточная поддержка, как правило одному кодеру нереально 24 часа в сутки проводить за ПК.
4. что-то еще...
 
Базонезависимый код.

Для хорошего криптора необходима базонезависимость (далее БН), думаю никто с этим спорить не станет.
БН позволит нашему коду выполняться при загрузке с любого виртуального адреса памяти, а также позволит криптору обслуживать программы и библиотеки с любым возможным виртуальным адресом загрузки.
Для обеспечения БН необходимо убрать из кода все абсолютные адреса (это могут вызовы, переходы или обращения к секции данных или другим секциям).
Например:
call [00400000h] (ff15 00004000)
jmp [00400000h] (ff25 00004000)
mov [00410000h], ebx (891d 00004100)

Совсем обойтись без абсолютных адресов достаточно сложно, и к тому же неудобно. Однако есть два достаточно простых способа сделать код БН.
Первый способ предлагает писать БН код, учитывая дельта смещение (далее ДС), для этого вычисляется ДС = РеальныйАдресЗагрузки - НеобходимыйАдресЗагрузки.
РеальныйАдресЗагрузки это виртуальный адрес памяти, по которому был загружен наш код. Теперь ДС необходимо прибавить ко всем абсолютным адресам в коде,
самый простой способ это выделить для ДС один из регистров, допустим eax, тогда наш код приобретет вид:
call [00400000h + eax] (ff90 00004000)
jmp [00400000h + eax] (ffa0 00004000)
mov [00410000h + eax], ebx (8998 00004100)

Минусы, конечно, есть, но идеальных решений не бывает. Зато наш код будет полностью БН, то есть если скопировать кусок кода в другую область памяти, то
для корректной работы достачно пересчитать ДС.
 
Второй способ - это заставить компноновщик (он же линкер) создавать таблицу перемещений (далее ТП). Для этого достаточно задать компоновщику опцию /FIXED:NO.
Если после компоновки программы мы не трогаем код, то проблем не будет. Однако, если код подвергается модификации (мутация, перемешивание, генерация мусора и т.д.), необходимо создать новую ТП. Это не так сложно, гораздо сложнее найти в коде абсолютные адреса, для этого нужен простенький дизассемблер. Мы прогоняем наш дизассемблер по коду и находим команды, содержащие в себе непосредственные операнды или смещения (нас интересуют 4-байтные числа).

Пример команды с непосредственным операндом:
mov eax, 410000h
push 420000h


Пример команды со смещением:
mov eax, [410000h]
push [420000h]


Далее необходимо выбрать те адреса, котороые указывают на память внутри программы. Другими словами, (address > ImageBase) and (address < (ImageBase + SizeOfImage)). Следующим шагом будет создание ТП, которая состоит из одного или более блоков настойки адресов. Каждый блок содержит настройки для 4 Кб данных и начинается с заголовка IMAGE_BASE_RELOCATION, имеющего следующий вид:
[RelativeVirtualAddress][SizeOfBlock], оба поля длиною в 4 байта.
После этого заголовка следует массив 16-битовых описателей настройки. Количество таких описателей равно (SizeOfBlock - IMAGE_SIZEOF_BASE_RELOCATION) / 2. Таблица настройки заканчивается блоком, у которого заголовок IMAGE_BASE_RELOCATION заполнен нулями.
Каждый описатель настройки в четырех старших битах содержит тип настройки, а в 12 младших битах – смещение от начального RVA до настраиваемых данных.
Нас интересуют два типа настроек.
1) IMAGE_REL_BASED_ABSOLUTE - нет настройки. Используется как заполнитель для выравнивания блоков на границу двойного слова. Младшие биты должны быть нулями
2) IMAGE_REL_BASED_HIGHLOW - к 32-битовому двойному слову по указанному адресу, добавить ДС = РеальныйАдресЗагрузки - НеобходимыйАдресЗагрузки.
Почти тоже самое, что и в первом способе, только здесь адреса корректируются загрузчиком один раз при загрузке программы в память.
Целевой адрес, по которому расположен корректируемый адрес, вычисляется как: ImageBase + RVA(блока настройки) + Offset(описателя настройки).
 
Ну что же давно не писал что-то я, пришло время поговорить об особенностях крипта dll.
Главных отличий от крипта exe (на мой взгляд) 3:

1. Экспорт
2. Обязательная обработка релоков (тут конечно можно поспорить, но 95% exe не требуют обработки релоков)
3. Восстановление адреса точки входа в dll (AddressOfEntryPoint, по этому адресу находится функция инициализации DllMain)

1. Обработка экспорта.
Сначала вспомним из чего состоит каталог импорта.
Сначала идет общая информация о dll и экспортируемых функциях
public struct ExportDirectory
{
public int Characteristics;
public int TimeDateStamp;
public short MajorVersion;
public short MinorVersion;
public int Name;
public int Base;
public int NumberOfFunctions;
public int NumberOfNames;
public int AddressOfFunctions;
public int AddressOfNames;
public int AddressOfNameOrdinals;
}

Далее идут 3 массива, на которые указывают 3 последних поля. Первый массив хранит RVA функций для их вызова (то есть адрес функций при загрузке в память, за вычетом базы загрузки). Второй массив хранит RVA имен функций, ну а третий, конечно, хранит ординалы функций. Еще раз отмечу, первые 2 массива хранят RVA, последний непосредственно ординалы.

Итак возникает вопрос, что мы можем поменять в экспорте нашей dll, без ущерба для ее использования? Тут все упирается в способ подключения dll.
Если dll подключается статически, то необходимо создать почти точную копию секции экспорта. Почему? А потому, что загрузчик ОС сначала проверяет доступность указанной dll, затем наличие в данной dll соответствующих функций в секции экспорта. Если загрузчик ОС не найдет нужных функций, загрузка приложения будет прервана. Если будут указаны неверные адреса функций, то приложение не сможет работать, так как эти адреса будут переданы в приложение при его загрузке. Получается мы можеv изменить положение каталога импорта в теле криптованного файла, однако имена и адреса функций должны остаться без изменений, желательно так же поступить с ординалами.

Совсем другая ситуация, если dll подключается динамически (LoadLibrary\GetProcAddress) или внедряется в другие процессы (после распаковки). Тут можно делать с каталогом экспорта что угодно. Менять его, переименовывать функции, менять их адреса и количество, можно вообще удалить каталог импорта. Все это никак не отразится на работоспособности приложения. Почему так происходит? Просто теперь поиск экспортируемых функций происходит после вызова DllMain, то есть в уже в распакованной dll, которая содержит правильный каталог экспорта.
Естественно что AddressOfEntryPoint (который в исходной dll указывает на функцию DllMain), в закриптованном файле должен указывать на функцию распаковки dll.

2. Dll создана чтобы загрузиться с любого удобного места в памяти, для этого была придумана таблица перемещений (каталог релоков). Об этом я писал, поэтому не буду расписывать подробно. Нам надо вручную обработать релоки, если мы загружены по адресу, отличному от ImageBase.

3. Подошли к самому интересному на мой взгляд, а именно к восстановлению оригинального AddressOfEntryPoint нашей dll.
Зачем это нужно? Дело все в механизме работы dll. Функция DllMain, на которую указывает AddressOfEntryPoint, за время работы dll вызывается загрузчиком ОС минимум 2 раза, при загрузке dll в память и при ее выгрузке (причем не зависит как происходит выгрузка - вызовом FreeLibrary или завершением работы приложения).
И если при первом вызове DllMain все в порядке (наша dll распаковывается и настраивается), то при следующих вызовах там будет неизвестно что. Там может оказаться код распаковки, который нам уже не нужен, а могут быть уже данные или код распакованной dll.
Мы можем расположить точку входа в DllMain, в запакованном файле, на том же месте, что и в оригинальном файле. Однако это неудобно и дает лишний повод для детекта. Мы пойдем другим путем - восстановим AddressOfEntryPoint в нужных нам структурах ОС. AddressOfEntryPoint в заголовке мы восстановили при распаковке, однако загрузчик смотрит его в другом месте. А именно в структуре PEB_LDR_DATA (содержит информацию о всех загруженных модулях текущего процесса, по официальной документации).
Адрес PEB_LDR_DATA, хранится в другой структуре - Process Envirnoment Block или PEB, она достаточно большая, поэтому не буду описывать ее тут.

Достаточно выполнить следующий код:
Код:
mov eax, fs:[30h]   ;адрес PEB
mov eax, [eax + 0ch];адрес PEB_LDR_DATA внутри PEB

Структура PEB_LDR_DATA выглядит следующим образом
typedef struct _PEB_LDR_DATA
{
ULONG Length;
UCHAR Initialized;
PVOID SsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
PVOID EntryInProgress;
} PEB_LDR_DATA, *PPEB_LDR_DATA;


Нас интересуют LIST_ENTRY, это обычные двусвязные списки. Их названий списков легко понять, что они содержат одинаковую информацию о модулях, однако
различается порядок записей о модулях.

typedef struct _LIST_ENTRY {
int *Flink;
int *Blink;
} LIST_ENTRY, *PLIST_ENTRY;


Получим адрес первого списка InLoadOrderModuleList
Код:
mov eax, fs:[30h]   ;адрес PEB
mov eax, [eax + 0ch];адрес PEB_LDR_DATA внутри PEB
mov ecx, [eax + 0ch];адрec InLoadOrderModuleList внутри PEB_LDR_DATA

Теперь в регистре ecx, адрес следующего элемента списка, который называется LDR_MODULE
typedef struct _LDR_MODULE
{
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
PVOID BaseAddress;
PVOID EntryPoint;
ULONG SizeOfImage;
USHORT FullDllNameLength;
USHORT FullDllNameMaxLength;
PWSTR FullDllNameBuffer;
USHORT BaseDllNameLength;
USHORT BaseDllNameMaxLength;
PWSTR BaseDllNameBuffer;
ULONG Flags;
SHORT LoadCount;
SHORT TlsIndex;
LIST_ENTRY HashTableEntry;
ULONG TimeDateStamp;
} LDR_MODULE, *PLDR_MODULE;


Вот наконец искомая нами информация, 5 поле данной структуры и содержит AddressOfEntryPoint. Теперь нам нужно пробежать по списку
InLoadOrderModuleList, до тех пор пока мы не найдем нашу криптованную dll.

Код:
mov eax, fs:[30h]   ;адрес PEB
mov eax, [eax + 0ch];адрес PEB_LDR_DATA внутри PEB
mov ecx, [eax + 0ch];адрec InLoadOrderModuleList внутри PEB_LDR_DATA
.repeat
    mov edi, [ecx + 1ch];EntryPoint
    mov esi, [ecx + 28h];FullDllNameBuffer
    mov ecx, [ecx + 4]  ;следующий элемент списка InLoadOrderModuleList
.until (eax == ecx)

Нам осталось найти необходимый элемент списка и заменить EntryPoint криптованной dll на EntryPoint исходной dll.

Все структуры описаны для процессов х86, тесты проводились на Win7 x86.
Буду благодарен за найденные неточности и ошибки.
 
если темку закроют, сможете всю авторскую инфу скинуть мне (желательно последовательно)? я забекаплю в статьи в chm
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх