Pregunta

¿Puedes usar ganchos de Windows u otros métodos para inyectar código con C#?He visto muchas cosas sobre la inyección de código, pero todas se realizan en C/C++.No conozco ninguno de esos idiomas y me cuesta mucho traducir.¿Alguien tiene alguna idea sobre cómo hacer esto?

¿Fue útil?

Solución

Kevin, es posible.Puede crear una biblioteca con un proceso de enlace de ventana utilizando C++ administrado.Todo lo que necesita hacer es inyectar este gancho en alguna aplicación usando WinAPI estándar (SetWindowsHookEx, etc.).Dentro de este enlace puede llamar al método System::AppDomain::CurrentDomain->Load para cargar su ensamblado en el AppDomain de la aplicación de destino.Luego puede llamar a los métodos definidos en su ensamblaje usando la reflexión.Por ejemplo, Fisgonear utiliza este método.

Otros consejos

Mike Stall tiene esta muestra, que utiliza CreateRemoteThread.Tiene la ventaja de no requerir ningún C++.

EDITAR: Parece que he malinterpretado la pregunta...Tenía la impresión de que la pregunta era sobre la inyección de código en el proceso actual.


Me uniré al grupo bastante tarde, pero usé exactamente esto hace unas semanas:

Un delegado contiene los campos privados. IntPtr _methodPtr y IntPtr _methodPtrAux, que representan la dirección de memoria del cuerpo.Al configurar el campo (mediante reflexión) en valores específicos, se puede alterar la dirección de memoria a la que apuntará el EIP.
Con esta información se puede hacer lo siguiente:

  1. Cree una matriz con bytes de ensamblaje, que se ejecutarán
  2. Mueva el puntero del método del delegado a los bytes en cuestión.
  3. llamar al delegado
  4. Ganancia ???

(Por supuesto, puedes cambiar el _methodPtr-value a cualquier dirección de memoria, incluso en el espacio del kernel, pero esto podría requerir privilegios de ejecución adecuados).


Tengo un ejemplo de código funcional aquí, si quieres:

public static unsafe int? InjectAndRunX86ASM(this Func<int> del, byte[] asm)
{
    if (del != null)
        fixed (byte* ptr = &asm[0])
        {
            FieldInfo _methodPtr = typeof(Delegate).GetField("_methodPtr", BindingFlags.NonPublic | BindingFlags.Instance);
            FieldInfo _methodPtrAux = typeof(Delegate).GetField("_methodPtrAux", BindingFlags.NonPublic | BindingFlags.Instance);

            _methodPtr.SetValue(del, ptr);
            _methodPtrAux.SetValue(del, ptr);

            return del();
        }
    else
        return null;
}

Que se puede utilizar de la siguiente manera:

Func<int> del = () => 0;
byte[] asm_bytes = new byte[] { 0xb8, 0x15, 0x03, 0x00, 0x00, 0xbb, 0x42, 0x00, 0x00, 0x00, 0x03, 0xc3 };
// mov eax, 315h
// mov ebx, 42h
// add eax, ebx
// ret

int res = del.InjectAndRunX86ASM(asm_bytes); // should be 789 + 66 = 855

Por supuesto, también se podría escribir el siguiente método:

public static unsafe int RunX86ASM(byte[] asm)
{
    Func<int> del = () => 0; // create a delegate variable
    Array.Resize(ref asm, asm.Length + 1);

    // add a return instruction at the end to prevent any memory leaks
    asm[asm.Length - 1] = 0xC3;

    fixed (byte* ptr = &asm[0])
    {
        FieldInfo _methodPtr = typeof(Delegate).GetField("_methodPtr", BindingFlags.NonPublic | BindingFlags.Instance);
        FieldInfo _methodPtrAux = typeof(Delegate).GetField("_methodPtrAux", BindingFlags.NonPublic | BindingFlags.Instance);

        _methodPtr.SetValue(del, ptr);
        _methodPtrAux.SetValue(del, ptr);

        return del();
    }
}

Probablemente se podría hacer lo mismo con los métodos existentes (no con los delegados) mediante la reflexión:

// UNTESTED //

Action new_method_body = () => { };
MethodInfo nfo = typeof(MyType).GetMethod( ..... );
IntPtr ptr = nfo.MethodHandle.Value; // ptr is a pointer to the method in question

InjectX86ASM(new_method_body, new byte[] { ......., 0xC3 }); // assembly bytes to be injected

int target = new_method_body.Method.MethodHandle.Value.ToInt32();

byte[] redirector = new byte[] {
    0xE8,   // CALL INSTRUCTION + TARGET ADDRESS IN LITTLE ENDIAN
    (byte)(target & 0xff),
    (byte)((target >> 8) & 0xff),
    (byte)((target >> 16) & 0xff),
    (byte)((target >> 24) & 0xff),
    0xC3,   // RETURN INSTRUCTION
};
Marshal.Copy(redirector, 0, ptr, redirector.Length);


Utilice cualquier código bajo su propia responsabilidad. Los ejemplos de código deben compilarse con el /unsafe-cambio del compilador.

Puede consultar CInject para inyectar código en ensamblados .NET en el sitio de CodePlex. http://codeinject.codeplex.com/.No necesita tener ningún conocimiento sobre la inyección de código para inyectar ningún código cuando utiliza CInject.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top