Ir al contenido



Foto

Desaferentar un PC remotamente


  • Por favor identifícate para responder
7 respuestas en este tema

#1 escafandra

escafandra

    Advanced Member

  • Moderadores
  • PipPipPip
  • 3.857 mensajes
  • LocationMadrid - España

Escrito 02 septiembre 2016 - 02:26

Basado en el ejercicio "Botón del Pánico o como desaferentar el PC" he adaptado el código para conseguir lo mismo de forma remota.
 
En esta ocasión precisamos un servidor que estará ejecutándose en la máquina remota y se encargará de la desaferentación (apagar el monitor, bloquear el teclado y bloquear el ratón) y un cliente que se encargará de enviar los comandos precisos para tales acciones. La conexión la he asegurado mediante protocolo TCP de forma que sabremos si el equipo remoto tiene el servidor en marcha y si recibe los comandos.
 
El Servidor de tan sólo 16K, carece de entorno gráfico, pasando desapercibido a la "víctima". El cliente tiene un entorno gráfico simple con los elementos justos para funcionar.
Quiero destacar que si se hacen pruebas en local, nos podemos quedar muy colgados con lo que he incorporado un sistema de seguridad para pruebas con un Timer que activará monitor, teclado y ratón en unos segundos siempre que estemos probando en local (IP = 127.0.0.1) pero no en remoto.
 
No hay mucho más que explicar, así que aquí va el corazón del código del cliente:

delphi
  1. function TForm1.EnableMonitor(SHost: PCHAR; Enable: BOOL): BOOL;
  2. const
  3. SEnable = 'Enable';
  4. SDisable = 'Disable';
  5. var
  6. WSA: TWSADATA;
  7. Sock: TSOCKET;
  8. Host: PHostent;
  9. Remote: sockaddr_in;
  10. IP: ^Integer;
  11. Conex: integer;
  12. Msg: array[0..10] of CHAR;
  13. begin
  14. Label1.Caption:= 'Enviando';
  15. Label1.Update;
  16. Result:= false;
  17. if Enable then lstrcpy(Msg, SEnable)
  18. else lstrcpy(Msg, SDisable);
  19.  
  20. if(WSAStartup(MakeWord(2,2), WSA) = 0) then
  21. begin
  22. Host:= gethostbyname(SHost);
  23. if Host <> nil then
  24. begin
  25. Sock:= socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  26. if(Sock <> INVALID_SOCKET) then
  27. begin
  28. IP:= @Host.h_addr_list^[0];
  29. Remote.sin_family:= AF_INET;
  30. Remote.sin_addr.s_addr:= INADDR_ANY;
  31. Remote.sin_port:= htons(9999);
  32. Remote.sin_addr.S_addr:= IP^;
  33. ZeroMemory(@Remote.sin_zero, 8);
  34.  
  35. //Intentamos establecer la conexión
  36. Conex:= connect(Sock, Remote, sizeof(Remote));
  37. if (conex <> -1) then
  38. Result:= -1 <> send(Sock, Msg, lstrlen(Msg), 0); //Enviar comando
  39.  
  40. ShutDown(Sock, SD_BOTH);
  41. CloseSocket(Sock);
  42. end;
  43. end;
  44. end;
  45. WSACleanUp;
  46. if Result then Label1.Caption:= 'Comando enviado'
  47. else
  48. Label1.Caption:= 'No se ha podido comunicar con Servidor';
  49. end;

Y lo que sigue es el código completo del servidor:

delphi
  1. program ServerMonitorPower;
  2.  
  3. uses
  4. WinSock,
  5. MMSystem,
  6. Windows,
  7. Messages;
  8.  
  9. var
  10. idThTurnOffMonitor: DWORD = 0;
  11. WHookKeyboard: HHOOK = 0;
  12. WHookMouse: HHOOK = 0;
  13.  
  14. function ThTurnOffMonitor(): DWORD; stdcall
  15. var
  16. msg: TMsg;
  17. i: DWORD;
  18. begin
  19. // Monitor off
  20. repeat PeekMessage(msg,0,0,0, PM_REMOVE);
  21. Sleep(100);
  22. SendNotifyMessage(GetForegroundWindow(), WM_SYSCOMMAND, SC_MONITORPOWER, 2);
  23. DispatchMessage(msg);
  24. until (msg.Message = WM_QUIT);
  25.  
  26. // Monitor on
  27. SendNotifyMessage(GetForegroundWindow(), WM_SYSCOMMAND, SC_MONITORPOWER, -1);
  28. for i:= 0 to 4 do
  29. begin
  30. mouse_event(MOUSEEVENTF_MOVE, 0, 10, 0, 0);
  31. Sleep(40);
  32. mouse_event(MOUSEEVENTF_MOVE, 0, DWORD(-10), 0, 0);
  33. end;
  34. Result:= 0;
  35. end;
  36.  
  37. function KeyboardHook(Code, wParam, lParam: Integer): Integer; stdcall;
  38. begin
  39. Result:= -1;
  40. if Code <> HC_ACTION then
  41. Result:= CallNextHookEx(WHookKeyboard, Code, wParam, lParam);
  42. end;
  43.  
  44. function MouseHook(Code, wParam, lParam: Integer): Integer; stdcall;
  45. begin
  46. Result:= -1;
  47. if Code <> HC_ACTION then
  48. Result:= CallNextHookEx(WHookMouse, Code, wParam, lParam);
  49. end;
  50.  
  51. procedure CmdEnableMonitor(Enable: BOOL);
  52. begin
  53. if not Enable and (idThTurnOffMonitor = 0) then
  54. // Turn off monitor
  55. CloseHandle(CreateThread(nil, 0, @ThTurnOffMonitor, nil, 0, idThTurnOffMonitor));
  56. // Hooking
  57. WHookKeyboard:= SetWindowsHookEx(13{WH_KEYBOARD_LL}, @KeyboardHook, HInstance, 0);
  58. WHookMouse:= SetWindowsHookEx(14{WH_MOUSE_LL}, @MouseHook, HInstance, 0);
  59. if Enable then
  60. begin
  61. // Turn on monitor
  62. PostThreadMessage(idThTurnOffMonitor, WM_QUIT, 0, 0);
  63. //UnHooling
  64. if WHookKeyboard <> 0 then UnhookWindowsHookEx(WHookKeyboard);
  65. if WHookMouse <> 0 then UnhookWindowsHookEx(WHookMouse);
  66. WHookMouse:= 0;
  67. WHookKeyboard:= 0;
  68. idThTurnOffMonitor:= 0;
  69. end;
  70. end;
  71.  
  72. // El servidor propiamente dicho
  73. var
  74. WSA: TWSADATA;
  75. Sock_c: TSOCKET;
  76. Sock_e: TSOCKET;
  77. Local: sockaddr_in;
  78. Buffer: array[0..1024] of CHAR;
  79. Len: integer;
  80. begin
  81. idThTurnOffMonitor:= 0;
  82.  
  83. if(WSAStartup(MakeWord(2,2), WSA) <> 0) then exit;
  84. Sock_e:= socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  85. if(Sock_e <> INVALID_SOCKET) then
  86. begin
  87.  
  88. local.sin_family:= AF_INET;
  89. local.sin_addr.s_addr:= INADDR_ANY;
  90. local.sin_port:= htons(9999);
  91.  
  92. // Asociamos el socket al puerto
  93. if(bind(Sock_e, Local, sizeof(Local)) <> -1) then
  94. begin
  95. // escucha...
  96. while true do
  97. begin
  98. // Socket a la escucha
  99. if (listen(sock_e, 1) = -1) then exit;
  100. Len:= sizeof(Tsockaddr);
  101.  
  102. // Aceptamos conexión
  103. Sock_c:= accept(Sock_e, PSOCKADDR(@Local), @Len);
  104.  
  105. Len:= recv(Sock_c, Buffer, 1023, 0); //recibimos los datos que envie
  106. if (Len > 0) then //si seguimos conectados
  107. begin
  108. Buffer[Len]:= #0; //le ponemos el final de cadena
  109.  
  110. if lstrcmpi(Buffer, 'Enable') = 0 then
  111. CmdEnableMonitor(true);
  112. if lstrcmpi(Buffer, 'Disable') = 0 then
  113. CmdEnableMonitor(false);
  114. end;
  115. closesocket(Sock_c);
  116. end;
  117. end;
  118. end;
  119. WSACleanUp;
  120.  
  121. CmdEnableMonitor(true);
  122. end.

He de decir que un código parecido ya use en una aplicación de escritorio remoto que era algo más que eso, la idea era que el usuario no pudiera intervenir cuando esa app se usaba en modo escritorio remoto, porque el resto de sus virtudes eran transparentes al usuario.
 
También he encontrado efectos interesantes en las pruebas que he hecho basadas en el código que muestro, como el bloqueo total de monitor, teclado y ratón incluidas las célebres CTR-ALT-SUP, pero eso es otra historia que tendré que investigar más a fondo y con más tiempo, así como los efectos reales causados.
 
Para no dejaros a medias con el cliente, subo el proyecto completo y compilado.
 
 
Saludos.

Archivos adjuntos


  • 1

#2 giulichajari

giulichajari

    Advanced Member

  • Miembros
  • PipPipPip
  • 433 mensajes

Escrito 02 septiembre 2016 - 02:54

Reiniciando la pc atacada esta volveria a la normalidad. Aunque se podria volver a invocar el metodo que la bloquee. Si tendriamos una tarea programada el proceso servidor se volveria a ejecutar al reiniciar..

Enviado desde mi SM-G530M mediante Tapatalk
  • 0

#3 escafandra

escafandra

    Advanced Member

  • Moderadores
  • PipPipPip
  • 3.857 mensajes
  • LocationMadrid - España

Escrito 02 septiembre 2016 - 03:07

Reiniciando la pc atacada esta volveria a la normalidad. Aunque se podria volver a invocar el metodo que la bloquee.


Claro, pero el objetivo no es bloquear por bloquear...

Saludos
  • 0

#4 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.262 mensajes
  • LocationArgentina

Escrito 02 septiembre 2016 - 03:36

A mi me parece muy útil disponer de esto en estaciones de trabajo que van a estar expuestas al público... En los cibers por ejemplo era habitual encontrarse con aplicaciones que habilitaban el equipo. Incluso llevaban un contador del tiempo para que el usuario supiera cuanto tiempo le queda de uso, y/o el tiempo consumido.

 

También puede ser útil en puestos en los que el personal puede ausentarse y evitar que alguien más entre y ututee. Me viene a la cabeza en los lugares de reposición y recepción de mercaderías... bodegas aduaneras, etc. La persona no estará siempre detrás del equipo y hay curiosos dando vueltas.

 

Saludos,


  • 0

#5 sir.dev.a.lot

sir.dev.a.lot

    Advanced Member

  • Miembros
  • PipPipPip
  • 545 mensajes
  • Location127.0.0.1

Escrito 02 septiembre 2016 - 06:00

Cuando estas haciendo una sesion remota con:

 

Logme In

TeamViewer

AnyDesk

PC Anywhere

Carbon Copies

Real VNC

etc

 

Que no quieres que nadie te toque o mueva el Puntero, o utilice el teclado, porque estas haciendo una actualizacion y presionando algo se interrumpe.  :@

 

Claro, obviamente, se pone la actualizacion en curso y luego se bloquea... :)

 

Saludos!


  • 1

#6 escafandra

escafandra

    Advanced Member

  • Moderadores
  • PipPipPip
  • 3.857 mensajes
  • LocationMadrid - España

Escrito 02 septiembre 2016 - 06:10

Cuanta utilidad le estáis sacando a este sutil código. :o

 

 

Saludos.


  • 1

#7 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14.000 mensajes
  • LocationMéxico

Escrito 02 septiembre 2016 - 06:13

Cuanta utilidad le estáis sacando a este sutil código. :o

 

 

Saludos.

 

O cualdo estas haciendo cosas pecaminosas :D :D :D

Saludos

 

 

Edito: A no, ese era el otro no éste  *-)  *-)  *-)


  • 0

#8 escafandra

escafandra

    Advanced Member

  • Moderadores
  • PipPipPip
  • 3.857 mensajes
  • LocationMadrid - España

Escrito 03 septiembre 2016 - 11:31

Me he animado y he hecho una versión C/C++

 

El corazón del cliente:


cpp
  1. bool TForm1::EnableMonitor(PCHAR SHost, BOOL Enable)
  2. {
  3. WSADATA Wsa;
  4. SOCKET Sock;
  5. struct hostent *host;
  6. struct sockaddr_in Addr;
  7. char *SEnable = "Enable";
  8. char *SDisable = "Disable";
  9. char *Msg;
  10. bool Result;
  11.  
  12. Msg = SDisable;
  13. if(Enable) Msg = SEnable;
  14. Label1->Caption = "Enviando";
  15. Label1->Update();
  16. Result = false;
  17.  
  18. //Inicializamos la librería winsock
  19. if(!WSAStartup(MAKEWORD(2,2),&Wsa)){
  20. host = gethostbyname(SHost);
  21. if(host != NULL){
  22. Sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  23. if(Sock != INVALID_SOCKET){
  24. //Definimos la dirección a conectar recibida de gethostbyname
  25. //y decidimos el puerto al que deberá conectar (9999)
  26. Addr.sin_family = AF_INET;
  27. Addr.sin_port = htons(9999);
  28. Addr.sin_addr = *((struct in_addr *)host->h_addr);
  29.  
  30. // Si conectamos, enviamos el comando
  31. if(connect(Sock, (sockaddr*)&Addr, sizeof(sockaddr)) != -1)
  32. Result = -1 != send(Sock, Msg, lstrlen(Msg), 0); //Enviar comando
  33.  
  34. // Terminamos
  35. shutdown(Sock, SD_BOTH);
  36. closesocket(Sock);
  37. }
  38. }
  39. }
  40. WSACleanup();
  41.  
  42. if(Result)
  43. Label1->Caption = "Comando enviado";
  44. else
  45. Label1->Caption = "No se ha podido comunicar con Servidor";
  46.  
  47. return Result;
  48. }

Y el servidor:


cpp
  1. //---------------------------------------------------------------------------
  2.  
  3. #include <windows.h>
  4. #include <winsock2.h>
  5.  
  6. #pragma hdrstop
  7.  
  8. //---------------------------------------------------------------------------
  9. DWORD idThTurnOffMonitor = 0;
  10. HHOOK WHookKeyboard = 0;
  11. HHOOK WHookMouse = 0;
  12. HINSTANCE HInstance;
  13.  
  14. DWORD WINAPI ThTurnOffMonitor(LPVOID lpParameter)
  15. {
  16. MSG msg;
  17. DWORD i;
  18.  
  19. // Monitor off
  20. do {
  21. PeekMessage(&msg,0,0,0, PM_REMOVE);
  22. Sleep(100);
  23. SendNotifyMessage(GetForegroundWindow(), WM_SYSCOMMAND, SC_MONITORPOWER, (LPARAM) 2);
  24. DispatchMessage(&msg);
  25. } while(msg.message != WM_QUIT);
  26.  
  27. // Monitor on
  28. SendNotifyMessage(GetForegroundWindow(), WM_SYSCOMMAND, SC_MONITORPOWER, -1);
  29. for(i= 0; i<4; i++){
  30. mouse_event(MOUSEEVENTF_MOVE, 0, 10, 0, 0);
  31. Sleep(40);
  32. mouse_event(MOUSEEVENTF_MOVE, 0, DWORD(-10), 0, 0);
  33. }
  34. return 0;
  35. }
  36.  
  37. LRESULT CALLBACK KeyboardHook(int nCode, WPARAM wParam, LPARAM lParam)
  38. {
  39. if(nCode == HC_ACTION) return -1;
  40. return CallNextHookEx(WHookKeyboard, nCode, wParam, lParam);
  41. }
  42.  
  43. LRESULT CALLBACK MouseHook(int nCode, WPARAM wParam, LPARAM lParam)
  44. {
  45. if(nCode == HC_ACTION) return -1;
  46. return CallNextHookEx(WHookMouse, nCode, wParam, lParam);
  47. }
  48.  
  49. void CmdEnableMonitor(BOOL Enable)
  50. {
  51. if(!Enable && !idThTurnOffMonitor){
  52. // Turn off monitor
  53. CloseHandle(CreateThread(NULL, 0, ThTurnOffMonitor, NULL, 0, &idThTurnOffMonitor));
  54. WHookKeyboard = SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)KeyboardHook, HInstance, 0);
  55. WHookMouse = SetWindowsHookEx(WH_MOUSE_LL, (HOOKPROC)MouseHook, HInstance, 0);
  56. }
  57. if(Enable){
  58. // Turn on monitor
  59. PostThreadMessage(idThTurnOffMonitor, WM_QUIT, 0, 0);
  60. idThTurnOffMonitor = 0;
  61. if(WHookKeyboard){
  62. UnhookWindowsHookEx(WHookKeyboard);
  63. WHookKeyboard = 0;
  64. }
  65. if(WHookMouse){
  66. UnhookWindowsHookEx(WHookMouse);
  67. WHookMouse = 0;
  68. }
  69. }
  70. }
  71.  
  72. void Acction(char* Command)
  73. {
  74. if(!lstrcmpi(Command, "Enable")) CmdEnableMonitor(true);
  75. if(!lstrcmpi(Command, "Disable")) CmdEnableMonitor(false);
  76. }
  77.  
  78. #pragma argsused
  79. WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
  80. {
  81. WSADATA Wsa;
  82. SOCKET Sock_e; // Sock de escucha
  83. SOCKET Sock_c; // Sock de comunicación
  84. struct sockaddr_in Server, Client;
  85. int Len=0;
  86. char Buffer[1024];
  87.  
  88. //Inicializamos
  89. if(WSAStartup(MAKEWORD(2, 0), &Wsa) != 0) return 0;
  90. HInstance = hInstance;
  91.  
  92. //Creamos el socket
  93. if((Sock_e = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) != INVALID_SOCKET){
  94. //defnimos dirección por defecto, ipv4 y el puerto 9999
  95. Server.sin_family = AF_INET;
  96. Server.sin_addr.s_addr = INADDR_ANY;
  97. Server.sin_port = htons(9999);
  98.  
  99. //asociamos el socket al puerto
  100. if (bind(Sock_e, (SOCKADDR*)&Server, sizeof(Server)) != -1){
  101. //ponemos el socket a la escucha
  102. while (true){
  103. if (listen(Sock_e, 1) != -1){
  104. //hay una conexión entrante y la aceptamos
  105. Len = sizeof(sockaddr);
  106. Sock_c = accept(Sock_e,(sockaddr*)&Client, &Len);
  107. if(Sock_c == INVALID_SOCKET) continue;
  108. //mientras estemos conectados con el otro pc
  109. do {
  110. Len = recv(Sock_c, Buffer, 1023, 0); //recibimos los datos que envie
  111. //si seguimos conectados
  112. if(Len>0){
  113. Buffer[Len]=0; //le ponemos el final de cadena
  114. Acction(Buffer);
  115. }
  116. } while (Len!=0 && Len != -1);
  117. closesocket(Sock_c);
  118. }
  119. }
  120. closesocket(Sock_e);
  121. }
  122. }
  123. WSACleanup();
  124. return 0;
  125. }
  126. //---------------------------------------------------------------------------

Saludos.

 

 

Archivos adjuntos


  • 4