
Analisador de Logs, Eventos e Protobuf do Android

Se quiser contribuir, fale comigo aqui: https://abrignoni.github.io
Postagens no blog aqui: https://leapps.org/blog
Python 3.10 ou superior
As dependências para o seu ambiente Python estão listadas em requirements.txt. Instale-as usando o comando abaixo. Certifique-se de que a parte py esteja correta para o seu ambiente, por exemplo, py, python ou python3, etc.
py -m pip install -r requirements.txt
ou
pip3 install -r requirements.txt
Para executar no Linux, você também precisará instalar o tkinter separadamente, assim:
sudo apt-get install python3-tk
Para compilar para um executável e poder executar em um sistema sem Python instalado.
Sistema operacional Windows
Para criar o aleapp.exe, execute:
pyinstaller scripts\pyinstaller\aleapp.spec
Para criar o aleappGUI.exe, execute:
pyinstaller scripts\pyinstaller\aleappGUI.spec
macOS
Para criar o aleapp, execute:
pyinstaller scripts/pyinstaller/aleapp_macOS.spec
Para criar o aleappGUI.app, execute:
pyinstaller scripts/pyinstaller/aleappGUI_macOS.spec
Linux
Para criar o aleapp, execute:
pyinstaller scripts/pyinstaller/aleapp_Linux.spec
Para criar o aleappGUI, execute:
pyinstaller scripts/pyinstaller/aleappGUI_Linux.spec
$ python aleapp.py -t <zip | tar | fs | gz> -i <caminho_para_extracao> -o <caminho_para_saida_do_relatorio>
$ python aleappGUI.py
$ python aleapp.py --help
Cada plugin é um arquivo-fonte Python que deve ser adicionado à pasta scripts/artifacts, que será carregado dinamicamente toda vez que o ALEAPP for executado.
O arquivo-fonte do plugin deve conter um dicionário chamado __artifacts_v2__ logo no início do módulo, que define os artefatos que o plugin processa. As chaves no dicionário __artifacts_v2__ devem ser IDs para o(s) artefato(s), que devem ser únicos dentro do ALEAPP. Os valores devem ser dicionários contendo as seguintes chaves:
name: O nome do artefato como uma string.description: Uma descrição do artefato como uma string.author: O autor do plugin como uma string.version: A versão do artefato como uma string.date: A data da última atualização do artefato como uma string.requirements: Quaisquer requisitos para processar o artefato como uma string.category: A categoria do artefato como uma string.notes: Quaisquer notas adicionais como uma string.paths: Uma tupla de strings contendo padrões de busca glob para corresponder ao caminho dos dados que o plugin espera para o artefato.function: O nome da função que é o ponto de entrada para o processamento do artefato como uma string.Por exemplo:
__artifacts_v2__ = {
"cool_artifact_1": {
"name": "Cool Artifact 1",
"description": "Extracts cool data from database files",
"author": "@username",
"version": "0.1",
"date": "2022-10-25",
"requirements": "none",
"category": "Really cool artifacts",
"notes": "",
"paths": ('*/com.android.cooldata/databases/database*.db',),
"function": "get_cool_data1"
},
"cool_artifact_2": {
"name": "Cool Artifact 2",
"description": "Extracts cool data from XML files",
"author": "@username",
"version": "0.1",
"date": "2022-10-25",
"requirements": "none",
"category": "Really cool artifacts",
"notes": "",
"paths": ('*/com.android.cooldata/files/cool.xml',),
"function": "get_cool_data2"
}
}
As funções referenciadas como pontos de entrada no dicionário __artifacts__ devem receber os seguintes argumentos:
Por exemplo:
def get_cool_data1(files_found, report_folder, seeker, wrap_text):
pass # faça o processamento aqui
Espera-se que os plugins forneçam saída no formato de saída HTML do ALEAPP, TSV e, opcionalmente, enviem registros para a linha do tempo. As funções para gerar essa saída podem ser encontradas nos módulos artifact_report e ilapfuncs. Em um nível alto, um exemplo pode se parecer com:
__artifacts_v2__ = {
"cool_artifact_1": {
"name": "Cool Artifact 1",
"description": "Extracts cool data from database files",
"author": "@username", # Substitua pelo nome de usuário ou nome real do autor
"version": "0.1", # Número da versão
"date": "2022-10-25", # Data da versão mais recente
"requirements": "none",
"category": "Really cool artifacts",
"notes": "",
"paths": ('*/com.android.cooldata/databases/database*.db',),
"function": "get_cool_data1"
}
}
import datetime
from scripts.artifact_report import ArtifactHtmlReport
import scripts.ilapfuncs
def get_cool_data1(files_found, report_folder, seeker, wrap_text):
# vamos fingir que realmente obtivemos esses dados de algum lugar:
rows = [
(datetime.datetime.now(), "Cool data col 1, value 1", "Cool data col 1, value 2", "Cool data col 1, value 3"),
(datetime.datetime.now(), "Cool data col 2, value 1", "Cool data col 2, value 2", "Cool data col 2, value 3"),
]
headers = ["Timestamp", "Data 1", "Data 2", "Data 3"]
# Saída HTML:
report = ArtifactHtmlReport("Cool stuff")
report_name = "Cool DFIR Data"
report.start_artifact_report(report_folder, report_name)
report.add_script()
report.write_artifact_data_table(headers, rows, files_found[0]) # assumindo que apenas o primeiro arquivo foi processado
report.end_artifact_report()
# Saída TSV:
scripts.ilapfuncs.tsv(report_folder, headers, rows, report_name, files_found[0]) # assumindo apenas o primeiro arquivo
# Linha do tempo:
scripts.ilapfuncs.timeline(report_folder, report_name, rows, headers)
Um PR que adiciona ou altera um artefato é mais fácil de revisar e mesclar quando chega com duas coisas: um pequeno fixture de teste extraído de uma extração real e valores de sample_data que registram o que o módulo produziu. Os scripts geram ambos. Aqui está o fluxo completo.
Uma regra antes de qualquer coisa: tudo o que você enviar aqui se torna público. Use apenas dados que você tem permissão para compartilhar, como um dispositivo de teste que você mesmo populou, uma imagem de pesquisa pública ou um arquivo que você sanitizou manualmente. Nunca use dados de casos reais.
1. Corte um fixture da sua extração
python admin/test/scripts/make_test_data.py <modulo> --case 1 --input <extracao.zip>
Isso extrai os arquivos que os padrões paths do seu módulo correspondem da extração e grava o arquivo de caso admin/test/cases/testdata.<modulo>.json além de um pequeno zip por artefato em admin/test/cases/data/<modulo>/.
Regras de tamanho: abaixo de 10 MB por zip, envie-o com o PR. Entre 10 e 25 MB, envie o arquivo de caso e anexe o zip a um comentário do PR. Maior que isso, informe no PR e um mantenedor providenciará uma transferência.
2. Registre a saída esperada
TZ=UTC python admin/test/scripts/test_module.py <modulo> -a all -c all
Isso executa o módulo contra o fixture e grava um snapshot da saída em admin/test/results/<modulo>/. Envie o snapshot também. Ele se torna a linha de base que protege o módulo após a mesclagem. Mantenha a parte TZ=UTC: os snapshots enviados estão em UTC e o CI executa em UTC.
3. Execute a mesma comparação que o CI executará
python admin/test/scripts/run_test_cases.py --module <modulo>
4. Gere os valores de sample_data
python admin/scripts/validate_sample_data.py --emit <extracao.zip> --key <nome_da_imagem>
Isso executa o ALEAPP de ponta a ponta na sua extração e imprime blocos de sample_data prontos para colar para os módulos alterados no seu branch. Cole-os no __artifacts_v2__ do seu módulo e adicione o nome e a versão do aplicativo que você viu na imagem. Se uma contagem for zero, verifique se o arquivo de origem realmente está vazio antes de registrá-lo.
5. Envie tudo e abra o PR
Envie o módulo, o arquivo de caso, os zips de fixture e o snapshot registrado juntos. Mais detalhes estão em admin/docs/testing/create_module_test_cases.md.
Se a sua extração não puder ser compartilhada, abra o PR mesmo assim e informe isso. Um fixture muitas vezes pode ser extraído de uma imagem de pesquisa pública, ou o arquivo real pode ser sanitizado manualmente. A revisão não para enquanto resolvemos isso.
Esta ferramenta é o resultado de um esforço colaborativo de muitas pessoas na comunidade DFIR.
Logotipo do ALEAPP cortesia de Derek Eiri.