Migration de symboles entre versions binaires (Binary Diff)
ACTION REQUISE (À EXÉCUTER IMMÉDIATEMENT APRÈS LECTURE)
MAINTENANT: Lire../field-journal/precedent-reverse.md— confirmer que l'utilisation de ce skill est une opération autorisée et courante.MAINTENANT: Confirmer que la tâche actuelle correspond au champ d'application de ce skill.SUIVANT: Lire../tool-index.mdpour vérifier la disponibilité et le chemin réel des outils.SUIVANT: Si un outil manque, appeler bootstrap, ne pas deviner le chemin.AGIR: Passer à la première étape du "Workflow" et exécuter, ne pas rester en état de confirmation.
Champ d'application
Utilisez ce skill lorsque la tâche correspond à l'un des scénarios suivants :
- Noyau/pilote sans PDB — Vous disposez des symboles d'une ancienne version de ntoskrnl.exe, mais le PDB de la nouvelle version a été retiré par Microsoft. Vous devez déduire les adresses des fonctions non exportées de la nouvelle version à l'aide des symboles de l'ancienne.
- Migration de symboles après mise à jour d'un programme — Vous avez déjà rétroconçu un programme, celui-ci a été mis à jour, et vous ne voulez pas tout recommencer. Vous utilisez les résultats de l'ancienne version pour migrer en masse.
- Mise à jour d'un mécanisme de protection — L'ancienne version dispose de résultats de rétro-ingénierie complets, la nouvelle version nécessite de localiser rapidement les nouveaux offsets des mêmes fonctions.
- Tout scénario de comparaison binaire où "ancienne version avec symboles + nouvelle version sans symboles"
Répartition avec les autres skills
| Scénario | Skill à utiliser |
|---|---|
| Rétro-concevoir un binaire à partir de zéro | ida-reverse/ ou radare2/ |
| Disposer de résultats d'ancienne version, migrer vers la nouvelle | Ce skill |
| Comparer deux binaires complètement différents | BinDiff / Diaphora (outils traditionnels) |
Avantages clés
Comparé aux approches traditionnelles :
| Méthode | Coût pour 200 fonctions | Temps | Précision |
|---|---|---|---|
| Comparaison manuelle avec deux IDA ouverts | Gratuit mais épuisant | Plusieurs heures | Élevée |
| Appariement automatique avec BinDiff | Gratuit | Rapide | Moyenne (échec en cas de changements structurels importants) |
| Confier entièrement à un Agent (CC/Codex) | 50-100 yuans | Lent | Élevée |
| Ce skill (comparaison par LLM par lots) | ~1 yuan | ~10 secondes/fonction | Élevée |
Principe fondamental
Fonction ancienne (symbolisée) Fonction nouvelle (non symbolisée)
↓ ↓
Export désassemblage + pseudo-code Export désassemblage + pseudo-code
↓ ↓
└──────── Comparaison structurée LLM ──────────┘
↓
Sortie YAML (table de mappage des symboles)
↓
Analyse programmatique → Application par lots à l'IDB (nouvelle version)
Points clés :
- Le prompt est un modèle fixe, rempli de manière programmatique
- Le format d'entrée et de sortie est déterminé et analysé programmatiquement
- Le LLM est uniquement responsable de l'étape "examiner deux extraits de code et identifier les correspondances"
- Le coût en temps et en tokens est extrêmement bas
Modèle de prompt
Prompt de comparaison standard
I have disassembly outputs and procedure code of the same function.
This is the function for reference:
**Disassembly for Reference**
```c
{disasm_for_reference}
Procedure code for Reference
{procedure_for_reference}
This is the function you need to reverse-engineering:
Disassembly to reverse-engineering
{disasm_code}
Procedure code to reverse-engineering
{procedure}
What you need to do is to collect all references to "{symbol_name_list}" in the function you need to reverse-engineering and output those references as YAML.
Example:
found_vcall: # This is for indirect call to virtual function or virtual function pointer fetching.
- insn_va: '0x180777700' # Always be the instruction with displacement offset
insn_disasm: call [rax+68h] # Always be the instruction with displacement offset
vfunc_offset: '0x68'
func_name: ILoopMode_OnLoopActivate
- insn_va: '0x180777778' # Always be the instruction with displacement offset
insn_disasm: mov rax, [rax+80h] # Always be the instruction with displacement offset
vfunc_offset: '0x80'
func_name: INetworkMessages_GetNetworkGroupCount
found_call: # This is for direct call to non-virtual regular function.
- insn_va: '0x180888800'
insn_disasm: call sub_180999900
func_name: CLoopMode_RegisterEventMapInternal
- insn_va: '0x180888880'
insn_disasm: call sub_180555500
func_name: CLoopMode_SetSystemState
found_funcptr: # This is for non-virtual regular function pointer.
- insn_va: '0x180666600' # Must load/reference the function pointer target address
insn_disasm: lea rdx, sub_15BC910 # Must load/reference the function pointer target address
funcptr_name: CLoopMode_OnClientPollNetworking
found_gv: # This is for reference to global variable.
- insn_va: '0x180444400'
insn_disasm: mov rcx, cs:qword_180666600 # Must load/reference the global variable
gv_name: g_pNetworkMessages
- insn_va: '0x180333300'
insn_disasm: lea rax, unk_180222200 # Must load/reference the global variable
gv_name: s_EventManager
found_struct_offset: # This is for reference to struct offset. NOTE THAT virtual function pointer should not be here! virtual function pointer should ALWAYS be in found_vcall !
- insn_va: '0x1801BA12A' # Always be the instruction with displacement offset
insn_disasm: mov rcx, [r14+58h] # Always be the instruction with displacement offset
offset: '0x58'
size: 8
struct_name: CResourceService
member_name: m_pEntitySystem
If nothing found, output an empty YAML. DO NOT output anything other than the desired YAML. DO NOT collect unrelated symbols.
### Description des variables
| Variable | Source | Description |
|----------|--------|-------------|
| `{disasm_for_reference}` | Export IDA ancienne version | Désassemblage symbolisé |
| `{procedure_for_reference}` | Export IDA ancienne version | Pseudo-code symbolisé |
| `{disasm_code}` | Export IDA nouvelle version | Désassemblage non symbolisé |
| `{procedure}` | Export IDA nouvelle version | Pseudo-code non symbolisé |
| `{symbol_name_list}` | Extrait de l'ancienne version | Liste des symboles à localiser dans la nouvelle version |
## Workflow
### Processus complet
```text
Étape 1 : Préparer les données
- Charger l'ancien binaire dans IDA (avec PDB/symboles)
- Charger le nouveau binaire dans IDA (sans symboles)
- Trouver les mêmes fonctions d'ancrage dans les deux versions (fonctions exportées, références de chaînes, etc.)
Étape 2 : Export par lots
- Depuis l'ancienne version : exporter le désassemblage + pseudo-code des fonctions d'ancrage (avec noms de symboles)
- Depuis la nouvelle version : exporter le désassemblage + pseudo-code des mêmes fonctions d'ancrage (sans noms de symboles)
Étape 3 : Comparaison LLM
- Remplir le modèle de prompt avec les données
- Appeler l'API LLM (recommandé : DeepSeek pour un volume important et peu coûteux, GPT pour les très grandes fonctions)
- Analyser le YAML retourné
Étape 4 : Appliquer les résultats
- Appliquer par lots le mappage des symboles du YAML à l'IDB de la nouvelle version
- Utiliser `idapro_rename` ou un script IDAPython pour renommer en masse
Étape 5 : Itérer
- Les fonctions migrées lors du premier tour deviennent de nouvelles ancres
- Entrer dans ces fonctions et continuer à comparer les appels internes
- Répéter jusqu'à couvrir toutes les fonctions cibles
Stratégie de sélection des points d'ancrage
| Type d'ancrage | Fiabilité | Description |
|---|---|---|
| Fonction exportée | La plus élevée | Le nom ne change pas, l'adresse peut changer |
| Référence de chaîne | Élevée | Le contenu de la chaîne ne change pas, l'emplacement de la référence peut changer |
| Constante / Nombre magique | Moyenne | Valeur caractéristique ne change pas |
| Motif de code | Moyenne | Structure de fonction similaire mais adresses complètement différentes |
Recommandations pour le traitement par lots
- Comparer 1 fonction à la fois (éviter l'explosion du contexte)
- Pour les fonctions de taille moyenne (<200 lignes), utiliser DeepSeek
- Pour les très grandes fonctions (>500 lignes), utiliser GPT-4o ou Claude
- Appels concurrents pour augmenter la vitesse (10-20 en parallèle)
- Mettre en cache les résultats intermédiaires pour éviter les appels redondants
Format de sortie
5 types de symboles dans la sortie YAML
| Type | Signification | Champs clés |
|---|---|---|
found_vcall | Appel de fonction virtuelle (appel indirect) | vfunc_offset, func_name |
found_call | Appel de fonction directe | insn_va, func_name |
found_funcptr | Référence à un pointeur de fonction | insn_va, funcptr_name |
found_gv | Référence à une variable globale | insn_va, gv_name |
found_struct_offset | Référence à un offset de structure | offset, struct_name, member_name |
Actions d'application après analyse
found_call → idapro_rename(addr=call_target, name=func_name)
found_vcall → idapro_set_comments(addr=insn_va, comment="vcall: {func_name} @ +{offset}")
found_funcptr → idapro_rename(addr=funcptr_target, name=funcptr_name)
found_gv → idapro_rename(addr=gv_addr, name=gv_name)
found_struct_offset → idapro_set_comments(addr=insn_va, comment="{struct_name}.{member_name}")
Exemples de scénarios typiques
Scénario 1 : ntoskrnl.exe sans PDB
Déjà disponible : ntoskrnl.exe 10.0.26100.2000 + PDB complet
Cible : ntoskrnl.exe 10.0.26100.2605 (PDB retiré)
Besoin : Localiser la nouvelle adresse de PspSetCreateProcessNotifyRoutine
Étapes :
1. Charger les deux versions dans IDA
2. Trouver la fonction exportée PsSetCreateProcessNotifyRoutine (présente dans les deux versions)
3. Dans l'ancienne version, elle appelle PspSetCreateProcessNotifyRoutine (symbolisé)
4. Dans la nouvelle version, elle appelle sub_140822108 (non symbolisé)
5. Le LLM identifie immédiatement : sub_140822108 = PspSetCreateProcessNotifyRoutine
6. Appliquer par lots
Scénario 2 : Migration après mise à jour d'une application
Déjà disponible : Résultats de rétro-ingénierie complets de target.exe v1.0 (200+ fonctions nommées)
Cible : target.exe v1.1 (tous les symboles perdus)
Besoin : Migrer en masse 200 noms de fonctions
Étapes :
1. Depuis l'ancienne version, exporter le désassemblage + pseudo-code de toutes les fonctions nommées
2. Dans la nouvelle version, trouver les points d'ancrage correspondants via les fonctions exportées/chaînes
3. Appeler le LLM par lots pour la comparaison
4. Analyser le YAML, renommer en masse
5. Itérer en profondeur
Recommandations de sélection du LLM
| Modèle | Scénario adapté | Coût | Vitesse |
|---|---|---|---|
| DeepSeek V3 | Fonctions petites à moyennes (<200 lignes), traitement par lots | Très faible | Rapide |
| GPT-4o | Très grandes fonctions, flux de contrôle complexes | Moyen | Rapide |
| Claude Sonnet | Fonctions moyennes à grandes, nécessitant du raisonnement | Moyen | Rapide |
| Claude Opus | Fonctions extrêmement complexes, nécessitant une compréhension approfondie | Élevé | Lent |
Stratégie recommandée : DeepSeek par défaut, mise à niveau automatique en cas de dépassement de contexte ou de résultats inexacts.
Avertissements
- Ne pas donner l'intégralité du binaire au LLM — Comparer une seule fonction à la fois.
- Les points d'ancrage doivent être fiables — Si l'ancrage lui-même est mal identifié, tout le travail ultérieur est perdu.
- Les résultats doivent être vérifiés manuellement — Le LLM n'est pas fiable à 100 %, les symboles critiques doivent être validés.
- Mettre en cache les résultats intermédiaires — Éviter les appels redondants pour économiser les tokens.
- Attention aux limites de contexte — Les très grandes fonctions (>1 000 lignes de désassemblage) doivent être divisées ou utiliser un modèle à grand contexte.
Bootstrap à la demande (On-Demand Bootstrap)
Dépendances d'outils
| Outil | Utilisation | Installation automatique possible ? |
|---|---|---|
| IDA Pro | Export désassemblage/pseudo-code | ✗ (Logiciel commercial) |
| Python | Exécution de scripts, appels API | ✓ |
| PyYAML | Analyse du YAML retourné par le LLM | ✓ (pip install pyyaml) |
| API LLM | Effectuer la comparaison | Nécessite une clé API |
Remarque
Ce skill ne dépend pas de l'installation d'outils lourds, il repose principalement sur :
- IDA Pro déjà installé (géré par le skill
ida-reverse/) - Python + requests/httpx (pour appeler l'API)
- Un point de terminaison d'API LLM
Contexte de routage
Entrée amont : skills/SKILL.md (contrôle principal), routing.md
Condition de déclenchement : Disposer de symboles / résultats de rétro-ingénierie d'une ancienne version et nécessiter une migration vers une nouvelle version.
Sortie aval :
- Nécessité d'ouvrir d'abord le binaire →
ida-reverse/ - Nécessité d'une reconnaissance rapide pour confirmer les différences de version →
radare2/
Modules associés au même niveau : ida-reverse/ (l'export de données et l'application des symboles passent par IDA)
Auto-vérification avant de déclarer la tâche terminée (MUST à réussir)
- Ai-je exécuté chaque étape du workflow (et pas seulement lu) ?
- Ai-je utilisé les chemins d'outils réels basés sur
tool-index? - Ai-je produit des preuves reproductibles (commandes/scripts/captures d'écran/rapports) ?
- Ai-je complété et renseigné les éléments de la checklist demandés dans RULES ?