552 / 24 / 7
Регистрация: 12.11.2013
Сообщений: 50

Output/Input в консоль без C Run-Time (CRT)

20.03.2019, 19:18. Показов 4959. Ответов 7
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Добрый день!
Пишу небольшой загрузчик без CRT с использованием некоторых Nt-функций.
Как таковой вывод информации на обозрение не так уж необходим, то что нужно смотрю в отладчике.
Но хотелось бы разобраться как всё же выводить данные и информацию в консоль?
На подобии как это делается при помощи printf или std::cout, но эти функции жестко завязаны на CRT.
Можно конечно замарочиться и писать всё что нужно в файл, но это не так практично как быстрый вывод в консоль.

Есть у кого какие идеи? Гугл ничего внятного сказать не может.
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
20.03.2019, 19:18
Ответы с готовыми решениями:

как сделать в MS VS 2010 express output не в консоль в output windows
сабж заранее спасибо

Run-Time ошибка "Переменная используется без инициализации"
Доброго времени суток, столкнулся с такой проблемой. 1) При попытке выполнить код жалуется на строку the variable 'nomer' is being used...

Разница в координатах в run-time и design-time
Может кто-нибудь объяснить почему координаты любого объекта(например Tshape) отличаются во время run и design? Например если создать...

7
2718 / 871 / 329
Регистрация: 10.02.2018
Сообщений: 2,073
20.03.2019, 21:50
А консольный WinAPI не подходит?
0
552 / 24 / 7
Регистрация: 12.11.2013
Сообщений: 50
21.03.2019, 00:59  [ТС]
Ygg, к сожалению нет.
Хотелось бы не использовать WinAPI, и насколько я понял консольные функции (AllocConsole, GetConsoleScreenBufferInfo и прочие) являются внутренними (Internal -> ConsoleCallServerGeneric) и обрабатываются где-то в недрах kernelbase.dll (kernel32.dll на более старых ОС).
Они не импортируют из ntdll.dll Nt-функции (ну может быть кроме NtDeviceIoControlFile), поэтому собрать консоль из native не получается.

Я тут присматриваюсь к структуре RTL_USER_PROCESS_PARAMETERS
По составу она близка к консоли - есть ConsoleHandle, методы StandardInput и StandardOutput, title, всевозможные координаты и др.
При вызове RtlCreateProcessParametersEx структура заполняется данными, но не всеми, как раз всё что связно с консолью сплошные нули.
Может где-то что-то нужно подсказать той функции, чтобы она схватила консоль среды?
Ведь моя программа собирается в VS2019 с subsystem:console.

Нашёл на форуме тему про RTL_USER_PROCESS_PARAMETERS И вновь консоль, redirect console output
Насколько я понял там при запуске родительского процесса handle и I/O консоли также null.
А запуск дочерних процессов приводит к тому, что появляются значения консоли, которые можно использовать для вывода информации.
Только там всё как-то вперемешку и не совсем понятно, опять же использовался стандатрный WinAPI - CreateProcess.
0
0 / 0 / 0
Регистрация: 19.03.2019
Сообщений: 11
21.03.2019, 06:30
К сожалению код у меня не сохранился, но прикрутить консоль к winapi как-то получалось. Кватернионы проверял в столбик.

Добавлено через 22 минуты
AllocConsole();
freopen("CONOUT$", "w", stdout);
freopen("CONIN$", "r", stdin);
ну это видимо CRT

Добавлено через 27 минут
судя по всему можно писать в фаил, а фаил приатачить к потоку вывода консоли, но как тогда открыть консоль через nt?

Добавлено через 45 минут
Юзай WINAPI NTAPI недокументирована и стара.
0
2718 / 871 / 329
Регистрация: 10.02.2018
Сообщений: 2,073
21.03.2019, 09:33
Цитата Сообщение от cloo Посмотреть сообщение
Они не импортируют из ntdll.dll Nt-функции (ну может быть кроме NtDeviceIoControlFile), поэтому собрать консоль из native не получается.
Не, на таком низком уровне ничего не подскажу. Мне проблем и в обычном мире API хватает. Шелл для синего экрана
1
552 / 24 / 7
Регистрация: 12.11.2013
Сообщений: 50
22.03.2019, 12:17  [ТС]

Не по теме:

Цитата Сообщение от qwertykon Посмотреть сообщение
как тогда открыть консоль через nt?
в этом и вопрос)



Ygg, спасибо за ссылку, хакера всегда приятно почитать
Но это немного не то, кроме раздела Запуск процессов.
Там структура RTL_USER_PROCESS_INFORMATION, её я заполняю при вызове RtlCreateUserProcessEx, в результате запускается процесс с главным потоком и заполняется интересная структура SECTION_IMAGE_INFORMATION, аналог IMAGE_OPTIONAL_HEADER.

Есть ещё одна занятная структура PS_STD_HANDLE_INFO которая заполняется enum'ом PS_STD_HANDLE_STATE и одним из определений define PS_STD_OUTPUT_HANDLE (очень похоже на консоль, по крайней мере хендлом).
Чтобы её использовать необходимо вызвать NtCreateUserProcess (кстати после отработки RtlCreateUserProcessEx вызывает NtCreateUserProcess, по сути это враппер), заполнив структуру PS_ATTRIBUTE_LIST примерно так
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
PS_STD_HANDLE_INFO PsStdHandle;
PsStdHandle.Flags = PS_STD_OUTPUT_HANDLE;
PsStdHandle.StdHandleSubsystemType = PsMaxStdHandleStates;
 
PS_ATTRIBUTE_LIST PsAttrList;
PsAttrList.Attributes[0].Attribute = PsAttributeValue(PsAttributeStdHandleInfo, FALSE,TRUE, FALSE);
PsAttrList.Attributes[0].Size = sizeof(PS_STD_HANDLE_INFO);
PsAttrList.Attributes[0].Value = (ULONG_PTR)&PsStdHandle;
 
NtCreateUserProcess(
    &hProcess,
    &hThread,
    0x2000000, // значение получено при помощи реверса kernelbase.dll
    0x2000000, // значение получено при помощи реверса kernelbase.dll
    NULL,
    NULL,
    0, // флаг процесса (0 - normal)
    1, // флаг потока (1 - suspended)
    RTL_USER_PROCESS_PARAMETERS*,
    &PS_CREATE_INFO,
    &PsAttrList
    );
Но проблема в том, что NtCreateUserProcess у меня не получилось завести на Windows 10 (1809).
Думаю это связано с переключением в режим ядра из пользовательского режима (nt!NtContinue не выполняется из-за PreviousMode = UserMode).

Жалко Убежденный ушёл с форума.
Просто из его ответа
1) Родительский процесс, назовем его Parent, вызывает CreateFile и получает хэндл файла,
причем при вызове функции в аргументе SECURITY_ATTRIBUTES указывается bInheritHandle = TRUE,
то есть, данный хэндл может наследоваться дочерними процессами (может - не означает обязан).

2) Parent запускает дочерний процесс по имени FirstChild.
Для запуска используется функция CreateProcess, причем в аргументе bInheritHandles тоже
указывается TRUE. Это означает, что все хэндлы, созданные в Parent с флагом bInheritHandle =
TRUE, будут валидны также в контексте процесса FirstChild. Сами хэндлы могут передаваться
через STARTUPINFO, командную строку, канал или другие механизмы, это не важно.
В данном случае хэндл файла записывается в STARTUPINFO.hStdOutput и дочерний FirstChild
пишет в этот хэндл, "думая", что это хэндл консоли.
получается хендл файла является хедлом консоли.
Именно поэтому консольные функции ничего не импортируют из ntdll.dll кроме функции NtDeviceIoControlFile которая как раз и принимает хендл файла первым аргументом.
0
Эксперт С++
 Аватар для _lunar_
3701 / 2835 / 451
Регистрация: 03.05.2011
Сообщений: 5,193
Записей в блоге: 21
23.03.2019, 18:24
Лучший ответ Сообщение было отмечено cloo как решение

Решение

Цитата Сообщение от cloo Посмотреть сообщение
printf или std::cout, но эти функции жестко завязаны на CRT
ntdll.dll содержит некоторые функции из CRT, но они урезаны.
в экспорте есть пара таких вот функций _vsnwprintf и _vsnwprintf_s
в хитросплетениях native (и в частности ntdll.dll) они вызываются некоторыми Rtl-функциями (которые пришли ещё с ХР).

_vsnwprintf:
перед её вызовом обрабатывается RtlFormatMessageEx (kernelbase!FormatMessage), которая в свою очередь вызывает следующие внутренние функции
RtlFormatMessageEx -> (Internal : RtlStringCchPrintfExW -> RtlStringVPrintfWorkerW) -> _vsnwprintf
а уже потом _vsnwprintf обращается к другим внутренним функциям
_vsnwprintf -> (Internal : _vsnwprintf_l -> _woutput_l -> write_string_0 -> write_char_0)

аналогично _vsnwprintf_s:
сначала RtlQueryAtomInAtomTable -> _snwprintf_s -> _vsnwprintf_s
а потом _vsnwprintf_s -> (Internal : _swoutput_s -> _woutput_s -> write_string_2 -> write_char_2)

тут легко запутаться, потому что в ntdll.dll printf-подобных функций куча целая.
я советую использовать _vsnwprintf - у неё и прототип не сложный, и адаптировать её в коде тоже достаточно легко.

итак, прототип
C++
1
2
3
4
5
6
7
typedef unsigned __int32(__cdecl* __ptr64 __vsnwprintf)(
    unsigned short* __ptr64 Dest,
    unsigned __int64 Count,
    const unsigned short* __ptr64 Format,
    char* __ptr64 Args
    );
__vsnwprintf _vsnwprintf;
далее пишем функцию-заглушку
C++
1
2
3
4
5
6
7
8
__int64 wprintf(const unsigned short* __ptr64 Format, ...) {
    const __int32 BufferSize = 256;
    unsigned short lpBuffer[256];
    unsigned __int32 nNumberOfCharsToWrite = _vsnwprintf(lpBuffer, BufferSize, Format, (char* __ptr64) & Format + sizeof(unsigned short* __ptr64));
    unsigned __int32 lpNumberOfCharsWritten;
    WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), lpBuffer, nNumberOfCharsToWrite, &lpNumberOfCharsWritten, NULL);
    return lpNumberOfCharsWritten;
}
STD_OUTPUT_HANDLE определён из winnt.h
C++
1
#define STD_OUTPUT_HANDLE ((unsigned __int32)-11)
процессорные define здесь собственно и не нужны (как вы заметили, они используются вместе с NtCreateUserProcess, но функция является ядерной и в пользовательском режиме не доступна, в usermode можно использовать NtCreateProcess/NtCreateProcessEx, но вывести хендлы из ядра сложно, т.к. нужно уведомлять csr)

WriteConsoleW и GetStdHandle импортировать из kernelbase.dll нет необходимости, компилятор уже сам предполагает что они extern с возвращаемым типом int (но если хочется, можно загрузить их через LdrLoadDll/LdrGetProcedureAddressForCaller и переопределить через typedef).

и дальше, используйте wprintf как обычную printf
C++
1
wprintf(L"0x%llx", ImageBaseAddr);
1
552 / 24 / 7
Регистрация: 12.11.2013
Сообщений: 50
23.03.2019, 18:55  [ТС]
_lunar_, вы хорошо разбираетесь в native.
всё получилось, и вывод в консоль работает, спасибо
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
23.03.2019, 18:55
Помогаю со студенческими работами здесь

Разница в координатах в run-time и design-time
Может кто-нибудь объяснить почему координаты любого объекта(например Tshape) отличаются во время run и design? Например если создать...

Compile-time и run-time методы и функции
Добрый день. Есть две функции, которые делают идентичную работу: template<bool leftShift, typename T> T byteShift(T data) { ...

ошибка: Cannot run compiler 'g++'. Output:
Установил qt на диск D. Когда выбираю компилятор Mingw 64-bit проект не компилится. Вылазит следующая ошибка- ошибка: Cannot run compiler...

Project ERROR: Cannot run compiler 'g++'. Output:
Доброго времени суток, недавно решил заняться разработкой приложений с графическим интерфейсом, создал пустой проект, запустил, и ... ...

Input, output
Как сделать так, чтобы при запуске программы можно было указать файлы откуда читать и куда писать без стрелок < и >, а в качестве...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
8
Ответ Создать тему
Опции темы

Новые блоги и статьи
Как использовать Bluetooth-модуль HC-05 с Arduino
Wired 08.07.2025
Bluetooth - это технология, созданная чтобы заменить кабельные соединения. Обычно ее используют для связи небольших устройств: мобильных телефонов, ноутбуков, наушников и т. д. Работает она на частоте. . .
Руководство по структурам данных Python
AI_Generated 08.07.2025
Я отчетливо помню свои первые серьезные проекты на Python - я писал код, он работал, заказчики были относительно довольны. Но однажды мой наставник, взглянув на мою реализацию поиска по огромному. . .
Тестирование энергоэффективности и скорости вычислений видеокарт в BOINC проектах
Programma_Boinc 08.07.2025
Тестирование энергоэффективности и скорости вычислений видеокарт в BOINC проектах Опубликовано: 07. 07. 2025 Рубрика: Uncategorized Автор: AlexA Статья размещается на сайте с разрешения. . .
Раскрываем внутренние механики Android с помощью контекста и манифеста
mobDevWorks 07.07.2025
Каждый Android-разработчик сталкивается с Context и манифестом буквально в первый день работы. Но много ли мы задумываемся о том, что скрывается за этими обыденными элементами? Я, честно говоря,. . .
API на базе FastAPI с Python за пару минут
AI_Generated 07.07.2025
FastAPI - это относительно молодой фреймворк для создания веб-API, который за короткое время заработал бешеную популярность в Python-сообществе. И не зря. Я помню, как впервые запустил приложение на. . .
Основы WebGL. Раскрашивание вершин с помощью VBO
8Observer8 05.07.2025
На русском https:/ / vkvideo. ru/ video-231374465_456239020 На английском https:/ / www. youtube. com/ watch?v=oskqtCrWns0 Исходники примера:
Мониторинг микросервисов с OpenTelemetry в Kubernetes
Mr. Docker 04.07.2025
Проблема наблюдаемости (observability) в Kubernetes - это не просто вопрос сбора логов или метрик. Это целый комплекс вызовов, которые возникают из-за самой природы контейнеризации и оркестрации. К. . .
Проблемы с Kotlin и Wasm при создании игры
GameUnited 03.07.2025
В современном мире разработки игр выбор технологии - это зачастую балансирование между удобством разработки, переносимостью и производительностью. Когда я решил создать свою первую веб-игру, мой. . .
Создаем микросервисы с Go и Kubernetes
golander 02.07.2025
Когда я только начинал с микросервисами, все спорили о том, какой язык юзать. Сейчас Go (или Golang) фактически захватил эту нишу. И вот почему этот язык настолько заходит для этих задач: . . .
C++23, квантовые вычисления и взаимодействие с Q#
bytestream 02.07.2025
Я всегда с некоторым скептицизмом относился к громким заявлениям о революциях в IT, но квантовые вычисления - это тот случай, когда революция действительно происходит прямо у нас на глазах. Последние. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru