#c #boost #hook #boost-propertytree #easyhook
#c #boost #перехват #boost-propertytree #easyhook
Вопрос:
Я работаю над утилитой для подключения различных бит Windows API, используемых различными приложениями. Цель проекта на данный момент состоит в том, чтобы сделать любое приложение переносимым путем перенаправления вызовов файловой системы и реестра в пользовательские местоположения с помощью easyhook и boost (в частности, библиотеки property_tree).
В настоящее время я работаю над частью проекта, связанной с реестром, и я успешно создал аналоги функций RegCreateKey (ExA / ExW / A / W), RegOpenKey (ExA / ExW / A / W) и RegCloseKey, и они работают нормально (я создал виртуальную систему дескрипторов для создания и перевода дескрипторов hKey). Они работают, в основном переводя все в строки и сохраняя их в дереве свойств boost (а затем записывая дерево в файл .info).
Я начал работать над функциями RegSetValue и RegQueryValue, которые фактически обрабатывают данные, и столкнулся с серьезной проблемой. Ниже приведены две функции. Обратите внимание, что они вызываются easyhook с теми же параметрами, что и исходный вызов winapi.
LSTATUS WINAPI myRegSetValueExA(HKEY hKey, LPCSTR lpValueName, DWORD Reserved, DWORD dwType, const BYTE* lpData, DWORD cbData)
{
boost::property_tree::ptree VirtualRegistry;
boost::property_tree::read_info("VirtualRegistry.info", VirtualRegistry);
VirtualRegistry.put(boost::property_tree::ptree::path_type(std::string(GetPathFromHandleA(hKey) '\' lpValueName), '\'), reinterpret_cast<const char*>(lpData));
boost::property_tree::write_info("VirtualRegistry.info", VirtualRegistry);
return ERROR_SUCCESS;
}
Это отлично работает для вызовов REG_SZ, но другие типы данных сохраняются некорректно.
LSTATUS WINAPI myRegQueryValueExA(HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData)
{
boost::property_tree::ptree VirtualRegistry;
boost::property_tree::read_info("VirtualRegistry.info", VirtualRegistry);
try
{
*lpData = reinterpret_cast<const BYTE*>VirtualRegistry.get_child(boost::property_tree::ptree::path_type(std::string(GetPathFromHandleA(hKey) "\" lpValueName), '\')).data();
return ERROR_SUCCESS;
}
catch (const boost::property_tree::ptree_bad_pathamp; e1)
{
std::cout << "n" << "ENTRY NOT FOUND" << "n";
return ERROR_FILE_NOT_FOUND;
}
}
Это не работает. Приведение к повторной интерпретации в строке 6 недопустимо, и оно не будет компилироваться.
Проблема в том, как мои функции обрабатывают разные типы данных. Вызов реестра может иметь много разных типов значений, и то, как я написал myRegSetValue, похоже, работает только для REG_SZ. Мне также придется сохранять тип значения при записи вызова в файл, но это не решает проблему.
Итак, мой вопрос в том, есть ли какой-либо способ сохранить необработанные данные вызова в виде строки без необходимости преобразования их в строку, чтобы они работали для всех типов данных, а затем считывать их из файла из строки обратно в необработанные данные и передавать их вприложение?
Думаю, я мог бы написать отдельный интерпретатор для каждого типа ключа, но я бы предпочел этого не делать, потому что это было бы очень сложно, а также нарушило бы работу приложений, которые неправильно используют registry API и хранят недопустимые значения в реестре (например, игра Unity Sunless Sea).
Спасибо, надеюсь, я объяснил это достаточно подробно.
Ответ №1:
Похоже, что реальная проблема уже заключается в реализации myRegSetValueExA
. Когда вы получаете lpData
, вы не можете предположить, что он указывает на данные, которые останутся действительными. Вы должны хранить не указатель, а данные, на которые указывают.
Это также cbData
необходимо; вам нужно знать, сколько данных хранить. Вы не можете полагаться на strlen
, поскольку тип может быть не таким REG_SZ
.
Обратите внимание, что ваше предположение о This works fine for REG_SZ
верно только потому VirtualRegistry.put(std::string key, const char* value)
, что это удобная перегрузка, которая требует strlen(buf)
вас.
Решение состоит в том, чтобы создать явно std::string data(static_cast<const char*>(lpData), cbData)
и использовать это в put
. Чтобы извлечь его, вы используете .get<std::string>(key)
вместо get_child(key).data()
.
Комментарии:
1. Я не создаю std::string из него. Я просто переосмысливаю приведение к const char* . Std::string является аргументом path для метода .put дерева свойств. Должен ли я каким-то образом поместить cbData в приведение?
2. Вы имеете в виду что-то вроде этого? std::строковые данные(static_cast<const char*>(lpData), static_cast<int>(cbData)); (Это не работает, недопустимое преобразование типов)
3. @enzeinzen: Ах, я думал, что дерево свойств boost хранит a
std::string
, поэтомуput
метод принимает строковый путь и строковое значение. Исправит.4. Спасибо за ваш ответ. Я понимаю концепцию, однако статическое приведение недопустимо. (недопустимое преобразование типов). Вместо этого я использовал приведение с повторной интерпретацией, и сохраняется только пустая строка.
5. @enzeinzen:
myRegQueryValueExA
Вы имеете в виду? Вы получилиstd::string
выход из дерева свойств? Но не удалось записать их обратно? Взгляните на семантику realRegQueryValueExA
. Вам нужно проверитьlpcbData
, достаточно ли он большой, затем скопировать содержимое строкиlpData
и обновитьlpcbData
.