AutoStartServiceRegistryKey [source]

Overview

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.

Detailed Breakdown & In-Depth Snippets

1. Resolving NT API & Preparing OBJECT_ATTRIBUTES

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

2. Creating/Open­ing the Service Key

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

3. Setting Service Configuration Values

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

Full Key Snippet

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