Исходник Shadow_syscall | C++20 Syscalls & Runtime DLL Utils

Stop Staring At the Shadows
Участник
Участник
Статус
Оффлайн
Регистрация
10 Окт 2020
Сообщения
535
Реакции
508
Достаточно удобный в использовании враппер сискола.
мой первый (но не последний) гитхаб репо:
Пожалуйста, авторизуйтесь для просмотра ссылки.

в будущем будет обновляться.

буду рад адекватному фидбэку и советам.


C++:
Expand Collapse Copy
// Execute "NtTerminateProcess" syscall
shadowsyscall<NTSTATUS>( "NtTerminateProcess", reinterpret_cast< HANDLE >( -1 ), -6932 );

// Since version 1.2, the return type may not be specified
shadowsyscall( "NtTerminateProcess", reinterpret_cast< HANDLE >( -1 ), -6932 );

// Execute any export at runtime
// Since version 1.2, the return type may not be specified
shadowcall<int>( "MessageBoxA", nullptr, "string 1", "string 2", MB_OK );


C++:
Expand Collapse Copy
#include <iostream>
#include <string>
#include "shadowsyscall.hpp"

int main() {
    // Enumerate every dll loaded to current process
    for ( const auto& dll : shadow::dlls() )
        std::cout << dll.filepath().string() << " : " << dll.native_handle() << "\n";

    std::cout.put( '\n' );

    // Find exactly known dll loaded to current process
    // "ntdll.dll" doesn't leave string in executable, it
    // being hashed on compile-time with consteval guarantee
    // The implementation doesn't care about the ".dll" suffix.
    auto ntdll = shadow::dll( "ntdll" /* after compilation it will become 384989384324938 */ );

    auto current_module = shadow::current_module();
    std::cout << "Current .exe filepath: " << current_module.filepath().string() << "\n";
    std::cout << "Current .text section checksum: " << current_module.section_checksum<std::size_t>( ".text" ) << "\n\n";

    std::cout << ntdll.base_address().ptr() << '\n';                         // .base_address() returns address_t
    std::cout << ntdll.native_handle() << '\n';                              // .native_handle() returns void*
    std::cout << ntdll.entry_point() << '\n';                                // .entry_point() returns address_t, if presented
    std::cout << ntdll.name().string() << '\n';                              // .name() returns win::unicode_string
    std::cout << ntdll.filepath().to_path().extension() << '\n';             // .filepath() returns win::unicode_string
    std::cout << ntdll.image()->get_nt_headers()->signature << '\n';         // returns uint32_t, NT magic value
    std::cout << ntdll.image()->get_optional_header()->size_image << "\n\n"; // returns uint32_t, loaded NTDLL image size

    std::cout << "5 exports of ntdll.dll:\n";
    for ( const auto& [name, address] : ntdll.exports() | std::views::take( 5 ) )
        std::cout << name << " : " << address.raw() << '\n';

    std::cout.put( '\n' );

    auto it = ntdll.exports().find_if( []( auto export_data ) -> bool {
        const auto& [name, address] = export_data;
        constexpr auto compiletime_hash = shadow::hash64_t{ "NtQuerySystemInformation" }; // after compilation it will become 384989384324938
        const auto runtime_hash = shadow::hash64_t{}( name );                             // accepts any range that have access by index
        return compiletime_hash == runtime_hash;
    } );

    const auto& [name, address] = *it;
    std::cout << "Found target export:\n" << name << " : " << address << "\n\n";

    // "location" returns a DLL struct that contains this export
    std::cout << "DLL that contains Sleep export is: " << shadow::dll_export( "Sleep" ).location().name().to_path() << "\n\n";

    // shared_data parses KUSER_SHARED_DATA
    // The class is a high-level wrapper for parsing,
    // which will save you from direct work with raw addresses

    auto shared = shadow::shared_data();

    std::cout << shared.safe_boot_enabled() << '\n';
    std::cout << shared.boot_id() << '\n';
    std::cout << shared.physical_pages_num() << '\n';
    std::cout << shared.kernel_debugger_present() << '\n';
    std::wcout << shared.system_root().to_path() << '\n';

    std::cout << shared.system().is_windows_11() << '\n';
    std::cout << shared.system().is_windows_10() << '\n';
    std::cout << shared.system().is_windows_7() << '\n';
    std::cout << shared.system().build_number() << '\n';
    std::cout << shared.system().formatted() << '\n';

    std::cout << shared.unix_epoch_timestamp().utc().time_since_epoch() << '\n';
    std::cout << shared.unix_epoch_timestamp().utc().format_iso8601() << '\n';
    std::cout << shared.unix_epoch_timestamp().local().time_since_epoch() << '\n';
    std::cout << shared.unix_epoch_timestamp().local().format_iso8601() << '\n';
    std::cout << shared.timezone_offset<std::chrono::seconds>() << "\n\n";

    // Iterators are compatible with the ranges library
    static_assert( std::bidirectional_iterator<shadow::detail::export_enumerator::iterator> );
    static_assert( std::bidirectional_iterator<shadow::detail::module_enumerator::iterator> );
}
 
Последнее редактирование:
Как это будет выглядеть рантайме?
 
Вижу только аутпут Иды
а че для тебя "рантайм"?
граф?листинг на 10 миллионов инструкций?
Вообще сложно ли обнаружить это в рантайме? Поставить какой-нибудь бп к примеру
по шаблону ясен хуй да.хз скажи тсу пусть завезет декрипт/энкрипт блока с сисколлом, мьютексом, блекджеком и шлюхами ?
 
1693102495061.png
1693102509056.png

есть два стула
1693102600262.png

а если в моём str нет нуля... то мемори оверлов получайца? std::string недоступен по соображениям религиозным?

а так ваще релиз хороший, +rep
 
Последнее редактирование:
Обновлено.

shadow syscall.hpp :
[+] - Добавлен выбор между SSE и AVX интринами.
[+] - Добавлены несколько методов к которым можно обратиться через макрос для более гибкого использования.
[-] - Макрос shadowsyscall переименован в shadowsyscall_

Репозиторий:
[+] - Добавлен бенчмарк для четкого обозначения разницы между кэшированным вызовом, и вызовом без него.
[+] - Добавлена схема объясняющая метод работы syscall`а на пальцах.
[+] - Указана целевая платформа.
 
Последнее редактирование:
Thank you very much for this great work , it's indeed really interesting and useful to learn more about syscalls !
 
В чём он shadow? В instumentation callback смотрится адрес возврата из ядра (R10) а он не в ntdll.dll
 
Обновлено.

Добавлен отдельный бранч с реализацией при помощи шеллкода. Следовательно - не тянущая за собой MASM.

Ссылка:
Пожалуйста, авторизуйтесь для просмотра ссылки.
 
Крутая работа, респект +rep
 
Обновлено.

shadow syscall shell.hpp :
[+] - std::map заменён на std::unordered_map
[+] - Пофикшены сисколлы для "win32u.dll" (заметил проблему только сегодня, для тех на кого это повлияло - сорян))

Репозиторий:
[+] - Изображение описывающее способ работы syscall`ов в Windows изменено на более подробное.

Завтра так же будет обновлён бранч MASM, а конкретнее завезу фикс win32u.dll
 
Обновлено.

shadow syscall shell.hpp :
[+] - std::map заменён на std::unordered_map
[+] - Пофикшены сисколлы для "win32u.dll" (заметил проблему только сегодня, для тех на кого это повлияло - сорян))

Репозиторий:
[+] - Изображение описывающее способ работы syscall`ов в Windows изменено на более подробное.

Завтра так же будет обновлён бранч MASM, а конкретнее завезу фикс win32u.dll
Сискалл NtCreateThreadEx почему-то возвращает ERROR_ACCESS_DENIED, в то время как обычный вызов из ntdll.dll с такими же аргументами работает нормально. А другие сискаллы, например NtTerminateThread работают

жду фикс :)
 
Последнее редактирование:
Сискалл NtCreateThreadEx почему-то возвращает ERROR_ACCESS_DENIED, в то время как обычный вызов из ntdll.dll с такими же аргументами работает нормально. А другие сискаллы, например NtTerminateThread работают
некоторые флаги отрубаются на уровне абстракций до сисколла(у меня был такой опыт.экстраполировать не надо)
upd, сел за кампутер:
что ж, никаких врапперов там нет(при прямом вызове ntdll NtCreateThread/Ex)
покажи код который работает и тот который не работает.
 
Последнее редактирование:
Сискалл NtCreateThreadEx почему-то возвращает ERROR_ACCESS_DENIED, в то время как обычный вызов из ntdll.dll с такими же аргументами работает нормально. А другие сискаллы, например NtTerminateThread работают

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

upd: единственный пока что known баг от меня, так это тотально разное восприятие NULL (или просто 0)) и nullptr распаковщиком аргументов, идей для фикса пока что нет.
1700643027646.png

1700643057569.png


Вариант 1: status = 0xC0000005 (STATUS_ACCESS_VIOLATION)
Вариант 2: status = 0x0
 
Последнее редактирование:
  • Мне нравится
Реакции: mj12
nullptr распаковщиком аргументов, идей для фикса пока что нет.
Думаю дело не в распаковщике, а в том что NULL это int, а nullptr это void* (т.е. размером size_t).
Т.к. аргумент на скрине как раз идет пятым, то на x64 он запишется в стек, компилятор заполнит нижние 32-бита от int нулем, а верхние 32-бита останутся неопределенными.
Потому что хандлер сискола ожидает там указатель размером void*, то для него этот адрес будет мусором, отсюда и AV.
Если бы аргумент шел 1/2/3/4, то компилятор бы сгенерировал запись в ecx/edx/r8d/r9d, по соглашению x64, запись в нижнюю половину 64-битного регистра обнуляет верхнюю часть тоже (т.е. ecx=0 => rcx=0), так что такая проблема должна существовать только на x64 для аргументов после четвертого.
Решение было бы на шаблонах перебирать все аргументы и вручную их кастовать к size_t размеру.
 
если не трудно то выдай полный, рабочий пример, нужно понять какие аргументы хотя-бы передаёшь)
как ток дашь - возьмусь за фикс

upd: единственный пока что known баг от меня, так это тотально разное восприятие NULL (или просто 0)) и nullptr распаковщиком аргументов, идей для фикса пока что нет.
Посмотреть вложение 264279
Посмотреть вложение 264280

Вариант 1: status = 0xC0000005 (STATUS_ACCESS_VIOLATION)
Вариант 2: status = 0x0
NtCreateThreadEx( &t, THREAD_ALL_ACCESS, NULL, (HANDLE)-1, (LPTHREAD_START_ROUTINE)startroutine, nullptr, FALSE, NULL, NULL, NULL, NULL );


но я уже походу понял в чем проблема, чувак выше написал
в ObjectAttributes, StackZeroBits, SizeOfStackCommit, SizeOfStackReserve, lpBytesBuffer nullptr вместо NULL передать
 
Назад
Сверху Снизу