Python plugins

At first, to be able to write a plugins in Python for radare2 you need to install r2lang plugin: r2pm -i lang-python. Note - in the following examples there are missing functions of the actual decoding for the sake of readability!

For this you need to do this:

  1. import r2lang and from r2lang import R (for constants)
  2. Make a function with 2 subfunctions - assemble and disassemble and returning plugin structure - for RAsm plugin
  1. def mycpu(a):
  2. def assemble(s):
  3. return [1, 2, 3, 4]
  4. def disassemble(memview, addr):
  5. try:
  6. opcode = get_opcode(memview) # https://docs.python.org/3/library/stdtypes.html#memoryview
  7. opstr = optbl[opcode][1]
  8. return [4, opstr]
  9. except:
  10. return [4, "unknown"]
  1. This structure should contain a pointers to these 2 functions - assemble and disassemble
  1. return {
  2. "name" : "mycpu",
  3. "arch" : "mycpu",
  4. "bits" : 32,
  5. "endian" : R.R_SYS_ENDIAN_LITTLE,
  6. "license" : "GPL",
  7. "desc" : "MYCPU disasm",
  8. "assemble" : assemble,
  9. "disassemble" : disassemble,
  10. }
  1. Make a function with 2 subfunctions - set_reg_profile and op and returning plugin structure - for RAnal plugin
  1. def mycpu_anal(a):
  2. def set_reg_profile():
  3. profile = "=PC pc\n" + \
  4. "=SP sp\n" + \
  5. "gpr r0 .32 0 0\n" + \
  6. "gpr r1 .32 4 0\n" + \
  7. "gpr r2 .32 8 0\n" + \
  8. "gpr r3 .32 12 0\n" + \
  9. "gpr r4 .32 16 0\n" + \
  10. "gpr r5 .32 20 0\n" + \
  11. "gpr sp .32 24 0\n" + \
  12. "gpr pc .32 28 0\n"
  13. return profile
  14. def op(memview, pc):
  15. analop = {
  16. "type" : R.R_ANAL_OP_TYPE_NULL,
  17. "cycles" : 0,
  18. "stackop" : 0,
  19. "stackptr" : 0,
  20. "ptr" : -1,
  21. "jump" : -1,
  22. "addr" : 0,
  23. "eob" : False,
  24. "esil" : "",
  25. }
  26. try:
  27. opcode = get_opcode(memview) # https://docs.python.org/3/library/stdtypes.html#memoryview
  28. esilstr = optbl[opcode][2]
  29. if optbl[opcode][0] == "J": # it's jump
  30. analop["type"] = R.R_ANAL_OP_TYPE_JMP
  31. analop["jump"] = decode_jump(opcode, j_mask)
  32. esilstr = jump_esil(esilstr, opcode, j_mask)
  33. except:
  34. result = analop
  35. # Don't forget to return proper instruction size!
  36. return [4, result]
  1. This structure should contain a pointers to these 2 functions - set_reg_profile and op
  1. return {
  2. "name" : "mycpu",
  3. "arch" : "mycpu",
  4. "bits" : 32,
  5. "license" : "GPL",
  6. "desc" : "MYCPU anal",
  7. "esil" : 1,
  8. "set_reg_profile" : set_reg_profile,
  9. "op" : op,
  10. }
  1. Then register those using r2lang.plugin("asm") and r2lang.plugin("anal") respectively
  1. print("Registering MYCPU disasm plugin...")
  2. print(r2lang.plugin("asm", mycpu))
  3. print("Registering MYCPU analysis plugin...")
  4. print(r2lang.plugin("anal", mycpu_anal))

You can combine everything in one file and load it using -i option:

  1. r2 -I mycpu.py some_file.bin

Or you can load it from the r2 shell: #!python mycpu.py

See also:

Implementing new format plugin in Python

Note - in the following examples there are missing functions of the actual decoding for the sake of readability!

For this you need to do this:

  1. import r2lang

  2. Make a function with subfunctions:

    • load
    • load_bytes
    • destroy
    • check_bytes
    • baddr
    • entries
    • sections
    • imports
    • relocs
    • binsym
    • info

    and returning plugin structure - for RAsm plugin

  1. def le_format(a):
  2. def load(binf):
  3. return [0]
  4. def check_bytes(buf):
  5. try:
  6. if buf[0] == 77 and buf[1] == 90:
  7. lx_off, = struct.unpack("<I", buf[0x3c:0x40])
  8. if buf[lx_off] == 76 and buf[lx_off+1] == 88:
  9. return [1]
  10. return [0]
  11. except:
  12. return [0]

and so on. Please be sure of the parameters for each function and format of returns. Note, that functions entries, sections, imports, relocs returns a list of special formed dictionaries - each with a different type. Other functions return just a list of numerical values, even if single element one. There is a special function, which returns information about the file - info:

  1. def info(binf):
  2. return [{
  3. "type" : "le",
  4. "bclass" : "le",
  5. "rclass" : "le",
  6. "os" : "OS/2",
  7. "subsystem" : "CLI",
  8. "machine" : "IBM",
  9. "arch" : "x86",
  10. "has_va" : 0,
  11. "bits" : 32,
  12. "big_endian" : 0,
  13. "dbg_info" : 0,
  14. }]
  1. This structure should contain a pointers to the most important functions like check_bytes, load and load_bytes, entries, relocs, imports.
  1. return {
  2. "name" : "le",
  3. "desc" : "OS/2 LE/LX format",
  4. "license" : "GPL",
  5. "load" : load,
  6. "load_bytes" : load_bytes,
  7. "destroy" : destroy,
  8. "check_bytes" : check_bytes,
  9. "baddr" : baddr,
  10. "entries" : entries,
  11. "sections" : sections,
  12. "imports" : imports,
  13. "symbols" : symbols,
  14. "relocs" : relocs,
  15. "binsym" : binsym,
  16. "info" : info,
  17. }
  1. Then you need to register it as a file format plugin:
  1. print("Registering OS/2 LE/LX plugin...")
  2. print(r2lang.plugin("bin", le_format))