├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── pyasmjit ├── __init__.py ├── main.py └── pyasmjit.c ├── setup.cfg ├── setup.py └── tests ├── __init__.py └── pyasmjit ├── __init__.py ├── test_arm_jit.py ├── test_x86_64_jit.py └── test_x86_jit.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | 47 | # Translations 48 | *.mo 49 | *.pot 50 | 51 | # Django stuff: 52 | *.log 53 | 54 | # Sphinx documentation 55 | docs/_build/ 56 | 57 | # PyBuilder 58 | target/ 59 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | ## [Unreleased] 6 | 7 | ## [0.3.0] - 2019-11-05 8 | ### Added 9 | - Add PyPI support. 10 | - Add x86 support by @adrianherrera. 11 | - Fix warnings thrown in function `x86_run` and `arm_run` when compiling `pyasmjit.c` 12 | 13 | ### Changed 14 | - Rename x86 JIT to x86_64 by @adrianherrera. 15 | - Improvements to `setup.py` by @adrianherrera. 16 | - General clean-up of `pyasmjit` module by @adrianherrera. 17 | - Updated ARM test by @adrianherrera. 18 | - Refactor test code to make use of Python's unit test module by @adrianherrera. 19 | 20 | ### Fixed 21 | - Fix Python 3 compatibility issues. 22 | - Fix x86 tests by @adrianherrera. 23 | 24 | ## [0.2] - 2015-04-06 25 | ### Added 26 | - Memory allocation mechanism (`alloc`/`free` style). 27 | - Add support for the ARM architecture (32 bits). 28 | 29 | ### Fixed 30 | - Fix context saving for long ints. 31 | - Fix missing registers when loading and saving context. 32 | 33 | ## 0.1 - 2014-11-19 34 | ### Added 35 | - First release. 36 | 37 | [Unreleased]: https://github.com/programa-stic/pyasmjit/compare/v0.3.0...master 38 | [0.3.0]: https://github.com/programa-stic/pyasmjit/compare/v0.2...v0.3.0 39 | [0.2]: https://github.com/programa-stic/pyasmjit/compare/v0.1...v0.2 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, Fundación Dr. Manuel Sadosky 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PyAsmJIT 2 | 3 | *PyAsmJIT* is a Python package for x86/x86_64/ARMv7 assembly code generation 4 | and execution. 5 | 6 | This package was developed as part of the BARF project 7 | (https://github.com/programa-stic/barf-project) in order to test instruction 8 | translation from x/86/x86_64/ARM to REIL. The main idea is to be able to run 9 | fragments of code natively. Then, the same fragment is translated to REIL and 10 | executed in a REIL VM. Finally, both final contexts (the one obtained through 11 | native execution and the one from emulation) are compare for differences. 12 | 13 | # Installation 14 | 15 | The following command installs the package: 16 | 17 | ```bash 18 | $ python setup.py install 19 | ``` 20 | 21 | # Dependecies 22 | 23 | * [NASM] : the Netwide Assembler, a portable 80x86 assembler 24 | 25 | # Quickstart 26 | 27 | The following extract shows how to execute on-the-fly a fragment of x86_64 28 | assembly code. 29 | 30 | ```python 31 | import pyasmjit 32 | 33 | code = """\ 34 | add rax, rbx 35 | """ 36 | 37 | context_in = { 38 | 'rax' : 0x1, 39 | 'rbx' : 0x2, 40 | 'rcx' : 0x1, 41 | 'rdx' : 0x1, 42 | 'rdi' : 0x1, 43 | 'rsi' : 0x1, 44 | } 45 | 46 | print code 47 | print context_in 48 | 49 | rv, context_out = pyasmjit.x86_execute(code, context_in) 50 | 51 | print context_out 52 | ``` 53 | And for ARMv7: 54 | 55 | ```python 56 | import pyasmjit 57 | 58 | code = """\ 59 | 60 | movs r8, r2, lsl #31 61 | mov r7, #0x7FFFFFFF 62 | mov r8, #0x7FFFFFFF 63 | adds r7, r7, r8 64 | #subs r10, r10, #0xFFFFFFFF 65 | """ 66 | 67 | context_in = { 68 | 'r0' : 0x0, 69 | 'r1' : 0x1, 70 | 'r2' : 0x2, 71 | 'r3' : 0x3, 72 | 'r4' : 0x4, 73 | 'r5' : 0x5, 74 | 'r6' : 0x6, 75 | 'r7' : 0x7, 76 | 'r8' : 0x8, 77 | 'r9' : 0x9, 78 | 'r10' : 0xa, 79 | 'r11' : 0xb, 80 | 'r12' : 0xc, 81 | 'apsr' : 0x0, 82 | } 83 | 84 | print code 85 | print context_in 86 | 87 | rv, context_out, mem = pyasmjit.arm_execute(code, context_in) 88 | 89 | print context_out 90 | ``` 91 | 92 | # Overview 93 | 94 | The inner workings of the package is very simple. PyAsmJIT communicates with 95 | *nasm* using the ``subprocess`` package. Once the machine code is generated, it 96 | is place in a memory location previously reserved with the proper permissions 97 | flags. Then, the code is executed as a thread. 98 | 99 | # Limitations 100 | 101 | Currently: 102 | 103 | * It does not handle memory operations 104 | * It only works with x86, x86_64 and ARMv7 105 | 106 | # License 107 | 108 | The BSD 2-Clause License. For more information, see [LICENSE](./LICENSE). 109 | 110 | [NASM]: http://nasm.us/ 111 | -------------------------------------------------------------------------------- /pyasmjit/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014, Fundacion Dr. Manuel Sadosky 2 | # All rights reserved. 3 | 4 | # Redistribution and use in source and binary forms, with or without 5 | # modification, are permitted provided that the following conditions are met: 6 | 7 | # 1. Redistributions of source code must retain the above copyright notice, this 8 | # list of conditions and the following disclaimer. 9 | 10 | # 2. Redistributions in binary form must reproduce the above copyright notice, 11 | # this list of conditions and the following disclaimer in the documentation 12 | # and/or other materials provided with the distribution. 13 | 14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | 25 | from .main import arm_alloc 26 | from .main import arm_execute 27 | from .main import arm_free 28 | from .main import x86_64_execute 29 | from .main import x86_execute 30 | -------------------------------------------------------------------------------- /pyasmjit/main.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014, Fundacion Dr. Manuel Sadosky 2 | # All rights reserved. 3 | 4 | # Redistribution and use in source and binary forms, with or without 5 | # modification, are permitted provided that the following conditions are met: 6 | 7 | # 1. Redistributions of source code must retain the above copyright notice, this 8 | # list of conditions and the following disclaimer. 9 | 10 | # 2. Redistributions in binary form must reproduce the above copyright notice, 11 | # this list of conditions and the following disclaimer in the documentation 12 | # and/or other materials provided with the distribution. 13 | 14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | 25 | from __future__ import absolute_import 26 | 27 | import os 28 | import subprocess 29 | import tempfile 30 | 31 | from builtins import bytes 32 | 33 | from . import pyasmjit 34 | 35 | 36 | x86_template_assembly = """\ 37 | ;; Make sure to compile in 32 bits 38 | BITS 32 39 | 40 | ;; Build stack frame 41 | push ebp 42 | mov ebp, esp 43 | 44 | ;; Save registers 45 | pushad 46 | 47 | ;; Store the pointer to context in EAX 48 | mov eax, [ebp+8] 49 | 50 | ;; Load context (registers) 51 | mov ebx, [eax+ 1*4] 52 | mov ecx, [eax+ 2*4] 53 | mov edx, [eax+ 3*4] 54 | mov edi, [eax+ 4*4] 55 | mov esi, [eax+ 5*4] 56 | 57 | ;; TODO: Set ebp, esp and eip registers 58 | 59 | ; mov ebp, [eax+ 6*4] 60 | ; mov esp, [eax+ 7*4] 61 | ; mov eip, [eax+ 8*4] 62 | 63 | ;; Load context (flags) 64 | push dword [eax+9*4] 65 | popfd 66 | 67 | ;; Load eax value 68 | mov eax, [eax+ 0*4] 69 | 70 | ;; Run code 71 | {code} 72 | 73 | ;; Save current eax value and restore ptr to context 74 | push eax 75 | mov eax, [ebp+8] 76 | 77 | ;; Save context 78 | mov [eax+ 1*4], ebx 79 | mov [eax+ 2*4], ecx 80 | mov [eax+ 3*4], edx 81 | mov [eax+ 4*4], edi 82 | mov [eax+ 5*4], esi 83 | 84 | ; mov [eax+ 6*4], ebp 85 | ; mov [eax+ 7*4], esp 86 | ; mov [eax+ 8*4], eip 87 | 88 | ;; Save context (flags) 89 | pushfd 90 | pop dword [eax+9*4] 91 | 92 | ;; Copy eax to ebx 93 | mov ebx, eax 94 | 95 | ;; Restore current eax value 96 | pop eax 97 | 98 | ;; Save eax value 99 | mov [ebx+ 0*4], eax 100 | 101 | ;; Restore registers 102 | popad 103 | 104 | pop ebp 105 | ret 106 | """ 107 | 108 | x86_64_template_assembly = """\ 109 | ;; Make sure to compile in 64 bits 110 | BITS 64 111 | 112 | ;; Build stack frame 113 | push rbp 114 | mov rbp, rsp 115 | 116 | ;; Allocate stack memory 117 | sub rsp, 8 118 | 119 | ;; Save registers 120 | push rax 121 | push rbx 122 | push rcx 123 | push rdx 124 | push rdi 125 | push rsi 126 | push r8 127 | push r9 128 | push r10 129 | push r11 130 | push r12 131 | push r13 132 | push r14 133 | push r15 134 | 135 | ;; Save ptr to context 136 | mov [rbp-0x08], rdi 137 | 138 | ;; Load context (flags) 139 | push qword [rdi+6*8] 140 | popfq 141 | 142 | ;; Load context (registers) 143 | mov rax, [rdi+ 0*8] 144 | mov rbx, [rdi+ 1*8] 145 | mov rcx, [rdi+ 2*8] 146 | mov rdx, [rdi+ 3*8] 147 | mov rsi, [rdi+ 5*8] 148 | 149 | ;; TODO: Set rbp, rsp and rip registers 150 | 151 | ; mov rbp, [rdi+ 6*8] 152 | ; mov rsp, [rdi+ 7*8] 153 | ; mov rip, [rdi+ 8*8] 154 | 155 | mov r8, [rdi+ 9*8] 156 | mov r9, [rdi+10*8] 157 | mov r10, [rdi+11*8] 158 | mov r11, [rdi+12*8] 159 | mov r12, [rdi+13*8] 160 | mov r13, [rdi+14*8] 161 | mov r14, [rdi+15*8] 162 | mov r15, [rdi+16*8] 163 | 164 | ;; Load context (flags) 165 | push qword [rdi+17*8] 166 | popfq 167 | 168 | ;; Load rdi value 169 | mov rdi, [rdi+ 4*8] 170 | 171 | ;; Run code 172 | {code} 173 | 174 | ;; Save current rdi value and restore ptr to context 175 | push rdi 176 | mov rdi, [rbp-0x08] 177 | 178 | ;; Save context 179 | mov [rdi+ 0*8], rax 180 | mov [rdi+ 1*8], rbx 181 | mov [rdi+ 2*8], rcx 182 | mov [rdi+ 3*8], rdx 183 | mov [rdi+ 5*8], rsi 184 | 185 | ; mov [rdi+ 6*8], rbp 186 | ; mov [rdi+ 7*8], rsp 187 | ; mov [rdi+ 8*8], rip 188 | 189 | mov [rdi+ 9*8], r8 190 | mov [rdi+10*8], r9 191 | mov [rdi+11*8], r10 192 | mov [rdi+12*8], r11 193 | mov [rdi+13*8], r12 194 | mov [rdi+14*8], r13 195 | mov [rdi+15*8], r14 196 | mov [rdi+16*8], r15 197 | 198 | ;; Save context (flags) 199 | pushfq 200 | pop qword [rdi+17*8] 201 | 202 | ;; Copy rdi to rsi 203 | mov rsi, rdi 204 | 205 | ;; Restore current rdi value 206 | pop rdi 207 | 208 | ;; Save rdi value 209 | mov [rsi+ 4*8], rdi 210 | 211 | ;; Restore registers 212 | pop r15 213 | pop r14 214 | pop r13 215 | pop r12 216 | pop r11 217 | pop r10 218 | pop r9 219 | pop r8 220 | pop rsi 221 | pop rdi 222 | pop rdx 223 | pop rcx 224 | pop rbx 225 | pop rax 226 | 227 | ;; Free up stack memory 228 | add rsp, 8 229 | 230 | pop rbp 231 | ret 232 | """ 233 | 234 | arm_template_assembly = """\ 235 | /* Save registers */ 236 | push {{r0 - r12, lr}} 237 | 238 | /* Save flags (user mode) */ 239 | mrs r1, apsr 240 | push {{r1}} 241 | 242 | /* Save context pointer (redundant, it was saved before, but done for code clarity) */ 243 | push {{r0}} 244 | 245 | /* Load context */ 246 | ldr r1, [r0, #(16 * 4)] 247 | msr apsr_nzcvq, r1 248 | ldm r0, {{r0 - r12}} 249 | 250 | /* Run code */ 251 | {code} 252 | 253 | /* TODO: lr is used as scratch register when saving the context so its value is not saved correctly */ 254 | /* Restore context pointer */ 255 | pop {{lr}} 256 | 257 | /* Save context */ 258 | stm lr, {{r0 - r12}} 259 | mrs r1, apsr 260 | str r1, [lr, #(16 * 4)] 261 | 262 | /* Restore flags */ 263 | pop {{r1}} 264 | msr apsr_nzcvq, r1 265 | 266 | /* Restore registers */ 267 | pop {{r0 - r12, lr}} 268 | 269 | /* Return */ 270 | blx lr 271 | """ 272 | 273 | 274 | def x86_execute(assembly, context): 275 | # Initialize return values 276 | rc = 0 277 | ctx = {} 278 | 279 | # Instantiate assembly template. 280 | assembly = x86_template_assembly.format(code=assembly) 281 | 282 | # Create temporary files for compilation. 283 | f_asm = tempfile.NamedTemporaryFile(delete=False) 284 | f_obj = tempfile.NamedTemporaryFile(delete=False) 285 | 286 | # Write assembly to a file. 287 | f_asm.write(bytes(assembly, 'ascii')) 288 | f_asm.close() 289 | 290 | # Run nasm. 291 | cmd_fmt = "nasm -f bin -o {0} {1}" 292 | cmd = cmd_fmt.format(f_obj.name, f_asm.name) 293 | return_code = subprocess.call(cmd, shell=True) 294 | 295 | # Check for assembler errors. 296 | if return_code == 0: 297 | # Read binary code. 298 | binary = f_obj.read() 299 | f_obj.close() 300 | 301 | # Run binary code. 302 | rc, ctx = pyasmjit.x86_jit(binary, context) 303 | else: 304 | rc = return_code 305 | 306 | # Remove temporary files. 307 | os.remove(f_asm.name) 308 | os.remove(f_obj.name) 309 | 310 | return rc, ctx 311 | 312 | 313 | def x86_64_execute(assembly, context): 314 | # Initialize return values 315 | rc = 0 316 | ctx = {} 317 | 318 | # Instantiate assembly template. 319 | assembly = x86_64_template_assembly.format(code=assembly) 320 | 321 | # Create temporary files for compilation. 322 | f_asm = tempfile.NamedTemporaryFile(delete=False) 323 | f_obj = tempfile.NamedTemporaryFile(delete=False) 324 | 325 | # Write assembly to a file. 326 | f_asm.write(bytes(assembly, 'ascii')) 327 | f_asm.close() 328 | 329 | # Run nasm. 330 | cmd_fmt = "nasm -f bin -o {0} {1}" 331 | cmd = cmd_fmt.format(f_obj.name, f_asm.name) 332 | return_code = subprocess.call(cmd, shell=True) 333 | 334 | # Check for assembler errors. 335 | if return_code == 0: 336 | # Read binary code. 337 | binary = f_obj.read() 338 | f_obj.close() 339 | 340 | # Run binary code. 341 | rc, ctx = pyasmjit.x86_64_jit(binary, context) 342 | else: 343 | rc = return_code 344 | 345 | # Remove temporary files. 346 | os.remove(f_asm.name) 347 | os.remove(f_obj.name) 348 | 349 | return rc, ctx 350 | 351 | 352 | def arm_execute(assembly, context): 353 | # Initialize return values 354 | rc = 0 355 | ctx = {} 356 | 357 | # Instantiate assembly template. 358 | assembly = arm_template_assembly.format(code=assembly) 359 | 360 | # Create temporary files for compilation. 361 | f_asm = tempfile.NamedTemporaryFile(delete=False) 362 | f_obj = tempfile.NamedTemporaryFile(delete=False) 363 | f_bin = tempfile.NamedTemporaryFile(delete=False) 364 | 365 | # Write assembly to a file. 366 | f_asm.write(bytes(assembly, 'ascii')) 367 | f_asm.close() 368 | 369 | # Run nasm. 370 | cmd_fmt = "gcc -c -x assembler {asm} -o {obj}; objcopy -O binary {obj} {bin};" 371 | cmd = cmd_fmt.format(asm=f_asm.name, obj=f_obj.name, bin=f_bin.name) 372 | return_code = subprocess.call(cmd, shell=True) 373 | 374 | # Check for assembler errors. 375 | if return_code == 0: 376 | # Read binary code. 377 | binary = f_bin.read() 378 | 379 | # Run binary code. 380 | rc, ctx, mem = pyasmjit.arm_jit(binary, context) 381 | else: 382 | rc = return_code 383 | 384 | # Remove temporary files. 385 | os.remove(f_asm.name) 386 | os.remove(f_obj.name) 387 | os.remove(f_bin.name) 388 | 389 | return rc, ctx, mem 390 | 391 | 392 | def arm_alloc(size): 393 | return pyasmjit.arm_alloc(size) 394 | 395 | 396 | def arm_free(): 397 | return pyasmjit.arm_free() 398 | -------------------------------------------------------------------------------- /pyasmjit/pyasmjit.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014, Fundacion Dr. Manuel Sadosky 2 | // All rights reserved. 3 | 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are met: 6 | 7 | // 1. Redistributions of source code must retain the above copyright notice, this 8 | // list of conditions and the following disclaimer. 9 | 10 | // 2. Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation 12 | // and/or other materials provided with the distribution. 13 | 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | /* TODO: Memory: See where to locate this information. */ 31 | void * arm_mem_pool = 0; 32 | unsigned int arm_mem_pool_size = 0; 33 | 34 | typedef struct { 35 | unsigned long eax; // 0 36 | unsigned long ebx; // 1 37 | unsigned long ecx; // 2 38 | unsigned long edx; // 3 39 | unsigned long edi; // 4 40 | unsigned long esi; // 5 41 | unsigned long ebp; // 6 42 | unsigned long esp; // 7 43 | unsigned long eip; // 8 44 | unsigned long eflags; // 9 45 | } x86_context_t; 46 | 47 | typedef struct { 48 | unsigned long rax; // 0 49 | unsigned long rbx; // 1 50 | unsigned long rcx; // 2 51 | unsigned long rdx; // 3 52 | unsigned long rdi; // 4 53 | unsigned long rsi; // 5 54 | unsigned long rbp; // 6 55 | unsigned long rsp; // 7 56 | unsigned long rip; // 8 57 | unsigned long r8; // 9 58 | unsigned long r9; // 10 59 | unsigned long r10; // 11 60 | unsigned long r11; // 12 61 | unsigned long r12; // 13 62 | unsigned long r13; // 14 63 | unsigned long r14; // 15 64 | unsigned long r15; // 16 65 | unsigned long rflags; // 17 66 | } x86_64_context_t; 67 | 68 | typedef struct { 69 | unsigned long r0; // 0 70 | unsigned long r1; // 1 71 | unsigned long r2; // 2 72 | unsigned long r3; // 3 73 | unsigned long r4; // 4 74 | unsigned long r5; // 5 75 | unsigned long r6; // 6 76 | unsigned long r7; // 7 77 | unsigned long r8; // 8 78 | unsigned long r9; // 9 79 | unsigned long r10; // 10 80 | unsigned long r11; // 11 81 | unsigned long r12; // 12 82 | unsigned long r13; // 13 83 | unsigned long r14; // 14 84 | unsigned long r15; // 15 85 | unsigned long apsr; // 16 86 | } arm_context_t; 87 | 88 | void 89 | x86_print_context(x86_context_t *ctx) 90 | { 91 | printf("ctx @ %p\n", ctx); 92 | 93 | printf(" eax : 0x%016lx @ %p\n", ctx->eax, &ctx->eax); 94 | printf(" ebx : 0x%016lx @ %p\n", ctx->ebx, &ctx->ebx); 95 | printf(" ecx : 0x%016lx @ %p\n", ctx->ecx, &ctx->ecx); 96 | printf(" edx : 0x%016lx @ %p\n", ctx->edx, &ctx->edx); 97 | printf(" edi : 0x%016lx @ %p\n", ctx->edi, &ctx->edi); 98 | printf(" esi : 0x%016lx @ %p\n", ctx->esi, &ctx->esi); 99 | printf(" ebp : 0x%016lx @ %p\n", ctx->ebp, &ctx->ebp); 100 | printf(" esp : 0x%016lx @ %p\n", ctx->esp, &ctx->esp); 101 | printf(" eip : 0x%016lx @ %p\n", ctx->eip, &ctx->eip); 102 | printf("eflags : 0x%016lx @ %p\n", ctx->eflags, &ctx->eflags); 103 | } 104 | 105 | void 106 | x86_64_print_context(x86_64_context_t *ctx) 107 | { 108 | printf("ctx @ %p\n", ctx); 109 | 110 | printf(" rax : 0x%016lx @ %p\n", ctx->rax, &ctx->rax); 111 | printf(" rbx : 0x%016lx @ %p\n", ctx->rbx, &ctx->rbx); 112 | printf(" rcx : 0x%016lx @ %p\n", ctx->rcx, &ctx->rcx); 113 | printf(" rdx : 0x%016lx @ %p\n", ctx->rdx, &ctx->rdx); 114 | printf(" rdi : 0x%016lx @ %p\n", ctx->rdi, &ctx->rdi); 115 | printf(" rsi : 0x%016lx @ %p\n", ctx->rsi, &ctx->rsi); 116 | printf(" rbp : 0x%016lx @ %p\n", ctx->rbp, &ctx->rbp); 117 | printf(" rsp : 0x%016lx @ %p\n", ctx->rsp, &ctx->rsp); 118 | printf(" rip : 0x%016lx @ %p\n", ctx->rip, &ctx->rip); 119 | printf(" r8 : 0x%016lx @ %p\n", ctx->r8, &ctx->r8); 120 | printf(" r9 : 0x%016lx @ %p\n", ctx->r9, &ctx->r9); 121 | printf(" r10 : 0x%016lx @ %p\n", ctx->r10, &ctx->r10); 122 | printf(" r11 : 0x%016lx @ %p\n", ctx->r11, &ctx->r11); 123 | printf(" r12 : 0x%016lx @ %p\n", ctx->r12, &ctx->r12); 124 | printf(" r13 : 0x%016lx @ %p\n", ctx->r13, &ctx->r13); 125 | printf(" r14 : 0x%016lx @ %p\n", ctx->r14, &ctx->r14); 126 | printf(" r15 : 0x%016lx @ %p\n", ctx->r15, &ctx->r15); 127 | printf("rflags : 0x%016lx @ %p\n", ctx->rflags, &ctx->rflags); 128 | } 129 | 130 | void 131 | arm_print_context(arm_context_t *ctx) 132 | { 133 | printf("ctx @ %p\n", ctx); 134 | 135 | printf(" r0 : 0x%08lx @ %p\n", ctx->r0, &ctx->r0); 136 | printf(" r1 : 0x%08lx @ %p\n", ctx->r1, &ctx->r1); 137 | printf(" r2 : 0x%08lx @ %p\n", ctx->r2, &ctx->r2); 138 | printf(" r3 : 0x%08lx @ %p\n", ctx->r3, &ctx->r3); 139 | printf(" r4 : 0x%08lx @ %p\n", ctx->r4, &ctx->r4); 140 | printf(" r5 : 0x%08lx @ %p\n", ctx->r5, &ctx->r5); 141 | printf(" r6 : 0x%08lx @ %p\n", ctx->r6, &ctx->r6); 142 | printf(" r7 : 0x%08lx @ %p\n", ctx->r7, &ctx->r7); 143 | printf(" r8 : 0x%08lx @ %p\n", ctx->r8, &ctx->r8); 144 | printf(" r9 : 0x%08lx @ %p\n", ctx->r9, &ctx->r9); 145 | printf(" r10 : 0x%08lx @ %p\n", ctx->r10, &ctx->r10); 146 | printf(" r11 : 0x%08lx @ %p\n", ctx->r11, &ctx->r11); 147 | printf(" r12 : 0x%08lx @ %p\n", ctx->r12, &ctx->r12); 148 | printf(" r13 : 0x%08lx @ %p\n", ctx->r13, &ctx->r13); 149 | printf(" r14 : 0x%08lx @ %p\n", ctx->r14, &ctx->r14); 150 | printf(" r15 : 0x%08lx @ %p\n", ctx->r15, &ctx->r15); 151 | printf("apsr : 0x%08lx @ %p\n", ctx->apsr, &ctx->apsr); 152 | } 153 | 154 | unsigned long 155 | load_register_from_dict(PyObject *dict, const char *reg, unsigned long _default) 156 | { 157 | unsigned long rv = _default; 158 | 159 | if (PyDict_Contains(dict, Py_BuildValue("s", reg)) == 1) { 160 | rv = PyLong_AsUnsignedLong(PyDict_GetItemString(dict, reg)); 161 | } 162 | 163 | return rv; 164 | } 165 | 166 | void 167 | x86_load_context_from_dict(PyObject *dict, x86_context_t *ctx) 168 | { 169 | ctx->eax = load_register_from_dict(dict, "eax", 0); 170 | ctx->ebx = load_register_from_dict(dict, "ebx", 0); 171 | ctx->ecx = load_register_from_dict(dict, "ecx", 0); 172 | ctx->edx = load_register_from_dict(dict, "edx", 0); 173 | ctx->edi = load_register_from_dict(dict, "edi", 0); 174 | ctx->esi = load_register_from_dict(dict, "esi", 0); 175 | ctx->ebp = load_register_from_dict(dict, "ebp", 0); 176 | ctx->esp = load_register_from_dict(dict, "esp", 0); 177 | ctx->eip = load_register_from_dict(dict, "eip", 0); 178 | /* TODO: Check the default value of eflags. */ 179 | ctx->eflags = load_register_from_dict(dict, "eflags", 0x202); 180 | } 181 | 182 | void 183 | x86_64_load_context_from_dict(PyObject *dict, x86_64_context_t *ctx) 184 | { 185 | ctx->rax = load_register_from_dict(dict, "rax", 0); 186 | ctx->rbx = load_register_from_dict(dict, "rbx", 0); 187 | ctx->rcx = load_register_from_dict(dict, "rcx", 0); 188 | ctx->rdx = load_register_from_dict(dict, "rdx", 0); 189 | ctx->rdi = load_register_from_dict(dict, "rdi", 0); 190 | ctx->rsi = load_register_from_dict(dict, "rsi", 0); 191 | ctx->rbp = load_register_from_dict(dict, "rbp", 0); 192 | ctx->rsp = load_register_from_dict(dict, "rsp", 0); 193 | ctx->rip = load_register_from_dict(dict, "rip", 0); 194 | ctx->r8 = load_register_from_dict(dict, "r8", 0); 195 | ctx->r9 = load_register_from_dict(dict, "r9", 0); 196 | ctx->r10 = load_register_from_dict(dict, "r10", 0); 197 | ctx->r11 = load_register_from_dict(dict, "r11", 0); 198 | ctx->r12 = load_register_from_dict(dict, "r12", 0); 199 | ctx->r13 = load_register_from_dict(dict, "r13", 0); 200 | ctx->r14 = load_register_from_dict(dict, "r14", 0); 201 | ctx->r15 = load_register_from_dict(dict, "r15", 0); 202 | ctx->rflags = load_register_from_dict(dict, "rflags", 0x202); 203 | } 204 | 205 | void 206 | arm_load_context_from_dict(PyObject *dict, arm_context_t *ctx) 207 | { 208 | ctx->r0 = load_register_from_dict(dict, "r0", 0); 209 | ctx->r1 = load_register_from_dict(dict, "r1", 0); 210 | ctx->r2 = load_register_from_dict(dict, "r2", 0); 211 | ctx->r3 = load_register_from_dict(dict, "r3", 0); 212 | ctx->r4 = load_register_from_dict(dict, "r4", 0); 213 | ctx->r5 = load_register_from_dict(dict, "r5", 0); 214 | ctx->r6 = load_register_from_dict(dict, "r6", 0); 215 | ctx->r7 = load_register_from_dict(dict, "r7", 0); 216 | ctx->r8 = load_register_from_dict(dict, "r8", 0); 217 | ctx->r9 = load_register_from_dict(dict, "r9", 0); 218 | ctx->r10 = load_register_from_dict(dict, "r10", 0); 219 | ctx->r11 = load_register_from_dict(dict, "r11", 0); 220 | ctx->r12 = load_register_from_dict(dict, "r12", 0); 221 | ctx->r13 = load_register_from_dict(dict, "r13", 0); 222 | ctx->r14 = load_register_from_dict(dict, "r14", 0); 223 | ctx->r15 = load_register_from_dict(dict, "r15", 0); 224 | ctx->apsr = load_register_from_dict(dict, "apsr", 0); 225 | } 226 | 227 | void 228 | x86_save_context_to_dict(PyObject *dict, x86_context_t *ctx) 229 | { 230 | PyDict_SetItemString(dict, "eax", Py_BuildValue("I", ctx->eax)); 231 | PyDict_SetItemString(dict, "ebx", Py_BuildValue("I", ctx->ebx)); 232 | PyDict_SetItemString(dict, "ecx", Py_BuildValue("I", ctx->ecx)); 233 | PyDict_SetItemString(dict, "edx", Py_BuildValue("I", ctx->edx)); 234 | PyDict_SetItemString(dict, "edi", Py_BuildValue("I", ctx->edi)); 235 | PyDict_SetItemString(dict, "esi", Py_BuildValue("I", ctx->esi)); 236 | PyDict_SetItemString(dict, "ebp", Py_BuildValue("I", ctx->ebp)); 237 | PyDict_SetItemString(dict, "esp", Py_BuildValue("I", ctx->esp)); 238 | PyDict_SetItemString(dict, "eip", Py_BuildValue("I", ctx->eip)); 239 | PyDict_SetItemString(dict, "eflags", Py_BuildValue("I", ctx->eflags)); 240 | } 241 | 242 | void 243 | x86_64_save_context_to_dict(PyObject *dict, x86_64_context_t *ctx) 244 | { 245 | PyDict_SetItemString(dict, "rax", Py_BuildValue("k", ctx->rax)); 246 | PyDict_SetItemString(dict, "rbx", Py_BuildValue("k", ctx->rbx)); 247 | PyDict_SetItemString(dict, "rcx", Py_BuildValue("k", ctx->rcx)); 248 | PyDict_SetItemString(dict, "rdx", Py_BuildValue("k", ctx->rdx)); 249 | PyDict_SetItemString(dict, "rdi", Py_BuildValue("k", ctx->rdi)); 250 | PyDict_SetItemString(dict, "rsi", Py_BuildValue("k", ctx->rsi)); 251 | PyDict_SetItemString(dict, "rbp", Py_BuildValue("k", ctx->rbp)); 252 | PyDict_SetItemString(dict, "rsp", Py_BuildValue("k", ctx->rsp)); 253 | PyDict_SetItemString(dict, "rip", Py_BuildValue("k", ctx->rip)); 254 | PyDict_SetItemString(dict, "r8", Py_BuildValue("k", ctx->r8)); 255 | PyDict_SetItemString(dict, "r9", Py_BuildValue("k", ctx->r9)); 256 | PyDict_SetItemString(dict, "r10", Py_BuildValue("k", ctx->r10)); 257 | PyDict_SetItemString(dict, "r11", Py_BuildValue("k", ctx->r11)); 258 | PyDict_SetItemString(dict, "r12", Py_BuildValue("k", ctx->r12)); 259 | PyDict_SetItemString(dict, "r13", Py_BuildValue("k", ctx->r13)); 260 | PyDict_SetItemString(dict, "r14", Py_BuildValue("k", ctx->r14)); 261 | PyDict_SetItemString(dict, "r15", Py_BuildValue("k", ctx->r15)); 262 | PyDict_SetItemString(dict, "rflags", Py_BuildValue("k", ctx->rflags)); 263 | } 264 | 265 | void 266 | arm_save_context_to_dict(PyObject *dict, arm_context_t *ctx) 267 | { 268 | PyDict_SetItemString(dict, "r0", Py_BuildValue("I", ctx->r0)); 269 | PyDict_SetItemString(dict, "r1", Py_BuildValue("I", ctx->r1)); 270 | PyDict_SetItemString(dict, "r2", Py_BuildValue("I", ctx->r2)); 271 | PyDict_SetItemString(dict, "r3", Py_BuildValue("I", ctx->r3)); 272 | PyDict_SetItemString(dict, "r4", Py_BuildValue("I", ctx->r4)); 273 | PyDict_SetItemString(dict, "r5", Py_BuildValue("I", ctx->r5)); 274 | PyDict_SetItemString(dict, "r6", Py_BuildValue("I", ctx->r6)); 275 | PyDict_SetItemString(dict, "r7", Py_BuildValue("I", ctx->r7)); 276 | PyDict_SetItemString(dict, "r8", Py_BuildValue("I", ctx->r8)); 277 | PyDict_SetItemString(dict, "r9", Py_BuildValue("I", ctx->r9)); 278 | PyDict_SetItemString(dict, "r10", Py_BuildValue("I", ctx->r10)); 279 | PyDict_SetItemString(dict, "r11", Py_BuildValue("I", ctx->r11)); 280 | PyDict_SetItemString(dict, "r12", Py_BuildValue("I", ctx->r12)); 281 | PyDict_SetItemString(dict, "r13", Py_BuildValue("I", ctx->r13)); 282 | PyDict_SetItemString(dict, "r14", Py_BuildValue("I", ctx->r14)); 283 | PyDict_SetItemString(dict, "r15", Py_BuildValue("I", ctx->r15)); 284 | PyDict_SetItemString(dict, "apsr", Py_BuildValue("I", ctx->apsr)); 285 | } 286 | 287 | unsigned long 288 | x86_run(unsigned char *data, unsigned int size, x86_context_t *ctx) { 289 | /* Allocate executable memory */ 290 | void *mem = mmap( 291 | NULL, 292 | size, 293 | PROT_WRITE | PROT_EXEC, 294 | #if defined (__x86_64__) 295 | MAP_ANONYMOUS | MAP_PRIVATE | MAP_32BIT, 296 | #else 297 | MAP_ANONYMOUS | MAP_PRIVATE, 298 | #endif 299 | -1, 300 | 0 301 | ); 302 | 303 | /* Return on error */ 304 | if (mem == MAP_FAILED) { 305 | return -1; 306 | } 307 | 308 | /* Copy binary code into allocated memory */ 309 | memcpy(mem, data, size); 310 | 311 | /* Typecast allocated memory to a function pointer */ 312 | void (*func) (x86_context_t *) = mem; 313 | 314 | /* Run code */ 315 | func(ctx); 316 | 317 | /* Free up allocated memory */ 318 | munmap(mem, size); 319 | 320 | return 0; 321 | } 322 | 323 | unsigned long 324 | x86_64_run(unsigned char *data, unsigned int size, x86_64_context_t *ctx) { 325 | /* Allocate executable memory */ 326 | void *mem = mmap( 327 | NULL, 328 | size, 329 | PROT_WRITE | PROT_EXEC, 330 | #if defined (__x86_64__) 331 | MAP_ANONYMOUS | MAP_PRIVATE | MAP_32BIT, 332 | #else 333 | MAP_ANONYMOUS | MAP_PRIVATE, 334 | #endif 335 | -1, 336 | 0 337 | ); 338 | 339 | /* Return on error */ 340 | if (mem == MAP_FAILED) { 341 | return -1; 342 | } 343 | 344 | /* Copy binary code into allocated memory */ 345 | memcpy(mem, data, size); 346 | 347 | /* Typecast allocated memory to a function pointer */ 348 | void (*func) (x86_64_context_t *) = mem; 349 | 350 | /* Run code */ 351 | func(ctx); 352 | 353 | /* Free up allocated memory */ 354 | munmap(mem, size); 355 | 356 | return 0; 357 | } 358 | 359 | unsigned long 360 | arm_run(unsigned char *data, unsigned int size, arm_context_t *ctx) { 361 | /* Allocate executable memory */ 362 | void *mem = mmap( 363 | NULL, 364 | size, 365 | PROT_WRITE | PROT_EXEC, 366 | MAP_ANONYMOUS | MAP_PRIVATE, 367 | -1, 368 | 0 369 | ); 370 | 371 | /* Return on error */ 372 | if (mem == MAP_FAILED) { 373 | return -1; 374 | } 375 | 376 | /* Copy binary code into allocated memory */ 377 | memcpy(mem, data, size); 378 | 379 | /* Typecast allocated memory to a function pointer */ 380 | void (*func) (arm_context_t *) = mem; 381 | 382 | /* Run code */ 383 | func(ctx); 384 | 385 | /* Free up allocated memory */ 386 | munmap(mem, size); 387 | 388 | return 0; 389 | } 390 | 391 | /* 392 | * Function to be called from Python 393 | */ 394 | static PyObject * 395 | pyasmjit_x86_jit(PyObject * self, PyObject * args) 396 | { 397 | unsigned char *data; 398 | unsigned int size; 399 | unsigned int rv; 400 | PyObject *dict_in; 401 | PyObject *dict_out = PyDict_New(); 402 | x86_context_t ctx; 403 | 404 | /* Check newly created dict is not null */ 405 | if (dict_out == NULL) 406 | return Py_BuildValue("I{}", -1); 407 | 408 | /* Parse input arguments */ 409 | PyArg_ParseTuple(args, "s#O!", &data, &size, &PyDict_Type, &dict_in); 410 | 411 | /* Load context from input dictionary */ 412 | x86_load_context_from_dict(dict_in, &ctx); 413 | 414 | /* Run input code */ 415 | rv = x86_run(data, size, &ctx); 416 | 417 | /* Save context to output dictionary */ 418 | x86_save_context_to_dict(dict_out, &ctx); 419 | 420 | /* Build return value and return */ 421 | return Py_BuildValue("IO", rv, dict_out); 422 | } 423 | 424 | /* 425 | * Function to be called from Python 426 | */ 427 | static PyObject * 428 | pyasmjit_x86_64_jit(PyObject * self, PyObject * args) 429 | { 430 | unsigned char *data; 431 | unsigned int size; 432 | unsigned int rv; 433 | PyObject *dict_in; 434 | PyObject *dict_out = PyDict_New(); 435 | x86_64_context_t ctx; 436 | 437 | /* Check newly created dict is not null */ 438 | if (dict_out == NULL) 439 | return Py_BuildValue("I{}", -1); 440 | 441 | /* Parse input arguments */ 442 | PyArg_ParseTuple(args, "s#O!", &data, &size, &PyDict_Type, &dict_in); 443 | 444 | /* Load context from input dictionary */ 445 | x86_64_load_context_from_dict(dict_in, &ctx); 446 | 447 | /* Run input code */ 448 | rv = x86_64_run(data, size, &ctx); 449 | 450 | /* Save context to output dictionary */ 451 | x86_64_save_context_to_dict(dict_out, &ctx); 452 | 453 | /* Build return value and return */ 454 | return Py_BuildValue("IO", rv, dict_out); 455 | } 456 | 457 | /* 458 | * Function to be called from Python 459 | */ 460 | static PyObject * 461 | pyasmjit_arm_jit(PyObject * self, PyObject * args) 462 | { 463 | unsigned char *data; 464 | unsigned int size; 465 | unsigned int rv; 466 | PyObject *dict_in; 467 | PyObject *dict_out = PyDict_New(); 468 | arm_context_t ctx; 469 | 470 | /* Check newly created dict is not null */ 471 | if (dict_out == NULL) 472 | return Py_BuildValue("I{}", -1); 473 | 474 | /* Parse input arguments */ 475 | PyArg_ParseTuple(args, "s#O!", &data, &size, &PyDict_Type, &dict_in); 476 | 477 | /* Load context from input dictionary */ 478 | arm_load_context_from_dict(dict_in, &ctx); 479 | 480 | /* Run input code */ 481 | rv = arm_run(data, size, &ctx); 482 | 483 | /* Save context to output dictionary */ 484 | arm_save_context_to_dict(dict_out, &ctx); 485 | 486 | /* TODO: Check that if pool is null it doesn't break the function. */ 487 | #if (PY_MAJOR_VERSION == 3) 488 | PyObject *py_buffer = Py_BuildValue("y#", arm_mem_pool, arm_mem_pool_size); 489 | #else 490 | PyObject *py_buffer = Py_BuildValue("s#", arm_mem_pool, arm_mem_pool_size); 491 | #endif 492 | 493 | /* Build return value and return */ 494 | return Py_BuildValue("IOO", rv, dict_out, py_buffer); 495 | } 496 | 497 | /* 498 | * Function to be called from Python 499 | */ 500 | static PyObject * 501 | pyasmjit_arm_alloc(PyObject * self, PyObject * args) 502 | { 503 | unsigned int size; 504 | 505 | /* Parse input arguments */ 506 | PyArg_ParseTuple(args, "I", &size); 507 | 508 | arm_mem_pool_size = size; 509 | 510 | /* Allocate executable memory */ 511 | arm_mem_pool = mmap( 512 | NULL, 513 | size, 514 | PROT_WRITE, 515 | MAP_ANONYMOUS | MAP_PRIVATE, 516 | -1, 517 | 0 518 | ); 519 | 520 | memset(arm_mem_pool, 0, arm_mem_pool_size); 521 | 522 | /* Build return value and return */ 523 | return Py_BuildValue("I", arm_mem_pool); 524 | } 525 | 526 | /* 527 | * Function to be called from Python 528 | */ 529 | static PyObject * 530 | pyasmjit_arm_free(PyObject * self, PyObject * args) 531 | { 532 | /* TODO: Allow multiple memory pools. */ 533 | if (arm_mem_pool) { 534 | munmap(arm_mem_pool, arm_mem_pool_size); 535 | arm_mem_pool = 0; 536 | } 537 | 538 | return Py_BuildValue("I", 0); 539 | } 540 | 541 | /* 542 | * Bind Python function names to our C functions 543 | */ 544 | static PyMethodDef pyasmjit_methods[] = { 545 | {"x86_jit", pyasmjit_x86_jit, METH_VARARGS, "JIT execute x86 code"}, 546 | {"x86_64_jit", pyasmjit_x86_64_jit, METH_VARARGS, "JIT execute x86_64 code"}, 547 | {"arm_jit", pyasmjit_arm_jit, METH_VARARGS, "JIT execute ARMv7 code"}, 548 | {"arm_alloc", pyasmjit_arm_alloc, METH_VARARGS, "Map ARM memory"}, 549 | {"arm_free", pyasmjit_arm_free, METH_VARARGS, "Unmap ARM memory"}, 550 | {NULL, NULL, 0, NULL} 551 | }; 552 | 553 | #if (PY_MAJOR_VERSION == 3) 554 | /* 555 | * Module definition 556 | * The arguments of this structure tell Python what to call your extension, 557 | * what it's methods are and where to look for it's method definitions 558 | */ 559 | static struct PyModuleDef pyasmjit_definition = { 560 | PyModuleDef_HEAD_INIT, 561 | "pyasmjit", 562 | "JIT module for pyasmjit", 563 | -1, 564 | pyasmjit_methods 565 | }; 566 | 567 | /* 568 | * Module initialization 569 | * Python calls this function when importing your extension. It is important 570 | * that this function is named PyInit_[[your_module_name]] exactly, and matches 571 | * the name keyword argument in setup.py's setup() call. 572 | */ 573 | PyMODINIT_FUNC PyInit_pyasmjit(void) { 574 | Py_Initialize(); 575 | return PyModule_Create(&pyasmjit_definition); 576 | } 577 | 578 | #else /* Python 2.x */ 579 | 580 | static const char *pyasmjit_docstring = "JIT module for pyasmjit"; 581 | 582 | /* 583 | * Python calls this to let us initialize our module 584 | */ 585 | PyMODINIT_FUNC 586 | initpyasmjit(void) 587 | { 588 | (void) Py_InitModule3("pyasmjit", pyasmjit_methods, pyasmjit_docstring); 589 | } 590 | 591 | #endif 592 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | description-file = README.md 3 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from setuptools import Extension 4 | from setuptools import find_packages 5 | from setuptools import setup 6 | 7 | __version__ = '0.3.0' 8 | 9 | pyasmjit_module = Extension( 10 | 'pyasmjit.pyasmjit', 11 | sources = [ 12 | 'pyasmjit/pyasmjit.c' 13 | ], 14 | ) 15 | 16 | setup( 17 | name = 'pyasmjit', 18 | author = 'Christian Heitman', 19 | author_email = 'barfframework@gmail.com', 20 | description = 'JIT assemby code generation and execution', 21 | download_url = 'https://github.com/programa-stic/pyasmjit/tarball/v0.3.0', 22 | install_requires = [ 23 | 'future', 24 | ], 25 | license = 'BSD 2-Clause', 26 | url = 'http://github.com/programa-stic/pyasmjit', 27 | version = __version__, 28 | classifiers = [ 29 | 'Development Status :: 2 - Pre-Alpha', 30 | 'License :: OSI Approved :: BSD License', 31 | 'Natural Language :: English', 32 | 'Operating System :: POSIX :: Linux', 33 | 'Programming Language :: Python :: 2.7', 34 | 'Programming Language :: Python :: 3.6', 35 | 'Programming Language :: C', 36 | 'Topic :: Software Development :: Assemblers', 37 | ], 38 | ext_modules = [ 39 | pyasmjit_module, 40 | ], 41 | packages=find_packages(exclude=['tests', 'tests.*']), 42 | test_suite = 'tests', 43 | ) 44 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014, Fundacion Dr. Manuel Sadosky 2 | # All rights reserved. 3 | 4 | # Redistribution and use in source and binary forms, with or without 5 | # modification, are permitted provided that the following conditions are met: 6 | 7 | # 1. Redistributions of source code must retain the above copyright notice, this 8 | # list of conditions and the following disclaimer. 9 | 10 | # 2. Redistributions in binary form must reproduce the above copyright notice, 11 | # this list of conditions and the following disclaimer in the documentation 12 | # and/or other materials provided with the distribution. 13 | 14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /tests/pyasmjit/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014, Fundacion Dr. Manuel Sadosky 2 | # All rights reserved. 3 | 4 | # Redistribution and use in source and binary forms, with or without 5 | # modification, are permitted provided that the following conditions are met: 6 | 7 | # 1. Redistributions of source code must retain the above copyright notice, this 8 | # list of conditions and the following disclaimer. 9 | 10 | # 2. Redistributions in binary form must reproduce the above copyright notice, 11 | # this list of conditions and the following disclaimer in the documentation 12 | # and/or other materials provided with the distribution. 13 | 14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /tests/pyasmjit/test_arm_jit.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014, Fundacion Dr. Manuel Sadosky 2 | # All rights reserved. 3 | 4 | # Redistribution and use in source and binary forms, with or without 5 | # modification, are permitted provided that the following conditions are met: 6 | 7 | # 1. Redistributions of source code must retain the above copyright notice, this 8 | # list of conditions and the following disclaimer. 9 | 10 | # 2. Redistributions in binary form must reproduce the above copyright notice, 11 | # this list of conditions and the following disclaimer in the documentation 12 | # and/or other materials provided with the distribution. 13 | 14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | 25 | import platform 26 | import unittest 27 | 28 | import pyasmjit 29 | 30 | 31 | @unittest.skipUnless(platform.machine().lower() == 'armv7l', 32 | 'Not running on an ARMv7 system') 33 | class Test_arm_jit(unittest.TestCase): 34 | 35 | def test_add(self): 36 | code = """ 37 | add r7, r7, r8 38 | """ 39 | ctx_in = { 40 | 'r7': 0x1, 41 | 'r8': 0x2, 42 | } 43 | 44 | rv, ctx_out, _ = pyasmjit.arm_execute(code, ctx_in) 45 | self.assertEqual(0x3, ctx_out['r7']) 46 | -------------------------------------------------------------------------------- /tests/pyasmjit/test_x86_64_jit.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014, Fundacion Dr. Manuel Sadosky 2 | # All rights reserved. 3 | 4 | # Redistribution and use in source and binary forms, with or without 5 | # modification, are permitted provided that the following conditions are met: 6 | 7 | # 1. Redistributions of source code must retain the above copyright notice, this 8 | # list of conditions and the following disclaimer. 9 | 10 | # 2. Redistributions in binary form must reproduce the above copyright notice, 11 | # this list of conditions and the following disclaimer in the documentation 12 | # and/or other materials provided with the distribution. 13 | 14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | 25 | import platform 26 | import unittest 27 | 28 | import pyasmjit 29 | 30 | 31 | @unittest.skipUnless(platform.machine().lower() == 'x86_64', 32 | 'Not running on an x86_64 system') 33 | class Test_x86_64_jit(unittest.TestCase): 34 | 35 | def test_add(self): 36 | code = """ 37 | add rax, rbx 38 | """ 39 | ctx_in = { 40 | 'rax': 0x1, 41 | 'rbx': 0x2, 42 | } 43 | 44 | rv, ctx_out = pyasmjit.x86_64_execute(code, ctx_in) 45 | self.assertEqual(0x3, ctx_out['rax']) 46 | -------------------------------------------------------------------------------- /tests/pyasmjit/test_x86_jit.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014, Fundacion Dr. Manuel Sadosky 2 | # All rights reserved. 3 | 4 | # Redistribution and use in source and binary forms, with or without 5 | # modification, are permitted provided that the following conditions are met: 6 | 7 | # 1. Redistributions of source code must retain the above copyright notice, this 8 | # list of conditions and the following disclaimer. 9 | 10 | # 2. Redistributions in binary form must reproduce the above copyright notice, 11 | # this list of conditions and the following disclaimer in the documentation 12 | # and/or other materials provided with the distribution. 13 | 14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | 25 | import platform 26 | import unittest 27 | 28 | import pyasmjit 29 | 30 | 31 | @unittest.skipUnless(platform.machine().lower() in ['i686', 'x86'], 32 | 'Not running on an x86 system') 33 | class Test_x86_jit(unittest.TestCase): 34 | 35 | def test_add(self): 36 | code = """ 37 | add eax, ebx 38 | """ 39 | ctx_in = { 40 | 'eax': 0x1, 41 | 'ebx': 0x2, 42 | } 43 | 44 | rv, ctx_out = pyasmjit.x86_execute(code, ctx_in) 45 | self.assertEqual(0x3, ctx_out['eax']) 46 | --------------------------------------------------------------------------------