
Plugin para IDA Pro para filtrar funções por padrões de assembly, sequências de bytes, referências de strings/nomes e restrições de tamanho, com pesquisa baseada em regras e cópia binária avançada.
FindFunc é um plugin do IDA Pro para encontrar funções de código que contenham um determinado padrão de assembly ou byte, referenciem um certo nome ou string, ou estejam em conformidade com várias outras restrições.
FindFunc ganhou o terceiro lugar no Concurso de Plugins do IDA Pro da HexRays 2022!

A funcionalidade principal do FindFunc é permitir que o usuário especifique um conjunto de "Regras" ou restrições que uma função de código no IDA Pro deve satisfazer. O FF então encontrará e listará todas as funções que satisfazem TODAS as regras (portanto, atualmente todas as Regras estão em uma conjunção AND). Exceção: As regras podem ser "invertidas" para serem correspondências negativas. Tais regras, portanto, se conformam a "AND NOT".
O FF irá agendar as regras em uma ordem inteligente para minimizar o tempo de processamento. Visão geral dos recursos:
O botão "Find Functions" limpa os resultados existentes e inicia uma nova pesquisa, "Refine Results" considera apenas os resultados da pesquisa anterior.
Um recurso secundário do FF é a opção de copiar a representação binária de instruções com as seguintes opções:
Veja a seção "cópia avançada" abaixo para detalhes. Este recurso complementa bem a regra de Padrão de Byte!
FindFunc é um plugin Python do IDA Pro sem dependências de pacotes externos. Pode ser instalado baixando o repositório e copiando o arquivo 'findfuncmain.py' e a pasta 'findfunc' para o diretório de plugins do seu IDA Pro. Para IDA 9.0+, o repositório também pode ser clonado diretamente no diretório de plugins. De qualquer forma, nenhuma construção é necessária.
Requisitos: IDA Pro 8.x (8.3+) com ambiente python3. FindFunc é projetado apenas para a arquitetura x86/x64. Foi testado com IDA 8.3 - 9.2, python 3.11 no Windows 10 + 11
Atualmente, as seis regras a seguir estão disponíveis. Elas estão ordenadas aqui de pesada a leve em relação ao impacto no desempenho. Com bancos de dados grandes, é uma boa ideia primeiro reduzir as funções candidatas com uma regra barata, antes de fazer correspondência pesada via, por exemplo, Regras de Código. O FF agendará automaticamente as regras de maneira inteligente.
Regra para filtrar funções com base em elas conterem um trecho de código assembly fornecido. Isso NÃO é uma pesquisa de texto pela representação textual de desmontagem do IDA, mas sim realiza correspondência avançada da instrução subjacente. O trecho pode conter muitas instruções consecutivas, uma por linha. Chunks de funções são suportados. Suporta correspondência especial com curingas, além de assembly literal:
mais exemplos:
mov r64, [r32 * 8 + 0x100]
mov r, [r * 8 - 0x100]
mov r64, [r32 * 8 + imm]
pass
mov r, word [eax + r32 * 8 - 0x100]
any r64, r64
push imm
push any
Armadilhas: Tenha cuidado ao copiar assembly do IDA. O IDA mistura nomes de variáveis locais e outras informações na instrução, o que leva a falhas na correspondência. Além disso, rótulos não são suportados ("call sub_123456").
Note que Padrões de Código é a Regra mais cara, e se apenas Regras de Código estiverem presentes, o FF não tem opção a não ser desmontar todo o banco de dados. Isso pode levar vários minutos para binários muito grandes. Veja notas sobre desempenho abaixo.
A função deve conter o imediato fornecido pelo menos uma vez em qualquer posição. Um valor imediato é um valor fixo na representação binária da instrução. Exemplos de instruções que correspondem ao valor imediato 0x100:
mov eax, 0x100
mov eax, [0x100]
and al, [eax + ebx*8 + 0x100]
push 0x100
Imediatos podem ser colados diretamente da área de transferência na lista de regras. Nota: O IDA realiza correspondência extensiva de qualquer tamanho e qualquer posição do imediato. Se você souber que ele tem uma largura específica de 4 ou 8 bytes, um padrão de byte pode ser mais rápido (mas pode produzir falsos positivos).
A função deve conter o padrão de byte fornecido pelo menos uma vez. O padrão tem o mesmo formato da pesquisa binária do IDA e, portanto, suporta curingas - a combinação perfeita para o recurso de cópia avançada!
Exemplos:
11 22 33 44 aa bb cc
11 22 33 ?? ?? bb cc -> ?? pode ser qualquer byte
Padrões de byte podem ser colados diretamente da área de transferência na lista de regras. Nota: A correspondência de padrões é bastante rápida e uma boa candidata para reduzir correspondências rapidamente!
A função deve referenciar a string fornecida pelo menos uma vez. A string é correspondida de acordo com o módulo 'fnmatch' do Python e, portanto, suporta correspondência do tipo curinga. A correspondência é realizada sem diferenciação de maiúsculas/minúsculas. Strings dos seguintes formatos são consideradas: [idaapi.STRTYPE_C, idaapi.STRTYPE_C_16] (isso pode ser alterado na classe Config).
Exemplos:
Nota: A correspondência de strings é rápida e uma boa escolha para reduzir candidatos rapidamente!
A função deve referenciar o nome/rótulo fornecido pelo menos uma vez. O nome/rótulo é correspondido de acordo com o módulo 'fnmatch' do Python e, portanto, suporta correspondência do tipo curinga. A correspondência é realizada sem diferenciação de maiúsculas/minúsculas.
Exemplos:
Nota: A correspondência de nomes é muito rápida e ideal para reduzir candidatos rapidamente!
O tamanho da função deve estar dentro do limite fornecido: "min <= tamanhofuncao <= max". Os dados são inseridos como uma string da forma "min,max". O tamanho de uma função inclui todos os seus chunks.
Nota: A correspondência de tamanho de função é muito rápida e ideal para reduzir candidatos rapidamente!
Para facilidade de uso, o FF pode ser usado através dos seguintes atalhos de teclado:
Uso adicional da GUI
Frequentemente queremos pesquisar por padrões binários de assembly, mas sem endereços e valores hardcoded (imediatos), ou até mesmo apenas os opcodes reais da instrução. FindFunc torna isso fácil adicionando três opções de cópia ao menu pop-up de desmontagem:
Copia todos os bytes da instrução como string hexadecimal para a área de transferência, para uso em uma Regra de Padrão de Byte (ou pesquisa binária do IDA).
B8 44332211 mov eax,11223344
68 00000001 push 1000000
66:894424 70 mov word ptr ss:[esp+70],ax
será copiado como
b8 44 33 22 11 68 00 00 00 01 66 89 44 24 70
Copia bytes da instrução para a instrução fornecida, mascarando quaisquer valores imediatos. Exemplo:
B8 44332211 mov eax,11223344
68 00000001 push 1000000
66:894424 70 mov word ptr ss:[esp+70],ax
será copiado como
b8 ?? ?? ?? ?? 68 ?? ?? ?? ?? 66 89 44 24 ??
Copia todos os bytes da instrução como string hexadecimal para a área de transferência, mascarando quaisquer bytes que não sejam o opcode real (incluindo sib, modrm, mas mantendo prefixos legados).
B8 44332211 mov eax,11223344
68 00000001 push 1000000
66:894424 70 mov word ptr ss:[esp+70],ax
será copiado como
b8 ?? ?? ?? ?? 68 ?? ?? ?? ?? 66 89 ?? ?? ??
Uma combinação que mantém opcode e imediatos, mas mascara, por exemplo, mod r/m. Note que isso mantém opcodes mesmo que eles exijam registradores específicos, ex.:
B8 44332211 mov eax,11223344
manterá o opcode B8.
Nota: Isso é um "melhor esforço" usando a API do IDA, portanto pode haver alguns casos em que funciona apenas parcialmente. Para uma solução 100% correta, teríamos que enviar uma biblioteca dedicada de desmontagem x86.
Resultados semelhantes podem ser alcançados com Regras de Padrão de Código, mas isso pode ser mais rápido, tanto para interação do usuário quanto para a pesquisa real.
Copia a desmontagem selecionada para a área de transferência, conforme aparece no IDA.
Uma breve palavra sobre desempenho: