
Plugin visualizador de cobertura de código binário para Ghidra
Dragon Dance é um plugin para Ghidra para visualizar e manipular os dados de cobertura de código binário. Os dados de cobertura podem ser importados de várias fontes de cobertura. Por enquanto, o plugin suporta as ferramentas de instrumentação binária Dynamorio e Intel Pin. O Dynamorio possui seu próprio módulo de coleta de cobertura chamado "drcov". O Intel Pin não fornece um módulo coletor de cobertura embutido. Para lidar com a falta de módulo, tive que escrever meu próprio módulo de coleta de cobertura para o Intel Pin. Então escrevi um módulo de coleta de cobertura para o Intel Pin chamado ddph (Dragon Dance Pin Helper). Então você pode usá-lo. Você pode ver o código fonte do ddph neste link. Se você tiver preguiça de compilar por conta própria, pode usar os binários compilados que forneci para Windows, macOS e Linux.

Dragon Dance pode importar e usar múltiplos dados de cobertura na mesma sessão. (Também suporta multi-sessão, mas por enquanto isso não é utilizável pela GUI). E você pode alternar entre eles ou aplicar operações de interseção, diferença, distinto ou soma entre eles rapidamente.
Dragon Dance permite visualizar a intensidade das instruções executadas. Assim, você pode ter uma dica sobre quais instruções são executadas com que frequência. Além disso, você pode visualizar a cobertura na janela do grafo de funções.


Ele oferece uma maneira flexível de brincar com os dados de cobertura. Você pode carregar, excluir, mostrar, fazer interseção, diferença, distinção, soma com eles. A seção seguinte conterá o sistema de script e a API. Pressione as teclas Alt + Enter para executar o script.
As funções embutidas são implementações das operações internas de cobertura para fornecer uma interface para o sistema de script. Uma função embutida pode retornar uma variável de objeto de cobertura ou nada. As funções embutidas podem ter aliases.
Elas aceitam o Built-in Arg como parâmetro. Os parâmetros podem ter comprimento variável.
Built-in Arg é uma referência para armazenar diferentes tipos de valores. Os Built-in Args são passados na ordem da esquerda para a direita. O Built-in Arg pode conter os seguintes tipos de valor:
As variáveis são responsáveis por armazenar apenas o objeto de cobertura. Elas podem ser carregadas por funções embutidas. Elas podem ser passadas como parâmetro (Built-in Arg) para as Funções Embutidas.
Existem dois tipos de objeto de cobertura.
Objeto de Cobertura Físico e Objeto de Cobertura Lógico
Objeto de Cobertura Físico aponta para um objeto de cobertura que foi carregado diretamente do arquivo de cobertura. Eles são visíveis na tabela de cobertura que está na GUI. Então você pode interagir com eles através das operações da GUI.
Objeto de Cobertura Lógico aponta para um objeto de cobertura que foi processado em uma função embutida e retornado como resultado. Eles não são visíveis na GUI, mas podem existir em uma Variável até serem destruídos.
O objeto de cobertura é mantido pelo objeto Variável automaticamente para ambos os tipos de objeto de cobertura. Por exemplo;``` cov1 = load("firstcoverage.out") cov2 = load("secondcov.out")
cov1 = diff(cov1,cov2)
Neste exemplo, cov1 e cov2 são variáveis. E ambas as variáveis possuem um objeto de cobertura físico. A função embutida `diff` recebe ambas as variáveis e define o valor de retorno na variável cov1. Essa operação de sobrescrita definirá o objeto de cobertura resultante na variável, mas não exclui o objeto de cobertura porque ele é um objeto de cobertura físico. Esses dados de cobertura permanecerão na sessão e também na tabela da GUI.
Vamos pensar no exemplo anterior assim;```
cov1 = load("first.out")
cov2 = load("second.out")
cov3 = load("third.out")
rvar = sum(cov1,cov2,cov3)
rvar = diff(rvar, cov2)
In this example, três variáveis de cobertura física entram na operação de soma, e a operação de soma retorna um objeto de resultado de cobertura lógica. Em seguida, a operação de diff recebe uma variável lógica e uma física e sobrescreve a variável chamada rvar.
Neste caso, o resultado será definido como rvar e seu valor de cobertura anterior será destruído imediatamente. Por ser um objeto lógico, deve ser excluído para evitar vazamento de objeto. Se você quiser destruir uma variável que contenha um objeto de cobertura física, é necessário chamar o built-in discard. Todos os built-ins serão detalhados abaixo.
Você pode escrever scripts complexos usando chamadas aninhadas de built-ins, algo como:
cres = diff(intersect(a, load("another.log"), c, d), sum(e,f) )
você não precisa escrever a lógica linha por linha.
A documentação da API a seguir e seus comportamentos podem mudar até atingir a versão final.
clear()
| Propriedade | Descrição |
|---|---|
| Valor de Retorno | Nenhum |
| Contagem Mínima de Parâmetros | 0 |
| Contagem Máxima de Parâmetros | 0 |
| Descrição | Este built-in limpa a cobertura que está sendo visualizada e define a cobertura ativa como nula. |
| Aliases | Nenhum |
cwd( String : workingDirectory )
| Propriedade | Descrição |
|---|---|
| Valor de Retorno | Nenhum |
| Contagem Mínima de Parâmetros | 1 |
| Contagem Máxima de Parâmetros | 1 |
| Descrição | Define o diretório de trabalho atual com o caminho informado. Todas as chamadas de importação sem caminho absoluto após o cwd procurarão os arquivos de cobertura no diretório de trabalho ativo. |
| Aliases | Nenhum |
diff( Variável : var1, var2, ..... varN )
| Propriedade | Descrição |
|---|---|
| Valor de Retorno | Variável |
| Contagem Mínima de Parâmetros | 2 |
| Contagem Máxima de Parâmetros | Ilimitado |
| Descrição | Aplica a operação de diferença às variáveis de comprimento variável fornecidas. E retorna a variável de cobertura resultante. |
| Aliases | Nenhum |
discard( Variável : var1, var2, ..... varN )