----------------------------------- Author: Chen Jingtao Source: CnXHacker.Net ------- ------------
Windows 2000 / XP and 2003, etc., which supports "service programs". The program is available as a service startup: (1) You can run it without logging in to the system. (2) Has the system privilege. So you are in progress Inside the manager, it is impossible to end it. The author has written the courseware upload and media service in 2003. Let's introduce how to create a service program with delphi7. Run Delphi7, select the menu File -> New -> Other ---> Service Application. The framework of a service program will be generated. Save the project as serviceDemo.dpr and unit_main.pas, then return to the main frame. We noticed that service has several properties. The following are our more common: (1) DisplayName: Service display name (2) name: Service name. We are here to change the value of DisplayName to "Delphi Service Demo", name change to "Delphiservice". Compiling this project will get servicesDemo.exe. This is already a service program! Enter the CMD mode, switch the project where the project is located, run the command "servicedeMo.exe / install", will prompt the service installation! Then "Net Start Delphiservice" Will start this service. Enter the Control Book -> Administrative Tools -> Services, will display this service and current status. But this service can't do anything now, because we have not written code :) First "Net Stop Delphiservice" Stop "ServiceDemo.exe / Uninstall" Delete this service. Back to Delphi7 IDE. Our plan is to add a main window for this service, run the taskbar display icon, double-click the icon will display the main window, there is one Buttons, click this button to implement Ctrl Alt Del function. In fact, the service program is not recognized by Winlogon desktop, you can open the control panel, see the properties of our service -> Login, where "Allow services Desktop interaction "is not hook. What should I do? Oh, return to IDE, pay attention to that Boolean properties: Interactive, when this property is TRUE, the service program can interact with the desktop. File -> new -> FORM Add window frmmain to the service, the unit is saved as Unit_FrmMain, and set this window to manually created. After the completion code As follows: unit Unit_Main; interfaceusesWindows, Messages, SysUtils, Classes, Graphics, Controls, SvcMgr, Dialogs, Unit_FrmMain; typeTDelphiService = class (TService) procedure ServiceContinue (Sender: TService; var Continued: Boolean); procedure ServiceExecute (Sender: TService); procedure ServicePause (Sender: TService; var Paused: Boolean); procedure ServiceShutdown (Sender: TService); procedure ServiceStart (Sender: TService; var Started: Boolean); procedure ServiceStop (Sender: TService; var Stopped: Boolean); private {Private Declarations} publicfunction getServiceController: tServiceController; Override; {public declarations}
varDelphiService: TDelphiService; FrmMain: TFrmMain; implementation {$ R * .DFM} procedure ServiceController (CtrlCode: DWord); stdcall; beginDelphiService.Controller (CtrlCode); end; function TDelphiService.GetServiceController: TServiceController; beginResult: = ServiceController; end; procedure TDelphiService.ServiceContinue (Sender: TService; var Continued: Boolean); beginwhile not Terminated dobeginSleep (10); ServiceThread.ProcessRequests (False); end; end; procedure TDelphiService.ServiceExecute (Sender: TService); beginwhile not Terminated dobeginSleep (10) ; ServiceThread.ProcessRequests (False); end; end; procedure TDelphiService.ServicePause (Sender: TService; var Paused: Boolean); beginPaused: = True; end; procedure TDelphiService.ServiceShutdown (Sender: TService); begingbCanClose: = true; frmMain .Free; Status: = csStopped; ReportStatus (); end; procedure TDelphiService.ServiceStart (Sender: TService; var Started: Boolean); beginStarted: = True; Svcmgr.Application.CreateForm (TFrmMain, frmMain); gbCanClose: = False; Frmmain .Hide; end; procedure TDelphiService.ServiceStop (Sender: TService; var Stopped: Boolean); beginStopped: = True; gbCanClose: = True; FrmMain.Free; end; end of the main window unit as follows:. Unit Unit_FrmMain; interfaceusesWindows, Messages, SysUtils, Variants, Classes, ShellApi, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls; constWM_TrayIcon = WM_USER 1234; typeTFrmMain = class (TForm) Timer1: TTimer; Button1: TButton; procedure FormCreate (Sender: TObject); procedure FormCloseQuery (Sender: TObject; var CanClose: Boolean); procedure FormDestroy (Sender: TObject); procedure Timer1Timer (Sender: TObject); procedure Button1Click (Sender: TObject); private {Private declarations} IconData: TNotifyIconData; procedure AddIconToTray;
procedure DelIconFromTray; procedure TrayIconMessage (var Msg: TMessage); message WM_TrayIcon; procedure SysButtonMsg (var Msg: TMessage); message WM_SYSCOMMAND; public {Public declarations} end; varFrmMain: TFrmMain; gbCanClose: Boolean; implementation {$ R * .dfm} procedure TFrmMain.FormCreate (Sender: TObject); beginFormStyle: = fsStayOnTop; {frontmost window} SetWindowLong (Application.Handle, GWL_EXSTYLE, WS_EX_TOOLWINDOW); {not the task bar} gbCanClose: = False; Timer1.Interval: = 1000; Timer1. Enabled: = True; end; procedure TFrmMain.FormCloseQuery (Sender: TObject; var CanClose: Boolean); beginCanClose: = gbCanClose; if not CanClose thenbeginHide; end; end; procedure TFrmMain.FormDestroy (Sender: TObject); beginTimer1.Enabled: = False; DelIconFromTray; end; procedure TFrmMain.AddIconToTray; beginZeroMemory (@IconData, SizeOf (TNotifyIconData)); IconData.cbSize: = SizeOf (TNotifyIconData); IconData.Wnd: = Handle; IconData.uID: = 1; IconData.uFlags : = Nif_message or nif_icon or nif_tip; icondata.ucallbackMessage: = WM_TRAYICON; ICONDATA.HICON : = Application.Icon.Handle; IconData.szTip: = 'Delphi service demonstration program'; Shell_NotifyIcon (NIM_ADD, @IconData); end; procedure TFrmMain.DelIconFromTray; beginShell_NotifyIcon (NIM_DELETE, @IconData); end; procedure TFrmMain.SysButtonMsg ( var Msg: TMessage); beginif (msg.wParam = SC_CLOSE) or (msg.wParam = SC_MINIMIZE) then Hideelse inherited; // default action end; procedure TFrmMain.TrayIconMessage (var Msg: TMessage); beginif (Msg.LParam = WM_LBUTTONDBLCLK) then Show (); end; procedure TFrmMain.Timer1Timer (Sender: TObject); beginAddIconToTray; end; procedure SendHokKey; stdcall; varHDesk_WL: HDESK; beginHDesk_WL: = OpenDesktop ( 'Winlogon', 0, False, DESKTOP_JOURNALPLAYBACK);
if (HDesk_WL <> 0) thenif (SetThreadDesktop (HDesk_WL) = True) thenPostMessage (HWND_BROADCAST, WM_HOTKEY, 0, MAKELONG (MOD_ALT or MOD_CONTROL, VK_DELETE)); end; procedure TFrmMain.Button1Click (Sender: TObject); vardwThreadID: DWORD; BegincreateThread (NIL, 0, @sendhokKKEY, NIL, 0, DWTHREADID); end; end. Supplement: (1) About more service programs, please visit the following URL: http://www.torry.net/pages .php? id = 226, the above contains a plurality of code that demonstrates how to control and manage system services. (2) Please remember: Windows actually exists multiple desktops. For example, the screen transmission will appear white screen, there may be two reasons: First, the system is locked or not logged in the desktop, and the other is in the screen to protect the desktop. At this time you have to switch the current desktop to the desktop. (3) About the service program and desktop interaction, there is a dynamic switching method. Probably unit as follows: unit ServiceDesktop; interfacefunction InitServiceDesktop: boolean; procedure DoneServiceDeskTop; implementationuses Windows, SysUtils; constDefaultWindowStation = 'WinSta0'; DefaultDesktop = 'Default'; varhwinstaSave: HWINSTA; hdeskSave: HDESK; hwinstaUser: HWINSTA; hdeskUser: HDESK; function InitServiceDesktop: boolean Vardwthreadid: DWORD; begindwthreadid: = getCurrentthReadId; // ensure connection to service window station and desktop, and // save their handles.hwinstasave: = getProcessWindowst ation; hdeskSave: = GetThreadDesktop (dwThreadId); hwinstaUser: = OpenWindowStation (DefaultWindowStation, FALSE, MAXIMUM_ALLOWED); if hwinstaUser = 0 thenbeginOutputDebugString (PChar ( 'OpenWindowStation failed' SysErrorMessage (GetLastError))); Result: = false; exit; end ; if not SetProcessWindowStation (hwinstaUser) thenbeginOutputDebugString ( 'SetProcessWindowStation failed'); Result: = false; exit; end; hdeskUser: = OpenDesktop (DefaultDesktop, 0, FALSE, MAXIMUM_ALLOWED); if hdeskUser = 0 thenbeginOutputDebugString ( 'OpenDesktop failed'); SetProcessWindowStation (HwinStasave); ClosewindowStation (HWInStause); Result: = false; exit; end; result: =
SetThreadDesktop (hdeskUser); if not Result thenOutputDebugString (PChar ( 'SetThreadDesktop' SysErrorMessage (GetLastError))); end; procedure DoneServiceDeskTop; begin // Restore window station and desktop.SetThreadDesktop (hdeskSave); SetProcessWindowStation (hwinstaSave); if hwinstaUser < .> 0 thenCloseWindowStation (hwinstaUser); if hdeskUser <> 0 thenCloseDesktop (hdeskUser); end; initializationInitServiceDesktop; finalizationDoneServiceDesktop; end of code more detailed presentation see: http: //www.torry.net/samples/samples/os/isarticle .zip (4) About the installation of how to add a service description. There are two ways: First, modify the registry. Details of the service are located in HKEY_LOCAL_MACHINE / System / Controlset001 / Services / below, for example, the service is located in hkey_local_machine / system / Controlset001 / Services / Delphiservice. The second method is to obtain service information first with QueryServiceConfig2 function, then ChangeServiceConfig2 changes the description. If implemented with Delphi, the unit is as follows: Unit Winsvcex; InterfaceUses Windows, Winsvc; Const /// Service Config Info levels // service_config_description = 1; service_config_failure_actions = 2; //// DLL Name of imported functions // advapidll = 'advapi32.dll'; type //// service Description STR ing // PServiceDescriptionA = ^ TServiceDescriptionA; PServiceDescriptionW = ^ TServiceDescriptionW; PServiceDescription = PServiceDescriptionA; {$ EXTERNALSYM _SERVICE_DESCRIPTIONA} _SERVICE_DESCRIPTIONA = recordlpDescription: PAnsiChar; end; {$ EXTERNALSYM _SERVICE_DESCRIPTIONW} _SERVICE_DESCRIPTIONW = recordlpDescription: PWideChar; end; {$ EXTERNALSYM _SERVICE_DESCRIPTION} _SERVICE_DESCRIPTION = _SERVICE_DESCRIPTIONA; {$ EXTERNALSYM SERVICE_DESCRIPTIONA} SERVICE_DESCRIPTIONA = _SERVICE_DESCRIPTIONA; {$ EXTERNALSYM SERVICE_DESCRIPTIONW} SERVICE_DESCRIPTIONW = _SERVICE_DESCRIPTIONW; {$ EXTERNALSYM SERVICE_DESCRIPTION} SERVICE_DESCRIPTION = _SERVICE_DESCRIPTIONA;
TServiceDescriptionA = _SERVICE_DESCRIPTIONA; TServiceDescriptionW = _SERVICE_DESCRIPTIONW; TServiceDescription = TServiceDescriptionA; //// Actions to take on service failure // {$ EXTERNALSYM _SC_ACTION_TYPE} _SC_ACTION_TYPE = (SC_ACTION_NONE, SC_ACTION_RESTART, SC_ACTION_REBOOT, SC_ACTION_RUN_COMMAND); {$ EXTERNALSYM SC_ACTION_TYPE} SC_ACTION_TYPE = _SC_ACTION_TYPE; PServiceAction = ^ TServiceAction; {$ EXTERNALSYM _SC_ACTION} _SC_ACTION = recordaType: SC_ACTION_TYPE; Delay: DWORD; end; {$ EXTERNALSYM SC_ACTION} SC_ACTION = _SC_ACTION; TServiceAction = _SC_ACTION; PServiceFailureActionsA = ^ TServiceFailureActionsA; PServiceFailureActionsW = ^ TServiceFailureActionsW; PServiceFailureActions = PServiceFailureActionsA; { $ EXTERNALSYM _SERVICE_FAILURE_ACTIONSA} _SERVICE_FAILURE_ACTIONSA = recorddwResetPeriod: DWORD; lpRebootMsg: LPSTR; lpCommand: LPSTR; cActions: DWORD; lpsaActions: ^ SC_ACTION; end; {$ EXTERNALSYM _SERVICE_FAILURE_ACTIONSW} _SERVICE_FAILURE_ACTIONSW = recorddwResetPeriod: DWORD; lpRebootMsg: LPWST R; lpCommand: LPWSTR; cActions: DWORD; lpsaActions: ^ SC_ACTION; end; {$ EXTERNALSYM _SERVICE_FAILURE_ACTIONS} _SERVICE_FAILURE_ACTIONS = _SERVICE_FAILURE_ACTIONSA; {$ EXTERNALSYM SERVICE_FAILURE_ACTIONSA} SERVICE_FAILURE_ACTIONSA = _SERVICE_FAILURE_ACTIONSA; {$ EXTERNALSYM SERVICE_FAILURE_ACTIONSW} SERVICE_FAILURE_ACTIONSW = _SERVICE_FAILURE_ACTIONSW; {$ EXTERNALSYM SERVICE_FAILURE_ACTIONS} SERVICE_FAILURE_ACTIONS = _SERVICE_FAILURE_ACTIONSA; TServiceFailureActionsA = _SERVICE_FAILURE_ACTIONSA; TServiceFailureActionsW = _SERVICE_FAILURE_ACTIONSW; TServiceFailureActions = TServiceFailureActionsA; ///// API Function Prototypes /// TQueryServiceConfig2 =
function (hService: SC_HANDLE; dwInfoLevel: DWORD; lpBuffer: pointer; cbBufSize: DWORD; var pcbBytesNeeded): BOOL; stdcall; TChangeServiceConfig2 = function (hService: SC_HANDLE; dwInfoLevel: DWORD; lpInfo: pointer): BOOL; stdcall; varhDLL: THandle ; LibLoaded: boolean; varOSVersionInfo: TOSVersionInfo; {$ EXTERNALSYM QueryServiceConfig2A} QueryServiceConfig2A: TQueryServiceConfig2; {$ EXTERNALSYM QueryServiceConfig2W} QueryServiceConfig2W: TQueryServiceConfig2; {$ EXTERNALSYM QueryServiceConfig2} QueryServiceConfig2: TQueryServiceConfig2; {$ EXTERNALSYM ChangeServiceConfig2A} ChangeServiceConfig2A: TChangeServiceConfig2; {$ EXTERNALSYM ChangeServiceConfig2W} ChangeServiceConfig2W: TChangeServiceConfig2; {$ EXTERNALSYM ChangeServiceConfig2} ChangeServiceConfig2: TChangeServiceConfig2; implementationinitializationOSVersionInfo.dwOSVersionInfoSize: = SizeOf (OSVersionInfo); GetVersionEx (OSVersionInfo); if (OSVersionInfo.dwPlatformId = VER_PLATFORM_WIN32_NT) and (OSVersionInfo.dwMajorVersion> = 5 ) Thenbeginif hDLL = 0 thenbeginhDLL: = GetModuleHandle (AdvApiDLL); LibLoaded: = False; if hDLL = 0 thenbeginhDLL: = LoadLibrary (AdvApiDLL); LibLoaded: = True; end; end; if hDLL <> 0 thenbegin @ QueryServiceConfig2A: = GetProcAddress (hDLL, 'QueryServiceConfig2A'); @ QueryServiceConfig2W: = GetProcAddress (hDLL, 'QueryServiceConfig2W'); @ QueryServiceConfig2: = @ QueryServiceConfig2A; @ ChangeServiceConfig2A: = GetProcAddress (hDLL, 'ChangeServiceConfig2A'); @ ChangeServiceConfig2W: = GetProcAddress (hDLL, ' ChangeServiceConfig2w '); @ ChangeServiceConfig2: = @ ChangeServiceConfig2a; End; endelsebegin @ queryserviceconfig2a: =
nil; @ QueryServiceConfig2W: = nil; @ QueryServiceConfig2: = nil; @ ChangeServiceConfig2A: = nil; @ ChangeServiceConfig2W: = nil; @ ChangeServiceConfig2: = nil; end; finalizationif (hDLL <> 0) and LibLoaded thenFreeLibrary (hDLL); end. unit winntService; interfaceusesWindows, WinSvc, WinSvcEx; function InstallService (const strServiceName, strDisplayName, strDescription, strFilename: string): Boolean; // eg: InstallService ( 'service name', 'display name', 'description', 'service files '); procedure UninstallService (strServiceName: string); implementationfunction StrLCopy (Dest: PChar; const Source: PChar; MaxLen: Cardinal): PChar; assembler; asmPUSH EDIPUSH ESIPUSH EBXMOV ESI, EAXMOV EDI, EDXMOV EBX, ECXXOR AL, ALTEST ECX, ECXJZ @@ 1REPNE SCASBJNE @@ 1INC ECX @@ 1: SUB EBX, ECXMOV EDI, ESIMOV ESI, EDXMOV EDX, EDIMOV ECX, EBXSHR ECX, 2REP MOVSDMOV ECX, EBXAND ECX, 3REP MOVSBSTOSBMOV EAX, EDXPOP EBXPOP ESIPOP EDIend; function StrPCopy ( DEST: PCHAR; Const Source: String): Pchar; BeginResult: = Strlcopy (DEST, PCHAR (SOURCE), Length (Source); End; Function InstallService erviceName, strDisplayName, strDescription, strFilename: string): Boolean; var // ss: TServiceStatus; // psTemp: PChar; hSCM, hSCS: THandle; srvdesc: PServiceDescription; desc: string; // SrvType: DWord; lpServiceArgVectors: pchar; beginResult: = False; // psTemp: = nil; // srvType: = SERVICE_WIN32_OWN_PROCESS and SERVICE_INTERACTIVE_PROCESS; hSCM: = OpenSCManager (nil, nil, SC_MANAGER_ALL_ACCESS); // connection service database if hSCM = 0 then Exit; // MessageBox (hHandle , PCHAR (SYSERRORMESSAGE (GetLasterror)), 'Server Manager', MB_ICONERROR MB_TOPMOST); HSCS: =
CreateService (// Create Service Function HSCM, // Service Control Handle PCHAR (STRSERVICENAME), // Service Name PCHAR (STRDISPLAYNAME), // Displayed Service Name Service_Access, // Access Service_WIN32_OWN_PROCESS or Service_INteractive_Process, // Service Type Service_win32_share_processService_Auto_Start, // Start Type Service_ERROR_IGNORE, / / Error Control Type PCHAR (STRFILENAME), // Server NIL, / Group Service Name NIL, // Group Identifier NIL, // Dependent Service NIL, // Start Service Account NIL ); // start the service password if hSCS = 0 then Exit; // MessageBox (hHandle, Pchar (SysErrorMessage (GetLastError)), Pchar (Application.Title), MB_ICONERROR MB_TOPMOST); if Assigned (ChangeServiceConfig2) thenbegindesc: = Copy ( strDescription, 1,1024); GetMem (srvdesc, SizeOf (TServiceDescription)); GetMem (srvdesc ^ .lpDescription, Length (desc) 1); tryStrPCopy (srvdesc ^ .lpDescription, desc); ChangeServiceConfig2 (hSCS, SERVICE_CONFIG_DESCRIPTION, srvdesc) ; finallyFreeMem (srvdesc ^ .lpDescription); FreeMem (srvdesc); end; end; lpServiceArgVectors: = nil; if not StartService (hSCS, 0, lpServiceArgVectors) then // start the service Exit; // MessageBox (hHandle, Pchar (SysErrorMessage ( GetLastError), PCHAR (AP plication.Title), MB_ICONERROR MB_TOPMOST); CloseServiceHandle (hSCS); // Close handle Result: = True; end; procedure UninstallService (strServiceName: string); varSCManager: SC_HANDLE; Service: SC_HANDLE; Status: TServiceStatus; beginSCManager: = OpenSCManager (nil, nil, SC_MANAGER_ALL_ACCESS); if SCManager = 0 then Exit; tryService: = OpenService (SCManager, Pchar (strServiceName), SERVICE_ALL_ACCESS); ControlService (Service, SERVICE_CONTROL_STOP, Status); DeleteService (Service); CloseServiceHandle (Service); finallyCloseServiceHandle (SCManager); end; end; end. (5) How violence closes a service program to implement the function of our previous "NT Toolbox"? First, in accordance with the process name to kill the process is the following functions: uses tlhelp32; function Killtask (ExefileName: String): integer; constprocess_terminate = $ 0001;
varContinueLoop: BOOL; FSnapshotHandle: THandle; FProcessEntry32: TProcessEntry32; beginResult: = 0; FSnapshotHandle: = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0); FProcessEntry32.dwSize: = SizeOf (FProcessEntry32); ContinueLoop: = Process32First (FSnapshotHandle, FProcessEntry32); while Integer ( ContinueLoop) <> 0 dobeginif ((UpperCase (ExtractFileName (FProcessEntry32.szExeFile)) = UpperCase (ExeFileName)) or (UpperCase (FProcessEntry32.szExeFile) = UpperCase (ExeFileName))) thenResult: = Integer (TerminateProcess (OpenProcess (PROCESS_TERMINATE, BOOL (0), FProcessEntry32.th32ProcessID), 0)); ContinueLoop: = Process32Next (FSnapshotHandle, FProcessEntry32); end; CloseHandle (FSnapshotHandle); end; but for service program, in fact, as long as it will prompt program have Debug "access Denied." permissions to: function EnableDebugPrivilege: Boolean; function enablePrivilege (hToken: Cardinal; PrivName: string; bEnable: Boolean): Boolean; varTP: TOKEN_PRIVILEGES; Dummy: Cardinal; beginTP.PrivilegeCount: = 1; LookupPrivilegeValue (nil, pchar (PrivName) , Tp.privileges [0] .luid); if Benable thentP. Privileges [0] .Attributes: = SE_PRIVILEGE_ENABLEDelse TP.Privileges [0] .Attributes: = 0; AdjustTokenPrivileges (hToken, False, TP, SizeOf (TP), nil, Dummy); Result: = GetLastError = ERROR_SUCCESS; end; varhToken: Cardinal; beginOpenProcessToken (GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES, hToken); result: = enablePrivilege (hToken, 'SeDebugPrivilege', True); CloseHandle (hToken); end; Usage: EnableDebugPrivilege; // elevated privileges KillTask ( 'xxxx.exe'); // Close the service program. (From http://blog.9cbs.net/flyhope2005)