Обмен данными с сервисом на Vista+

Тема в разделе "WASM.X64", создана пользователем Marylin, 11 фев 2026.

Метки:
  1. Marylin

    Marylin Active Member

    Публикаций:
    0
    Регистрация:
    17 фев 2023
    Сообщения:
    295
    Всем привет!
    Пишу службу/сервис для Win7, и юм-софт для управления им.
    Вроде всё ок, CreateService() создаёт, а ControlService() отправляет коды управления службе.
    Только непонятно, какими средствами можно организовать обратный канал связи от службы к моему приложению, чтобы я мог получить запрошенную инфу. Прежние IPC типа Pipe/MailSlot/Socket вроде не работаю начиная с Vista, а что тогда осталось?

    Где-то советуют RDP, но это слишком громоздко получается, т.к. почти на всех машинах этот протокол отключён, и нужно включать его глобально через реестр с последующим ребутом. Так-ли всё плохо на самом деле?

     
    Последнее редактирование: 11 фев 2026
  2. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    4.207
    Тимур, а почему не работают? Все примеры в Межпроцессные взаимодействия были написаны под Win8 и Win10
     
  3. Application

    Application Active Member

    Публикаций:
    1
    Регистрация:
    15 окт 2022
    Сообщения:
    156
    Код легко конвертируется в Си в любом даже самом всратом gpt. Имхо, лучше чем сокеты.
    Код (Text):
    1. //---
    2.  
    3. const
    4.   str_len = 16384;
    5.  
    6. var
    7.   Terminated: bool;
    8.   hProcess, hThread: THandle;
    9.  
    10. var
    11.   hPipeInputRead, hPipeInputWrite: THandle;
    12.   hPipeOutputRead, hPipeOutputWrite: THandle;
    13.  
    14. //---  
    15.  
    16. function IsPipeOpen(hPipe: THandle): Boolean;
    17. begin
    18.   Result := (GetFileType(hPipe) = FILE_TYPE_PIPE);
    19. end; //IsPipeOpen
    20.  
    21. procedure NotifyThread;
    22. begin
    23.   Terminated := false;
    24.   WaitForSingleObject(hProcess, INFINITE);
    25.   Writeln('Process stoped.');
    26.   Terminated := true;
    27.   CloseHandle(hThread);
    28. end; //NotifyThread
    29.  
    30. procedure StartNotifyThread;
    31. var
    32.   ThreadId: Cardinal;
    33. begin
    34.   hThread := CreateThread(nil, 0, @NotifyThread, nil, 0, ThreadId);
    35. end; //StartNotifyThread
    36.  
    37. //---
    38.  
    39. function StartProcess(current_file: string): bool;
    40. var
    41.   s: string;
    42.   StartupInfo: TStartupInfo;
    43.   ProcessInformation: TProcessInformation;
    44.   SecurityAttributes: TSecurityAttributes;
    45. begin
    46.   Result := true;
    47.  
    48.   Writeln('Process started.');
    49.  
    50.   ZeroMemory(@StartupInfo, SizeOf(TStartupInfo));
    51.   ZeroMemory(@ProcessInformation, SizeOf(TProcessInformation));
    52.  
    53.   ZeroMemory(@SecurityAttributes, SizeOf(TSecurityAttributes));
    54.  
    55.   SecurityAttributes.nLength := SizeOf(TSecurityAttributes);
    56.   SecurityAttributes.lpSecurityDescriptor := nil;
    57.   SecurityAttributes.bInheritHandle := True;
    58.  
    59.   CreatePipe(hPipeInputRead, hPipeInputWrite, @SecurityAttributes, 0);
    60.   CreatePipe(hPipeOutputRead, hPipeOutputWrite, @SecurityAttributes, 0);
    61.  
    62.   StartupInfo.cb := SizeOf(TStartupInfo);
    63.   StartupInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
    64.   StartupInfo.wShowWindow := SW_HIDE;
    65.   StartupInfo.hStdInput := hPipeInputRead;
    66.   StartupInfo.hStdOutput := hPipeOutputWrite;
    67.   StartupInfo.hStdError := hPipeOutputWrite;
    68.  
    69.   s := format('python "%s"', [current_file]);
    70.  
    71.   if CreateProcess(nil, PChar(s), nil, nil,
    72.                    true, CREATE_NEW_CONSOLE, nil, nil, StartupInfo,
    73.                    ProcessInformation) then
    74.   begin
    75.     hProcess := ProcessInformation.hProcess;
    76.     StartNotifyThread;
    77.   end
    78.   else
    79.   begin
    80.     Result := false;
    81.   end;
    82. end; //StartProcess
    83.  
    84. function GetPipeInfo: string;
    85. var
    86.   BytesCount: Cardinal;
    87.   Buffer: array [0..str_len] of Char;
    88. begin
    89.   Result := '';
    90.   if IsPipeOpen(hPipeOutputRead) then
    91.   begin
    92.     if ReadFile(hPipeOutputRead, Buffer, SizeOf(Buffer), BytesCount, nil) then
    93.     begin
    94.       if BytesCount > 0 then
    95.       begin
    96.         OemToAnsiBuff(Buffer, Buffer, BytesCount);
    97.         Result := Copy(Buffer, 1, BytesCount);
    98.       end;
    99.     end;
    100.   end;
    101. end; //GetPipeInfo
    102.  
    103. procedure SetPipeInfo(s: string);
    104. const
    105.   br = #13#10;
    106. var
    107.   BytesCount: Cardinal;
    108.   Buffer: array [0..str_len] of Char;
    109. begin
    110.   if Length(s) + 2 < str_len then
    111.   begin
    112.     StrPCopy(Buffer, s + br);
    113.     if IsPipeOpen(hPipeInputWrite) then
    114.     begin
    115.       WriteFile(hPipeInputWrite, Buffer, Length(s) + 2, BytesCount, nil);
    116.     end;
    117.   end;
    118. end; //SetPipeInfo
    119.  
    120. procedure StopThread; //
    121. begin
    122.   TerminateProcess(hProcess, 255);
    123.   WaitForSingleObject(hProcess, INFINITE);
    124.   CloseHandle(hProcess);
    125.   CloseHandle(hPipeInputWrite);
    126.   CloseHandle(hPipeInputRead);
    127.   CloseHandle(hPipeOutputWrite);
    128.   CloseHandle(hPipeOutputRead);
    129. end; //StopThread
    130.  
    131. //---
    132.  
    Код (Text):
    1. procedure ReadThreadProc;
    2. var
    3.   s: string;
    4. begin
    5.   while not Terminated do
    6.   begin
    7.     s := GetPipeInfo;
    8.     if s <> '' then
    9.     begin
    10.       WritelnRus(s);
    11.       //FormMain.MemoConsole.Text := FormMain.MemoConsole.Text + s;
    12.       //Application.ProcessMessages;
    13.     end;
    14.     Sleep(100);
    15.   end;
    16. end; //ReadThreadProc
    17.  
    18. procedure StartPipeRead;
    19. var
    20.   ThreadId: Cardinal;
    21. begin
    22.   CreateThread(nil, 0, @ReadThreadProc, nil, 0, ThreadId);
    23. end; //StartPipeRead
    24.  
    25.   if StartProcess('!___Run.py') then
    26.   begin
    27.     StartPipeRead;
    28.   end;
    29.  
    30.   //SetPipeInfo('html_code');
    31.  
    32.   Readln(s);
    33.   if s <> '' then
    34.   begin
    35.     SetPipeInfo(s);
    36.   end;
    Код (Text):
    1. # start.py
    2. print("test str")
    3.  
    4. run = True
    5.  
    6. while run:
    7.     # Получение данных от main.py
    8.     data = input('start.py -> Enter data: ')
    9.  
    10.     # Обработка данных и генерация ответа
    11.     response = f"start.py -> Hi, you enter: {data}"
    12.  
    13.     if data == "111":
    14.         run = False
    15.         print("Exit")
    16.     else:
    17.         # Передача ответа обратно в main.py
    18.         print(response)
    19.  
     
    Последнее редактирование: 11 фев 2026
    Mikl___ и Marylin нравится это.
  4. Marylin

    Marylin Active Member

    Публикаций:
    0
    Регистрация:
    17 фев 2023
    Сообщения:
    295
    Mikl___, это внутри одной пользовательской сессии(1+), а я говорю про обмен со службой в закрытой сессии(0).
     
    Mikl___ нравится это.
  5. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    4.207
    Marylin,
    я так глубоко не копал, извини, Тимур :)
     
    Marylin нравится это.
  6. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.351
    Здесь речь идет только об оконных сообщениях, пайпы (неименованные) и сокеты будут работать.
     
    Marylin нравится это.
  7. youneuoy

    youneuoy New Member

    Публикаций:
    0
    Регистрация:
    7 сен 2020
    Сообщения:
    11
    делай объект в пространстве имён Global и или подключайся из той 0 сессии или устанавливай соответствующий ACL. Всё работает - и общая память и пайпы и что угодно другое
     
    Application нравится это.
  8. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    898
    Marylin, так указывай префикс Global\ в имени объекта,.
     
    Marylin нравится это.
  9. Marylin

    Marylin Active Member

    Публикаций:
    0
    Регистрация:
    17 фев 2023
    Сообщения:
    295
    Спасибо всем за советы,
    но у меня что-то не воркает функция StartService(), если вызывать её с аргументами. Эти аргументы нужны мне для передачи службе дескрипторов Read/Write анонимного пайпа. Крэш AV получаю до GetLastError(), где-то внутри либы RPCRT4.dll. Если-же вызывать StartService() без аргументов, то всё ОК, но тогда сервис остаётся без хэндлов пайпа. Пробовал собирать под х32/64, и всегда одинаковая проблема. Может начиная с Vista эти аргументы уже не действительны - хз. Вот фрагмент кода приложения:

    Код (ASM):
    1. .data
    2. hScm         dd  0
    3. hServ        dd  0
    4. hReadPipe    dd  0
    5. hWritePipe   dd  0
    6.  
    7. align 16
    8. szSrvName    db  'WiFiService',0  ; lpServiceArgVectors
    9. szRpipe      db  16 dup(0)
    10. szWpipe      db  16 dup(0)
    11. ;//-----------------
    12.  
    13. .code
    14. start:    invoke  OpenSCManager,0,0,SC_MANAGER_ALL_ACCESS
    15.           or      eax,eax
    16.           jnz     @f
    17.           invoke  MessageBox,0,<'Ошибка! Не удалось открыть SCM.',0>,0,30h
    18.           jmp     @close
    19.  
    20. @@:       mov     [hScm],eax
    21.           invoke  GetFullPathName,<'WiFiService.exe',0>,256,buff,esp
    22.           invoke  CreateService,[hScm],\
    23.                                 <'WiFiService',0>,\
    24.                                 <'Частная служба процесса WiFiTest',0>,\
    25.                                 SERVICE_ALL_ACCESS,\
    26.                                 SERVICE_WIN32_OWN_PROCESS,\ ; + SERVICE_INTERACTIVE_PROCESS,\
    27.                                 SERVICE_DEMAND_START,\
    28.                                 SERVICE_ERROR_NORMAL,\
    29.                                 buff,0,0,0,0,0
    30.           or      eax,eax
    31.           jne     @f
    32.           invoke  MessageBox,0,<'Ошибка! Не удалось создать службу.',0>,0,0
    33.           jmp     @close
    34.  
    35. @@:       mov     [hServ],eax
    36. ;// Создаю анонимный пайп, и перевожу 2 его хэндла в строку,
    37. ;// ...чтобы передать как аргументы в StartService()
    38.  
    39.           invoke  CreatePipe,hReadPipe,\
    40.                              hWritePipe,0,0
    41.          cinvoke  _ltoa,[hReadPipe], szRpipe,10
    42.          cinvoke  _ltoa,[hWritePipe],szWpipe,10
    43.          cinvoke  strlen,szRpipe
    44.           inc     eax
    45.           push    eax
    46.          cinvoke  strlen,szWpipe
    47.           inc     eax
    48.  
    49. ;// Формирую массив нуль-терминальных строк,
    50. ;// как требует агрумент "lpServiceArgVectors" сл.функции
    51. ;// https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-startservicea
    52.  
    53.           xchg    ecx,eax
    54.           pop     ebx
    55.           mov     edi,szRpipe
    56.           add     edi,ebx
    57.           mov     esi,szWpipe
    58.           rep     movsb
    59.  
    60.           invoke  StartService,[hServ],0,0           ;<----- Так всё ОК!
    61. ;          invoke  StartService,[hServ],3,szSrvName  ;<----- а так крэш :(
    62.  
    63.           invoke  GetLastError
    64.          cinvoke  _ltoa,eax,buff,16
    65.           invoke  MessageBox,0,buff,0,0
    66.  
    67.           invoke  ControlService,[hServ],SERVICE_CONTROL_STOP,sStatus
    68.           invoke  DeleteService, [hServ]
    69.           invoke  CloseServiceHandle,[hServ]
    70.           invoke  CloseServiceHandle,[hScm]
    71.  
     
  10. M0rg0t

    M0rg0t Well-Known Member

    Публикаций:
    0
    Регистрация:
    18 окт 2010
    Сообщения:
    1.647
    Marylin, вроде там надо массив строк, а не просто строку. Попробуй типа такого:
    Код (ASM):
    1. szSrvName    db 'WiFiService',0
    2. argsArray     dd offset szSrvName  
    3. invoke StartService.... , offset argsArray
     
    Mikl___, Marylin и Thetrik нравится это.
  11. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    898
    Marylin, хендлы пайпов будут невалидны в контексте службы, создавай по имени. Ну и M0rg0t, верно написал, нужно передавать массив строк что есть массив указателей на данные строк. Ну и вызов A функций - это не есть хорошо.
     
    Mikl___ и Marylin нравится это.
  12. Research

    Research Active Member

    Публикаций:
    1
    Регистрация:
    6 янв 2024
    Сообщения:
    392
    Исправил некоторые грубые ошибки. Скопилировал в виде .ехе 42 кб для тех кто любит реверсить делфи код.
     

    Вложения:

    • 14 February.rar
      Размер файла:
      22,8 КБ
      Просмотров:
      71
    Последнее редактирование: 14 фев 2026
    Marylin нравится это.
  13. Marylin

    Marylin Active Member

    Публикаций:
    0
    Регистрация:
    17 фев 2023
    Сообщения:
    295
    Наконец разобрался я со-своей службой, и скажу гемор ещё тот, т.к. имеются известные проблемы с отладкой на этапе тестирования. Некоторую инфу о сервисе можно получить в "ProcessHacker". Учитывая, что все службы запускаются процессом services.exe, то достаточно в списке его детей найти свой, и заглянуть в свойства по Enter. Аналогично и на вкладке "Сервисы", где можно узнать состояние Run/Stop и уже немного другие свойства.

    Как правильно заметил M0rg0t, аргументы StartService() нужно оформлять в виде массива указателей на строки, но поскольку я заменил анонимный пайп на именованный по совету Thetrik, то эти аргументы уже мне не понадобились, ведь клиент открывает пайп по его имени. Кстати само имя не обязательно должно быть с префиксом "Global" - норм.работает и без него (в утилите WinObj видно, что линк всё равно прописывается в папке Global).

    В общем теперь моя служба работает от имени System, что собственно мне и требовалось для вызова CryptUnprotectData() из crypt32.dll. Всем спасибо за дельные советы!
    Код (ASM):
    1. ;......
    2.           invoke  CreateNamedPipe,<'\\.\pipe\WiFiPipe',0>,\  ;<-- '\\.\pipe\Global\WiFiPipe'
    3.                                   PIPE_ACCESS_DUPLEX,\
    4.                                   PIPE_TYPE_MESSAGE,1,1024,1024,0,0
    5.           mov     [hPipe],eax
    6.  
    7.           invoke  StartService,[hServ],0,0
    8.           invoke  ControlService,[hServ],\
    9.                                  SERVICE_CONTROL_INTERROGATE, sStatus
    10.  
    11. ;// Ждать подключения клиента к каналу..
    12.           invoke  ConnectNamedPipe,[hPipe],0
    13.           invoke  Sleep,1000
    14.  
    15. ;// Прочитать приветствие сервиса!
    16.           invoke  ReadFile,[hPipe],buff,128,byteRetn,0
    17.           invoke  SetDlgItemText,[hwnddlg],ID_File,buff
    18.           jmp     @next
     
    Mikl___ нравится это.