¿Hay alguna forma de restaurar la estructura mediante ingeniería inversa? El puntero a esa estructura es devuelto por la única función para exportar dentro de DLL

Un poco... tengo una DLL, que exporta la única función CreateInterface
Del código desensamblado y luego descompilado:

int __cdecl CreateInterface(const char *a1, int a2)
{
//many crazy things
}

aquí tiene un tipo de retorno como int, pero en realidad es un puntero a alguna estructura. desde un exe principal, esta biblioteca se carga y luego se usa de esa manera:

int (__stdcall *__cdecl Sys_GetFactory(int (__stdcall *hModule)()))()
{
  int (__stdcall *result)(); // eax@1

  result = hModule;
  if ( hModule )
    result = GetProcAddress(hModule, "CreateInterface");
  return result;
}

void some_funct()
{
    FARPROC net_interface =  Sys_GetFactory(pModule);
    int s_pClientNet = ((int (__cdecl *)(_DWORD, _DWORD))net_interface)("INetClient_003", 0);
}

y después de ser inicializado, se usó de esa manera:

 int result = (*(int (__stdcall **)(int, int, int, int))(*(_DWORD *)s_pClientNet + 60))(
                 login,
                 password,
                 mw_account_struct,
                 mw_account_struct_size);

así que... de vuelta a la estructura. De todos modos, para restaurarlo, ¿en lugar de llamar a las funciones necesarias de una manera tan loca? quiero decir (s_pClientNet + 60)

PD: seguro que no tengo fuentes dll, archivos de definición, etc. y ni siquiera tengo idea de qué funciones pueden estar en la clase / estructura de destino ... lo único que sé son algunas llamadas a funciones como esa s_pClientNet + 60

preguntado el 12 de junio de 12 a las 16:06

Algunas preguntas: ¿Cómo sabe que el tipo devuelto es un puntero a la estructura? Aunque ya sabes, ¿no estaba destinado a ser usado de esa manera (es decir, como un tipo opaco)? WHY ¿Necesita obtener/conocer el contenido de la estructura? -

ehm, porque el valor de retorno se usa como puntero a clase/estructura para llamar a funciones como s_pClientNet + 60, por lo que s_pClientNet es un puntero al comienzo, y 60 se compensa con alguna función. -

y no conozco todas las funciones en esa clase/estructura, ¿puedo ver que +60? +48 y etc, quien cuantos mas hay? así que esperaba que tal vez haya alguna forma de reconstruir los campos de estructura -

3 Respuestas

Hmm, parece que podría ser una clase de C++. Hay un nivel extra de direccionamiento indirecto, y apuesto a que es una vtable. s_pClientNet es definitivamente un puntero, pero ocurre el +60 después de desreferenciandolo. Los vpointers suelen ser el primer elemento de la clase, por lo que es más evidencia. Será básicamente imposible recrear una clase de C++ que se compile con el mismo diseño, a menos que tengas mucha suerte. Pero podrías manejar algunas piezas manualmente.

typedef int(*login_fcn_t)(int, int, int, int);

struct ClientInterfaceVtable
{
    _DWORD reserved[60];
    login_fcn_t login_fcn;
};

struct ClientInterface
{
    ClientInterfaceVtable *vpointer;
    /// other fields
};

Ahora, después de lanzar tu s_pClientNet a una ClientInterface *, debería poder invocar el método de inicio de sesión a través de s_pClientNet->vpointer->login_fcn(login, etc.);

Después de descubrir algunos campos más, siempre puede intentar crear una clase C++ polimórfica y ver si puede cambiar las definiciones hasta que obtenga una coincidencia, pero eso no será portátil.

Edit:

Hmm, acabo de darme cuenta de que el código no está pasando el this puntero. Si no estoy completamente equivocado acerca de vtable, eso sugiere que este es un método estático, tal vez un método de fábrica de algún tipo.

Respondido el 12 de junio de 12 a las 18:06

Es bastante difícil o imposible, AFAIK no hay garantía con respecto al diseño y la alineación de la estructura, por lo que cada compilador puede diseñar la estructura de manera diferente. Incluso el mismo compilador puede tener diferentes diseños de datos a través de modificadores y/u opciones de compilador.

Respondido el 12 de junio de 12 a las 17:06

No conozco ninguna forma de identificar automáticamente la estructura, sin embargo, si está utilizando IDA, puede definir la estructura dentro de IDA y luego cambiar la firma de llamada para usarla explícitamente (cambiando el valor de retorno a esa estructura tipo y obligando a volver a analizar).

Esto puede ayudarlo a analizar más rápidamente la estructura y comprender el comportamiento del programa, pero en última instancia será principalmente un análisis manual.

Puede haber algunos scripts para IDA/OllyDbg que pueden ayudar con esto, por lo que podría valer la pena echarle un vistazo http://www.openrce.org/downloads/

Respondido el 12 de junio de 12 a las 17:06

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.