I am trying to create a registry key with type REG_SZ and with a value longer than 4 chars.
But I can't figure out the right way to pass the data as argument :
#include <windows.h>
#include <stdio.h>
HKEY OpenKey(HKEY hRootKey, wchar_t* strKey)
{
HKEY hKey;
LONG nError = RegOpenKeyEx(hRootKey, strKey, 0, KEY_ALL_ACCESS, &hKey);
if (nError == ERROR_FILE_NOT_FOUND)
{
printf("Debug: Creating registry key\n");
nError = RegCreateKeyEx(hRootKey, strKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL);
}
if (nError) {
printf("Error: Could not find or create\n");
}
return hKey;
}
void SetValSZ(HKEY hKey, LPCTSTR lpValue, LPCTSTR data)
{
LONG nError = RegSetValueEx(hKey, lpValue, 0, REG_SZ, (const BYTE*) data, sizeof(data));
if (nError)
printf("Error: Could not set registry value\n");
}
int main()
{
HKEY hKey = OpenKey(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Policies\\Microsoft\\FVE");
const wchar_t data[] = L"AAAABBBBCCCC";
SetValSZ(hKey, L"RecoveryKeyMessage", data);
RegCloseKey(hKey);
return 0;
}
When I run it, only the first 4 characters are saved.
I must have a type mistake...
Do you have any idea to help me to fix it ?
Thank you.
PS: I hope my english is clear enoth, feel free to ask me more if it isn't.
void SetValSZ(HKEY hKey, LPCTSTR lpValue, LPCTSTR data)
{
RegSetValueEx(hKey, lpValue, 0, REG_SZ, (const BYTE*) data, sizeof(data));
}
data is being passed as a pointer to a function, so its actual size will be lost. sizeof(data) is translated to the size of a pointer, which is 4 bytes in this case.
You have to either pass in the size as a parameter:
int len = sizeof(data);
SetValSZ(..., data, len);
Or better yet, use wcslen() to calculate the string length, then multiply that by sizeof(wchar_t).
Since you are using those T macros, the function can be written as:
RegSetValueEx(hKey,lpValue,0,REG_SZ,(const BYTE*)data,sizeof(TCHAR)*(lstrlen(data) + 1));
Edit: The size should also include the terminating null character
Related
I am having an issue with my project where I am attempting to copy a structure from memory.
Copying the structure into a char array and writing the bytes in the char array to a registry key of type REG_BINARY
Here is the code so far, I am using RtlCopyMemory to achieve copying the bytes from memory:
VOID ReadVirtualMem(ULONG32 address, PVOID buffer, SIZE_T size)
{
PEPROCESS Process;
if (NT_SUCCESS(PsLookupProcessByProcessId((HANDLE)ProcessID, &Process)))
{
KAPC_STATE apc_state;
KeStackAttachProcess(Process, &apc_state);
if (MmIsAddressValid((PVOID)address) && MmIsAddressValid((PVOID)(address + size)))
{
RtlCopyMemory(buffer, (PVOID)address, size);
}
KeUnstackDetachProcess(&apc_state);
}
}
The above code will take in a vew parameters, address of the location I need reading from, buffer aka output the bytes need to be stored in, and the amount of bytes I want copied.
So here is how I am obtaining the bytes from memory:
struct PlayerInformation {
float Position;
int Points;
float Speed;
};
struct PlayerInformation PlayerInfo;
ReadVirtualMem(ReadAddress, &PlayerInfo, size);
I then cast this information to a PVOID data type so I can write this to the registry key like so:
PVOID Buffer;
memcpy(&Buffer, &PlayerInfo, sizeof(struct PlayerInfo));
status = WriteToKey(L"\\Registry\\Machine\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", L"Bytes", REG_BINARY, Buffer, size);
if (!NT_SUCCESS(status))
return STATUS_UNSUCCESSFUL;
The following above code works just fine for 8 bytes only. I believe this is due to PVOID only having a size of 8 bytes.
Here is my code for writing to the registry key:
NTSTATUS WriteToKey(PWSTR registry_path, PWSTR value_name, ULONG type, PVOID data, ULONG length)
{
UNICODE_STRING valname;
UNICODE_STRING keyname;
OBJECT_ATTRIBUTES attribs;
HANDLE handle;
NTSTATUS rc;
ULONG result;
RtlInitUnicodeString(&valname, registry_path);
RtlInitUnicodeString(&keyname, value_name);
InitializeObjectAttributes(&attribs, &valname, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
rc = ZwCreateKey(&handle, KEY_ALL_ACCESS, &attribs, 0, NULL, REG_OPTION_VOLATILE, &result);
if (!NT_SUCCESS(rc))
return STATUS_UNSUCCESSFUL;
rc = ZwSetValueKey(handle, &keyname, 0, type, &data, length);
if (!NT_SUCCESS(rc))
STATUS_UNSUCCESSFUL;
return STATUS_SUCCESS;
}
My question is how would I be able to take the data copied from RtlCopyMemory into a structure, turn that structure into a char array and write this data to the registry key path.
In c++ its as easy as this:
unsigned char b[sizeof(PlayerInfo)];
std::cout << "Size of structure: " << sizeof(PlayerInfo) << "\n\n";
memcpy(b, &PlayerInfo, sizeof(PlayerInfo));
HKEY handle;
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", 0, KEY_WRITE, &handle) == ERROR_SUCCESS)
{
RegSetValueEx(handle, L"Bytes", 0, REG_BINARY, (BYTE*)&b, sizeof(b));
But C has no data type for BYTE* so I am just a bit confused on how I could go on about taking this C++ function, which works perfectly, and implementing it into C code to work the exact same way as the C++ function.
If you need any other details I will be more than gladly to give you the information.
Thanks in advance!
EDIT: So I edited my function to accept the PlayerInfo struct as an argument and now all the data is read correctly.
Here is the updated code:
NTSTATUS WriteToBytes(PWSTR registry_path, PWSTR value_name, ULONG type, struct PlayerInfo data, ULONG length)
{
UNICODE_STRING valname;
UNICODE_STRING keyname;
OBJECT_ATTRIBUTES attribs;
HANDLE handle;
NTSTATUS rc;
ULONG result;
RtlInitUnicodeString(&valname, registry_path);
RtlInitUnicodeString(&keyname, value_name);
InitializeObjectAttributes(&attribs, &valname, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
rc = ZwCreateKey(&handle, KEY_ALL_ACCESS, &attribs, 0, NULL, REG_OPTION_VOLATILE, &result);
if (!NT_SUCCESS(rc))
return STATUS_UNSUCCESSFUL;
rc = ZwSetValueKey(handle, &keyname, 0, type, &data, length);
if (!NT_SUCCESS(rc))
STATUS_UNSUCCESSFUL;
return STATUS_SUCCESS;
}
This works well, no errors from what I can see. does anyone know why this works? And not passing a void* to the original write key function?
I am getting More data is available error with the GetComputerNameEx function, but no idea how to fix it.
This is my code:
int wmain()
{
COMPUTER_NAME_FORMAT nameType = ComputerNameDnsFullyQualified;
WCHAR computerName[MAX_COMPUTERNAME_LENGTH + 1];
DWORD size = ARRAYSIZE(computerName);
BOOL pcName = GetComputerNameEx(nameType, computerName, &size);
DWORD error = GetLastError();
if (pcName != 0)
{
wprintf("Computer name: %s\n", computerName);
}
else
{
wprintf(L"Error getting the name. Code: %li\n", error);
}
return 0;
}
No idea how to set size variable as output so I can declare the computerName array correctly.
You have to call the function twice; once with a null pointer to get the required size, and again with a buffer of (at least) the specified size. As the docs say:
To ensure that this buffer is large enough, set this parameter to NULL
and use the required buffer size returned in the lpnSize parameter.
This is a common pattern for Win32 functions. And yes, it does lead to a possible race condition, but that's just how it works.
Example
DWORD dwSize = 0;
if (GetComputerNameEx(nameType, nullptr, &dwSize))
{
WCHAR* computerName;
computerName = (WCHAR*)malloc(dwSize * sizeof(WCHAR));
if (GetComputerNameEx(nameType, computerName, &dwSize))
{
// use the name
}
free(computerName); // don't forget to free
}
Per the GetComputerNameEx() documentation:
lpBuffer [out]
A pointer to a buffer that receives the computer name or the cluster virtual server name.
The length of the name may be greater than MAX_COMPUTERNAME_LENGTH characters because DNS allows longer names. To ensure that this buffer is large enough, set this parameter to NULL and use the required buffer size returned in the lpnSize parameter.
lpnSize [in, out]
On input, specifies the size of the buffer, in TCHARs. On output, receives the number of TCHARs copied to the destination buffer, not including the terminating null character.
If the buffer is too small, the function fails and GetLastError returns ERROR_MORE_DATA. This parameter receives the size of the buffer required, including the terminating null character.
If lpBuffer is NULL, this parameter must be zero.
For example:
int wmain()
{
COMPUTER_NAME_FORMAT nameType = ComputerNameDnsFullyQualified;
WCHAR *computerName = NULL, *computerNameNew;
DWORD size = 0;
BOOL pcName;
DWORD error;
do
{
pcName = GetComputerNameExW(nameType, computerName, &size);
if (pcName) break;
error = GetLastError();
if (error != ERROR_MORE_DATA) break;
computerNameNew = (WCHAR*) realloc(computerName, sizeof(WCHAR) * size);
if (!computerNameNew) {
error = ERROR_OUTOFMEMORY;
break;
}
computerName = computerNameNew;
}
while (1);
if (pcName)
{
wprintf("Computer name: %s\n", computerName);
}
else
{
wprintf(L"Error getting the name. Code: %ul\n", error);
}
free(computerName);
return 0;
}
That error means that the GetComputerNameEx function needs a larger buffer to store the returned string.
To avoid the race condition cited in Jonathan Potter's answer, you could do something like this:
LONG error = ERROR_MORE_DATA;
WCHAR* buffer = NULL;
DWORD bufferLength = /* Some initial reasonable length for the string buffer */;
while (error == ERROR_MORE_DATA) {
// Create a buffer with bufferLength size (measured in WCHARs)
buffer = realloc(buffer, bufferLength * sizeof(WCHAR));
if (GetComputerNameEx(nameType, buffer, &bufferLength)) {
error = ERROR_SUCCESS;
} else {
error = GetLastError();
}
}
if (error != ERROR_SUCCESS) {
// Some error occurred
...
}
// Use buffer containing computer name
// Don't forget to free(buffer)
I am trying to show a single value's name using RegEnumValue (I can use RegGetValue, but i'm trying to learn how to use the RegEnumValue function), but I'm getting the error code 87, "The parameter is incorrect".
Here's my code:
int wmain()
{
//RegOpenKeyEx
HKEY hKey = HKEY_CURRENT_USER;
LPCWSTR subKey = L"WinSide";
DWORD options = 0;
REGSAM samDesired = KEY_QUERY_VALUE;
HKEY pkOpenResult;
//RegEnumValue
DWORD index = 0;
WCHAR valueName[16383];
LPWSTR pValueName = valueName;
DWORD size=sizeof(valueName);
DWORD reserved = NULL;
DWORD type;
WCHAR data[255];
LPWSTR pData=data;
DWORD sizeData = sizeof(data);
LONG openKey = RegOpenKeyEx(hKey, subKey, options, samDesired, &pkOpenResult);
if (openKey != ERROR_SUCCESS)
{
wprintf(L"Error opening the key. Code: %li\n");
}
else
{
wprintf(L"Key opened!\n");
LONG enumValue = RegEnumValue(pkOpenResult, index, pValueName, &size,
&reserved, &type, pData, &sizeData);
if (enumValue != ERROR_SUCCESS)
wprintf(L"Error code: %li\n", enumValue);
else
{
wprintf(L"Going to show the value's name here!");
}
RegCloseKey(pkOpenResult);
}
return 0;
}
What am I doing wrong?
So sorry for any mistake.
lpReserved must be NULL as stated in the documentation. You pass a non-null value. That is the reason for the failure. Remove the reserved variable and simply pass NULL for lpReserved.
The lpcchValueName argument specifies characters rather than bytes. You pass the number of bytes in error. That mistake won't necessarily hurt you now but there is a buffer overrun error in the making there so you do need to fix it.
I'm implementing an iterator to go over the records from a Berkeley DB. However, it seems I need to set the DB_DBT_USERMEM flag before the call to cursor->get with DB_NEXT.
Doing it that way would make my iterator less cohesive and will have to implement multiple iterators for each data type I want to retrieve.
Is there a way to have a generic iterator that can traverse structures w/o pointers, and basic data types? Here's what I'm trying to achieve.
#include <stdio.h>
#include <string.h>
#include <db.h>
// let this function handle integers and use DB_DBT_USERMEM for memory alignment
void integer_items(DBT key, DBT data) {
int number = 0;
data.data = &number;
data.flags = DB_DBT_USERMEM;
data.ulen = sizeof(int);
printf("key is: %s, data is: %d\n", (char *) key.data,number);
}
// let this function handle pointer structs. No need for DB_DBT_USERMEM
void ptr_struct_items(DBT key, DBT data) {
// MY_STRUCT user;
// marshall struct...
// buffsize = sizeof(int) +(strlen(user.familiar_name) + strlen(user.surname) + 2);
// databuff = malloc(buffsize);
// memset(databuff, 0, buffsize);
// ...
// printf("key is: %s, data is: %d\n", (char *) key.data,number);
}
int iterator(DB *database, void(*function)(DBT key, DBT data)) {
DBT key, data;
DBC *cursor;
memset(&key, 0, sizeof(DBT));
memset(&data, 0, sizeof(DBT));
database->cursor(database, NULL, &cursor, 0);
while(cursor->c_get(cursor, &key, &data, DB_NEXT) == 0){
(*function)(key, data);
}
cursor->c_close(cursor);
return 0;
}
int main() {
DB_ENV *myEnv;
DB *dbp;
DBT key, data;
int r, v = 10;
char *k = "Test";
db_env_create(&myEnv, 0);
myEnv->open(myEnv, "./", DB_CREATE | DB_INIT_MPOOL, 0);
db_create(&dbp, myEnv, 0);
dbp->open(dbp, NULL, "test.db", NULL, DB_HASH, DB_CREATE, 0664);
memset(&key, 0, sizeof(key));
memset(&data, 0, sizeof(data));
key.data = k;
key.size = strlen(k) +1;
data.data = &v;
data.size = sizeof(int);
if((r=dbp->put(dbp, NULL, &key, &data, 0)!=0))
fprintf(stderr, "%s\n", db_strerror(r));
iterator(dbp, integer_items);
iterator(dbp, ptr_struct_items);
return 0;
}
You almost always want to use DB_DBT_USERMEM, if only to avoiding the malloc() from inside BDB for DB_DBT_MALLOC/REALLOC. When you use it, you must pass in your own memory large enough to hold the largest item in your database. This holds for the key DBT too, as you may want to use it there.
In your example, as the key and data are so small, I'd just put character arrays on the stack in your "iterator" function, and then initialize key and data after the call to memset(). What you've got above is wrong because you're setting USERMEM after the call to c_get().
Here's a reworked example that gives BDB 256 bytes to work with for key and data.
void integer_items(DBT key, DBT data) {
int number = 0;
if (data.size == sizeof number) {
number = *(int *)data.data;
printf("key is: %s, data is: %d\n", (char *) key.data, number);
}
}
int iterator(DB *database, void(*function)(DBT key, DBT data)) {
DBT key, data;
DBC *cursor;
char kmem[256];
char dmem[256];
memset(&key, 0, sizeof(DBT));
memset(&data, 0, sizeof(DBT));
key.flags = DB_DBT_USERMEM;
key.data = kmem;
key.ulen = sizeof kmem;
data.flags = DB_DBT_USERMEM;
data.data = dmem;
data.ulen = sizeof dmem;
database->cursor(database, NULL, &cursor, 0);
while(cursor->c_get(cursor, &key, &data, DB_NEXT) == 0){
(*function)(key, data);
}
cursor->c_close(cursor);
return 0;
}
To handle different structures inside your iterator, include the data type as part of the key somehow. For example, instead of a bare integer for the key, use a struct, and have the first character define which kind of type it is. Then, inside your iterator function, you can switch on that.
I'm having a bit of a problem with the following code. I've seen tons of examples for using InternetReadFile to save to a file. But I cant find one, or get it to work for a char[]. I want to add the szBuffer up to get holdBuff, and then set content equal to holdBuff.
#include <stdio.h>
#include <tchar.h>
#include <string.h>
#include <windows.h>
#include <WinInet.h>
HINTERNET hSession;
void urlToChar(char* url, char** content);
int main()
{
hSession = InternetOpen("Mozilla/4.0 (compatible) Poison", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
char* content;
urlToChar("http://google.com/", &content);
printf("%s",content);
return 0;
}
void urlToChar(char* url, char** content)
{
HINTERNET hConnect = InternetConnect(hSession, _T(""),INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1);
HINTERNET hRequest = InternetOpenUrl(hSession, url, NULL, 0, 0, 0);
if (hRequest)
{
char holdBuff[] = "";
char szBuff[1025];
memset(szBuff, 0x00, sizeof(szBuff));
DWORD bytesRead;
while (InternetReadFile(hRequest, szBuff, 1024, &bytesRead) == TRUE && bytesRead > 0)
{
// Cat szBuff to holdBuff
memset(szBuff, 0x00, sizeof(szBuff));
}
*content = holdBuff;
// memset(holdBuff, 0x00, sizeof(holdBuff)); <-- Need this?
}
InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
}
The variable declaration
char xyz[] = "Hello World!";
will tell the compiler to put the contents of the string on the stack. Of course, the stack goes away when your function returns.
So in your case:
char holdBuff[] = "";
...
*content = holdBuff;
This tells the compiler to create a string of length one (the NULL terminator) as a local variable. Just because you've set the value of content to holdBuff doesn't mean that what holdBuff was pointing exists anymore.
You have to correct two things. Firstly, you must use strcpy() or similar function. Second, you must allocate sufficient space for holdBuff.
Example:
char holdBuff[4096]; // or some other sufficiently large size
...
*content = malloc (strlen(holdBuff) + 1);
strcpy (*content, holdBuff);
You'll then need to free(content) in main() once you're finished with it.
Now, for how to actually do the concatenation: Your performance will be much better if you forget about using szBuff at all and just write directly to holdBuff.
char* temp = holdBuff;
while (InternetReadFile(hRequest, temp, 1024, &bytesRead) == TRUE && bytesRead > 0)
{
temp += bytesRead;
}
*temp = '\0'; // manually append NULL terminator
Now holdBuff will have the data you want with no need for intermediary concatenation.
void urlToChar(char* url, char** content)
{
HINTERNET hConnect = InternetConnect(hSession, _T(""),INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1);
HINTERNET hRequest = InternetOpenUrl(hSession, url, NULL, 0, 0, 0);
if (hRequest)
{
char holdBuff[] = ""; //do not use fixed size char array and allocate buffer in stack,you can allocate large enough buffer in heap,but recommend you can use string or CString
char szBuff[1025];
memset(szBuff, 0x00, sizeof(szBuff));
DWORD bytesRead;
while (InternetReadFile(hRequest, szBuff, 1024, &bytesRead) == TRUE && bytesRead > 0)
{
// Cat szBuff to holdBuff
//strcat when using char array
// operator+ when using stl string
// [stl string][1]
memset(szBuff, 0x00, sizeof(szBuff));
}
*content = holdBuff;
// memset(holdBuff, 0x00, sizeof(holdBuff)); <-- Need this?
}
InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
}