0.00
Table of contents

RefinedPool

 |   |  6 min read

![[image_paranoid.png| Paranoid Ninja]]

Então esse post vai ser uma atualização do meu post anterior: carregamento-por-proxy onde eu mostrei a técnica do Paranoid Ninja de carregamento de dll por “proxy”, mas como já é de se esperar já existe regras para detectar esse tipo de técnica, eu já havia feito uso dessa técnica do paranoid ninja eu um projeto meu que foi o Hell-Code-Loader pois carregar a amsi.dll no processo de forma normal fazia com que o processo fosse detectado como malicioso, eu não pensei que tivesse algum outro projeto que aprimorasse essa técnica do paranoid ninja, e de fato, quando fiz o projeto ainda não havia, então a alguns dias eu me deparei com artigo: evading-elastic-callstack-signatures, graças a um usuário aleatório do servidor do yurirdev link:

![[image-6.png]]

Eu não pensei que esse projetinho iria virar um post, mas como estou pobre de ideias, melhor isso do que nada, então eu meio que realitizei em algumas partes desse post o meu proprio README do projeto então não estranhe.

Trabalho Original

Basicamente o trabalho/pesquisa realizado pelo @SAERXCIT possibilita adicionar mais um elemento a stack quebrando assim a rule de detecção, é bem simples de entender:

A técnica original do LibTPLoadLib (detalhada neste post) funciona assim:

  • Usa callbacks do Thread Pool para fazer proxy de chamadas a LoadLibraryA
  • Aproveita um call gadget (call r10; add rsp, 0x28; ret) para remover a função de callback da call stack

diagrama

A abordagem original exigia:

  • Carregar uma DLL específica e hardcoded (dsdmo_10.0.26100.1882.dll) que contém o gadget
  • A DLL precisava ser colocada manualmente em C:\dsdmo_10.0.26100.1882.dll
  • Isso cria uma dependência circular: carregar uma DLL suspeita para evadir a detecção de carregamento de DLLs

Basicamente eu vi isso mais como um obstáculo logo de começo, com todo o respeito ao dono original do projeto mas publicar um POC para mim é algo que quando você baixar, vou ter que apenas compilar e executar, mas não, você me obrigou a procurar DLLs que tivessem o gadget, no próprio README é escrito isso:

WARNING ⚠️ : This project is not usable as-is. The call gadget used for this PoC is no longer available in current versions of Windows. You’ll have to find your own. Read the blogpost for more info.

Tudo bem, o cara é o dono do projeto, eu tenho mais é que agradeçer do que reclamar, mas então, na minha cabeça eu pensei assim, “então para carregar uma dll eu vou ter que já ter carregado na memoria do processo atual uma dll que já tenha o gadget necessario?” então eu pensei cara vamos escrever o gadget em um code cave existente em alguma dll já existente na memoria do processo, claro isso tem seus vários pontos negativos, você vai ter que escrever na memoria de outra dll já carregada no processo, mas a vida é assim não é mesmo?

”Inovação”

Eu coloco entre aspas inovação pois, não inovei em nada sendo sincero, eu apenas eliminei a necessidade de DLLs externas, para fazer isso eu apenas fiz injeção dinâmica em code caves.

Então em vez de procurar gadgets pré-existentes em DLLs hardcoded, o RefinedPool:

  1. Enumera os módulos carregados no processo atual
  2. Localiza code caves dentro de seções executáveis, especificamente:
    • Procura dentro dos limites de funções existentes usando o Exception Directory (.pdata / tabela RUNTIME_FUNCTION)
    • Busca sequências contínuas de bytes nulos ou instruções INT3 (0xCC)
    • Garante que a cave tenha pelo menos 10 bytes para comportar o gadget
  3. Escreve o gadget dinamicamente na code cave descoberta:
    41 FF D2        ; call r10
    33 C0           ; xor eax, eax
    48 83 C4 28     ; add rsp, 0x28
    C3              ; ret
  4. Usa o gadget injetado no callback do Thread Pool, assim como na técnica original

Vantagens

  • Sem dependências de DLLs externas: funciona com módulos já carregados em memória
  • Mais furtivo: não há operações suspeitas de carregamento de DLL que possam disparar alertas
  • Mais prático: não depende de versões específicas do Windows nem de arquivos pré-posicionados
  • Adaptação dinâmica: pesquisa automaticamente em múltiplos módulos candidatos
  • Ciente de funções (function-aware): prioriza posicionar gadgets dentro de limites legítimos de funções para “melhor furtividade”

Resultado na Call Stack

resultado

resultado_execucao_shellcode

PIC Shellcode?

Bom eu sou muito desatendo e percebi que o projeto que fiz fugia um pouco da “IDEIA” que os projetos originais buscavam, basicamente se lermos o readme do projeto LibTPLoadLib vamos ver que ele menciona o uso do Crystal Palace.

O ponto que eu deixei passar é que o Crystal Palace é um linker especializado em criar PIC (Position-Independent Code) a partir de arquivos COFF. Ou seja:

  • Aqueles projetos foram feitos para serem bibliotecas (libs).

  • Eles são “peças” que você encaixa em um loader de shellcode maior.

Então é eu não segui esse padrão de “lib modular para linker de shellcode”, e só fui perceber depois, sou muito desatendo. Mas isso não quer dizer que o projeto não pode ser aprimorado para virar algo do tipo, então eu basicamente decidi fazer um POC apenas para mim, e gerei uma shellcode PIC do projeto em si, claro, tive que modificar “bastante” o código para conseguir fazer isso, no final eu consegui gerar a shellcode PIC do projeto:

![[Drawing 2026-02-20 00.00.48.excalidraw 1.png]]

Bom observando a print vemos que não muda quase nada kk, a diferença mesmo é que agora não foi executado uma SRDI, como na print anterior, então sim da para implementar deixar esse código PIC e não é nada difícil, só não vou publicar o PIC dele pois vou utilizar esse mesmo código para outro projeto futuro.

Você pode olhar esse video para ver o uso da técnica e também para ver o uso de como ficaria o projeto caso fosse utilizado como uma shellcode pic:

video


Agradecimentos

E é claro que eu tenho que deixar os meus mais sinceros agradecimentos ao: @AlmondOffSec / @SAERXCIT pela pesquisa e implementação originais que tornaram este “aprimoramento” possível.