
واجهة برمجة تطبيقات بايثون كائنية التوجه لتبسيط التفاعل مع IDA للهندسة العكسية، مما يتيح تطوير الإضافات وأتمتة تحليلات التفكيك.
Bip
Bip هو مشروع يهدف إلى تبسيط استخدام python للتفاعل مع IDA. أهدافه الرئيسية هي تسهيل استخدام python في وحدة التحكم التفاعلية لـ IDA وكتابة الإضافات. بشكل أكثر عمومية، الهدف هو أتمتة المهام المتكررة التي تتم عبر واجهة برمجة تطبيقات python. كما تم تطوير Bip لتوفير واجهة برمجة تطبيقات أكثر توجهاً نحو الكائنات، وقريبة من أسلوب python، وتوثيق حقيقي.
هذا الكود غير مكتمل، وما زالت العديد من الميزات مفقودة. يتم تحديد أولويات التطوير بناءً على ما يطلبه الأشخاص وما يستخدمه المطورون، لذا لا تتردد في تقديم PR أو Feature Request أو Issues (بما في ذلك المتعلقة بالتوثيق).
التوثيق متاح بصيغة RST (ويمكن تجميعه باستخدام sphinx) في مجلد docs/، وهو متاح أيضاً على الإنترنت <https://synacktiv.github.io/bip/build/html/index.html>_.
تم اختبار هذا التثبيت على Windows وLinux فقط: python install.py.
من الممكن استخدام وسيط اختياري --dest للتثبيت في مجلد معين:
.. code-block:: none
usage: install.py [-h] [--dest DEST]
optional arguments:
-h, --help show this help message and exit
--dest DEST Destination folder where to install Bip
لا يقوم هذا المثبت بتثبيت أي إضافات افتراضياً، بل يثبت فقط نواة Bip. افتراضياً، يكون مجلد الوجهة هو المستخدم محلياً بواسطة IDA (%APPDATA%\Hex-Rays\IDA Pro\ لنظام Windows و$HOME/.idapro لنظامي Linux وMacOSX).
تهدف هذه النظرة العامة إلى إظهار كيفية تنفيذ العمليات الأكثر شيوعاً، وهي بعيدة كل البعد عن الاكتمال. جميع الدوال والكائنات في Bip موثقة باستخدام doc string، لذا فقط استخدم help(BipClass) وhelp(obj.bipmethod) للحصول على التوثيق في الصدفة الخاصة بك.
تحتوي الوحدة bip.base على معظم الميزات الأساسية للتفاعل مع IDA. عملياً، هذا هو بشكل أساسي جزء المفكك في IDA، ويشمل: التعامل مع التعليمات، والدوال، والكتل الأساسية، والمعاملات، والبيانات، والمراجع المتبادلة (xrefs)، والهياكل، والأنواع، ...
التعليمات / المعاملات~~~~~~~~~~~~~~~~~~~~~~~
The classes bip.base.BipInstr and bip.base.BipOperand:
.. code-block:: pycon
>>> 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
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
~~~~~~~
~~~~~~~