Publicado: setembro 3, 2024
Pense como um agente malicioso: Modificação de binários do iOS
Introdução à Modificação Binária: Motivação por trás deste artigo
Este artigo apresenta a segunda parte da nossa série sobre cibercrimes em iOS. Você pode encontrar o primeiro artigo aqui. aqui., que explica a formatação de pacotes IPA do iOS e o sideloading de aplicativos. Recomendamos que você se familiarize com essas informações básicas antes de prosseguir com este artigo.
Os agentes maliciosos que atacam aplicativos geralmente desejam modificar o binário que estão atacando. No entanto, existem várias etapas para realizar engenharia reversa e depurar o binário antes de modificá-lo. Os agentes maliciosos podem usar muitas técnicas para aprender sobre um binário e muitas outras para criar modificações inteligentes que burlam a funcionalidade ou adicionam comportamento malicioso. Mesmo modificações simples que alteram apenas alguns bytes de um aplicativo podem ter um impacto significativo.
Este artigo apresentará um guia passo a passo de como encontrar e modificar uma instrução simples de 4 bytes em um aplicativo iOS para burlar completamente uma verificação de autenticação. Recomendo aprender os fundamentos de diversos vetores de ataque e pensar como um agente malicioso, pois entender esses agentes facilitará muito a defesa contra eles. Essas técnicas podem ser usadas para verificar Digital.ai proteções ou para aprender e entender por que a segurança de aplicativos é necessária para se proteger contra esses ataques.
Motivações dos agentes da ameaça
Os agentes maliciosos podem modificar um aplicativo por diversos motivos, e este texto aborda apenas um exemplo. Aqui está uma lista de motivações realistas e do mundo real:
- Ignore a Gestão de Direitos Digitais (DRM) ou a verificação de licença.
- Substituir uma função por malware, spyware, mineração de bitcoin ou qualquer outra atividade maliciosa.
- Desative uma thread ou desative um mecanismo de watchdog.
- Tentativa de desativar as proteções inseridas por produtos de segurança de aplicativos.
Ferramentas necessárias para seguir este guia
- Uma ferramenta de desmontagem: Este guia utiliza o Ghidra 11.1.2. Alternativas podem ser o IDA, o Hopper ou o Binary Ninja.
- Código X: Este guia utiliza o Xcode 15.4, mas uma gama mais ampla de versões é suportada.
- git: O código-fonte usado para o aplicativo iOS está localizado em clique aqui.
- Pitão 3: Utilizado para criar scripts que descompactam e modificam o binário do iOS.
- iOS: Configuração de assinatura ou instalação de aplicativos por fora da página de destino.
- iPhone para testar o aplicativo: Este guia utiliza um iPhone físico, mas você poderá usar um iPad ou um Mac com chip Apple Silicon e PlayCover, ou adaptar o guia para criar e executar um aplicativo macOS com chip Apple Silicon.
- Opcional: Ferramenta de linha de comando XXD para verificar seu trabalho.
Exemplo de candidatura para despachante de empregos
O Job Dispatcher é um exemplo de aplicativo iOS útil para demonstrar ataques contra aplicativos iOS e testar mecanismos de segurança. Técnicos podem usar o Job Dispatcher para receber e concluir tarefas. Para este guia, vamos imaginar que somos agentes maliciosos tentando burlar as verificações de autenticação para que qualquer senha seja aceita.
O primeiro passo é compilar o aplicativo de exemplo, baixando-o do link do GitHub acima e usando o Xcode para gerar um arquivo IPA.
Identificando o alvo a ser modificado
Este guia mostrará como contornar a tela de login do aplicativo Job Dispatcher. Mais especificamente, mostraremos como contornar a verificação de senha para aceitar qualquer senha.
Para começar, precisamos de uma ferramenta que nos ajude a entender o arquivo binário compilado. O Ghidra consegue desmontar um aplicativo compilado, convertendo-o novamente em código assembly legível por humanos e decompilando-o em uma linguagem de programação semelhante a C. Este guia utiliza o Ghidra para encontrar a seção de código relevante para a tela de login dentro de um binário e analisar quais instruções de assembly podem ser alteradas para contornar a tela de login.
Note que a função de login no Job Dispatcher não é realista. Ela usa um nome de usuário e senha fixos no código para a verificação. Embora esse método de login não seja realista, muitas funções seguem esse mesmo padrão, verificando entradas abertas em relação a restrições conhecidas. A ideia é aprender como contornar uma verificação de função, ou seja, uma função cujos efeitos são visíveis, por isso o guia a utiliza.
Os agentes maliciosos não terão o código-fonte de um aplicativo, mas vamos dar uma olhada rápida mesmo assim para sabermos com o que estamos lidando e simplificar nossos passos.
Encontrar o alvo por meio de engenharia reversa de um binário pode ser demorado, especialmente se o aplicativo estiver ofuscado. Nesse caso, a função alvo deve estar próxima das strings “tech” e “secret”, então vamos procurá-las no binário compilado. Em muitos aplicativos, os engenheiros reversos podem usar mensagens de erro ou strings de log para encontrar as seções de código de seu interesse. Há também uma string para “Nome de usuário ou senha inválidos”, que é uma string realista que um atacante usaria para encontrar segmentos de código relevantes. Devido à forma como o Swift lida com chamadas de alerta, a string “Nome de usuário ou senha inválidos” será mais adequada para uma técnica de análise dinâmica do que para a abordagem de análise estática que utilizaremos.
Despachante de Tarefas de Engenharia Reversa
Agora, vamos abrir o arquivo binário Mach-O do Job Dispatcher no Ghidra. Você precisará criar um novo projeto não compartilhado no Ghidra. Assim que chegar à tela do CodeBrowser, podemos importar o arquivo do Job Dispatcher e usar todas as opções de análise padrão. Isso levará alguns minutos para ser executado.
Vale ressaltar que não fornecemos o aplicativo pré-compilado. Ao compilar o aplicativo usando diferentes versões do Xcode, configurações de compilação ou, potencialmente, modificações no código-fonte, os endereços, registradores e até mesmo o próprio assembly podem apresentar valores diferentes. Talvez seja necessário ajustar os endereços e registradores utilizados para acompanhar o tutorial.
Sabemos que o código que queremos está próximo das palavras “tech” e “secret”. Vamos procurar por essas palavras. Para isso, use as opções do menu “Pesquisar” –> “Por palavras…”
Um agente malicioso típico poderia começar a adivinhar sequências de caracteres potencialmente interessantes até encontrar algo que valha a pena investigar. Vamos evitar as adivinhações aqui e simplesmente procurar pela sequência "secret".
Clicar na sequência de caracteres deslocará o navegador de código para a localização da sequência. Serão necessários alguns passos para encontrar o código relevante. Agora, vamos seguir as referências da sequência até encontrarmos o código.
Parece que “tech” e “secret” estão armazenados lado a lado na seção de strings constantes do binário. Agora, siga as referências cruzadas (XREF) para outro local de dados fornecido.
As strings constantes são encapsuladas em objetos CFString, que podemos ver aqui. Abaixo, podemos continuar seguindo as referências cruzadas (XREFs) dos objetos CFString e ver onde o código usa essas strings.

Parece que este pode ser o código que estamos procurando. Em um binário simplificado, os nomes das funções internas não existem. O Ghidra gentilmente nomeou esta função como FUN_10004000 para indicar a função no endereço 10004000. Precisaremos analisar esta desmontagem e descompilação para ver se corresponde ao código-fonte muito mais simples apresentado anteriormente. A linguagem assembly pode ser difícil de ler, então, primeiro, analise a descompilação à direita. Há uma função que recebe dois argumentos e, em seguida, faz uma chamada para FUN_10001e2ec para realizar algumas comparações. A seguir (abaixo), verificaremos esta função auxiliar para ver o que ela faz.

É uma função de comparação de strings. É exatamente isso que estamos procurando. Essas funções parecem um pouco diferentes no Ghidra em comparação com o código-fonte. Você pode consultar o código-fonte no GitHub para entender melhor que tipo de informação é removida durante a engenharia reversa.
De acordo com os documentosA função retornará "SIM" se as strings coincidirem e "NÃO" caso contrário. Queremos que ela sempre retorne "SIM" para permitir qualquer senha.

Esta é a parte relevante do código Assembly. A string “password” é referenciada usando o registrador x2. Em seguida, chamamos a função “isEqualToString”. O valor de retorno de uma chamada de função usando a convenção de chamada ARM64v8 seria armazenado no registrador x0. Podemos ver que o valor de retorno da comparação de strings é processado na linha imediatamente após a chamada da função de comparação de strings. Trata-se de “mov x20, x0”, que copia o valor do registrador x0 para o registrador x20. Podemos facilmente modificar esta instrução MOV em Assembly para sempre colocar YES em x20, independentemente da senha fornecida.
Para isso, queremos substituir esta linha de código assembly no arquivo binário:
MOV x20, x0
Que é representado como “f4 03 00 aa” em hexadecimal.
Com essa linha de código assembly, que usa um valor constante que representa "SIM" e ignora completamente o resultado da comparação de strings:
MOV x20, #01
Podemos usar um conversor online de Assembly ARM64v8 para Binário para determinar que Mov x20, #01 é representado pelos seguintes valores hexadecimais:
34 00 80 D2
Ghidra mostra que esta linha de montagem está armazenada no seguinte local:
0x100004040
Neste caso, 0x10000000 é o deslocamento da imagem na seção TEXT, onde as instruções binárias são armazenadas. O carregador de aplicativos usa esse deslocamento, mas o endereço do conteúdo do arquivo no disco começa em 0x0.
Portanto, o deslocamento da instrução binária que queremos substituir será 0x4040 no arquivo binário do Job Dispatcher. Agora sabemos o que precisamos alterar e onde no arquivo precisamos fazer a alteração.
Vamos começar a hackear!
Embora pudéssemos abrir manualmente o arquivo binário em um editor hexadecimal e substituir os bytes, isso é um pouco impraticável. Aqui está um script Python conveniente que descompacta, modifica uma linha de código assembly e compacta o binário modificado novamente. Talvez seja necessário ajustar o caminho para corresponder aos diretórios escolhidos.
1 from zipfile import ZipFile 2 import os 3 import shutil 4 5 def hack_and_repack(payloadDir, hackedDir, inputIpa, movOffset, storeTrue): 6 7 # descompacta o IPA para acessar o binário alvo 8 with ZipFile(inputIpa, 'r') as zObject: 9 zObject.extractall(path=payloadDir) 10 11 target = os.path.join(payloadDir, "Payload", "Job Dispatcher.app", "Job Dispatcher") 12 13 # parte hackzorz propriamente dita 14 with open(target, "r+b") as targetFile: 15 targetFile.seek(movOffset) 16 targetFile.write(storeTrue) 17 18 # compacta e reforma o IPA 19 hackedIpa = os.path.join(hackedDir, "Job Dispatcher.ipa") 20 shutil.make_archive(os.path.join(hackedDir, "Job Dispatcher.ipa"), 'zip', payloadDir) 21 os.rename(os.path.join(hackedDir, "Job Dispatcher.ipa.zip"), hackedIpa) 22 23 hack_and_repack("payload", "hacked_dir", "JobDispatcher/Job Dispatcher.ipa", int(b"4040", 16), b'\x34\x00\x80\xD2')
Execute este script usando: script_de_hacking_python3.py
Após a conclusão do script, um novo arquivo IPA deve ser adicionado. Este arquivo IPA deve ser modificado com a nova instrução de montagem MOV, que fará com que qualquer senha seja aceita. Também podemos verificar se o binário foi editado corretamente carregando-o novamente no Ghidra ou fazendo uma verificação rápida usando o XXD.
% xxd -s 0x4034 -c 4 -g 1 -l 16 Payload/Job\ Dispatcher.app/Job\ Dispatcher 00004034: 02 09 46 f9 ..F. 00004038: e0 03 13 aa .... 0000403c: ac 68 00 94 .h.. 00004040: 34 00 80 d2 4...
Podemos ver que a nova instrução de movimentação foi inserida no endereço 0x4040.
Para executar e testar o aplicativo iOS modificado, precisamos assiná-lo novamente corretamente ou instalá-lo manualmente em nosso dispositivo iOS. Isso é descrito no [link para o documento/documentação]. primeiro artigo desta sérieExecute o aplicativo e teste usando o nome de usuário "tech" e qualquer coisa no campo de senha; tudo deve ser aceito e você deverá prosseguir para a próxima tela.
Aprendizado
Aplicações desprotegidas aumentam o risco para os negócios, expondo a lógica crítica de negócios a potenciais ameaças, permitindo que agentes maliciosos façam modificações não autorizadas no código binário da aplicação e potencialmente contornem recursos de segurança cruciais, como verificações de licenciamento, verificações de autenticação ou outras funções críticas.
No caso de jogos, os agentes maliciosos costumam criar versões modificadas ou versões sem DRM e, em seguida, disponibilizam essas versões para outros usuários. Se um agente malicioso conseguir modificar o arquivo binário, ele também poderá inserir cryptojacking ou malware no aplicativo e tentar redistribuir o aplicativo modificado para usuários desavisados. Digital.ai Pode reduzir esses riscos e tornar a invasão de aplicativos tão difícil e demorada que até mesmo os agentes de ameaças mais determinados optarão por atacar outros alvos mais fáceis. A próxima parte desta série abordará a defesa contra a modificação do binário do iOS.
Se você já utiliza nossos produtos, pode ser um bom exercício tentar proteger o Job Dispatcher para que ele detecte as modificações na função de autenticação e encerre o aplicativo antes mesmo que o usuário tente fazer login. Recomendo desativar a ofuscação se você tentar isso, ou poderá achar quase impossível.
Confira nossa página Para obter mais informações sobre como interromper modificações binárias.
Também recomendamos
De dias a horas: como a engenharia reversa de chapéu branco evoluiu com a IA
Em 2020, a engenharia reversa de um código binário complexo frequentemente levava dias…
Analisando os ataques de deepfake de Conheça Seu Cliente (KYC)
Onde o endurecimento se encaixa na superfície de ataque do Deepfake: Um rosto…
Decifrando as falhas de aplicativos móveis — do caos à clareza
Os aplicativos móveis estão sob ataque constante. De acordo com Digital.ai's 2026…







