Pergunta

Você pode usar ganchos do Windows ou outros métodos para fazer injeção de código com c#?Já vi muitas coisas sobre injeção de código, mas todas elas são feitas em C/C++.Não conheço nenhum desses idiomas e tenho muita dificuldade em traduzir.Alguém tem alguma idéia de como fazer isso?

Foi útil?

Solução

Kevin, é possível.Você pode criar uma biblioteca com procedimento de gancho de janela usando C++ gerenciado.Tudo que você precisa fazer é injetar esse gancho em algum aplicativo usando WinAPI padrão (SetWindowsHookEx etc.).Dentro deste gancho você pode chamar o método System::AppDomain::CurrentDomain->Load para carregar seu assembly no AppDomain do aplicativo de destino.Então você pode chamar métodos definidos em sua montagem usando reflexão.Por exemplo, bisbilhoteiro usa esse método.

Outras dicas

Mike Stall tem esta amostra, que usa CreateRemoteThread.Tem a vantagem de não exigir nenhum C++.

EDITAR: Parece que interpretei mal a pergunta....Fiquei com a impressão de que a questão era sobre injeção de código no processo atual.


Estou entrando na festa um pouco tarde, mas usei exatamente isso há algumas semanas:

Um delegado contém os campos privados IntPtr _methodPtr e IntPtr _methodPtrAux, que representam o endereço de memória do corpo.Ao definir o campo (via reflexão) para valores específicos, pode-se alterar o endereço de memória para o qual o EIP estará apontando.
Usando essas informações, pode-se fazer o seguinte:

  1. Crie um array com bytes assembly, que serão executados
  2. Mova o ponteiro do método do delegado para os bytes em questão
  3. Chame o delegado
  4. Lucro ???

(Claro, você pode alterar o _methodPtr-value para qualquer endereço de memória - mesmo no espaço do kernel, mas isso pode exigir privilégios de execução apropriados).


Eu tenho um exemplo de código funcional aqui, se você quiser:

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 pode ser usado da seguinte forma:

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

Claro, também poderia escrever o seguinte 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();
    }
}

O mesmo provavelmente poderia ser feito com métodos existentes (não delegados) por meio de reflexão:

// 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 qualquer código por sua conta e risco. Os exemplos de código devem ser compilados com o /unsafe-comutador do compilador.

Você pode verificar o CInject para injeção de código em assemblies .NET no site CodePlex http://codeinject.codeplex.com/.Você não precisa ter nenhum conhecimento sobre injeção de código para injetar qualquer código ao usar o CInject.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top