
Framework d'émulation binaire scriptable intégrant IDA Pro/Radare2 avec Unicorn engine pour l'analyse automatisée de malwares, le déchiffrement de chaînes et l'exploration de chemins de code sur les architectures x86, ARM et ARM64.
flare-emu associe un framework d'analyse binaire supporté, tel qu'IDA Pro ou Radare2, avec le framework d'émulation d'Unicorn pour offrir à l'utilisateur une interface facile à utiliser et flexible pour script des tâches d'émulation. Il est conçu pour gérer toute la maintenance nécessaire à la mise en place d'un émulateur flexible et robuste pour ses architectures supportées, afin que vous puissiez vous concentrer sur la résolution de vos problèmes d'analyse de code. Actuellement, flare-emu prend en charge les architectures x86, x86_64, ARM et ARM64.
Il fournit actuellement cinq interfaces différentes pour répondre à vos besoins d'émulation, ainsi qu'une multitude de fonctions d'aide et d'utilitaires associées.
emulateRange – Cette API est utilisée pour émuler une plage d'instructions, ou une fonction, dans un contexte spécifié par l'utilisateur. Elle offre des options pour des hooks définis par l'utilisateur à la fois pour les instructions individuelles et pour lorsque des instructions « call » sont rencontrées. L'utilisateur peut décider si l'émulateur doit ignorer ou exécuter les appels de fonction. Cette interface fournit un moyen facile pour l'utilisateur de spécifier des valeurs pour des registres et arguments de pile donnés. Si une chaîne d'octets est spécifiée, elle est écrite dans la mémoire de l'émulateur et le pointeur est écrit dans le registre ou la variable de pile. Après l'émulation, l'utilisateur peut utiliser les fonctions utilitaires de flare-emu pour lire des données de la mémoire ou des registres émulés, ou utiliser l'objet d'émulation Unicorn retourné pour une interrogation directe. Une petite fonction d'encapsulation pour emulateRange, nommée emulateSelection, peut être utilisée pour émuler la plage d'instructions actuellement mise en surbrillance dans IDA Pro.
iterate - Cette API est utilisée pour forcer l'émulation sur des branches spécifiques au sein d'une fonction afin d'atteindre une cible donnée. L'utilisateur peut spécifier une liste d'adresses cibles, ou l'adresse d'une fonction à partir de laquelle une liste de références croisées à la fonction est utilisée comme cibles, ainsi qu'un rappel pour lorsqu'une cible est atteinte. Les cibles seront atteintes, indépendamment des conditions lors de l'émulation qui auraient pu causer la prise de branches différentes. Comme l'API emulateRange, des options pour des hooks définis par l'utilisateur à la fois pour les instructions individuelles et pour lorsque des instructions « call » sont rencontrées sont fournies. Un exemple d'utilisation de l'API iterate est d'obtenir quelque chose de similaire à ce que fait notre outil argtracker.
iterateAllPaths - Cette API est très similaire à iterate, sauf qu'au lieu de fournir une ou plusieurs adresses cibles, vous fournissez une fonction cible pour laquelle elle tentera de trouver tous les chemins et de les émuler. Cela est utile lorsque vous effectuez une analyse de code qui souhaite atteindre chaque bloc de base d'une fonction.
emulateBytes – Cette API offre un moyen d'émuler simplement un blob de shellcode extérieur. Les octets fournis ne sont pas ajoutés à l'IDB et sont simplement émulés tels quels. Cela peut être utile pour préparer l'environnement d'émulation. Par exemple, flare-emu lui-même utilise cette API pour manipuler un registre spécifique au modèle (MSR) pour le processeur ARM64 qui n'est pas exposé par Unicorn afin d'activer les instructions Vector Floating Point (VFP) et l'accès aux registres. L'objet d'émulation Unicorn est retourné pour une exploration plus poussée par l'utilisateur.
emulateFrom - Cette API est utile dans les cas où les limites des fonctions ne sont pas clairement définies, comme c'est souvent le cas avec des binaires obfusqués ou du shellcode. Vous fournissez une adresse de départ, et elle émule jusqu'à ce qu'il n'y ait plus rien à émuler ou que vous arrêtiez l'émulation dans l'un de vos hooks. Avec IDA Pro, cela peut être appelé avec le paramètre strict défini sur False pour activer la découverte dynamique de code ; flare-emu fera en sorte qu'IDA Pro crée les instructions au fur et à mesure qu'elles sont rencontrées lors de l'émulation.
Pour installer flare-emu pour IDA Pro, déposez simplement flare_emu.py, flare_emu_ida.py et flare_emu_hooks.py dans le répertoire python de votre IDA Pro et importez-le en tant que module dans vos scripts IDAPython.
Pour installer flare-emu pour Rizin, assurez-vous simplement que flare_emu.py, flare_emu_rizin.py et flare_emu_hooks.py se trouvent dans le chemin de recherche de Python pour l'importation de modules. Lorsque vous utilisez Rizin comme composant d'analyse binaire pour flare-emu, rzpipe est requis.
Pour installer flare-emu pour Radare2, assurez-vous simplement que flare_emu.py, flare_emu_radare.py et flare_emu_hooks.py se trouvent dans le chemin de recherche de Python pour l'importation de modules. Lorsque vous utilisez Radare2 comme composant d'analyse binaire pour flare-emu, r2pipe est requis.
Dans tous les cas, flare-emu dépend d'Unicorn et de ses bindings Python.
NOTE IMPORTANTE
flare-emu a été écrit en utilisant la nouvelle API IDA Pro 7x, il n'est pas rétrocompatible avec les versions précédentes d'IDA Pro.
Bien que flare-emu puisse être utilisé pour résoudre de nombreux problèmes d'analyse de code, l'une de ses utilisations les plus courantes est d'aider à déchiffrer des chaînes dans des binaires de malwares. FLOSS est un excellent outil qui peut souvent le faire automatiquement en essayant d'identifier la ou les fonctions de déchiffrement de chaînes et en utilisant l'émulation pour déchiffrer les chaînes passées à chaque référence croisée. Cependant, il n'est pas possible pour FLOSS de toujours identifier ces fonctions et de les émuler correctement avec ses approches génériques. Parfois, vous devez faire un peu plus de travail, et c'est là que flare-emu peut vous faire gagner beaucoup de temps une fois que vous êtes à l'aise avec. Parcourons un scénario courant auquel un analyste de malwares est confronté lorsqu'il traite des chaînes chiffrées.
Vous avez identifié la fonction qui déchiffre toutes les chaînes dans un binaire x86_64. Cette fonction est appelée partout et déchiffre de nombreuses chaînes différentes. Dans IDA Pro, vous nommez cette fonction decryptString. Voici votre script flare-emu pour déchiffrer toutes ces chaînes et placer des commentaires avec les chaînes déchiffrées à chaque appel de fonction, ainsi que journaliser chaque chaîne déchiffrée et l'adresse à laquelle elle est déchiffrée.```
from future import print_function
import flare_emu
def decrypt(argv): myEH = flare_emu.EmuHelper() myEH.emulateRange(myEH.analysisHelper.getNameAddr("decryptString"), registers = {"arg1":argv[0], "arg2":argv[1], "arg3":argv[2], "arg4":argv[3]}) return myEH.getEmuString(argv[0])
def iterateCallback(eh, address, argv, userData): s = decrypt(argv) print("%s: %s" % (eh.hexString(address), s)) eh.analysisHelper.setComment(address, s, False)
if name == 'main':
eh = flare_emu.EmuHelper()
eh.iterate(eh.analysisHelper.getNameAddr("decryptString"), iterateCallback)
Dans `__main__`, nous commençons par créer une instance de la classe `EmuHelper` issue de `flare-emu`. C'est la classe que nous utilisons pour tout faire avec `flare-emu`. Ensuite, nous utilisons l'API `iterate`, en lui donnant l'adresse de notre fonction `decryptString` et le nom de notre fonction de rappel que `EmuHelper` appellera pour chaque référence croisée émulée jusqu'à.
La fonction `iterateCallback` reçoit l'instance `EmuHelper`, nommée `eh` ici, ainsi que l'adresse de la référence croisée, les arguments passés à cet appel particulier, et un dictionnaire spécial nommé `userData` ici. `userData` n'est pas utilisé dans cet exemple simple, mais considérez-le comme un contexte persistant pour votre émulateur où vous pouvez stocker vos propres données personnalisées. Attention cependant, car `flare-emu` lui-même utilise aussi ce dictionnaire pour stocker des informations critiques nécessaires à l'exécution de ses tâches. Une de ces informations est l'instance `EmuHelper` elle-même, stockée dans la clé `"EmuHelper"`. Si cela vous intéresse, consultez le code source pour en savoir plus sur ce dictionnaire. Cette fonction de rappel appelle simplement la fonction `decrypt`, affiche la chaîne déchiffrée et crée un commentaire pour celle-ci à l'adresse de cet appel à `decryptString`.
`decrypt` crée une seconde instance de `EmuHelper` qui sert à émuler la fonction `decryptString` elle-même, ce qui déchiffrera la chaîne pour nous. Le prototype de cette fonction `decryptString` est le suivant : `char * decryptString(char *text, int textLength, char *key, int keyLength)`. Elle déchiffre simplement la chaîne sur place. Notre fonction `decrypt` transmet les arguments reçus par la fonction `iterateCallback` à notre appel à l'API `emulateRange` de `EmuHelper`. Comme il s'agit d'un binaire `x86_64`, la convention d'appel utilise des registres pour passer les arguments et non la pile. `flare-emu` détermine automatiquement quels registres représentent quels arguments en fonction de l'architecture et du format de fichier du binaire, comme déterminé par IDA Pro, ce qui vous permet d'écrire un code au moins partiellement indépendant de l'architecture. S'il s'agissait de `x86` 32 bits, vous utiliseriez l'argument `stack` pour passer les arguments, comme ceci : `myEH.emulateRange(myEH.analysisHelper.getNameAddr("decryptString"), stack = [0, argv[0], argv[1], argv[2], argv[3]])`. La première valeur de la pile est l'adresse de retour en `x86`, nous utilisons donc `0` comme valeur factice ici. Une fois l'émulation terminée, nous appelons l'API `getEmuString` pour récupérer la chaîne terminée par un nul stockée à l'emplacement mémoire pointé par le premier argument passé à la fonction.
### flare-emu et idalib
* installer IDA Pro
* installer idalib selon le guide utilisateur Hex-Rays
* (activer l'environnement virtuel)
* pip install /path/to/IDA/installation/idalib/python
* python /path/to/IDA/installation/idalib/python/py-activate-idalib.py [-d /path/to/active/IDA/installation]
* importer idapro et écrire votre script
* voir tests/test_flare_emu_idalib.py pour un exemple
### Scénario de déchiffrement facile de chaîne avec Rizin
En utilisant le même exemple ci-dessus, peu de choses changent lorsque l'on travaille avec Rizin plutôt qu'IDA Pro. Une différence est que `flare-emu` est actuellement conçu pour être exécuté en tant que script en ligne de commande ou dans un shell Python lorsqu'on travaille avec Rizin. Le shell Python est idéal pour la résolution de problèmes ad hoc, tandis que le script en ligne de commande est parfait pour le traitement par lots. La version Rizin du script ci-dessus ressemble à ceci (vous pouvez aussi omettre le chemin de l'échantillon pour l'exécuter dans rizin) :```
from __future__ import print_function
import sys
import flare_emu
def decrypt(argv, eh):
myEH = flare_emu.EmuHelper(samplePath=sys.argv[1], emuHelper=eh, isRizin=True)
myEH.emulateRange(
myEH.analysisHelper.getNameAddr("decryptString"),
registers={
"arg1": argv[0],
"arg2": argv[1],
"arg3": argv[2],
"arg4": argv[3],
},
)
return myEH.getEmuString(argv[0])
def iterateCallback(eh, address, argv, userData):
s = decrypt(argv, eh)
print("%s: %s" % (eh.hexString(address), s))
eh.analysisHelper.setComment(address, s, False)
if __name__ == "__main__":
eh = flare_emu.EmuHelper(samplePath=sys.argv[1], isRizin=True)
rz = eh.analysisHelper.r
eh.analysisHelper.setName(0x100000D60, "decryptString")
eh.iterate(eh.analysisHelper.getNameAddr("decryptString"), iterateCallback)
En utilisant le même exemple ci-dessus, peu de choses changent lorsque l'on travaille avec Radare2 plutôt qu'avec IDA Pro. Une différence est que flare-emu est actuellement conçu pour être exécuté comme un script en ligne de commande ou dans un shell Python lorsque l'on travaille avec Radare2. Le shell Python est idéal pour la résolution de problèmes ponctuels tandis que le script en ligne de commande est idéal pour le traitement par lots. La version Radare2 du script ci-dessus ressemble à ceci :```
from future import print_function
import flare_emu
def decrypt(argv, eh): myEH = flare_emu.EmuHelper(samplePath=sys.argv[1], emuHelper=eh) myEH.emulateRange(myEH.analysisHelper.getNameAddr("decryptString"), registers = {"arg1":argv[0], "arg2":argv[1], "arg3":argv[2], "arg4":argv[3]}) return myEH.getEmuString(argv[0])
def iterateCallback(eh, address, argv, userData): s = decrypt(argv, eh) print("%s: %s" % (eh.hexString(address), s)) eh.analysisHelper.setComment(address, s, False)
if name == 'main':
eh = flare_emu.EmuHelper(samplePath=sys.argv[1])
eh.analysisHelper.setName(, "decryptString")
eh.iterate(eh.analysisHelper.getNameAddr("decryptString"), iterateCallback)
Il y a deux différences avec ce script. Premièrement, le constructeur `EmuHelper` prend un paramètre ici : `samplePath=sys.argv[1]`. Lorsque le paramètre `samplePath` est fourni, `flare-emu` utilisera Radare2 avec `r2pipe` comme moteur d'analyse binaire. Vous pouvez également voir qu'un second paramètre est passé à la deuxième instance `EmuHelper` créée dans la fonction `decrypt`. Le paramètre `emuHelper` prend un objet `EmuHelper` existant et clone sa mémoire lors de la création du nouvel objet. De plus, si vous utilisez Radare2, la nouvelle instance réutilise la session Radare2 existante au lieu d'en créer une nouvelle, ce qui ajouterait plus de surcharge. Deuxièmement, `flare-emu` crée une nouvelle instance de Radare2 en utilisant `r2pipe.open`, donc il n'aura probablement pas le nom `decryptString` pour la fonction qui nous intéresse. Vous pouvez soit définir le nom vous-même en utilisant l'objet `analysisHelper` de `EmuHelper` comme ceci : `eh.analysisHelper.setName(<une adresse>, "decryptString")`, ou bien vous pouvez directement saisir l'adresse pour les appels à `iterate` et `emulateRange`.
## [Emulation Functions](#emulationfuncs)
`emulateRange(startAddr, endAddr=None, registers=None, stack=None, instructionHook=None, callHook=None, memAccessHook=None, hookData=None, skipCalls=True, hookApis=True, strict=True, count=0)` - Émule la plage d'instructions commençant à `startAddress` et se terminant à `endAddress`, sans inclure l'instruction à `endAddress`. Si `endAddress` est `None`, l'émulation s'arrête lorsqu'une instruction de type "return" est rencontrée dans la même fonction que celle où l'émulation a commencé.
* `registers` est un dictionnaire dont les clés sont des noms de registres et les valeurs sont des valeurs de registres. Certains noms de registres spéciaux sont créés par `flare-emu` et peuvent être utilisés ici, tels que `arg1`, `arg2`, etc., `ret`, et `pc`.
* `stack` est un tableau de valeurs à placer sur la pile dans l'ordre inverse, un peu comme les arguments d'une fonction en `x86`. En `x86`, n'oubliez pas que la première valeur de ce tableau est utilisée comme adresse de retour pour un appel de fonction et non comme premier argument de la fonction. `flare-emu` initialisera le contexte et la mémoire du thread émulé selon les valeurs spécifiées dans les arguments `registers` et `stack`. Si une chaîne est spécifiée pour l'une de ces valeurs, elle sera écrite à un emplacement mémoire et un pointeur vers cette mémoire sera écrit à l'emplacement de registre ou de pile spécifié à la place.
* `instructionHook` peut être une fonction que vous définissez pour être appelée avant l'émulation de chaque instruction. Elle a le prototype suivant : `instructionHook(unicornObject, address, instructionSize, userData)`.
* `callHook` peut être une fonction que vous définissez pour être appelée chaque fois qu'une instruction de type "call" est rencontrée pendant l'émulation. Elle a le prototype suivant : `callHook(address, arguments, functionName, userData)`.
* `hookData` est un dictionnaire contenant des données définies par l'utilisateur à rendre disponibles à vos fonctions de hook. C'est un moyen de persister les données tout au long de l'émulation. `flare-emu` utilise également ce dictionnaire pour ses propres besoins, donc il faut faire attention à ne pas définir une clé déjà définie. Cette variable est souvent nommée `userData` dans les fonctions de hook définies par l'utilisateur en raison de son nom dans Unicorn.
* `skipCalls` amènera l'émulateur à ignorer les instructions de type "call" et à ajuster la pile en conséquence, par défaut `True`.
* `hookApis` amène `flare-emu` à effectuer une implémentation naïve de certaines des fonctions de bibliothèque runtime et OS les plus courantes qu'il rencontre pendant l'émulation. Cela vous évite d'avoir à vous soucier des appels à des fonctions telles que `memcpy`, `strcat`, `malloc`, etc., et par défaut `True`.
* `memAccessHook` peut être une fonction que vous définissez pour être appelée chaque fois que la mémoire est accédée en lecture ou en écriture. Elle a le prototype suivant : `memAccessHook(unicornObject, accessType, memAccessAddress, memAccessSize, memValue, userData)`.
* `strict`, lorsqu'il est défini sur `True` (par défaut), vérifie les destinations des branchements pour s'assurer que le désassembleur s'attend à des instructions. Sinon, il saute l'instruction de branchement. S'il est défini sur `False` lors de l'utilisation d'IDA Pro, `flare-emu` fabriquera des instructions dans IDA Pro au fur et à mesure de leur émulation **(À UTILISER AVEC PRUDENCE)**.
* `count` est le nombre maximum d'instructions à émuler, par défaut `0` ce qui signifie aucune limite.
`iterate(target, targetCallback, preEmuCallback=None, callHook=None, instructionHook=None, hookData=None, resetEmuMem=False, hookApis=True, memAccessHook=None)` - Pour chaque cible spécifiée par `target`, une émulation séparée est effectuée depuis le début de la fonction contenante jusqu'à l'adresse cible. L'émulation sera forcée dans les branches nécessaires pour atteindre chaque cible. `target` peut être l'adresse d'une fonction, auquel cas la liste des cibles est remplie avec toutes les références croisées vers la fonction spécifiée. Ou, `target` peut être une liste explicite de cibles.
* `targetCallback` est une fonction que vous créez et qui sera appelée par `flare-emu` pour chaque cible atteinte pendant l'émulation. Elle a le prototype suivant : `targetHook(emuHelper, address, arguments, userData)`.
* `preEmuCallback` est une fonction que vous créez et qui sera appelée avant que l'émulation ne commence pour chaque cible. Vous pouvez implémenter du code de configuration ici si nécessaire.
* `resetEmuMem` amènera `flare-emu` à réinitialiser la mémoire d'émulation avant le début de l'émulation de chaque cible, par défaut `False`.
`iterateAllPaths(target, targetCallback, preEmuCallback=None, callHook=None, instructionHook=None, hookData=None, resetEmuMem=False, hookApis=True, memAccessHook=None, maxPaths=MAXCODEPATHS, maxNodes=MAXNODESEARCH)` - Pour la fonction contenant l'adresse `target`, une émulation séparée est effectuée pour chaque chemin découvert à travers celle-ci, jusqu'à `maxPaths`.
* `maxPaths` - le nombre maximum de chemins à travers la fonction qui seront recherchés et émulés. Certaines fonctions plus complexes peuvent faire en sorte que la fonction de recherche de graphe prenne très longtemps ou ne se termine jamais ; ajustez ce paramètre pour répondre à vos besoins dans un délai raisonnable.
* `maxNodes` - le nombre maximum de blocs de base qui seront recherchés lors de la recherche de chemins à travers la fonction cible. Il s'agit d'une mesure de sécurité pour éviter des temps de recherche déraisonnables et des blocages et ne nécessite probablement pas d'être modifié.
`emulateBytes(bytes, registers=None, stack=None, baseAddress=0x400000, instructionHook=None, hookData=None)` - Écrit le code contenu dans `bytes` dans la mémoire d'émulation à `baseAddress` si possible et émule les instructions du début à la fin de `bytes`.
`emulateFrom(startAddr, registers=None, stack=None, instructionHook=None, callHook=None, memAccessHook=None, hookData=None, skipCalls=True, hookApis=True, strict=True, count=0)` - Cette API est utile dans les cas où les limites des fonctions ne sont pas clairement définies comme c'est souvent le cas avec les binaires obfusqués ou le shellcode. Vous fournissez une adresse de départ comme `startAddr`, et elle émule jusqu'à ce qu'il n'y ait plus rien à émuler ou que vous arrêtiez l'émulation dans l'un de vos hooks. Cela peut être appelé avec le paramètre `strict` défini sur `False` pour permettre la découverte dynamique de code ; `flare-emu` fera en sorte qu'IDA Pro fabrique des instructions au fur et à mesure qu'elles sont rencontrées pendant l'émulation.
## [Utility Functions](#utility)
La liste suivante est une liste incomplète de certaines des fonctions utilitaires utiles fournies par la classe `EmuHelper`.
* `hexString(value)` - Retourne une chaîne formatée en hexadécimal pour la valeur. Utile pour les instructions de journalisation et d'impression.
* `skipInstruction(userData, useAnalysisHelper=False)` - Appelez ceci depuis un hook d'émulation pour sauter l'instruction courante, en déplaçant le compteur de programme à l'instruction suivante. L'option `useAnalysisHelper` a été ajoutée pour gérer les cas où le framework d'analyse binaire fusionne plusieurs instructions en une seule pseudo-instruction et que vous souhaitez toutes les sauter. Cette fonction ne peut pas être appelée plusieurs fois depuis un seul hook d'instruction pour sauter plusieurs instructions. Pour sauter plusieurs instructions, il est recommandé de ne pas écrire directement dans le compteur de programme si vous émulez du code ARM car cela pourrait causer des problèmes avec le mode thumb. Essayez plutôt l'API `changeProgramCounter` de `EmuHelper` (décrite ci-dessous).
* `changeProgramCounter(userData, newAddress)` - Appelez ceci depuis un hook d'émulation pour changer la valeur du registre du compteur de programme. Cette API prend en charge le suivi du mode thumb pour l'architecture ARM.
* `getRegVal(registerName)` - Récupère la valeur du registre spécifié, en tenant compte de l'adressage des sous-registres. Par exemple, "ax" retournera les 16 bits de poids faible du registre EAX/RAX en `x86`.
* `stopEmulation(userData)` - Appelez ceci depuis un hook d'émulation pour arrêter l'émulation. Utilisez ceci au lieu d'appeler l'API Unicorn `emu_stop` afin que l'objet `EmuHelper` puisse gérer la comptabilité liée à la fonctionnalité `iterate`.
* `getEmuString(address)` - Retourne la chaîne de caractères située à une adresse dans la mémoire émulée, jusqu'à un terminateur nul. Les caractères ne sont pas nécessairement imprimables.
* `getEmuWideString(address)` - Retourne la chaîne de "caractères larges" située à une adresse dans la mémoire émulée, jusqu'à un terminateur nul. "Caractères larges" est utilisé ici de manière approximative pour désigner toute série d'octets contenant un octet nul tous les deux octets, comme ce serait le cas pour une chaîne ASCII encodée en UTF-16 LE. Les caractères ne sont pas nécessairement imprimables.
* `getEmuBytes(address, length)` - Retourne une chaîne d'octets située à une adresse dans la mémoire émulée.
* `getEmuPtr(address)` - Retourne la valeur du pointeur situé à l'adresse donnée.
* `writeEmuPtr(address, value)` - Écrit la valeur du pointeur à l'adresse donnée dans la mémoire émulée.
* `loadBytes(bytes, address=None)` - Alloue de la mémoire dans l'émulateur et y écrit les octets.
* `isValidEmuPtr(address)` - Retourne `True` si l'adresse fournie pointe vers de la mémoire émulée valide.
* `getEmuMemRegion(address)` - Retourne un tuple contenant l'adresse de début et de fin de la région mémoire contenant l'adresse fournie, ou `None` si l'adresse n'est pas valide.
* `getArgv()` - Appelez ceci depuis un hook d'émulation à une instruction de type "call" pour recevoir un tableau des arguments de la fonction.
* `addApiHook(apiName, hook)` - Ajoute un nouveau hook d'API pour cette instance de `EmuHelper`. Chaque fois qu'une instruction d'appel à `apiName` est rencontrée pendant l'émulation, `EmuHelper` appellera la fonction spécifiée par `hook`. Si `hook` est une chaîne, elle doit être le nom d'une API déjà hookée par `EmuHelper`, auquel cas elle appellera sa fonction de hook existante. Si `hook` est une fonction, elle appellera cette fonction.
* `allocEmuMem(size, addr=None)` - Alloue suffisamment de mémoire d'émulation pour contenir `size` octets. Il tente de respecter l'`adresse` demandée, mais si elle chevauche une région mémoire existante, il allouera dans une région mémoire inutilisée et retournera la nouvelle adresse. Si l'`adresse` n'est pas alignée sur une page, il retournera une adresse qui conserve le même décalage aligné sur une page au sein de la nouvelle région. Par exemple, demander l'adresse `0x1234` alors que `0x1000` est déjà alloué, peut l'amener à allouer à `0x2000` et retourner `0x2234` à la place.
# [Learn More](#learn)
Pour en savoir plus sur **flare-emu**, veuillez lire notre blog d'introduction à https://www.fireeye.com/blog/threat-research/2018/12/automating-objective-c-code-analysis-with-emulation.html.