Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
bip — API de Python orientada a objetos para simplificar la interacción con IDA en ingeniería inversa, permitiendo el desarrollo de plugins y la automatización de análisis de desensamblado. | Kitploit
Herramientas/GitHubGitHub/synacktiv/bip
Análisis EstáticoAnálisis de CódigoIngeniería InversaScripting y AutomatizaciónAnálisis de Binarios
GitHubsynacktiv/bip

bip

API de Python orientada a objetos para simplificar la interacción con IDA en ingeniería inversa, permitiendo el desarrollo de plugins y la automatización de análisis de desensamblado.

Ver Repositorio
20519hace 4 añosRevisado por Kitploit

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

Bip

Bip es un proyecto que tiene como objetivo simplificar el uso de Python para interactuar con IDA. Sus principales objetivos son facilitar el uso de Python en la consola interactiva de IDA y la escritura de plugins. De un modo más general, el objetivo es automatizar tareas recurrentes realizadas a través de la API de Python. Bip también se desarrolla para proporcionar una API más orientada a objetos, "similar a Python" y una documentación real.

Este código no está completo, y muchas características aún faltan. El desarrollo se prioriza en función de lo que la gente pide y de lo que usan los desarrolladores, así que no dudes en hacer PR, Feature Requests e Issues (incluyendo para la documentación).

La documentación está disponible en formato RST (y se puede compilar usando sphinx) en el directorio docs/; también está disponible en línea <https://synacktiv.github.io/bip/build/html/index.html>_.

  • Versión actual de IDA: IDA 7.5SP1 y Python 2.7 o 3.8
  • Última versión de Bip: 1.0

Instalación

Esta instalación solo se ha probado en Windows y Linux: python install.py.

Es posible usar un argumento opcional --dest para instalar en una carpeta concreta:

.. code-block:: none

root@kitploit:~
usage: install.py [-h] [--dest DEST]

optional arguments:
  -h, --help   show this help message and exit
  --dest DEST  Destination folder where to install Bip

Este instalador no instala ningún plugin por defecto, sino simplemente el núcleo de Bip. Por defecto, la carpeta de destino es la que usa IDA localmente (%APPDATA%\Hex-Rays\IDA Pro\ para Windows y $HOME/.idapro para Linux y MacOSX).

Resumen

Este resumen tiene como objetivo mostrar cómo se pueden realizar las operaciones más habituales; está lejos de ser completo. Todas las funciones y objetos en Bip están documentados usando cadenas de documentación (docstrings), así que solo usa help(BipClass) y help(obj.bipmethod) para obtener la documentación en tu shell.

Base

El módulo bip.base contiene la mayoría de las características básicas para interactuar con IDA. En la práctica, esta es principalmente la parte del desensamblador de IDA; esto incluye: manipulación de instrucciones, funciones, bloques básicos, operandos, datos, xrefs, estructuras, tipos, ...

Instrucciones / Operandos~~~~~~~~~~~~~~~~~~~~~~~

The classes bip.base.BipInstr and bip.base.BipOperand:

.. code-block:: pycon

root@kitploit:~
>>> from bip.base import *
>>> i = BipInstr() # BipInstr is the base class for representing an instruction
>>> i # by default the address on the screen is taken
BipInstr: 0x1800D324B (mov     rcx, r13)
>>> i2 = BipInstr(0x01800D3242) # pass the address in argument
>>> i2
BipInstr: 0x1800D3242 (mov     r8d, 8)
>>> i2.next # access next instruction, previous with i2.prev
BipInstr: 0x1800D3248 (mov     rdx, r14)
>>> l = [i3 for i3 in BipInstr.iter_all()] # l contains the list of all BipInstruction of the database, iter_all produces a generator object
>>> i.ea # access the address
6443315787
>>> i.mnem # mnemonic representation
mov
>>> i.ops # access to the operands
[<bip.base.operand.BipOperand object at 0x0000022B0291DA90>, <bip.base.operand.BipOperand object at 0x0000022B0291DA58>]
>>> i.ops[0].str # string representation of an operand
rcx
>>> i.bytes # bytes in the instruction
[73L, 139L, 205L]
>>> i.size # number of bytes of this instruction
3
>>> i.comment = "hello" # set a comment, rcomment for the repeatable comments
>>> i
BipInstr: 0x1800D324B (mov     rcx, r13; hello)
>>> i.comment # get a comment
hello
>>> i.func # access to the function
Func: RtlQueryProcessLockInformation (0x1800D2FF0)
>>> i.block # access to basic block
BipBlock: 0x1800D3242 (from Func: RtlQueryProcessLockInformation (0x1800D2FF0))

Function / Basic block

root@kitploit:~

The classes ``bip.base.BipFunction`` and ``bip.base.BipBlock``:

.. code-block:: pycon

    >>> from bip.base import *
    >>> f = BipFunction() # Get the function, screen address used if not provided
    >>> f
    Func: RtlQueryProcessLockInformation (0x1800D2FF0)
    >>> f2 = BipFunction(0x0018010E975) # provide an address, not necessary the first one
    >>> f2
    Func: sub_18010E968 (0x18010E968)
    >>> f == f2 # compare two functions
    False
    >>> f == BipFunction(0x001800D3021)
    True
    >>> hex(f.ea) # start address
    0x1800d2ff0L
    >>> hex(f.end) # end address
    0x1800d3284L
    >>> f = BipFunction.get_by_name("RtlQueryProcessLockInformation") # fetch the function from its name
    >>> f.name # get and set the name
    RtlQueryProcessLockInformation
    >>> f.name = "test"
    >>> f.name
    test
    >>> f.size # number of bytes in the function
    660
    >>> f.bytes # bytes of the function
    [72L, ..., 255L]
    >>> f.callees # list of functions called by this function
    [<bip.base.func.BipFunction object at 0x0000022B0291DD30>, ..., <bip.base.func.BipFunction object at 0x0000022B045487F0>]
    >>> f.callers # list of functions which call this function
    [<bip.base.func.BipFunction object at 0x0000022B04544048>]
    >>> f.instr # list of instructions in the function
    [<bip.base.instr.BipInstr object at 0x0000022B0291DB00>, ..., <bip.base.instr.BipInstr object at 0x0000022B0454D080>]
    >>> f.comment = "welcome to bip" # comment of the function, rcomment for repeatable ones
    >>> f.comment
    welcome to bip
    >>> f.does_return # does this function return ?
    True
    >>> BipFunction.iter_all() # allows to iter on all functions defined in the database
    <generator object iter_all at 0x0000022B029231F8>
    >>> f.nb_blocks # number of basic blocks
    33
    >>> f.blocks # list of blocks
    [<bip.base.block.BipBlock object at 0x0000022B04544D68>, ..., <bip.base.block.BipBlock object at 0x0000022B04552240>]
    >>> f.blocks[5] # access the basic block 5, could be done with BipBlock(addr)
    BipBlock: 0x1800D306E (from Func: test (0x1800D2FF0))
    >>> f.blocks[5].func # link back to the function
    Func: test (0x1800D2FF0)
    >>> f.blocks[5].instr # list of instructions in the block
    [<bip.base.instr.BipInstr object at 0x0000022B04544710>, ..., <bip.base.instr.BipInstr object at 0x0000022B0291DB00>]
    >>> f.blocks[5].pred # predecessor blocks, blocks where control flow lead to this one
    [<bip.base.block.BipBlock object at 0x0000022B04544D68>]
    >>> f.blocks[5].succ # successor blocks
    [<bip.base.block.BipBlock object at 0x0000022B04544710>, <bip.base.block.BipBlock object at 0x0000022B04544438>]
    >>> f.blocks[5].is_ret # is this block containing a return
    False

Data
~~~~

The class ``bip.base.BipData``:

.. code-block:: pycon

    >>> from bip.base import *
    >>> d = BipData(0x000180110068) # .rdata:0000000180110068 bip_ex          dq offset unk_180110DE0
    >>> d
    BipData at 0x180110068 = 0x180110DE0 (size=8)
    >>> d.name # Name of the symbol if any
    bip_ex
    >>> d.is_word # is it a word
    False
    >>> d.is_qword # is it a qword
    True
    >>> hex(d.value) # value at that address, this take into account the basic type (byte, word, dword, qword) defined in IDA
    0x180110de0L
    >>> hex(d.ea) # address
    0x180110068L
    >>> d.comment = "example" # comment as before
    >>> d.comment
    example
    >>> d.value = 0xAABBCCDD # change the value
    >>> hex(d.value)
    0xaabbccddL
    >>> d.bytes # get the bytes, as before
    [221L, 204L, 187L, 170L, 0L, 0L, 0L, 0L]
    >>> hex(d.original_value) # get the original value before modification
    0x180110de0L
    >>> d.bytes = [0x11, 0x22, 0x33, 0x44, 0, 0, 0, 0] # patch the bytes
    >>> hex(d.value) # get the value
    0x44332211L
    >>> BipData.iter_heads() # iter on "heads" of the IDB, heads are defined data in the IDB
    <generator object iter_heads at 0x0000022B02923240>
    >>> hex(BipData.get_dword(0x0180110078)) # staticmethod for reading value at an address
    0x60004L
    >>> BipData.set_byte(0x0180110078, 0xAA) # static method for modifying a value at an address
    >>> hex(BipData.get_qword(0x0180110078))
    0x600aaL

Element
~~~~~~~

In Bip most basic objects inherit from the same classes: ``BipBaseElt`` which is
the most basic one, ``BipRefElt`` which includes all the objects which can have
xrefs (including structures (``BipStruct``) and structure members
(``BStructMember``), see below), ``BipElt``
which represents all elements which have an address in the IDA DataBase (idb),
including ``BipData`` and ``BipInstr`` (it is this class which
implements the properties: ``comment``,  ``name``, ``bytes``, ...).

It is possible to use the functions ``GetElt`` and ``GetEltByName``
to get the right basic element from an address or a name
representing a location in the binary.

.. code-block:: pycon

    >>> from bip.base import *
    >>> GetElt() # get the element at current address, in this case return a BipData object
    BipData at 0x180110068 = 0xAABBCCDD (size=8)
    >>> GetElt(0x00180110078) # get the element at the address 0x00180110078
    BipData at 0x180110078 = 0xAA (size=1)
    >>> GetElt(0x1800D2FF0) # in this case it returns an BipInstr object because this is code
    BipInstr: 0x1800D2FF0 (mov     rax, rsp)
    >>> GetEltByName("bip_ex") # Get using a name and not an address
    BipData at 0x180110068 = 0xAABBCCDD (size=8)
    >>> isinstance(GetElt(0x1800D2FF0), BipInstr) # test if that element is an instruction ?
    True
    >>> GetElt(0x1800D2FF0).is_code # are we on code ? same for is_data; do not work for struct
    True
    >>> isinstance(GetElt(0x1800D2FF0), BipData) # or data ?
    False

Some static functions are provided to search elements in the database:

.. code-block:: pycon

    >>> from bip.base import *
    >>> GetElt()
    BipInstr: 0x1800D3248 (mov     rdx, r14)
    >>> BipElt.next_code() # find next code elt from current addres or addr passed as arg
    BipInstr: 0x1800D324B (mov     rcx, r13)
    >>> BipElt.next_code(down=False) # find prev code element
    BipInstr: 0x1800D3242 (mov     r8d, 8)
    >>> BipElt.next_data() # find next data elt from current address or addr passed as arg
    BipData at 0x1800D3284 = 0xCC (size=1)
    >>> BipElt.next_data(down=False) # find previous data element
    BipData at 0x1800D2FE1 = 0xCC (size=1)
    >>> hex(BipElt.next_data_addr(down=False)) # find address of the previous data element
    0x1800d2fe1L
    >>> BipElt.next_unknown() # same for unknown, which are not typed element of IDA and are considered data by Bip
    BipData at 0x180110000 = 0xE (size=1)
    >>> BipElt.next_defined() # opposite of unknown: data or code
    BipInstr: 0x1800D324B (mov     rcx, r13)
    >>> BipElt.search_bytes("49 ? CD", 0x1800D3248) # search for byte sequence (ignore the current position by default)
    BipInstr: 0x1800D324B (mov     rcx, r13)

Xref
~~~~

All elements which inherit from ``BipRefElt`` (``BipInstr``,
``BipData``, ``BipStruct``, ...) and some other (in
particular ``BipFunction``) contain methods which allow
to access xrefs. They are represented by the ``BipXref`` objects which
have a ``src`` (origin of the xref) and a ``dst`` (destination of the xref).

.. code-block:: pycon

    >>> from bip.base import *
    >>> i = BipInstr(0x01800D3063)
    >>> i # example with instruction but works the same with BipData
    BipInstr: 0x1800D3063 (cmp     r15, [rsp+98h+var_58])
    >>> i.xTo # List of xref which point on this instruction
    [<bip.base.xref.BipXref object at 0x0000022B04544438>, <bip.base.xref.BipXref object at 0x0000022B045447F0>]
    >>> i.xTo[0].src # previous instruction
    BipInstr: 0x1800D305E (mov     [rsp+98h+var_78], rsi)
    >>> i.xTo[0].is_ordinaryflow # is this an ordinary flow between to instruction (not jmp or call)
    True
    >>> i.xTo[1].src # jmp to instruction i at 0x1800D3063
    BipInstr: 0x1800D3222 (jmp     loc_1800D3063)
    >>> i.xTo[1].is_jmp # is this xref because of a jmp ?
    True
    >>> i.xEaTo # bypass the xref objects and get the address directly
    [6443315294L, 6443315746L]
    >>> i.xEltTo # bypass the xref objects and get the elements directly, will list BipData if any
    [<bip.base.instr.BipInstr object at 0x0000022B045447F0>, <bip.base.instr.BipInstr object at 0x0000022B04544978>]
    >>> i.xCodeTo # bypass the xref objects and get the instr directly, if a BipData was pointed at this address it will not be listed
    [<bip.base.instr.BipInstr object at 0x0000022B04544438>, <bip.base.instr.BipInstr object at 0x0000022B0291DD30>]
    >>> i.xFrom # same but for coming from this instruction
    [<bip.base.xref.BipXref object at 0x0000022B04544D68>]
    >>> i.xFrom[0]
    <bip.base.xref.BipXref object at 0x0000022B04544438>
    >>> i.xFrom[0].dst # next instruction
    BipInstr: 0x1800D3068 (jz      loc_1800D3227)
    >>> i.xFrom[0].src # current instruction
    BipInstr: 0x1800D3063 (cmp     r15, [rsp+98h+var_58])
    >>> hex(i.xFrom[0].dst_ea) # address of the next instruction
    0x1800D3068L
    >>> i.xFrom[0].is_codepath # this is a normal code path (include jmp and call)
    True
    >>> i.xFrom[0].is_call # is this because of a call ?
    False
    >>> f = BipFunction()
    >>> f
    Func: RtlQueryProcessLockInformation (0x1800D2FF0)
    >>> f.xTo # works also for functions, but only with To, not with the From
    [<bip.base.xref.BipXref object at 0x000001D95529EB00>, <bip.base.xref.BipXref object at 0x000001D95529EB70>, <bip.base.xref.BipXref object at 0x000001D95529EBE0>, <bip.base.xref.BipXref object at 0x000001D95529EC88>]
    >>> f.xEltTo # here we have 3 data references to this function
    [<bip.base.instr.BipInstr object at 0x000001D95529EE48>, <bip.base.data.BipData object at 0x000001D95529EEF0>, <bip.base.data.BipData object at 0x000001D95529EF28>, <bip.base.data.BipData object at 0x000001D95529EF60>]
    >>> f.xCodeTo # but only one instruction
    [<bip.base.instr.BipInstr object at 0x000001D95529EC88>]

Struct
~~~~~~

Manipulating struct (``BipStruct``) and members (``BStructMember``):

.. code-block:: pycon

    >>> from bip.base import *
    >>> st = BipStruct.get("EXCEPTION_RECORD") # Structs are accessed by using get and their name
    >>> st # BipStruct object
    Struct: EXCEPTION_RECORD (size=0x98)
    >>> st.comment = "struct comment"
    >>> st.comment
    struct comment
    >>> st.name
    EXCEPTION_RECORD
    >>> st.size
    152
    >>> st["ExceptionFlags"] # access to the BStructMember by their name
    Member: EXCEPTION_RECORD.ExceptionFlags (offset=0x4, size=0x4)
    >>> st[8] # or by their offset, this is *not* the entry number 8!!!
    Member: EXCEPTION_RECORD.ExceptionRecord (offset=0x8, size=0x8)
    >>> st[2] # offset does not need to be the first one
    Member: EXCEPTION_RECORD.ExceptionCode (offset=0x0, size=0x4)
    >>> st.members # list of members
    [<bip.base.struct.BStructMember object at 0x000001D95529EEF0>, ..., <bip.base.struct.BStructMember object at 0x000001D95536DF28>]
    >>> st[0].name
    ExceptionCode
    >>> st[0].fullname
    EXCEPTION_RECORD.ExceptionCode
    >>> st[0].size
    4
    >>> st[0].struct
    Struct: EXCEPTION_RECORD (size=0x98)
    >>> st[0].comment = "member comment"
    >>> st[0].comment
    member comment
    >>> st[8].xEltTo # BStructMember et BipStruct have xrefs
    [<bip.base.instr.BipInstr object at 0x000001D95536DD30>, <bip.base.instr.BipInstr object at 0x000001D95536D9E8>]
    >>> st[8].xEltTo[0]
    BipInstr: 0x1800A0720 (mov     [rsp+538h+ExceptionRecord.ExceptionRecord], r10)

Creating struct, adding members and nested structure:

.. code-block:: pycon

    >>> from bip.base import *
    >>> st = BipStruct.create("NewStruct") # create a new structure
    >>> st
    Struct: NewStruct (size=0x0)
    >>> st.add("NewField", 4) # add a new member named "NewField" of size 4
    Member: NewStruct.NewField (offset=0x0, size=0x4)
    >>> st.add("NewQword", 8)
    Member: NewStruct.NewQword (offset=0x4, size=0x8)
    >>> st
    Struct: NewStruct (size=0xC)
    >>> st.add("struct_nested", 1)
    Member: NewStruct.struct_nested (offset=0xC, size=0x1)
    >>> st["struct_nested"].type = BipType.from_c("EXCEPTION_RECORD") # changing the type of member struct_nested to struct EXCEPTION_RECORD
    >>> st["struct_nested"]
    Member: NewStruct.struct_nested (offset=0xC, size=0x98)
    >>> st["struct_nested"].is_nested # is this a nested structure ?
    True
    >>> st["struct_nested"].nested_struct # getting the nested structure
    Struct: EXCEPTION_RECORD (size=0x98)

Types
~~~~~

IDA uses extensively types in hexrays but also in the base API for defining
types of data, variables and so on. In Bip the different types inherit from
the same class ``BipType``. This class offers some basic methods common to all
types and subclasses (class starting by ``BType``) can define more specific
ones.

The types should be seen as a recursive structure: a ``void *`` is a
``BTypePtr`` containing a ``BTypeVoid`` structure. For a list of the
different types implemented in Bip see the `documentation <https://synacktiv.github.io/bip/build/html/base/type.html>`_.

.. code-block:: pycon

    >>> from bip.base import *
    >>> pv = BipType.from_c("void *") # from_c is the easiest way to create a type
    >>> pv
    <bip.base.biptype.BTypePtr object at 0x000001D95536DDD8>
    >>> pv.size # ptr on x64 is 8 bytes
    8
    >>> pv.str # C string representation
    void *
    >>> pv.is_named # this type is not named
    False
    >>> pv.pointed # type below the pointer (recursive)
    <bip.base.biptype.BTypeVoid object at 0x000001D95536DF60>
    >>> pv.children # list of type pointed
    [<bip.base.biptype.BTypeVoid object at 0x000001D95536DEB8>]
    >>> d = BipData(0x000180110068)
    >>> d.type # access directly to the type at the address
    <bip.base.biptype.BTypePtr object at 0x000001D95536D9E8>
    >>> d.type.str
    void *
    >>> ps = BipType.from_c("EXCEPTION_RECORD *")
    >>> ps.pointed # type for struct EXCEPTION_RECORD
    <bip.base.biptype.BTypeStruct object at 0x000001D95536DD30>
    >>> ps.pointed.is_named # this one is named
    True
    >>> ps.pointed.name
    EXCEPTION_RECORD
    >>> ps.set_at(d.ea) # set the type ps at address d.ea
    >>> d.type.str # the type has indeed changed
    EXCEPTION_RECORD *
    >>> d.type = pv # rolling it back
    >>> d.type.str
    void *
    >>> BipType.get_at(d.ea) # Possible to directly get the type with get_at(address)
    <bip.base.biptype.BTypePtr object at 0x000001D95536DEB8>

Hexrays
-------

The module ``bip.hexrays`` contains the features linked to the decompiler
provided by IDA.

Functions / local variables

Las funciones de Hexrays están representadas por los objetos HxCFunc y las variables locales por los objetos HxLvar:

.. code-block:: pycon

root@kitploit:~
>>> HxCFunc.from_addr() # HxCFunc represents a decompiled function
<bip.hexrays.hx_cfunc.HxCFunc object at 0x00000278AE80C860>
>>> hf = BipFunction().hxfunc # accessible from a "normal function"
>>> hex(hf.ea) # address of the function
0x1800d2ff0L
>>> hf.args # list of the arguments as HxLvar objects
[<bip.hexrays.hx_lvar.HxLvar object at 0x00000278AFDAACF8>]
>>> hf.lvars # list of all local variables (including args)
[<bip.hexrays.hx_lvar.HxLvar object at 0x00000278AFDAAB70>, ..., <bip.hexrays.hx_lvar.HxLvar object at 0x00000278AFDAF4E0>]
>>> lv = hf.lvars[0] # getting the first one
>>> lv
LVAR(name=a1, size=8, type=<bip.base.biptype.BTypeInt object at 0x00000278AFDAAFD0>)
>>> lv.name # getting name of lvar
a1
>>> lv.is_arg # is this variable an argument ?
True
>>> lv.name = "thisisthefirstarg" # changing name of the lvar
>>> lv
>>> lv.type = BipType.from_c("void *") # changing the type
>>> lv.comment = "new comment" # adding a comment
>>> lv.size # getting the size
8

CNode / Visitantes~~~~~~~~~~~~~~~~

Hexrays allows to manipulate the AST it produces, this is a particularly useful feature as it allows to make static analysis at a way higher level. Bip defines CNode which represents a node of the AST, each type of node is represented by a subclass of CNode. All types of node have child nodes except CNodeExprFinal which are the leaf of the AST. Two main types of nodes exist CNodeExpr (expressions) and CNodeStmt (statements). Statements correspond to the C Statements: if, while, ... , expressions are everything else. Statements can have children statements or expressions while expressions can only have expression children.

A list of all the different types of nodes and more details on what they do and how to write a visitor is available in the documentation <https://synacktiv.github.io/bip/build/html/hexrays/astnodes.html#ast-node-types>_.

Directly accessing the nodes:

.. code-block:: pycon

root@kitploit:~
>>> hf = HxCFunc.from_addr() # get the HxCFunc
>>> rn = hf.root_node # accessing the root node of the function
>>> rn # root node is always a CNodeStmtBlock
CNodeStmtBlock(ea=0x1800D3006, stmt_children=[<bip.hexrays.cnode.CNodeStmtExpr object at 0x00000278AFDAADD8>, ..., <bip.hexrays.cnode.CNodeStmtReturn object at 0x00000278B16355F8>])
>>> hex(rn.ea) # address of the root node, after the function prolog
0x1800d3006L
>>> rn.has_parent # root node does not have parent
False
>>> rn.expr_children # this node does not have expression statements
[]
>>> ste = rn.stmt_children[0] # getting the first statement children
>>> ste # CNodeStmtExpr contain one child expression
CNodeStmtExpr(ea=0x1800D3006, value=CNodeExprAsg(ea=0x1800D3006, ops=[<bip.hexrays.cnode.CNodeExprVar object at 0x00000278AFDAADD8>, <bip.hexrays.cnode.CNodeExprVar object at 0x00000278B1637080>]))
>>> ste.parent # the parent is the root node
CNodeStmtBlock(ea=0x1800D3006, stmt_children=[<bip.hexrays.cnode.CNodeStmtExpr object at 0x00000278B1637048>, ..., <bip.hexrays.cnode.CNodeStmtReturn object at 0x00000278B16376D8>])
>>> a = ste.value # getting the expression of the node
>>> a # Asg is an assignement
CNodeExprAsg(ea=0x1800D3006, ops=[<bip.hexrays.cnode.CNodeExprVar object at 0x00000278AFDAADD8>, <bip.hexrays.cnode.CNodeExprVar object at 0x00000278B1637080>])
>>> a.first_op # first operand of the assignement is a lvar, lvar are leaf
CNodeExprVar(ea=0xFFFFFFFFFFFFFFFF, value=1)
>>> a.first_op.lvar # get the lvar object
LVAR(name=v1, size=8, type=<bip.base.biptype.BTypeInt object at 0x00000278B16390B8>)
>>> a.ops # list all operands of the expression
[<bip.hexrays.cnode.CNodeExprVar object at 0x00000278AFDAADD8>, <bip.hexrays.cnode.CNodeExprVar object at 0x00000278B1639080>]
>>> a.ops[1] # getting the second operand, also a lvar
CNodeExprVar(ea=0xFFFFFFFFFFFFFFFF, value=0)
>>> hex(a.ops[1].closest_ea) # lvar have no position in the ASM, but possible to take the one of the parents
0x1800d3006L

The previous code show how to get a value and manipulate nodes quickly. To do an analysis it is easier to use visitors on the complete function. HxCFunc.visit_cnode allows to visit all the nodes in a function with a callback, HxCFunc.visit_cnode_filterlist allows to visit only nodes of a certain type by passing a list of the node classes.

This script is an example to visit a function and get the format string passed to a printk function. It locates the call to printk, gets the address of the first argument, gets the string and adds a comment in both hexrays and the assembly:

.. code-block:: python

root@kitploit:~
from bip import *

"""
    Search for all call to printk, if possible gets the string and adds
    it in comments at the level of the call.
"""

def is_call_to_printk(cn):
    """
        Check if the node object represent a call to the function ``printk``.

        :param cn: A :class:`CNodeExprCall` object.
        :return: True if it is a call to printk, False otherwise
    """
    f = cn.caller_func
    return f is not None and f.name == "printk"

def visit_call_printk(cn):
    """
        Visitor for call node which will check if a node is a call to
        ``printk`` and add the string in comment if possible.

        :param cn: A :class:`CNodeExprCall` object.
    """
    # check if it calls to printk
    # For more perf. we would want to use xref to printk and checks of
    #   the address of the node
    if not is_call_to_printk(cn): # not a call to printk: ignore
        return
    if cn.number_args < 1: # not enough args
        print("Not enough args at 0x{:X}".format(cn.closest_ea))
        return
    cnr = cn.get_arg(0).ignore_cast # get the arg
    # if we have a ref (&global) we want the object under
    if isinstance(cnr, CNodeExprRef):
        cnr = cnr.ops[0].ignore_cast
    # if this is not a global object we ignore it
    if not isinstance(cnr, CNodeExprObj):
        print("Not an object at 0x{:X}".format(cn.closest_ea))
        return
    ea = cnr.value # get the address of the object
    s = None
    try:
        s = BipData.get_cstring(ea + 2) # get the string
    except Exception:
        pass
    if s is None or s == "":
        print("Invalid string at 0x{:X}".format(cn.closest_ea))
        return
    s = s.strip() # remove \n
    # add comment both in hexrays and in asm view
    cn.hxcfunc.add_cmt(cn.closest_ea, s)
    GetElt(cn.closest_ea).comment = s

# Final function which takes the address of a function and comments the call
#   to printk
def printk_handler(eafunc):
    hf = HxCFunc.from_addr(eafunc) # get the hexrays function
    hf.visit_cnode_filterlist(visit_call_printk, [CNodeExprCall]) # visit only the call nodes

While visitors are convenient (and "fast"), Bip also exposes methods to directly get the CNode objects as a list. The methods HxCFunc.get_cnode_filter and HxCFunc.get_cnode_filter_type allow to avoid having a visitor function and make it easier to manipulate the hexrays API. It is also worth noting that all visitors functions provided by HxCFunc objects are also available directly in CNode objects to visit only a sub-tree of the full AST.

Plugins

Plugins using Bip should all inherit from the class BipPlugin. Those plugins are different from the IDA plugins and are loaded and called by the BipPluginManager. Each plugin is identified by its class name and those should be unique. Bip can be used with standard plugin but most of the bip.gui implementation is linked to the use of BipPlugin. For more information about plugins and internals see the documentation <https://synacktiv.github.io/bip/build/html/gui/plugin.html#gui-plugins>_.

Here is a simple plugin example:

.. code-block:: python

root@kitploit:~
from bip.gui import * # BipPlugin is defined in the bip.gui module

class ExPlugin(BipPlugin):
    # inherit from BipPlugin, all plugin should be instantiated only once
    # this should be done by the plugin manager, not "by hand"

    @classmethod
    def to_load(cls): # allow to test if the plugin apply, this MUST be a classmethod
        return True # always loading

    @shortcut("Ctrl-H") # add a shortcut as a decorator, will call the method below
    @shortcut("Ctrl-5") # add an other one
    @menu("Bip/MyPluginExample/", "ExPlugin Action!") # add a menu entry named "ExPlugin Action!", default is the method name
    def action_with_shortcut(self):
        print(self) # this is the ExPlugin object
        print("In ExPlugin action !")# code here

bpm = get_plugin_manager() # get the BipPluginManager object
bpm.addld_plugin("ExPlugin", ExPlugin) # ask the BipPluginManager to load the plugin
# plugins in ``bipplugin`` folder will be loaded automatically and do not need those lines

The menu decorator will automatically create the MyPluginExample menu entry in the Bip top level menu entry (which is created by the BipPluginManager), creating an entry in the Edit/Plugins/ directory may not work because of how the entry of this submenu are created by IDA.

A plugin can expose methods which another plugin wants to call or directly from the console. A plugin should not be directly instantiated, it is the BipPluginManager which is in charge of loading it. To get a BipPlugin object, it should be requested to the plugin manager:

.. code-block:: python

root@kitploit:~
from bip.gui import *
bpm = get_plugin_manager() # get the BipPluginManager object
bpm
# <bip.gui.pluginmanager.BipPluginManager object at 0x000001EFE42D68D0>
tp = bpm["TstPlugin"] # get the plugin object name TstPlugin
tp # can also be recuperated by passing directly the class
# <__plugins__tst_plg.TstPlugin object at 0x000001EFE42D69B0>
tp.hello() # calling a method of TstPlugin
# hello

For the previous example with printk we could write the following plugin:

.. code-block:: python

root@kitploit:~
class PrintkComs(BipPlugin):

    def printk_handler(self, eafunc):
        """
            Comment all call to printk in a function with the format string
            pass to the printk. Comments are added in both the hexrays and ASM
            view. Works only if the first argument is a global.

            :param eafunc: The addess of the function in which to add the
                comment.
        """
        try:
            hf = HxCFunc.from_addr(eafunc) # get hexray view of the func
        except Exception:
            print("Fail getting the decompile view for function at 0x{:X}".format(eafunc))
            return
        hf.visit_cnode_filterlist(visit_call_printk, [CNodeExprCall]) # visit only on the call

    @shortcut("Ctrl-H")
    @menu("Bip/PrintkCom/", "Comment printk in current function")
    def printk_current(self):
        """
            Add comment for the current function.
        """
        self.printk_handler(Here())

    @menu("Bip/PrintkCom/", "Comment all printk")
    def printk_all(self):
        """
            Add comment for the all the functions in the IDB.
        """
        # get the function which call printk
        f = BipFunction.get_by_name("printk")
        if f is None:
            print("No function named printk")
            return
        for fu in f.callers:
            print("Renaming for {}".format(fu))
            self.printk_handler(fu.ea)

Similar projects

  • sark <https://sark.readthedocs.io/en/latest/>_: "an object-oriented scripting layer written on top of IDAPython".
  • ida-minsc <https://github.com/arizvisa/ida-minsc>_: "a plugin for IDA Pro that assists a user with scripting the IDAPython plugin that is bundled with the disassembler".
  • FIDL <https://github.com/fireeye/FIDL>_: "FLARE IDA Decompiler Library"

Thanks

Some people to thanks:

  • saph <https://twitter.com/clementberthaux>_: for starting this project.
  • hakril <https://twitter.com/hakril>_: for the inspiration for the project and his insights on designing it.
Descargar herramienta