Por Caio A. P. Burgardt

Área de memória alocada e não escrita é um erro de programação comum. Quem costuma programar para Windows, pode esquecer de inicializar propriamente uma variável, e acarretar, assim, comportamentos inesperados na aplicação. Esse é um erro frequente, e, por isso mesmo, o sistema operacional é preparado para dar o aviso. Afinal, áreas de memória alocadas e não escritas podem se tornar um problema de segurança. Portanto, é necessário que sejam investigadas e corrigidas.

Mas e se, mais que isso, o programador use do erro de programação, para criar em sua aplicação um anti-debugging? Afinal, novas técnicas anti-debugging são sempre bem vindas, como veremos mais adiante; sendo sempre importante a detecção e prevenção do debugging não desejado.

Primeiramente, é preciso que se faça o programa reconhecer que está em um processo de debug. Uma forma simples do programa detectar que está sendo executado em um debugger é através dos padrões de bytes na heap, após alocações de memória. Ao investigar um bug de erro de memória alocada e não escrita, aos olhos de um debugger, encontramos o seguinte cenário:

A posição de memória relacionada à variável não inicializada está preenchida com o valor hexadecimal “0xbaadf00d”, onde temos 0D F0 AD BA, em little endian, ou melhor BA AD F0 0D, sendo repetido diversas vezes.

Em C/C++, quando alocamos dinamicamente uma variável, e esquecemos de a inicializar com um valor, a variável pode possuir o que chamamos de ‘lixo de memória’, isto é, informação residual na memória que não é mais útil para futuras computações. Entretanto, o padrão encontrado (“0xbaadf00d”) não aparenta ser lixo de memória, pois ele se repete em toda execução durante o debugging e indica ter algum significado, o que pode ser percebido pela fácil leitura da expressão inglesa “bad food” em l33tspeak.

Hewardt e Pravat [1] afirmam que o valor “0xbaadf00d” é utilizado pela função HeapAlloc() do Windows durante o debugging para auxiliar na detecção de bugs. Já em nobugs.org [2], descobrimos a existência de outros padrões de bytes colocados na memória em situações especiais para ajudar no descobrimento de bugs:

Para reproduzir os valores acima, preparamos um programa que tenta replicar os casos de alocação na heap nos diferentes casos:

A seguir, estão os 4 possíveis resultados, alterando as configurações de compilação:

Técnicas anti-debugging, como esta, são importantes para que os desenvolvedores possam dificultar a utilização de engenharia reversa contra seu software, a fim de proteger sua propriedade intelectual. Porém, não podemos deixar de reconhecer que tais técnicas também podem ser usadas em cenários escusos e ilegais; quando, por exemplo, atores maliciosos planejam dificultar a análise de seus malwares.

Essas técnicas consistem em explorar comportamentos de debuggers a fim de realizar a detecção de suas ações; e por fim, impedir seu carregamento ou execução em trechos críticos. Para demonstrar que é possível utilizar essa propriedade da heap como um mecanismo anti-debugging, apresentamos, abaixo, um trecho de código que causa o comportamento anteriormente descrito:

Para finalizar, ressaltamos a importância de conhecer os efeitos que um debugger pode causar na sua aplicação, mesmo que passivamente. Por isso, a fim de implementar uma solução forte de anti-debugging, deve-se utilizar várias técnicas, de modo a criar uma camada de dificuldade considerável contra o processo de engenharia reversa, sendo a técnica apresentada aqui, apenas mais uma que pode ser utilizada com tal finalidade.

Referências

[1] Advanced Windows Debugging de Mario Hewardt e Daniel Pravat [https://www.oreilly.com/library/view/advanced-windows-debugging/9780321374462/]

[2] http://www.nobugs.org/developer/win32/debug_crt_heap.html