Simple EDR
Bom, neste post vou criar uma ideia para o começo de um EDR/AV básico que provavelmente eu nunca vou terminar.
A ideia principal agora é criar uma DLL simples que utilize a MinHook para conseguir realizar um hook em APIs.
Como vai funcionar?
Primeiro vamos fazer o código principal que será responsável por injetar nossa dll no executavel que queremos monitorar. O principal intuito vai ser monitorar as APIs utilizadas por loaders. O intuito é apenas monitorar as chamadas de API da kernel32. Ou seja, se o programa utilizar técnicas como syscalls indiretas ou diretas, nosso EDR/AV não terá como detectar o loader.
Código que obtém o ID do processo com o nome fornecido:
DWORD GetProcessIdByName(const wstring& processName) {
DWORD processId = 0;
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 processEntry = { sizeof(PROCESSENTRY32) };
if (Process32First(snapshot, &processEntry)) {
do {
if (processName == processEntry.szExeFile) {
processId = processEntry.th32ProcessID;
break;
}
} while (Process32Next(snapshot, &processEntry));
}
CloseHandle(snapshot);
return processId;
}Código para Injeção da DLL:
Abertura do Processo Alvo:Utiliza a APIOpenProcesspara obter um identificador para o processo alvo, especificado peloprocessId.Localização da Função LoadLibraryW:Obtém o endereço da funçãoLoadLibraryWna bibliotecakernel32.dllque será utilizada para carregar a DLL no processo alvo.Alocação de Memória no Processo Alvo:UsaVirtualAllocExpara alocar memória no processo alvo para armazenar o caminho da DLL.Escrita do Caminho da DLL na Memória do Processo Alvo:ComWriteProcessMemory.Criação de um Novo Thread:Cria um novo thread no processo alvo comCreateRemoteThread, que executa a funçãoLoadLibraryWpara carregar a DLL.Aguarda a Conclusão da Injeção:UtilizaWaitForSingleObjectpara aguardar o término do thread.Limpeza e Fechamento:Após a execução, libera a memória alocada comVirtualFreeExe fecha o handle do processo e do thread comCloseHandle.
NamedPipeServer para Comunicação:
O NamedPipeServer é basicamente responsável por criar um servidor de Named Pipe que escuta por conexões e processa mensagens recebidas.
Explicação do Código:
Criação do Named Pipe:Utiliza CreateNamedPipe para criar um pipe nomeado (MyPipe) que aceita conexões. Configurado para acesso de entrada (PIPE_ACCESS_INBOUND), com suporte a mensagens e leitura no modo de mensagens.Conexão com o Pipe:ConnectNamedPipe aguarda a conexão de um cliente ao pipe. Se falhar, o erro é exibido e o pipe é fechado.Leitura de Dados:Usa ReadFile para ler os dados do pipe. Se ocorrer um erro de leitura ou o pipe for quebrado (ERROR_BROKEN_PIPE), o loop de leitura é interrompido. Se a leitura for bem-sucedida, os dados são exibidos no console.Fechamento e Repetição:Após a leitura ou se a conexão falhar, o handle do pipe é fechado. O servidor continua a executar e criar novos pipes em um loop infinito.
Inclusão da MinHook:
Este trecho de código inclui a biblioteca MinHook, uma popular biblioteca de hooking para a API do Windows.
Funções:
Aqui definidos tipos de função para algumas das APIs do Windows que serão hooked. Cada tipo de função corresponde a uma função da API do Windows que será substituída por uma função personalizada para monitorar ou modificar seu comportamento.
Ponteiros para as funções originais:
Essa parte define ponteiros para as funções originais da API do Windows que serão substituídas pelos hooks. Esses ponteiros são necessários para que o código possa chamar as funções originais após interceptá-las.
Enviar Mensagem para o Named Pipe:
Essa parte é responsável por enviar mensagens para o nosso Named Pipe.
Código Responsavel por terminar o processo:
Essa parte do código exibe uma caixa de mensagem de alerta e em seguida encerra o processo atual. essa função será usada para bloquear a execução do processo caso ele faça uso de uma API que consideramos maliciosa.
Função para o hook OpenProcess:
Esta parte é uma função de um hook para a função OpenProcess. Ela vai interceptar as chamadas para a API OpenProcess, então vai enviar uma mensagem com o ID do processo alvo para nosso Named Pipe, e depois irá chamar a função original do OpenProcess.
Função para o hook WriteProcessMemory:
Essa é outra função de hook mas para a API WriteProcessMemory. essa parte registra detalhes sobre o endereço de memória que está sendo modificado e envia para o nosso Named Pipe, e depois chama a função original WriteProcessMemory para garantir que a operação de escrita ocorra normalmente.
Função para o hook VirtualAllocEx:
Função para o hook CreateRemoteThread:
Essa é outra função de hook, mas para a API CreateRemoteThread. Diferente das outras, essa irá chamar a função BlockExecution que irá barrar a execução do programa e em seguida, chamará a função original CreateRemoteThread.
Função para Implementar o hook:
Agora nossa função SetupHook vai configurar todos os hooks necessários utilizando a biblioteca MinHook. então ela irá criar os hooks para VirtualAllocEx, CreateRemoteThread, OpenProcess, e WriteProcessMemory, e finalmente habilita todos os hooks criados. Se houver falhas em qualquer uma dessas operações, uma mensagem de erro é enviada para o Named Pipe.
Iniciar thread após a dll ser carregada:
Agora por fim a função DllMain é o ponto de entrada para a DLL. Quando a DLL é carregada DLL_PROCESS_ATTACH, ela desativa as chamadas de thread para a DLL e configura os hooks. Quando a DLL é descarregada DLL_PROCESS_DETACH, ela desativa todos os hooks e desinicializa a biblioteca MinHook.
Entendendo o que fizemos:
O código que fizemos implementa um sistema de hooking para monitorar e controlar chamadas para funções críticas da API do Windows, como OpenProcess, WriteProcessMemory, VirtualAllocEx, e CreateRemoteThread. O uso de hooks nos permite interceptar essas funções para detectar e bloquear ações que possam indicar comportamento malicioso. e enviar mensagens de alerta sobre o uso dessas APIs para o nosso "painel".
Prova de Conceito:
Last updated