patron - Inyección de código con C#
patron de inyeccion de dependencias c# (5)
Acabo de encontrar un enlace que trata este tema en detalle, así que quería volver a publicarlo aquí: Cómo inyectar un ensamblado .NET administrado (DLL) en otro proceso.
¿Puedes usar ganchos de Windows u otros métodos para hacer la inyección de código con c #? He visto muchas cosas sobre la inyección de código, pero todas se hacen en C / C ++. No conozco ninguno de esos idiomas y me cuesta mucho traducirlo. ¿Alguien tiene alguna idea sobre cómo hacer esto?
Kevin, es posible. Puede crear una biblioteca con el proceso de hook de ventana utilizando C ++ administrado. Todo lo que necesita hacer es inyectar este enlace en alguna aplicación utilizando WinAPI estándar (SetWindowsHookEx, etc.). Dentro de este enlace puede llamar a System :: AppDomain :: CurrentDomain-> Cargar método para cargar su ensamblado en AppDomain de la aplicación de destino. Luego puede llamar a los métodos definidos en su conjunto mediante reflexión. Por ejemplo, Snoop usa este método.
Mike Stall tiene esta muestra , que usa CreateRemoteThread. Tiene la ventaja de no requerir ningún C ++.
Puede ver CInject para la inyección de código en ensamblados .NET en el sitio 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 está utilizando CInject.
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 estoy uniendo a la fiesta bastante tarde, pero acabo de usar exactamente esto hace unas semanas: Un delegado contiene los campos privados IntPtr _methodPtr
e IntPtr _methodPtrAux
, que representan la dirección de memoria del cuerpo. Al configurar el campo (a través de la reflexión) a valores específicos, se puede modificar la dirección de la memoria a la que apunta el EIP.
Usando esta información, uno puede hacer lo siguiente:
- Crear una matriz con bytes de ensamblaje, que se deben ejecutar
- Mueva el puntero de método del delegado a los bytes en cuestión
- Llamar al delegado
- Lucro ???
(Por supuesto, puede cambiar el valor _methodPtr
a cualquier dirección de memoria, incluso en el espacio del kernel, pero esto podría requerir privilegios de ejecución apropiados).
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 usar 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 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();
}
}
Lo mismo podría hacerse probablemente con los métodos existentes (no con los delegados) a través de 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);
Use cualquier código bajo su propio riesgo. Los ejemplos de código se deben compilar con el modificador /unsafe
compilador /unsafe
.