ReactOS  0.4.13-dev-464-g6b95727
service.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS Local Spooler API Tests
3  * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE: Functions needed to run our code as a service. This is needed to run in SYSTEM security context.
5  * COPYRIGHT: Copyright 2015 Colin Finck (colin@reactos.org)
6  */
7 
8 #include <apitest.h>
9 
10 #define WIN32_NO_STATUS
11 #include <windef.h>
12 #include <winbase.h>
13 #include <wingdi.h>
14 #include <winreg.h>
15 #include <winsvc.h>
16 #include <winspool.h>
17 #include <winsplp.h>
18 #include <tlhelp32.h>
19 
20 #include "localspl_apitest.h"
21 
22 //#define NDEBUG
23 #include <debug.h>
24 
25 
26 static void
28 {
29  DWORD cbDLLPath;
31  HANDLE hSnapshot;
33  PROCESSENTRY32W pe;
34  PVOID pLoadLibraryAddress;
35  PVOID pLoadLibraryArgument;
36  PWSTR p;
37  WCHAR wszFilePath[MAX_PATH];
38 
39  // Get the full path to our EXE file.
40  if (!GetModuleFileNameW(NULL, wszFilePath, _countof(wszFilePath)))
41  {
42  DPRINT("GetModuleFileNameW failed with error %lu!\n", GetLastError());
43  return;
44  }
45 
46  // Replace the extension.
47  p = wcsrchr(wszFilePath, L'.');
48  if (!p)
49  {
50  DPRINT("File path has no file extension: %S\n", wszFilePath);
51  return;
52  }
53 
54  wcscpy(p, L".dll");
55  cbDLLPath = (wcslen(wszFilePath) + 1) * sizeof(WCHAR);
56 
57  // Create a snapshot of the currently running processes.
59  if (hSnapshot == INVALID_HANDLE_VALUE)
60  {
61  DPRINT("CreateToolhelp32Snapshot failed with error %lu!\n", GetLastError());
62  return;
63  }
64 
65  // Enumerate through all running processes.
66  pe.dwSize = sizeof(pe);
67  if (!Process32FirstW(hSnapshot, &pe))
68  {
69  DPRINT("Process32FirstW failed with error %lu!\n", GetLastError());
70  return;
71  }
72 
73  do
74  {
75  // Check if this is the spooler server process.
76  if (wcsicmp(pe.szExeFile, L"spoolsv.exe") != 0)
77  continue;
78 
79  // Open a handle to the process.
81  if (!hProcess)
82  {
83  DPRINT("OpenProcess failed with error %lu!\n", GetLastError());
84  return;
85  }
86 
87  // Get the address of LoadLibraryW.
88  pLoadLibraryAddress = (PVOID)GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "LoadLibraryW");
89  if (!pLoadLibraryAddress)
90  {
91  DPRINT("GetProcAddress failed with error %lu!\n", GetLastError());
92  return;
93  }
94 
95  // Allocate memory for the DLL path in the spooler process.
96  pLoadLibraryArgument = VirtualAllocEx(hProcess, NULL, cbDLLPath, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
97  if (!pLoadLibraryArgument)
98  {
99  DPRINT("VirtualAllocEx failed with error %lu!\n", GetLastError());
100  return;
101  }
102 
103  // Write the DLL path to the process memory.
104  if (!WriteProcessMemory(hProcess, pLoadLibraryArgument, wszFilePath, cbDLLPath, NULL))
105  {
106  DPRINT("WriteProcessMemory failed with error %lu!\n", GetLastError());
107  return;
108  }
109 
110  // Create a new thread in the spooler process that calls LoadLibraryW as the start routine with our DLL as the argument.
111  // This effectively injects our DLL into the spooler process and we can inspect localspl.dll there just like the spooler.
112  hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pLoadLibraryAddress, pLoadLibraryArgument, 0, NULL);
113  if (!hThread)
114  {
115  DPRINT("CreateRemoteThread failed with error %lu!\n", GetLastError());
116  return;
117  }
118 
120  break;
121  }
122  while (Process32NextW(hSnapshot, &pe));
123 }
124 
125 static DWORD WINAPI
126 _ServiceControlHandlerEx(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext)
127 {
128  return NO_ERROR;
129 }
130 
131 static void WINAPI
132 _ServiceMain(DWORD dwArgc, LPWSTR* lpszArgv)
133 {
136 
137  UNREFERENCED_PARAMETER(dwArgc);
138  UNREFERENCED_PARAMETER(lpszArgv);
139 
140  // Register our service for control.
142 
143  // Report SERVICE_RUNNING status.
147  ServiceStatus.dwWaitHint = 4000;
151 
152  // Do our funky crazy stuff.
153  _DoDLLInjection();
154 
155  // Our work is done.
158 }
159 
160 START_TEST(service)
161 {
162  int argc;
163  char** argv;
164 
166  {
168  { NULL, NULL }
169  };
170 
171  // This is no real test, but an easy way to integrate the service handler routines into the API-Test executable.
172  // Therefore, bail out if someone tries to run "service" as a usual test.
174  if (argc != 3)
175  return;
176 
177  // If we have exactly 3 arguments, we're run as a service, so initialize the corresponding service handler functions.
179 
180  // Prevent the testing framework from outputting a "0 tests executed" line here.
181  ExitProcess(0);
182 }
DWORD WINAPI GetModuleFileNameW(HINSTANCE hModule, LPWSTR lpFilename, DWORD nSize)
Definition: loader.c:607
static int argc
Definition: ServiceArgs.c:12
DWORD(WINAPI * LPTHREAD_START_ROUTINE)(LPVOID)
Definition: winbase.h:707
#define CloseHandle
Definition: compat.h:398
#define PROCESS_ALL_ACCESS
Definition: nt_native.h:1324
DWORD dwCurrentState
Definition: winsvc.h:100
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:323
uint16_t * PWSTR
Definition: typedefs.h:54
#define _countof(array)
Definition: fontsub.cpp:30
WCHAR szExeFile[MAX_PATH]
Definition: tlhelp32.h:58
static SERVICE_STATUS ServiceStatus
Definition: dcomlaunch.c:27
#define SERVICE_ACCEPT_STOP
Definition: winsvc.h:28
LPVOID NTAPI VirtualAllocEx(IN HANDLE hProcess, IN LPVOID lpAddress, IN SIZE_T dwSize, IN DWORD flAllocationType, IN DWORD flProtect)
Definition: virtmem.c:23
static void _DoDLLInjection()
Definition: service.c:27
#define INVALID_HANDLE_VALUE
Definition: compat.h:391
VOID WINAPI ExitProcess(IN UINT uExitCode)
Definition: proc.c:1517
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
_In_ BOOL _In_ HANDLE hProcess
Definition: mapping.h:70
DWORD dwServiceSpecificExitCode
Definition: winsvc.h:103
#define argv
Definition: mplay32.c:18
#define NO_ERROR
Definition: dderror.h:5
BOOL WINAPI StartServiceCtrlDispatcherW(const SERVICE_TABLE_ENTRYW *lpServiceStartTable)
Definition: sctrl.c:1123
#define MEM_COMMIT
Definition: nt_native.h:1313
DWORD th32ProcessID
Definition: tlhelp32.h:51
BOOL WINAPI SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus, LPSERVICE_STATUS lpServiceStatus)
Definition: sctrl.c:986
#define SERVICE_STOPPED
Definition: winsvc.h:21
static void WINAPI _ServiceMain(DWORD dwArgc, LPWSTR *lpszArgv)
Definition: service.c:132
#define MEM_RESERVE
Definition: nt_native.h:1314
#define SERVICE_RUNNING
Definition: winsvc.h:24
smooth NULL
Definition: ftsmooth.c:416
void DPRINT(...)
Definition: polytest.cpp:61
_Check_return_ _CRTIMP _CONST_RETURN wchar_t *__cdecl wcsrchr(_In_z_ const wchar_t *_Str, _In_ wchar_t _Ch)
BOOL WINAPI Process32FirstW(HANDLE hSnapshot, LPPROCESSENTRY32W lppe)
Definition: toolhelp.c:984
void * PVOID
Definition: retypes.h:9
#define SERVICE_WIN32_OWN_PROCESS
Definition: cmtypes.h:960
#define SERVICE_ACCEPT_SHUTDOWN
Definition: winsvc.h:30
__wchar_t WCHAR
Definition: xmlstorage.h:180
DWORD dwWaitHint
Definition: winsvc.h:105
#define MAX_PATH
Definition: compat.h:26
#define WINAPI
Definition: msvc.h:8
DWORD dwWin32ExitCode
Definition: winsvc.h:102
unsigned long DWORD
Definition: ntddk_ex.h:95
DWORD dwServiceType
Definition: winsvc.h:99
int winetest_get_mainargs(char ***pargv)
_CRTIMP wchar_t *__cdecl wcscpy(_Out_writes_z_(_String_length_(_Source)+1) wchar_t *_Dest, _In_z_ const wchar_t *_Source)
static const WCHAR L[]
Definition: oid.c:1250
BOOL WINAPI Process32NextW(HANDLE hSnapshot, LPPROCESSENTRY32W lppe)
Definition: toolhelp.c:1073
SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW(LPCWSTR lpServiceName, LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext)
Definition: sctrl.c:802
SERVICE_STATUS_HANDLE hServiceStatus
Definition: main.c:10
#define wcsicmp
Definition: string.h:1152
static SERVICE_TABLE_ENTRYW ServiceTable[2]
Definition: eventlog.c:24
DWORD dwControlsAccepted
Definition: winsvc.h:101
HANDLE WINAPI OpenProcess(IN DWORD dwDesiredAccess, IN BOOL bInheritHandle, IN DWORD dwProcessId)
Definition: proc.c:1257
#define SERVICE_NAME
Definition: wlansvc.c:18
#define TH32CS_SNAPPROCESS
Definition: tlhelp32.h:26
HANDLE hThread
Definition: wizard.c:27
HANDLE WINAPI CreateToolhelp32Snapshot(DWORD dwFlags, DWORD th32ProcessID)
Definition: toolhelp.c:1255
static DWORD WINAPI _ServiceControlHandlerEx(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext)
Definition: service.c:126
HMODULE WINAPI GetModuleHandleW(LPCWSTR lpModuleName)
Definition: loader.c:845
#define GetProcAddress(x, y)
Definition: compat.h:410
GLfloat GLfloat p
Definition: glext.h:8902
WCHAR * LPWSTR
Definition: xmlstorage.h:184
static SERVICE_STATUS_HANDLE(WINAPI *pRegisterServiceCtrlHandlerExA)(LPCSTR
size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
BOOL NTAPI WriteProcessMemory(IN HANDLE hProcess, IN LPVOID lpBaseAddress, IN LPCVOID lpBuffer, IN SIZE_T nSize, OUT SIZE_T *lpNumberOfBytesWritten)
Definition: proc.c:2086
START_TEST(service)
Definition: service.c:160
#define PAGE_READWRITE
Definition: nt_native.h:1304
HANDLE WINAPI CreateRemoteThread(IN HANDLE hProcess, IN LPSECURITY_ATTRIBUTES lpThreadAttributes, IN DWORD dwStackSize, IN LPTHREAD_START_ROUTINE lpStartAddress, IN LPVOID lpParameter, IN DWORD dwCreationFlags, OUT LPDWORD lpThreadId)
Definition: thread.c:133