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;
}