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?
Copyright Notice:Content Author:「Ballers」,Reproduced under the CC 4.0 BY-SA copyright license with a link to the original source and this disclaimer.
Link to original article:https://stackoverflow.com/questions/63836256/copying-bytes-from-memory-to-char-array-then-writing-the-bytes-to-a-registry-key