Ситуация такая: Программа пишет логи, в начале которых вставляет разную информацию о системе.
Чтобы получить наименование системы, использую TOSVersion.Name.
Для Windows 10 всегда возвращает просто "Windows". Из кода понятно, что так и должно быть.
Погуглил и увидел множество советов исправить это добавлением следующего фрагмента в сертификат:
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!— Windows 10 —>
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
<!— Windows 8.1 —>
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!— Windows Vista —>
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
<!— Windows 7 —>
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!— Windows 8 —>
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
</application>
</compatibility>
Это никак ситуацию не исправило.
В самом начале я анализировал dwMinorVersion и dwMajorVersion. Предполагал, что 10-ка - это 10.0, но получал 6.2, т.е. Windows 8.
Собственно, вопрос: как определить ось (хотя бы правильные Major и Minor), собирая программу в XE2?
Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице. Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.
08-01-2022 02:43 | Сообщение от автора вопроса
Тема уже старая, но для тех, кто хочет получить доступ к PЕB, но прислушался к предостережениям от Python, сообщаю:
Имеется API NtQueryInformationProcess, которое позволяет получить указанную структуру.
Однако сама структура строго определена (для 32 и 64 bit), и если "структура структуры" поменяется, то всё равно нужно менять программу.
Сейчас эти структуры представлены на сайте Microsoft. Если предполагать, что Microsoft станет рандомно менять всё на свете (а случаи были), то надо завязывать с программированием или переходить на Электрон.
Так получилось, что мы с вашей программой обмениваемся данными. И для того, чтобы идентифицировать клиента, я отдаю вам некий "хендл", который фактически - указатель на структуру TSomething. Вам зачем-то понадобился доступ к полю value2. Вы случайно (или намеренно, через отладчик, по совету Гугля или принцессы Луняшки) обнаружили тот факт, что отданный мною хендл - это указатель на TSomething и по смещению +4 байта там лежит нужная вам информация. Преобразовали хендл в указатель, разыменовали, пользуетесь.
Шли годы и хак забылся. А я про него и не знал никогда. И вот мне (а может, программисту, унаследовавшему мой код) требуется добавить ещё одно поле во внутреннюю структуру программы. О нём, напоминаю, никто кроме меня (и наследника-программиста) не знает, мы эту структуру не афишировали, а то, что вернули хендл в виде указателя... ну так никому до этого никакого дела быть не должно. И вот наследник (или я) делаем такую вещь:
Другими словами - добавили что-то в свою внутреннюю структуру. Конечно, все процедуры, которые пользовались value2 в НАШЕЙ программе тут же были пересобраны умным компилятором и стали пользоваться правильными смещениями. Но вот ваша программа об этом никак не знает. И хорошо, если она СРАЗУ ЖЕ, в ту же секунду, как придёт обновление МОЕЙ программы, просто упадёт и больше не поднимется - хотя бы будет понятно, что виновато конкретно это обновление! Но если пройдёт десять лет и вдруг окажется, что всё это время в логи вашей программы падала фигня? Или, что ещё хуже, все эти десять лет вы использовали данную (рандомную по сути) величину для расчёта дозы облучения пациентов рентгеном? Мне бы не хотелось оказаться пациентом у врача, который пользуется аппаратом, софт которого писали вот такие "хакеры" (хотя, честно говоря, выбора особенного и нет, весь софт так сейчас пишется).
Там два момента:
1. Для Delphi ниже XE
2. Редактируется манифест изначальное размера. В принципе, можно подогнать.
Возьму на заметку. Но это усложнит процесс сборки. У меня и так все выборочно компилит ресурсы, копируется в разные папки, переименовывается и тд. Если помру, то никто не выпустит новую версию. ;)
>>>Но настройки проекта таковы, что этот манифест заменяется при сборке на "по умолчанию".
Теперь становится яснее суть проблемы. Хочу между прочим обратить внимание, что приложение Resource Tuner позволяет вставить манифест в уже готовый exe-файл. Вставив нужный вам манифест таким образом, т.е. в скомпилированный exe-файл, вы смогли бы убедиться, работает ли нормально программа в том случае, если при компиляции у нас не будет манифест заменяться на манифест "по умолчанию". Если работа будет нормальной, то можно будет сфокусировать свое внимание на то, как правильно компилировать, чтобы вставлялся нужный нам манифест.
Помню, разбирался как-то с этим вопросом в Delphi 2009. Это действительно нелегкий вопрос.
Чистота понравившегося мне способа разволновала мои чувства. Начал гуглить и натыкаться только на варианты чтения чужого процесса.
Тогда проанализируем:
1. Читаем из регистра FS адрес Thread Environment Block (со смещением к PEB).
Какой в этом криминал? Был бы благодарен за критику или слова поддержки.
Кстати, в PEB есть много полезных полей, например флаг работы под отладчиком.
to Михаил Власенко
Да, конечно, манифест! Спасибо.
Он есть и я его вынимаю, редактирую и добавляю утилитой ResourceEditor. Но настройки проекта таковы, что этот манифест заменяется при сборке на "по умолчанию". Подозреваю, это связано с использованием runtime themes.
to Python
Я, честно говоря, не вижу проблемы. Я ведь читаю из памяти своего процесса. Многочисленные опыты с XP до 10-ки никаких проблем не выявили. Eсли это слишком грязно, то может надо через OpenProcess? Спасибо, что обратили внимание.
Забить на это очень заманчиво, но не знаю, как убедить тех, кто дает задание. Да и версия системы важна для получения картины возможных ошибок у клиентов.
>>> Просто прочитать два байта по определенному адресу
Очень странно, что это в принципе работает. Потому что не должно. Ибо во всех системах с семёрки и до куда угодно должен и обязан быть включён ASLR - address space layout randomiztion. То есть: система НАМЕРЕННО постоянно перемешивает адреса системных библиотек, чтобы ничего при разных запусках не лежало по одному и тому же адресу. Это правильно, так как не позволяет хакерским утилитам с использованием какого-нибудь переполнения стека вызвать правильную функцию: наиболее вероятно, что программа просто упадёт, потому что влетит по неизвестному (для взламываемой программы) адресу неизвестно куда.
Таким образом, решение с прямым чтением откуда бы то ни было, является кривым by design и не должно использоваться. Наиболее правильным решением вижу: забить огромный болт на правильное определение версии. Что вернула система - то и правильно. Вернула, что Windows 98, на котором установлен DirectX 14.7 - значит, так оно и есть, утрись и пользуйся.
>>>Но я получаю не те dwMajorVersion и dwMinorVersion, когда запускаю в Windows10 программу, собранную на Windows7 в XE2.
А вы уверены в том, что в вашей программе присутствует созданный вами манифест (вы называете "сертификат")?
Чтобы в этом убедиться, можно воспользоваться приложением Resource Tuner. {http://www.restuner.com/}
Если манифест в программе есть, то вот как это будет выглядеть в диалоге Resource Tuner: https://yadi.sk/i/9rqV1Hu3hmzE7w
Если манифеста нет, то картина будет примерно такой: https://yadi.sk/i/3Gtj7cbeEvuQOw
Это понятно. Но я получаю не те dwMajorVersion и dwMinorVersion, когда запускаю в Windows10 программу, собранную на Windows7 в XE2.
Ещё можно заюзать NetServerGetInfo, ещё функции из netapi32 (не помню сейчас названий). WMI - но я прочитал инфу, что не все функции WMI могут быть активированы в текущей системе.
Всё это вроде, возвращает правильную версию. Но выбранный мной вариант самый лаконичный. Просто прочитать два байта по определенному адресу.
Из того, что мне удалось нагуглить, понял, что старый проверенный API возвращает версию системы, которую винда эмулирует для программ, собранных в старых средах. Вроде, как решается сертификатом, который упомянут выше. Но при моих настройках он заменяется. WMI может быть не везде полностью включенным, другое API зависит от версии. Поэтому решил сделать через чтение из PEB
Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter. Функция может не работать в некоторых версиях броузеров.