Skip to content

MASTG-TEST-0072: Testando App Extensions

Visão Geral

Análise Estática

A análise estática cuidará de:

  • Verificar se o aplicativo contém extensões de aplicativo
  • Determinar os tipos de dados suportados
  • Verificar o compartilhamento de dados com o aplicativo principal
  • Verificar se o aplicativo restringe o uso de extensões de aplicativo

Verificando se o Aplicativo Contém Extensões de Aplicativo

Se você tiver o código-fonte original, pode pesquisar todas as ocorrências de NSExtensionPointIdentifier com o Xcode (cmd+shift+f) ou verificar em "Build Phases / Embed App extensions":

Lá você pode encontrar os nomes de todas as extensões de aplicativo incorporadas, seguidas por .appex. Agora você pode navegar até as extensões de aplicativo individuais no projeto.

Caso não tenha o código-fonte original:

Use o comando grep para buscar NSExtensionPointIdentifier entre todos os arquivos dentro do pacote do aplicativo (IPA ou aplicativo instalado):

$ grep -nr NSExtensionPointIdentifier Payload/Telegram\ X.app/
Binary file Payload/Telegram X.app//PlugIns/SiriIntents.appex/Info.plist matches
Binary file Payload/Telegram X.app//PlugIns/Share.appex/Info.plist matches
Binary file Payload/Telegram X.app//PlugIns/NotificationContent.appex/Info.plist matches
Binary file Payload/Telegram X.app//PlugIns/Widget.appex/Info.plist matches
Binary file Payload/Telegram X.app//Watch/Watch.app/PlugIns/Watch Extension.appex/Info.plist matches

Você também pode acessar via SSH, encontrar o pacote do aplicativo e listar tudo dentro de PlugIns (eles são colocados lá por padrão) ou fazer isso com o objection:

ph.telegra.Telegraph on (iPhone: 11.1.2) [usb] # cd PlugIns
    /var/containers/Bundle/Application/15E6A58F-1CA7-44A4-A9E0-6CA85B65FA35/
    Telegram X.app/PlugIns

ph.telegra.Telegraph on (iPhone: 11.1.2) [usb] # ls
NSFileType      Perms  NSFileProtection    Read    Write     Name
------------  -------  ------------------  ------  -------   -------------------------
Directory         493  None                True    False     NotificationContent.appex
Directory         493  None                True    False     Widget.appex
Directory         493  None                True    False     Share.appex
Directory         493  None                True    False     SiriIntents.appex

Podemos ver agora as mesmas quatro extensões de aplicativo que vimos anteriormente no Xcode.

Determinando os Tipos de Dados Suportados

Isso é importante para dados compartilhados com aplicativos host (por exemplo, via Extensões de Compartilhamento ou Ação). Quando o usuário seleciona algum tipo de dados em um aplicativo host e ele corresponde aos tipos de dados definidos aqui, o aplicativo host oferecerá a extensão. Vale notar a diferença entre isso e o compartilhamento de dados via UIActivity, onde tínhamos que definir os tipos de documento, também usando UTIs. Um aplicativo não precisa ter uma extensão para isso. É possível compartilhar dados usando apenas UIActivity.

Inspecione o arquivo Info.plist da extensão do aplicativo e procure por NSExtensionActivationRule. Essa chave especifica os dados suportados, bem como, por exemplo, o número máximo de itens suportados. Por exemplo:

<key>NSExtensionAttributes</key>
    <dict>
        <key>NSExtensionActivationRule</key>
        <dict>
            <key>NSExtensionActivationSupportsImageWithMaxCount</key>
            <integer>10</integer>
            <key>NSExtensionActivationSupportsMovieWithMaxCount</key>
            <integer>1</integer>
            <key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
            <integer>1</integer>
        </dict>
    </dict>

Apenas os tipos de dados presentes aqui e que não tenham 0 como MaxCount serão suportados. No entanto, é possível fazer filtragem mais complexa usando uma chamada string de predicado que avaliará as UTIs fornecidas. Consulte o Apple App Extension Programming Guide para obter informações mais detalhadas sobre isso.

Verificando o Compartilhamento de Dados com o Aplicativo Principal

Lembre-se de que as extensões de aplicativo e seus aplicativos principais não têm acesso direto aos contêineres um do outro. No entanto, o compartilhamento de dados pode ser habilitado. Isso é feito por meio de "App Groups" e da API NSUserDefaults. Veja esta figura do Apple App Extension Programming Guide:

Como também mencionado no guia, o aplicativo deve configurar um contêiner compartilhado se a extensão do aplicativo usar a classe NSURLSession para realizar um upload ou download em segundo plano, para que tanto a extensão quanto seu aplicativo principal possam acessar os dados transferidos.

Verificando se o Aplicativo Restringe o Uso de Extensões de Aplicativo

É possível rejeitar um tipo específico de extensão de aplicativo usando o seguinte método:

No entanto, atualmente isso só é possível para extensões de aplicativo de "teclado personalizado" (e deve ser verificado ao testar aplicativos que lidam com dados sensíveis via teclado, como aplicativos bancários).

Análise Dinâmica

Para a análise dinâmica, podemos fazer o seguinte para obter conhecimento sem ter o código-fonte:

  • Inspecionar os itens sendo compartilhados
  • Identificar as extensões de aplicativo envolvidas

Inspecionando os Itens Sendo Compartilhados

Para isso, devemos conectar NSExtensionContext - inputItems no aplicativo de origem dos dados.

Seguindo o exemplo anterior do Telegram, usaremos agora o botão "Compartilhar" em um arquivo de texto (que foi recebido de um chat) para criar uma nota no aplicativo Notes com ele:

Se executarmos um trace, veremos a seguinte saída:

(0x1c06bb420) NSExtensionContext - inputItems
0x18284355c Foundation!-[NSExtension _itemProviderForPayload:extensionContext:]
0x1828447a4 Foundation!-[NSExtension _loadItemForPayload:contextIdentifier:completionHandler:]
0x182973224 Foundation!__NSXPCCONNECTION_IS_CALLING_OUT_TO_EXPORTED_OBJECT_S3__
0x182971968 Foundation!-[NSXPCConnection _decodeAndInvokeMessageWithEvent:flags:]
0x182748830 Foundation!message_handler
0x181ac27d0 libxpc.dylib!_xpc_connection_call_event_handler
0x181ac0168 libxpc.dylib!_xpc_connection_mach_event
...
RET: (
"<NSExtensionItem: 0x1c420a540> - userInfo:
{
    NSExtensionItemAttachmentsKey =     (
    "<NSItemProvider: 0x1c46b30e0> {types = (\n \"public.plain-text\",\n \"public.file-url\"\n)}"
    );
}"
)

Aqui podemos observar que:

  • Isso ocorreu nos bastidores via XPC, concretamente é implementado por meio de uma NSXPCConnection que usa o Framework libxpc.dylib.
  • As UTIs incluídas no NSItemProvider são public.plain-text e public.file-url, a última sendo incluída em NSExtensionActivationRule do Info.plist da "Extensão de Compartilhamento" do Telegram.

Identificando as Extensões de Aplicativo Envolvidas

Você também pode descobrir qual extensão de aplicativo está cuidando de suas solicitações e respostas conectando NSExtension - _plugIn:

Executamos o mesmo exemplo novamente:

(0x1c0370200) NSExtension - _plugIn
RET: <PKPlugin: 0x1163637f0 ph.telegra.Telegraph.Share(5.3) 5B6DE177-F09B-47DA-90CD-34D73121C785
1(2) /private/var/containers/Bundle/Application/15E6A58F-1CA7-44A4-A9E0-6CA85B65FA35
/Telegram X.app/PlugIns/Share.appex>

(0x1c0372300)  -[NSExtension _plugIn]
RET: <PKPlugin: 0x10bff7910 com.apple.mobilenotes.SharingExtension(1.5) 73E4F137-5184-4459-A70A-83
F90A1414DC 1(2) /private/var/containers/Bundle/Application/5E267B56-F104-41D0-835B-F1DAB9AE076D
/MobileNotes.app/PlugIns/com.apple.mobilenotes.SharingExtension.appex>

Como você pode ver, há duas extensões de aplicativo envolvidas:

  • Share.appex está enviando o arquivo de texto (public.plain-text e public.file-url).
  • com.apple.mobilenotes.SharingExtension.appex que está recebendo e processará o arquivo de texto.

Se você quiser aprender mais sobre o que está acontecendo nos bastidores em termos de XPC, recomendamos dar uma olhada nas chamadas internas de "libxpc.dylib". Por exemplo, você pode usar frida-trace e então se aprofundar nos métodos que achar mais interessantes, estendendo os stubs gerados automaticamente.