Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > API de Windows
Registrarse FAQ Miembros Calendario Guía de estilo Buscar Temas de Hoy Marcar Foros Como Leídos

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 26-04-2008
rolandoj rolandoj is offline
Miembro
 
Registrado: abr 2007
Posts: 395
Poder: 17
rolandoj Va por buen camino
Question Error ejecutando una rutina inyectada a un proceso remoto

Hola,

Estoy teniendo problemas al ejecutar una rutina inyectada en un proceso remoto. Funcionalmente, la rutina se ejecuta perfectamente; pero, bien al momento de regresar, o al momento de limpiarse la memoria alocada para ella, el proceso remoto indica que ha generado errores y que se cerrará.

Dado que este es un tipo de programación particularmente complicada, por simplicidad diré que conceptualmente, y en forma muy resumida, la situación es la siguiente:

1. Tenemos desarrollada una rutina que debe ejecutarse en una aplicación distinta a aquella en la que la hemos escrito.

2, Para ello es necesario copiar, el código de la rutina en sí y la estructura de los datos a pasarle como parámetros, desde nuestro espacio de direcciones al espacio de direcciones del proceso remoto, lo que implica reservar memoria en el proceso remoto para copiarle esa información

3. La rutina debe ejcutarse con CreateRemoteThread

4. La memoria reservada en el proceso remoto debe liberarse con VirtualFreeEx. VirtualFreeEx no reporta errores, por lo que aparentemente esa parte está bien; pero no estoy 100% seguro

Básicamente, la rutina a ejecutarse remotamente debe tener la forma:

function NombreDeFuncion(dwEntryPoint: Pointer): longword; stdcall;

El parámetro dwEntryPoint debe ser un apuntador a la estructura de datos pasados a la rutina desde el proceso que llama, y entre otras cosas contiene apuntadores a las rutinas de User32 y Kernel32 que pudieran necesitarse.

Cuando la rutina termina es donde empiezan mis principales dudas. He visto ejemplos donde no se hace nada especial, otros donde se llama a ExitThread y otros llamando a ExitProcess: pero ninguna combinación ha funcionado.

Además, ni para ExitThread ni para ExitProcess he encontrado una explicación clara de cual debe ser el valor de ExitCode que se les pase.

Agradecería si alguién pudiera aclarar conceptualmente las condiciones que deben cumplir ese tipo de rutinas para ser terminadas y para limpiar la memoria alocada para ellas.
Responder Con Cita
  #2  
Antiguo 26-04-2008
Khronos Khronos is offline
Miembro
 
Registrado: abr 2007
Posts: 298
Poder: 17
Khronos Va por buen camino
Primero, la ejecución de código remoto en otro proceso casi nunca es para nada bueno.
Segundo, los antivirus detectan esas llamadas a las apis y las bloquean.
Y tercero, el método que empleas da muchisimos errores. El metodo mas eficaz que he probado con éxito es el de cargar una dll en otro proceso.

Si tengo tiempo te busco el código.


Salu2
Responder Con Cita
  #3  
Antiguo 26-04-2008
rolandoj rolandoj is offline
Miembro
 
Registrado: abr 2007
Posts: 395
Poder: 17
rolandoj Va por buen camino
Es una alternativa; pero ...

Cita:
Empezado por Khronos Ver Mensaje
Primero, la ejecución de código remoto en otro proceso casi nunca es para nada bueno.
Segundo, los antivirus detectan esas llamadas a las apis y las bloquean.
Y tercero, el método que empleas da muchisimos errores. El metodo mas eficaz que he probado con éxito es el de cargar una dll en otro proceso.

Si tengo tiempo te busco el código.

Salu2
Hola,

Muchas gracias por la sugerencia y la oferta. Te comento al respecto.

En primer lugar, la razón de usar esta técnica es que el programa debe adiministrar aplicativos externos y se necesita cierta información de esos aplicativos externos que no es accesible directamente vía comunicación standard simple entre procesos; entre otras cosas porque esos aplicativos son de terceros y por ello no puedo incorporar directamente mensajes registrados de Windows para dicha comunicación.

La alternativa de DLLs la había considerado; pero en este caso, hasta ahora, he optado por la copia directa. Tengo varias razones :

1. El aplicativo se usará básicamente en muy pocos equipos (usualmente uno), y la situación de antivirus es controlable.

2. Cada ejecución implica recorrer todos los aplicativos activos y ejecutar el código en cada uno. En ese orden de ideas, la opción vía memoria a memoria es más efciciente que cargar y descargar DLLs.

3. El grado de dificultad de la técnica que he visto para hacerlo con DLLs es similar y quizás mayor a la que uso actualmente.

Por otro lado, dado que el sistema está funcionando básicamente bien, antes de ponerme a recodificar todo, preferiría agotar la opción de corregir el error que se está presentando.
Responder Con Cita
  #4  
Antiguo 27-04-2008
Khronos Khronos is offline
Miembro
 
Registrado: abr 2007
Posts: 298
Poder: 17
Khronos Va por buen camino
Aquí tienes el código:

Código Delphi [-]

uses TlHelp32;

function EnabledDebugPrivilege(const Enabled : Boolean) : Boolean;
var
  hTk : THandle;
  rtnTemp : Dword;
  TokenPri : TOKEN_PRIVILEGES;
const
  SE_DEBUG = 'SeDebugPrivilege';
begin
  Result := False;
  if (OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,hTk)) then
  begin
    TokenPri.PrivilegeCount := 1;
    LookupPrivilegeValue(nil,SE_DEBUG,TokenPri.Privileges[0].Luid);
    if Enabled then
      TokenPri.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED
    else
      TokenPri.Privileges[0].Attributes := 0;
    rtnTemp := 0;
    AdjustTokenPrivileges(hTk,False,TokenPri,sizeof(TokenPri),nil,rtnTemp);
    Result := GetLastError = ERROR_SUCCESS;
    CloseHandle(hTk);
  end;
end;
 
{Esta es una función muy importante que sirve para
obtener el ID de un proceso.}
function GetProcessID(Exename: string): DWORD; 
var
  hProcSnap: THandle;
  pe32: TProcessEntry32;
begin
  result := 0;
  hProcSnap := CreateToolHelp32SnapShot(TH32CS_SNAPPROCESS, 0);
  if hProcSnap <> INVALID_HANDLE_VALUE then
  begin
    pe32.dwSize := SizeOf(ProcessEntry32);
    if Process32First(hProcSnap, pe32) = true then
    begin
      while Process32Next(hProcSnap, pe32) = true do
      begin
        if pos(Exename, pe32.szExeFile) <> 0 then
          result := pe32.th32ProcessID;
      end;
    end;
    CloseHandle(hProcSnap);
  end;
end;
 
function InjectTo(const Host, Guest: string): DWORD;
var
  hRemoteProcess: THandle;  
  dwRemoteProcessId: DWORD;  
  memSize: DWORD;        
  pszLibFileRemote: Pointer;  
  iReturnCode: Boolean;
  TempVar: DWORD;
  pfnStartAddr: TFNThreadStartRoutine; 
  pszLibAFilename: PwideChar;
begin
  Result := 0;
  EnabledDebugPrivilege(True);
  Getmem(pszLibAFilename, Length(Guest) * 2 + 1);
  StringToWideChar(Guest, pszLibAFilename, Length(Guest) * 2 + 1);
  dwRemoteProcessID:=GetProcessId(host);
 
  hRemoteProcess := OpenProcess(PROCESS_CREATE_THREAD + PROCESS_VM_OPERATION +
      PROCESS_VM_WRITE,
      FALSE, dwRemoteProcessId);
  //abrimos el proceso basándonos en la Id de dicho proceso
  memSize := (1 + lstrlenW(pszLibAFilename)) * sizeof(WCHAR)*2;
 
  pszLibFileRemote := PWIDESTRING(VirtualAllocEx(hRemoteProcess, nil, memSize, MEM_COMMIT, PAGE_READWRITE));
  TempVar := 0;
  iReturnCode := WriteProcessMemory(hRemoteProcess, pszLibFileRemote, pszLibAFilename, memSize, TempVar);
    if iReturnCode then
  begin
    pfnStartAddr := GetProcAddress(GetModuleHandle('Kernel32'), 'LoadLibraryW');
    TempVar := 0;
    Result := CreateRemoteThread(hRemoteProcess, nil, 0, pfnStartAddr, pszLibFileRemote, 0, TempVar);
  end;
  Freemem(pszLibAFilename);
end;

Ejemplo de uso:

Código Delphi [-]
begin
  InjectTo('notepad.exe', 'C:\MyDll.dll');
end;

Nunca utilices un proceso critíco del sistema. Si tienes alguna duda, pregunta.


Salu2 y suerte.

Última edición por Khronos fecha: 27-04-2008 a las 16:30:41.
Responder Con Cita
  #5  
Antiguo 27-04-2008
rolandoj rolandoj is offline
Miembro
 
Registrado: abr 2007
Posts: 395
Poder: 17
rolandoj Va por buen camino
Muchas gracias. Primeras dudas

Hola,

Muchas gracias por el aporte.

Efectivamente es muy similar a lo que ya conocía de esa técnica, y la complejidad luce mayor a la copia directa de memoria a memoria. Voy a analizarlo con bastante calma; pero te adelanto dos temas que me saltan a la vista:

1. Veo que la memoria alocada en el proceso remoto no la liberas con VirtualFreeEx sino con FreeMem, como es posible si se supone que están en espacios de direcciones diferentes ?

2. No mencionas nada acerca de la función que se va a ejecutar remotamente. Lo que indicas es ejecutar la carga de la librería como tal. Que hay de las observaciones que yo hacía en mi primera nota acerca de las condiciones que debe cumplir una rutina para ejecutarse en el proceso remoto ?. Es que acaso aquí la lógica es que lo único que se ejecuta es la rutina de inicialización del DLL ?. Si es así, que hay del paso de parámetros desde el proceso principal a la rutina remota ?, sería solo vía mensajes registrados?

Bueno, aunque como obvio interes profesional pienso detallar tú código, sigo con mi idea de corregir el problema con lo que tengo, que funcionalmente ya me está trabajando bien. Alguna idea de porque puede fallar después de haber ejecutado bien todas las instrucciones en el cuerpo de la rutina ?. Quizás es algún problema por la convención de llamadas stdcall, tal como la limpieza de la pila ?

Una vez más muchas gracias y seguiremos en contacto.

Muchos saludos
Responder Con Cita
  #6  
Antiguo 27-04-2008
rolandoj rolandoj is offline
Miembro
 
Registrado: abr 2007
Posts: 395
Poder: 17
rolandoj Va por buen camino
El problema con VirtualFreeEx

Hola,

Las pruebas que he hecho ya me han confirmado que el problema surge cuando libero el código de la rutina con VirtualFreeEx. Una investigación en Internet me ha mostrado que ese problema le ha ocurrido a otros; pero, hasta ahora, en ninguno de los sitios que he visto que lo han reportado se ha dado una explicación t/o solución.

El código que uso para liberar es :

Código Delphi [-]
TheResult := VirtualFreeEx(AProcessHandle, TheExtFuncAddr, 0, MEM_RELEASE);
        If Not Assigned(TheResult) Then Begin
           ShowMessage('Error liberando la Función '+SysErrorMessage(GetLastError));
        End;

Ahora bien, la rutina no me devuelve error, o sea, mi programa sigue funcionando; pero el proceso externo dice generar errores y se cierra.

La liberación de memoria de la parte de datos la hago de manera idéntica; pero esa no genera ningún problema.

La función la reservo así :

Código Delphi [-]
TheExtFuncAddr := VirtualAllocEx(AProcessHandle,
                                      0,
                                      AFunctionSize,
                                      MEM_COMMIT or MEM_RESERVE,
                                      PAGE_EXECUTE_READWRITE);

Quedo atento a sugerencias
Responder Con Cita
  #7  
Antiguo 29-04-2008
rolandoj rolandoj is offline
Miembro
 
Registrado: abr 2007
Posts: 395
Poder: 17
rolandoj Va por buen camino
El impacto de no liberar la memoria

Hola Khronos,

Pués sigo estancado en el error. No ha habido forma de encontrar una explicación de la falla de los programas al liberar la memoria con VirtualFreeEx.

Ante eso, sin recurrir a tú solución, me queda la alternativa de no liberar la memoria. En principio, el impacto de ello parece despreciable, Mi rutina ocupa 56 bytes, por tanto, se necesitaría llamarla mil veces seguídas para generar un excedente de 56000 bytes en un proceso. Considerando la frecuencia con la que se llama, es casi imposible aproximarse a esa cifra sin que al menos se haya cerrado sesión.

Las pruebas que he hecho no indican que dejar esa memoria sin liberar pueda generar algún problema; por tanto, aunque burda, parece una solución viable. Sin embargo, no estoy tan convencido. Se te ocurre algo que pudiera pasar muy a largo plazo ?

Respecto a tú solución, como verás, el hecho de que no me anime mucho a usarla es, aparte de que obliga a recodificar, por la diferencia de eficiencia. Aquí solo paso 56 bytes al otro proceso; en el otro método hay que cargar y descargar DLLs.

Eso sí, encuentro muy interesantes algunos puntos de tú método; entre ellos EnabledDebugPrivilege. No he tenido tiempo de investigarla a fondo; pero, esta rutina aparentemente asigna privilegios al proceso actual, o sea a mi propio proceso. Lo que no entiendo es que impacto tiene en el método de cargar el DLL
Responder Con Cita
  #8  
Antiguo 29-04-2008
Khronos Khronos is offline
Miembro
 
Registrado: abr 2007
Posts: 298
Poder: 17
Khronos Va por buen camino
Hola rolandoj, perdona por no haber contestado antes pero estuve algo ocupado

En principio al no liberar la memoria, dudo mucho que provoques un desbordamiento de la memoria , supongo que otro proceso sobreescribirá esa zona..

Antes de intentar inyectar codigo en otros procesos mediante dlls, probé un método parecido al tuyo pero me saltaba el DEP (Prevención de ejecución de datos de Windows) y me paraba el proceso. El método que utilizaba funcionaba perfectamente con funciones de la API de windows como DeleteFile, Sleep.. pero con funciones propias se iba a la mierda . Por eso pensé que inyectando una dll entera conseguiría "saltarme" esa protección y me salí con la mia .

Información de DEP: http://www.microsoft.com/latam/techn.../depcnfxp.mspx

Si encuentro el código lo pongo. Por cierto, ¿podrías enseñarnos tu código para ver el método que usas?

PD: Tengo que hacer una ejemplo de inyecciones de procesos mediante dll y subirlo. No es tan díficil como te piensas y funciona perfecto.

Salu2

Última edición por Khronos fecha: 29-04-2008 a las 21:32:50.
Responder Con Cita
  #9  
Antiguo 29-04-2008
rolandoj rolandoj is offline
Miembro
 
Registrado: abr 2007
Posts: 395
Poder: 17
rolandoj Va por buen camino
Gracias por los aportes. Comentarios

Hola,

Muchas gracias por aportar al tema.

Colocar el código completo puede ser inconveniente porque resulta complicado de seguír debido a la cantidad de detalles. Si la idea es documentar para que a otros les quede más facil este tortuoso camino; epro potencialmente eficiente camino, creo mejor ir colocandolo por fragmentos y comentar en detalle esos fragmentos.

Tengo que salir ahora; pero, al final de la noche trataré de sacar un tiempo para empezar a explicar la teoría, al menos lo que yo sé. Lo ideal sería que más colegas se sumaran a esta discusión y pudieran aclarar aspectos que para mí aún son oscuros,
Responder Con Cita
  #10  
Antiguo 01-05-2008
rolandoj rolandoj is offline
Miembro
 
Registrado: abr 2007
Posts: 395
Poder: 17
rolandoj Va por buen camino
Smile Abrí un hilo para explicar la inyección directa de código

Hola Khronos,

Pensandolo bien, para no confundir temas, ya que aquí lo busco es averiguar porque falla la limpieza de código en mi rutina, he creado un nuevo tema para discutir el método de inyectar código a un proceso externo. Puedes leerlo aquí:

http://www.clubdelphi.com/foros/showthread.php?t=55924

Es un tema largo y complicado que amerita explicaciones claras en varios puntos; por eso, solo he colocado hasta ahora el inicio del mismo. Debido al tiempo que me toma escribir acerca de esto, pondré más a medida que vea que hay interés de los colegas.

Esperaré tús comentarios
Responder Con Cita
Respuesta


Herramientas Buscar en Tema
Buscar en Tema:

Búsqueda Avanzada
Desplegado

Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
ayuda ejecutando un proceso como "SYSTEM" y haciendo que no se pueda terminar lostprophets Varios 2 05-02-2008 03:28:50
ayuda "Detectando un proceso y ejecutando otro" lostprophets Varios 1 30-01-2008 00:54:03
Error de conexion a servidor Remoto con Firebird Gaim2205 Firebird e Interbase 5 18-09-2007 22:33:00
Error al conectar la base de datos en modo Remoto oscjae Firebird e Interbase 2 26-01-2006 12:19:33
Error de memoria con proceso de Data Pump burasu Conexión con bases de datos 4 22-11-2005 12:14:22


La franja horaria es GMT +2. Ahora son las 01:41:53.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi
Copyright 1996-2007 Club Delphi