- Статус
- Оффлайн
- Регистрация
- 13 Фев 2026
- Сообщения
- 602
- Реакции
- 16
Суть проблемы
Пытаюсь реализовать внешний вызов функции (x64) в таргете через самописный шеллкод. Сама функция отрабатывает, вызов проходит успешно, но возник затык на элементарном: не получается сохранить возвращаемое значение (return value) в заранее выделенный буфер (allocation2). Данные в память просто не записываются.
Технические нюансы и подозрения
Риски и траблшутинг
Если используете CreateRemoteThread для запуска, имейте в виду, что логика работы со стеком может отличаться от обычного вызова. Советую навесить отладчик (x64dbg) на целевой процесс, поставить бряк на точку входа шеллкода и пошагово посмотреть, что лежит в RAX после вызова и куда на самом деле указывает адрес из вашего кода.
Интересно послушать мысли тех, кто плотно сидит на внешних вызовах через шеллкоды @KVANTOR815 — хватает ли тут 16 байт под выравнивание или стоит копать в сторону корректного пролога/эпилога?
Пытаюсь реализовать внешний вызов функции (x64) в таргете через самописный шеллкод. Сама функция отрабатывает, вызов проходит успешно, но возник затык на элементарном: не получается сохранить возвращаемое значение (return value) в заранее выделенный буфер (allocation2). Данные в память просто не записываются.
Код:
auto shellcode = make_shellcode(
"\x48\x83\xEC\x10", // sub rsp, 0x10 (reserve 16 bytes of stack space)
"\x48\xB8", uint64_t(address), // mov rax, address of my_malloc
"\x48\x89\xC7", // mov rdi, rax (rdi holds the address of my_malloc)
"\x48\xB9", uint64_t(size), // mov rcx, size (first argument for my_malloc)
"\x48\xBA", uint64_t(alignment), // mov rdx, alignment (second argument for my_malloc)
"\xFF\xD7", // call rdi (call my_malloc)
"\x48\x89\xC7", // mov rdi, rax (move return value to rdi)
"\x48\xB8", uint64_t(allocation2), // mov rax, address of allocation2
"\x48\x89\x00", // mov [rax], rdi (store return value at allocation2)
"\x48\x83\xC4\x10", // add rsp, 0x10 (restore stack pointer)
"\xC3" // ret (return from the shellcode)
);
Технические нюансы и подозрения
- Shadow Space. Это классическая проблема в x64. По соглашению вызова Microsoft (fastcall), вызывающий обязан выделить минимум 32 байта (0x20) под "теневое пространство" на стеке, даже если аргументов меньше. Здесь выделено всего 16 байт (0x10), что может приводить к затиранию данных самой функцией или порче стека.
- Регистр RDI. Почему результат перекидывается из RAX в RDI перед записью? В коде RAX затирается адресом allocation2, и это логично, но стоит убедиться, что вызываемая функция (my_malloc) не ожидает чего-то специфического в регистрах, которые вы используете.
- Права доступа. Очевидный момент, но всё же — проверьте, с какими флагами выделена память под allocation2. Если нет PAGE_READWRITE, то инструкция mov [rax], rdi просто молча уйдет в небытие или вызовет исключение, которое вы не ловите.
- Выравнивание стека. Перед инструкцией CALL стек должен быть выровнен по границе 16 байт. На входе в шеллкод (после CALL от инжектора) стек уже смещен на 8 байт (адрес возврата). Манипуляции с sub rsp должны это учитывать.
Риски и траблшутинг
Если используете CreateRemoteThread для запуска, имейте в виду, что логика работы со стеком может отличаться от обычного вызова. Советую навесить отладчик (x64dbg) на целевой процесс, поставить бряк на точку входа шеллкода и пошагово посмотреть, что лежит в RAX после вызова и куда на самом деле указывает адрес из вашего кода.
Интересно послушать мысли тех, кто плотно сидит на внешних вызовах через шеллкоды @KVANTOR815 — хватает ли тут 16 байт под выравнивание или стоит копать в сторону корректного пролога/эпилога?