RandomHash
RandomHash

Reputation: 681

Writing to registry failing, no data added to key, yet functions returning ERROR_SUCCESS

I am writing a method to add data to registry key using RegSetValueEx() after checking the registry the value has not been written to the key. All 3 functions I use to load the hive, key and add value are returning ERROR_SUCCESS which has got me stumped. I have read this and this, however both of these questions suggest I should be receiving an error if I were coming across these problems.

I feel I am missing something to do with wide strings, ANSI and Unicode, although I cannot understand what. I could be way off base here though. I will also add that Visual Studio is running as Admin.

This is the code I have written so far:

#include <iostream>
#include <Windows.h>

int addValuetoRegistryKey(std::string executable) {

    LPCWSTR registryKey = L"Software\\Classes\\mscfile\\shell\\open\\command\\";
    HKEY hiveHandle;
    HKEY keyHandle;

    if (RegOpenCurrentUser(KEY_SET_VALUE, &hiveHandle) != ERROR_SUCCESS) {

        wchar_t buf[256];
        FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
            buf, (sizeof(buf) / sizeof(wchar_t)), NULL);

        /* Display error */
        std::wcout << "Opening hive failed: " << buf << std::endl;

        return -1;

    }
    else {

        std::wcout << "HKCU Hive opened successfully" << std::endl;

    }

    if (RegOpenKeyEx(hiveHandle, registryKey, 0, KEY_SET_VALUE, &keyHandle) != ERROR_SUCCESS) {

        wchar_t buf[256];
        FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
            buf, (sizeof(buf) / sizeof(wchar_t)), NULL);

        /* Display error */
        std::wcout << "Opening key failed: " << buf << std::endl;

        return -1;

    }
    else {

        std::wcout << registryKey << " opened successfully" << std::endl;

    }

    if (RegSetValueEx(keyHandle, NULL, 0, REG_SZ, (LPCBYTE)executable.c_str(), executable.size() + 1) != ERROR_SUCCESS) {

        wchar_t buf[256];
        FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
            buf, (sizeof(buf) / sizeof(wchar_t)), NULL);

        /* Display error */
        std::wcout << "Writing value to  key failed: " << buf << std::endl;

        return -1;
    }
    else {

        std::wcout << executable.c_str() << " written to key" << std::endl;

    }

    RegCloseKey(keyHandle);
    RegCloseKey(hiveHandle);

    return 0;
}

int main() {

    addValuetoRegistryKey("C:\\Windows\\System32\\cmd.exe");

}

Full disclosure: I am a computer security graduate, and some users may notice that I am trying to implement a method for UAC bypass. This is simply for educational purposes, instead of implementing metasploit modules, I would like to write the code and understand the workflow myself.

This is the data returned to the console: enter image description here

Upvotes: 0

Views: 208

Answers (1)

RandomHash
RandomHash

Reputation: 681

Thanks for dxiv for pointing me toward the right resources.

Firstly, after reading the Microsoft information, I decided to change all strings to wide strings, as ANSI no longer needs to be supported in new applications, or when NOT taking user input.

std::string executable to LPCWSTR executable,

std::wcout << executable.c_str() << " written to key" << std::endl; to std::wcout << executable << " written to key" << std::endl;

addValuetoRegistryKey("C:\\Windows\\System32\\cmd.exe"); to addValuetoRegistryKey(L"C:\\Windows\\System32\\cmd.exe");

Next I chose to use the specific wide character implementation of RegSetValueEx, RegSetValueExW.

Using (wcslen(executable) + 1) * sizeof(wchar_t) to calculate the length of executable for the final parameter.

The final code is below:

#include <iostream>
#include <Windows.h>

int addValuetoRegistryKey(LPCWSTR executable) {

    LPCWSTR registryKey = L"Software\\Classes\\mscfile\\shell\\open\\command\\";
    HKEY hiveHandle;
    HKEY keyHandle;

    if (RegOpenCurrentUser(KEY_SET_VALUE, &hiveHandle) != ERROR_SUCCESS) {

        wchar_t buf[256];
        FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
            buf, (sizeof(buf) / sizeof(wchar_t)), NULL);

        /* Display error */
        std::wcout << "Opening hive failed: " << buf << std::endl; 

        return -1;

    }
    else {

        std::wcout << "HKCU Hive opened successfully" << std::endl;

    }

    if (RegOpenKeyEx(hiveHandle, registryKey, 0, KEY_SET_VALUE, &keyHandle) != ERROR_SUCCESS) {

        wchar_t buf[256];
        FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
            buf, (sizeof(buf) / sizeof(wchar_t)), NULL);

        /* Display error */
        std::wcout << "Opening key failed: " << buf << std::endl;

        return -1;

    }
    else {

        std::wcout << registryKey << " opened successfully" << std::endl;

    }


    if (RegSetValueExW(keyHandle, NULL, 0, REG_SZ, (LPCBYTE) executable, (wcslen(executable) + 1) * sizeof(wchar_t)) != ERROR_SUCCESS) {

        wchar_t buf[256];
        FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
            buf, (sizeof(buf) / sizeof(wchar_t)), NULL);

        /* Display error */
        std::wcout << "Writing value to  key failed: " << buf << std::endl;

        return -1;
    }
    else {

        std::wcout << executable << " written to key" << std::endl;

    }

    RegCloseKey(keyHandle);
    RegCloseKey(hiveHandle);

    return 0;


}

int main() {

    addValuetoRegistryKey("C:\\Windows\\System32\\cmd.exe");

}

The value is now written to the registry correctly. Upon reading more of the Microsoft docs, the function RegSetKeyValueW was suggested. I have implemented this method, however, I wanted to work out how to do this correctly, and post here.

For anyone who stumbles upon this question, and would like an example of how to implement the RegSetKeyValueW function, you can find the code below:

if (RegSetKeyValueW(keyHandle, NULL, 0, REG_SZ, executable, (wcslen(executable) + 1) * sizeof(wchar_t)) != ERROR_SUCCESS) {

        wchar_t buf[256];
        FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
            buf, (sizeof(buf) / sizeof(wchar_t)), NULL);

        /* Display error */
        std::wcout << "Writing value to  key failed: " << buf << std::endl;

        return -1;
    }
    else {

        std::wcout << executable << " written to key" << std::endl;

    }

Upvotes: 1

Related Questions