AutoStartServiceRegistryKey uses native NT calls to create or open the registry key under HKLM\SYSTEM\CurrentControlSet\Services\MyService and sets the values needed to register a new Windows service that will auto-start at boot. No Windows Service API calls are used—only NtCreateKey and NtSetValueKey.
The code loads ntdll.dll and obtains pointers to RtlInitUnicodeString, NtCreateKey, NtSetValueKey, and NtClose. Then it builds the registry path "\Registry\Machine\System\CurrentControlSet\Services\MyService" into a UNICODE_STRING and initializes OBJECT_ATTRIBUTES.
// Load and resolve NT functions
HMODULE hNtdll = LoadLibraryA("ntdll.dll");
auto pRtlInitUnicodeString = (PFN_RtlInitUnicodeString)GetProcAddress(hNtdll, "RtlInitUnicodeString");
auto pNtCreateKey = (PFN_NtCreateKey) GetProcAddress(hNtdll, "NtCreateKey");
auto pNtSetValueKey = (PFN_NtSetValueKey) GetProcAddress(hNtdll, "NtSetValueKey");
// Initialize registry path
UNICODE_STRING regPath;
pRtlInitUnicodeString(®Path,
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\MyService");
// Build OBJECT_ATTRIBUTES
OBJECT_ATTRIBUTES objAttr;
InitializeObjectAttributes(&objAttr, ®Path, OBJ_CASE_INSENSITIVE, NULL, NULL);
A call to NtCreateKey with REG_OPTION_NON_VOLATILE opens or creates the key. The disposition flags indicate whether it was new or existing.
HANDLE hKey = NULL;
ULONG disposition = 0;
NTSTATUS status = pNtCreateKey(
&hKey,
KEY_ALL_ACCESS,
&objAttr,
0,
NULL,
REG_OPTION_NON_VOLATILE,
&disposition
);
if (!NT_SUCCESS(status)) {
// handle error
}
wprintf(L"Key created/opened; disposition: 0x%X\n", disposition);
Each service property—ImagePath, Type, Start, ErrorControl, and ObjectName—is written via NtSetValueKey. Notably, ImagePath uses REG_EXPAND_SZ so environment variables like %SystemRoot% expand at runtime.
// Helper to write a registry value
auto SetVal = [&](const wchar_t* name, ULONG type, const void* data, ULONG sz) {
UNICODE_STRING valueName;
pRtlInitUnicodeString(&valueName, name);
return pNtSetValueKey(hKey, &valueName, 0, type, (PVOID)data, sz);
};
// Define parameters
const wchar_t* img = L"%SystemRoot%\\System32\\myservice.exe";
DWORD svcType = 0x10; // SERVICE_WIN32_OWN_PROCESS
DWORD startAuto = 2; // SERVICE_AUTO_START
DWORD errCtrl = 1; // SERVICE_ERROR_NORMAL
// Set each value
SetVal(L"ImagePath", REG_EXPAND_SZ, &img, (wcslen(img)+1)*2);
SetVal(L"Type", REG_DWORD, &svcType, sizeof(svcType));
SetVal(L"Start", REG_DWORD, &startAuto, sizeof(startAuto));
SetVal(L"ErrorControl",REG_DWORD, &errCtrl, sizeof(errCtrl));
SetVal(L"ObjectName", REG_SZ, L"LocalSystem", (wcslen(L"LocalSystem")+1)*2);
int main() {
// 1. Resolve and init
HMODULE hNtdll = LoadLibraryA("ntdll.dll");
/* resolve RtlInitUnicodeString, NtCreateKey, NtSetValueKey, NtClose */
UNICODE_STRING regPath;
RtlInitUnicodeString(®Path, L"\\Registry\\Machine\\CurrentControlSet\\Services\\MyService");
OBJECT_ATTRIBUTES objAttr;
InitializeObjectAttributes(&objAttr, ®Path, OBJ_CASE_INSENSITIVE, NULL, NULL);
// 2. Create/open key
HANDLE hKey; ULONG disp;
NTSTATUS s = NtCreateKey(&hKey, KEY_ALL_ACCESS, &objAttr,
0, NULL, REG_OPTION_NON_VOLATILE, &disp);
// 3. Write values
SetVal(L"ImagePath", REG_EXPAND_SZ, L"%SystemRoot%\\System32\\myservice.exe", (wcslen(img)+1)*2);
SetVal(L"Type", REG_DWORD, &svcType, sizeof(svcType));
SetVal(L"Start", REG_DWORD, &startAuto, sizeof(startAuto));
SetVal(L"ErrorControl",REG_DWORD, &errCtrl, sizeof(errCtrl));
SetVal(L"ObjectName", REG_SZ, L"LocalSystem", (wcslen(L"LocalSystem")+1)*2);
NtClose(hKey);
return 0;
}