Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
Ferramentas/GitHubGitHub/google/afl
Análise de VulnerabilidadesFuzzingTestes de PenetraçãoAnálise de BináriosArchived
GitHubgoogle/afl

AFL

american fuzzy lop - um fuzzer voltado para segurança

Ver Repositório
4.2k6714há 5 anosRevisado pelo Kitploit
Site

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

american fuzzy lop

Build Status

Desenvolvido originalmente por Michal Zalewski [email protected].

Consulte QuickStartGuide.txt se você não tiver tempo de ler este arquivo.

1) Desafios do fuzzing guiado

Fuzzing é uma das estratégias mais poderosas e comprovadas para identificar problemas de segurança em software do mundo real; é responsável pela grande maioria dos bugs de execução remota de código e escalonamento de privilégios encontrados até hoje em software de segurança crítica.

Infelizmente, o fuzzing também é relativamente superficial; mutações cegas e aleatórias tornam muito improvável alcançar certos caminhos de código no software testado, deixando algumas vulnerabilidades totalmente fora do alcance dessa técnica.

Houve inúmeras tentativas de resolver esse problema. Uma das primeiras abordagens - cujo pioneiro foi Tavis Ormandy - é a destilação de corpus. O método depende de sinais de cobertura para selecionar um subconjunto de sementes interessantes de um corpus massivo e de alta qualidade de arquivos candidatos, e então submetê-los a fuzzing por meios tradicionais. A abordagem funciona excepcionalmente bem, mas exige que esse corpus esteja prontamente disponível. Além disso, as medições de cobertura de blocos fornecem apenas uma compreensão muito simplista do estado do programa e são menos úteis para guiar o esforço de fuzzing a longo prazo.

Outras pesquisas mais sofisticadas focaram em técnicas como análise de fluxo de programa ("execução concólica"), execução simbólica ou análise estática. Todos esses métodos são extremamente promissores em ambientes experimentais, mas tendem a sofrer com problemas de confiabilidade e desempenho em usos práticos - e atualmente não oferecem uma alternativa viável às técnicas de fuzzing "burro".

2) A abordagem do afl-fuzz

American Fuzzy Lop é um fuzzer de força bruta combinado com um algoritmo genético guiado por instrumentação extremamente simples, mas sólido como uma rocha. Ele usa uma forma modificada de cobertura de arestas para capturar sem esforço mudanças sutis em escala local no fluxo de controle do programa.

Baixar ferramenta

Simplificando um pouco, o algoritmo geral pode ser resumido como:

  1. Carregar os casos de teste iniciais fornecidos pelo usuário na fila,

  2. Pegar o próximo arquivo de entrada da fila,

  3. Tentar reduzir o caso de teste ao menor tamanho que não altere o comportamento medido do programa,

  4. Mutar repetidamente o arquivo usando uma variedade equilibrada e bem pesquisada de estratégias tradicionais de fuzzing,

  5. Se alguma das mutações geradas resultar em uma nova transição de estado registrada pela instrumentação, adicionar a saída mutada como uma nova entrada na fila.

  6. Ir para 2.

Os casos de teste descobertos também são periodicamente eliminados para remover aqueles que se tornaram obsoletos por descobertas mais novas e com maior cobertura; e passam por várias outras etapas de minimização de esforço orientadas por instrumentação.

Como resultado secundário do processo de fuzzing, a ferramenta cria um corpus pequeno e autocontido de casos de teste interessantes. Esses casos são extremamente úteis para semear outros regimes de teste que exigem muito trabalho ou recursos - por exemplo, para testes de estresse em navegadores, aplicativos de escritório, suítes gráficas ou ferramentas de código fechado.

O fuzzer é minuciosamente testado para entregar desempenho imediato muito superior ao fuzzing cego ou a ferramentas baseadas apenas em cobertura.

3) Instrumentando programas para uso com AFL

Quando o código-fonte está disponível, a instrumentação pode ser injetada por uma ferramenta complementar que funciona como substituto direto do gcc ou clang em qualquer processo de build padrão para código de terceiros.

A instrumentação tem um impacto de desempenho bastante modesto; em conjunto com outras otimizações implementadas pelo afl-fuzz, a maioria dos programas pode ser submetida a fuzzing tão rápido ou até mais rápido do que seria possível com ferramentas tradicionais.

A maneira correta de recompilar o programa alvo pode variar dependendo das especificidades do processo de build, mas uma abordagem quase universal seria:```shell $ CC=/path/to/afl/afl-gcc ./configure $ make clean all

root@kitploit:~
Para programas em C++, você também vai querer definir `CXX=/path/to/afl/afl-g++`.

Os wrappers do clang (afl-clang e afl-clang++) podem ser usados da mesma forma;
usuários do clang também podem optar por usar um modo de instrumentação de maior desempenho,
conforme descrito em llvm_mode/README.llvm.

Ao testar bibliotecas, você precisa encontrar ou escrever um programa simples que leia
dados do stdin ou de um arquivo e os passe para a biblioteca testada. Nesse
caso, é essencial vincular esse executável a uma versão estática da
biblioteca instrumentada, ou garantir que o arquivo .so correto seja carregado em
tempo de execução (geralmente definindo `LD_LIBRARY_PATH`). A opção mais simples é uma compilação
estática, geralmente possível via:```shell
$ CC=/path/to/afl/afl-gcc ./configure --disable-shared

Definir AFL_HARDEN=1 ao chamar 'make' fará com que o wrapper CC ative automaticamente opções de endurecimento de código que facilitam a detecção de bugs simples de memória. Libdislocator, uma biblioteca auxiliar incluída com AFL (veja libdislocator/README.dislocator) também pode ajudar a descobrir problemas de corrupção de heap.

PS. Usuários de ASAN são aconselhados a revisar o arquivo notes_for_asan.txt para importantes ressalvas.

4) Instrumentando aplicativos somente binários

Quando o código-fonte NÃO está disponível, o fuzzer oferece suporte experimental para instrumentação rápida e on-the-fly de binários black-box. Isso é realizado com uma versão do QEMU rodando no modo pouco conhecido de "emulação de espaço do usuário".

O QEMU é um projeto separado do AFL, mas você pode compilar o recurso de forma conveniente fazendo:```shell $ cd qemu_mode $ ./build_qemu_support.sh

root@kitploit:~
Para instruções adicionais e ressalvas, consulte qemu_mode/README.qemu.

O modo é aproximadamente 2 a 5 vezes mais lento que a instrumentação em tempo de compilação, é
menos propício à paralelização e pode ter algumas outras peculiaridades.

## 5) Escolhendo casos de teste iniciais

Para operar corretamente, o fuzzer requer um ou mais arquivos iniciais que
contenham um bom exemplo dos dados de entrada normalmente esperados pelo
aplicativo alvo. Há duas regras básicas:

  - Mantenha os arquivos pequenos. Abaixo de 1 kB é o ideal, embora não seja estritamente necessário.
    Para uma discussão sobre por que o tamanho importa, consulte [perf_tips.txt](https://github.com/google/afl/blob/master/docs/perf_tips.txt).

  - Use vários casos de teste somente se forem funcionalmente diferentes entre
    si. Não adianta usar cinquenta fotos de férias diferentes para
    fazer fuzzing em uma biblioteca de imagens.

Você pode encontrar muitos bons exemplos de arquivos iniciais no subdiretório testcases/
que acompanha esta ferramenta.

PS. Se um grande corpus de dados estiver disponível para triagem, você pode querer usar
o utilitário afl-cmin para identificar um subconjunto de arquivos funcionalmente distintos que
exercitem diferentes caminhos de código no binário alvo.

## 6) Fuzzing de binários

O processo de fuzzing em si é executado pelo utilitário afl-fuzz. Este programa
requer um diretório somente leitura com casos de teste iniciais, um local separado para
armazenar suas descobertas, além de um caminho para o binário a ser testado.

Para binários alvo que aceitam entrada diretamente do stdin, a sintaxe usual é:```shell
$ ./afl-fuzz -i testcase_dir -o findings_dir /path/to/program [...params...]

Para programas que recebem entrada de um arquivo, use '@@' para marcar a posição na linha de comando do alvo onde o nome do arquivo de entrada deve ser colocado. O fuzzer substituirá isso por você:```shell $ ./afl-fuzz -i testcase_dir -o findings_dir /path/to/program @@

root@kitploit:~
Você também pode usar a opção -f para que os dados mutados sejam gravados em um
arquivo específico. Isso é útil se o programa esperar uma determinada extensão de arquivo ou algo assim.

Binários não instrumentados podem ser fuzzados no modo QEMU (adicione -Q na linha
de comando) ou em um modo fuzzer cego tradicional (especifique -n).

Você pode usar -t e -m para substituir o tempo limite padrão e o limite de memória do
processo executado; exemplos raros de alvos que podem precisar dessas configurações
ajustadas incluem compiladores e decodificadores de vídeo.

Dicas para otimizar o desempenho do fuzzing são discutidas em [perf_tips.txt](https://github.com/google/afl/blob/master/docs/perf_tips.txt).

Observe que o afl-fuzz começa executando uma série de etapas de fuzzing
determinísticas, que podem levar vários dias, mas tendem a produzir casos de teste
elegantes. Se você quiser resultados rápidos e sujos imediatamente - semelhante ao
zzuf e a outros fuzzers tradicionais - adicione a opção -d à linha de comando.

## 7) Interpretando a saída

Consulte o arquivo [status_screen.txt](https://github.com/google/afl/blob/master/docs/status_screen.txt) para obter informações sobre
como interpretar as estatísticas exibidas e monitorar a saúde do processo.
Certifique-se de consultar esse arquivo especialmente se algum elemento da interface estiver
destacado em vermelho.

O processo de fuzzing continuará até você pressionar Ctrl-C. No mínimo, você quer
permitir que o fuzzer complete um ciclo de fila, o que pode levar de algumas horas
a uma semana ou mais.

Existem três subdiretórios criados dentro do diretório de saída e atualizados
em tempo real:

  - queue/   - casos de teste para cada caminho de execução distinto, além de todos os
               arquivos iniciais fornecidos pelo usuário. Este é o corpus sintetizado
               mencionado na seção 2.
               Antes de usar este corpus para qualquer outra finalidade, você pode reduzi-lo
               para um tamanho menor usando a ferramenta afl-cmin. A ferramenta encontrará
               um subconjunto menor de arquivos que oferece cobertura de arestas equivalente.

  - crashes/ - casos de teste exclusivos que fazem o programa testado receber um
               sinal fatal (por exemplo, SIGSEGV, SIGILL, SIGABRT). As entradas são
               agrupadas pelo sinal recebido.

  - hangs/   - casos de teste exclusivos que fazem o programa testado atingir o tempo limite. O
               limite de tempo padrão antes que algo seja classificado como travamento é
               o maior entre 1 segundo e o valor do parâmetro -t.
               O valor pode ser ajustado com precisão definindo AFL_HANG_TMOUT, mas isso
               raramente é necessário.

Crashes e travamentos são considerados "exclusivos" se os caminhos de execução associados
envolverem quaisquer transições de estado não vistas em falhas registradas anteriormente. Se um
único bug puder ser alcançado de várias maneiras, haverá alguma inflação na contagem
no início do processo, mas isso deve diminuir rapidamente.

Os nomes de arquivo para crashes e travamentos são correlacionados com entradas de fila pai,
sem falhas. Isso deve ajudar na depuração.

Quando você não consegue reproduzir um crash encontrado pelo afl-fuzz, a causa mais provável é
que você não está definindo o mesmo limite de memória usado pela ferramenta. Tente:```shell
$ LIMIT_MB=50
$ ( ulimit -Sv $[LIMIT_MB << 10]; /path/to/tested_binary ... )

Mude LIMIT_MB para corresponder ao parâmetro -m passado ao afl-fuzz. No OpenBSD, altere também -Sv para -Sd.

Qualquer diretório de saída existente também pode ser usado para retomar trabalhos abortados; tente:```shell $ ./afl-fuzz -i- -o existing_output_dir [...etc...]

root@kitploit:~
Se você tiver o gnuplot instalado, também pode gerar alguns gráficos interessantes para qualquer tarefa de fuzzing ativa usando o afl-plot. Para um exemplo de como isso se parece, veja [http://lcamtuf.coredump.cx/afl/plot/](http://lcamtuf.coredump.cx/afl/plot/).

## 8) Fuzzing paralelizado

Cada instância do afl-fuzz ocupa aproximadamente um núcleo. Isso significa que em sistemas multi-core, a paralelização é necessária para utilizar totalmente o hardware. Para dicas sobre como aplicar fuzzing a um alvo comum em múltiplos núcleos ou múltiplas máquinas em rede, consulte [parallel_fuzzing.txt](https://github.com/google/afl/blob/master/docs/parallel_fuzzing.txt).

O modo de fuzzing paralelo também oferece uma maneira simples de interfacear o AFL com outros fuzzers, com mecanismos de execução simbólica ou concólica, e assim por diante; novamente, veja a última seção de [parallel_fuzzing.txt](https://github.com/google/afl/blob/master/docs/parallel_fuzzing.txt) para dicas.

## 9) Dicionários de fuzzing

Por padrão, o mecanismo de mutação do afl-fuzz é otimizado para formatos de dados compactos — por exemplo, imagens, multimídia, dados compactados, sintaxe de expressões regulares ou scripts de shell. Ele é um pouco menos adequado para linguagens com vocabulário particularmente verboso e redundante — notavelmente incluindo HTML, SQL ou JavaScript.

Para evitar o trabalho de criar ferramentas com consciência de sintaxe, o afl-fuzz oferece uma maneira de semear o processo de fuzzing com um dicionário opcional de palavras-chave da linguagem, cabeçalhos mágicos ou outros tokens especiais associados ao tipo de dados alvo — e usar isso para reconstruir a gramática subjacente em tempo real:

  [http://lcamtuf.blogspot.com/2015/01/afl-fuzz-making-up-grammar-with.html](http://lcamtuf.blogspot.com/2015/01/afl-fuzz-making-up-grammar-with.html)

Para usar esse recurso, primeiro você precisa criar um dicionário em um dos dois formatos discutidos em dictionaries/README.dictionaries; e então apontar o fuzzer para ele por meio da opção -x na linha de comando.

(Vários dicionários comuns já são fornecidos nesse subdiretório também.)

Não há como fornecer descrições mais estruturadas da sintaxe subjacente, mas o fuzzer provavelmente descobrirá parte disso com base apenas no feedback de instrumentação. Isso realmente funciona na prática, por exemplo:

  [http://lcamtuf.blogspot.com/2015/04/finding-bugs-in-sqlite-easy-way.html](http://lcamtuf.blogspot.com/2015/04/finding-bugs-in-sqlite-easy-way.html)

PS. Mesmo quando nenhum dicionário explícito é fornecido, o afl-fuzz tentará extrair tokens de sintaxe existentes no corpus de entrada observando a instrumentação muito de perto durante inversões determinísticas de bytes. Isso funciona para alguns tipos de parsers e gramáticas, mas não é tão bom quanto o modo -x.

Se for realmente difícil obter um dicionário, outra opção é deixar o AFL rodar por um tempo e depois usar a biblioteca de captura de tokens que acompanha o AFL como um utilitário complementar. Para isso, veja libtokencap/README.tokencap.

## 10) Triagem de crashes

O agrupamento de crashes baseado em cobertura geralmente produz um pequeno conjunto de dados que pode ser rapidamente triado manualmente ou com um script muito simples de GDB ou Valgrind. Cada crash também é rastreável até o caso de teste pai (não-crash) na fila, facilitando o diagnóstico de falhas.

Dito isso, é importante reconhecer que alguns crashes de fuzzing podem ser difíceis de avaliar rapidamente quanto à explorabilidade sem muito trabalho de depuração e análise de código. Para auxiliar nessa tarefa, o afl-fuzz suporta um modo muito exclusivo de "exploração de crashes" habilitado com a flag -C.

Nesse modo, o fuzzer recebe um ou mais casos de teste que causam crash como entrada e usa suas estratégias de fuzzing orientadas por feedback para enumerar muito rapidamente todos os caminhos de código que podem ser alcançados no programa, mantendo-o no estado de crash.

Mutações que não resultam em crash são rejeitadas; assim como quaisquer alterações que não afetem o caminho de execução.

A saída é um pequeno corpus de arquivos que pode ser examinado muito rapidamente para ver qual grau de controle o atacante tem sobre o endereço de falha, ou se é possível passar por uma leitura inicial fora dos limites — e ver o que existe por baixo.

Ah, mais uma coisa: para minimização de casos de teste, experimente o afl-tmin. A ferramenta pode ser operada de uma maneira muito simples:```shell
$ ./afl-tmin -i test_case -o minimized_result -- /path/to/program [...]

The tool works with crashing and non-crashing test cases alike. In the crash mode, it will happily accept instrumented and non-instrumented binaries. In the non-crashing mode, the minimizer relies on standard AFL instrumentation to make the file simpler without altering the execution path.

The minimizer accepts the -m, -t, -f and @@ syntax in a manner compatible with afl-fuzz.

Another recent addition to AFL is the afl-analyze tool. It takes an input file, attempts to sequentially flip bytes, and observes the behavior of the tested program. It then color-codes the input based on which sections appear to be critical, and which are not; while not bulletproof, it can often offer quick insights into complex file formats. More info about its operation can be found near the end of technical_details.txt.

11) Indo além de crashes

Fuzzing é uma técnica maravilhosa e subutilizada para descobrir também erros de design e implementação que não causam crash. Muitos bugs interessantes foram encontrados ao modificar os programas-alvo para chamar abort() quando, por exemplo:

  • Duas bibliotecas de bignum produzem saídas diferentes quando recebem a mesma entrada gerada pelo fuzzer,

  • Uma biblioteca de imagens produz saídas diferentes quando solicitada a decodificar a mesma imagem de entrada várias vezes seguidas,

  • Uma biblioteca de serialização / desserialização não consegue produzir saídas estáveis ao serializar e desserializar iterativamente dados fornecidos pelo fuzzer,

  • Uma biblioteca de compressão produz uma saída inconsistente com o arquivo de entrada quando solicitada a comprimir e depois descomprimir um blob específico.

Implementar essas ou verificações de sanidade semelhantes geralmente leva muito pouco tempo; se você é o mantenedor de um pacote específico, pode tornar esse código condicional com #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION (um flag também compartilhado com o libfuzzer) ou #ifdef __AFL_COMPILER (este é apenas para o AFL).

12) Riscos de senso comum

Lembre-se de que, da mesma forma que muitas outras tarefas computacionalmente intensivas, o fuzzing pode sobrecarregar seu hardware e o sistema operacional. Em particular:

  • Sua CPU vai esquentar e precisará de resfriamento adequado. Na maioria dos casos, se o resfriamento for insuficiente ou parar de funcionar corretamente, as velocidades da CPU serão automaticamente reduzidas. Dito isso, especialmente ao fazer fuzzing em hardware menos adequado (laptops, smartphones etc.), não é totalmente impossível que algo queime.

  • Os programas-alvo podem acabar consumindo gigabytes de memória de forma errática ou enchendo o espaço em disco com arquivos inúteis. O AFL tenta impor limites básicos de memória, mas não pode evitar todos os possíveis imprevistos. No fim das contas, você não deve fazer fuzzing em sistemas onde a perspectiva de perda de dados não seja um risco aceitável.

  • O fuzzing envolve bilhões de leituras e gravações no sistema de arquivos. Em sistemas modernos, isso geralmente será fortemente armazenado em cache, resultando em I/O "físico" bastante modesto — mas há muitos fatores que podem alterar essa equação. É sua responsabilidade monitorar possíveis problemas; com I/O muito pesado, a vida útil de muitos HDDs e SSDs pode ser reduzida.

    Uma boa maneira de monitorar o I/O de disco no Linux é o comando 'iostat':```shell $ iostat -d 3 -x -k [...optional disk ID...]

root@kitploit:~
## 13) Limitações conhecidas e áreas para melhoria

Aqui estão algumas das advertências mais importantes para o AFL:

  - O AFL detecta falhas verificando se o primeiro processo gerado morre devido a
    um sinal (SIGSEGV, SIGABRT, etc.). Programas que instalam manipuladores personalizados para
    esses sinais podem precisar ter o código relevante comentado. Da mesma
    forma, falhas em processos filhos gerados pelo alvo fuzzeado podem escapar
    da detecção, a menos que você adicione manualmente algum código para capturá-las.

  - Como em qualquer outra ferramenta de força bruta, o fuzzer oferece cobertura limitada se
    criptografia, somas de verificação, assinaturas criptográficas ou compactação forem usadas para
    envolver totalmente o formato de dados real a ser testado.

    Para contornar isso, você pode comentar as verificações relevantes (veja
    experimental/libpng_no_checksum/ para inspiração); se isso não for possível,
    você também pode escrever um pós-processador, como explicado em
    experimental/post_library/.

  - Existem algumas desvantagens infelizes com ASAN e binários de 64 bits. Isso
    não se deve a nenhuma falha específica do afl-fuzz; consulte [notes_for_asan.txt](https://github.com/google/afl/blob/master/docs/notes_for_asan.txt)
    para dicas.

  - Não há suporte direto para fuzzing de serviços de rede, daemons em segundo plano
    ou aplicativos interativos que exigem interação com a interface do usuário para funcionar. Você pode
    precisar fazer alterações simples no código para que eles se comportem de uma maneira mais
    tradicional. O Preeny também pode oferecer uma opção relativamente simples - veja:
    https://github.com/zardus/preeny

    Algumas dicas úteis para modificar serviços baseados em rede também podem ser encontradas em:
    https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop

  - O AFL não gera dados de cobertura legíveis por humanos. Se você quiser monitorar
    a cobertura, use o afl-cov de Michael Rash: https://github.com/mrash/afl-cov

  - Ocasionalmente, máquinas sencientes se levantam contra seus criadores. Se isso
    acontecer com você, consulte http://lcamtuf.coredump.cx/prep/.

Além disso, consulte INSTALL para dicas específicas da plataforma.

## 14) Agradecimentos especiais

Muitas das melhorias no afl-fuzz não seriam possíveis sem feedback,
relatórios de bugs ou patches de:```
  Jann Horn                             Hanno Boeck
  Felix Groebert                        Jakub Wilk
  Richard W. M. Jones                   Alexander Cherepanov
  Tom Ritter                            Hovik Manucharyan
  Sebastian Roschke                     Eberhard Mattes
  Padraig Brady                         Ben Laurie
  @dronesec                             Luca Barbato
  Tobias Ospelt                         Thomas Jarosch
  Martin Carpenter                      Mudge Zatko
  Joe Zbiciak                           Ryan Govostes
  Michael Rash                          William Robinet
  Jonathan Gray                         Filipe Cabecinhas
  Nico Weber                            Jodie Cunningham
  Andrew Griffiths                      Parker Thompson
  Jonathan Neuschfer                    Tyler Nighswander
  Ben Nagy                              Samir Aguiar
  Aidan Thornton                        Aleksandar Nikolich
  Sam Hakim                             Laszlo Szekeres
  David A. Wheeler                      Turo Lamminen
  Andreas Stieger                       Richard Godbee
  Louis Dassy                           teor2345
  Alex Moneger                          Dmitry Vyukov
  Keegan McAllister                     Kostya Serebryany
  Richo Healey                          Martijn Bogaard
  rc0r                                  Jonathan Foote
  Christian Holler                      Dominique Pelle
  Jacek Wielemborek                     Leo Barnes
  Jeremy Barnes                         Jeff Trull
  Guillaume Endignoux                   ilovezfs
  Daniel Godas-Lopez                    Franjo Ivancic
  Austin Seipp                          Daniel Komaromy
  Daniel Binderman                      Jonathan Metzman
  Vegard Nossum                         Jan Kneschke
  Kurt Roeckx                           Marcel Bohme
  Van-Thuan Pham                        Abhik Roychoudhury
  Joshua J. Drake                       Toby Hutton
  Rene Freingruber                      Sergey Davidoff
  Sami Liedes                           Craig Young
  Andrzej Jackowski                     Daniel Hodson

Obrigado!

15) Contato

Perguntas? Preocupações? Relatórios de bugs? Por favor, use o GitHub.

Há também uma lista de e-mails para o projeto; para participar, envie um e-mail para [email protected]. Ou, se preferir navegar pelos arquivos primeiro, tente: https://groups.google.com/group/afl-users.