# Python插件

在用python写r2插件之前，需要安装一个r2lang的插件 `r2pm -i lang-python` 。 注意 - 为了可读性，下面的例子中省略了实际的解码函数。

编写python插件的流程如下： 1. `import r2lang` and `from r2lang import R` (for constants) 2. 创建一个函数，其包含两个子函数 - `assemble` 和 `disassemble` 并返回一个一个plugin struct - 用于RAsm插件

```python
def mycpu(a):
    def assemble(s):
        return [1, 2, 3, 4]

    def disassemble(memview, addr):
        try:
            opcode = get_opcode(memview) # https://docs.python.org/3/library/stdtypes.html#memoryview
            opstr = optbl[opcode][1]
            return [4, opstr]
        except:
            return [4, "unknown"]
```

1. 该结构体需要包含指向这两个函数的指针 - `assemble`和`disassemble`

```python
    return {
            "name" : "mycpu",
            "arch" : "mycpu",
            "bits" : 32,
            "endian" : R.R_SYS_ENDIAN_LITTLE,
            "license" : "GPL",
            "desc" : "MYCPU disasm",
            "assemble" : assemble,
            "disassemble" : disassemble,
    }
```

1. 创建一个函数，其包含两个子函数 - `set_reg_profile` 和 `op`， 并返回一个plugin struct - 用于RAnal插件

   \`\`\`python def mycpu\_anal(a): def set\_reg\_profile(): profile = "=PC pc\n" +  "=SP sp\n" +  "gpr r0 .32 0 0\n" +  "gpr r1 .32 4 0\n" +  "gpr r2 .32 8 0\n" +  "gpr r3 .32 12 0\n" +  "gpr r4 .32 16 0\n" +  "gpr r5 .32 20 0\n" +  "gpr sp .32 24 0\n" +  "gpr pc .32 28 0\n" return profile

   def op(memview, pc): analop = { "type" : R.R\_ANAL\_OP\_TYPE\_NULL, "cycles" : 0, "stackop" : 0, "stackptr" : 0, "ptr" : -1, "jump" : -1, "addr" : 0, "eob" : False, "esil" : "", } try: opcode = get\_opcode(memview) # <https://docs.python.org/3/library/stdtypes.html#memoryview> esilstr = optbl\[opcode]\[2] if optbl\[opcode]\[0] == "J": # it's jump analop\["type"] = R.R\_ANAL\_OP\_TYPE\_JMP analop\["jump"] = decode\_jump(opcode, j\_mask) esilstr = jump\_esil(esilstr, opcode, j\_mask)

   ```
    except:
        result = analop
    # Don't forget to return proper instruction size!
    return [4, result]
   ```

````
5. 该结构体需要包含指向这两个函数的指针 - `set_reg_profile`和`op`

```python
    return {
            "name" : "mycpu",
            "arch" : "mycpu",
            "bits" : 32,
            "license" : "GPL",
            "desc" : "MYCPU anal",
            "esil" : 1,
            "set_reg_profile" : set_reg_profile,
            "op" : op,
    }
````

1. 分别用`r2lang.plugin("asm")` and `r2lang.plugin("anal")`进行注册：

```python
print("Registering MYCPU disasm plugin...")
print(r2lang.plugin("asm", mycpu))
print("Registering MYCPU analysis plugin...")
print(r2lang.plugin("anal", mycpu_anal))
```

可以把上面这些写在一个文件里，然后用`-i`选项加载就行了：

```
r2 -I mycpu.py some_file.bin
```

或者可以在r2 shell里进行加载： `#!python mycpu.py`

参见:

* [Python](https://github.com/radareorg/radare2-bindings/blob/master/libr/lang/p/test-py-asm.py)
* [Javascript](https://github.com/radareorg/radare2-bindings/blob/master/libr/lang/p/dukasm.js)

## 用python实现一个文件格式插件

注意 - 为了可读性，下面的例子中省略了实际的解码函数。

步骤: 1. `import r2lang` 2. 创建一个函数，其包含下面这些子函数:

* `load`
* `load_bytes`
* `destroy`
* `check_bytes`
* `baddr`
* `entries`
* `sections`
* `imports`
* `relocs`
* `binsym`
* `info`

  并返回一个plugin struct - 用于 RAsm plugin：

  ```python
  def le_format(a):
  def load(binf):
     return [0]

  def check_bytes(buf):
     try:
         if buf[0] == 77 and buf[1] == 90:
             lx_off, = struct.unpack("<I", buf[0x3c:0x40])
             if buf[lx_off] == 76 and buf[lx_off+1] == 88:
                 return [1]
         return [0]
     except:
         return [0]
  ```

  诸如此类。 注意检查每个函数的参数和返回值的格式，`entries`，`sections`，`imports`，`relocs`都返回一个包含字典的列表，但不同列表中包含的字典类型是不同的。 其余函数的返回值只是一个包含数值的列表，甚至可能只包含一个元素。 下面是一个特殊的函数，其返回文件信息结构 - `info`：

  ```python
  def info(binf):
     return [{
             "type" : "le",
             "bclass" : "le",
             "rclass" : "le",
             "os" : "OS/2",
             "subsystem" : "CLI",
             "machine" : "IBM",
             "arch" : "x86",
             "has_va" : 0,
             "bits" : 32,
             "big_endian" : 0,
             "dbg_info" : 0,
             }]
  ```

1. 返回的plugin struct需要包含大部分的核心函数指针，比如`check_bytes`, `load`和`load-bytes`, `entries`, `relocs`, `imports`。

```python
    return {
            "name" : "le",
            "desc" : "OS/2 LE/LX format",
            "license" : "GPL",
            "load" : load,
            "load_bytes" : load_bytes,
            "destroy" : destroy,
            "check_bytes" : check_bytes,
            "baddr" : baddr,
            "entries" : entries,
            "sections" : sections,
            "imports" : imports,
            "symbols" : symbols,
            "relocs" : relocs,
            "binsym" : binsym,
            "info" : info,
    }
```

1. 作为为文件格式插件进行注册:

```python
print("Registering OS/2 LE/LX plugin...")
print(r2lang.plugin("bin", le_format))
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://heersin.gitbook.io/radare2/intro-10/python.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
