Como Funciona
O algoritmo do EntropyReducer é determinado pelos valores de BUFF_SIZE e NULL_BYTES. A seguir está como o EntropyReducer organizaria seu payload se BUFF_SIZE fosse definido como 4 e NULL_BYTES como 2.

Algoritmo de Ofuscação
- O EntropyReducer primeiro verifica se o payload bruto de entrada tem um tamanho que seja múltiplo de
BUFF_SIZE; caso não seja, ele o preenche para que seja.
- Em seguida, ele pega cada bloco de
BUFF_SIZE do payload e cria um nó de lista encadeada para ele, usando a função InitializePayloadList, inicializando o payload como uma lista encadeada.
- O nó criado terá um buffer vazio de tamanho
NULL_BYTES, que será usado para reduzir a entropia
- Neste ponto, embora o EntropyReducer tenha concluído sua tarefa reduzindo a entropia do payload, ele não para por aqui. Ele então continua randomizando a ordem de cada nó na lista encadeada, quebrando a ordem do payload bruto. Esta etapa é feita por meio de um Algoritmo de Merge Sort implementado através da função MergeSort.
- A lista encadeada ordenada fica em ordem aleatória porque o valor pelo qual a lista encadeada é ordenada é o valor XOR dos três primeiros bytes do payload bruto; esse valor determina sua posição na lista encadeada reorganizada, e esta etapa pode ser vista aqui
- Como salvar uma lista encadeada em um arquivo é impossível devido ao fato de ela estar ligada por ponteiros, somos forçados a serializá-la.
- A serialização da lista encadeada gerada é feita através da função
Obfuscate aqui.
- Depois disso, os dados serializados estão prontos para serem gravados no arquivo de saída.
Algoritmo de Desofuscação
- Como a última etapa no
Algoritmo de Ofuscação foi a serialização da lista encadeada, a primeira coisa que deve ser feita aqui é desserializar o payload ofuscado, gerando uma lista encadeada a partir dele; esta etapa é feita aqui na função Deobfuscate.
- A próxima etapa é ordenar a lista encadeada usando o Id do nó, o que é feito usando o mesmo Algoritmo de Merge Sort usado anteriormente.
- Agora, a lista encadeada está na ordem correta para reconstruir os bytes do payload como deveriam ser. Então simplesmente extraímos os bytes originais do payload de cada nó, como feito aqui.
- A última etapa é liberar os nós alocados, o que é feito aqui.
Uso
- O EntropyReducer simplesmente lê o arquivo de payload bruto a partir da linha de comando e grava a versão ofuscada no mesmo nome de arquivo prefixado com ".ER".
- O tamanho do payload ofuscado final varia dependendo dos valores de
BUFF_SIZE e NULL_BYTES. No entanto, ele pode ser determinado usando a seguinte equação
FinalSize = ((OriginalSize + BUFF_SIZE - OriginalSize % BUFF_SIZE ) / BUFF_SIZE) * (BUFF_SIZE + NULL_BYTES + sizeof(INT))
O projeto PoC neste repositório é usado para executar o arquivo ".ER" gerado como exemplo de desserialização e desofuscação do mesmo.
Incluir em Seus Projetos
Tudo o que você precisa fazer é adicionar os arquivos EntropyReducer.c e EntropyReducer.h ao seu projeto e chamar a função Deobfuscate. Você pode consultar PoC/main.c como referência.
Exemplo de Saída
Neste exemplo, BUFF_SIZE foi definido como 3 e NULL_BYTES como 1.
- O payload bruto, primeiro chunk do payload (
FC 48 83)

- O mesmo chunk do payload, mas em um offset diferente

Resultado
- O shellcode calc x64 gerado pelo metasploit possui entropia de
5.883, visualizado pelo pestudio.

- O mesmo arquivo, criptografado com AES, apresenta entropia de
7.110.

- Resultado praticamente igual com o algoritmo RC4 também;
7.210

- Usando o EntropyReducer, no entanto, a entropia fica ainda menor do que a do payload bruto original;
4.093

O Algoritmo Merge Sort foi retirado de c-linked-list.