about summary refs log tree commit diff stats
path: root/miasm2/jitter/jitcore_python.py
blob: b71bd1385ffe449a011d4fb681033b8a4a717ff1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
import miasm2.jitter.jitcore as jitcore
import miasm2.expression.expression as m2_expr
import miasm2.jitter.csts as csts
from miasm2.expression.simplifications import expr_simp
from miasm2.ir.symbexec import symbexec


################################################################################
#                      Util methods for Python jitter                          #
################################################################################

def update_cpu_from_engine(cpu, exec_engine):
    """Updates @cpu instance according to new CPU values
    @cpu: JitCpu instance
    @exec_engine: symbexec instance"""

    for symbol in exec_engine.symbols:
        if isinstance(symbol, m2_expr.ExprId):
            if hasattr(cpu, symbol.name):
                value = exec_engine.symbols.symbols_id[symbol]
                if not isinstance(value, m2_expr.ExprInt):
                    raise ValueError("A simplification is missing: %s" % value)

                setattr(cpu, symbol.name, value.arg.arg)
        else:
            raise NotImplementedError("Type not handled: %s" % symbol)


def update_engine_from_cpu(cpu, exec_engine):
    """Updates CPU values according to @cpu instance
    @cpu: JitCpu instance
    @exec_engine: symbexec instance"""

    for symbol in exec_engine.symbols:
        if isinstance(symbol, m2_expr.ExprId):
            if hasattr(cpu, symbol.name):
                value = m2_expr.ExprInt_fromsize(symbol.size,
                                                 getattr(cpu, symbol.name))
                exec_engine.symbols.symbols_id[symbol] = value
        else:
            raise NotImplementedError("Type not handled: %s" % symbol)


################################################################################
#                              Python jitter Core                              #
################################################################################


class JitCore_Python(jitcore.JitCore):
    "JiT management, using Miasm2 Symbol Execution engine as backend"

    def __init__(self, ir_arch, bs=None):
        super(JitCore_Python, self).__init__(ir_arch, bs)
        self.symbexec = None
        self.ir_arch = ir_arch

    def load(self):
        "Preload symbols according to current architecture"

        symbols_init =  {}
        for r in self.ir_arch.arch.regs.all_regs_ids_no_alias:
            symbols_init[r] = self.ir_arch.arch.regs.regs_init[r]

        self.symbexec = symbexec(self.ir_arch, symbols_init,
                                 func_read = self.func_read,
                                 func_write = self.func_write)

    def func_read(self, expr_mem):
        """Memory read wrapper for symbolic execution
        @expr_mem: ExprMem"""

        addr = expr_mem.arg.arg.arg
        size = expr_mem.size / 8
        value = self.vmmngr.vm_get_mem(addr, size)

        return m2_expr.ExprInt_fromsize(expr_mem.size,
                                        int(value[::-1].encode("hex"), 16))

    def func_write(self, symb_exec, dest, data, mem_cache):
        """Memory read wrapper for symbolic execution
        @symb_exec: symbexec instance
        @dest: ExprMem instance
        @data: Expr instance
        @mem_cache: dict"""

        # Get the content to write
        data = expr_simp(data)
        if not isinstance(data, m2_expr.ExprInt):
            raise NotImplementedError("A simplification is missing: %s" % data)
        to_write = data.arg.arg

        # Format information
        addr = dest.arg.arg.arg
        size = data.size / 8
        content = hex(to_write).replace("0x", "").replace("L", "")
        content = "0" * (size * 2 - len(content)) + content
        content = content.decode("hex")[::-1]

        # Write in VmMngr context
        self.vmmngr.vm_set_mem(addr, content)

    def jitirblocs(self, label, irblocs):
        """Create a python function corresponding to an irblocs' group.
        @label: the label of the irblocs
        @irblocs: a gorup of irblocs
        """

        def myfunc(cpu, vmmngr):
            """Execute the function according to cpu and vmmngr states
            @cpu: JitCpu instance
            @vm: VmMngr instance
            """

            # Keep current location in irblocs
            cur_label = label
            loop = True

            # Required to detect new instructions
            offsets_jitted = set()

            # Get exec engine
            exec_engine = self.symbexec

            # For each irbloc inside irblocs
            while loop is True:

                # Get the current bloc
                loop = False
                for irb in irblocs:
                    if irb.label == cur_label:
                        loop = True
                        break

                # Irblocs must end with returning an ExprInt instance
                assert(loop is not False)

                # Refresh CPU values according to @cpu instance
                update_engine_from_cpu(cpu, exec_engine)

                # Execute current ir bloc
                for ir, line in zip(irb.irs, irb.lines):

                    # For each new instruction (in assembly)
                    if line.offset not in offsets_jitted:
                        offsets_jitted.add(line.offset)

                        # Log registers values
                        if self.log_regs:
                            update_cpu_from_engine(cpu, exec_engine)
                            cpu.vm_dump_gpregs()

                        # Log instruction
                        if self.log_mn:
                            print "%08x %s" % (line.offset, line)

                        # Check for memory exception
                        if (vmmngr.vm_get_exception() != 0):
                            update_cpu_from_engine(cpu, exec_engine)
                            return line.offset

                    # Eval current instruction (in IR)
                    exec_engine.eval_ir(ir)

                    # Check for memory exception which do not update PC
                    if (vmmngr.vm_get_exception() & csts.EXCEPT_DO_NOT_UPDATE_PC != 0):
                        update_cpu_from_engine(cpu, exec_engine)
                        return line.offset

                # Get next bloc address
                ad = expr_simp(exec_engine.eval_expr(self.ir_arch.IRDst))

                # Updates @cpu instance according to new CPU values
                update_cpu_from_engine(cpu, exec_engine)

                # Manage resulting address
                if isinstance(ad, m2_expr.ExprInt):
                    return ad.arg.arg
                elif isinstance(ad, m2_expr.ExprId):
                    cur_label = ad.name
                else:
                    raise NotImplementedError("Type not handled: %s" % ad)

        # Associate myfunc with current label
        self.lbl2jitbloc[label.offset] = myfunc

    def jit_call(self, label, cpu, vmmngr):
        """Call the function label with cpu and vmmngr states
        @label: function's label
        @cpu: JitCpu instance
        @vm: VmMngr instance
        """

        # Get Python function corresponding to @label
        fc_ptr = self.lbl2jitbloc[label]

        # Update memory state
        self.vmmngr = vmmngr

        # Execute the function
        return fc_ptr(cpu, vmmngr)