Skip to content
KitploitKITPLOIT
ИнструментыЭксплойтыБлог
Log in
Отправить
ИнструментыЭксплойтыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
ThreadStackSpoofer — Thread Stack Spoofing - PoC для продвинутой техники обхода в памяти, позволяющей лучше скрывать выделение памяти под внедренный шеллкод от сканеров и аналитиков. | Kitploit
Инструменты/GitHubGitHub/mgeeky/threadstackspoofer
Фреймворки для пентестаФреймворки для эксплойтовКриминалистика памятиШелл-кодАнализ вредоносных программRed TeamingРазработка Полезной Нагрузки
GitHubmgeeky/threadstackspoofer

ThreadStackSpoofer

Thread Stack Spoofing - PoC для продвинутой техники обхода в памяти, позволяющей лучше скрывать выделение памяти под внедренный шеллкод от сканеров и аналитиков.

Репозиторий
1.2k192194 лет назадПроверено Kitploit

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

Thread Stack Spoofing / Call Stack Spoofing PoC

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

Введение

Это пример реализации техники Thread Stack Spoofing (подделка стека потока), направленной на обход специалистов по анализу вредоносного ПО, антивирусов и EDR, которые ищут ссылки на фреймы шеллкода в стеке вызовов проверяемого потока. Идея заключается в сокрытии ссылок на шеллкод в стеке вызовов потока, маскируя таким образом выделенную память, содержащую код вредоносного ПО.

Эта реализация вместе с моим ShellcodeFluctuation предоставляет сообществу Offensive Security примеры реализаций, чтобы мы могли не отставать от предложений коммерческих C2-продуктов и делать не хуже в наших Red Team-инструментах. 💪

Реализация изменилась

Текущая реализация сильно отличается от изначально опубликованной. Это связано с тем, что я осознал: существует гораздо более простой способ завершить обработку стека вызовов потока и скрыть связанные с шеллкодом фреймы — просто записать 0 в адрес возврата первого контролируемого нами фрейма:

void WINAPI MySleep(DWORD _dwMilliseconds)
{
    [...]
    auto overwrite = (PULONG_PTR)_AddressOfReturnAddress();
    const auto origReturnAddress = *overwrite;
    *overwrite = 0;

    [...]
    *overwrite = origReturnAddress;
}

Предыдущая реализация, использующая StackWalk64, доступна в этом коммите: commit c250724.

Эта реализация гораздо стабильнее и отлично работает как в Debug, так и в Release под обеими архитектурами — x64 и x86.

Демонстрация

Вот как может выглядеть стек вызовов, когда он НЕ подделан:

not-spoofed

А вот как — когда подделка стека включена:

spoofed

Выше мы видим, что последним фреймом в нашем стеке вызовов является наш колбэк MySleep. Можно задаться вопросом: не порождает ли это сразу новые IOC? Правила охоты могут искать потоки, чьи стеки вызовов не раскручиваются до следующих ожидаемых точек входа потока, расположенных в системных библиотеках:

kernel32!BaseThreadInitThunk+0x14
ntdll!RtlUserThreadStart+0x21

Однако стек вызовов поддельного потока поначалу может выглядеть странно. Краткое исследование моей системы показало, что существуют и другие потоки, не раскручивающиеся до указанных выше точек входа:

legit call stack

На скриншоте выше показан поток немодифицированного Total Commander x64. Как видим, его стек вызовов очень похож на наш с точки зрения начальных фреймов.

Зачем нам тщательно подделывать стек вызовов, если существуют процессы, демонстрирующие схожие признаки, которые мы можем просто имитировать?

Как это работает?

Приблизительный алгоритм:

  1. Чтение содержимого шеллкода из файла.
  2. Получение всех необходимых указателей на функции из dbghelp.dll, вызов SymInitialize.
  3. Перехват kernel32!Sleep с перенаправлением на наш колбэк.
  4. Инъекция и запуск шеллкода через VirtualAlloc + memcpy + CreateThread. Поток должен начинаться с нашей функции runShellcode, чтобы избежать указания StartAddress потока на что-то неожиданное и аномальное (например, ntdll!RtlUserThreadStart+0x21).
  5. Как только Beacon пытается уснуть, вызывается наш колбэк MySleep.
  6. Затем мы перезаписываем последний адрес возврата в стеке на 0, что фактически завершает стек вызовов.
  7. Наконец, вызывается ::SleepEx, чтобы позволить Beacon'у спать в ожидании дальнейшей связи.
  8. После завершения сна мы восстанавливаем ранее сохранённые оригинальные адреса возврата функций, и выполнение продолжается.

Адреса возврата функций разбросаны по всей области стека потока, на которую указывает регистр RBP/EBP. Чтобы найти их в стеке, необходимо сначала собрать указатели на фреймы, а затем разыменовать их для перезаписи:

stack frame

(изображение выше взято из поста Эли Бендерски (Eli Bendersky) «Stack frame layout on x86-64» (angлийская версия))

	*(PULONG_PTR)(frameAddr + sizeof(void*)) = Fake_Return_Address;

Первоначальная реализация ThreadStackSpoofer делала это в функциях walkCallStack и spoofCallStack, однако текущая реализация показывает, что эти усилия не требуются для поддержания скрытного стека вызовов.

Пример запуска

Использование:

C:\> ThreadStackSpoofer.exe <shellcode> <spoof>

Где:

  • <shellcode> — путь к файлу шеллкода
  • <spoof> — если 1 или true, включает подделку стека потока; в противном случае отключает.

Пример запуска, подделывающего стек вызовов потока Beacon:

PS D:\dev2\ThreadStackSpoofer> .\x64\Release\ThreadStackSpoofer.exe .\tests\beacon64.bin 1
[.] Чтение байтов шеллкода...
[.] Перехват kernel32!Sleep...
[.] Инъекция шеллкода...
[+] Шеллкод запущен.
[>] Оригинальный адрес возврата: 0x1926747bd51. Завершение стека вызовов...

===> MySleep(5000)

[<] Восстановление оригинального адреса возврата...
[>] Оригинальный адрес возврата: 0x1926747bd51. Завершение стека вызовов...

===> MySleep(5000)

[<] Восстановление оригинального адреса возврата...
[>] Оригинальный адрес возврата: 0x1926747bd51. Завершение стека вызовов...

Как мне это использовать?

Посмотрите на код и его реализацию, поймите концепцию и перереализуйте её в своих собственных загрузчиках шеллкода, которые вы используете для своих Red Team-задач. Это ещё одна техника продвинутого внутрипроцессного обхода, которая повышает шансы вашей команды не быть обнаруженными антивирусами, EDR и аналитиками вредоносного ПО, изучающими ваши импланты.

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

  • Шифрование кучи процесса — вдохновитесь постом в блоге: Hook Heaps and Live Free — это может позволить обойти экстракторы конфигурации Beacon, такие как BeaconEye
  • Изменить защиту страниц памяти вашего Beacon на RW (с RX/RWX) и зашифровать их содержимое — используя технику Shellcode Fluctuation — прямо перед сном (это может обойти сканеры, такие как Moneta или pe-sieve)
  • Очистить все остатки от рефлективного загрузчика — чтобы избежать сигнатурных детектов в памяти
  • Снять все перехваты, которые вы могли установить (например, AMSI, ETW, WLDP) перед сном, а затем восстановить их после.

На самом деле это (пока) не настоящая подделка стека

Как мне указали, данная техника пока не совсем соответствует названию «подделка стека». Поскольку мы лишь перезаписываем адреса возврата в стеке потока, мы не подделываем остальные области самого стека. Более того, мы делаем наш стек вызовов нераскручиваемым, что выглядит аномально, так как система не сможет корректно пройти по всей цепочке фреймов стека вызовов.

Скачать инструмент