Есть ли способ сохранить необработанные двоичные данные из вызова реестра в строку без преобразования их в строку?

#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 выход из дерева свойств? Но не удалось записать их обратно? Взгляните на семантику real RegQueryValueExA . Вам нужно проверить lpcbData , достаточно ли он большой, затем скопировать содержимое строки lpData и обновить lpcbData .