diff --git a/.github/workflows/build-ci.yml b/.github/workflows/build-ci.yml index 1b652b8d3..2dc4b7663 100644 --- a/.github/workflows/build-ci.yml +++ b/.github/workflows/build-ci.yml @@ -10,21 +10,18 @@ jobs: fail-fast: false matrix: #os: [windows-2019, macos-10.15, ubuntu-18.04, ubuntu-20.04] - os: [windows-latest, ubuntu-18.04, ubuntu-20.04] - python-version: [3.8, 3.9] - exclude: - - os: ubuntu-18.04 - python-version: 3.9 + os: [windows-latest, ubuntu-20.04] + python-version: [3.8, 3.9] include: - - os: ubuntu-18.04 + - os: ubuntu-22.04 python-version: 3.9 container: Docker steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} diff --git a/ChangeLog b/ChangeLog index c868d96d2..7cb4592b5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,48 @@ This file details the changelog of Qiling Framework. +------------------------------------ +[Version 1.4.5]: December 29th, 2022 + +New features: +- Qdb with PE (#1295) + +Improvements: +- Add pstate in const_arm64.py (#1236) +- Implement ql_syscall_sched_yield (#1237) +- Periodic quality PR (#1238) +- Speed up MCU interrupt handler (#1240) +- Minor update for setup.py, mcu test and windows registry (#1246) +- Optimize qltui (#1247) +- Optimize evm dependency package version manage (#1248) +- Fix getrlimit related syscall (aka tenda fix) (#1249) +- Add new ci for arm firmware (#1250) +- More detailed tenda CI test and cleanup elf multithrad http test (#1251) +- Fix MIPS relocs (#1252) +- Newly compiled picohttpd for armeb and new test script (#1254) +- Update armeb test binary and testing docker (#1255) +- Update rootfs (#1256) +- Qdb bug fix and improvement (#1257) +- Improve handling of gdb 42000 magic pid (#1259) +- Fix mcu issue in qdb and show flags in uppercase (#1263) +- Update setup.py (#1267) +- Handle Cortex M as a specific arch (#1271) +- Fix some error in syscall fcntl and getsockopt (#1272) +- Periodic maintenance PR (#1274) +- Fix gdb attach on ARM thumb mode (#1285) +- Qdb: add command show_args (#1289) +- Periodic maintenance PR (#1293) + +Contributors: +- richor1042 +- vhertz +- elicn +- kabeor +- xwings +- ucgJhe +- aquynh +- owl129 +- + ------------------------------------ [Version 1.4.4]: September 24th, 2022 @@ -87,7 +130,6 @@ Contributors: - elicn - xwings - cq674350529 -- elicn - TheZ3ro - bet4it - chinggg diff --git a/README.md b/README.md index aba7e7e2e..5686fd45f 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,10 @@ Qiling is an advanced binary emulation framework, with the following features: Qiling also made its way to various international conferences. +2022: +- [Black Hat, EU](https://www.blackhat.com/eu-22/arsenal/schedule/#reversing-mcu-with-firmware-emulation-29553) +- [Black Hat, MEA](https://blackhatmea.com/node/724) + 2021: - [Black Hat, USA](https://www.blackhat.com/us-21/arsenal/schedule/index.html#bringing-the-x-complete-re-experience-to-smart-contract-24119) - [Hack In The Box, Amsterdam](https://conference.hitb.org/hitbsecconf2021ams/sessions/when-qiling-framework-meets-symbolic-execution/) diff --git a/examples/fuzzing/stm32f429/afl_inputs/sample b/examples/fuzzing/stm32f429/afl_inputs/sample new file mode 100644 index 000000000..80c2dfa12 --- /dev/null +++ b/examples/fuzzing/stm32f429/afl_inputs/sample @@ -0,0 +1,2 @@ +hackme +aaaaaaaaaaaa diff --git a/examples/fuzzing/stm32f429/fuzz.py b/examples/fuzzing/stm32f429/fuzz.py new file mode 100644 index 000000000..3f90bd212 --- /dev/null +++ b/examples/fuzzing/stm32f429/fuzz.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import os +import sys + +from typing import Any, Optional + +sys.path.append("../../..") +from qiling.core import Qiling +from qiling.const import QL_VERBOSE + +from qiling.extensions.afl import ql_afl_fuzz_custom +from qiling.extensions.mcu.stm32f4 import stm32f429 + +from unicorn import UC_ERR_OK, UcError + +def main(input_file: str): + ql = Qiling(["../../rootfs/mcu/stm32f429/bof.elf"], + archtype="cortex_m", + env=stm32f429, + ostype='mcu', + verbose=QL_VERBOSE.DISABLED) + + ql.hw.create('rcc') + ql.hw.create('usart2') + ql.hw.create('usart3') + + ql.fast_mode = True + + def place_input_callback(ql: Qiling, input_bytes: bytes, persistent_round: int) -> Optional[bool]: + """Called with every newly generated input.""" + + ql.hw.usart3.send(input_bytes) + + return True + + def fuzzing_callback(ql: Qiling): + ql.run(end=0x80006d9) + + return UC_ERR_OK + + ql.uc.ctl_exits_enabled(True) + ql.uc.ctl_set_exits([0x80006d9]) + + ql_afl_fuzz_custom(ql, input_file, place_input_callback, fuzzing_callback=fuzzing_callback) + + os.exit(0) + +if __name__ == "__main__": + if len(sys.argv) == 1: + raise ValueError("No input file provided.") + + main(sys.argv[1]) \ No newline at end of file diff --git a/examples/fuzzing/stm32f429/fuzz.sh b/examples/fuzzing/stm32f429/fuzz.sh new file mode 100755 index 000000000..6ab893678 --- /dev/null +++ b/examples/fuzzing/stm32f429/fuzz.sh @@ -0,0 +1,2 @@ +#!/bin/bash +AFL_AUTORESUME=1 afl-fuzz -i afl_inputs -o afl_outputs -U -- python3 ./fuzz.py @@ diff --git a/examples/hello_mips32_linux_customapi.py b/examples/hello_mips32_linux_customapi.py index 286d62faa..01fe30558 100644 --- a/examples/hello_mips32_linux_customapi.py +++ b/examples/hello_mips32_linux_customapi.py @@ -17,4 +17,5 @@ def my_puts(ql: Qiling): if __name__ == "__main__": ql = Qiling(["rootfs/mips32_linux/bin/mips32_hello"], "rootfs/mips32_linux", verbose=QL_VERBOSE.DEBUG) + ql.os.set_api("puts", my_puts) ql.run() diff --git a/examples/mcu/gd32vf103_blink.py b/examples/mcu/gd32vf103_blink.py index ff2e49dc3..003e5a1c5 100644 --- a/examples/mcu/gd32vf103_blink.py +++ b/examples/mcu/gd32vf103_blink.py @@ -10,7 +10,7 @@ from qiling.const import QL_VERBOSE from qiling.extensions.mcu.gd32vf1 import gd32vf103 -ql = Qiling(['../rootfs/mcu/gd32vf103/blink.hex'], archtype="riscv64", +ql = Qiling(['../rootfs/mcu/gd32vf103/blink.hex'], archtype="riscv64", ostype="mcu", env=gd32vf103, verbose=QL_VERBOSE.DEBUG) ql.hw.create('rcu') diff --git a/examples/mcu/stm32f407_gpio_hook.py b/examples/mcu/stm32f407_gpio_hook.py index f3a0f3e0b..5d0c9dbe9 100644 --- a/examples/mcu/stm32f407_gpio_hook.py +++ b/examples/mcu/stm32f407_gpio_hook.py @@ -13,7 +13,7 @@ ql = Qiling(["../rootfs/mcu/stm32f407/ai-sine-test.elf"], - archtype="cortex_m", env=stm32f407, verbose=QL_VERBOSE.DEFAULT) + archtype="cortex_m", ostype="mcu", env=stm32f407, verbose=QL_VERBOSE.DEFAULT) ql.hw.create('rcc') ql.hw.create('pwr') @@ -23,6 +23,7 @@ ql.hw.create('gpiod') ql.hw.create('spi1') ql.hw.create('crc') +ql.hw.create('dbgmcu') oled = PyGameSSD1306Spi(dc=(ql.hw.gpiod, 5)) ql.hw.spi1.connect(oled) diff --git a/examples/mcu/stm32f407_hack_lock.py b/examples/mcu/stm32f407_hack_lock.py index 17b4addbf..de41dad44 100644 --- a/examples/mcu/stm32f407_hack_lock.py +++ b/examples/mcu/stm32f407_hack_lock.py @@ -27,7 +27,7 @@ def dicts(): # Cracking the passwd of lock def crack(passwd): ql = Qiling(["../../examples/rootfs/mcu/stm32f407/backdoorlock.hex"], - archtype="cortex_m", env=stm32f407, verbose=QL_VERBOSE.OFF) + archtype="cortex_m", ostype="mcu", env=stm32f407, verbose=QL_VERBOSE.DISABLED) ql.hw.create('spi2') ql.hw.create('gpioe') diff --git a/examples/mcu/stm32f407_mnist_oled.py b/examples/mcu/stm32f407_mnist_oled.py index 16338b77d..6055518d8 100644 --- a/examples/mcu/stm32f407_mnist_oled.py +++ b/examples/mcu/stm32f407_mnist_oled.py @@ -13,12 +13,13 @@ ql = Qiling(["../rootfs/mcu/stm32f407/mnist.bin", 0x8000000], - archtype="cortex_m", env=stm32f407, verbose=QL_VERBOSE.DEFAULT) + archtype="cortex_m", ostype="mcu", env=stm32f407, verbose=QL_VERBOSE.DEFAULT) ql.hw.create('rcc') ql.hw.create('gpiod') ql.hw.create('spi1') ql.hw.create('crc') +ql.hw.create('dbgmcu') oled = PyGameSSD1306Spi(dc=(ql.hw.gpiod, 5)) ql.hw.spi1.connect(oled) diff --git a/examples/mcu/stm32f411_dma_logger.py b/examples/mcu/stm32f411_dma_logger.py index cb20f5966..5ab10c515 100644 --- a/examples/mcu/stm32f411_dma_logger.py +++ b/examples/mcu/stm32f411_dma_logger.py @@ -12,7 +12,7 @@ def stm32f411_dma(): ql = Qiling(["../rootfs/mcu/stm32f411/dma-clock.hex"], - archtype="cortex_m", env=stm32f411, verbose=QL_VERBOSE.DEBUG) + archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEBUG) ql.hw.create('usart2').watch() ql.hw.create('dma1').watch() diff --git a/examples/mcu/stm32f411_freertos.py b/examples/mcu/stm32f411_freertos.py index 57abd323e..ee003f141 100644 --- a/examples/mcu/stm32f411_freertos.py +++ b/examples/mcu/stm32f411_freertos.py @@ -13,7 +13,7 @@ def stm32f411_freertos(): ql = Qiling(["../rootfs/mcu/stm32f411/os-demo.hex"], - archtype="cortex_m", env=stm32f411, verbose=QL_VERBOSE.DEBUG) + archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEBUG) ql.hw.create('usart2').watch() ql.hw.create('gpioa').watch() diff --git a/examples/mcu/stm32f411_gpio_hook.py b/examples/mcu/stm32f411_gpio_hook.py index 9e8b42faf..5fbb23979 100644 --- a/examples/mcu/stm32f411_gpio_hook.py +++ b/examples/mcu/stm32f411_gpio_hook.py @@ -12,7 +12,7 @@ def test_mcu_gpio_stm32f411(): ql = Qiling(["../../examples/rootfs/mcu/stm32f411/hello_gpioA.hex"], - archtype="cortex_m", env=stm32f411, verbose=QL_VERBOSE.DEBUG) + archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEBUG) ql.hw.create('usart2').watch() ql.hw.create('rcc').watch() diff --git a/examples/mcu/stm32f411_i2c_lcd.py b/examples/mcu/stm32f411_i2c_lcd.py index 3e09f11f9..48b143834 100644 --- a/examples/mcu/stm32f411_i2c_lcd.py +++ b/examples/mcu/stm32f411_i2c_lcd.py @@ -13,7 +13,7 @@ from qiling.extensions.mcu.stm32f4 import stm32f411 def create(path, lcd): - ql = Qiling([path], archtype="cortex_m", env=stm32f411, verbose=QL_VERBOSE.DEBUG) + ql = Qiling([path], archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEBUG) ql.hw.create('i2c1') ql.hw.create('rcc') diff --git a/examples/mcu/stm32f411_interact_usart.py b/examples/mcu/stm32f411_interact_usart.py index 3cab93584..19f5ba839 100644 --- a/examples/mcu/stm32f411_interact_usart.py +++ b/examples/mcu/stm32f411_interact_usart.py @@ -16,7 +16,7 @@ ql = Qiling(["../../examples/rootfs/mcu/stm32f411/md5_server.hex"], - archtype="cortex_m", env=stm32f411, verbose=QL_VERBOSE.OFF) + archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.OFF) ql.hw.create('usart2') ql.hw.create('rcc') diff --git a/examples/mcu/stm32f411_spi_oled12864.py b/examples/mcu/stm32f411_spi_oled12864.py index 8f4a63982..69fdcb707 100644 --- a/examples/mcu/stm32f411_spi_oled12864.py +++ b/examples/mcu/stm32f411_spi_oled12864.py @@ -12,7 +12,7 @@ from qiling.hw.external_device.oled.ssd1306 import PyGameSSD1306Spi ql = Qiling(['../rootfs/mcu/stm32f411/oled12864.hex'], - archtype="cortex_m", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) + archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) ql.hw.create('rcc') ql.hw.create('gpioa') diff --git a/examples/rootfs b/examples/rootfs index 54756aecf..32c4fcf52 160000 --- a/examples/rootfs +++ b/examples/rootfs @@ -1 +1 @@ -Subproject commit 54756aecffddc8b22843ddcb8a92afd1b0e545a3 +Subproject commit 32c4fcf52f4aa0efaa1cb03ab6b2186c61f512c6 diff --git a/examples/shellcode_run.py b/examples/shellcode_run.py index c45f9ed27..c7e189696 100644 --- a/examples/shellcode_run.py +++ b/examples/shellcode_run.py @@ -1,58 +1,107 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -from binascii import unhexlify import sys sys.path.append("..") from qiling import Qiling -from qiling.const import QL_VERBOSE - -X86_LIN = unhexlify('31c050682f2f7368682f62696e89e3505389e1b00bcd80') -X8664_LIN = unhexlify('31c048bbd19d9691d08c97ff48f7db53545f995257545eb03b0f05') -MIPS32EL_LIN = unhexlify('ffff0628ffffd004ffff05280110e4270ff08424ab0f02240c0101012f62696e2f7368') -X86_WIN = unhexlify('fce8820000006089e531c0648b50308b520c8b52148b72280fb74a2631ffac3c617c022c20c1cf0d01c7e2f252578b52108b4a3c8b4c1178e34801d1518b592001d38b4918e33a498b348b01d631ffacc1cf0d01c738e075f6037df83b7d2475e4588b582401d3668b0c4b8b581c01d38b048b01d0894424245b5b61595a51ffe05f5f5a8b12eb8d5d6a01eb2668318b6f87ffd5bbf0b5a25668a695bd9dffd53c067c0a80fbe07505bb4713726f6a0053ffd5e8d5ffffff63616c6300') -X8664_WIN = unhexlify('fc4881e4f0ffffffe8d0000000415141505251564831d265488b52603e488b52183e488b52203e488b72503e480fb74a4a4d31c94831c0ac3c617c022c2041c1c90d4101c1e2ed5241513e488b52203e8b423c4801d03e8b80880000004885c0746f4801d0503e8b48183e448b40204901d0e35c48ffc93e418b34884801d64d31c94831c0ac41c1c90d4101c138e075f13e4c034c24084539d175d6583e448b40244901d0663e418b0c483e448b401c4901d03e418b04884801d0415841585e595a41584159415a4883ec204152ffe05841595a3e488b12e949ffffff5d49c7c1000000003e488d95fe0000003e4c8d850f0100004831c941ba45835607ffd54831c941baf0b5a256ffd548656c6c6f2c2066726f6d204d534621004d657373616765426f7800') -ARM_LIN = unhexlify('01108fe211ff2fe102200121921a0f02193701df061c08a11022023701df3f270221301c01df0139fbd505a0921a05b469460b2701dfc046020012340a0002022f73797374656d2f62696e2f736800') -ARM64_LIN = unhexlify('420002ca210080d2400080d2c81880d2010000d4e60300aa01020010020280d2681980d2010000d4410080d2420002cae00306aa080380d2010000d4210400f165ffff54e0000010420002ca210001caa81b80d2010000d4020004d27f0000012f62696e2f736800') -X8664_FBSD = unhexlify('6a61586a025f6a015e990f054897baff02aaaa80f2ff524889e699046680c2100f05046a0f05041e4831f6990f0548976a035852488d7424f080c2100f0548b8523243427730637257488d3e48af74084831c048ffc00f055f4889d04889fe48ffceb05a0f0575f799043b48bb2f62696e2f2f73685253545f5257545e0f05') -X8664_MACOS = unhexlify('4831f65648bf2f2f62696e2f7368574889e74831d24831c0b00248c1c828b03b0f05') +from qiling.const import QL_ARCH, QL_OS, QL_VERBOSE + +X86_LIN = bytes.fromhex('31c050682f2f7368682f62696e89e3505389e1b00bcd80') +X8664_LIN = bytes.fromhex('31c048bbd19d9691d08c97ff48f7db53545f995257545eb03b0f05') + +MIPS32EL_LIN = bytes.fromhex(''' + ffff0628ffffd004ffff05280110e4270ff08424ab0f02240c0101012f62696e + 2f7368 +''') + +X86_WIN = bytes.fromhex(''' + fce8820000006089e531c0648b50308b520c8b52148b72280fb74a2631ffac3c + 617c022c20c1cf0d01c7e2f252578b52108b4a3c8b4c1178e34801d1518b5920 + 01d38b4918e33a498b348b01d631ffacc1cf0d01c738e075f6037df83b7d2475 + e4588b582401d3668b0c4b8b581c01d38b048b01d0894424245b5b61595a51ff + e05f5f5a8b12eb8d5d6a01eb2668318b6f87ffd5bbf0b5a25668a695bd9dffd5 + 3c067c0a80fbe07505bb4713726f6a0053ffd5e8d5ffffff63616c6300 +''') + +X8664_WIN = bytes.fromhex(''' + fc4881e4f0ffffffe8d0000000415141505251564831d265488b52603e488b52 + 183e488b52203e488b72503e480fb74a4a4d31c94831c0ac3c617c022c2041c1 + c90d4101c1e2ed5241513e488b52203e8b423c4801d03e8b80880000004885c0 + 746f4801d0503e8b48183e448b40204901d0e35c48ffc93e418b34884801d64d + 31c94831c0ac41c1c90d4101c138e075f13e4c034c24084539d175d6583e448b + 40244901d0663e418b0c483e448b401c4901d03e418b04884801d0415841585e + 595a41584159415a4883ec204152ffe05841595a3e488b12e949ffffff5d49c7 + c1000000003e488d95fe0000003e4c8d850f0100004831c941ba45835607ffd5 + 4831c941baf0b5a256ffd548656c6c6f2c2066726f6d204d534621004d657373 + 616765426f7800 +''') + +ARM_LIN = bytes.fromhex(''' + 01108fe211ff2fe102200121921a0f02193701df061c08a11022023701df3f27 + 0221301c01df0139fbd505a0921a05b469460b2701dfc046020012340a000202 + 2f73797374656d2f62696e2f736800 +''') + +ARM64_LIN = bytes.fromhex(''' + 420002ca210080d2400080d2c81880d2010000d4e60300aa01020010020280d2 + 681980d2010000d4410080d2420002cae00306aa080380d2010000d4210400f1 + 65ffff54e0000010420002ca210001caa81b80d2010000d4020004d27f000001 + 2f62696e2f736800 +''') + +X8664_FBSD = bytes.fromhex(''' + 6a61586a025f6a015e990f054897baff02aaaa80f2ff524889e699046680c210 + 0f05046a0f05041e4831f6990f0548976a035852488d7424f080c2100f0548b8 + 523243427730637257488d3e48af74084831c048ffc00f055f4889d04889fe48 + ffceb05a0f0575f799043b48bb2f62696e2f2f73685253545f5257545e0f05 +''') + +X8664_MACOS = bytes.fromhex(''' + 4831f65648bf2f2f62696e2f7368574889e74831d24831c0b00248c1c828b03b + 0f05 +''') + if __name__ == "__main__": print("\nLinux ARM 64bit Shellcode") - ql = Qiling(code=ARM64_LIN, archtype="arm64", ostype="linux", verbose=QL_VERBOSE.DEBUG) + ql = Qiling(code=ARM64_LIN, archtype=QL_ARCH.ARM64, ostype=QL_OS.LINUX, verbose=QL_VERBOSE.DEBUG) ql.run() print("\nLinux ARM 32bit Shellcode") - ql = Qiling(code=ARM_LIN, archtype="arm", ostype="linux", verbose=QL_VERBOSE.DEBUG) + ql = Qiling(code=ARM_LIN, archtype=QL_ARCH.ARM, ostype=QL_OS.LINUX, verbose=QL_VERBOSE.DEBUG) ql.run() - print("\nLinux X86 32bit Shellcode") - ql = Qiling(code=X86_LIN, archtype="x86", ostype="linux", verbose=QL_VERBOSE.DEBUG) + print("\nLinux x86 32bit Shellcode") + ql = Qiling(code=X86_LIN, archtype=QL_ARCH.X86, ostype=QL_OS.LINUX, verbose=QL_VERBOSE.DEBUG) ql.run() print("\nLinux MIPS 32bit EL Shellcode") - ql = Qiling(code=MIPS32EL_LIN, archtype="mips", ostype="linux", verbose=QL_VERBOSE.DEBUG) + ql = Qiling(code=MIPS32EL_LIN, archtype=QL_ARCH.MIPS, ostype=QL_OS.LINUX, verbose=QL_VERBOSE.DEBUG) ql.run() - print("\nLinux X86 64bit Shellcode") - ql = Qiling(code=X8664_LIN, archtype="x8664", ostype="linux", verbose=QL_VERBOSE.DEBUG) + print("\nLinux x86-64 Shellcode") + ql = Qiling(code=X8664_LIN, archtype=QL_ARCH.X8664, ostype=QL_OS.LINUX, verbose=QL_VERBOSE.DEBUG) ql.run() - print("\nWindows X86 32bit Shellcode") - ql = Qiling(code=X86_WIN, archtype="x86", ostype="windows", rootfs="rootfs/x86_windows") + print("\nWindows x86 Shellcode") + ql = Qiling(code=X86_WIN, archtype=QL_ARCH.X86, ostype=QL_OS.WINDOWS, rootfs=r'rootfs/x86_windows') ql.run() - print("\nWindows X8664 64bit Shellcode") - ql = Qiling(code=X8664_WIN, archtype="x8664", ostype="windows", rootfs="rootfs/x8664_windows") + print("\nWindows x86-64 Shellcode") + ql = Qiling(code=X8664_WIN, archtype=QL_ARCH.X8664, ostype=QL_OS.WINDOWS, rootfs=r'rootfs/x8664_windows') ql.run() - print("\nFreeBSD X86 64bit Shellcode") - ql = Qiling(code=X8664_FBSD, archtype="x8664", ostype="freebsd", verbose=QL_VERBOSE.DEBUG) - ql.run() + # FIXME: freebsd sockets are currently broken. + # + # print("\nFreeBSD x86-64 Shellcode") + # ql = Qiling(code=X8664_FBSD, archtype=QL_ARCH.X8664, ostype=QL_OS.FREEBSD, verbose=QL_VERBOSE.DEBUG) + # ql.run() - print("\nmacos X86 64bit Shellcode") - ql = Qiling(code=X8664_MACOS, archtype="x8664", ostype="macos", verbose=QL_VERBOSE.DEBUG) - ql.run() + # FIXME: macos shellcode loader is currently broken + # + # print("\nMacOS x86-64 Shellcode") + # ql = Qiling(code=X8664_MACOS, archtype=QL_ARCH.X8664, ostype=QL_OS.MACOS, verbose=QL_VERBOSE.DEBUG) + # ql.run() diff --git a/examples/src/linux/armeb_hello b/examples/src/linux/armeb_hello new file mode 100755 index 000000000..1da07e674 Binary files /dev/null and b/examples/src/linux/armeb_hello differ diff --git a/examples/src/linux/armeb_hello_static b/examples/src/linux/armeb_hello_static new file mode 100755 index 000000000..1da07e674 Binary files /dev/null and b/examples/src/linux/armeb_hello_static differ diff --git a/examples/src/linux/armeb_multithreading b/examples/src/linux/armeb_multithreading new file mode 100755 index 000000000..200cd7f9b Binary files /dev/null and b/examples/src/linux/armeb_multithreading differ diff --git a/examples/src/linux/armeb_puts b/examples/src/linux/armeb_puts new file mode 100755 index 000000000..c49a45444 Binary files /dev/null and b/examples/src/linux/armeb_puts differ diff --git a/examples/src/linux/armeb_tcp_test b/examples/src/linux/armeb_tcp_test new file mode 100755 index 000000000..c31bc69b8 Binary files /dev/null and b/examples/src/linux/armeb_tcp_test differ diff --git a/examples/src/linux/armeb_udp_test b/examples/src/linux/armeb_udp_test new file mode 100755 index 000000000..5524b07a2 Binary files /dev/null and b/examples/src/linux/armeb_udp_test differ diff --git a/examples/src/linux/picohttpd/Makefile b/examples/src/linux/picohttpd/Makefile index 8cd91a626..e6b0864d2 100644 --- a/examples/src/linux/picohttpd/Makefile +++ b/examples/src/linux/picohttpd/Makefile @@ -4,7 +4,6 @@ clean: @rm -rf *.o @rm -rf x64_server @rm -rf arm_server - @rm -rf armeb_server x64_server: main.o httpd.o gcc -o x64_server $^ diff --git a/examples/src/linux/picohttpd/picohttpd b/examples/src/linux/picohttpd/picohttpd new file mode 100755 index 000000000..90963e835 Binary files /dev/null and b/examples/src/linux/picohttpd/picohttpd differ diff --git a/examples/src/linux/picohttpd/readme.txt b/examples/src/linux/picohttpd/readme.txt index 32ad9edb1..3ebba350a 100644 --- a/examples/src/linux/picohttpd/readme.txt +++ b/examples/src/linux/picohttpd/readme.txt @@ -1 +1,3 @@ copy from: https://gist.github.com/laobubu/d6d0e9beb934b60b2e552c2d03e1409e + +compile armeb with https://crosstool-ng.github.io/docs/internals/ , with linux kernel diff --git a/qiling/arch/arch.py b/qiling/arch/arch.py index e1b84d186..0687d3dc2 100644 --- a/qiling/arch/arch.py +++ b/qiling/arch/arch.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # @@ -15,6 +15,7 @@ from .register import QlRegisterManager from .utils import QlArchUtils + class QlArch: type: QL_ARCH bits: int @@ -57,7 +58,6 @@ def stack_push(self, value: int) -> int: return self.regs.arch_sp - def stack_pop(self) -> int: """Pop a value from the architectural stack. @@ -69,7 +69,6 @@ def stack_pop(self) -> int: return data - def stack_read(self, offset: int) -> int: """Peek the architectural stack at a specified offset from its top, without affecting the top of the stack. @@ -86,7 +85,6 @@ def stack_read(self, offset: int) -> int: return self.ql.mem.read_ptr(self.regs.arch_sp + offset) - def stack_write(self, offset: int, value: int) -> None: """Write a value to the architectural stack at a specified offset from its top, without affecting the top of the stack. @@ -101,17 +99,14 @@ def stack_write(self, offset: int, value: int) -> None: self.ql.mem.write_ptr(self.regs.arch_sp + offset, value) - # Unicorn's CPU state save def save(self) -> UcContext: return self.uc.context_save() - # Unicorn's CPU state restore method def restore(self, saved_context: UcContext): self.uc.context_restore(saved_context) - @property @abstractmethod def disassembler(self) -> Cs: @@ -120,7 +115,6 @@ def disassembler(self) -> Cs: pass - @property @abstractmethod def assembler(self) -> Ks: @@ -135,4 +129,4 @@ def endian(self) -> QL_ENDIAN: """Get processor endianess. """ - pass \ No newline at end of file + pass diff --git a/qiling/arch/arm.py b/qiling/arch/arm.py index 394258f79..b290ee8e5 100644 --- a/qiling/arch/arm.py +++ b/qiling/arch/arm.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # @@ -15,6 +15,7 @@ from qiling.arch.register import QlRegisterManager from qiling.const import QL_ARCH, QL_ENDIAN + class QlArchARM(QlArch): type = QL_ARCH.ARM bits = 32 @@ -43,7 +44,9 @@ def uc(self) -> Uc: def regs(self) -> QlRegisterManager: regs_map = dict( **arm_const.reg_map, - **arm_const.reg_vfp + **arm_const.reg_vfp, + **arm_const.reg_map_q, + **arm_const.reg_map_s ) pc_reg = 'pc' @@ -65,7 +68,7 @@ def effective_pc(self) -> int: """ # append 1 to pc if in thumb mode, or 0 otherwise - return self.regs.pc + int(self.is_thumb) + return self.regs.pc | int(self.is_thumb) @property def disassembler(self) -> Cs: diff --git a/qiling/arch/arm64.py b/qiling/arch/arm64.py index 659496694..c7578fa62 100644 --- a/qiling/arch/arm64.py +++ b/qiling/arch/arm64.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # @@ -14,6 +14,7 @@ from qiling.arch.register import QlRegisterManager from qiling.const import QL_ARCH, QL_ENDIAN + class QlArchARM64(QlArch): type = QL_ARCH.ARM64 bits = 64 diff --git a/qiling/arch/arm64_const.py b/qiling/arch/arm64_const.py index ee2b55167..0845df59a 100644 --- a/qiling/arch/arm64_const.py +++ b/qiling/arch/arm64_const.py @@ -6,16 +6,16 @@ from unicorn.arm64_const import * reg_map = { - "x0": UC_ARM64_REG_X0, - "x1": UC_ARM64_REG_X1, - "x2": UC_ARM64_REG_X2, - "x3": UC_ARM64_REG_X3, - "x4": UC_ARM64_REG_X4, - "x5": UC_ARM64_REG_X5, - "x6": UC_ARM64_REG_X6, - "x7": UC_ARM64_REG_X7, - "x8": UC_ARM64_REG_X8, - "x9": UC_ARM64_REG_X9, + "x0": UC_ARM64_REG_X0, + "x1": UC_ARM64_REG_X1, + "x2": UC_ARM64_REG_X2, + "x3": UC_ARM64_REG_X3, + "x4": UC_ARM64_REG_X4, + "x5": UC_ARM64_REG_X5, + "x6": UC_ARM64_REG_X6, + "x7": UC_ARM64_REG_X7, + "x8": UC_ARM64_REG_X8, + "x9": UC_ARM64_REG_X9, "x10": UC_ARM64_REG_X10, "x11": UC_ARM64_REG_X11, "x12": UC_ARM64_REG_X12, @@ -41,249 +41,250 @@ "pc": UC_ARM64_REG_PC, "lr": UC_ARM64_REG_LR, "cpacr_el1": UC_ARM64_REG_CPACR_EL1, - "tpidr_el0": UC_ARM64_REG_TPIDR_EL0 + "tpidr_el0": UC_ARM64_REG_TPIDR_EL0, + "pstate": UC_ARM64_REG_PSTATE } reg_map_b = { - "b0" : UC_ARM64_REG_B0, - "b1" : UC_ARM64_REG_B1, - "b2" : UC_ARM64_REG_B2, - "b3" : UC_ARM64_REG_B3, - "b4" : UC_ARM64_REG_B4, - "b5" : UC_ARM64_REG_B5, - "b6" : UC_ARM64_REG_B6, - "b7" : UC_ARM64_REG_B7, - "b8" : UC_ARM64_REG_B8, - "b9" : UC_ARM64_REG_B9, - "b10" : UC_ARM64_REG_B10, - "b11" : UC_ARM64_REG_B11, - "b12" : UC_ARM64_REG_B12, - "b13" : UC_ARM64_REG_B13, - "b14" : UC_ARM64_REG_B14, - "b15" : UC_ARM64_REG_B15, - "b16" : UC_ARM64_REG_B16, - "b17" : UC_ARM64_REG_B17, - "b18" : UC_ARM64_REG_B18, - "b19" : UC_ARM64_REG_B19, - "b20" : UC_ARM64_REG_B20, - "b21" : UC_ARM64_REG_B21, - "b22" : UC_ARM64_REG_B22, - "b23" : UC_ARM64_REG_B23, - "b24" : UC_ARM64_REG_B24, - "b25" : UC_ARM64_REG_B25, - "b26" : UC_ARM64_REG_B26, - "b27" : UC_ARM64_REG_B27, - "b28" : UC_ARM64_REG_B28, - "b29" : UC_ARM64_REG_B29, - "b30" : UC_ARM64_REG_B30, - "b31" : UC_ARM64_REG_B31 + "b0": UC_ARM64_REG_B0, + "b1": UC_ARM64_REG_B1, + "b2": UC_ARM64_REG_B2, + "b3": UC_ARM64_REG_B3, + "b4": UC_ARM64_REG_B4, + "b5": UC_ARM64_REG_B5, + "b6": UC_ARM64_REG_B6, + "b7": UC_ARM64_REG_B7, + "b8": UC_ARM64_REG_B8, + "b9": UC_ARM64_REG_B9, + "b10": UC_ARM64_REG_B10, + "b11": UC_ARM64_REG_B11, + "b12": UC_ARM64_REG_B12, + "b13": UC_ARM64_REG_B13, + "b14": UC_ARM64_REG_B14, + "b15": UC_ARM64_REG_B15, + "b16": UC_ARM64_REG_B16, + "b17": UC_ARM64_REG_B17, + "b18": UC_ARM64_REG_B18, + "b19": UC_ARM64_REG_B19, + "b20": UC_ARM64_REG_B20, + "b21": UC_ARM64_REG_B21, + "b22": UC_ARM64_REG_B22, + "b23": UC_ARM64_REG_B23, + "b24": UC_ARM64_REG_B24, + "b25": UC_ARM64_REG_B25, + "b26": UC_ARM64_REG_B26, + "b27": UC_ARM64_REG_B27, + "b28": UC_ARM64_REG_B28, + "b29": UC_ARM64_REG_B29, + "b30": UC_ARM64_REG_B30, + "b31": UC_ARM64_REG_B31 } reg_map_d = { - "d0" : UC_ARM64_REG_D0, - "d1" : UC_ARM64_REG_D1, - "d2" : UC_ARM64_REG_D2, - "d3" : UC_ARM64_REG_D3, - "d4" : UC_ARM64_REG_D4, - "d5" : UC_ARM64_REG_D5, - "d6" : UC_ARM64_REG_D6, - "d7" : UC_ARM64_REG_D7, - "d8" : UC_ARM64_REG_D8, - "d9" : UC_ARM64_REG_D9, - "d10" : UC_ARM64_REG_D10, - "d11" : UC_ARM64_REG_D11, - "d12" : UC_ARM64_REG_D12, - "d13" : UC_ARM64_REG_D13, - "d14" : UC_ARM64_REG_D14, - "d15" : UC_ARM64_REG_D15, - "d16" : UC_ARM64_REG_D16, - "d17" : UC_ARM64_REG_D17, - "d18" : UC_ARM64_REG_D18, - "d19" : UC_ARM64_REG_D19, - "d20" : UC_ARM64_REG_D20, - "d21" : UC_ARM64_REG_D21, - "d22" : UC_ARM64_REG_D22, - "d23" : UC_ARM64_REG_D23, - "d24" : UC_ARM64_REG_D24, - "d25" : UC_ARM64_REG_D25, - "d26" : UC_ARM64_REG_D26, - "d27" : UC_ARM64_REG_D27, - "d28" : UC_ARM64_REG_D28, - "d29" : UC_ARM64_REG_D29, - "d30" : UC_ARM64_REG_D30, - "d31" : UC_ARM64_REG_D31 + "d0": UC_ARM64_REG_D0, + "d1": UC_ARM64_REG_D1, + "d2": UC_ARM64_REG_D2, + "d3": UC_ARM64_REG_D3, + "d4": UC_ARM64_REG_D4, + "d5": UC_ARM64_REG_D5, + "d6": UC_ARM64_REG_D6, + "d7": UC_ARM64_REG_D7, + "d8": UC_ARM64_REG_D8, + "d9": UC_ARM64_REG_D9, + "d10": UC_ARM64_REG_D10, + "d11": UC_ARM64_REG_D11, + "d12": UC_ARM64_REG_D12, + "d13": UC_ARM64_REG_D13, + "d14": UC_ARM64_REG_D14, + "d15": UC_ARM64_REG_D15, + "d16": UC_ARM64_REG_D16, + "d17": UC_ARM64_REG_D17, + "d18": UC_ARM64_REG_D18, + "d19": UC_ARM64_REG_D19, + "d20": UC_ARM64_REG_D20, + "d21": UC_ARM64_REG_D21, + "d22": UC_ARM64_REG_D22, + "d23": UC_ARM64_REG_D23, + "d24": UC_ARM64_REG_D24, + "d25": UC_ARM64_REG_D25, + "d26": UC_ARM64_REG_D26, + "d27": UC_ARM64_REG_D27, + "d28": UC_ARM64_REG_D28, + "d29": UC_ARM64_REG_D29, + "d30": UC_ARM64_REG_D30, + "d31": UC_ARM64_REG_D31 } reg_map_h = { - "h0" : UC_ARM64_REG_H0, - "h1" : UC_ARM64_REG_H1, - "h2" : UC_ARM64_REG_H2, - "h3" : UC_ARM64_REG_H3, - "h4" : UC_ARM64_REG_H4, - "h5" : UC_ARM64_REG_H5, - "h6" : UC_ARM64_REG_H6, - "h7" : UC_ARM64_REG_H7, - "h8" : UC_ARM64_REG_H8, - "h9" : UC_ARM64_REG_H9, - "h10" : UC_ARM64_REG_H10, - "h11" : UC_ARM64_REG_H11, - "h12" : UC_ARM64_REG_H12, - "h13" : UC_ARM64_REG_H13, - "h14" : UC_ARM64_REG_H14, - "h15" : UC_ARM64_REG_H15, - "h16" : UC_ARM64_REG_H16, - "h17" : UC_ARM64_REG_H17, - "h18" : UC_ARM64_REG_H18, - "h19" : UC_ARM64_REG_H19, - "h20" : UC_ARM64_REG_H20, - "h21" : UC_ARM64_REG_H21, - "h22" : UC_ARM64_REG_H22, - "h23" : UC_ARM64_REG_H23, - "h24" : UC_ARM64_REG_H24, - "h25" : UC_ARM64_REG_H25, - "h26" : UC_ARM64_REG_H26, - "h27" : UC_ARM64_REG_H27, - "h28" : UC_ARM64_REG_H28, - "h29" : UC_ARM64_REG_H29, - "h30" : UC_ARM64_REG_H30, - "h31" : UC_ARM64_REG_H31 + "h0": UC_ARM64_REG_H0, + "h1": UC_ARM64_REG_H1, + "h2": UC_ARM64_REG_H2, + "h3": UC_ARM64_REG_H3, + "h4": UC_ARM64_REG_H4, + "h5": UC_ARM64_REG_H5, + "h6": UC_ARM64_REG_H6, + "h7": UC_ARM64_REG_H7, + "h8": UC_ARM64_REG_H8, + "h9": UC_ARM64_REG_H9, + "h10": UC_ARM64_REG_H10, + "h11": UC_ARM64_REG_H11, + "h12": UC_ARM64_REG_H12, + "h13": UC_ARM64_REG_H13, + "h14": UC_ARM64_REG_H14, + "h15": UC_ARM64_REG_H15, + "h16": UC_ARM64_REG_H16, + "h17": UC_ARM64_REG_H17, + "h18": UC_ARM64_REG_H18, + "h19": UC_ARM64_REG_H19, + "h20": UC_ARM64_REG_H20, + "h21": UC_ARM64_REG_H21, + "h22": UC_ARM64_REG_H22, + "h23": UC_ARM64_REG_H23, + "h24": UC_ARM64_REG_H24, + "h25": UC_ARM64_REG_H25, + "h26": UC_ARM64_REG_H26, + "h27": UC_ARM64_REG_H27, + "h28": UC_ARM64_REG_H28, + "h29": UC_ARM64_REG_H29, + "h30": UC_ARM64_REG_H30, + "h31": UC_ARM64_REG_H31 } reg_map_q = { - "q0" : UC_ARM64_REG_Q0, - "q1" : UC_ARM64_REG_Q1, - "q2" : UC_ARM64_REG_Q2, - "q3" : UC_ARM64_REG_Q3, - "q4" : UC_ARM64_REG_Q4, - "q5" : UC_ARM64_REG_Q5, - "q6" : UC_ARM64_REG_Q6, - "q7" : UC_ARM64_REG_Q7, - "q8" : UC_ARM64_REG_Q8, - "q9" : UC_ARM64_REG_Q9, - "q10" : UC_ARM64_REG_Q10, - "q11" : UC_ARM64_REG_Q11, - "q12" : UC_ARM64_REG_Q12, - "q13" : UC_ARM64_REG_Q13, - "q14" : UC_ARM64_REG_Q14, - "q15" : UC_ARM64_REG_Q15, - "q16" : UC_ARM64_REG_Q16, - "q17" : UC_ARM64_REG_Q17, - "q18" : UC_ARM64_REG_Q18, - "q19" : UC_ARM64_REG_Q19, - "q20" : UC_ARM64_REG_Q20, - "q21" : UC_ARM64_REG_Q21, - "q22" : UC_ARM64_REG_Q22, - "q23" : UC_ARM64_REG_Q23, - "q24" : UC_ARM64_REG_Q24, - "q25" : UC_ARM64_REG_Q25, - "q26" : UC_ARM64_REG_Q26, - "q27" : UC_ARM64_REG_Q27, - "q28" : UC_ARM64_REG_Q28, - "q29" : UC_ARM64_REG_Q29, - "q30" : UC_ARM64_REG_Q30, - "q31" : UC_ARM64_REG_Q31 + "q0": UC_ARM64_REG_Q0, + "q1": UC_ARM64_REG_Q1, + "q2": UC_ARM64_REG_Q2, + "q3": UC_ARM64_REG_Q3, + "q4": UC_ARM64_REG_Q4, + "q5": UC_ARM64_REG_Q5, + "q6": UC_ARM64_REG_Q6, + "q7": UC_ARM64_REG_Q7, + "q8": UC_ARM64_REG_Q8, + "q9": UC_ARM64_REG_Q9, + "q10": UC_ARM64_REG_Q10, + "q11": UC_ARM64_REG_Q11, + "q12": UC_ARM64_REG_Q12, + "q13": UC_ARM64_REG_Q13, + "q14": UC_ARM64_REG_Q14, + "q15": UC_ARM64_REG_Q15, + "q16": UC_ARM64_REG_Q16, + "q17": UC_ARM64_REG_Q17, + "q18": UC_ARM64_REG_Q18, + "q19": UC_ARM64_REG_Q19, + "q20": UC_ARM64_REG_Q20, + "q21": UC_ARM64_REG_Q21, + "q22": UC_ARM64_REG_Q22, + "q23": UC_ARM64_REG_Q23, + "q24": UC_ARM64_REG_Q24, + "q25": UC_ARM64_REG_Q25, + "q26": UC_ARM64_REG_Q26, + "q27": UC_ARM64_REG_Q27, + "q28": UC_ARM64_REG_Q28, + "q29": UC_ARM64_REG_Q29, + "q30": UC_ARM64_REG_Q30, + "q31": UC_ARM64_REG_Q31 } reg_map_s = { - "s0" : UC_ARM64_REG_S0, - "s1" : UC_ARM64_REG_S1, - "s2" : UC_ARM64_REG_S2, - "s3" : UC_ARM64_REG_S3, - "s4" : UC_ARM64_REG_S4, - "s5" : UC_ARM64_REG_S5, - "s6" : UC_ARM64_REG_S6, - "s7" : UC_ARM64_REG_S7, - "s8" : UC_ARM64_REG_S8, - "s9" : UC_ARM64_REG_S9, - "s10" : UC_ARM64_REG_S10, - "s11" : UC_ARM64_REG_S11, - "s12" : UC_ARM64_REG_S12, - "s13" : UC_ARM64_REG_S13, - "s14" : UC_ARM64_REG_S14, - "s15" : UC_ARM64_REG_S15, - "s16" : UC_ARM64_REG_S16, - "s17" : UC_ARM64_REG_S17, - "s18" : UC_ARM64_REG_S18, - "s19" : UC_ARM64_REG_S19, - "s20" : UC_ARM64_REG_S20, - "s21" : UC_ARM64_REG_S21, - "s22" : UC_ARM64_REG_S22, - "s23" : UC_ARM64_REG_S23, - "s24" : UC_ARM64_REG_S24, - "s25" : UC_ARM64_REG_S25, - "s26" : UC_ARM64_REG_S26, - "s27" : UC_ARM64_REG_S27, - "s28" : UC_ARM64_REG_S28, - "s29" : UC_ARM64_REG_S29, - "s30" : UC_ARM64_REG_S30, - "s31" : UC_ARM64_REG_S31 + "s0": UC_ARM64_REG_S0, + "s1": UC_ARM64_REG_S1, + "s2": UC_ARM64_REG_S2, + "s3": UC_ARM64_REG_S3, + "s4": UC_ARM64_REG_S4, + "s5": UC_ARM64_REG_S5, + "s6": UC_ARM64_REG_S6, + "s7": UC_ARM64_REG_S7, + "s8": UC_ARM64_REG_S8, + "s9": UC_ARM64_REG_S9, + "s10": UC_ARM64_REG_S10, + "s11": UC_ARM64_REG_S11, + "s12": UC_ARM64_REG_S12, + "s13": UC_ARM64_REG_S13, + "s14": UC_ARM64_REG_S14, + "s15": UC_ARM64_REG_S15, + "s16": UC_ARM64_REG_S16, + "s17": UC_ARM64_REG_S17, + "s18": UC_ARM64_REG_S18, + "s19": UC_ARM64_REG_S19, + "s20": UC_ARM64_REG_S20, + "s21": UC_ARM64_REG_S21, + "s22": UC_ARM64_REG_S22, + "s23": UC_ARM64_REG_S23, + "s24": UC_ARM64_REG_S24, + "s25": UC_ARM64_REG_S25, + "s26": UC_ARM64_REG_S26, + "s27": UC_ARM64_REG_S27, + "s28": UC_ARM64_REG_S28, + "s29": UC_ARM64_REG_S29, + "s30": UC_ARM64_REG_S30, + "s31": UC_ARM64_REG_S31 } reg_map_w = { - "w0" : UC_ARM64_REG_W0, - "w1" : UC_ARM64_REG_W1, - "w2" : UC_ARM64_REG_W2, - "w3" : UC_ARM64_REG_W3, - "w4" : UC_ARM64_REG_W4, - "w5" : UC_ARM64_REG_W5, - "w6" : UC_ARM64_REG_W6, - "w7" : UC_ARM64_REG_W7, - "w8" : UC_ARM64_REG_W8, - "w9" : UC_ARM64_REG_W9, - "w10" : UC_ARM64_REG_W10, - "w11" : UC_ARM64_REG_W11, - "w12" : UC_ARM64_REG_W12, - "w13" : UC_ARM64_REG_W13, - "w14" : UC_ARM64_REG_W14, - "w15" : UC_ARM64_REG_W15, - "w16" : UC_ARM64_REG_W16, - "w17" : UC_ARM64_REG_W17, - "w18" : UC_ARM64_REG_W18, - "w19" : UC_ARM64_REG_W19, - "w20" : UC_ARM64_REG_W20, - "w21" : UC_ARM64_REG_W21, - "w22" : UC_ARM64_REG_W22, - "w23" : UC_ARM64_REG_W23, - "w24" : UC_ARM64_REG_W24, - "w25" : UC_ARM64_REG_W25, - "w26" : UC_ARM64_REG_W26, - "w27" : UC_ARM64_REG_W27, - "w28" : UC_ARM64_REG_W28, - "w29" : UC_ARM64_REG_W29, - "w30" : UC_ARM64_REG_W30 + "w0": UC_ARM64_REG_W0, + "w1": UC_ARM64_REG_W1, + "w2": UC_ARM64_REG_W2, + "w3": UC_ARM64_REG_W3, + "w4": UC_ARM64_REG_W4, + "w5": UC_ARM64_REG_W5, + "w6": UC_ARM64_REG_W6, + "w7": UC_ARM64_REG_W7, + "w8": UC_ARM64_REG_W8, + "w9": UC_ARM64_REG_W9, + "w10": UC_ARM64_REG_W10, + "w11": UC_ARM64_REG_W11, + "w12": UC_ARM64_REG_W12, + "w13": UC_ARM64_REG_W13, + "w14": UC_ARM64_REG_W14, + "w15": UC_ARM64_REG_W15, + "w16": UC_ARM64_REG_W16, + "w17": UC_ARM64_REG_W17, + "w18": UC_ARM64_REG_W18, + "w19": UC_ARM64_REG_W19, + "w20": UC_ARM64_REG_W20, + "w21": UC_ARM64_REG_W21, + "w22": UC_ARM64_REG_W22, + "w23": UC_ARM64_REG_W23, + "w24": UC_ARM64_REG_W24, + "w25": UC_ARM64_REG_W25, + "w26": UC_ARM64_REG_W26, + "w27": UC_ARM64_REG_W27, + "w28": UC_ARM64_REG_W28, + "w29": UC_ARM64_REG_W29, + "w30": UC_ARM64_REG_W30 } reg_map_v = { - "v0" : UC_ARM64_REG_V0, - "v1" : UC_ARM64_REG_V1, - "v2" : UC_ARM64_REG_V2, - "v3" : UC_ARM64_REG_V3, - "v4" : UC_ARM64_REG_V4, - "v5" : UC_ARM64_REG_V5, - "v6" : UC_ARM64_REG_V6, - "v7" : UC_ARM64_REG_V7, - "v8" : UC_ARM64_REG_V8, - "v9" : UC_ARM64_REG_V9, - "v10" : UC_ARM64_REG_V10, - "v11" : UC_ARM64_REG_V11, - "v12" : UC_ARM64_REG_V12, - "v13" : UC_ARM64_REG_V13, - "v14" : UC_ARM64_REG_V14, - "v15" : UC_ARM64_REG_V15, - "v16" : UC_ARM64_REG_V16, - "v17" : UC_ARM64_REG_V17, - "v18" : UC_ARM64_REG_V18, - "v19" : UC_ARM64_REG_V19, - "v20" : UC_ARM64_REG_V20, - "v21" : UC_ARM64_REG_V21, - "v22" : UC_ARM64_REG_V22, - "v23" : UC_ARM64_REG_V23, - "v24" : UC_ARM64_REG_V24, - "v25" : UC_ARM64_REG_V25, - "v26" : UC_ARM64_REG_V26, - "v27" : UC_ARM64_REG_V27, - "v28" : UC_ARM64_REG_V28, - "v29" : UC_ARM64_REG_V29, - "v30" : UC_ARM64_REG_V30, - "v31" : UC_ARM64_REG_V31 + "v0": UC_ARM64_REG_V0, + "v1": UC_ARM64_REG_V1, + "v2": UC_ARM64_REG_V2, + "v3": UC_ARM64_REG_V3, + "v4": UC_ARM64_REG_V4, + "v5": UC_ARM64_REG_V5, + "v6": UC_ARM64_REG_V6, + "v7": UC_ARM64_REG_V7, + "v8": UC_ARM64_REG_V8, + "v9": UC_ARM64_REG_V9, + "v10": UC_ARM64_REG_V10, + "v11": UC_ARM64_REG_V11, + "v12": UC_ARM64_REG_V12, + "v13": UC_ARM64_REG_V13, + "v14": UC_ARM64_REG_V14, + "v15": UC_ARM64_REG_V15, + "v16": UC_ARM64_REG_V16, + "v17": UC_ARM64_REG_V17, + "v18": UC_ARM64_REG_V18, + "v19": UC_ARM64_REG_V19, + "v20": UC_ARM64_REG_V20, + "v21": UC_ARM64_REG_V21, + "v22": UC_ARM64_REG_V22, + "v23": UC_ARM64_REG_V23, + "v24": UC_ARM64_REG_V24, + "v25": UC_ARM64_REG_V25, + "v26": UC_ARM64_REG_V26, + "v27": UC_ARM64_REG_V27, + "v28": UC_ARM64_REG_V28, + "v29": UC_ARM64_REG_V29, + "v30": UC_ARM64_REG_V30, + "v31": UC_ARM64_REG_V31 } diff --git a/qiling/arch/arm_const.py b/qiling/arch/arm_const.py index 2a268cdfd..1726a8071 100644 --- a/qiling/arch/arm_const.py +++ b/qiling/arch/arm_const.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # @@ -30,37 +30,91 @@ } reg_vfp = { - "d0" : UC_ARM_REG_D0, - "d1" : UC_ARM_REG_D1, - "d2" : UC_ARM_REG_D2, - "d3" : UC_ARM_REG_D3, - "d4" : UC_ARM_REG_D4, - "d5" : UC_ARM_REG_D5, - "d6" : UC_ARM_REG_D6, - "d7" : UC_ARM_REG_D7, - "d8" : UC_ARM_REG_D8, - "d9" : UC_ARM_REG_D9, - "d10" : UC_ARM_REG_D10, - "d11" : UC_ARM_REG_D11, - "d12" : UC_ARM_REG_D12, - "d13" : UC_ARM_REG_D13, - "d14" : UC_ARM_REG_D14, - "d15" : UC_ARM_REG_D15, - "d16" : UC_ARM_REG_D16, - "d17" : UC_ARM_REG_D17, - "d18" : UC_ARM_REG_D18, - "d19" : UC_ARM_REG_D19, - "d20" : UC_ARM_REG_D20, - "d21" : UC_ARM_REG_D21, - "d22" : UC_ARM_REG_D22, - "d23" : UC_ARM_REG_D23, - "d24" : UC_ARM_REG_D24, - "d25" : UC_ARM_REG_D25, - "d26" : UC_ARM_REG_D26, - "d27" : UC_ARM_REG_D27, - "d28" : UC_ARM_REG_D28, - "d29" : UC_ARM_REG_D29, - "d30" : UC_ARM_REG_D30, - "d31" : UC_ARM_REG_D31, - "fpscr" : UC_ARM_REG_FPSCR + "d0": UC_ARM_REG_D0, + "d1": UC_ARM_REG_D1, + "d2": UC_ARM_REG_D2, + "d3": UC_ARM_REG_D3, + "d4": UC_ARM_REG_D4, + "d5": UC_ARM_REG_D5, + "d6": UC_ARM_REG_D6, + "d7": UC_ARM_REG_D7, + "d8": UC_ARM_REG_D8, + "d9": UC_ARM_REG_D9, + "d10": UC_ARM_REG_D10, + "d11": UC_ARM_REG_D11, + "d12": UC_ARM_REG_D12, + "d13": UC_ARM_REG_D13, + "d14": UC_ARM_REG_D14, + "d15": UC_ARM_REG_D15, + "d16": UC_ARM_REG_D16, + "d17": UC_ARM_REG_D17, + "d18": UC_ARM_REG_D18, + "d19": UC_ARM_REG_D19, + "d20": UC_ARM_REG_D20, + "d21": UC_ARM_REG_D21, + "d22": UC_ARM_REG_D22, + "d23": UC_ARM_REG_D23, + "d24": UC_ARM_REG_D24, + "d25": UC_ARM_REG_D25, + "d26": UC_ARM_REG_D26, + "d27": UC_ARM_REG_D27, + "d28": UC_ARM_REG_D28, + "d29": UC_ARM_REG_D29, + "d30": UC_ARM_REG_D30, + "d31": UC_ARM_REG_D31, + "fpscr": UC_ARM_REG_FPSCR +} + +reg_map_q = { + "q0": UC_ARM_REG_Q0, + "q1": UC_ARM_REG_Q1, + "q2": UC_ARM_REG_Q2, + "q3": UC_ARM_REG_Q3, + "q4": UC_ARM_REG_Q4, + "q5": UC_ARM_REG_Q5, + "q6": UC_ARM_REG_Q6, + "q7": UC_ARM_REG_Q7, + "q8": UC_ARM_REG_Q8, + "q9": UC_ARM_REG_Q9, + "q10": UC_ARM_REG_Q10, + "q11": UC_ARM_REG_Q11, + "q12": UC_ARM_REG_Q12, + "q13": UC_ARM_REG_Q13, + "q14": UC_ARM_REG_Q14, + "q15": UC_ARM_REG_Q15 +} + +reg_map_s = { + "s0": UC_ARM_REG_S0, + "s1": UC_ARM_REG_S1, + "s2": UC_ARM_REG_S2, + "s3": UC_ARM_REG_S3, + "s4": UC_ARM_REG_S4, + "s5": UC_ARM_REG_S5, + "s6": UC_ARM_REG_S6, + "s7": UC_ARM_REG_S7, + "s8": UC_ARM_REG_S8, + "s9": UC_ARM_REG_S9, + "s10": UC_ARM_REG_S10, + "s11": UC_ARM_REG_S11, + "s12": UC_ARM_REG_S12, + "s13": UC_ARM_REG_S13, + "s14": UC_ARM_REG_S14, + "s15": UC_ARM_REG_S15, + "s16": UC_ARM_REG_S16, + "s17": UC_ARM_REG_S17, + "s18": UC_ARM_REG_S18, + "s19": UC_ARM_REG_S19, + "s20": UC_ARM_REG_S20, + "s21": UC_ARM_REG_S21, + "s22": UC_ARM_REG_S22, + "s23": UC_ARM_REG_S23, + "s24": UC_ARM_REG_S24, + "s25": UC_ARM_REG_S25, + "s26": UC_ARM_REG_S26, + "s27": UC_ARM_REG_S27, + "s28": UC_ARM_REG_S28, + "s29": UC_ARM_REG_S29, + "s30": UC_ARM_REG_S30, + "s31": UC_ARM_REG_S31 } diff --git a/qiling/arch/arm_utils.py b/qiling/arch/arm_utils.py index 3f7ff87f5..14181a699 100644 --- a/qiling/arch/arm_utils.py +++ b/qiling/arch/arm_utils.py @@ -1,11 +1,12 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # from qiling import Qiling from qiling.const import QL_ENDIAN + def init_linux_traps(ql: Qiling, address_map) -> None: # If the compiler for the target does not provides some primitives for some # reasons (e.g. target limitations), the kernel is responsible to assist @@ -84,7 +85,8 @@ def init_linux_traps(ql: Qiling, address_map) -> None: ql.log.debug(f'Set kernel trap: {trap_name} at {address_map[trap_name]:#x}') + def swap_endianness(s: bytes, blksize: int = 4) -> bytes: blocks = (s[i:i + blksize] for i in range(0, len(s), blksize)) - return b''.join(bytes(reversed(b)) for b in blocks) \ No newline at end of file + return b''.join(bytes(reversed(b)) for b in blocks) diff --git a/qiling/arch/cortex_m.py b/qiling/arch/cortex_m.py index a9e0a64ee..3d3419f39 100644 --- a/qiling/arch/cortex_m.py +++ b/qiling/arch/cortex_m.py @@ -1,12 +1,12 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # from functools import cached_property from contextlib import ContextDecorator -from unicorn import Uc, UC_ARCH_ARM, UC_MODE_ARM, UC_MODE_MCLASS, UC_MODE_THUMB +from unicorn import UC_ARCH_ARM, UC_MODE_ARM, UC_MODE_MCLASS, UC_MODE_THUMB from capstone import Cs, CS_ARCH_ARM, CS_MODE_ARM, CS_MODE_MCLASS, CS_MODE_THUMB from keystone import Ks, KS_ARCH_ARM, KS_MODE_ARM, KS_MODE_THUMB @@ -17,6 +17,8 @@ from qiling.arch.cortex_m_const import IRQ, EXC_RETURN, CONTROL, EXCP from qiling.const import QL_ARCH, QL_ENDIAN, QL_VERBOSE from qiling.exception import QlErrorNotImplemented +from qiling.extensions.multitask import MultiTaskUnicorn + class QlInterruptContext(ContextDecorator): def __init__(self, ql: Qiling): @@ -27,7 +29,7 @@ def __enter__(self): for reg in self.reg_context: val = self.ql.arch.regs.read(reg) self.ql.arch.stack_push(val) - + if self.ql.verbose >= QL_VERBOSE.DISASM: self.ql.log.info(f'Enter into interrupt') @@ -44,23 +46,24 @@ def __exit__(self, *exc): # switch the stack accroding exc_return old_ctrl = self.ql.arch.regs.read('control') if retval & EXC_RETURN.RETURN_SP: - self.ql.arch.regs.write('control', old_ctrl | CONTROL.SPSEL) + self.ql.arch.regs.write('control', old_ctrl | CONTROL.SPSEL) else: self.ql.arch.regs.write('control', old_ctrl & ~CONTROL.SPSEL) # Restore stack for reg in reversed(self.reg_context): val = self.ql.arch.stack_pop() - if reg == 'xpsr': + if reg == 'xpsr': self.ql.arch.regs.write('XPSR_NZCVQG', val) else: - self.ql.arch.regs.write(reg, val) + self.ql.arch.regs.write(reg, val) if self.ql.verbose >= QL_VERBOSE.DISASM: self.ql.log.info('Exit from interrupt') + class QlArchCORTEX_M(QlArchARM): - type = QL_ARCH.ARM + type = QL_ARCH.CORTEX_M bits = 32 def __init__(self, ql: Qiling): @@ -68,7 +71,7 @@ def __init__(self, ql: Qiling): @cached_property def uc(self): - return Uc(UC_ARCH_ARM, UC_MODE_ARM + UC_MODE_MCLASS + UC_MODE_THUMB) + return MultiTaskUnicorn(UC_ARCH_ARM, UC_MODE_ARM + UC_MODE_MCLASS + UC_MODE_THUMB, 10) @cached_property def regs(self) -> QlRegisterManager: @@ -94,27 +97,6 @@ def is_thumb(self) -> bool: def endian(self) -> QL_ENDIAN: return QL_ENDIAN.EL - def step(self): - self.ql.emu_start(self.effective_pc, 0, count=1) - self.ql.hw.step() - - def stop(self): - self.ql.emu_stop() - self.runable = False - - def run(self, count=-1, end=None): - self.runable = True - - if type(end) is int: - end |= 1 - - while self.runable and count != 0: - if self.effective_pc == end: - break - - self.step() - count -= 1 - def is_handler_mode(self): return self.regs.ipsr > 1 @@ -126,7 +108,7 @@ def init_context(self): self.regs.msp = self.ql.mem.read_ptr(0x0) self.regs.pc = self.ql.mem.read_ptr(0x4) - def soft_interrupt_handler(self, ql, intno): + def unicorn_exception_handler(self, ql, intno): forward_mapper = { EXCP.UDEF : IRQ.HARD_FAULT, # undefined instruction EXCP.SWI : IRQ.SVCALL, # software interrupt @@ -157,7 +139,7 @@ def soft_interrupt_handler(self, ql, intno): except IndexError: raise QlErrorNotImplemented(f'Unhandled interrupt number ({intno})') - def hard_interrupt_handler(self, ql, intno): + def interrupt_handler(self, ql, intno): basepri = self.regs.basepri & 0xf0 if basepri and basepri <= ql.hw.nvic.get_priority(intno): return @@ -176,10 +158,10 @@ def hard_interrupt_handler(self, ql, intno): offset = isr * 4 entry = ql.mem.read_ptr(offset) - exc_return = 0xFFFFFFFD if self.using_psp() else 0xFFFFFFF9 + exc_return = 0xFFFFFFFD if self.using_psp() else 0xFFFFFFF9 self.regs.write('ipsr', isr) self.regs.write('pc', entry) - self.regs.write('lr', exc_return) + self.regs.write('lr', exc_return) - self.ql.emu_start(self.effective_pc, 0, count=0xffffff) + self.uc.emu_start(self.effective_pc, 0, 0, 0xffffff) diff --git a/qiling/arch/cortex_m_const.py b/qiling/arch/cortex_m_const.py index cae4f4393..8f915163d 100644 --- a/qiling/arch/cortex_m_const.py +++ b/qiling/arch/cortex_m_const.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # @@ -7,38 +7,39 @@ from enum import IntEnum reg_map = { - "r0": UC_ARM_REG_R0, - "r1": UC_ARM_REG_R1, - "r2": UC_ARM_REG_R2, - "r3": UC_ARM_REG_R3, - "r4": UC_ARM_REG_R4, - "r5": UC_ARM_REG_R5, - "r6": UC_ARM_REG_R6, - "r7": UC_ARM_REG_R7, - "r8": UC_ARM_REG_R8, - "r9": UC_ARM_REG_R9, - "r10": UC_ARM_REG_R10, + "r0": UC_ARM_REG_R0, + "r1": UC_ARM_REG_R1, + "r2": UC_ARM_REG_R2, + "r3": UC_ARM_REG_R3, + "r4": UC_ARM_REG_R4, + "r5": UC_ARM_REG_R5, + "r6": UC_ARM_REG_R6, + "r7": UC_ARM_REG_R7, + "r8": UC_ARM_REG_R8, + "r9": UC_ARM_REG_R9, + "r10": UC_ARM_REG_R10, "r11": UC_ARM_REG_R11, - "r12": UC_ARM_REG_R12, - "sp": UC_ARM_REG_SP, - "lr": UC_ARM_REG_LR, - "pc": UC_ARM_REG_PC, + "r12": UC_ARM_REG_R12, + "sp": UC_ARM_REG_SP, + "lr": UC_ARM_REG_LR, + "pc": UC_ARM_REG_PC, # cortex-M Special Register - "msp": UC_ARM_REG_MSP, - "psp": UC_ARM_REG_PSP, - "xpsr": UC_ARM_REG_XPSR, - "apsr": UC_ARM_REG_APSR, - "ipsr": UC_ARM_REG_IPSR, - "epsr": UC_ARM_REG_EPSR, - "primask": UC_ARM_REG_PRIMASK, + "msp": UC_ARM_REG_MSP, + "psp": UC_ARM_REG_PSP, + "xpsr": UC_ARM_REG_XPSR, + "apsr": UC_ARM_REG_APSR, + "ipsr": UC_ARM_REG_IPSR, + "epsr": UC_ARM_REG_EPSR, + "primask": UC_ARM_REG_PRIMASK, "faultmask": UC_ARM_REG_FAULTMASK, - "basepri": UC_ARM_REG_BASEPRI, - "control": UC_ARM_REG_CONTROL, + "basepri": UC_ARM_REG_BASEPRI, + "control": UC_ARM_REG_CONTROL, "xpsr_nzcvqg": UC_ARM_REG_XPSR_NZCVQG, } + class IRQ(IntEnum): NMI = -14 HARD_FAULT = -13 @@ -50,16 +51,19 @@ class IRQ(IntEnum): SYSTICK = -1 NOTHING = 0 + class CONTROL(IntEnum): FPCA = 0b100 SPSEL = 0b010 PRIV = 0b001 + class EXC_RETURN(IntEnum): MASK = 0xfffffff0 RETURN_SP = 0b0100 RETURN_MODE = 0b1000 + class EXCP(IntEnum): UDEF = 1 # undefined instruction SWI = 2 # software interrupt @@ -68,8 +72,8 @@ class EXCP(IntEnum): IRQ = 5 FIQ = 6 BKPT = 7 - EXCEPTION_EXIT = 8 # Return from v7M exception. - KERNEL_TRAP = 9 # Jumped to kernel code page. + EXCEPTION_EXIT = 8 # Return from v7M exception. + KERNEL_TRAP = 9 # Jumped to kernel code page. HVC = 11 # HyperVisor Call HYP_TRAP = 12 SMC = 13 # Secure Monitor Call diff --git a/qiling/arch/evm/__init__.py b/qiling/arch/evm/__init__.py index 2f003ebe7..1dcd2791f 100644 --- a/qiling/arch/evm/__init__.py +++ b/qiling/arch/evm/__init__.py @@ -1,9 +1,5 @@ import sys -# python 3.10 has not been supported yet in the latest blake2b-py release -if sys.version_info >= (3,10): - sys.exit('Sorry, Python > 3.10 is not supported for now') - # Ensure we can reach 1024 frames of recursion # EVM_RECURSION_LIMIT = 1024 * 12 diff --git a/qiling/arch/mips.py b/qiling/arch/mips.py index 9368634f2..5a32481dc 100644 --- a/qiling/arch/mips.py +++ b/qiling/arch/mips.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # @@ -15,6 +15,7 @@ from qiling.arch.register import QlRegisterManager from qiling.const import QL_ARCH, QL_ENDIAN + class QlArchMIPS(QlArch): type = QL_ARCH.MIPS bits = 32 @@ -49,8 +50,8 @@ def regs(self) -> QlRegisterManager: @cached_property def disassembler(self) -> Cs: endian = { - QL_ENDIAN.EL : CS_MODE_LITTLE_ENDIAN, - QL_ENDIAN.EB : CS_MODE_BIG_ENDIAN + QL_ENDIAN.EL: CS_MODE_LITTLE_ENDIAN, + QL_ENDIAN.EB: CS_MODE_BIG_ENDIAN }[self.endian] return Cs(CS_ARCH_MIPS, CS_MODE_MIPS32 + endian) @@ -58,8 +59,8 @@ def disassembler(self) -> Cs: @cached_property def assembler(self) -> Ks: endian = { - QL_ENDIAN.EL : KS_MODE_LITTLE_ENDIAN, - QL_ENDIAN.EB : KS_MODE_BIG_ENDIAN + QL_ENDIAN.EL: KS_MODE_LITTLE_ENDIAN, + QL_ENDIAN.EB: KS_MODE_BIG_ENDIAN }[self.endian] return Ks(KS_ARCH_MIPS, KS_MODE_MIPS32 + endian) diff --git a/qiling/arch/mips_const.py b/qiling/arch/mips_const.py index 8e3141f4f..1c4467ebb 100644 --- a/qiling/arch/mips_const.py +++ b/qiling/arch/mips_const.py @@ -1,120 +1,120 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # from unicorn.mips_const import * reg_map = { - "r0" : UC_MIPS_REG_0, - "r1" : UC_MIPS_REG_1, - "r2" : UC_MIPS_REG_2, - "r3" : UC_MIPS_REG_3, - "r4" : UC_MIPS_REG_4, - "r5" : UC_MIPS_REG_5, - "r6" : UC_MIPS_REG_6, - "r7" : UC_MIPS_REG_7, - "r8" : UC_MIPS_REG_8, - "r9" : UC_MIPS_REG_9, - "r10" : UC_MIPS_REG_10, - "r11" : UC_MIPS_REG_11, - "r12" : UC_MIPS_REG_12, - "r13" : UC_MIPS_REG_13, - "r14" : UC_MIPS_REG_14, - "r15" : UC_MIPS_REG_15, - "r16" : UC_MIPS_REG_16, - "r17" : UC_MIPS_REG_17, - "r18" : UC_MIPS_REG_18, - "r19" : UC_MIPS_REG_19, - "r20" : UC_MIPS_REG_20, - "r21" : UC_MIPS_REG_21, - "r22" : UC_MIPS_REG_22, - "r23" : UC_MIPS_REG_23, - "r24" : UC_MIPS_REG_24, - "r25" : UC_MIPS_REG_25, - "r26" : UC_MIPS_REG_26, - "r27" : UC_MIPS_REG_27, - "r28" : UC_MIPS_REG_28, - "r29" : UC_MIPS_REG_29, - "r30" : UC_MIPS_REG_30, - "r31" : UC_MIPS_REG_31, + "r0": UC_MIPS_REG_0, + "r1": UC_MIPS_REG_1, + "r2": UC_MIPS_REG_2, + "r3": UC_MIPS_REG_3, + "r4": UC_MIPS_REG_4, + "r5": UC_MIPS_REG_5, + "r6": UC_MIPS_REG_6, + "r7": UC_MIPS_REG_7, + "r8": UC_MIPS_REG_8, + "r9": UC_MIPS_REG_9, + "r10": UC_MIPS_REG_10, + "r11": UC_MIPS_REG_11, + "r12": UC_MIPS_REG_12, + "r13": UC_MIPS_REG_13, + "r14": UC_MIPS_REG_14, + "r15": UC_MIPS_REG_15, + "r16": UC_MIPS_REG_16, + "r17": UC_MIPS_REG_17, + "r18": UC_MIPS_REG_18, + "r19": UC_MIPS_REG_19, + "r20": UC_MIPS_REG_20, + "r21": UC_MIPS_REG_21, + "r22": UC_MIPS_REG_22, + "r23": UC_MIPS_REG_23, + "r24": UC_MIPS_REG_24, + "r25": UC_MIPS_REG_25, + "r26": UC_MIPS_REG_26, + "r27": UC_MIPS_REG_27, + "r28": UC_MIPS_REG_28, + "r29": UC_MIPS_REG_29, + "r30": UC_MIPS_REG_30, + "r31": UC_MIPS_REG_31, - "zero": UC_MIPS_REG_ZERO, - "at": UC_MIPS_REG_AT, + "zero": UC_MIPS_REG_ZERO, + "at": UC_MIPS_REG_AT, "v0": UC_MIPS_REG_V0, - "v1": UC_MIPS_REG_V1, - "a0": UC_MIPS_REG_A0, + "v1": UC_MIPS_REG_V1, + "a0": UC_MIPS_REG_A0, "a1": UC_MIPS_REG_A1, - "a2": UC_MIPS_REG_A2, - "a3": UC_MIPS_REG_A3, + "a2": UC_MIPS_REG_A2, + "a3": UC_MIPS_REG_A3, "t0": UC_MIPS_REG_T0, - "t1": UC_MIPS_REG_T1, - "t2": UC_MIPS_REG_T2, + "t1": UC_MIPS_REG_T1, + "t2": UC_MIPS_REG_T2, "t3": UC_MIPS_REG_T3, - "t4": UC_MIPS_REG_T4, - "t5": UC_MIPS_REG_T5, + "t4": UC_MIPS_REG_T4, + "t5": UC_MIPS_REG_T5, "t6": UC_MIPS_REG_T6, - "t7": UC_MIPS_REG_T7, + "t7": UC_MIPS_REG_T7, "s0": UC_MIPS_REG_S0, "s1": UC_MIPS_REG_S1, - "s2": UC_MIPS_REG_S2, - "s3": UC_MIPS_REG_S3, + "s2": UC_MIPS_REG_S2, + "s3": UC_MIPS_REG_S3, "s4": UC_MIPS_REG_S4, - "s5": UC_MIPS_REG_S5, - "s6": UC_MIPS_REG_S6, + "s5": UC_MIPS_REG_S5, + "s6": UC_MIPS_REG_S6, "s7": UC_MIPS_REG_S7, - "t8": UC_MIPS_REG_T8, - "t9": UC_MIPS_REG_T9, + "t8": UC_MIPS_REG_T8, + "t9": UC_MIPS_REG_T9, "k0": UC_MIPS_REG_K0, "k1": UC_MIPS_REG_K1, - "gp": UC_MIPS_REG_GP, + "gp": UC_MIPS_REG_GP, "sp": UC_MIPS_REG_SP, "s8": UC_MIPS_REG_S8, "ra": UC_MIPS_REG_RA, - "status": UC_MIPS_REG_INVALID, - "lo": UC_MIPS_REG_LO, - "hi": UC_MIPS_REG_HI, + "status": UC_MIPS_REG_INVALID, + "lo": UC_MIPS_REG_LO, + "hi": UC_MIPS_REG_HI, "badvaddr": UC_MIPS_REG_INVALID, - "cause":UC_MIPS_REG_INVALID, - "pc": UC_MIPS_REG_PC, + "cause": UC_MIPS_REG_INVALID, + "pc": UC_MIPS_REG_PC } reg_map_afpr128 = { - "cp0_config3" : UC_MIPS_REG_CP0_CONFIG3, - "cp0_userlocal": UC_MIPS_REG_CP0_USERLOCAL, + "cp0_config3": UC_MIPS_REG_CP0_CONFIG3, + "cp0_userlocal": UC_MIPS_REG_CP0_USERLOCAL } reg_map_fpu = { - "f0" : UC_MIPS_REG_F0, - "f1" : UC_MIPS_REG_F1, - "f2" : UC_MIPS_REG_F2, - "f3" : UC_MIPS_REG_F3, - "f4" : UC_MIPS_REG_F4, - "f5" : UC_MIPS_REG_F5, - "f6" : UC_MIPS_REG_F6, - "f7" : UC_MIPS_REG_F7, - "f8" : UC_MIPS_REG_F8, - "f9" : UC_MIPS_REG_F9, - "f10" : UC_MIPS_REG_F10, - "f11" : UC_MIPS_REG_F11, - "f12" : UC_MIPS_REG_F12, - "f13" : UC_MIPS_REG_F13, - "f14" : UC_MIPS_REG_F14, - "f15" : UC_MIPS_REG_F15, - "f16" : UC_MIPS_REG_F16, - "f17" : UC_MIPS_REG_F17, - "f18" : UC_MIPS_REG_F18, - "f19" : UC_MIPS_REG_F19, - "f20" : UC_MIPS_REG_F20, - "f21" : UC_MIPS_REG_F21, - "f22" : UC_MIPS_REG_F22, - "f23" : UC_MIPS_REG_F23, - "f24" : UC_MIPS_REG_F24, - "f25" : UC_MIPS_REG_F25, - "f26" : UC_MIPS_REG_F26, - "f27" : UC_MIPS_REG_F27, - "f28" : UC_MIPS_REG_F28, - "f29" : UC_MIPS_REG_F29, - "f30" : UC_MIPS_REG_F30, - "f31" : UC_MIPS_REG_F31 + "f0": UC_MIPS_REG_F0, + "f1": UC_MIPS_REG_F1, + "f2": UC_MIPS_REG_F2, + "f3": UC_MIPS_REG_F3, + "f4": UC_MIPS_REG_F4, + "f5": UC_MIPS_REG_F5, + "f6": UC_MIPS_REG_F6, + "f7": UC_MIPS_REG_F7, + "f8": UC_MIPS_REG_F8, + "f9": UC_MIPS_REG_F9, + "f10": UC_MIPS_REG_F10, + "f11": UC_MIPS_REG_F11, + "f12": UC_MIPS_REG_F12, + "f13": UC_MIPS_REG_F13, + "f14": UC_MIPS_REG_F14, + "f15": UC_MIPS_REG_F15, + "f16": UC_MIPS_REG_F16, + "f17": UC_MIPS_REG_F17, + "f18": UC_MIPS_REG_F18, + "f19": UC_MIPS_REG_F19, + "f20": UC_MIPS_REG_F20, + "f21": UC_MIPS_REG_F21, + "f22": UC_MIPS_REG_F22, + "f23": UC_MIPS_REG_F23, + "f24": UC_MIPS_REG_F24, + "f25": UC_MIPS_REG_F25, + "f26": UC_MIPS_REG_F26, + "f27": UC_MIPS_REG_F27, + "f28": UC_MIPS_REG_F28, + "f29": UC_MIPS_REG_F29, + "f30": UC_MIPS_REG_F30, + "f31": UC_MIPS_REG_F31 } diff --git a/qiling/arch/msr.py b/qiling/arch/msr.py index 08409cffe..8ea13cafc 100644 --- a/qiling/arch/msr.py +++ b/qiling/arch/msr.py @@ -1,10 +1,11 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # from unicorn import Uc + class QlMsrManager: """Enables access to Intel MSR. """ diff --git a/qiling/arch/ppc.py b/qiling/arch/ppc.py index 4e6d099db..9863648a9 100644 --- a/qiling/arch/ppc.py +++ b/qiling/arch/ppc.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # @@ -9,12 +9,12 @@ from capstone import Cs, CS_ARCH_PPC, CS_MODE_32, CS_MODE_BIG_ENDIAN from keystone import Ks, KS_ARCH_PPC, KS_MODE_PPC32, KS_MODE_BIG_ENDIAN -from qiling import Qiling from qiling.arch.arch import QlArch from qiling.arch import ppc_const from qiling.arch.register import QlRegisterManager from qiling.const import QL_ARCH, QL_ENDIAN + class QlArchPPC(QlArch): type = QL_ARCH.PPC bits = 32 diff --git a/qiling/arch/ppc_const.py b/qiling/arch/ppc_const.py index 732cba1c9..c2fa86d42 100644 --- a/qiling/arch/ppc_const.py +++ b/qiling/arch/ppc_const.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # @@ -7,16 +7,17 @@ from enum import IntEnum reg_map = { - "r0": UC_PPC_REG_0, - "r1": UC_PPC_REG_1, - "r2": UC_PPC_REG_2, - "r3": UC_PPC_REG_3, - "r4": UC_PPC_REG_4, - "r5": UC_PPC_REG_5, - "r6": UC_PPC_REG_6, - "r7": UC_PPC_REG_7, - "r8": UC_PPC_REG_8, - "r9": UC_PPC_REG_9, + "pc": UC_PPC_REG_PC, + "r0": UC_PPC_REG_0, + "r1": UC_PPC_REG_1, + "r2": UC_PPC_REG_2, + "r3": UC_PPC_REG_3, + "r4": UC_PPC_REG_4, + "r5": UC_PPC_REG_5, + "r6": UC_PPC_REG_6, + "r7": UC_PPC_REG_7, + "r8": UC_PPC_REG_8, + "r9": UC_PPC_REG_9, "r10": UC_PPC_REG_10, "r11": UC_PPC_REG_11, "r12": UC_PPC_REG_12, @@ -39,25 +40,24 @@ "r29": UC_PPC_REG_29, "r30": UC_PPC_REG_30, "r31": UC_PPC_REG_31, - "pc": UC_PPC_REG_PC, - "msr": UC_PPC_REG_MSR, - "cr": UC_PPC_REG_CR0, - "lr": UC_PPC_REG_LR, - "ctr": UC_PPC_REG_CTR, + "cr": UC_PPC_REG_CR0, + "lr": UC_PPC_REG_LR, "xer": UC_PPC_REG_XER, + "ctr": UC_PPC_REG_CTR, + "msr": UC_PPC_REG_MSR } reg_float_map = { - "f0": UC_PPC_REG_FPR0, - "f1": UC_PPC_REG_FPR1, - "f2": UC_PPC_REG_FPR2, - "f3": UC_PPC_REG_FPR3, - "f4": UC_PPC_REG_FPR4, - "f5": UC_PPC_REG_FPR5, - "f6": UC_PPC_REG_FPR6, - "f7": UC_PPC_REG_FPR7, - "f8": UC_PPC_REG_FPR8, - "f9": UC_PPC_REG_FPR9, + "f0": UC_PPC_REG_FPR0, + "f1": UC_PPC_REG_FPR1, + "f2": UC_PPC_REG_FPR2, + "f3": UC_PPC_REG_FPR3, + "f4": UC_PPC_REG_FPR4, + "f5": UC_PPC_REG_FPR5, + "f6": UC_PPC_REG_FPR6, + "f7": UC_PPC_REG_FPR7, + "f8": UC_PPC_REG_FPR8, + "f9": UC_PPC_REG_FPR9, "f10": UC_PPC_REG_FPR10, "f11": UC_PPC_REG_FPR11, "f12": UC_PPC_REG_FPR12, @@ -79,9 +79,10 @@ "f28": UC_PPC_REG_FPR28, "f29": UC_PPC_REG_FPR29, "f30": UC_PPC_REG_FPR30, - "f31": UC_PPC_REG_FPR31, + "f31": UC_PPC_REG_FPR31 } + class MSR(IntEnum): SF = 1 << 63 TAG = 1 << 62 diff --git a/qiling/arch/register.py b/qiling/arch/register.py index 368864f6f..15b426765 100644 --- a/qiling/arch/register.py +++ b/qiling/arch/register.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # @@ -7,6 +7,7 @@ from unicorn import Uc + class QlRegisterManager: """This class exposes the ql.arch.regs features that allows you to directly access or assign values to CPU registers of a particular architecture. @@ -40,7 +41,6 @@ def __getattr__(self, name: str) -> Any: else: return super().__getattribute__(name) - def __setattr__(self, name: str, value: Any): name = name.lower() @@ -50,35 +50,30 @@ def __setattr__(self, name: str, value: Any): else: super().__setattr__(name, value) - - # read register def read(self, register: Union[str, int]): """Read a register value. """ - if type(register) is str: + if isinstance(register, str): register = self.register_mapping[register.lower()] return self.uc.reg_read(register) - def write(self, register: Union[str, int], value: int) -> None: """Write a register value. """ - if type(register) is str: + if isinstance(register, str): register = self.register_mapping[register.lower()] return self.uc.reg_write(register, value) - def save(self) -> MutableMapping[str, Any]: """Save CPU context. """ return dict((reg, self.read(reg)) for reg in self.register_mapping) - def restore(self, context: MutableMapping[str, Any] = {}) -> None: """Restore CPU context. """ @@ -86,7 +81,6 @@ def restore(self, context: MutableMapping[str, Any] = {}) -> None: for reg, val in context.items(): self.write(reg, val) - @property def arch_pc(self) -> int: """Get the value of the architectural program counter register. @@ -94,7 +88,6 @@ def arch_pc(self) -> int: return self.uc.reg_read(self.uc_pc) - @arch_pc.setter def arch_pc(self, value: int) -> None: """Set the value of the architectural program counter register. @@ -102,7 +95,6 @@ def arch_pc(self, value: int) -> None: return self.uc.reg_write(self.uc_pc, value) - @property def arch_sp(self) -> int: """Get the value of the architectural stack pointer register. @@ -110,7 +102,6 @@ def arch_sp(self) -> int: return self.uc.reg_read(self.uc_sp) - @arch_sp.setter def arch_sp(self, value: int) -> None: """Set the value of the architectural stack pointer register. diff --git a/qiling/arch/riscv.py b/qiling/arch/riscv.py index 80d614c37..ded5f6302 100644 --- a/qiling/arch/riscv.py +++ b/qiling/arch/riscv.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # @@ -16,6 +16,7 @@ from qiling.const import QL_ARCH, QL_ENDIAN from qiling.exception import QlErrorNotImplemented + class QlArchRISCV(QlArch): type = QL_ARCH.RISCV bits = 32 @@ -59,35 +60,10 @@ def enable_float(self): def init_context(self): self.regs.pc = 0x08000000 - - def soft_interrupt_handler(self, ql, intno): - if intno == 2: - try: - address, size = ql.arch.regs.pc - 4, 4 - tmp = ql.mem.read(address, size) - qd = ql.arch.disassembler - - insn = '\n> '.join(f'{insn.mnemonic} {insn.op_str}' for insn in qd.disasm(tmp, address)) - except QlErrorNotImplemented: - insn = '' - - ql.log.warning(f'[{hex(address)}] Illegal instruction ({insn})') - else: - raise QlErrorNotImplemented(f'Unhandled interrupt number ({intno})') - - def step(self): - self.ql.emu_start(self.regs.arch_pc, 0, count=1) - self.ql.hw.step() - def stop(self): - self.runable = False + def unicorn_exception_handler(self, ql, intno): + if intno == 2: + ql.log.warning(f'[{hex(self.regs.arch_pc)}] Illegal instruction') - def run(self, count=-1, end=None): - self.runable = True - - while self.runable and count != 0: - if self.regs.arch_pc == end: - break - - self.step() - count -= 1 + else: + raise QlErrorNotImplemented(f'Unhandled interrupt number ({intno})') diff --git a/qiling/arch/riscv64.py b/qiling/arch/riscv64.py index 295cf1171..5dfafcde7 100644 --- a/qiling/arch/riscv64.py +++ b/qiling/arch/riscv64.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # @@ -15,6 +15,7 @@ from .riscv import QlArchRISCV + class QlArchRISCV64(QlArchRISCV): type = QL_ARCH.RISCV64 bits = 64 diff --git a/qiling/arch/riscv_const.py b/qiling/arch/riscv_const.py index d85b68f76..4598674ce 100644 --- a/qiling/arch/riscv_const.py +++ b/qiling/arch/riscv_const.py @@ -1,23 +1,22 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # from unicorn.riscv_const import * from enum import IntEnum - reg_general_map = { - "x0": UC_RISCV_REG_X0, - "x1": UC_RISCV_REG_X1, - "x2": UC_RISCV_REG_X2, - "x3": UC_RISCV_REG_X3, - "x4": UC_RISCV_REG_X4, - "x5": UC_RISCV_REG_X5, - "x6": UC_RISCV_REG_X6, - "x7": UC_RISCV_REG_X7, - "x8": UC_RISCV_REG_X8, - "x9": UC_RISCV_REG_X9, + "x0": UC_RISCV_REG_X0, + "x1": UC_RISCV_REG_X1, + "x2": UC_RISCV_REG_X2, + "x3": UC_RISCV_REG_X3, + "x4": UC_RISCV_REG_X4, + "x5": UC_RISCV_REG_X5, + "x6": UC_RISCV_REG_X6, + "x7": UC_RISCV_REG_X7, + "x8": UC_RISCV_REG_X8, + "x9": UC_RISCV_REG_X9, "x10": UC_RISCV_REG_X10, "x11": UC_RISCV_REG_X11, "x12": UC_RISCV_REG_X12, @@ -39,31 +38,31 @@ "x28": UC_RISCV_REG_X28, "x29": UC_RISCV_REG_X29, "x30": UC_RISCV_REG_X30, - "x31": UC_RISCV_REG_X31, + "x31": UC_RISCV_REG_X31 } reg_csr_map = { - "ustatus": UC_RISCV_REG_USTATUS, - "uie": UC_RISCV_REG_UIE, - "utvec": UC_RISCV_REG_UTVEC, - "uscratch": UC_RISCV_REG_USCRATCH, - "uepc": UC_RISCV_REG_UEPC, - "ucause": UC_RISCV_REG_UCAUSE, - "utval": UC_RISCV_REG_UTVAL, - "uip": UC_RISCV_REG_UIP, - "fflags": UC_RISCV_REG_FFLAGS, - "frm": UC_RISCV_REG_FRM, - "fcsr": UC_RISCV_REG_FCSR, - "cycle": UC_RISCV_REG_CYCLE, - "time": UC_RISCV_REG_TIME, - "instret": UC_RISCV_REG_INSTRET, - "hpmcounter3": UC_RISCV_REG_HPMCOUNTER3, - "hpmcounter4": UC_RISCV_REG_HPMCOUNTER4, - "hpmcounter5": UC_RISCV_REG_HPMCOUNTER5, - "hpmcounter6": UC_RISCV_REG_HPMCOUNTER6, - "hpmcounter7": UC_RISCV_REG_HPMCOUNTER7, - "hpmcounter8": UC_RISCV_REG_HPMCOUNTER8, - "hpmcounter9": UC_RISCV_REG_HPMCOUNTER9, + "ustatus": UC_RISCV_REG_USTATUS, + "uie": UC_RISCV_REG_UIE, + "utvec": UC_RISCV_REG_UTVEC, + "uscratch": UC_RISCV_REG_USCRATCH, + "uepc": UC_RISCV_REG_UEPC, + "ucause": UC_RISCV_REG_UCAUSE, + "utval": UC_RISCV_REG_UTVAL, + "uip": UC_RISCV_REG_UIP, + "fflags": UC_RISCV_REG_FFLAGS, + "frm": UC_RISCV_REG_FRM, + "fcsr": UC_RISCV_REG_FCSR, + "cycle": UC_RISCV_REG_CYCLE, + "time": UC_RISCV_REG_TIME, + "instret": UC_RISCV_REG_INSTRET, + "hpmcounter3": UC_RISCV_REG_HPMCOUNTER3, + "hpmcounter4": UC_RISCV_REG_HPMCOUNTER4, + "hpmcounter5": UC_RISCV_REG_HPMCOUNTER5, + "hpmcounter6": UC_RISCV_REG_HPMCOUNTER6, + "hpmcounter7": UC_RISCV_REG_HPMCOUNTER7, + "hpmcounter8": UC_RISCV_REG_HPMCOUNTER8, + "hpmcounter9": UC_RISCV_REG_HPMCOUNTER9, "hpmcounter10": UC_RISCV_REG_HPMCOUNTER10, "hpmcounter11": UC_RISCV_REG_HPMCOUNTER11, "hpmcounter12": UC_RISCV_REG_HPMCOUNTER12, @@ -86,9 +85,9 @@ "hpmcounter29": UC_RISCV_REG_HPMCOUNTER29, "hpmcounter30": UC_RISCV_REG_HPMCOUNTER30, "hpmcounter31": UC_RISCV_REG_HPMCOUNTER31, - "cycleh": UC_RISCV_REG_CYCLEH, - "timeh": UC_RISCV_REG_TIMEH, - "instreth": UC_RISCV_REG_INSTRETH, + "cycleh": UC_RISCV_REG_CYCLEH, + "timeh": UC_RISCV_REG_TIMEH, + "instreth": UC_RISCV_REG_INSTRETH, "hpmcounter3h": UC_RISCV_REG_HPMCOUNTER3H, "hpmcounter4h": UC_RISCV_REG_HPMCOUNTER4H, "hpmcounter5h": UC_RISCV_REG_HPMCOUNTER5H, @@ -118,69 +117,69 @@ "hpmcounter29h": UC_RISCV_REG_HPMCOUNTER29H, "hpmcounter30h": UC_RISCV_REG_HPMCOUNTER30H, "hpmcounter31h": UC_RISCV_REG_HPMCOUNTER31H, - "mcycle": UC_RISCV_REG_MCYCLE, - "minstret": UC_RISCV_REG_MINSTRET, - "mcycleh": UC_RISCV_REG_MCYCLEH, - "minstreth": UC_RISCV_REG_MINSTRETH, - "mvendorid": UC_RISCV_REG_MVENDORID, - "marchid": UC_RISCV_REG_MARCHID, - "mimpid": UC_RISCV_REG_MIMPID, - "mhartid": UC_RISCV_REG_MHARTID, - "mstatus": UC_RISCV_REG_MSTATUS, - "misa": UC_RISCV_REG_MISA, - "medeleg": UC_RISCV_REG_MEDELEG, - "mideleg": UC_RISCV_REG_MIDELEG, - "mie": UC_RISCV_REG_MIE, - "mtvec": UC_RISCV_REG_MTVEC, - "mcounteren": UC_RISCV_REG_MCOUNTEREN, - "mstatush": UC_RISCV_REG_MSTATUSH, - "mucounteren": UC_RISCV_REG_MUCOUNTEREN, - "mscounteren": UC_RISCV_REG_MSCOUNTEREN, - "mhcounteren": UC_RISCV_REG_MHCOUNTEREN, - "mscratch": UC_RISCV_REG_MSCRATCH, - "mepc": UC_RISCV_REG_MEPC, - "mcause": UC_RISCV_REG_MCAUSE, - "mtval": UC_RISCV_REG_MTVAL, - "mip": UC_RISCV_REG_MIP, - "mbadaddr": UC_RISCV_REG_MBADADDR, - "sstatus": UC_RISCV_REG_SSTATUS, - "sedeleg": UC_RISCV_REG_SEDELEG, - "sideleg": UC_RISCV_REG_SIDELEG, - "sie": UC_RISCV_REG_SIE, - "stvec": UC_RISCV_REG_STVEC, - "scounteren": UC_RISCV_REG_SCOUNTEREN, - "sscratch": UC_RISCV_REG_SSCRATCH, - "sepc": UC_RISCV_REG_SEPC, - "scause": UC_RISCV_REG_SCAUSE, - "stval": UC_RISCV_REG_STVAL, - "sip": UC_RISCV_REG_SIP, - "sbadaddr": UC_RISCV_REG_SBADADDR, - "sptbr": UC_RISCV_REG_SPTBR, - "satp": UC_RISCV_REG_SATP, - "hstatus": UC_RISCV_REG_HSTATUS, - "hedeleg": UC_RISCV_REG_HEDELEG, - "hideleg": UC_RISCV_REG_HIDELEG, - "hie": UC_RISCV_REG_HIE, - "hcounteren": UC_RISCV_REG_HCOUNTEREN, - "htval": UC_RISCV_REG_HTVAL, - "hip": UC_RISCV_REG_HIP, - "htinst": UC_RISCV_REG_HTINST, - "hgatp": UC_RISCV_REG_HGATP, - "htimedelta": UC_RISCV_REG_HTIMEDELTA, - "htimedeltah": UC_RISCV_REG_HTIMEDELTAH, + "mcycle": UC_RISCV_REG_MCYCLE, + "minstret": UC_RISCV_REG_MINSTRET, + "mcycleh": UC_RISCV_REG_MCYCLEH, + "minstreth": UC_RISCV_REG_MINSTRETH, + "mvendorid": UC_RISCV_REG_MVENDORID, + "marchid": UC_RISCV_REG_MARCHID, + "mimpid": UC_RISCV_REG_MIMPID, + "mhartid": UC_RISCV_REG_MHARTID, + "mstatus": UC_RISCV_REG_MSTATUS, + "misa": UC_RISCV_REG_MISA, + "medeleg": UC_RISCV_REG_MEDELEG, + "mideleg": UC_RISCV_REG_MIDELEG, + "mie": UC_RISCV_REG_MIE, + "mtvec": UC_RISCV_REG_MTVEC, + "mcounteren": UC_RISCV_REG_MCOUNTEREN, + "mstatush": UC_RISCV_REG_MSTATUSH, + "mucounteren": UC_RISCV_REG_MUCOUNTEREN, + "mscounteren": UC_RISCV_REG_MSCOUNTEREN, + "mhcounteren": UC_RISCV_REG_MHCOUNTEREN, + "mscratch": UC_RISCV_REG_MSCRATCH, + "mepc": UC_RISCV_REG_MEPC, + "mcause": UC_RISCV_REG_MCAUSE, + "mtval": UC_RISCV_REG_MTVAL, + "mip": UC_RISCV_REG_MIP, + "mbadaddr": UC_RISCV_REG_MBADADDR, + "sstatus": UC_RISCV_REG_SSTATUS, + "sedeleg": UC_RISCV_REG_SEDELEG, + "sideleg": UC_RISCV_REG_SIDELEG, + "sie": UC_RISCV_REG_SIE, + "stvec": UC_RISCV_REG_STVEC, + "scounteren": UC_RISCV_REG_SCOUNTEREN, + "sscratch": UC_RISCV_REG_SSCRATCH, + "sepc": UC_RISCV_REG_SEPC, + "scause": UC_RISCV_REG_SCAUSE, + "stval": UC_RISCV_REG_STVAL, + "sip": UC_RISCV_REG_SIP, + "sbadaddr": UC_RISCV_REG_SBADADDR, + "sptbr": UC_RISCV_REG_SPTBR, + "satp": UC_RISCV_REG_SATP, + "hstatus": UC_RISCV_REG_HSTATUS, + "hedeleg": UC_RISCV_REG_HEDELEG, + "hideleg": UC_RISCV_REG_HIDELEG, + "hie": UC_RISCV_REG_HIE, + "hcounteren": UC_RISCV_REG_HCOUNTEREN, + "htval": UC_RISCV_REG_HTVAL, + "hip": UC_RISCV_REG_HIP, + "htinst": UC_RISCV_REG_HTINST, + "hgatp": UC_RISCV_REG_HGATP, + "htimedelta": UC_RISCV_REG_HTIMEDELTA, + "htimedeltah": UC_RISCV_REG_HTIMEDELTAH } reg_float_map = { - "f0": UC_RISCV_REG_F0, - "f1": UC_RISCV_REG_F1, - "f2": UC_RISCV_REG_F2, - "f3": UC_RISCV_REG_F3, - "f4": UC_RISCV_REG_F4, - "f5": UC_RISCV_REG_F5, - "f6": UC_RISCV_REG_F6, - "f7": UC_RISCV_REG_F7, - "f8": UC_RISCV_REG_F8, - "f9": UC_RISCV_REG_F9, + "f0": UC_RISCV_REG_F0, + "f1": UC_RISCV_REG_F1, + "f2": UC_RISCV_REG_F2, + "f3": UC_RISCV_REG_F3, + "f4": UC_RISCV_REG_F4, + "f5": UC_RISCV_REG_F5, + "f6": UC_RISCV_REG_F6, + "f7": UC_RISCV_REG_F7, + "f8": UC_RISCV_REG_F8, + "f9": UC_RISCV_REG_F9, "f10": UC_RISCV_REG_F10, "f11": UC_RISCV_REG_F11, "f12": UC_RISCV_REG_F12, @@ -202,80 +201,81 @@ "f28": UC_RISCV_REG_F28, "f29": UC_RISCV_REG_F29, "f30": UC_RISCV_REG_F30, - "f31": UC_RISCV_REG_F31, + "f31": UC_RISCV_REG_F31 } reg_map = { - "pc": UC_RISCV_REG_PC, "zero": UC_RISCV_REG_ZERO, - "ra": UC_RISCV_REG_RA, - "sp": UC_RISCV_REG_SP, - "gp": UC_RISCV_REG_GP, - "tp": UC_RISCV_REG_TP, - "t0": UC_RISCV_REG_T0, - "t1": UC_RISCV_REG_T1, - "t2": UC_RISCV_REG_T2, - "s0": UC_RISCV_REG_S0, - "fp": UC_RISCV_REG_FP, - "s1": UC_RISCV_REG_S1, - "a0": UC_RISCV_REG_A0, - "a1": UC_RISCV_REG_A1, - "a2": UC_RISCV_REG_A2, - "a3": UC_RISCV_REG_A3, - "a4": UC_RISCV_REG_A4, - "a5": UC_RISCV_REG_A5, - "a6": UC_RISCV_REG_A6, - "a7": UC_RISCV_REG_A7, - "s2": UC_RISCV_REG_S2, - "s3": UC_RISCV_REG_S3, - "s4": UC_RISCV_REG_S4, - "s5": UC_RISCV_REG_S5, - "s6": UC_RISCV_REG_S6, - "s7": UC_RISCV_REG_S7, - "s8": UC_RISCV_REG_S8, - "s9": UC_RISCV_REG_S9, - "s10": UC_RISCV_REG_S10, - "s11": UC_RISCV_REG_S11, - "t3": UC_RISCV_REG_T3, - "t4": UC_RISCV_REG_T4, - "t5": UC_RISCV_REG_T5, - "t6": UC_RISCV_REG_T6, - "ft0": UC_RISCV_REG_FT0, - "ft1": UC_RISCV_REG_FT1, - "ft2": UC_RISCV_REG_FT2, - "ft3": UC_RISCV_REG_FT3, - "ft4": UC_RISCV_REG_FT4, - "ft5": UC_RISCV_REG_FT5, - "ft6": UC_RISCV_REG_FT6, - "ft7": UC_RISCV_REG_FT7, - "fs0": UC_RISCV_REG_FS0, - "fs1": UC_RISCV_REG_FS1, - "fa0": UC_RISCV_REG_FA0, - "fa1": UC_RISCV_REG_FA1, - "fa2": UC_RISCV_REG_FA2, - "fa3": UC_RISCV_REG_FA3, - "fa4": UC_RISCV_REG_FA4, - "fa5": UC_RISCV_REG_FA5, - "fa6": UC_RISCV_REG_FA6, - "fa7": UC_RISCV_REG_FA7, - "fs2": UC_RISCV_REG_FS2, - "fs3": UC_RISCV_REG_FS3, - "fs4": UC_RISCV_REG_FS4, - "fs5": UC_RISCV_REG_FS5, - "fs6": UC_RISCV_REG_FS6, - "fs7": UC_RISCV_REG_FS7, - "fs8": UC_RISCV_REG_FS8, - "fs9": UC_RISCV_REG_FS9, + "ra": UC_RISCV_REG_RA, + "sp": UC_RISCV_REG_SP, + "gp": UC_RISCV_REG_GP, + "tp": UC_RISCV_REG_TP, + "t0": UC_RISCV_REG_T0, + "t1": UC_RISCV_REG_T1, + "t2": UC_RISCV_REG_T2, + "s0": UC_RISCV_REG_S0, + "fp": UC_RISCV_REG_FP, + "s1": UC_RISCV_REG_S1, + "a0": UC_RISCV_REG_A0, + "a1": UC_RISCV_REG_A1, + "a2": UC_RISCV_REG_A2, + "a3": UC_RISCV_REG_A3, + "a4": UC_RISCV_REG_A4, + "a5": UC_RISCV_REG_A5, + "a6": UC_RISCV_REG_A6, + "a7": UC_RISCV_REG_A7, + "s2": UC_RISCV_REG_S2, + "s3": UC_RISCV_REG_S3, + "s4": UC_RISCV_REG_S4, + "s5": UC_RISCV_REG_S5, + "s6": UC_RISCV_REG_S6, + "s7": UC_RISCV_REG_S7, + "s8": UC_RISCV_REG_S8, + "s9": UC_RISCV_REG_S9, + "s10": UC_RISCV_REG_S10, + "s11": UC_RISCV_REG_S11, + "t3": UC_RISCV_REG_T3, + "t4": UC_RISCV_REG_T4, + "t5": UC_RISCV_REG_T5, + "t6": UC_RISCV_REG_T6, + "ft0": UC_RISCV_REG_FT0, + "ft1": UC_RISCV_REG_FT1, + "ft2": UC_RISCV_REG_FT2, + "ft3": UC_RISCV_REG_FT3, + "ft4": UC_RISCV_REG_FT4, + "ft5": UC_RISCV_REG_FT5, + "ft6": UC_RISCV_REG_FT6, + "ft7": UC_RISCV_REG_FT7, + "fs0": UC_RISCV_REG_FS0, + "fs1": UC_RISCV_REG_FS1, + "fa0": UC_RISCV_REG_FA0, + "fa1": UC_RISCV_REG_FA1, + "fa2": UC_RISCV_REG_FA2, + "fa3": UC_RISCV_REG_FA3, + "fa4": UC_RISCV_REG_FA4, + "fa5": UC_RISCV_REG_FA5, + "fa6": UC_RISCV_REG_FA6, + "fa7": UC_RISCV_REG_FA7, + "fs2": UC_RISCV_REG_FS2, + "fs3": UC_RISCV_REG_FS3, + "fs4": UC_RISCV_REG_FS4, + "fs5": UC_RISCV_REG_FS5, + "fs6": UC_RISCV_REG_FS6, + "fs7": UC_RISCV_REG_FS7, + "fs8": UC_RISCV_REG_FS8, + "fs9": UC_RISCV_REG_FS9, "fs10": UC_RISCV_REG_FS10, "fs11": UC_RISCV_REG_FS11, - "ft8": UC_RISCV_REG_FT8, - "ft9": UC_RISCV_REG_FT9, + "ft8": UC_RISCV_REG_FT8, + "ft9": UC_RISCV_REG_FT9, "ft10": UC_RISCV_REG_FT10, "ft11": UC_RISCV_REG_FT11, + "pc": UC_RISCV_REG_PC } + class MSTATUS(IntEnum): - FS_OFF = 0 - FS_INITIAL = 1 << 13 - FS_CLEAN = 2 << 13 - FS_DIRTY = 3 << 13 + FS_OFF = 0 + FS_INITIAL = 1 << 13 + FS_CLEAN = 2 << 13 + FS_DIRTY = 3 << 13 diff --git a/qiling/arch/utils.py b/qiling/arch/utils.py index 7c6bcd9c8..83941c977 100644 --- a/qiling/arch/utils.py +++ b/qiling/arch/utils.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # @@ -18,6 +18,7 @@ from qiling import Qiling from qiling.const import QL_ARCH, QL_ENDIAN, QL_VERBOSE + class QlArchUtils: def __init__(self, ql: Qiling): self.ql = ql @@ -83,6 +84,7 @@ def ql_hook_block_disasm(ql: Qiling, address: int, size: int): if verbosity >= QL_VERBOSE.DUMP: self._block_hook = self.ql.hook_block(ql_hook_block_disasm) + # used by qltool prior to ql instantiation. to get an assembler object # after ql instantiation, use the appropriate ql.arch method def assembler(arch: QL_ARCH, endianess: QL_ENDIAN, is_thumb: bool) -> Ks: @@ -97,20 +99,21 @@ def assembler(arch: QL_ARCH, endianess: QL_ENDIAN, is_thumb: bool) -> Ks: """ endian = { - QL_ENDIAN.EL : KS_MODE_LITTLE_ENDIAN, - QL_ENDIAN.EB : KS_MODE_BIG_ENDIAN + QL_ENDIAN.EL: KS_MODE_LITTLE_ENDIAN, + QL_ENDIAN.EB: KS_MODE_BIG_ENDIAN }[endianess] thumb = KS_MODE_THUMB if is_thumb else 0 asm_map = { - QL_ARCH.ARM : (KS_ARCH_ARM, KS_MODE_ARM + endian + thumb), - QL_ARCH.ARM64 : (KS_ARCH_ARM64, KS_MODE_ARM), - QL_ARCH.MIPS : (KS_ARCH_MIPS, KS_MODE_MIPS32 + endian), - QL_ARCH.A8086 : (KS_ARCH_X86, KS_MODE_16), - QL_ARCH.X86 : (KS_ARCH_X86, KS_MODE_32), - QL_ARCH.X8664 : (KS_ARCH_X86, KS_MODE_64), - QL_ARCH.PPC : (KS_ARCH_PPC, KS_MODE_PPC32 + KS_MODE_BIG_ENDIAN) + QL_ARCH.CORTEX_M: (KS_ARCH_ARM, KS_MODE_ARM + KS_MODE_LITTLE_ENDIAN + KS_MODE_THUMB), + QL_ARCH.ARM: (KS_ARCH_ARM, KS_MODE_ARM + endian + thumb), + QL_ARCH.ARM64: (KS_ARCH_ARM64, KS_MODE_ARM), + QL_ARCH.MIPS: (KS_ARCH_MIPS, KS_MODE_MIPS32 + endian), + QL_ARCH.A8086: (KS_ARCH_X86, KS_MODE_16), + QL_ARCH.X86: (KS_ARCH_X86, KS_MODE_32), + QL_ARCH.X8664: (KS_ARCH_X86, KS_MODE_64), + QL_ARCH.PPC: (KS_ARCH_PPC, KS_MODE_PPC32 + KS_MODE_BIG_ENDIAN) } if arch in asm_map: diff --git a/qiling/arch/x86.py b/qiling/arch/x86.py index 0a787e8b9..6db9e664c 100644 --- a/qiling/arch/x86.py +++ b/qiling/arch/x86.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # @@ -15,6 +15,7 @@ from qiling.arch import x86_const from qiling.const import QL_ARCH, QL_ENDIAN + class QlArchIntel(QlArch): @property def endian(self) -> QL_ENDIAN: @@ -27,6 +28,7 @@ def msr(self) -> QlMsrManager: return QlMsrManager(self.uc) + class QlArchA8086(QlArchIntel): type = QL_ARCH.A8086 bits = 16 @@ -56,6 +58,7 @@ def disassembler(self) -> Cs: def assembler(self) -> Ks: return Ks(KS_ARCH_X86, KS_MODE_16) + class QlArchX86(QlArchIntel): type = QL_ARCH.X86 bits = 32 @@ -71,6 +74,7 @@ def regs(self) -> QlRegisterManager: **x86_const.reg_map_16, **x86_const.reg_map_32, **x86_const.reg_map_cr, + **x86_const.reg_map_dr, **x86_const.reg_map_st, **x86_const.reg_map_misc ) @@ -88,6 +92,7 @@ def disassembler(self) -> Cs: def assembler(self) -> Ks: return Ks(KS_ARCH_X86, KS_MODE_32) + class QlArchX8664(QlArchIntel): type = QL_ARCH.X8664 bits = 64 @@ -104,6 +109,7 @@ def regs(self) -> QlRegisterManager: **x86_const.reg_map_32, **x86_const.reg_map_64, **x86_const.reg_map_cr, + **x86_const.reg_map_dr, **x86_const.reg_map_st, **x86_const.reg_map_misc, **x86_const.reg_map_64_b, @@ -119,6 +125,7 @@ def regs(self) -> QlRegisterManager: sp_reg = 'rsp' return QlRegisterManager(self.uc, regs_map, pc_reg, sp_reg) + @cached_property def disassembler(self) -> Cs: return Cs(CS_ARCH_X86, CS_MODE_64) diff --git a/qiling/arch/x86_const.py b/qiling/arch/x86_const.py index 1e60479fb..d4716ba6e 100644 --- a/qiling/arch/x86_const.py +++ b/qiling/arch/x86_const.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # @@ -60,7 +60,7 @@ "dh": UC_X86_REG_DH, "dl": UC_X86_REG_DL, "bh": UC_X86_REG_BH, - "bl": UC_X86_REG_BL, + "bl": UC_X86_REG_BL } reg_map_16 = { @@ -72,44 +72,44 @@ "bp": UC_X86_REG_BP, "si": UC_X86_REG_SI, "di": UC_X86_REG_DI, - "ip": UC_X86_REG_IP, + "ip": UC_X86_REG_IP } reg_map_32 = { - "eax": UC_X86_REG_EAX, - "ecx": UC_X86_REG_ECX, + "eax": UC_X86_REG_EAX, + "ecx": UC_X86_REG_ECX, "edx": UC_X86_REG_EDX, "ebx": UC_X86_REG_EBX, - "esp": UC_X86_REG_ESP, + "esp": UC_X86_REG_ESP, "ebp": UC_X86_REG_EBP, - "esi": UC_X86_REG_ESI, - "edi": UC_X86_REG_EDI, - "eip": UC_X86_REG_EIP, + "esi": UC_X86_REG_ESI, + "edi": UC_X86_REG_EDI, + "eip": UC_X86_REG_EIP } reg_map_64 = { "rax": UC_X86_REG_RAX, - "rbx": UC_X86_REG_RBX, - "rcx": UC_X86_REG_RCX, + "rbx": UC_X86_REG_RBX, + "rcx": UC_X86_REG_RCX, "rdx": UC_X86_REG_RDX, - "rsi": UC_X86_REG_RSI, + "rsi": UC_X86_REG_RSI, "rdi": UC_X86_REG_RDI, "rbp": UC_X86_REG_RBP, - "rsp": UC_X86_REG_RSP, - "r8": UC_X86_REG_R8, - "r9": UC_X86_REG_R9, + "rsp": UC_X86_REG_RSP, + "r8": UC_X86_REG_R8, + "r9": UC_X86_REG_R9, "r10": UC_X86_REG_R10, "r11": UC_X86_REG_R11, - "r12": UC_X86_REG_R12, - "r13": UC_X86_REG_R13, + "r12": UC_X86_REG_R12, + "r13": UC_X86_REG_R13, "r14": UC_X86_REG_R14, "r15": UC_X86_REG_R15, - "rip": UC_X86_REG_RIP, + "rip": UC_X86_REG_RIP } reg_map_seg_base = { - "fsbase" : UC_X86_REG_FS_BASE, - "gsbase" : UC_X86_REG_GS_BASE + "fsbase": UC_X86_REG_FS_BASE, + "gsbase": UC_X86_REG_GS_BASE } reg_map_64_b = { @@ -120,7 +120,7 @@ "r12b": UC_X86_REG_R12B, "r13b": UC_X86_REG_R13B, "r14b": UC_X86_REG_R14B, - "r15b": UC_X86_REG_R15B, + "r15b": UC_X86_REG_R15B } reg_map_64_w = { @@ -131,7 +131,7 @@ "r12w": UC_X86_REG_R12W, "r13w": UC_X86_REG_R13W, "r14w": UC_X86_REG_R14W, - "r15w": UC_X86_REG_R15W, + "r15w": UC_X86_REG_R15W } reg_map_64_d = { @@ -142,48 +142,48 @@ "r12d": UC_X86_REG_R12D, "r13d": UC_X86_REG_R13D, "r14d": UC_X86_REG_R14D, - "r15d": UC_X86_REG_R15D, + "r15d": UC_X86_REG_R15D } reg_map_cr = { - "cr0": UC_X86_REG_CR0, + "cr0": UC_X86_REG_CR0, "cr1": UC_X86_REG_CR1, - "cr2": UC_X86_REG_CR2, - "cr3": UC_X86_REG_CR3, + "cr2": UC_X86_REG_CR2, + "cr3": UC_X86_REG_CR3, "cr4": UC_X86_REG_CR4, "cr8": UC_X86_REG_CR8 } reg_map_dr = { - "dr0": UC_X86_REG_DR0, + "dr0": UC_X86_REG_DR0, "dr1": UC_X86_REG_DR1, - "dr2": UC_X86_REG_DR2, - "dr3": UC_X86_REG_DR3, + "dr2": UC_X86_REG_DR2, + "dr3": UC_X86_REG_DR3, "dr4": UC_X86_REG_DR4, - "dr5": UC_X86_REG_DR5, - "dr6": UC_X86_REG_DR6, - "dr7": UC_X86_REG_DR7, + "dr5": UC_X86_REG_DR5, + "dr6": UC_X86_REG_DR6, + "dr7": UC_X86_REG_DR7 } reg_map_st = { - "st0": UC_X86_REG_ST0, + "st0": UC_X86_REG_ST0, "st1": UC_X86_REG_ST1, - "st2": UC_X86_REG_ST2, - "st3": UC_X86_REG_ST3, + "st2": UC_X86_REG_ST2, + "st3": UC_X86_REG_ST3, "st4": UC_X86_REG_ST4, - "st5": UC_X86_REG_ST5, - "st6": UC_X86_REG_ST6, + "st5": UC_X86_REG_ST5, + "st6": UC_X86_REG_ST6, "st7": UC_X86_REG_ST7 } reg_map_misc = { - "eflags": UC_X86_REG_EFLAGS, - "cs": UC_X86_REG_CS, + "eflags": UC_X86_REG_EFLAGS, + "cs": UC_X86_REG_CS, "ss": UC_X86_REG_SS, - "ds": UC_X86_REG_DS, - "es": UC_X86_REG_ES, + "ds": UC_X86_REG_DS, + "es": UC_X86_REG_ES, "fs": UC_X86_REG_FS, - "gs": UC_X86_REG_GS, + "gs": UC_X86_REG_GS } reg_map_fp = { @@ -194,20 +194,20 @@ "fp4": UC_X86_REG_FP4, "fp5": UC_X86_REG_FP5, "fp6": UC_X86_REG_FP6, - "fp7": UC_X86_REG_FP7, + "fp7": UC_X86_REG_FP7 } reg_map_xmm = { - "xmm0": UC_X86_REG_XMM0, - "xmm1": UC_X86_REG_XMM1, - "xmm2": UC_X86_REG_XMM2, - "xmm3": UC_X86_REG_XMM3, - "xmm4": UC_X86_REG_XMM4, - "xmm5": UC_X86_REG_XMM5, - "xmm6": UC_X86_REG_XMM6, - "xmm7": UC_X86_REG_XMM7, - "xmm8": UC_X86_REG_XMM8, - "xmm9": UC_X86_REG_XMM9, + "xmm0": UC_X86_REG_XMM0, + "xmm1": UC_X86_REG_XMM1, + "xmm2": UC_X86_REG_XMM2, + "xmm3": UC_X86_REG_XMM3, + "xmm4": UC_X86_REG_XMM4, + "xmm5": UC_X86_REG_XMM5, + "xmm6": UC_X86_REG_XMM6, + "xmm7": UC_X86_REG_XMM7, + "xmm8": UC_X86_REG_XMM8, + "xmm9": UC_X86_REG_XMM9, "xmm10": UC_X86_REG_XMM10, "xmm11": UC_X86_REG_XMM11, "xmm12": UC_X86_REG_XMM12, @@ -229,20 +229,20 @@ "xmm28": UC_X86_REG_XMM28, "xmm29": UC_X86_REG_XMM29, "xmm30": UC_X86_REG_XMM30, - "xmm31": UC_X86_REG_XMM31, + "xmm31": UC_X86_REG_XMM31 } reg_map_ymm = { - "ymm0": UC_X86_REG_YMM0, - "ymm1": UC_X86_REG_YMM1, - "ymm2": UC_X86_REG_YMM2, - "ymm3": UC_X86_REG_YMM3, - "ymm4": UC_X86_REG_YMM4, - "ymm5": UC_X86_REG_YMM5, - "ymm6": UC_X86_REG_YMM6, - "ymm7": UC_X86_REG_YMM7, - "ymm8": UC_X86_REG_YMM8, - "ymm9": UC_X86_REG_YMM9, + "ymm0": UC_X86_REG_YMM0, + "ymm1": UC_X86_REG_YMM1, + "ymm2": UC_X86_REG_YMM2, + "ymm3": UC_X86_REG_YMM3, + "ymm4": UC_X86_REG_YMM4, + "ymm5": UC_X86_REG_YMM5, + "ymm6": UC_X86_REG_YMM6, + "ymm7": UC_X86_REG_YMM7, + "ymm8": UC_X86_REG_YMM8, + "ymm9": UC_X86_REG_YMM9, "ymm10": UC_X86_REG_YMM10, "ymm11": UC_X86_REG_YMM11, "ymm12": UC_X86_REG_YMM12, @@ -264,20 +264,20 @@ "ymm28": UC_X86_REG_YMM28, "ymm29": UC_X86_REG_YMM29, "ymm30": UC_X86_REG_YMM30, - "ymm31": UC_X86_REG_YMM31, + "ymm31": UC_X86_REG_YMM31 } reg_map_zmm = { - "zmm0": UC_X86_REG_ZMM0, - "zmm1": UC_X86_REG_ZMM1, - "zmm2": UC_X86_REG_ZMM2, - "zmm3": UC_X86_REG_ZMM3, - "zmm4": UC_X86_REG_ZMM4, - "zmm5": UC_X86_REG_ZMM5, - "zmm6": UC_X86_REG_ZMM6, - "zmm7": UC_X86_REG_ZMM7, - "zmm8": UC_X86_REG_ZMM8, - "zmm9": UC_X86_REG_ZMM9, + "zmm0": UC_X86_REG_ZMM0, + "zmm1": UC_X86_REG_ZMM1, + "zmm2": UC_X86_REG_ZMM2, + "zmm3": UC_X86_REG_ZMM3, + "zmm4": UC_X86_REG_ZMM4, + "zmm5": UC_X86_REG_ZMM5, + "zmm6": UC_X86_REG_ZMM6, + "zmm7": UC_X86_REG_ZMM7, + "zmm8": UC_X86_REG_ZMM8, + "zmm9": UC_X86_REG_ZMM9, "zmm10": UC_X86_REG_ZMM10, "zmm11": UC_X86_REG_ZMM11, "zmm12": UC_X86_REG_ZMM12, @@ -299,6 +299,5 @@ "zmm28": UC_X86_REG_ZMM28, "zmm29": UC_X86_REG_ZMM29, "zmm30": UC_X86_REG_ZMM30, - "zmm31": UC_X86_REG_ZMM31, + "zmm31": UC_X86_REG_ZMM31 } - diff --git a/qiling/arch/x86_utils.py b/qiling/arch/x86_utils.py index f0f58706f..587477ad7 100644 --- a/qiling/arch/x86_utils.py +++ b/qiling/arch/x86_utils.py @@ -8,6 +8,7 @@ from qiling.exception import QlGDTError, QlMemoryMappedError from qiling.os.memory import QlMemoryManager + class GDTArray: entsize = QL_X86_GDT_ENTRY_SIZE @@ -48,7 +49,7 @@ def get_next_free(self, start: Optional[int] = None, end: Optional[int] = None) class GDTManager: - def __init__(self, ql: Qiling, base = QL_X86_GDT_ADDR, limit = QL_X86_GDT_LIMIT, num_entries = 16): + def __init__(self, ql: Qiling, base=QL_X86_GDT_ADDR, limit=QL_X86_GDT_LIMIT, num_entries=16): ql.log.debug(f'Mapping GDT at {base:#x} with limit {limit:#x}') if not ql.mem.is_available(base, limit): @@ -144,7 +145,7 @@ def setup_cs_ds_ss_es(self, base: int, size: int) -> None: self.arch.regs.cs = selector # TODO : The section permission here should be QL_X86_A_PRIV_3, but I do n’t know why it can only be set to QL_X86_A_PRIV_0. - # While debugging the Linux kernel segment, I found that the three segments DS, SS, and ES all point to the same location in the GDT table. + # While debugging the Linux kernel segment, I found that the three segments DS, SS, and ES all point to the same location in the GDT table. # This position is the fifth segment table of GDT. access = QL_X86_A_PRESENT | QL_X86_A_DATA | QL_X86_A_DATA_WRITABLE | QL_X86_A_PRIV_0 | QL_X86_A_DIR_CON_BIT selector = self.gdtm.register_gdt_segment(5, base, size - 1, access) diff --git a/qiling/const.py b/qiling/const.py index d7ac9f8db..edfff6fc7 100644 --- a/qiling/const.py +++ b/qiling/const.py @@ -1,15 +1,17 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # from enum import Enum, Flag, IntEnum -from typing import Mapping, Type, TypeVar +from typing import Final, Mapping, Type, TypeVar + class QL_ENDIAN(IntEnum): EL = 1 EB = 2 + class QL_ARCH(IntEnum): X86 = 101 X8664 = 102 @@ -23,6 +25,7 @@ class QL_ARCH(IntEnum): RISCV64 = 111 PPC = 112 + class QL_OS(IntEnum): LINUX = 201 FREEBSD = 202 @@ -35,44 +38,53 @@ class QL_OS(IntEnum): MCU = 209 BLOB = 210 + class QL_VERBOSE(IntEnum): - DISABLED = -1 # turn off all the output - OFF = 0 # output only warnings - DEFAULT = 1 # output warnings and Qiling execute process information - DEBUG = 4 # output all logs above and debug information, include syscall information - DISASM = 10 # output all assembly instructions during Qiling execution - DUMP = 20 # output any log Qiling can, include instructions and registers + DISABLED = -1 # turn off all the output + OFF = 0 # output only warnings + DEFAULT = 1 # output warnings and Qiling execute process information + DEBUG = 4 # output all logs above and debug information, include syscall information + DISASM = 10 # output all assembly instructions during Qiling execution + DUMP = 20 # output any log Qiling can, include instructions and registers + class QL_DEBUGGER(IntEnum): GDB = 1 IDAPRO = 2 QDB = 3 + class QL_INTERCEPT(IntEnum): CALL = 1 ENTER = 2 EXIT = 3 + class QL_STOP(Flag): NONE = 0 STACK_POINTER = (1 << 0) - EXIT_TRAP = (1 << 1) + EXIT_TRAP = (1 << 1) + + +QL_ARCH_INTERPRETER: Final = (QL_ARCH.EVM,) -QL_ARCH_INTERPRETER = (QL_ARCH.EVM,) +QL_OS_POSIX: Final = (QL_OS.LINUX, QL_OS.FREEBSD, QL_OS.MACOS, QL_OS.QNX) +QL_OS_BAREMETAL: Final = (QL_OS.MCU,) -QL_OS_POSIX = (QL_OS.LINUX, QL_OS.FREEBSD, QL_OS.MACOS, QL_OS.QNX) -QL_OS_BAREMETAL = (QL_OS.MCU,) QL_HOOK_BLOCK = 0b0001 QL_CALL_BLOCK = 0b0010 T = TypeVar('T', bound=Enum) + + def __casefold_enum(e: Type[T]) -> Mapping[str, T]: '''Create a casefolded mapping of an enum to allow case-insensitive lookup. ''' return dict((k.casefold(), v) for k, v in e._member_map_.items()) + debugger_map = __casefold_enum(QL_DEBUGGER) arch_map = __casefold_enum(QL_ARCH) os_map = __casefold_enum(QL_OS) diff --git a/qiling/core.py b/qiling/core.py index 1e8b62d69..efa05fdb5 100644 --- a/qiling/core.py +++ b/qiling/core.py @@ -3,7 +3,9 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -import os, pickle +import os +import pickle +from functools import cached_property from typing import TYPE_CHECKING, Any, AnyStr, List, Mapping, MutableMapping, Optional, Sequence, Tuple, Union # See https://stackoverflow.com/questions/39740632/python-type-hinting-without-cyclic-imports @@ -26,7 +28,7 @@ from .core_struct import QlCoreStructs from .core_hooks import QlCoreHooks -# Mixin Pattern + class Qiling(QlCoreHooks, QlCoreStructs): def __init__( self, @@ -78,9 +80,9 @@ def __init__( ############################### self.entry_point = None self.exit_point = None - self.timeout = None - self.count = None - self._initial_sp = None + self.timeout = 0 + self.count = 0 + self._initial_sp = 0 """ Qiling Framework Core Engine @@ -95,8 +97,6 @@ def __init__( raise QlErrorFileNotFound(f'Target binary not found: "{argv[0]}"') self._argv = argv - self._path = self.argv[0] - self._targetname = os.path.basename(self.path) ################ # rootfs setup # @@ -109,8 +109,6 @@ def __init__( ################# # arch os setup # ################# - self._host = QlHost() - if type(archtype) is str: archtype = arch_convert(archtype) @@ -203,11 +201,10 @@ def mem(self) -> "QlMemoryManager": def hw(self) -> "QlHwManager": """ Qiling hardware manager. - Example: + Example: """ return self._hw - @property def arch(self) -> "QlArch": """ Qiling architecture layer. @@ -251,12 +248,7 @@ def log(self) -> "Logger": @property def multithread(self) -> bool: - """ Specify whether multithread has been enabled. - - WARNING: This property shouldn't be set after Qiling.__init__. - - Type: bool - Example: Qiling(multithread=True) + """Detremine whether multi-threading has been enabled. """ return self._multithread @@ -274,18 +266,32 @@ def profile(self) -> "ConfigParser": @property def argv(self) -> Sequence[str]: - """ The program argv. + """Emulated program arguments. + Note that `code` and `argv` are mutually exclusive. - Example: Qiling(argv=['/bin/ls', '-a']) + Example: + >>> ql = Qiling([r'myrootfs/path/to/target.bin', 'arg1'], 'myrootfs') + >>> ql.argv + ['myrootfs/path/to/target.bin', 'arg1'] """ return self._argv @property def rootfs(self) -> str: - """ The program rootfs. For some common rootfs, see examples/rootfs/ for details. + """Path to emulated system root directory, to which the emulated program + will be confined to. - Type: str - Example: Qiling(argv=['/bin/ls', '-a'], rootfs='examples/rootfs/x8664_linux/') + Everything under rootfs is accessible by the emulated program. DO NOT USE + the hosting system root directory unless you ABSOLUTLEY TRUST the emulated + program. + + For commonly used rootfs, see directories under examples/rootfs/ + + Example: + >>> ROOTFS = r'examples/rootfs/x8664_linux' + >>> ql = Qiling([rf'{ROOTFS}/bin/ping', '-n', '-4'], ROOTFS) + >>> ql.rootfs + 'examples/rootfs/x8664_linux' """ return self._rootfs @@ -298,48 +304,57 @@ def env(self) -> MutableMapping[AnyStr, AnyStr]: return self._env @property - def code(self) -> bytes: - """ The shellcode to execute. - - Note: It can't be used with "argv" parameter. - - Type: bytes - Example: Qiling(code=b"\x90", ostype="macos", archtype="x8664") + def code(self) -> Optional[bytes]: + """The shellcode that was set for execution, or `None` if not set. + Note that `code` and `argv` are mutually exclusive. + + Example: + >>> EXIT_SYSCALL = bytes.fromhex( + '''31 c0 ''' # xor eax, eax + '''40 ''' # inc eax + '''cd 80 ''' # int 0x80 + ) + >>> ql = Qiling(code=EXIT_SYSCALL, ostype=QL_OS.LINUX, archtype=QL_ARCH.X86) + >>> ql.code + b'1\\xc0@\\xcd\\x80' """ return self._code @property def path(self) -> str: - """ The file path of the executable. + """Emulated binary path as specified in argv. - Type: str + Example: + >>> ql = Qiling([r'myrootfs/path/to/target.bin', 'arg1'], 'myrootfs') + >>> ql.targetname + 'myrootfs/path/to/target.bin' """ - return self._path + return self.argv[0] @property def targetname(self) -> str: - """ The target name of the executable. e.g. "c.exe" in "a\b\c.exe" + """Emulated binary base name. - Type: str + Example: + >>> ql = Qiling([r'myrootfs/path/to/target.bin', 'arg1'], 'myrootfs') + >>> ql.targetname + 'target.bin' """ - return self._targetname + return os.path.basename(self.path) @property def interpreter(self) -> bool: - """ Interpreter Engine - - Blockchain related - - Java engine? + """Indicate whether an interpreter engine is being emulated. - Type: bool + Currently supporting: EVM """ return self.arch.type in QL_ARCH_INTERPRETER @property def baremetal(self) -> bool: - """ MCU / Bare Metal type - - STM32, RTOS + """Indicate whether a baremetal system is being emulated. - Type: bool + Currently supporting: MCU """ # os is not initialized for interpreter archs @@ -348,16 +363,16 @@ def baremetal(self) -> bool: return self.os.type in QL_OS_BAREMETAL - @property + @cached_property def host(self) -> QlHost: """Provide an interface to the hosting platform where Qiling runs on. """ - return self._host + return QlHost() @property def internal_exception(self) -> Optional[Exception]: - """ Internal exception catched during Unicorn callback. Not intended for regular users. + """Internal exception caught during Unicorn callback. Not intended for regular users. Type: Exception """ @@ -365,7 +380,7 @@ def internal_exception(self) -> Optional[Exception]: @property def verbose(self) -> QL_VERBOSE: - """Set verbosity level. + """Set logging verbosity level. Values: `QL_VERBOSE.DISABLED`: turn off logging @@ -533,7 +548,6 @@ def write_exit_trap(self): elif QL_STOP.EXIT_TRAP in self.stop_options: self.log.debug(f'Loader requested to skip exit_trap!') - ############### # Qiling APIS # ############### @@ -563,23 +577,15 @@ def run(self, begin: Optional[int] = None, end: Optional[int] = None, timeout: i # patch binary self.do_bin_patch() - if self.baremetal: - if self.count <= 0: - self.count = -1 - - self.arch.run(count=self.count, end=self.exit_point) - else: - self.write_exit_trap() - # emulate the binary - self.os.run() + self.write_exit_trap() + # emulate the binary + self.os.run() # run debugger if debugger and self.debugger: debugger.run() - - # patch code to memory address - def patch(self, offset: int, data: bytes, target: str = None) -> None: + def patch(self, offset: int, data: bytes, target: Optional[str] = None) -> None: """Volatilely patch binary and libraries with arbitrary content. Patching may be done prior to emulation start. @@ -594,9 +600,23 @@ def patch(self, offset: int, data: bytes, target: str = None) -> None: else: self.patch_lib.append((offset, data, target)) + def save(self, reg=True, mem=True, hw=False, fd=False, cpu_context=False, os=False, loader=False, *, snapshot: Optional[str] = None): + """Pack Qiling's current state into an object and optionally dump it to a file. + Specific components may be included or excluded from the save state. + + Args: + reg : include all registers values + mem : include memory layout and content + hw : include hardware entities state (baremetal only) + fd : include OS file descriptors table, where supported + cpu_context : include underlying Unicorn state + os : include OS-related state + loader : include Loader-related state + snapshot : specify a filename to dump the state into (optional) + + Returns: a dictionary holding Qiling's current state + """ - # save all qiling instance states - def save(self, reg=True, mem=True, fd=False, cpu_context=False, os=False, loader=False, *, snapshot: str = None): saved_states = {} if reg: @@ -605,6 +625,9 @@ def save(self, reg=True, mem=True, fd=False, cpu_context=False, os=False, loader if mem: saved_states["mem"] = self.mem.save() + if hw: + saved_states["hw"] = self.hw.save() + if fd: saved_states["fd"] = self.os.fd.save() @@ -623,9 +646,18 @@ def save(self, reg=True, mem=True, fd=False, cpu_context=False, os=False, loader return saved_states + def restore(self, saved_states: Mapping[str, Any] = {}, *, snapshot: Optional[str] = None): + """Unpack and apply a saved Qiling state. + Only saved components will be restored; the rest remains intact. - # restore states qiling instance from saved_states - def restore(self, saved_states: Mapping[str, Any] = {}, *, snapshot: str = None): + Args: + saved_states : a saved state dictionary originally created by the `save` method + snapshot : path of a snapshot file containing a dumped saved state. + + Notes: + Only restore a saved state provided by a trusted entity. + In case both arguments are provided, snapshot file will be ignored + """ # snapshot will be ignored if saved_states is set if (not saved_states) and (snapshot is not None): @@ -641,6 +673,9 @@ def restore(self, saved_states: Mapping[str, Any] = {}, *, snapshot: str = None) if "reg" in saved_states: self.arch.regs.restore(saved_states["reg"]) + if "hw" in saved_states: + self.hw.restore(saved_states['hw']) + if "fd" in saved_states: self.os.fd.restore(saved_states["fd"]) @@ -650,7 +685,6 @@ def restore(self, saved_states: Mapping[str, Any] = {}, *, snapshot: str = None) if "loader" in saved_states: self.loader.restore(saved_states["loader"]) - # Map "ql_path" to any objects which implements QlFsMappedObject. def add_fs_mapper(self, ql_path: Union["PathLike", str], real_dest): self.os.fs_mapper.add_fs_mapping(ql_path, real_dest) @@ -658,43 +692,39 @@ def add_fs_mapper(self, ql_path: Union["PathLike", str], real_dest): # Remove "ql_path" mapping. def remove_fs_mapper(self, ql_path: Union["PathLike", str]): self.os.fs_mapper.remove_fs_mapping(ql_path) - + # push to stack bottom, and update stack register def stack_push(self, data): return self.arch.stack_push(data) - # pop from stack bottom, and update stack register def stack_pop(self): return self.arch.stack_pop() - # read from stack, at a given offset from stack bottom # NOTE: unlike stack_pop(), this does not change stack register def stack_read(self, offset): return self.arch.stack_read(offset) - # write to stack, at a given offset from stack bottom # NOTE: unlike stack_push(), this does not change stack register def stack_write(self, offset, data): return self.arch.stack_write(offset, data) - # stop emulation def emu_stop(self): self.uc.emu_stop() - + # stop emulation def stop(self): if self.multithread: - self.os.thread_management.stop() + self.os.thread_management.stop() elif self.baremetal: - self.arch.stop() + self.os.stop() else: - self.uc.emu_stop() + self.uc.emu_stop() # start emulation def emu_start(self, begin: int, end: int, timeout: int = 0, count: int = 0): @@ -704,13 +734,24 @@ def emu_start(self, begin: int, end: int, timeout: int = 0, count: int = 0): begin : emulation starting address end : emulation ending address timeout : max emulation time (in microseconds); unlimited by default - count : max emulation steps (instructions count); unlimited by default + count : max emulation steps (instructions count); unlimited by default """ - if self._arch.type in (QL_ARCH.ARM, QL_ARCH.CORTEX_M) and self._arch._init_thumb: - begin |= 1 + # FIXME: we cannot use arch.is_thumb to determine this because unicorn sets the coresponding bit in cpsr + # only when pc is set. unicorn sets or clears the thumb mode bit based on pc lsb, ignoring the mode it + # was initialized with. + # + # either unicorn is patched to reflect thumb mode in cpsr upon initialization, or we pursue the same logic + # by determining the endianess by address lsb. either way this condition should not be here + if getattr(self.arch, '_init_thumb', False): + begin |= 0b1 + + # reset exception status before emulation starts + self._internal_exception = None + # effectively start the emulation. this returns only after uc.emu_stop is called self.uc.emu_start(begin, end, timeout, count) - if self._internal_exception is not None: - raise self._internal_exception + # if an exception was raised during emulation, propagate it up + if self.internal_exception is not None: + raise self.internal_exception diff --git a/qiling/core_hooks.py b/qiling/core_hooks.py index 0a8e4cb83..f142684fd 100644 --- a/qiling/core_hooks.py +++ b/qiling/core_hooks.py @@ -8,6 +8,7 @@ # handling hooks # ############################################## +import functools from typing import Any, Callable, MutableMapping, MutableSequence, Protocol from typing import TYPE_CHECKING @@ -15,7 +16,6 @@ from unicorn.unicorn_const import * from .core_hooks_types import Hook, HookAddr, HookIntr, HookRet -from .utils import catch_KeyboardInterrupt from .const import QL_HOOK_BLOCK from .exception import QlErrorCoreHook @@ -86,6 +86,19 @@ def __call__(self, __ql: 'Qiling', intno: int, *__context: Any) -> Any: pass +def hookcallback(ql: 'Qiling', callback: Callable): + + functools.wraps(callback) + def wrapper(*args, **kwargs): + try: + return callback(*args, **kwargs) + except (KeyboardInterrupt, Exception) as ex: + ql.stop() + ql._internal_exception = ex + + return wrapper + + # Don't assume self is Qiling. class QlCoreHooks: def __init__(self, uc: Uc): @@ -235,13 +248,13 @@ def _hook_addr_cb(self, uc: Uc, addr: int, size: int, pack_data): # Class Hooks # ############### def _ql_hook_internal(self, hook_type: int, callback: Callable, context: Any, *args) -> int: - _callback = catch_KeyboardInterrupt(self, callback) + _callback = hookcallback(self, callback) return self._h_uc.hook_add(hook_type, _callback, (self, context), 1, 0, *args) def _ql_hook_addr_internal(self, callback: Callable, address: int) -> int: - _callback = catch_KeyboardInterrupt(self, callback) + _callback = hookcallback(self, callback) return self._h_uc.hook_add(UC_HOOK_CODE, _callback, self, address, address) diff --git a/qiling/debugger/__init__.py b/qiling/debugger/__init__.py index eeadc6bf8..57e0576ed 100644 --- a/qiling/debugger/__init__.py +++ b/qiling/debugger/__init__.py @@ -1,3 +1,3 @@ from .debugger import QlDebugger -from .disassember import QlDisassember -from .utils import QlReadELF +# from .disassember import QlDisassember +# from .utils import QlReadELF diff --git a/qiling/debugger/debugger.py b/qiling/debugger/debugger.py index 233f655e6..fe8f2812e 100644 --- a/qiling/debugger/debugger.py +++ b/qiling/debugger/debugger.py @@ -3,24 +3,16 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -from qiling import Qiling +from typing import TYPE_CHECKING -class QlDebugger(): - def __init__(self, ql:Qiling): - self.ql = ql - - def dbg_start(self): - pass +if TYPE_CHECKING: + from qiling import Qiling - def dbg_run(self, begin_addr=None, end_addr=None): - self.ql.emu_start(begin=begin_addr, end=end_addr) - - def dbg_step(self): - pass - def dbg_continue(self): - pass +class QlDebugger: + def __init__(self, ql: 'Qiling'): + self.ql = ql - def dbg_set_breakpoint(self): - pass + def run(self): + raise NotImplementedError diff --git a/qiling/debugger/gdb/gdb.py b/qiling/debugger/gdb/gdb.py index 040614458..cf2a23b6a 100644 --- a/qiling/debugger/gdb/gdb.py +++ b/qiling/debugger/gdb/gdb.py @@ -13,10 +13,13 @@ # gdb remote protocol: # https://sourceware.org/gdb/current/onlinedocs/gdb/Remote-Protocol.html -import os, socket, re, tempfile +import os +import socket +import re +import tempfile +from functools import partial from logging import Logger -from typing import Iterator, Mapping, Optional, Union -import typing +from typing import IO, Iterator, MutableMapping, Optional, Union from unicorn import UcError from unicorn.unicorn_const import ( @@ -32,7 +35,6 @@ from qiling.debugger.gdb.xmlregs import QlGdbFeatures from qiling.debugger.gdb.utils import QlGdbUtils from qiling.os.linux.procfs import QlProcFS -from qiling.os.mapper import QlFsMappedCallable, QlFsMappedObject # gdb logging prompt PROMPT = r'gdb>' @@ -62,6 +64,7 @@ # reply type Reply = Union[bytes, str] + class QlGdb(QlDebugger): """A simple gdbserver implementation. """ @@ -92,6 +95,11 @@ def __init__(self, ql: Qiling, ip: str = '127.0.0.1', port: int = 9999): else: entry_point = ql.os.entry_point + # though linkers set the entry point LSB to indicate arm thumb mode, the + # effective entry point address is aligned. make sure we have it aligned + if hasattr(ql.arch, 'is_thumb'): + entry_point &= ~0b1 + # Only part of the binary file will be debugged. if ql.entry_point is not None: entry_point = ql.entry_point @@ -104,10 +112,7 @@ def __init__(self, ql: Qiling, ip: str = '127.0.0.1', port: int = 9999): self.features = QlGdbFeatures(self.ql.arch.type, self.ql.os.type) self.regsmap = self.features.regsmap - # https://sourceware.org/bugzilla/show_bug.cgi?id=17760 - # 42000 is the magic pid to indicate the remote process. - self.ql.add_fs_mapper(r'/proc/42000/maps', QlFsMappedCallable(QlProcFS.self_map, self.ql.mem)) - self.fake_procfs: Mapping[int, typing.IO] = {} + self.fake_procfs: MutableMapping[int, IO] = {} def run(self): server = GdbSerialConn(self.ip, self.port, self.ql.log) @@ -158,11 +163,9 @@ def __swap_endianess(value: int) -> int: return int.from_bytes(raw, 'big') - def handle_exclaim(subcmd: str) -> Reply: return REPLY_OK - def handle_qmark(subcmd: str) -> Reply: """Request status. @@ -211,7 +214,6 @@ def __get_reg_info(ucreg: int) -> str: return f'T{SIGTRAP:02x}{bp_info}{sp_info}{pc_info}' - def handle_c(subcmd: str) -> Reply: try: self.gdb.resume_emu() @@ -237,7 +239,7 @@ def handle_c(subcmd: str) -> Reply: reply = f'S{SIGINT:02x}' else: - if self.ql.arch.regs.arch_pc == self.gdb.last_bp: + if getattr(self.ql.arch, 'effective_pc', self.ql.arch.regs.arch_pc) == self.gdb.last_bp: # emulation stopped because it hit a breakpoint reply = f'S{SIGTRAP:02x}' else: @@ -246,7 +248,6 @@ def handle_c(subcmd: str) -> Reply: return reply - def handle_g(subcmd: str) -> Reply: # NOTE: in the past the 'g' reply packet for arm included the f0-f7 and fps registers between pc # and cpsr, which placed cpsr at index (regnum) 25. as the f-registers became obsolete the cpsr @@ -261,7 +262,6 @@ def handle_g(subcmd: str) -> Reply: return ''.join(__get_reg_value(*entry) for entry in self.regsmap) - def handle_G(subcmd: str) -> Reply: data = subcmd @@ -272,7 +272,6 @@ def handle_G(subcmd: str) -> Reply: return REPLY_OK - def handle_H(subcmd: str) -> Reply: op = subcmd[0] @@ -281,14 +280,12 @@ def handle_H(subcmd: str) -> Reply: return REPLY_EMPTY - def handle_k(subcmd: str) -> Reply: global killed killed = True return REPLY_OK - def handle_m(subcmd: str) -> Reply: """Read target memory. """ @@ -302,7 +299,6 @@ def handle_m(subcmd: str) -> Reply: else: return data - def handle_M(subcmd: str) -> Reply: """Write target memory. """ @@ -322,7 +318,6 @@ def handle_M(subcmd: str) -> Reply: else: return REPLY_OK - def handle_p(subcmd: str) -> Reply: """Read register value by index. """ @@ -331,7 +326,6 @@ def handle_p(subcmd: str) -> Reply: return __get_reg_value(*self.regsmap[idx]) - def handle_P(subcmd: str) -> Reply: """Write register value by index. """ @@ -346,7 +340,6 @@ def handle_P(subcmd: str) -> Reply: return 'E00' - def handle_Q(subcmd: str) -> Reply: """General queries. @@ -369,14 +362,12 @@ def handle_Q(subcmd: str) -> Reply: return REPLY_OK if feature in supported else REPLY_EMPTY - def handle_D(subcmd: str) -> Reply: """Detach. """ return REPLY_OK - def handle_q(subcmd: str) -> Reply: query, *data = subcmd.split(':') @@ -396,13 +387,9 @@ def handle_q(subcmd: str) -> Reply: 'QAgent+', 'QCatchSyscalls+', 'QDisableRandomization+', - 'QEnvironmentHexEncoded+', - 'QEnvironmentReset+', - 'QEnvironmentUnset+', 'QNonStop+', 'QPassSignals+', 'QProgramSignals+', - 'QSetWorkingDir+', 'QStartNoAckMode+', 'QStartupWithShell+', 'QTBuffer:size+', @@ -415,7 +402,6 @@ def handle_q(subcmd: str) -> Reply: 'hwbreak+', 'multiprocess+', 'no-resumed+', - 'qXfer:auxv:read+', 'qXfer:features:read+', # 'qXfer:libraries-svr4:read+', # 'qXfer:osdata:read+', @@ -453,9 +439,19 @@ def handle_q(subcmd: str) -> Reply: # os dependent features if not self.ql.interpreter: + features += [ + 'QEnvironmentHexEncoded+', + 'QEnvironmentReset+', + 'QEnvironmentUnset+' + ] + # filesystem dependent features if hasattr(self.ql.os, 'path'): - features.append('qXfer:exec-file:read+') + features += [ + 'QSetWorkingDir+', + 'qXfer:auxv:read+', + 'qXfer:exec-file:read+' + ] # process dependent features if hasattr(self.ql.os, 'pid'): @@ -489,7 +485,7 @@ def handle_q(subcmd: str) -> Reply: elif feature == 'auxv' and op == 'read': try: with self.ql.os.fs_mapper.open('/proc/self/auxv', 'rb') as infile: - infile.seek(offset, 0) # SEEK_SET + infile.seek(offset, 0) # SEEK_SET auxv_data = infile.read(length) except FileNotFoundError: @@ -568,7 +564,6 @@ def handle_q(subcmd: str) -> Reply: return REPLY_EMPTY - def handle_v(subcmd: str) -> Reply: if subcmd == 'MustReplyEmpty': return REPLY_EMPTY @@ -590,15 +585,29 @@ def handle_v(subcmd: str) -> Reply: virtpath = self.ql.os.path.virtual_abspath(path) - if virtpath.startswith(r'/proc') and self.ql.os.fs_mapper.has_mapping(virtpath): - # Mapped object by itself is not backed with a host fd and thus a tempfile can - # 1. Make pread easy to implement and avoid duplicate code like seek, fd etc. - # 2. Avoid fd clash if we assign a generated fd. - tfile = tempfile.TemporaryFile("rb+") - tfile.write(self.ql.os.fs_mapper.open(virtpath, "rb+").read()) - tfile.seek(0, os.SEEK_SET) - fd = tfile.fileno() - self.fake_procfs[fd] = tfile + if virtpath.startswith(r'/proc/'): + pid, _, vfname = virtpath[6:].partition(r'/') + + # 42000 is a magic number indicating the remote process' pid + # see: https://sourceware.org/bugzilla/show_bug.cgi?id=17760 + if pid == '42000': + vfmap = { + 'maps': lambda: partial(QlProcFS.self_map, self.ql.mem) + } + + if vfname in vfmap and not self.ql.os.fs_mapper.has_mapping(virtpath): + self.ql.add_fs_mapper(virtpath, vfmap[vfname]()) + + if self.ql.os.fs_mapper.has_mapping(virtpath): + # Mapped object by itself is not backed with a host fd and thus a tempfile can + # 1. Make pread easy to implement and avoid duplicate code like seek, fd etc. + # 2. Avoid fd clash if we assign a generated fd. + tfile = tempfile.TemporaryFile("rb+") + tfile.write(self.ql.os.fs_mapper.open(virtpath, "rb+").read()) + tfile.seek(0, os.SEEK_SET) + + fd = tfile.fileno() + self.fake_procfs[fd] = tfile else: host_path = self.ql.os.path.virtual_to_host_path(path) @@ -621,10 +630,10 @@ def handle_v(subcmd: str) -> Reply: fd = int(fd, 16) os.close(fd) - + if fd in self.fake_procfs: del self.fake_procfs[fd] - + return 'F0' return REPLY_EMPTY @@ -658,22 +667,14 @@ def handle_v(subcmd: str) -> Reply: return REPLY_EMPTY - def handle_s(subcmd: str) -> Reply: """Perform a single step. """ - # BUG: a known unicorn caching issue causes it to emulate more - # steps than requestes. until that issue is fixed, single stepping - # is essentially broken. - # - # @see: https://github.com/unicorn-engine/unicorn/issues/1606 - self.gdb.resume_emu(steps=1) return f'S{SIGTRAP:02x}' - def handle_X(subcmd: str) -> Reply: """Write data to memory. """ @@ -692,7 +693,6 @@ def handle_X(subcmd: str) -> Reply: else: return REPLY_OK - def handle_Z(subcmd: str) -> Reply: """Insert breakpoints or watchpoints. """ @@ -708,11 +708,11 @@ def handle_Z(subcmd: str) -> Reply: # 4 = access watchpoint if type == 0: - self.gdb.bp_insert(addr) - return REPLY_OK + success = self.gdb.bp_insert(addr, kind) - return REPLY_EMPTY + return REPLY_OK if success else 'E22' + return REPLY_EMPTY def handle_z(subcmd: str) -> Reply: """Remove breakpoints or watchpoints. @@ -721,15 +721,11 @@ def handle_z(subcmd: str) -> Reply: type, addr, kind = (int(p, 16) for p in subcmd.split(',')) if type == 0: - try: - self.gdb.bp_remove(addr) - except ValueError: - return 'E22' - else: - return REPLY_OK + success = self.gdb.bp_remove(addr, kind) - return REPLY_EMPTY + return REPLY_OK if success else 'E22' + return REPLY_EMPTY handlers = { '!': handle_exclaim, diff --git a/qiling/debugger/gdb/utils.py b/qiling/debugger/gdb/utils.py index 30bba47e8..5e3b208bf 100644 --- a/qiling/debugger/gdb/utils.py +++ b/qiling/debugger/gdb/utils.py @@ -6,19 +6,19 @@ from typing import Optional from qiling import Qiling -from qiling.const import QL_ARCH # this code is partially based on uDbg # @see: https://github.com/iGio90/uDdbg PROMPT = r'gdb>' + class QlGdbUtils: def __init__(self, ql: Qiling, entry_point: int, exit_point: int): self.ql = ql self.exit_point = exit_point - self.bp_list = [] + self.swbp = set() self.last_bp = None def __entry_point_hook(ql: Qiling): @@ -32,45 +32,53 @@ def __entry_point_hook(ql: Qiling): # that hook will be used to set up the breakpoint handling hook ep_hret = ql.hook_address(__entry_point_hook, entry_point) - def dbg_hook(self, ql: Qiling, address: int, size: int): - if ql.arch.type == QL_ARCH.ARM and ql.arch.is_thumb: - address += 1 + if getattr(ql.arch, 'is_thumb', False): + address |= 1 # resuming emulation after hitting a breakpoint will re-enter this hook. # avoid an endless hooking loop by detecting and skipping this case if address == self.last_bp: self.last_bp = None - elif address in self.bp_list: + elif address in self.swbp: self.last_bp = address ql.log.info(f'{PROMPT} breakpoint hit, stopped at {address:#x}') ql.stop() - # # TODO: not sure what this is about - # if address + size == self.exit_point: - # ql.log.debug(f'{PROMPT} emulation entrypoint at {self.entry_point:#x}') - # ql.log.debug(f'{PROMPT} emulation exitpoint at {self.exit_point:#x}') + def bp_insert(self, addr: int, size: int): + targets = set(addr + i for i in range(size or 1)) + + if targets.intersection(self.swbp): + return False + + for bp in targets: + self.swbp.add(bp) + + self.ql.log.info(f'{PROMPT} breakpoint added at {addr:#x}') + + return True + def bp_remove(self, addr: int, size: int) -> bool: + targets = set(addr + i for i in range(size or 1)) - def bp_insert(self, addr: int): - if addr not in self.bp_list: - self.bp_list.append(addr) - self.ql.log.info(f'{PROMPT} breakpoint added at {addr:#x}') + if not targets.issubset(self.swbp): + return False + for bp in targets: + self.swbp.remove(bp) - def bp_remove(self, addr: int): - self.bp_list.remove(addr) self.ql.log.info(f'{PROMPT} breakpoint removed from {addr:#x}') + return True def resume_emu(self, address: Optional[int] = None, steps: int = 0): if address is None: address = self.ql.arch.regs.arch_pc - if self.ql.arch.type == QL_ARCH.ARM and self.ql.arch.is_thumb: - address += 1 + if getattr(self.ql.arch, 'is_thumb', False): + address |= 0b1 op = f'stepping {steps} instructions' if steps else 'resuming' self.ql.log.info(f'{PROMPT} {op} from {address:#x}') diff --git a/qiling/debugger/gdb/xmlregs.py b/qiling/debugger/gdb/xmlregs.py index 7385a303f..89b68964b 100644 --- a/qiling/debugger/gdb/xmlregs.py +++ b/qiling/debugger/gdb/xmlregs.py @@ -3,28 +3,39 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -from typing import Iterator, Mapping, Optional, Sequence, Tuple +from typing import Iterator, List, Mapping, Optional, Sequence, Tuple from pathlib import PurePath from xml.etree import ElementTree, ElementInclude -from qiling.arch.arm_const import reg_map as arm_regs -from qiling.arch.arm_const import reg_vfp as arm_regs_vfp -from qiling.arch.arm64_const import reg_map as arm64_regs -from qiling.arch.arm64_const import reg_map_v as arm64_regs_v -from qiling.arch.mips_const import reg_map as mips_regs_gpr -from qiling.arch.mips_const import reg_map_fpu as mips_regs_fpu -from qiling.arch.x86_const import reg_map_32 as x86_regs_32 -from qiling.arch.x86_const import reg_map_64 as x86_regs_64 -from qiling.arch.x86_const import reg_map_misc as x86_regs_misc -from qiling.arch.x86_const import reg_map_cr as x86_regs_cr -from qiling.arch.x86_const import reg_map_st as x86_regs_st -from qiling.arch.x86_const import reg_map_xmm as x86_regs_xmm -from qiling.arch.x86_const import reg_map_ymm as x86_regs_ymm +from qiling.arch.arm_const import ( + reg_map as arm_regs, + reg_vfp as arm_regs_vfp, + reg_map_q as arm_regs_q, + reg_map_s as arm_regs_s +) +from qiling.arch.arm64_const import ( + reg_map as arm64_regs, + reg_map_v as arm64_regs_v +) +from qiling.arch.mips_const import ( + reg_map as mips_regs_gpr, + reg_map_fpu as mips_regs_fpu +) +from qiling.arch.x86_const import ( + reg_map_32 as x86_regs_32, + reg_map_64 as x86_regs_64, + reg_map_misc as x86_regs_misc, + reg_map_cr as x86_regs_cr, + reg_map_st as x86_regs_st, + reg_map_xmm as x86_regs_xmm, + reg_map_ymm as x86_regs_ymm +) from qiling.const import QL_ARCH, QL_OS RegEntry = Tuple[Optional[int], int, int] + class QlGdbFeatures: def __init__(self, archtype: QL_ARCH, ostype: QL_OS): xmltree = QlGdbFeatures.__load_target_xml(archtype, ostype) @@ -79,13 +90,13 @@ def __wrapped(href: str, parse, encoding=None): # earlier gdb versions use 'Cygwin' instead abitag = { - QL_OS.LINUX : 'GNU/Linux', - QL_OS.FREEBSD : 'FreeBSD', - QL_OS.MACOS : 'Darwin', - QL_OS.WINDOWS : 'Windows', - QL_OS.UEFI : 'Windows', - QL_OS.DOS : 'Windows', - QL_OS.QNX : 'QNX-Neutrino' + QL_OS.LINUX: 'GNU/Linux', + QL_OS.FREEBSD: 'FreeBSD', + QL_OS.MACOS: 'Darwin', + QL_OS.WINDOWS: 'Windows', + QL_OS.UEFI: 'Windows', + QL_OS.DOS: 'Windows', + QL_OS.QNX: 'QNX-Neutrino' }.get(ostype, 'unknown') osabi.text = abitag @@ -118,20 +129,20 @@ def __load_regsmap(archtype: QL_ARCH, xmltree: ElementTree.ElementTree) -> Seque # retreive the relevant set of registers; their order of appearance is not # important as it is determined by the info read from the xml files ucregs: Mapping[str, int] = { - QL_ARCH.A8086 : dict(**x86_regs_32, **x86_regs_misc, **x86_regs_cr, **x86_regs_st), - QL_ARCH.X86 : dict(**x86_regs_32, **x86_regs_misc, **x86_regs_cr, **x86_regs_st, **x86_regs_xmm), - QL_ARCH.X8664 : dict(**x86_regs_64, **x86_regs_misc, **x86_regs_cr, **x86_regs_st, **x86_regs_xmm, **x86_regs_ymm), - QL_ARCH.ARM : dict(**arm_regs, **arm_regs_vfp), - QL_ARCH.CORTEX_M : arm_regs, - QL_ARCH.ARM64 : dict(**arm64_regs, **arm64_regs_v), - QL_ARCH.MIPS : dict(**mips_regs_gpr, **mips_regs_fpu) + QL_ARCH.A8086: dict(**x86_regs_32, **x86_regs_misc, **x86_regs_cr, **x86_regs_st), + QL_ARCH.X86: dict(**x86_regs_32, **x86_regs_misc, **x86_regs_cr, **x86_regs_st, **x86_regs_xmm), + QL_ARCH.X8664: dict(**x86_regs_64, **x86_regs_misc, **x86_regs_cr, **x86_regs_st, **x86_regs_xmm, **x86_regs_ymm), + QL_ARCH.ARM: dict(**arm_regs, **arm_regs_vfp, **arm_regs_q, **arm_regs_s), + QL_ARCH.CORTEX_M: arm_regs, + QL_ARCH.ARM64: dict(**arm64_regs, **arm64_regs_v), + QL_ARCH.MIPS: dict(**mips_regs_gpr, **mips_regs_fpu) }[archtype] regsinfo = sorted(QlGdbFeatures.__walk_xml_regs(xmltree)) # pre-allocate regmap and occupy it with null entries last_regnum = regsinfo[-1][0] - regmap: Sequence[RegEntry] = [(None, 0, 0)] * (last_regnum + 1) + regmap: List[RegEntry] = [(None, 0, 0)] * (last_regnum + 1) pos = 0 diff --git a/qiling/debugger/qdb/arch/arch_arm.py b/qiling/debugger/qdb/arch/arch_arm.py index 1e24eef19..ed2e797c4 100644 --- a/qiling/debugger/qdb/arch/arch_arm.py +++ b/qiling/debugger/qdb/arch/arch_arm.py @@ -10,16 +10,21 @@ class ArchARM(Arch): def __init__(self): super().__init__() - - @property - def regs(self): - return ( + self._regs = ( "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc", ) + @property + def regs(self): + return self._regs + + @regs.setter + def regs(self, regs): + self._regs += regs + @property def regs_need_swapped(self): return { diff --git a/qiling/debugger/qdb/branch_predictor/branch_predictor_x8664.py b/qiling/debugger/qdb/branch_predictor/branch_predictor_x8664.py index f50dad11a..eda3a5923 100644 --- a/qiling/debugger/qdb/branch_predictor/branch_predictor_x8664.py +++ b/qiling/debugger/qdb/branch_predictor/branch_predictor_x8664.py @@ -98,7 +98,7 @@ def predict(self): prophecy.going = jump_reg_table.get(line.mnemonic)(self.ql.arch.regs.ecx) if prophecy.going: - takeaway_list = ["ptr", "dword", "[", "]"] + takeaway_list = ["ptr", "dword", "qword", "[", "]"] if len(line.op_str.split()) > 1: new_line = line.op_str.replace(":", "+") @@ -114,7 +114,6 @@ def predict(self): if each_reg in new_line: new_line = re.sub(each_reg, hex(self.read_reg(each_reg)), new_line) - prophecy.where = check_and_eval(new_line) elif line.op_str in self.ql.arch.regs.register_mapping: diff --git a/qiling/debugger/qdb/memory.py b/qiling/debugger/qdb/memory.py index 9dbece6a9..e26f49302 100644 --- a/qiling/debugger/qdb/memory.py +++ b/qiling/debugger/qdb/memory.py @@ -167,8 +167,19 @@ def parse(self, line: str): for each in output: print(f"0x{each.address:x}: {each.mnemonic}\t{each.op_str}") + elif ft == "s": + # handle read c-style string + try: + print(f"0x{addr:08x}: {self.ql.os.utils.read_cstring(addr)}") + except: + return f"error reading c-style string at 0x{addr:08x}" + else: lines = 1 if ct <= 4 else math.ceil(ct / 4) + # parse command + prefix = "0x" if ft in ("x", "a") else "" + pad = '0' + str(sz*2) if ft in ('x', 'a', 't') else '' + ft = ft.lower() if ft in ("x", "o", "b", "d") else ft.lower().replace("t", "b").replace("a", "x") mem_read = [] for offset in range(ct): @@ -186,9 +197,6 @@ def parse(self, line: str): idx = line * self.ql.arch.pointersize for each in mem_read[idx:idx+self.ql.arch.pointersize]: data = self.fmt_unpack(each, sz) - prefix = "0x" if ft in ("x", "a") else "" - pad = '0' + str(sz*2) if ft in ('x', 'a', 't') else '' - ft = ft.lower() if ft in ("x", "o", "b", "d") else ft.lower().replace("t", "b").replace("a", "x") print(f"{prefix}{data:{pad}{ft}}\t", end="") print() diff --git a/qiling/debugger/qdb/qdb.py b/qiling/debugger/qdb/qdb.py index 4dd516e7c..0d1d1fbf6 100644 --- a/qiling/debugger/qdb/qdb.py +++ b/qiling/debugger/qdb/qdb.py @@ -3,12 +3,13 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -from typing import Callable, Optional, Mapping, Tuple, Union - import cmd +from typing import Optional, Tuple, Union +from contextlib import contextmanager + from qiling import Qiling -from qiling.const import QL_OS, QL_ARCH, QL_VERBOSE +from qiling.const import QL_OS, QL_ARCH, QL_ENDIAN from qiling.debugger import QlDebugger from .utils import setup_context_render, setup_branch_predictor, setup_address_marker, SnapshotManager, run_qdb_script @@ -18,6 +19,7 @@ from .utils import QDB_MSG, qdb_print + class QlQdb(cmd.Cmd, QlDebugger): """ The built-in debugger of Qiling Framework @@ -81,11 +83,7 @@ def bp_handler(ql, address, size, bp_list): self.cur_addr = self.ql.loader.entry_point - if self.ql.arch.type == QL_ARCH.CORTEX_M: - self._run() - - else: - self.init_state = self.ql.save() + self.init_state = self.ql.save() if self._script: run_qdb_script(self, self._script) @@ -117,27 +115,26 @@ def _run(self, address: int = 0, end: int = 0, count: int = 0) -> None: if not address: address = self.cur_addr - if self.ql.arch.type == QL_ARCH.CORTEX_M and self.ql.count != 0: - - while self.ql.count: - - if (bp := self.bp_list.pop(self.cur_addr, None)): - if isinstance(bp, TempBreakpoint): - self.del_breakpoint(bp) - else: - qdb_print(QDB_MSG.INFO, f"hit breakpoint at 0x{self.cur_addr:08x}") - - break - - self.ql.arch.step() - self.ql.count -= 1 + if getattr(self.ql.arch, 'is_thumb', False): + address |= 1 - return + # assume we're running PE if on Windows + if self.ql.os.type == QL_OS.WINDOWS: + self.ql.count = count + self.ql.entry_point = address + self.ql.os.run() - if self.ql.arch.type in (QL_ARCH.ARM, QL_ARCH.CORTEX_M) and self.ql.arch.is_thumb: - address |= 1 + else: + self.ql.emu_start(begin=address, end=end, count=count) - self.ql.emu_start(begin=address, end=end, count=count) + @contextmanager + def _save(self, reg=True, mem=True, hw=False, fd=False, cpu_context=False, os=False, loader=False): + """ + helper function for fetching specific context by emulating instructions + """ + saved_states = self.ql.save(reg=reg, mem=mem) + yield self + self.ql.restore(saved_states) def save_reg_dump(func) -> None: """ @@ -226,11 +223,12 @@ def do_step_in(self, *args) -> Optional[bool]: if prophecy.where is True: return True - if self.ql.arch == QL_ARCH.CORTEX_M: - self.ql.arch.step() - else: - self._run(count=1) + step = 1 + # make sure follow branching + if prophecy.going is True and self.ql.arch.type == QL_ARCH.MIPS: + step += 1 + self._run(count=step) self.do_context() @SnapshotManager.snapshot @@ -245,7 +243,12 @@ def do_step_over(self, *args) -> Optional[bool]: if prophecy.going: cur_insn = self.predictor.disasm(self.cur_addr) - self.set_breakpoint(self.cur_addr + cur_insn.size, is_temp=True) + bp_addr = self.cur_addr + cur_insn.size + + if self.ql.arch.type == QL_ARCH.MIPS: + bp_addr += cur_insn.size + + self.set_breakpoint(bp_addr, is_temp=True) else: self.set_breakpoint(prophecy.where, is_temp=True) @@ -333,7 +336,7 @@ def do_examine(self, line: str) -> None: if type(err_msg := self.mm.parse(line)) is str: qdb_print(QDB_MSG.ERROR, err_msg) - + def do_set(self, line: str) -> None: """ @@ -431,13 +434,101 @@ def do_mark(self, args=""): qdb_print(QDB_MSG.INFO, f"mark symbol '{sym_name}' at address: 0x{loc:08x} ...") + @parse_int + def do_show_args(self, argc: int = -1): + """ + show arguments of a function call + default argc is 2 since we don't know the function definition + """ + + if argc is None: + argc = -1 + + elif argc > 16: + qdb_print(QDB_MSG.ERROR, 'Maximum argc is 16.') + return + + prophecy = self.predictor.predict() + if not prophecy.going: + qdb_print(QDB_MSG.ERROR, 'Not on a braching instruction currently.') + return + + if argc == -1: + reg_n, stk_n = 2, 0 + else: + if argc > 4: + stk_n = argc - 4 + elif argc <= 4: + reg_n, stk_n = argc, 0 + + ptr_size = self.ql.arch.pointersize + + reg_args = [] + arch_type = self.ql.arch.type + if arch_type in (QL_ARCH.MIPS, QL_ARCH.ARM, QL_ARCH.CORTEX_M, QL_ARCH.X8664): + + reg_idx = None + if arch_type == QL_ARCH.MIPS: + slot_addr = self.cur_addr + ptr_size + + op_str = self.predictor.disasm(slot_addr).op_str + # register may be changed due to dealy slot + if '$a' in op_str.split(',')[0]: + dst_reg = op_str.split(',')[0].strip('$') + reg_idx = int(dst_reg.strip('a')) + + # fetch real value by emulating instruction in delay slot + with self._save() as qdb: + qdb._run(slot_addr, 0, count=1) + real_val = self.ql.arch.regs.read(dst_reg) + + reg_names = [f'a{d}'for d in range(reg_n)] + if reg_idx != None: + reg_names.pop(reg_idx) + + elif arch_type in (QL_ARCH.ARM, QL_ARCH.CORTEX_M): + reg_names = [f'r{d}'for d in range(reg_n)] + + elif arch_type == QL_ARCH.X8664: + reg_names = ('rdi', 'rsi', 'rdx', 'rcx', 'r8', 'r9')[:reg_n] + + reg_args = [self.ql.arch.regs.read(reg_name) for reg_name in reg_names] + if reg_idx != None: + reg_args.insert(reg_idx, real_val) + + reg_args = list(map(hex, reg_args)) + + elif arch_type == QL_ARCH.X86: + stk_n = 2 if argc == -1 else argc + + # read arguments on stack + if stk_n >= 0: + shadow_n = 0 + base_offset = self.ql.arch.regs.arch_sp + + if arch_type in (QL_ARCH.X86, QL_ARCH.X8664): + # shadow 1 pointer size for return address + shadow_n = 1 + + elif arch_type == QL_ARCH.MIPS: + # shadow 4 pointer size for mips + shadow_n = 4 + + base_offset = self.ql.arch.regs.arch_sp + shadow_n * ptr_size + stk_args = [self.ql.mem.read(base_offset+offset*ptr_size, ptr_size) for offset in range(stk_n)] + endian = 'little' if self.ql.arch.endian == QL_ENDIAN.EL else 'big' + stk_args = list(map(hex, map(lambda x: int.from_bytes(x, endian), stk_args))) + + args = reg_args + stk_args + qdb_print(QDB_MSG.INFO, f'args: {args}') + def do_show(self, *args) -> None: """ show some runtime information """ for info_line in self.ql.mem.get_formatted_mapinfo(): - self.ql.log.info(info_line) + qdb_print(QDB_MSG.INFO, info_line) qdb_print(QDB_MSG.INFO, f"Breakpoints: {[hex(addr) for addr in self.bp_list.keys()]}") qdb_print(QDB_MSG.INFO, f"Marked symbol: {[{key:hex(val)} for key,val in self.marker.mark_list]}") @@ -487,6 +578,7 @@ def do_EOF(self, *args) -> None: do_r = do_run do_s = do_step_in do_n = do_step_over + do_a = do_show_args do_j = do_jump do_m = do_mark do_q = do_quit diff --git a/qiling/debugger/qdb/render/render.py b/qiling/debugger/qdb/render/render.py index 393e7707b..4ce64fa1c 100644 --- a/qiling/debugger/qdb/render/render.py +++ b/qiling/debugger/qdb/render/render.py @@ -51,6 +51,7 @@ def wrapper(*args, **kwargs): def __init__(self): self.regs_a_row = 4 self.stack_num = 10 + self.disasm_num = 0x10 self.color = color def reg_diff(self, cur_regs, saved_reg_dump): @@ -100,7 +101,7 @@ def render_stack_dump(self, arch_sp: int) -> None: if (val := self.try_read_pointer(addr)[0]): # defined to be try_read_pointer(addr)[0] - dereferneces pointer # @TODO: Bug here where the values on the stack are being displayed in 32-bit format - print(f"RSP + 0x{idx*self.pointersize:02x}│ [0x{addr:08x}] —▸ 0x{self.unpack(val):08x}", end="") + print(f"SP + 0x{idx*self.pointersize:02x}│ [0x{addr:08x}] —▸ 0x{self.unpack(val):08x}", end="") # try to dereference wether it's a pointer if (buf := self.try_read_pointer(addr))[0] is not None: @@ -188,7 +189,6 @@ def context_stack(self) -> None: display context stack dump """ - print(f"{self.ql.arch.regs.arch_sp:x}") self.render_stack_dump(self.ql.arch.regs.arch_sp) @Render.divider_printer("[ REGISTERS ]") @@ -207,13 +207,14 @@ def context_asm(self) -> None: lines = {} past_list = [] - from_addr = self.cur_addr - 0x10 - to_addr = self.cur_addr + 0x10 + from_addr = self.cur_addr - self.disasm_num + to_addr = self.cur_addr + self.disasm_num cur_addr = from_addr while cur_addr != to_addr: insn = self.disasm(cur_addr) - cur_addr += self.arch_insn_size + # cur_addr += self.arch_insn_size + cur_addr += insn.size if not insn: continue past_list.append(insn) diff --git a/qiling/debugger/qdb/render/render_arm.py b/qiling/debugger/qdb/render/render_arm.py index 4e10ac27d..7209be2c6 100644 --- a/qiling/debugger/qdb/render/render_arm.py +++ b/qiling/debugger/qdb/render/render_arm.py @@ -16,10 +16,20 @@ class ContextRenderARM(ContextRender, ArchARM): def __init__(self, ql, predictor): super().__init__(ql, predictor) ArchARM.__init__(self) + self.disasm_num = 8 @staticmethod def print_mode_info(bits): - print(color.GREEN, "[{cpsr[mode]} mode], Thumb: {cpsr[thumb]}, FIQ: {cpsr[fiq]}, IRQ: {cpsr[irq]}, NEG: {cpsr[neg]}, ZERO: {cpsr[zero]}, Carry: {cpsr[carry]}, Overflow: {cpsr[overflow]}".format(cpsr=ArchARM.get_flags(bits)), color.END, sep="") + flags = ArchARM.get_flags(bits) + + print(f"[{flags.pop('mode')} mode] ", end="") + for key, val in flags.items(): + if val: + print(f"{color.BLUE}{key.upper()} ", end="") + else: + print(f"{color.GREEN}{key.lower()} ", end="") + + print(color.END) @Render.divider_printer("[ REGISTERS ]") def context_reg(self, saved_reg_dump): diff --git a/qiling/debugger/qdb/render/render_x86.py b/qiling/debugger/qdb/render/render_x86.py index 5c43d0e55..c13b92fe7 100644 --- a/qiling/debugger/qdb/render/render_x86.py +++ b/qiling/debugger/qdb/render/render_x86.py @@ -22,7 +22,17 @@ def context_reg(self, saved_reg_dump): cur_regs = self.dump_regs() diff_reg = self.reg_diff(cur_regs, saved_reg_dump) self.render_regs_dump(cur_regs, diff_reg=diff_reg) - print(color.GREEN, "EFLAGS: [CF: {flags[CF]}, PF: {flags[PF]}, AF: {flags[AF]}, ZF: {flags[ZF]}, SF: {flags[SF]}, OF: {flags[OF]}]".format(flags=self.get_flags(self.ql.arch.regs.eflags)), color.END, sep="") + + flags = self.get_flags(self.ql.arch.regs.eflags) + print("EFLAGS: ", end="") + print(color.GREEN, end="") + for key, val in flags.items(): + if val: + print(f"{color.BLUE}{key.upper()} ", end="") + else: + print(f"{color.GREEN}{key.lower()} ", end="") + + print(color.END) @Render.divider_printer("[ DISASM ]") def context_asm(self): diff --git a/qiling/extensions/afl/__init__.py b/qiling/extensions/afl/__init__.py index 05f5d6fc7..ceeeabe5a 100644 --- a/qiling/extensions/afl/__init__.py +++ b/qiling/extensions/afl/__init__.py @@ -1 +1 @@ -from .afl import ql_afl_fuzz \ No newline at end of file +from .afl import ql_afl_fuzz, ql_afl_fuzz_custom \ No newline at end of file diff --git a/qiling/extensions/mcu/__init__.py b/qiling/extensions/mcu/__init__.py new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/qiling/extensions/mcu/__init__.py @@ -0,0 +1 @@ + diff --git a/qiling/extensions/mcu/atmel/sam3x8e.py b/qiling/extensions/mcu/atmel/sam3x8e.py index 1be34c01a..6c2328cc3 100644 --- a/qiling/extensions/mcu/atmel/sam3x8e.py +++ b/qiling/extensions/mcu/atmel/sam3x8e.py @@ -5,16 +5,31 @@ sam3x8e = { "SRAM BB": { - "alias": 0x22000000, - "base": 0x20000000, - "size": 0x200000, - "type": "bitband" + "base": 0x22000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x20000000, + "size": 0x200000, + } }, "PERIP BB": { - "alias": 0x42000000, - "base": 0x40000000 , - "size": 0x100000, - "type": "bitband" + "base": 0x42000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x40000000, + "size": 0x100000, + } + }, + "REMAP": { + "base": 0x0, + "struct": "MemoryRemap", + "type": "core", + "kwargs": { + "base": 0x80000, + "size": 0x80000, + } }, "SYSTICK": { "base": 0xe000e010, @@ -56,6 +71,21 @@ "size": 0x100000, "type": "mmio" }, + "SRAM BBR": { + "base": 0x22000000, + "size": 0x4000000, + "type": "mmio" + }, + "PERIP BBR": { + "base": 0x42000000, + "size": 0x2000000, + "type": "mmio" + }, + "REMAP REGION": { + "base": 0x0, + "size": 0x80000, + "type": "mmio", + }, "HSMCI": { "base": 0x40000000, "struct": "SAM3xaHsmci", @@ -256,15 +286,15 @@ "intn": 0x27 } }, - "DACC": { + "DAC": { "base": 0x400c8000, - "struct": "SAM3xaDacc", + "struct": "SAM3xaDac", "type": "peripheral", "kwargs": { "intn": 0x26 } }, - "PDC_DACC": { + "PDC_DAC": { "base": 0x400c8100, "struct": "SAM3xaPdc", "type": "peripheral" @@ -401,10 +431,4 @@ "struct": "SAM3xaGpbr", "type": "peripheral" }, - "CODE": { - "base": 0x80000, - "size": 0x80000, - "alias": 0x0, - "type": "remap" - } } \ No newline at end of file diff --git a/qiling/hw/adc/__init__.py b/qiling/extensions/mcu/nxp/__init__.py similarity index 73% rename from qiling/hw/adc/__init__.py rename to qiling/extensions/mcu/nxp/__init__.py index 446ef249b..1318afcf5 100644 --- a/qiling/hw/adc/__init__.py +++ b/qiling/extensions/mcu/nxp/__init__.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -from .sam3xa_adc import SAM3xaAdc +from .mk64f12 import mk64f12 diff --git a/qiling/extensions/mcu/nxp/mk64f12.py b/qiling/extensions/mcu/nxp/mk64f12.py new file mode 100644 index 000000000..ee88d4f35 --- /dev/null +++ b/qiling/extensions/mcu/nxp/mk64f12.py @@ -0,0 +1,610 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +mk64f12 = { + "BME": { + "base": 0x44000000, + "struct": "KinetisBME", + "type": "core", + "kwargs": { + "base": 0x40000000, + "size": 0x70000, + } + }, + "PERIP BB": { + "base": 0x42000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x40000000, + "size": 0x100000, + } + }, + "SYSTICK": { + "base": 0xe000e010, + "struct": "CortexM4SysTick", + "type": "core" + }, + "NVIC": { + "base": 0xe000e100, + "struct": "CortexM4Nvic", + "type": "core" + }, + "SCB": { + "base": 0xe000ed00, + "struct": "CortexM4Scb", + "type": "core" + }, + "FLASH": { + "base": 0x00000000, + "size": 0x100000, + "type": "memory", + }, + "SRAM": { + "base": 0x1fff0000, + "size": 0x00040000, + "type": "memory", + }, + "PERIP": { + "base": 0x40000000, + "size": 0x100000, + "type": "mmio" + }, + "PERIP BBR": { + "base": 0x42000000, + "size": 0x2000000, + "type": "mmio" + }, + "PPB": { + "base": 0xe0000000, + "size": 0x100000, + "type": "mmio" + }, + "BME AND REGION": { + "base": 0x44000000, + "size": 0x70000, + "type": "mmio" + }, + "BME OR REGION": { + "base": 0x48000000, + "size": 0x70000, + "type": "mmio" + }, + "FTFE": { + "type": "peripheral", + "base": 0x400, + "struct": "MK64F12Ftfe" + }, + "AIPS0": { + "type": "peripheral", + "base": 0x40000000, + "struct": "MK64F12Aips" + }, + "AIPS1": { + "type": "peripheral", + "base": 0x40080000, + "struct": "MK64F12Aips" + }, + "AXBS": { + "type": "peripheral", + "base": 0x40004000, + "struct": "MK64F12Axbs" + }, + "DMA": { + "type": "peripheral", + "base": 0x40008000, + "struct": "MK64F12Dma", + "kwargs": { + "dma0_intn": 0x0, + "dma1_intn": 0x1, + "dma2_intn": 0x2, + "dma3_intn": 0x3, + "dma4_intn": 0x4, + "dma5_intn": 0x5, + "dma6_intn": 0x6, + "dma7_intn": 0x7, + "dma8_intn": 0x8, + "dma9_intn": 0x9, + "dma10_intn": 0xa, + "dma11_intn": 0xb, + "dma12_intn": 0xc, + "dma13_intn": 0xd, + "dma14_intn": 0xe, + "dma15_intn": 0xf, + "error_intn": 0x10 + } + }, + "FB": { + "type": "peripheral", + "base": 0x4000c000, + "struct": "MK64F12Fb" + }, + "SYSMPU": { + "type": "peripheral", + "base": 0x4000d000, + "struct": "MK64F12Sysmpu" + }, + "FMC": { + "type": "peripheral", + "base": 0x4001f000, + "struct": "MK64F12Fmc" + }, + "FTFE": { + "type": "peripheral", + "base": 0x40020000, + "struct": "MK64F12Ftfe", + "kwargs": { + "intn": 0x12, + "read_collision_intn": 0x13 + } + }, + "DMAMUX": { + "type": "peripheral", + "base": 0x40021000, + "struct": "MK64F12Dmamux" + }, + "CAN0": { + "type": "peripheral", + "base": 0x40024000, + "struct": "MK64F12Can", + "kwargs": { + "ored_message_buffer_intn": 0x4b, + "bus_off_intn": 0x4c, + "error_intn": 0x4d, + "tx_warning_intn": 0x4e, + "rx_warning_intn": 0x4f, + "wake_up_intn": 0x50 + } + }, + "RNG": { + "type": "peripheral", + "base": 0x40029000, + "struct": "MK64F12Rng", + "kwargs": { + "intn": 0x17 + } + }, + "SPI0": { + "type": "peripheral", + "base": 0x4002c000, + "struct": "MK64F12Spi", + "kwargs": { + "intn": 0x1a + } + }, + "SPI1": { + "type": "peripheral", + "base": 0x4002d000, + "struct": "MK64F12Spi", + "kwargs": { + "intn": 0x1b + } + }, + "SPI2": { + "type": "peripheral", + "base": 0x400ac000, + "struct": "MK64F12Spi", + "kwargs": { + "intn": 0x41 + } + }, + "I2S0": { + "type": "peripheral", + "base": 0x4002f000, + "struct": "MK64F12I2s", + "kwargs": { + "tx_intn": 0x1c, + "rx_intn": 0x1d + } + }, + "CRC": { + "type": "peripheral", + "base": 0x40032000, + "struct": "MK64F12Crc" + }, + "USBDCD": { + "type": "peripheral", + "base": 0x40035000, + "struct": "MK64F12Usbdcd", + "kwargs": { + "intn": 0x36 + } + }, + "PDB0": { + "type": "peripheral", + "base": 0x40036000, + "struct": "MK64F12Pdb", + "kwargs": { + "intn": 0x34 + } + }, + "PIT": { + "type": "peripheral", + "base": 0x40037000, + "struct": "MK64F12Pit", + "kwargs": { + "pit0_intn": 0x30, + "pit1_intn": 0x31, + "pit2_intn": 0x32, + "pit3_intn": 0x33 + } + }, + "FTM0": { + "type": "peripheral", + "base": 0x40038000, + "struct": "MK64F12Ftm", + "kwargs": { + "intn": 0x2a + } + }, + "FTM1": { + "type": "peripheral", + "base": 0x40039000, + "struct": "MK64F12Ftm", + "kwargs": { + "intn": 0x2b + } + }, + "FTM2": { + "type": "peripheral", + "base": 0x4003a000, + "struct": "MK64F12Ftm", + "kwargs": { + "intn": 0x2c + } + }, + "FTM3": { + "type": "peripheral", + "base": 0x400b9000, + "struct": "MK64F12Ftm", + "kwargs": { + "intn": 0x47 + } + }, + "ADC0": { + "type": "peripheral", + "base": 0x4003b000, + "struct": "MK64F12Adc", + "kwargs": { + "intn": 0x27 + } + }, + "ADC1": { + "type": "peripheral", + "base": 0x400bb000, + "struct": "MK64F12Adc", + "kwargs": { + "intn": 0x49 + } + }, + "RTC": { + "type": "peripheral", + "base": 0x4003d000, + "struct": "MK64F12Rtc", + "kwargs": { + "intn": 0x2e, + "seconds_intn": 0x2f + } + }, + "RFVBAT": { + "type": "peripheral", + "base": 0x4003e000, + "struct": "MK64F12Rfvbat" + }, + "LPTMR0": { + "type": "peripheral", + "base": 0x40040000, + "struct": "MK64F12Lptmr", + "kwargs": { + "intn": 0x3a + } + }, + "RFSYS": { + "type": "peripheral", + "base": 0x40041000, + "struct": "MK64F12Rfsys" + }, + "SIM": { + "type": "peripheral", + "base": 0x40047000, + "struct": "MK64F12Sim" + }, + "PORTA": { + "type": "peripheral", + "base": 0x40049000, + "struct": "MK64F12Port", + "kwargs": { + "intn": 0x3b + } + }, + "PORTB": { + "type": "peripheral", + "base": 0x4004a000, + "struct": "MK64F12Port", + "kwargs": { + "intn": 0x3c + } + }, + "PORTC": { + "type": "peripheral", + "base": 0x4004b000, + "struct": "MK64F12Port", + "kwargs": { + "intn": 0x3d + } + }, + "PORTD": { + "type": "peripheral", + "base": 0x4004c000, + "struct": "MK64F12Port", + "kwargs": { + "intn": 0x3e + } + }, + "PORTE": { + "type": "peripheral", + "base": 0x4004d000, + "struct": "MK64F12Port", + "kwargs": { + "intn": 0x3f + } + }, + "WDOG": { + "type": "peripheral", + "base": 0x40052000, + "struct": "MK64F12Wdog", + "kwargs": { + "ewm_intn": 0x16 + } + }, + "EWM": { + "type": "peripheral", + "base": 0x40061000, + "struct": "MK64F12Ewm", + "kwargs": { + "wdog_ewm_intn": 0x16 + } + }, + "CMT": { + "type": "peripheral", + "base": 0x40062000, + "struct": "MK64F12Cmt", + "kwargs": { + "intn": 0x2d + } + }, + "MCG": { + "type": "peripheral", + "base": 0x40064000, + "struct": "MK64F12Mcg" + }, + "OSC": { + "type": "peripheral", + "base": 0x40065000, + "struct": "MK64F12Osc" + }, + "I2C0": { + "type": "peripheral", + "base": 0x40066000, + "struct": "MK64F12I2c", + "kwargs": { + "intn": 0x18 + } + }, + "I2C1": { + "type": "peripheral", + "base": 0x40067000, + "struct": "MK64F12I2c", + "kwargs": { + "intn": 0x19 + } + }, + "I2C2": { + "type": "peripheral", + "base": 0x400e6000, + "struct": "MK64F12I2c", + "kwargs": { + "intn": 0x4a + } + }, + "UART0": { + "type": "peripheral", + "base": 0x4006a000, + "struct": "MK64F12Uart", + "kwargs": { + "lon_intn": 0x1e, + "rx_tx_intn": 0x1f, + "err_intn": 0x20 + } + }, + "UART1": { + "type": "peripheral", + "base": 0x4006b000, + "struct": "MK64F12Uart", + "kwargs": { + "rx_tx_intn": 0x21, + "err_intn": 0x22 + } + }, + "UART2": { + "type": "peripheral", + "base": 0x4006c000, + "struct": "MK64F12Uart", + "kwargs": { + "rx_tx_intn": 0x23, + "err_intn": 0x24 + } + }, + "UART3": { + "type": "peripheral", + "base": 0x4006d000, + "struct": "MK64F12Uart", + "kwargs": { + "rx_tx_intn": 0x25, + "err_intn": 0x26 + } + }, + "UART4": { + "type": "peripheral", + "base": 0x400ea000, + "struct": "MK64F12Uart", + "kwargs": { + "rx_tx_intn": 0x42, + "err_intn": 0x43 + } + }, + "UART5": { + "type": "peripheral", + "base": 0x400eb000, + "struct": "MK64F12Uart", + "kwargs": { + "rx_tx_intn": 0x44, + "err_intn": 0x45 + } + }, + "USB0": { + "type": "peripheral", + "base": 0x40072000, + "struct": "MK64F12Usb", + "kwargs": { + "intn": 0x35 + } + }, + "CMP0": { + "type": "peripheral", + "base": 0x40073000, + "struct": "MK64F12Cmp", + "kwargs": { + "intn": 0x28 + } + }, + "CMP1": { + "type": "peripheral", + "base": 0x40073008, + "struct": "MK64F12Cmp", + "kwargs": { + "intn": 0x29 + } + }, + "CMP2": { + "type": "peripheral", + "base": 0x40073010, + "struct": "MK64F12Cmp", + "kwargs": { + "intn": 0x46 + } + }, + "VREF": { + "type": "peripheral", + "base": 0x40074000, + "struct": "MK64F12Vref" + }, + "LLWU": { + "type": "peripheral", + "base": 0x4007c000, + "struct": "MK64F12Llwu", + "kwargs": { + "intn": 0x15 + } + }, + "PMC": { + "type": "peripheral", + "base": 0x4007d000, + "struct": "MK64F12Pmc", + "kwargs": { + "lvd_lvw_intn": 0x14 + } + }, + "SMC": { + "type": "peripheral", + "base": 0x4007e000, + "struct": "MK64F12Smc" + }, + "RCM": { + "type": "peripheral", + "base": 0x4007f000, + "struct": "MK64F12Rcm" + }, + "SDHC": { + "type": "peripheral", + "base": 0x400b1000, + "struct": "MK64F12Sdhc", + "kwargs": { + "intn": 0x51 + } + }, + "ENET": { + "type": "peripheral", + "base": 0x400c0000, + "struct": "MK64F12Enet", + "kwargs": { + "1588_timer_intn": 0x52, + "transmit_intn": 0x53, + "receive_intn": 0x54, + "error_intn": 0x55 + } + }, + "DAC0": { + "type": "peripheral", + "base": 0x400cc000, + "struct": "MK64F12Dac", + "kwargs": { + "intn": 0x38 + } + }, + "DAC1": { + "type": "peripheral", + "base": 0x400cd000, + "struct": "MK64F12Dac", + "kwargs": { + "intn": 0x48 + } + }, + "GPIOA": { + "type": "peripheral", + "base": 0x400ff000, + "struct": "MK64F12Gpio", + "kwargs": { + "intn": 0x3b + } + }, + "GPIOB": { + "type": "peripheral", + "base": 0x400ff040, + "struct": "MK64F12Gpio", + "kwargs": { + "intn": 0x3c + } + }, + "GPIOC": { + "type": "peripheral", + "base": 0x400ff080, + "struct": "MK64F12Gpio", + "kwargs": { + "intn": 0x3d + } + }, + "GPIOD": { + "type": "peripheral", + "base": 0x400ff0c0, + "struct": "MK64F12Gpio", + "kwargs": { + "intn": 0x3e + } + }, + "GPIOE": { + "type": "peripheral", + "base": 0x400ff100, + "struct": "MK64F12Gpio", + "kwargs": { + "intn": 0x3f + } + }, + "CAU": { + "type": "peripheral", + "base": 0xe0081000, + "struct": "MK64F12Cau" + } +} \ No newline at end of file diff --git a/qiling/extensions/mcu/stm32f1/stm32f103.py b/qiling/extensions/mcu/stm32f1/stm32f103.py index a7331ffee..dddafc040 100644 --- a/qiling/extensions/mcu/stm32f1/stm32f103.py +++ b/qiling/extensions/mcu/stm32f1/stm32f103.py @@ -5,16 +5,22 @@ stm32f103 = { "SRAM BB": { - "alias": 0x22000000, - "base": 0x20000000, - "size": 0x100000, - "type": "bitband" + "base": 0x22000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x20000000, + "size": 0x100000, + } }, "PERIP BB": { - "alias": 0x42000000, - "base": 0x40000000, - "size": 0x100000, - "type": "bitband" + "base": 0x42000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x40000000, + "size": 0x100000, + } }, "SYSTICK": { "base": 0xe000e010, @@ -56,6 +62,16 @@ "size": 0x100000, "type": "mmio" }, + "SRAM BBR": { + "base": 0x22000000, + "size": 0x2000000, + "type": "mmio" + }, + "PERIP BBR": { + "base": 0x42000000, + "size": 0x2000000, + "type": "mmio" + }, "TIM2": { "type": "peripheral", "base": 0x40000000, @@ -239,15 +255,9 @@ "struct": "STM32F1xxTim", "kwargs": { "brk_intn": 0x18, - "up_intn": 0x19, - "trg_com_intn": 0x1a, "cc_intn": 0x1b, - "brk_tim15_intn": 0x18, - "brk_tim9_intn": 0x18, - "trg_com_tim17_intn": 0x1a, - "trg_com_tim11_intn": 0x1a, - "up_tim16_intn": 0x19, - "up_tim10_intn": 0x19 + "trg_com_intn": 0x1a, + "up_intn": 0x19, } }, "SPI1": { @@ -307,10 +317,18 @@ "base": 0xe0042000, "struct": "STM32F1xxDbgmcu" }, - "CODE": { - "base": 0x8000000, + "REMAP": { + "base": 0x0, + "struct": "MemoryRemap", + "type": "core", + "kwargs": { + "base": 0x8000000, + "size": 0x80000, + } + }, + "REMAP REGION": { + "base": 0x0, "size": 0x80000, - "alias": 0x0, - "type": "remap" - } + "type": "mmio", + }, } \ No newline at end of file diff --git a/qiling/extensions/mcu/stm32f4/stm32f401.py b/qiling/extensions/mcu/stm32f4/stm32f401.py index a030de277..70c00c223 100644 --- a/qiling/extensions/mcu/stm32f4/stm32f401.py +++ b/qiling/extensions/mcu/stm32f4/stm32f401.py @@ -5,16 +5,31 @@ stm32f401 = { "SRAM BB": { - "alias": 0x22000000, - "base": 0x20000000, - "size": 0x100000, - "type": "bitband" + "base": 0x22000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x20000000, + "size": 0x100000, + } }, "PERIP BB": { - "alias": 0x42000000, - "base": 0x40000000, - "size": 0x100000, - "type": "bitband" + "base": 0x42000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x40000000, + "size": 0x100000, + } + }, + "REMAP": { + "base": 0x0, + "struct": "MemoryRemap", + "type": "core", + "kwargs": { + "base": 0x8000000, + "size": 0x80000, + } }, "SYSTICK": { "base": 0xe000e010, @@ -61,6 +76,21 @@ "size": 0x100000, "type": "mmio" }, + "SRAM BBR": { + "base": 0x22000000, + "size": 0x2000000, + "type": "mmio" + }, + "PERIP BBR": { + "base": 0x42000000, + "size": 0x2000000, + "type": "mmio" + }, + "REMAP REGION": { + "base": 0x0, + "size": 0x80000, + "type": "mmio", + }, "TIM2": { "base": 0x40000000, "struct": "STM32F4xxTim", @@ -185,10 +215,10 @@ "base": 0x40010000, "struct": "STM32F4xxTim", "kwargs": { - "brk_tim9_intn": 0x18, + "brk_intn": 0x18, "cc_intn": 0x1b, - "trg_com_tim11_intn": 0x1a, - "up_tim10_intn": 0x19 + "trg_com_intn": 0x1a, + "up_intn": 0x19 }, "type": "peripheral" }, @@ -351,10 +381,4 @@ }, "type": "peripheral" }, - "CODE": { - "base": 0x8000000, - "size": 0x80000, - "alias": 0x0, - "type": "remap" - } } \ No newline at end of file diff --git a/qiling/extensions/mcu/stm32f4/stm32f405.py b/qiling/extensions/mcu/stm32f4/stm32f405.py index eb9d86b9c..14b25e37c 100644 --- a/qiling/extensions/mcu/stm32f4/stm32f405.py +++ b/qiling/extensions/mcu/stm32f4/stm32f405.py @@ -5,16 +5,31 @@ stm32f405 = { "SRAM BB": { - "alias": 0x22000000, - "base": 0x20000000, - "size": 0x100000, - "type": "bitband" + "base": 0x22000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x20000000, + "size": 0x100000, + } }, "PERIP BB": { - "alias": 0x42000000, - "base": 0x40000000, - "size": 0x100000, - "type": "bitband" + "base": 0x42000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x40000000, + "size": 0x100000, + } + }, + "REMAP": { + "base": 0x0, + "struct": "MemoryRemap", + "type": "core", + "kwargs": { + "base": 0x8000000, + "size": 0x100000, + } }, "SYSTICK": { "base": 0xe000e010, @@ -61,6 +76,21 @@ "size": 0x100000, "type": "mmio" }, + "SRAM BBR": { + "base": 0x22000000, + "size": 0x2000000, + "type": "mmio" + }, + "PERIP BBR": { + "base": 0x42000000, + "size": 0x2000000, + "type": "mmio" + }, + "REMAP REGION": { + "base": 0x0, + "size": 0x100000, + "type": "mmio", + }, "TIM2": { "base": 0x40000000, "struct": "STM32F4xxTim", @@ -267,10 +297,10 @@ "base": 0x40010000, "struct": "STM32F4xxTim", "kwargs": { - "brk_tim9_intn": 0x18, + "brk_intn": 0x18, "cc_intn": 0x1b, - "trg_com_tim11_intn": 0x1a, - "up_tim10_intn": 0x19 + "trg_com_intn": 0x1a, + "up_intn": 0x19 }, "type": "peripheral" }, @@ -278,10 +308,10 @@ "base": 0x40010400, "struct": "STM32F4xxTim", "kwargs": { - "brk_tim12_intn": 0x2b, + "brk_intn": 0x2b, "cc_intn": 0x2e, - "trg_com_tim14_intn": 0x2d, - "up_tim13_intn": 0x2c + "trg_com_intn": 0x2d, + "up_intn": 0x2c }, "type": "peripheral" }, @@ -469,10 +499,4 @@ }, "type": "peripheral" }, - "CODE": { - "base": 0x8000000, - "size": 0x100000, - "alias": 0x0, - "type": "remap" - } } \ No newline at end of file diff --git a/qiling/extensions/mcu/stm32f4/stm32f407.py b/qiling/extensions/mcu/stm32f4/stm32f407.py index 7ed14c4c3..1c71c0361 100644 --- a/qiling/extensions/mcu/stm32f4/stm32f407.py +++ b/qiling/extensions/mcu/stm32f4/stm32f407.py @@ -5,16 +5,31 @@ stm32f407 = { "SRAM BB": { - "alias": 0x22000000, - "base": 0x20000000, - "size": 0x100000, - "type": "bitband" + "base": 0x22000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x20000000, + "size": 0x100000, + } }, "PERIP BB": { - "alias": 0x42000000, - "base": 0x40000000, - "size": 0x100000, - "type": "bitband" + "base": 0x42000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x40000000, + "size": 0x100000, + } + }, + "REMAP": { + "base": 0x0, + "struct": "MemoryRemap", + "type": "core", + "kwargs": { + "base": 0x8000000, + "size": 0x100000, + } }, "SYSTICK": { "base": 0xe000e010, @@ -61,6 +76,21 @@ "size": 0x100000, "type": "mmio" }, + "SRAM BBR": { + "base": 0x22000000, + "size": 0x2000000, + "type": "mmio" + }, + "PERIP BBR": { + "base": 0x42000000, + "size": 0x2000000, + "type": "mmio" + }, + "REMAP REGION": { + "base": 0x0, + "size": 0x100000, + "type": "mmio", + }, "TIM2": { "base": 0x40000000, "struct": "STM32F4xxTim", @@ -267,10 +297,10 @@ "base": 0x40010000, "struct": "STM32F4xxTim", "kwargs": { - "brk_tim9_intn": 0x18, + "brk_intn": 0x18, "cc_intn": 0x1b, - "trg_com_tim11_intn": 0x1a, - "up_tim10_intn": 0x19 + "trg_com_intn": 0x1a, + "up_intn": 0x19 }, "type": "peripheral" }, @@ -278,10 +308,10 @@ "base": 0x40010400, "struct": "STM32F4xxTim", "kwargs": { - "brk_tim12_intn": 0x2b, + "brk_intn": 0x2b, "cc_intn": 0x2e, - "trg_com_tim14_intn": 0x2d, - "up_tim13_intn": 0x2c + "trg_com_intn": 0x2d, + "up_intn": 0x2c }, "type": "peripheral" }, @@ -486,10 +516,4 @@ }, "type": "peripheral" }, - "CODE": { - "base": 0x8000000, - "size": 0x100000, - "alias": 0x0, - "type": "remap" - } } \ No newline at end of file diff --git a/qiling/extensions/mcu/stm32f4/stm32f410.py b/qiling/extensions/mcu/stm32f4/stm32f410.py index 70ada507e..3d248fa83 100644 --- a/qiling/extensions/mcu/stm32f4/stm32f410.py +++ b/qiling/extensions/mcu/stm32f4/stm32f410.py @@ -5,16 +5,31 @@ stm32f410 = { "SRAM BB": { - "alias": 0x22000000, - "base": 0x20000000, - "size": 0x100000, - "type": "bitband" + "base": 0x22000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x20000000, + "size": 0x100000, + } }, "PERIP BB": { - "alias": 0x42000000, - "base": 0x40000000, - "size": 0x100000, - "type": "bitband" + "base": 0x42000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x40000000, + "size": 0x100000, + } + }, + "REMAP": { + "base": 0x0, + "struct": "MemoryRemap", + "type": "core", + "kwargs": { + "base": 0x8000000, + "size": 0x20000, + } }, "SYSTICK": { "base": 0xe000e010, @@ -61,6 +76,21 @@ "size": 0x100000, "type": "mmio" }, + "SRAM BBR": { + "base": 0x22000000, + "size": 0x2000000, + "type": "mmio" + }, + "PERIP BBR": { + "base": 0x42000000, + "size": 0x2000000, + "type": "mmio" + }, + "REMAP REGION": { + "base": 0x0, + "size": 0x20000, + "type": "mmio", + }, "TIM5": { "base": 0x40000c00, "struct": "STM32F4xxTim", @@ -164,9 +194,9 @@ "base": 0x40010000, "struct": "STM32F4xxTim", "kwargs": { - "brk_tim9_intn": 0x18, + "brk_intn": 0x18, "cc_intn": 0x1b, - "trg_com_tim11_intn": 0x1a, + "trg_com_intn": 0x1a, "up_intn": 0x19 }, "type": "peripheral" @@ -315,10 +345,4 @@ }, "type": "peripheral" }, - "CODE": { - "base": 0x8000000, - "size": 0x20000, - "alias": 0x0, - "type": "remap" - } } \ No newline at end of file diff --git a/qiling/extensions/mcu/stm32f4/stm32f411.py b/qiling/extensions/mcu/stm32f4/stm32f411.py index 7b527ee02..f2a2fb94c 100644 --- a/qiling/extensions/mcu/stm32f4/stm32f411.py +++ b/qiling/extensions/mcu/stm32f4/stm32f411.py @@ -5,16 +5,31 @@ stm32f411 = { "SRAM BB": { - "alias": 0x22000000, - "base": 0x20000000, - "size": 0x100000, - "type": "bitband" + "base": 0x22000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x20000000, + "size": 0x100000, + } }, "PERIP BB": { - "alias": 0x42000000, - "base": 0x40000000, - "size": 0x100000, - "type": "bitband" + "base": 0x42000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x40000000, + "size": 0x100000, + } + }, + "REMAP": { + "base": 0x0, + "struct": "MemoryRemap", + "type": "core", + "kwargs": { + "base": 0x8000000, + "size": 0x80000, + } }, "SYSTICK": { "base": 0xe000e010, @@ -61,6 +76,21 @@ "size": 0x100000, "type": "mmio" }, + "SRAM BBR": { + "base": 0x22000000, + "size": 0x2000000, + "type": "mmio" + }, + "PERIP BBR": { + "base": 0x42000000, + "size": 0x2000000, + "type": "mmio" + }, + "REMAP REGION": { + "base": 0x0, + "size": 0x80000, + "type": "mmio", + }, "TIM2": { "base": 0x40000000, "struct": "STM32F4xxTim", @@ -185,10 +215,10 @@ "base": 0x40010000, "struct": "STM32F4xxTim", "kwargs": { - "brk_tim9_intn": 0x18, + "brk_intn": 0x18, "cc_intn": 0x1b, - "trg_com_tim11_intn": 0x1a, - "up_tim10_intn": 0x19 + "trg_com_intn": 0x1a, + "up_intn": 0x19 }, "type": "peripheral" }, @@ -359,10 +389,4 @@ }, "type": "peripheral" }, - "CODE": { - "base": 0x8000000, - "size": 0x80000, - "alias": 0x0, - "type": "remap" - } } \ No newline at end of file diff --git a/qiling/extensions/mcu/stm32f4/stm32f412.py b/qiling/extensions/mcu/stm32f4/stm32f412.py index 39af87267..9ffbdb0ea 100644 --- a/qiling/extensions/mcu/stm32f4/stm32f412.py +++ b/qiling/extensions/mcu/stm32f4/stm32f412.py @@ -5,16 +5,31 @@ stm32f412 = { "SRAM BB": { - "alias": 0x22000000, - "base": 0x20000000, - "size": 0x100000, - "type": "bitband" + "base": 0x22000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x20000000, + "size": 0x100000, + } }, "PERIP BB": { - "alias": 0x42000000, - "base": 0x40000000, - "size": 0x100000, - "type": "bitband" + "base": 0x42000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x40000000, + "size": 0x100000, + } + }, + "REMAP": { + "base": 0x0, + "struct": "MemoryRemap", + "type": "core", + "kwargs": { + "base": 0x8000000, + "size": 0x100000, + } }, "SYSTICK": { "base": 0xe000e010, @@ -61,6 +76,21 @@ "size": 0x100000, "type": "mmio" }, + "SRAM BBR": { + "base": 0x22000000, + "size": 0x2000000, + "type": "mmio" + }, + "PERIP BBR": { + "base": 0x42000000, + "size": 0x2000000, + "type": "mmio" + }, + "REMAP REGION": { + "base": 0x0, + "size": 0x100000, + "type": "mmio", + }, "TIM2": { "base": 0x40000000, "struct": "STM32F4xxTim", @@ -255,10 +285,10 @@ "base": 0x40010000, "struct": "STM32F4xxTim", "kwargs": { - "brk_tim9_intn": 0x18, + "brk_intn": 0x18, "cc_intn": 0x1b, - "trg_com_tim11_intn": 0x1a, - "up_tim10_intn": 0x19 + "trg_com_intn": 0x1a, + "up_intn": 0x19 }, "type": "peripheral" }, @@ -266,10 +296,10 @@ "base": 0x40010400, "struct": "STM32F4xxTim", "kwargs": { - "brk_tim12_intn": 0x2b, + "brk_intn": 0x2b, "cc_intn": 0x2e, - "trg_com_tim14_intn": 0x2d, - "up_tim13_intn": 0x2c + "trg_com_intn": 0x2d, + "up_intn": 0x2c }, "type": "peripheral" }, @@ -466,10 +496,4 @@ }, "type": "peripheral" }, - "CODE": { - "base": 0x8000000, - "size": 0x100000, - "alias": 0x0, - "type": "remap" - } } \ No newline at end of file diff --git a/qiling/extensions/mcu/stm32f4/stm32f413.py b/qiling/extensions/mcu/stm32f4/stm32f413.py index 477b68fe7..afdf2b16a 100644 --- a/qiling/extensions/mcu/stm32f4/stm32f413.py +++ b/qiling/extensions/mcu/stm32f4/stm32f413.py @@ -5,16 +5,31 @@ stm32f413 = { "SRAM BB": { - "alias": 0x22000000, - "base": 0x20000000, - "size": 0x100000, - "type": "bitband" + "base": 0x22000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x20000000, + "size": 0x100000, + } }, "PERIP BB": { - "alias": 0x42000000, - "base": 0x40000000, - "size": 0x100000, - "type": "bitband" + "base": 0x42000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x40000000, + "size": 0x100000, + } + }, + "REMAP": { + "base": 0x0, + "struct": "MemoryRemap", + "type": "core", + "kwargs": { + "base": 0x8000000, + "size": 0x180000, + } }, "SYSTICK": { "base": 0xe000e010, @@ -61,6 +76,21 @@ "size": 0x100000, "type": "mmio" }, + "SRAM BBR": { + "base": 0x22000000, + "size": 0x2000000, + "type": "mmio" + }, + "PERIP BBR": { + "base": 0x42000000, + "size": 0x2000000, + "type": "mmio" + }, + "REMAP REGION": { + "base": 0x0, + "size": 0x180000, + "type": "mmio", + }, "TIM2": { "base": 0x40000000, "struct": "STM32F4xxTim", @@ -311,10 +341,10 @@ "base": 0x40010000, "struct": "STM32F4xxTim", "kwargs": { - "brk_tim9_intn": 0x18, + "brk_intn": 0x18, "cc_intn": 0x1b, - "trg_com_tim11_intn": 0x1a, - "up_tim10_intn": 0x19 + "trg_com_intn": 0x1a, + "up_intn": 0x19 }, "type": "peripheral" }, @@ -322,10 +352,10 @@ "base": 0x40010400, "struct": "STM32F4xxTim", "kwargs": { - "brk_tim12_intn": 0x2b, + "brk_intn": 0x2b, "cc_intn": 0x2e, - "trg_com_tim14_intn": 0x2d, - "up_tim13_intn": 0x2c + "trg_com_intn": 0x2d, + "up_intn": 0x2c }, "type": "peripheral" }, @@ -546,10 +576,4 @@ }, "type": "peripheral" }, - "CODE": { - "base": 0x8000000, - "size": 0x180000, - "alias": 0x0, - "type": "remap" - } } \ No newline at end of file diff --git a/qiling/extensions/mcu/stm32f4/stm32f415.py b/qiling/extensions/mcu/stm32f4/stm32f415.py index 7c47e814f..9a448a08e 100644 --- a/qiling/extensions/mcu/stm32f4/stm32f415.py +++ b/qiling/extensions/mcu/stm32f4/stm32f415.py @@ -5,16 +5,31 @@ stm32f415 = { "SRAM BB": { - "alias": 0x22000000, - "base": 0x20000000, - "size": 0x100000, - "type": "bitband" + "base": 0x22000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x20000000, + "size": 0x100000, + } }, "PERIP BB": { - "alias": 0x42000000, - "base": 0x40000000, - "size": 0x100000, - "type": "bitband" + "base": 0x42000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x40000000, + "size": 0x100000, + } + }, + "REMAP": { + "base": 0x0, + "struct": "MemoryRemap", + "type": "core", + "kwargs": { + "base": 0x8000000, + "size": 0x100000, + } }, "SYSTICK": { "base": 0xe000e010, @@ -61,6 +76,21 @@ "size": 0x100000, "type": "mmio" }, + "SRAM BBR": { + "base": 0x22000000, + "size": 0x2000000, + "type": "mmio" + }, + "PERIP BBR": { + "base": 0x42000000, + "size": 0x2000000, + "type": "mmio" + }, + "REMAP REGION": { + "base": 0x0, + "size": 0x100000, + "type": "mmio", + }, "TIM2": { "base": 0x40000000, "struct": "STM32F4xxTim", @@ -267,10 +297,10 @@ "base": 0x40010000, "struct": "STM32F4xxTim", "kwargs": { - "brk_tim9_intn": 0x18, + "brk_intn": 0x18, "cc_intn": 0x1b, - "trg_com_tim11_intn": 0x1a, - "up_tim10_intn": 0x19 + "trg_com_intn": 0x1a, + "up_intn": 0x19 }, "type": "peripheral" }, @@ -278,10 +308,10 @@ "base": 0x40010400, "struct": "STM32F4xxTim", "kwargs": { - "brk_tim12_intn": 0x2b, + "brk_intn": 0x2b, "cc_intn": 0x2e, - "trg_com_tim14_intn": 0x2d, - "up_tim13_intn": 0x2c + "trg_com_intn": 0x2d, + "up_intn": 0x2c }, "type": "peripheral" }, @@ -482,10 +512,4 @@ }, "type": "peripheral" }, - "CODE": { - "base": 0x8000000, - "size": 0x100000, - "alias": 0x0, - "type": "remap" - } } \ No newline at end of file diff --git a/qiling/extensions/mcu/stm32f4/stm32f417.py b/qiling/extensions/mcu/stm32f4/stm32f417.py index 22a25c06a..8c9575cab 100644 --- a/qiling/extensions/mcu/stm32f4/stm32f417.py +++ b/qiling/extensions/mcu/stm32f4/stm32f417.py @@ -5,16 +5,31 @@ stm32f417 = { "SRAM BB": { - "alias": 0x22000000, - "base": 0x20000000, - "size": 0x100000, - "type": "bitband" + "base": 0x22000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x20000000, + "size": 0x100000, + } }, "PERIP BB": { - "alias": 0x42000000, - "base": 0x40000000, - "size": 0x100000, - "type": "bitband" + "base": 0x42000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x40000000, + "size": 0x100000, + } + }, + "REMAP": { + "base": 0x0, + "struct": "MemoryRemap", + "type": "core", + "kwargs": { + "base": 0x8000000, + "size": 0x100000, + } }, "SYSTICK": { "base": 0xe000e010, @@ -61,6 +76,21 @@ "size": 0x100000, "type": "mmio" }, + "SRAM BBR": { + "base": 0x22000000, + "size": 0x2000000, + "type": "mmio" + }, + "PERIP BBR": { + "base": 0x42000000, + "size": 0x2000000, + "type": "mmio" + }, + "REMAP REGION": { + "base": 0x0, + "size": 0x100000, + "type": "mmio", + }, "TIM2": { "base": 0x40000000, "struct": "STM32F4xxTim", @@ -267,10 +297,10 @@ "base": 0x40010000, "struct": "STM32F4xxTim", "kwargs": { - "brk_tim9_intn": 0x18, + "brk_intn": 0x18, "cc_intn": 0x1b, - "trg_com_tim11_intn": 0x1a, - "up_tim10_intn": 0x19 + "trg_com_intn": 0x1a, + "up_intn": 0x19 }, "type": "peripheral" }, @@ -278,10 +308,10 @@ "base": 0x40010400, "struct": "STM32F4xxTim", "kwargs": { - "brk_tim12_intn": 0x2b, + "brk_intn": 0x2b, "cc_intn": 0x2e, - "trg_com_tim14_intn": 0x2d, - "up_tim13_intn": 0x2c + "trg_com_intn": 0x2d, + "up_intn": 0x2c }, "type": "peripheral" }, @@ -499,10 +529,4 @@ }, "type": "peripheral" }, - "CODE": { - "base": 0x8000000, - "size": 0x100000, - "alias": 0x0, - "type": "remap" - } } \ No newline at end of file diff --git a/qiling/extensions/mcu/stm32f4/stm32f423.py b/qiling/extensions/mcu/stm32f4/stm32f423.py index f6904cc5b..9819f37a9 100644 --- a/qiling/extensions/mcu/stm32f4/stm32f423.py +++ b/qiling/extensions/mcu/stm32f4/stm32f423.py @@ -5,16 +5,31 @@ stm32f423 = { "SRAM BB": { - "alias": 0x22000000, - "base": 0x20000000, - "size": 0x100000, - "type": "bitband" + "base": 0x22000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x20000000, + "size": 0x100000, + } }, "PERIP BB": { - "alias": 0x42000000, - "base": 0x40000000, - "size": 0x100000, - "type": "bitband" + "base": 0x42000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x40000000, + "size": 0x100000, + } + }, + "REMAP": { + "base": 0x0, + "struct": "MemoryRemap", + "type": "core", + "kwargs": { + "base": 0x8000000, + "size": 0x180000, + } }, "SYSTICK": { "base": 0xe000e010, @@ -61,6 +76,21 @@ "size": 0x100000, "type": "mmio" }, + "SRAM BBR": { + "base": 0x22000000, + "size": 0x2000000, + "type": "mmio" + }, + "PERIP BBR": { + "base": 0x42000000, + "size": 0x2000000, + "type": "mmio" + }, + "REMAP REGION": { + "base": 0x0, + "size": 0x180000, + "type": "mmio", + }, "TIM2": { "base": 0x40000000, "struct": "STM32F4xxTim", @@ -311,10 +341,10 @@ "base": 0x40010000, "struct": "STM32F4xxTim", "kwargs": { - "brk_tim9_intn": 0x18, + "brk_intn": 0x18, "cc_intn": 0x1b, - "trg_com_tim11_intn": 0x1a, - "up_tim10_intn": 0x19 + "trg_com_intn": 0x1a, + "up_intn": 0x19 }, "type": "peripheral" }, @@ -322,10 +352,10 @@ "base": 0x40010400, "struct": "STM32F4xxTim", "kwargs": { - "brk_tim12_intn": 0x2b, + "brk_intn": 0x2b, "cc_intn": 0x2e, - "trg_com_tim14_intn": 0x2d, - "up_tim13_intn": 0x2c + "trg_com_intn": 0x2d, + "up_intn": 0x2c }, "type": "peripheral" }, @@ -554,10 +584,4 @@ }, "type": "peripheral" }, - "CODE": { - "base": 0x8000000, - "size": 0x180000, - "alias": 0x0, - "type": "remap" - } } \ No newline at end of file diff --git a/qiling/extensions/mcu/stm32f4/stm32f427.py b/qiling/extensions/mcu/stm32f4/stm32f427.py index 5bcd1f35a..a08395732 100644 --- a/qiling/extensions/mcu/stm32f4/stm32f427.py +++ b/qiling/extensions/mcu/stm32f4/stm32f427.py @@ -5,16 +5,31 @@ stm32f427 = { "SRAM BB": { - "alias": 0x22000000, - "base": 0x20000000, - "size": 0x100000, - "type": "bitband" + "base": 0x22000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x20000000, + "size": 0x100000, + } }, "PERIP BB": { - "alias": 0x42000000, - "base": 0x40000000, - "size": 0x100000, - "type": "bitband" + "base": 0x42000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x40000000, + "size": 0x100000, + } + }, + "REMAP": { + "base": 0x0, + "struct": "MemoryRemap", + "type": "core", + "kwargs": { + "base": 0x8000000, + "size": 0x200000, + } }, "SYSTICK": { "base": 0xe000e010, @@ -61,6 +76,21 @@ "size": 0x100000, "type": "mmio" }, + "SRAM BBR": { + "base": 0x22000000, + "size": 0x2000000, + "type": "mmio" + }, + "PERIP BBR": { + "base": 0x42000000, + "size": 0x2000000, + "type": "mmio" + }, + "REMAP REGION": { + "base": 0x0, + "size": 0x200000, + "type": "mmio", + }, "TIM2": { "base": 0x40000000, "struct": "STM32F4xxTim", @@ -283,10 +313,10 @@ "base": 0x40010000, "struct": "STM32F4xxTim", "kwargs": { - "brk_tim9_intn": 0x18, + "brk_intn": 0x18, "cc_intn": 0x1b, - "trg_com_tim11_intn": 0x1a, - "up_tim10_intn": 0x19 + "trg_com_intn": 0x1a, + "up_intn": 0x19 }, "type": "peripheral" }, @@ -294,10 +324,10 @@ "base": 0x40010400, "struct": "STM32F4xxTim", "kwargs": { - "brk_tim12_intn": 0x2b, + "brk_intn": 0x2b, "cc_intn": 0x2e, - "trg_com_tim14_intn": 0x2d, - "up_tim13_intn": 0x2c + "trg_com_intn": 0x2d, + "up_intn": 0x2c }, "type": "peripheral" }, @@ -549,10 +579,4 @@ }, "type": "peripheral" }, - "CODE": { - "base": 0x8000000, - "size": 0x200000, - "alias": 0x0, - "type": "remap" - } } \ No newline at end of file diff --git a/qiling/extensions/mcu/stm32f4/stm32f429.py b/qiling/extensions/mcu/stm32f4/stm32f429.py index bf87d82c0..d2751ba59 100644 --- a/qiling/extensions/mcu/stm32f4/stm32f429.py +++ b/qiling/extensions/mcu/stm32f4/stm32f429.py @@ -5,16 +5,31 @@ stm32f429 = { "SRAM BB": { - "alias": 0x22000000, - "base": 0x20000000, - "size": 0x100000, - "type": "bitband" + "base": 0x22000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x20000000, + "size": 0x100000, + } }, "PERIP BB": { - "alias": 0x42000000, - "base": 0x40000000, - "size": 0x100000, - "type": "bitband" + "base": 0x42000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x40000000, + "size": 0x100000, + } + }, + "REMAP": { + "base": 0x0, + "struct": "MemoryRemap", + "type": "core", + "kwargs": { + "base": 0x8000000, + "size": 0x200000, + } }, "SYSTICK": { "base": 0xe000e010, @@ -48,7 +63,12 @@ }, "SRAM": { "base": 0x20000000, - "size": 0x20000, + "size": 0x30000, + "type": "memory" + }, + "CCMRAM": { + "base": 0x10000000, + "size": 0x10000, "type": "memory" }, "PERIP": { @@ -61,6 +81,21 @@ "size": 0x100000, "type": "mmio" }, + "SRAM BBR": { + "base": 0x22000000, + "size": 0x2000000, + "type": "mmio" + }, + "PERIP BBR": { + "base": 0x42000000, + "size": 0x2000000, + "type": "mmio" + }, + "REMAP REGION": { + "base": 0x0, + "size": 0x200000, + "type": "mmio", + }, "TIM2": { "base": 0x40000000, "struct": "STM32F4xxTim", @@ -283,10 +318,10 @@ "base": 0x40010000, "struct": "STM32F4xxTim", "kwargs": { - "brk_tim9_intn": 0x18, + "brk_intn": 0x18, "cc_intn": 0x1b, - "trg_com_tim11_intn": 0x1a, - "up_tim10_intn": 0x19 + "trg_com_intn": 0x1a, + "up_intn": 0x19 }, "type": "peripheral" }, @@ -294,10 +329,10 @@ "base": 0x40010400, "struct": "STM32F4xxTim", "kwargs": { - "brk_tim12_intn": 0x2b, + "brk_intn": 0x2b, "cc_intn": 0x2e, - "trg_com_tim14_intn": 0x2d, - "up_tim13_intn": 0x2c + "trg_com_intn": 0x2d, + "up_intn": 0x2c }, "type": "peripheral" }, @@ -558,10 +593,4 @@ }, "type": "peripheral" }, - "CODE": { - "base": 0x8000000, - "size": 0x200000, - "alias": 0x0, - "type": "remap" - } } \ No newline at end of file diff --git a/qiling/extensions/mcu/stm32f4/stm32f437.py b/qiling/extensions/mcu/stm32f4/stm32f437.py index ebe5c80ce..75d222b61 100644 --- a/qiling/extensions/mcu/stm32f4/stm32f437.py +++ b/qiling/extensions/mcu/stm32f4/stm32f437.py @@ -5,16 +5,31 @@ stm32f437 = { "SRAM BB": { - "alias": 0x22000000, - "base": 0x20000000, - "size": 0x100000, - "type": "bitband" + "base": 0x22000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x20000000, + "size": 0x100000, + } }, "PERIP BB": { - "alias": 0x42000000, - "base": 0x40000000, - "size": 0x100000, - "type": "bitband" + "base": 0x42000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x40000000, + "size": 0x100000, + } + }, + "REMAP": { + "base": 0x0, + "struct": "MemoryRemap", + "type": "core", + "kwargs": { + "base": 0x8000000, + "size": 0x200000, + } }, "SYSTICK": { "base": 0xe000e010, @@ -61,6 +76,21 @@ "size": 0x100000, "type": "mmio" }, + "SRAM BBR": { + "base": 0x22000000, + "size": 0x2000000, + "type": "mmio" + }, + "PERIP BBR": { + "base": 0x42000000, + "size": 0x2000000, + "type": "mmio" + }, + "REMAP REGION": { + "base": 0x0, + "size": 0x200000, + "type": "mmio", + }, "TIM2": { "base": 0x40000000, "struct": "STM32F4xxTim", @@ -283,10 +313,10 @@ "base": 0x40010000, "struct": "STM32F4xxTim", "kwargs": { - "brk_tim9_intn": 0x18, + "brk_intn": 0x18, "cc_intn": 0x1b, - "trg_com_tim11_intn": 0x1a, - "up_tim10_intn": 0x19 + "trg_com_intn": 0x1a, + "up_intn": 0x19 }, "type": "peripheral" }, @@ -294,10 +324,10 @@ "base": 0x40010400, "struct": "STM32F4xxTim", "kwargs": { - "brk_tim12_intn": 0x2b, + "brk_intn": 0x2b, "cc_intn": 0x2e, - "trg_com_tim14_intn": 0x2d, - "up_tim13_intn": 0x2c + "trg_com_intn": 0x2d, + "up_intn": 0x2c }, "type": "peripheral" }, @@ -565,10 +595,4 @@ }, "type": "peripheral" }, - "CODE": { - "base": 0x8000000, - "size": 0x200000, - "alias": 0x0, - "type": "remap" - } } \ No newline at end of file diff --git a/qiling/extensions/mcu/stm32f4/stm32f439.py b/qiling/extensions/mcu/stm32f4/stm32f439.py index 779fcd298..f02354c7f 100644 --- a/qiling/extensions/mcu/stm32f4/stm32f439.py +++ b/qiling/extensions/mcu/stm32f4/stm32f439.py @@ -5,16 +5,31 @@ stm32f439 = { "SRAM BB": { - "alias": 0x22000000, - "base": 0x20000000, - "size": 0x100000, - "type": "bitband" + "base": 0x22000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x20000000, + "size": 0x100000, + } }, "PERIP BB": { - "alias": 0x42000000, - "base": 0x40000000, - "size": 0x100000, - "type": "bitband" + "base": 0x42000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x40000000, + "size": 0x100000, + } + }, + "REMAP": { + "base": 0x0, + "struct": "MemoryRemap", + "type": "core", + "kwargs": { + "base": 0x8000000, + "size": 0x200000, + } }, "SYSTICK": { "base": 0xe000e010, @@ -61,6 +76,21 @@ "size": 0x100000, "type": "mmio" }, + "SRAM BBR": { + "base": 0x22000000, + "size": 0x2000000, + "type": "mmio" + }, + "PERIP BBR": { + "base": 0x42000000, + "size": 0x2000000, + "type": "mmio" + }, + "REMAP REGION": { + "base": 0x0, + "size": 0x200000, + "type": "mmio", + }, "TIM2": { "base": 0x40000000, "struct": "STM32F4xxTim", @@ -283,10 +313,10 @@ "base": 0x40010000, "struct": "STM32F4xxTim", "kwargs": { - "brk_tim9_intn": 0x18, + "brk_intn": 0x18, "cc_intn": 0x1b, - "trg_com_tim11_intn": 0x1a, - "up_tim10_intn": 0x19 + "trg_com_intn": 0x1a, + "up_intn": 0x19 }, "type": "peripheral" }, @@ -294,10 +324,10 @@ "base": 0x40010400, "struct": "STM32F4xxTim", "kwargs": { - "brk_tim12_intn": 0x2b, + "brk_intn": 0x2b, "cc_intn": 0x2e, - "trg_com_tim14_intn": 0x2d, - "up_tim13_intn": 0x2c + "trg_com_intn": 0x2d, + "up_intn": 0x2c }, "type": "peripheral" }, @@ -574,10 +604,4 @@ }, "type": "peripheral" }, - "CODE": { - "base": 0x8000000, - "size": 0x200000, - "alias": 0x0, - "type": "remap" - } } \ No newline at end of file diff --git a/qiling/extensions/mcu/stm32f4/stm32f446.py b/qiling/extensions/mcu/stm32f4/stm32f446.py index 4d0fa0fc1..ba1bbdd20 100644 --- a/qiling/extensions/mcu/stm32f4/stm32f446.py +++ b/qiling/extensions/mcu/stm32f4/stm32f446.py @@ -5,16 +5,31 @@ stm32f446 = { "SRAM BB": { - "alias": 0x22000000, - "base": 0x20000000, - "size": 0x100000, - "type": "bitband" + "base": 0x22000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x20000000, + "size": 0x100000, + } }, "PERIP BB": { - "alias": 0x42000000, - "base": 0x40000000, - "size": 0x100000, - "type": "bitband" + "base": 0x42000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x40000000, + "size": 0x100000, + } + }, + "REMAP": { + "base": 0x0, + "struct": "MemoryRemap", + "type": "core", + "kwargs": { + "base": 0x8000000, + "size": 0x80000, + } }, "SYSTICK": { "base": 0xe000e010, @@ -61,6 +76,21 @@ "size": 0x100000, "type": "mmio" }, + "SRAM BBR": { + "base": 0x22000000, + "size": 0x2000000, + "type": "mmio" + }, + "PERIP BBR": { + "base": 0x42000000, + "size": 0x2000000, + "type": "mmio" + }, + "REMAP REGION": { + "base": 0x0, + "size": 0x80000, + "type": "mmio", + }, "TIM2": { "base": 0x40000000, "struct": "STM32F4xxTim", @@ -279,10 +309,10 @@ "base": 0x40010000, "struct": "STM32F4xxTim", "kwargs": { - "brk_tim9_intn": 0x18, + "brk_intn": 0x18, "cc_intn": 0x1b, - "trg_com_tim11_intn": 0x1a, - "up_tim10_intn": 0x19 + "trg_com_intn": 0x1a, + "up_intn": 0x19 }, "type": "peripheral" }, @@ -290,10 +320,10 @@ "base": 0x40010400, "struct": "STM32F4xxTim", "kwargs": { - "brk_tim12_intn": 0x2b, + "brk_intn": 0x2b, "cc_intn": 0x2e, - "trg_com_tim14_intn": 0x2d, - "up_tim13_intn": 0x2c + "trg_com_intn": 0x2d, + "up_intn": 0x2c }, "type": "peripheral" }, @@ -508,10 +538,4 @@ }, "type": "peripheral" }, - "CODE": { - "base": 0x8000000, - "size": 0x80000, - "alias": 0x0, - "type": "remap" - } } \ No newline at end of file diff --git a/qiling/extensions/mcu/stm32f4/stm32f469.py b/qiling/extensions/mcu/stm32f4/stm32f469.py index 527aa390d..e20d25216 100644 --- a/qiling/extensions/mcu/stm32f4/stm32f469.py +++ b/qiling/extensions/mcu/stm32f4/stm32f469.py @@ -5,16 +5,31 @@ stm32f469 = { "SRAM BB": { - "alias": 0x22000000, - "base": 0x20000000, - "size": 0x100000, - "type": "bitband" + "base": 0x22000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x20000000, + "size": 0x100000, + } }, "PERIP BB": { - "alias": 0x42000000, - "base": 0x40000000, - "size": 0x100000, - "type": "bitband" + "base": 0x42000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x40000000, + "size": 0x100000, + } + }, + "REMAP": { + "base": 0x0, + "struct": "MemoryRemap", + "type": "core", + "kwargs": { + "base": 0x8000000, + "size": 0x200000, + } }, "SYSTICK": { "base": 0xe000e010, @@ -61,6 +76,21 @@ "size": 0x100000, "type": "mmio" }, + "SRAM BBR": { + "base": 0x22000000, + "size": 0x2000000, + "type": "mmio" + }, + "PERIP BBR": { + "base": 0x42000000, + "size": 0x2000000, + "type": "mmio" + }, + "REMAP REGION": { + "base": 0x0, + "size": 0x200000, + "type": "mmio", + }, "TIM2": { "base": 0x40000000, "struct": "STM32F4xxTim", @@ -283,10 +313,10 @@ "base": 0x40010000, "struct": "STM32F4xxTim", "kwargs": { - "brk_tim9_intn": 0x18, + "brk_intn": 0x18, "cc_intn": 0x1b, - "trg_com_tim11_intn": 0x1a, - "up_tim10_intn": 0x19 + "trg_com_intn": 0x1a, + "up_intn": 0x19 }, "type": "peripheral" }, @@ -294,10 +324,10 @@ "base": 0x40010400, "struct": "STM32F4xxTim", "kwargs": { - "brk_tim12_intn": 0x2b, + "brk_intn": 0x2b, "cc_intn": 0x2e, - "trg_com_tim14_intn": 0x2d, - "up_tim13_intn": 0x2c + "trg_com_intn": 0x2d, + "up_intn": 0x2c }, "type": "peripheral" }, @@ -574,10 +604,4 @@ }, "type": "peripheral" }, - "CODE": { - "base": 0x8000000, - "size": 0x200000, - "alias": 0x0, - "type": "remap" - } } \ No newline at end of file diff --git a/qiling/extensions/mcu/stm32f4/stm32f479.py b/qiling/extensions/mcu/stm32f4/stm32f479.py index 6a504fe5c..dc1665156 100644 --- a/qiling/extensions/mcu/stm32f4/stm32f479.py +++ b/qiling/extensions/mcu/stm32f4/stm32f479.py @@ -5,16 +5,31 @@ stm32f479 = { "SRAM BB": { - "alias": 0x22000000, - "base": 0x20000000, - "size": 0x100000, - "type": "bitband" + "base": 0x22000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x20000000, + "size": 0x100000, + } }, "PERIP BB": { - "alias": 0x42000000, - "base": 0x40000000, - "size": 0x100000, - "type": "bitband" + "base": 0x42000000, + "struct": "CortexMBitband", + "type": "core", + "kwargs": { + "base": 0x40000000, + "size": 0x100000, + } + }, + "REMAP": { + "base": 0x0, + "struct": "MemoryRemap", + "type": "core", + "kwargs": { + "base": 0x8000000, + "size": 0x200000, + } }, "SYSTICK": { "base": 0xe000e010, @@ -61,6 +76,21 @@ "size": 0x100000, "type": "mmio" }, + "SRAM BBR": { + "base": 0x22000000, + "size": 0x2000000, + "type": "mmio" + }, + "PERIP BBR": { + "base": 0x42000000, + "size": 0x2000000, + "type": "mmio" + }, + "REMAP REGION": { + "base": 0x0, + "size": 0x200000, + "type": "mmio", + }, "TIM2": { "base": 0x40000000, "struct": "STM32F4xxTim", @@ -283,10 +313,10 @@ "base": 0x40010000, "struct": "STM32F4xxTim", "kwargs": { - "brk_tim9_intn": 0x18, + "brk_intn": 0x18, "cc_intn": 0x1b, - "trg_com_tim11_intn": 0x1a, - "up_tim10_intn": 0x19 + "trg_com_intn": 0x1a, + "up_intn": 0x19 }, "type": "peripheral" }, @@ -294,10 +324,10 @@ "base": 0x40010400, "struct": "STM32F4xxTim", "kwargs": { - "brk_tim12_intn": 0x2b, + "brk_intn": 0x2b, "cc_intn": 0x2e, - "trg_com_tim14_intn": 0x2d, - "up_tim13_intn": 0x2c + "trg_com_intn": 0x2d, + "up_intn": 0x2c }, "type": "peripheral" }, @@ -590,10 +620,4 @@ }, "type": "peripheral" }, - "CODE": { - "base": 0x8000000, - "size": 0x200000, - "alias": 0x0, - "type": "remap" - } } \ No newline at end of file diff --git a/qiling/extensions/multitask.py b/qiling/extensions/multitask.py new file mode 100644 index 000000000..a9da37bbf --- /dev/null +++ b/qiling/extensions/multitask.py @@ -0,0 +1,372 @@ +# Lazymio (mio@lazym.io) + +from typing import Dict, List +from unicorn import * +from unicorn.x86_const import UC_X86_REG_EIP, UC_X86_REG_RIP +from unicorn.arm64_const import UC_ARM64_REG_PC +from unicorn.arm_const import UC_ARM_REG_PC, UC_ARM_REG_CPSR +from unicorn.mips_const import UC_MIPS_REG_PC +from unicorn.m68k_const import UC_M68K_REG_PC +from unicorn.riscv_const import UC_RISCV_REG_PC +from unicorn.ppc_const import UC_PPC_REG_PC +from unicorn.sparc_const import UC_SPARC_REG_PC + +import gevent +import gevent.threadpool +import gevent.lock +import threading + +# This class is named UnicornTask be design since it's not a +# real thread. The expected usage is to inherit this class +# and overwrite specific methods. +# +# This class is a friend class of MultiTaskUnicorn +class UnicornTask: + + def __init__(self, uc: Uc, begin: int, end: int, task_id = None): + self._uc = uc + self._begin = begin + self._end = end + self._stop_request = False + self._ctx = None + self._task_id = None + self._arch = self._uc._arch + self._mode = self._uc._mode + + @property + def pc(self): + """ Get current PC of the thread. This property should only be accessed when + the task is running. + """ + raw_pc = self._raw_pc() + if (self._uc.reg_read(UC_ARM_REG_CPSR) & (1 << 5)): + return raw_pc | 1 + else: + return raw_pc + + def _raw_pc(self): + # This extension is designed to be independent of Qiling, so let's + # do this manually... + if self._arch == UC_ARCH_X86: + if (self._mode & UC_MODE_32) != 0: + return self._uc.reg_read(UC_X86_REG_EIP) + elif (self._mode & UC_MODE_64) != 0: + return self._uc.reg_read(UC_X86_REG_RIP) + elif self._arch == UC_ARCH_MIPS: + return self._uc.reg_read(UC_MIPS_REG_PC) + elif self._arch == UC_ARCH_ARM: + return self._uc.reg_read(UC_ARM_REG_PC) + + elif self._arch == UC_ARCH_ARM64: + return self._uc.reg_read(UC_ARM64_REG_PC) + elif self._arch == UC_ARCH_PPC: + return self._uc.reg_read(UC_PPC_REG_PC) + elif self._arch == UC_ARCH_M68K: + return self._uc.reg_read(UC_M68K_REG_PC) + elif self._arch == UC_ARCH_SPARC: + return self._uc.reg_read(UC_SPARC_REG_PC) + elif self._arch == UC_ARCH_RISCV: + return self._uc.reg_read(UC_RISCV_REG_PC) + + # Really? + return 0 + + def _reach_end(self): + # We may stop due to the scheduler asks us to, so check it manually. + #print(f"{hex(self._raw_pc())} {hex(self._end)}") + return self._raw_pc() == self._end + + def save(self): + """ This method is used to save the task context. + Overwrite this method to implement specifc logic. + """ + return self._uc.context_save() + + def restore(self, context): + """ This method is used to restore the task context. + Overwrite this method to implement specific logic. + """ + self._uc.context_restore(context) + self._begin = self.pc + + def on_start(self): + """ This callback is triggered when a task gets scheduled. + """ + if self._ctx: + self.restore(self._ctx) + + def on_interrupted(self, ucerr: int): + """ This callback is triggered when a task gets interrupted, which + is useful to emulate a clock interrupt. + """ + self._ctx = self.save() + + def on_exit(self): + """ This callback is triggered when a task is about to exit. + """ + pass + +# This manages nested uc_emu_start calls and is designed as a friend +# class of MultiTaskUnicorn. +class NestedCounter: + + def __init__(self, mtuc: "MultiTaskUnicorn"): + self._mtuc = mtuc + + def __enter__(self, *args, **kwargs): + self._mtuc._nested_started += 1 + return self + + def __exit__(self, *args, **kwargs): + self._mtuc._nested_started -= 1 + +# This mimic a Unicorn object by maintaining the same interface. +# If no task is registered, the behavior is exactly the same as +# a normal unicorn. +# +# Note: To implement a non-block syscall: +# 1. Record the syscall in the hook, but **do nothing** +# 2. Stop emulation. +# 3. Handle the syscall in the on_interruped callback with +# proper **gevent functions** like gevent.sleep instead +# of time.sleep. +# 4. In this case, gevent would schedule another task to +# take emulation if the task is blocked. +# +# Bear in mind that only one task can be picked to emulate at +# the same time. +class MultiTaskUnicorn(Uc): + + def __init__(self, arch, mode, interval: int = 100): + """ Create a MultiTaskUnicorn object. + Interval: Sceduling interval in **ms**. The longger interval, the better + performance but less interrupts. + """ + super().__init__(arch, mode) + self._interval = interval + self._tasks = {} # type: Dict[int, UnicornTask] + self._task_id_counter = 2000 + self._to_stop = False + self._cur_utk_id = None + self._running = False + self._run_lock = threading.RLock() + self._multitask_enabled = False + self._count = 0 + self._nested_started = 0 + + @property + def current_thread(self): + return self._tasks[self._cur_utk_id] + + @property + def running(self): + return self._running + + def _next_task_id(self): + while self._task_id_counter in self._tasks: + self._task_id_counter += 1 + + return self._task_id_counter + + def _emu_start_locked(self, begin: int, end: int, timeout: int, count: int): + with self._run_lock: + try: + self._running = True + super().emu_start(begin, end, timeout, count) + self._running = False + except UcError as err: + return err.errno + + return UC_ERR_OK + + def _emu_start_utk_locked(self, utk: UnicornTask): + return self._emu_start_locked(utk._begin, utk._end, 0, 0) + + def _timeout_main(self, timeout: int): + + gevent.sleep(timeout / 1000) + + self.tasks_stop() + + def _task_main(self, utk_id: int): + + utk = self._tasks[utk_id] + use_count = (self._count > 0) + + while True: + # utk may be stopped before running once, check it. + if utk._stop_request: + return # If we have to stop due to a tasks_stop, we preserve all threads so that we may resume. + + self._cur_utk_id = utk_id + + utk.on_start() + + with gevent.Timeout(self._interval / 1000, False): + try: + pool = gevent.get_hub().threadpool # type: gevent.threadpool.ThreadPool + task = pool.spawn(self._emu_start_utk_locked, utk) # Run unicorn in a separate thread. + task.wait() + finally: + if not task.done(): + # Interrupted by timeout, in this case we call uc_emu_stop. + super().emu_stop() + + # Wait until we get the result. + ucerr = task.get() + + if utk._reach_end(): + utk._stop_request = True + + if use_count: + self._count -= 1 + + if self._count <= 0: + self.tasks_stop() + return + + if utk._stop_request: + utk.on_exit() + break + else: + utk.on_interrupted(ucerr) + + if self._to_stop: + return + + # on_interrupted callback may have asked us to stop. + if utk._stop_request: + utk.on_exit() + break + + # Give up control at once. + gevent.sleep(0) + + del self._tasks[utk_id] + + def tasks_save(self): + """ Save all tasks' contexts. + """ + return { k: v.save() for k, v in self._tasks.items() } + + def tasks_restore(self, tasks_context: dict): + """ Restore the contexts of all tasks. + """ + for task_id, context in tasks_context: + if task_id in self._tasks: + self._tasks[task_id].restore(context) + + def task_create(self, utk: UnicornTask): + """ Create a unicorn task. utk should be a initialized UnicornTask object. + If the task_id is not set, we generate one. + utk: The task to add. + """ + if not isinstance(utk, UnicornTask): + raise TypeError("Expect a UnicornTask or derived class") + self._multitask_enabled = True + if utk._task_id is None: + utk._task_id = self._next_task_id() + self._tasks[utk._task_id] = utk + return utk._task_id + + def task_exit(self, utk_id): + """ Stop a task. + + utk_id: The id returned from task_create. + """ + if utk_id not in self._tasks: + return + + if utk_id == self._cur_utk_id and self._running: + self.emu_stop() + + self._tasks[utk_id]._stop_request = True + + def emu_start(self, begin: int, end: int, timeout: int, count: int): + """ Emulate an area of code just once. This overwrites the original emu_start interface and + provides extra cares when multitask is enabled. If no task is registerd, this call bahaves + like the original emu_start. + NOTE: Calling this method may cause current greenlet to be switched out. + begin, end, timeout, count: refer to Uc.emu_start + """ + if self._multitask_enabled: + if self._nested_started > 0: + with NestedCounter(self): + pool = gevent.get_hub().threadpool # type: gevent.threadpool.ThreadPool + task = pool.spawn(self._emu_start_locked, begin, end, timeout, count) + ucerr = task.get() + + if ucerr != UC_ERR_OK: + raise UcError(ucerr) + + return ucerr + else: + + # Assume users resume on the last thread (and that should be the case) + if self._cur_utk_id in self._tasks: + self._tasks[self._cur_utk_id]._begin = begin + self._tasks[self._cur_utk_id]._end = end + else: + print(f"Warning: Can't found last thread we scheduled") + + # This translation is not accurate, though. + self.tasks_start(count, timeout) + else: + return super().emu_start(begin, end, timeout, count) + + def emu_stop(self): + """ Stop the emulation. If no task is registerd, this call bahaves like the original emu_stop. + """ + if self._multitask_enabled: + if self._running: + super().emu_stop() + # Stop the world as original uc_emu_stop does + if self._nested_started == 1: + self.tasks_stop() + else: + super().emu_stop() + + def tasks_stop(self): + """ This will stop all running tasks. If no task is registered, this call does nothing. + """ + if self._multitask_enabled: + self._to_stop = True + if self._running: + super().emu_stop() + + def tasks_start(self, count: int = 0, timeout: int = 0): + """ This will start emulation until all tasks get done. + count: Stop after sceduling *count* times. <=0 disables this check. + timeout: Stop after *timeout* ms. <=0 disables this check. + """ + workset = [] # type: List[gevent.Greenlet] + self._to_stop = False + self._count = count + + if self._nested_started != 0: + print("Warning: tasks_start is called inside an uc_emu_start!") + return + + with NestedCounter(self): + + if self._count <= 0: + self._count = 0 + + if self._multitask_enabled: + + if timeout > 0: + workset.append(gevent.spawn(self._timeout_main, timeout)) + + while len(self._tasks) != 0 and not self._to_stop: + + new_workset = [ v for v in workset if not v.dead] + + for utk_id in self._tasks: + new_workset.append(gevent.spawn(self._task_main, utk_id)) + + workset = new_workset + + gevent.joinall(workset, raise_error=True) + + if len(self._tasks) == 0: + self._multitask_enabled = False \ No newline at end of file diff --git a/qiling/hw/__init__.py b/qiling/hw/__init__.py index 1edb4b432..8e1c15be5 100644 --- a/qiling/hw/__init__.py +++ b/qiling/hw/__init__.py @@ -3,7 +3,7 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -from .adc import * +from .analog import * from .char import * from .dma import * from .flash import * @@ -11,7 +11,9 @@ from .i2c import * from .intc import * from .math import * +from .mem import * from .misc import * +from .net import * from .power import * from .sd import * from .spi import * diff --git a/qiling/hw/analog/__init__.py b/qiling/hw/analog/__init__.py new file mode 100644 index 000000000..e8a844396 --- /dev/null +++ b/qiling/hw/analog/__init__.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +from .sam3xa_adc import SAM3xaAdc +from .sam3xa_dac import SAM3xaDac +from .sam3xa_pwm import SAM3xaPwm +from .stm32f1xx_adc import STM32F1xxAdc +from .stm32f4xx_dac import STM32F4xxDac +from .mk64f12_adc import MK64F12Adc diff --git a/qiling/hw/analog/mk64f12_adc.py b/qiling/hw/analog/mk64f12_adc.py new file mode 100644 index 000000000..59528bd96 --- /dev/null +++ b/qiling/hw/analog/mk64f12_adc.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import ctypes + +from qiling.hw.peripheral import QlPeripheral +from qiling.hw.const.mk64f12_adc import SC1, SC3 + + +class MK64F12Adc(QlPeripheral): + class Type(ctypes.Structure): + """ Analog-to-Digital Converter """ + _fields_ = [ + ("SC1" , ctypes.c_uint32 * 2), # ADC Status and Control Registers 1 + ("CFG1", ctypes.c_uint32), # ADC Configuration Register 1 + ("CFG2", ctypes.c_uint32), # ADC Configuration Register 2 + ("R1" , ctypes.c_uint32), # ADC Data Result Register 1 + ("R2" , ctypes.c_uint32), # ADC Data Result Register 2 + ("CV1" , ctypes.c_uint32), # Compare Value Registers 1 + ("CV2" , ctypes.c_uint32), # Compare Value Registers 2 + ("SC2" , ctypes.c_uint32), # Status and Control Register 2 + ("SC3" , ctypes.c_uint32), # Status and Control Register 3 + ("OFS" , ctypes.c_uint32), # ADC Offset Correction Register + ("PG" , ctypes.c_uint32), # ADC Plus-Side Gain Register + ("MG" , ctypes.c_uint32), # ADC Minus-Side Gain Register + ("CLPD", ctypes.c_uint32), # ADC Plus-Side General Calibration Value Register + ("CLPS", ctypes.c_uint32), # ADC Plus-Side General Calibration Value Register + ("CLP4", ctypes.c_uint32), # ADC Plus-Side General Calibration Value Register + ("CLP3", ctypes.c_uint32), # ADC Plus-Side General Calibration Value Register + ("CLP2", ctypes.c_uint32), # ADC Plus-Side General Calibration Value Register + ("CLP1", ctypes.c_uint32), # ADC Plus-Side General Calibration Value Register + ("CLP0", ctypes.c_uint32), # ADC Plus-Side General Calibration Value Register + ("RESERVED0", ctypes.c_uint32), + ("CLMD", ctypes.c_uint32), # ADC Minus-Side General Calibration Value Register + ("CLMS", ctypes.c_uint32), # ADC Minus-Side General Calibration Value Register + ("CLM4", ctypes.c_uint32), # ADC Minus-Side General Calibration Value Register + ("CLM3", ctypes.c_uint32), # ADC Minus-Side General Calibration Value Register + ("CLM2", ctypes.c_uint32), # ADC Minus-Side General Calibration Value Register + ("CLM1", ctypes.c_uint32), # ADC Minus-Side General Calibration Value Register + ("CLM0", ctypes.c_uint32), # ADC Minus-Side General Calibration Value Register + ] + + def __init__(self, ql, label, intn=None): + super().__init__(ql, label) + + self.intn = intn + self.instance = self.struct( + R1 = 0x7ff, + R2 = 0x7ff, + ) + + @QlPeripheral.monitor() + def write(self, offset, size, value): + if offset == self.struct.SC1.offset: + return + + else: + self.raw_write(offset, size, value) + + if offset == self.struct.SC3.offset: + if value & SC3.CAL: + self.instance.SC3 &= ~SC3.CAL + self.instance.SC1[0] |= SC1.COCO + self.instance.SC1[1] |= SC1.COCO + + if value & SC3.CALF: + self.instance.SC3 &= ~SC3.CALF diff --git a/qiling/hw/adc/sam3xa_adc.py b/qiling/hw/analog/sam3xa_adc.py similarity index 77% rename from qiling/hw/adc/sam3xa_adc.py rename to qiling/hw/analog/sam3xa_adc.py index 47f009a65..52c7eb42c 100644 --- a/qiling/hw/adc/sam3xa_adc.py +++ b/qiling/hw/analog/sam3xa_adc.py @@ -6,6 +6,7 @@ import ctypes from qiling.hw.peripheral import QlPeripheral +from qiling.hw.const.sam3xa_adc import CR, ISR, LCDR class SAM3xaAdc(QlPeripheral): @@ -50,5 +51,29 @@ class Type(ctypes.Structure): def __init__(self, ql, label, intn = None): super().__init__(ql, label) - self.adc = self.struct() + self.instance = self.struct( + LCDR = 0xfff, + ) self.intn = intn + + @QlPeripheral.monitor() + def read(self, offset: int, size: int) -> int: + buf = ctypes.create_string_buffer(size) + ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) + return int.from_bytes(buf.raw, byteorder='little') + + @QlPeripheral.monitor() + def write(self, offset: int, size: int, value: int): + if offset == self.struct.CHER.offset: + self.instance.CHER |= value + + elif offset == self.struct.CHDR.offset: + self.instance.CHER &= ~value + + elif offset == self.struct.CR.offset: + if value & CR.START: + self.instance.ISR |= ISR.DRDY + + else: + data = (value).to_bytes(size, 'little') + ctypes.memmove(ctypes.addressof(self.instance) + offset, data, size) diff --git a/qiling/hw/analog/sam3xa_dac.py b/qiling/hw/analog/sam3xa_dac.py new file mode 100644 index 000000000..2d557c094 --- /dev/null +++ b/qiling/hw/analog/sam3xa_dac.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import ctypes + +from qiling.hw.peripheral import QlPeripheral +from qiling.hw.const.sam3xa_dac import ISR + + +class SAM3xaDac(QlPeripheral): + class Type(ctypes.Structure): + """ Digital-to-Analog Converter Controller """ + _fields_ = [ + ("CR" , ctypes.c_uint32), # Control Register + ("MR" , ctypes.c_uint32), # Mode Register + ("Reserved1", ctypes.c_uint32 * 2), + ("CHER", ctypes.c_uint32), # Channel Enable Register + ("CHDR", ctypes.c_uint32), # Channel Disable Register + ("CHSR", ctypes.c_uint32), # Channel Status Register + ("Reserved2", ctypes.c_uint32), + ("CDR" , ctypes.c_uint32), # Conversion Data Register + ("IER" , ctypes.c_uint32), # Interrupt Enable Register + ("IDR" , ctypes.c_uint32), # Interrupt Disable Register + ("IMR" , ctypes.c_uint32), # Interrupt Mask Register + ("ISR" , ctypes.c_uint32), # Interrupt Status Register + ("Reserved3", ctypes.c_uint32 * 24), + ("ACR" , ctypes.c_uint32), # Analog Current Register + ("Reserved4", ctypes.c_uint32 * 19), + ("WPMR", ctypes.c_uint32), # Write Protect Mode register + ("WPSR", ctypes.c_uint32), # Write Protect Status register + ("Reserved5", ctypes.c_uint32 * 7), + ("TPR" , ctypes.c_uint32), # Transmit Pointer Register + ("TCR" , ctypes.c_uint32), # Transmit Counter Register + ("Reserved6", ctypes.c_uint32 * 2), + ("TNPR", ctypes.c_uint32), # Transmit Next Pointer Register + ("TNCR", ctypes.c_uint32), # Transmit Next Counter Register + ("PTCR", ctypes.c_uint32), # Transfer Control Register + ("PTSR", ctypes.c_uint32), # Transfer Status Register + ] + + def __init__(self, ql, label, intn=None): + super().__init__(ql, label) + + self.intn = intn + + @QlPeripheral.monitor() + def write(self, offset: int, size: int, value: int): + if offset == self.struct.CDR.offset: + self.instance.ISR |= ISR.EOC + + data = (value).to_bytes(size, 'little') + ctypes.memmove(ctypes.addressof(self.instance) + offset, data, size) diff --git a/qiling/hw/analog/sam3xa_pwm.py b/qiling/hw/analog/sam3xa_pwm.py new file mode 100644 index 000000000..7261cd465 --- /dev/null +++ b/qiling/hw/analog/sam3xa_pwm.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import ctypes + +from qiling.hw.peripheral import QlPeripheral + + +class PwmCh(ctypes.Structure): + _fields_ = [ + ("CMR" , ctypes.c_uint32), # (PwmCh_num Offset: 0x0) PWM Channel Mode Register + ("CDTY" , ctypes.c_uint32), # (PwmCh_num Offset: 0x4) PWM Channel Duty Cycle Register + ("CDTYUPD" , ctypes.c_uint32), # (PwmCh_num Offset: 0x8) PWM Channel Duty Cycle Update Register + ("CPRD" , ctypes.c_uint32), # (PwmCh_num Offset: 0xC) PWM Channel Period Register + ("CPRDUPD" , ctypes.c_uint32), # (PwmCh_num Offset: 0x10) PWM Channel Period Update Register + ("CCNT" , ctypes.c_uint32), # (PwmCh_num Offset: 0x14) PWM Channel Counter Register + ("DT" , ctypes.c_uint32), # (PwmCh_num Offset: 0x18) PWM Channel Dead Time Register + ("DTUPD" , ctypes.c_uint32), # (PwmCh_num Offset: 0x1C) PWM Channel Dead Time Update Register + ] + +class PwmCmp(ctypes.Structure): + _fields_ = [ + ("CMPV" , ctypes.c_uint32), # (PwmCmp Offset: 0x0) PWM Comparison 0 Value Register + ("CMPVUPD", ctypes.c_uint32), # (PwmCmp Offset: 0x4) PWM Comparison 0 Value Update Register + ("CMPM" , ctypes.c_uint32), # (PwmCmp Offset: 0x8) PWM Comparison 0 Mode Register + ("CMPUPD" , ctypes.c_uint32), # (PwmCmp Offset: 0xC) PWM Comparison 0 Mode Update Register + ] + +class SAM3xaPwm(QlPeripheral): + class Type(ctypes.Structure): + """ Pulse Width Modulation Controller """ + _fields_ = [ + ("CLK" , ctypes.c_uint32), # PWM Clock Register + ("ENA" , ctypes.c_uint32), # PWM Enable Register + ("DIS" , ctypes.c_uint32), # PWM Disable Register + ("SR" , ctypes.c_uint32), # PWM Status Register + ("IER1" , ctypes.c_uint32), # PWM Interrupt Enable Register 1 + ("IDR1" , ctypes.c_uint32), # PWM Interrupt Disable Register 1 + ("IMR1" , ctypes.c_uint32), # PWM Interrupt Mask Register 1 + ("ISR1" , ctypes.c_uint32), # PWM Interrupt Status Register 1 + ("SCM" , ctypes.c_uint32), # PWM Sync Channels Mode Register + ("Reserved1", ctypes.c_uint32), + ("SCUC" , ctypes.c_uint32), # PWM Sync Channels Update Control Register + ("SCUP" , ctypes.c_uint32), # PWM Sync Channels Update Period Register + ("SCUPUPD" , ctypes.c_uint32), # PWM Sync Channels Update Period Update Register + ("IER2" , ctypes.c_uint32), # PWM Interrupt Enable Register 2 + ("IDR2" , ctypes.c_uint32), # PWM Interrupt Disable Register 2 + ("IMR2" , ctypes.c_uint32), # PWM Interrupt Mask Register 2 + ("ISR2" , ctypes.c_uint32), # PWM Interrupt Status Register 2 + ("OOV" , ctypes.c_uint32), # PWM Output Override Value Register + ("OS" , ctypes.c_uint32), # PWM Output Selection Register + ("OSS" , ctypes.c_uint32), # PWM Output Selection Set Register + ("OSC" , ctypes.c_uint32), # PWM Output Selection Clear Register + ("OSSUPD" , ctypes.c_uint32), # PWM Output Selection Set Update Register + ("OSCUPD" , ctypes.c_uint32), # PWM Output Selection Clear Update Register + ("FMR" , ctypes.c_uint32), # PWM Fault Mode Register + ("FSR" , ctypes.c_uint32), # PWM Fault Status Register + ("FCR" , ctypes.c_uint32), # PWM Fault Clear Register + ("FPV" , ctypes.c_uint32), # PWM Fault Protection Value Register + ("FPE1" , ctypes.c_uint32), # PWM Fault Protection Enable Register 1 + ("FPE2" , ctypes.c_uint32), # PWM Fault Protection Enable Register 2 + ("Reserved2",ctypes.c_uint32 * 2), + ("ELMR" , ctypes.c_uint32 * 2), # PWM Event Line 0 Mode Register + ("Reserved3",ctypes.c_uint32 * 11), + ("SMMR" , ctypes.c_uint32), # PWM Stepper Motor Mode Register + ("Reserved3",ctypes.c_uint32 * 12), + ("WPCR" , ctypes.c_uint32), # PWM Write Protect Control Register + ("WPSR" , ctypes.c_uint32), # PWM Write Protect Status Register + ("Reserved5",ctypes.c_uint32 * 7), + ("TPR" , ctypes.c_uint32), # Transmit Pointer Register + ("TCR" , ctypes.c_uint32), # Transmit Counter Register + ("Reserved6",ctypes.c_uint32 * 2), + ("TNPR" , ctypes.c_uint32), # Transmit Next Pointer Register + ("TNCR" , ctypes.c_uint32), # Transmit Next Counter Register + ("PTCR" , ctypes.c_uint32), # Transfer Control Register + ("PTSR" , ctypes.c_uint32), # Transfer Status Register + ("Reserved7",ctypes.c_uint32 * 2), + ("CMP" ,PwmCmp * 8), + ("Reserved8",ctypes.c_uint32 * 20), + ("CHNUM" ,PwmCh * 8), + ] + + def __init__(self, ql, label, intn = None): + super().__init__(ql, label) + + self.intn = intn diff --git a/qiling/hw/analog/stm32f1xx_adc.py b/qiling/hw/analog/stm32f1xx_adc.py new file mode 100644 index 000000000..d894b85f7 --- /dev/null +++ b/qiling/hw/analog/stm32f1xx_adc.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import ctypes + +from qiling.hw.peripheral import QlPeripheral +from qiling.hw.const.stm32f1xx_adc import ADC_CR2, ADC_SR + + +class STM32F1xxAdc(QlPeripheral): + class Type(ctypes.Structure): + """ the structure available in : + stm32f100xb + stm32f100xe + stm32f101xb + stm32f101xe + stm32f101xg + stm32f102xb + stm32f103xb + stm32f103xe + stm32f103xg + stm32f105xc + stm32f107xc + """ + + _fields_ = [ + ("SR" , ctypes.c_uint32), + ("CR1" , ctypes.c_uint32), + ("CR2" , ctypes.c_uint32), + ("SMPR1", ctypes.c_uint32), + ("SMPR2", ctypes.c_uint32), + ("JOFR1", ctypes.c_uint32), + ("JOFR2", ctypes.c_uint32), + ("JOFR3", ctypes.c_uint32), + ("JOFR4", ctypes.c_uint32), + ("HTR" , ctypes.c_uint32), + ("LTR" , ctypes.c_uint32), + ("SQR1" , ctypes.c_uint32), + ("SQR2" , ctypes.c_uint32), + ("SQR3" , ctypes.c_uint32), + ("JSQR" , ctypes.c_uint32), + ("JDR1" , ctypes.c_uint32), + ("JDR2" , ctypes.c_uint32), + ("JDR3" , ctypes.c_uint32), + ("JDR4" , ctypes.c_uint32), + ("DR" , ctypes.c_uint32), + ] + + def __init__(self, ql, label, intn = None): + super().__init__(ql, label) + + self.instance = self.struct( + DR = 0x7ff, + ) + self.intn = intn + + @QlPeripheral.monitor() + def read(self, offset: int, size: int) -> int: + buf = ctypes.create_string_buffer(size) + ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) + return int.from_bytes(buf.raw, byteorder='little') + + @QlPeripheral.monitor() + def write(self, offset: int, size: int, value: int): + self.raw_write(offset, size, value) + + if offset == self.struct.CR2.offset: + if value & ADC_CR2.RSTCAL: + self.instance.CR2 = value & ~ADC_CR2.RSTCAL + if value & ADC_CR2.CAL: + self.instance.CR2 = value & ~ADC_CR2.CAL + if value & ADC_CR2.SWSTART: + self.instance.SR |= ADC_SR.EOS + self.instance.CR2 = value & ~ADC_CR2.SWSTART diff --git a/qiling/hw/analog/stm32f4xx_dac.py b/qiling/hw/analog/stm32f4xx_dac.py new file mode 100644 index 000000000..db7fbeb4c --- /dev/null +++ b/qiling/hw/analog/stm32f4xx_dac.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import ctypes + +from qiling.hw.peripheral import QlPeripheral + + +class STM32F4xxDac(QlPeripheral): + class Type(ctypes.Structure): + """ the structure available in : + stm32f405xx + stm32f407xx + stm32f410cx + stm32f410rx + stm32f410tx + stm32f413xx + stm32f415xx + stm32f417xx + stm32f423xx + stm32f427xx + stm32f429xx + stm32f437xx + stm32f439xx + stm32f446xx + stm32f469xx + stm32f479xx + """ + + _fields_ = [ + ("CR" , ctypes.c_uint32), # DAC control register, Address offset: 0x00 + ("SWTRIGR", ctypes.c_uint32), # DAC software trigger register, Address offset: 0x04 + ("DHR12R1", ctypes.c_uint32), # DAC channel1 12-bit right-aligned data holding register, Address offset: 0x08 + ("DHR12L1", ctypes.c_uint32), # DAC channel1 12-bit left aligned data holding register, Address offset: 0x0C + ("DHR8R1" , ctypes.c_uint32), # DAC channel1 8-bit right aligned data holding register, Address offset: 0x10 + ("DHR12R2", ctypes.c_uint32), # DAC channel2 12-bit right aligned data holding register, Address offset: 0x14 + ("DHR12L2", ctypes.c_uint32), # DAC channel2 12-bit left aligned data holding register, Address offset: 0x18 + ("DHR8R2" , ctypes.c_uint32), # DAC channel2 8-bit right-aligned data holding register, Address offset: 0x1C + ("DHR12RD", ctypes.c_uint32), # Dual DAC 12-bit right-aligned data holding register, Address offset: 0x20 + ("DHR12LD", ctypes.c_uint32), # DUAL DAC 12-bit left aligned data holding register, Address offset: 0x24 + ("DHR8RD" , ctypes.c_uint32), # DUAL DAC 8-bit right aligned data holding register, Address offset: 0x28 + ("DOR1" , ctypes.c_uint32), # DAC channel1 data output register, Address offset: 0x2C + ("DOR2" , ctypes.c_uint32), # DAC channel2 data output register, Address offset: 0x30 + ("SR" , ctypes.c_uint32), # DAC status register, Address offset: 0x34 + ] diff --git a/qiling/hw/char/__init__.py b/qiling/hw/char/__init__.py index 444f179f0..ef8a35a65 100644 --- a/qiling/hw/char/__init__.py +++ b/qiling/hw/char/__init__.py @@ -8,3 +8,4 @@ from .gd32vf1xx_usart import GD32VF1xxUsart from .sam3xa_uotghs import SAM3xaUotghs from .sam3xa_uart import SAM3xaUart +from .mk64f12_uart import MK64F12Uart diff --git a/qiling/hw/char/gd32vf1xx_usart.py b/qiling/hw/char/gd32vf1xx_usart.py index 6c13f0359..1ddef5c5d 100644 --- a/qiling/hw/char/gd32vf1xx_usart.py +++ b/qiling/hw/char/gd32vf1xx_usart.py @@ -27,7 +27,7 @@ class Type(ctypes.Structure): def __init__(self, ql, label): super().__init__(ql, label) - self.usart = self.struct( + self.instance = self.struct( STAT = 0x000000c0, DATA = 0x00000000, BAUD = 0x00000000, @@ -36,7 +36,3 @@ def __init__(self, ql, label): CTL2 = 0x00000000, GP = 0x00000000, ) - - @QlConnectivityPeripheral.device_handler - def step(self): - pass diff --git a/qiling/hw/char/mk64f12_uart.py b/qiling/hw/char/mk64f12_uart.py new file mode 100644 index 000000000..b3909612b --- /dev/null +++ b/qiling/hw/char/mk64f12_uart.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import ctypes + +from qiling.hw.peripheral import QlPeripheral +from qiling.hw.connectivity import QlConnectivityPeripheral +from qiling.hw.const.mk64f12_uart import S1, C2, PFIFO + + +class MK64F12Uart(QlConnectivityPeripheral): + class Type(ctypes.Structure): + """ Serial Communication Interface """ + _fields_ = [ + ("BDH" , ctypes.c_uint8), # UART Baud Rate Registers: High + ("BDL" , ctypes.c_uint8), # UART Baud Rate Registers: Low + ("C1" , ctypes.c_uint8), # UART Control Register 1 + ("C2" , ctypes.c_uint8), # UART Control Register 2 + ("S1" , ctypes.c_uint8), # UART Status Register 1 + ("S2" , ctypes.c_uint8), # UART Status Register 2 + ("C3" , ctypes.c_uint8), # UART Control Register 3 + ("D" , ctypes.c_uint8), # UART Data Register + ("MA1" , ctypes.c_uint8), # UART Match Address Registers 1 + ("MA2" , ctypes.c_uint8), # UART Match Address Registers 2 + ("C4" , ctypes.c_uint8), # UART Control Register 4 + ("C5" , ctypes.c_uint8), # UART Control Register 5 + ("ED" , ctypes.c_uint8), # UART Extended Data Register + ("MODEM" , ctypes.c_uint8), # UART Modem Register + ("IR" , ctypes.c_uint8), # UART Infrared Register + ("RESERVED0", ctypes.c_uint8), + ("PFIFO" , ctypes.c_uint8), # UART FIFO Parameters + ("CFIFO" , ctypes.c_uint8), # UART FIFO Control Register + ("SFIFO" , ctypes.c_uint8), # UART FIFO Status Register + ("TWFIFO" , ctypes.c_uint8), # UART FIFO Transmit Watermark + ("TCFIFO" , ctypes.c_uint8), # UART FIFO Transmit Count + ("RWFIFO" , ctypes.c_uint8), # UART FIFO Receive Watermark + ("RCFIFO" , ctypes.c_uint8), # UART FIFO Receive Count + ("RESERVED1", ctypes.c_uint8), + ("C7816" , ctypes.c_uint8), # UART 7816 Control Register + ("IE7816" , ctypes.c_uint8), # UART 7816 Interrupt Enable Register + ("IS7816" , ctypes.c_uint8), # UART 7816 Interrupt Status Register + ("WP7816T0", ctypes.c_uint8), # UART 7816 Wait Parameter Register + ("WN7816" , ctypes.c_uint8), # UART 7816 Wait N Register + ("WF7816" , ctypes.c_uint8), # UART 7816 Wait FD Register + ("ET7816" , ctypes.c_uint8), # UART 7816 Error Threshold Register + ("TL7816" , ctypes.c_uint8), # UART 7816 Transmit Length Register + ] + + def __init__(self, ql, label, + lon_intn = None, + rx_tx_intn = None, + err_intn = None + ): + super().__init__(ql, label) + + self.lon_intn = lon_intn + self.rx_tx_intn = rx_tx_intn + self.err_intn = err_intn + + self.instance = self.struct( + S1 = S1.TDRE | S1.TC + ) + + @QlPeripheral.monitor() + def write(self, offset, size, value): + if offset == self.struct.D.offset: + self.send_to_user(value) + else: + self.raw_write(offset, size, value) + + @QlPeripheral.monitor() + def read(self, offset, size): + if offset == self.struct.D.offset: + if self.instance.PFIFO & PFIFO.RXFE: + self.instance.RCFIFO = 0 + else: + self.instance.S1 &= ~S1.RDRF + return self.recv_from_user() + + return self.raw_read(offset, size) + + def step(self): + if self.has_input(): + if self.instance.PFIFO & PFIFO.RXFE: + self.instance.RCFIFO = 1 + else: + self.instance.S1 |= S1.RDRF + + if self.instance.C2 & C2.RIE: + self.ql.hw.nvic.set_pending(self.rx_tx_intn) diff --git a/qiling/hw/char/sam3xa_uart.py b/qiling/hw/char/sam3xa_uart.py index 1ea3f6a2c..e4ccf2d9a 100644 --- a/qiling/hw/char/sam3xa_uart.py +++ b/qiling/hw/char/sam3xa_uart.py @@ -7,7 +7,7 @@ from qiling.hw.peripheral import QlPeripheral from qiling.hw.connectivity import QlConnectivityPeripheral -from qiling.hw.const.sam3xa_uart import SR +from qiling.hw.const.sam3xa_uart import SR, IER, CR class SAM3xaUart(QlConnectivityPeripheral): @@ -38,21 +38,41 @@ class Type(ctypes.Structure): def __init__(self, ql, label, intn = None): super().__init__(ql, label) - self.uart = self.struct( + self.instance = self.struct( SR = SR.TXRDY ) self.intn = intn @QlPeripheral.monitor() def read(self, offset: int, size: int) -> int: + if offset == self.struct.RHR.offset: + if self.has_input(): + self.instance.SR &= ~SR.RXRDY + return self.recv_from_user() + buf = ctypes.create_string_buffer(size) - ctypes.memmove(buf, ctypes.addressof(self.uart) + offset, size) + ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) return int.from_bytes(buf.raw, byteorder='little') @QlPeripheral.monitor() def write(self, offset: int, size: int, value: int): if offset == self.struct.THR.offset: self.send_to_user(value) + + elif offset == self.struct.IDR.offset: + self.instance.IER &= ~value + + elif offset == self.struct.IER.offset: + self.instance.IER |= value + + else: + data = (value).to_bytes(size, byteorder='little') + ctypes.memmove(ctypes.addressof(self.instance) + offset, data, size) - data = (value).to_bytes(size, byteorder='little') - ctypes.memmove(ctypes.addressof(self.uart) + offset, data, size) + def step(self): + if self.instance.IER & IER.RXRDY and \ + self.instance.CR & CR.RXEN and \ + self.has_input(): + + self.instance.SR |= SR.RXRDY + self.ql.hw.nvic.set_pending(self.intn) diff --git a/qiling/hw/char/sam3xa_uotghs.py b/qiling/hw/char/sam3xa_uotghs.py index 0903fcab5..a97c1fad7 100644 --- a/qiling/hw/char/sam3xa_uotghs.py +++ b/qiling/hw/char/sam3xa_uotghs.py @@ -102,20 +102,20 @@ class Type(ctypes.Structure): def __init__(self, ql, label, intn = None): super().__init__(ql, label) - self.uotghs = self.struct() + self.instance = self.struct() self.intn = intn @QlPeripheral.monitor() def read(self, offset: int, size: int) -> int: buf = ctypes.create_string_buffer(size) - ctypes.memmove(buf, ctypes.addressof(self.uotghs) + offset, size) + ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) return int.from_bytes(buf.raw, byteorder='little') @QlPeripheral.monitor() def write(self, offset: int, size: int, value: int): if offset == self.struct.CTRL.offset: if value & CTRL.OTGPADE == 0: - self.uotghs.SR |= SR.CLKUSABLE + self.instance.SR |= SR.CLKUSABLE data = (value).to_bytes(size, 'little') - ctypes.memmove(ctypes.addressof(self.uotghs) + offset, data, size) + ctypes.memmove(ctypes.addressof(self.instance) + offset, data, size) diff --git a/qiling/hw/char/stm32f4xx_usart.py b/qiling/hw/char/stm32f4xx_usart.py index f4556d350..8351e1afe 100644 --- a/qiling/hw/char/stm32f4xx_usart.py +++ b/qiling/hw/char/stm32f4xx_usart.py @@ -51,7 +51,7 @@ class Type(ctypes.Structure): def __init__(self, ql, label, intn=None): super().__init__(ql, label) - self.usart = self.struct( + self.instance = self.struct( SR = USART_SR.RESET, ) @@ -59,53 +59,43 @@ def __init__(self, ql, label, intn=None): @QlPeripheral.monitor() def read(self, offset: int, size: int) -> int: - buf = ctypes.create_string_buffer(size) - ctypes.memmove(buf, ctypes.addressof(self.usart) + offset, size) - retval = int.from_bytes(buf.raw, byteorder='little') - if offset == self.struct.DR.offset: - self.usart.SR &= ~USART_SR.RXNE + self.instance.SR &= ~USART_SR.RXNE + retval = self.recv_from_user() + self.transfer() + else: + retval = self.raw_read(offset, size) + return retval @QlPeripheral.monitor() - def write(self, offset: int, size: int, value: int): + def write(self, offset: int, size: int, value: int): if offset == self.struct.SR.offset: - self.usart.SR &= value | USART_SR.CTS | USART_SR.LBD | USART_SR.TC | USART_SR.RXNE - + self.instance.SR &= value | USART_SR.CTS | USART_SR.LBD | USART_SR.TC | USART_SR.RXNE | USART_SR.TXE + elif offset == self.struct.DR.offset: - self.usart.SR &= ~USART_SR.TXE - self.usart.DR = value + self.send_to_user(value) else: data = (value).to_bytes(size, byteorder='little') - ctypes.memmove(ctypes.addressof(self.usart) + offset, data, size) + ctypes.memmove(ctypes.addressof(self.instance) + offset, data, size) def transfer(self): - """ transfer data from DR to shift buffer and - receive data from user buffer into DR - """ - - if not (self.usart.SR & USART_SR.TXE): - data = self.usart.DR - - self.usart.SR |= USART_SR.TXE - self.send_to_user(data) - - if not (self.usart.SR & USART_SR.RXNE): - # TXE bit must had been cleared + if not (self.instance.SR & USART_SR.RXNE): if self.has_input(): - self.usart.SR |= USART_SR.RXNE - self.usart.DR = self.recv_from_user() + self.instance.SR |= USART_SR.RXNE + + def check_interrupt(self): + if self.intn is not None: + if (self.instance.CR1 & USART_CR1.PEIE and self.instance.SR & USART_SR.PE) or \ + (self.instance.CR1 & USART_CR1.TXEIE and self.instance.SR & USART_SR.TXE) or \ + (self.instance.CR1 & USART_CR1.TCIE and self.instance.SR & USART_SR.TC) or \ + (self.instance.CR1 & USART_CR1.RXNEIE and self.instance.SR & USART_SR.RXNE) or \ + (self.instance.CR1 & USART_CR1.IDLEIE and self.instance.SR & USART_SR.IDLE): + self.ql.hw.nvic.set_pending(self.intn) @QlConnectivityPeripheral.device_handler def step(self): self.transfer() - - if self.intn is not None: - if (self.usart.CR1 & USART_CR1.PEIE and self.usart.SR & USART_SR.PE) or \ - (self.usart.CR1 & USART_CR1.TXEIE and self.usart.SR & USART_SR.TXE) or \ - (self.usart.CR1 & USART_CR1.TCIE and self.usart.SR & USART_SR.TC) or \ - (self.usart.CR1 & USART_CR1.RXNEIE and self.usart.SR & USART_SR.RXNE) or \ - (self.usart.CR1 & USART_CR1.IDLEIE and self.usart.SR & USART_SR.IDLE): - self.ql.hw.nvic.set_pending(self.intn) + self.check_interrupt() diff --git a/qiling/hw/connectivity.py b/qiling/hw/connectivity.py index 284155ff6..0b492e90f 100644 --- a/qiling/hw/connectivity.py +++ b/qiling/hw/connectivity.py @@ -31,6 +31,20 @@ def write(self, data: bytes): for byte in bytearray(data): self.put(byte) + def save(self): + data = bytearray() + while self.readable(): + data.append(self.get()) + + self.write(data) + return bytes(data) + + def restore(self, data: bytes): + while self.readable(): + self.get() + + self.write(data) + class QlConnectivityPeripheral(QlPeripheral): class Type(ctypes.Structure): @@ -107,4 +121,14 @@ def wrapper(self): func(self) - return wrapper \ No newline at end of file + return wrapper + + def save(self): + return self.itube.save(), self.otube.save(), bytes(self.instance) + + def restore(self, data): + itube, otube, instance = data + + self.itube.restore(itube) + self.otube.restore(otube) + ctypes.memmove(ctypes.addressof(self.instance), instance, len(data)) diff --git a/qiling/hw/const/mk64f12_adc.py b/qiling/hw/const/mk64f12_adc.py new file mode 100644 index 000000000..c4410eb98 --- /dev/null +++ b/qiling/hw/const/mk64f12_adc.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +from enum import IntEnum + + +class SC1(IntEnum): + ADCH = 0x1f << 0 # Input channel select + DIFF = 0x1 << 5 # Differential Mode Enable + AIEN = 0x1 << 6 # Interrupt Enable + COCO = 0x1 << 7 # Conversion Complete Flag + +class CFG1(IntEnum): + ADICLK = 0x3 << 0 # Input Clock Select + MODE = 0x3 << 2 # Conversion mode selection + ADLSMP = 0x1 << 4 # Sample Time Configuration + ADIV = 0x3 << 5 # Clock Divide Select + ADLPC = 0x1 << 7 # Low-Power Configuration + +class CFG2(IntEnum): + ADLSTS = 0x3 << 0 # Long Sample Time Select + ADHSC = 0x1 << 2 # High-Speed Configuration + ADACKEN = 0x1 << 3 # Asynchronous Clock Output Enable + MUXSEL = 0x1 << 4 # ADC Mux Select + +class SC2(IntEnum): + REFSEL = 0x3 << 0 # Voltage Reference Selection + DMAEN = 0x1 << 2 # DMA Enable + ACREN = 0x1 << 3 # Compare Function Range Enable + ACFGT = 0x1 << 4 # Compare Function Greater Than Enable + ACFE = 0x1 << 5 # Compare Function Enable + ADTRG = 0x1 << 6 # Conversion Trigger Select + ADACT = 0x1 << 7 # Conversion Active + +class SC3(IntEnum): + AVGS = 0x3 << 0 # Hardware Average Select + AVGE = 0x1 << 2 # Hardware Average Enable + ADCO = 0x1 << 3 # Continuous Conversion Enable + CALF = 0x1 << 6 # Calibration Failed Flag + CAL = 0x1 << 7 # Calibration diff --git a/qiling/hw/const/mk64f12_ftm.py b/qiling/hw/const/mk64f12_ftm.py new file mode 100644 index 000000000..42bdb7b64 --- /dev/null +++ b/qiling/hw/const/mk64f12_ftm.py @@ -0,0 +1,226 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +from enum import IntEnum + + +class SC(IntEnum): + PS = 0x7 << 0 # Prescale Factor Selection + CLKS = 0x3 << 3 # Clock Source Selection + CPWMS = 0x1 << 5 # Center-Aligned PWM Select + TOIE = 0x1 << 6 # Timer Overflow Interrupt Enable + TOF = 0x1 << 7 # Timer Overflow Flag + +class CSC(IntEnum): + DMA = 0x1 << 0 # DMA Enable + ELSA = 0x1 << 2 # Edge or Level Select + ELSB = 0x1 << 3 # Edge or Level Select + MSA = 0x1 << 4 # Channel Mode Select + MSB = 0x1 << 5 # Channel Mode Select + CHIE = 0x1 << 6 # Channel Interrupt Enable + CHF = 0x1 << 7 # Channel Flag + +class STATUS(IntEnum): + CH0F = 0x1 << 0 # Channel 0 Flag + CH1F = 0x1 << 1 # Channel 1 Flag + CH2F = 0x1 << 2 # Channel 2 Flag + CH3F = 0x1 << 3 # Channel 3 Flag + CH4F = 0x1 << 4 # Channel 4 Flag + CH5F = 0x1 << 5 # Channel 5 Flag + CH6F = 0x1 << 6 # Channel 6 Flag + CH7F = 0x1 << 7 # Channel 7 Flag + +class MODE(IntEnum): + FTMEN = 0x1 << 0 # FTM Enable + INIT = 0x1 << 1 # Initialize The Channels Output + WPDIS = 0x1 << 2 # Write Protection Disable + PWMSYNC = 0x1 << 3 # PWM Synchronization Mode + CAPTEST = 0x1 << 4 # Capture Test Mode Enable + FAULTM = 0x3 << 5 # Fault Control Mode + FAULTIE = 0x1 << 7 # Fault Interrupt Enable + +class SYNC(IntEnum): + CNTMIN = 0x1 << 0 # Minimum Loading Point Enable + CNTMAX = 0x1 << 1 # Maximum Loading Point Enable + REINIT = 0x1 << 2 # FTM Counter Reinitialization By Synchronization (FTM counter synchronization) + SYNCHOM = 0x1 << 3 # Output Mask Synchronization + TRIG0 = 0x1 << 4 # PWM Synchronization Hardware Trigger 0 + TRIG1 = 0x1 << 5 # PWM Synchronization Hardware Trigger 1 + TRIG2 = 0x1 << 6 # PWM Synchronization Hardware Trigger 2 + SWSYNC = 0x1 << 7 # PWM Synchronization Software Trigger + +class OUTINIT(IntEnum): + CH0OI = 0x1 << 0 # Channel 0 Output Initialization Value + CH1OI = 0x1 << 1 # Channel 1 Output Initialization Value + CH2OI = 0x1 << 2 # Channel 2 Output Initialization Value + CH3OI = 0x1 << 3 # Channel 3 Output Initialization Value + CH4OI = 0x1 << 4 # Channel 4 Output Initialization Value + CH5OI = 0x1 << 5 # Channel 5 Output Initialization Value + CH6OI = 0x1 << 6 # Channel 6 Output Initialization Value + CH7OI = 0x1 << 7 # Channel 7 Output Initialization Value + +class OUTMASK(IntEnum): + CH0OM = 0x1 << 0 # Channel 0 Output Mask + CH1OM = 0x1 << 1 # Channel 1 Output Mask + CH2OM = 0x1 << 2 # Channel 2 Output Mask + CH3OM = 0x1 << 3 # Channel 3 Output Mask + CH4OM = 0x1 << 4 # Channel 4 Output Mask + CH5OM = 0x1 << 5 # Channel 5 Output Mask + CH6OM = 0x1 << 6 # Channel 6 Output Mask + CH7OM = 0x1 << 7 # Channel 7 Output Mask + +class COMBINE(IntEnum): + COMBINE0 = 0x1 << 0 # Combine Channels For n = 0 + COMP0 = 0x1 << 1 # Complement Of Channel (n) For n = 0 + DECAPEN0 = 0x1 << 2 # Dual Edge Capture Mode Enable For n = 0 + DECAP0 = 0x1 << 3 # Dual Edge Capture Mode Captures For n = 0 + DTEN0 = 0x1 << 4 # Deadtime Enable For n = 0 + SYNCEN0 = 0x1 << 5 # Synchronization Enable For n = 0 + FAULTEN0 = 0x1 << 6 # Fault Control Enable For n = 0 + COMBINE1 = 0x1 << 8 # Combine Channels For n = 2 + COMP1 = 0x1 << 9 # Complement Of Channel (n) For n = 2 + DECAPEN1 = 0x1 << 10 # Dual Edge Capture Mode Enable For n = 2 + DECAP1 = 0x1 << 11 # Dual Edge Capture Mode Captures For n = 2 + DTEN1 = 0x1 << 12 # Deadtime Enable For n = 2 + SYNCEN1 = 0x1 << 13 # Synchronization Enable For n = 2 + FAULTEN1 = 0x1 << 14 # Fault Control Enable For n = 2 + COMBINE2 = 0x1 << 16 # Combine Channels For n = 4 + COMP2 = 0x1 << 17 # Complement Of Channel (n) For n = 4 + DECAPEN2 = 0x1 << 18 # Dual Edge Capture Mode Enable For n = 4 + DECAP2 = 0x1 << 19 # Dual Edge Capture Mode Captures For n = 4 + DTEN2 = 0x1 << 20 # Deadtime Enable For n = 4 + SYNCEN2 = 0x1 << 21 # Synchronization Enable For n = 4 + FAULTEN2 = 0x1 << 22 # Fault Control Enable For n = 4 + COMBINE3 = 0x1 << 24 # Combine Channels For n = 6 + COMP3 = 0x1 << 25 # Complement Of Channel (n) for n = 6 + DECAPEN3 = 0x1 << 26 # Dual Edge Capture Mode Enable For n = 6 + DECAP3 = 0x1 << 27 # Dual Edge Capture Mode Captures For n = 6 + DTEN3 = 0x1 << 28 # Deadtime Enable For n = 6 + SYNCEN3 = 0x1 << 29 # Synchronization Enable For n = 6 + FAULTEN3 = 0x1 << 30 # Fault Control Enable For n = 6 + +class DEADTIME(IntEnum): + DTVAL = 0x3f << 0 # Deadtime Value + DTPS = 0x3 << 6 # Deadtime Prescaler Value + +class EXTTRIG(IntEnum): + CH2TRIG = 0x1 << 0 # Channel 2 Trigger Enable + CH3TRIG = 0x1 << 1 # Channel 3 Trigger Enable + CH4TRIG = 0x1 << 2 # Channel 4 Trigger Enable + CH5TRIG = 0x1 << 3 # Channel 5 Trigger Enable + CH0TRIG = 0x1 << 4 # Channel 0 Trigger Enable + CH1TRIG = 0x1 << 5 # Channel 1 Trigger Enable + INITTRIGEN = 0x1 << 6 # Initialization Trigger Enable + TRIGF = 0x1 << 7 # Channel Trigger Flag + +class POL(IntEnum): + POL0 = 0x1 << 0 # Channel 0 Polarity + POL1 = 0x1 << 1 # Channel 1 Polarity + POL2 = 0x1 << 2 # Channel 2 Polarity + POL3 = 0x1 << 3 # Channel 3 Polarity + POL4 = 0x1 << 4 # Channel 4 Polarity + POL5 = 0x1 << 5 # Channel 5 Polarity + POL6 = 0x1 << 6 # Channel 6 Polarity + POL7 = 0x1 << 7 # Channel 7 Polarity + +class FMS(IntEnum): + FAULTF0 = 0x1 << 0 # Fault Detection Flag 0 + FAULTF1 = 0x1 << 1 # Fault Detection Flag 1 + FAULTF2 = 0x1 << 2 # Fault Detection Flag 2 + FAULTF3 = 0x1 << 3 # Fault Detection Flag 3 + FAULTIN = 0x1 << 5 # Fault Inputs + WPEN = 0x1 << 6 # Write Protection Enable + FAULTF = 0x1 << 7 # Fault Detection Flag + +class FILTER(IntEnum): + CH0FVAL = 0xf << 0 # Channel 0 Input Filter + CH1FVAL = 0xf << 4 # Channel 1 Input Filter + CH2FVAL = 0xf << 8 # Channel 2 Input Filter + CH3FVAL = 0xf << 12 # Channel 3 Input Filter + +class FLTCTRL(IntEnum): + FAULT0EN = 0x1 << 0 # Fault Input 0 Enable + FAULT1EN = 0x1 << 1 # Fault Input 1 Enable + FAULT2EN = 0x1 << 2 # Fault Input 2 Enable + FAULT3EN = 0x1 << 3 # Fault Input 3 Enable + FFLTR0EN = 0x1 << 4 # Fault Input 0 Filter Enable + FFLTR1EN = 0x1 << 5 # Fault Input 1 Filter Enable + FFLTR2EN = 0x1 << 6 # Fault Input 2 Filter Enable + FFLTR3EN = 0x1 << 7 # Fault Input 3 Filter Enable + FFVAL = 0xf << 8 # Fault Input Filter + +class QDCTRL(IntEnum): + QUADEN = 0x1 << 0 # Quadrature Decoder Mode Enable + TOFDIR = 0x1 << 1 # Timer Overflow Direction In Quadrature Decoder Mode + QUADIR = 0x1 << 2 # FTM Counter Direction In Quadrature Decoder Mode + QUADMODE = 0x1 << 3 # Quadrature Decoder Mode + PHBPOL = 0x1 << 4 # Phase B Input Polarity + PHAPOL = 0x1 << 5 # Phase A Input Polarity + PHBFLTREN = 0x1 << 6 # Phase B Input Filter Enable + PHAFLTREN = 0x1 << 7 # Phase A Input Filter Enable + +class CONF(IntEnum): + NUMTOF = 0x1f << 0 # TOF Frequency + BDMMODE = 0x3 << 6 # BDM Mode + GTBEEN = 0x1 << 9 # Global Time Base Enable + GTBEOUT = 0x1 << 10 # Global Time Base Output + +class FLTPOL(IntEnum): + FLT0POL = 0x1 << 0 # Fault Input 0 Polarity + FLT1POL = 0x1 << 1 # Fault Input 1 Polarity + FLT2POL = 0x1 << 2 # Fault Input 2 Polarity + FLT3POL = 0x1 << 3 # Fault Input 3 Polarity + +class SYNCONF(IntEnum): + HWTRIGMODE = 0x1 << 0 # Hardware Trigger Mode + CNTINC = 0x1 << 2 # CNTIN Register Synchronization + INVC = 0x1 << 4 # INVCTRL Register Synchronization + SWOC = 0x1 << 5 # SWOCTRL Register Synchronization + SYNCMODE = 0x1 << 7 # Synchronization Mode + SWRSTCNT = 0x1 << 8 # FTM counter synchronization is activated by the software trigger. + SWWRBUF = 0x1 << 9 # MOD, CNTIN, and CV registers synchronization is activated by the software trigger. + SWOM = 0x1 << 10 # Output mask synchronization is activated by the software trigger. + SWINVC = 0x1 << 11 # Inverting control synchronization is activated by the software trigger. + SWSOC = 0x1 << 12 # Software output control synchronization is activated by the software trigger. + HWRSTCNT = 0x1 << 16 # FTM counter synchronization is activated by a hardware trigger. + HWWRBUF = 0x1 << 17 # MOD, CNTIN, and CV registers synchronization is activated by a hardware trigger. + HWOM = 0x1 << 18 # Output mask synchronization is activated by a hardware trigger. + HWINVC = 0x1 << 19 # Inverting control synchronization is activated by a hardware trigger. + HWSOC = 0x1 << 20 # Software output control synchronization is activated by a hardware trigger. + +class INVCTRL(IntEnum): + INV0EN = 0x1 << 0 # Pair Channels 0 Inverting Enable + INV1EN = 0x1 << 1 # Pair Channels 1 Inverting Enable + INV2EN = 0x1 << 2 # Pair Channels 2 Inverting Enable + INV3EN = 0x1 << 3 # Pair Channels 3 Inverting Enable + +class SWOCTRL(IntEnum): + CH0OC = 0x1 << 0 # Channel 0 Software Output Control Enable + CH1OC = 0x1 << 1 # Channel 1 Software Output Control Enable + CH2OC = 0x1 << 2 # Channel 2 Software Output Control Enable + CH3OC = 0x1 << 3 # Channel 3 Software Output Control Enable + CH4OC = 0x1 << 4 # Channel 4 Software Output Control Enable + CH5OC = 0x1 << 5 # Channel 5 Software Output Control Enable + CH6OC = 0x1 << 6 # Channel 6 Software Output Control Enable + CH7OC = 0x1 << 7 # Channel 7 Software Output Control Enable + CH0OCV = 0x1 << 8 # Channel 0 Software Output Control Value + CH1OCV = 0x1 << 9 # Channel 1 Software Output Control Value + CH2OCV = 0x1 << 10 # Channel 2 Software Output Control Value + CH3OCV = 0x1 << 11 # Channel 3 Software Output Control Value + CH4OCV = 0x1 << 12 # Channel 4 Software Output Control Value + CH5OCV = 0x1 << 13 # Channel 5 Software Output Control Value + CH6OCV = 0x1 << 14 # Channel 6 Software Output Control Value + CH7OCV = 0x1 << 15 # Channel 7 Software Output Control Value + +class PWMLOAD(IntEnum): + CH0SEL = 0x1 << 0 # Channel 0 Select + CH1SEL = 0x1 << 1 # Channel 1 Select + CH2SEL = 0x1 << 2 # Channel 2 Select + CH3SEL = 0x1 << 3 # Channel 3 Select + CH4SEL = 0x1 << 4 # Channel 4 Select + CH5SEL = 0x1 << 5 # Channel 5 Select + CH6SEL = 0x1 << 6 # Channel 6 Select + CH7SEL = 0x1 << 7 # Channel 7 Select + LDOK = 0x1 << 9 # Load Enable diff --git a/qiling/hw/const/mk64f12_mcg.py b/qiling/hw/const/mk64f12_mcg.py new file mode 100644 index 000000000..9577b5ef5 --- /dev/null +++ b/qiling/hw/const/mk64f12_mcg.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +from enum import IntEnum + + +class C1(IntEnum): + IREFSTEN = 0x1 << 0 # Internal Reference Stop Enable + IRCLKEN = 0x1 << 1 # Internal Reference Clock Enable + IREFS = 0x1 << 2 # Internal Reference Select + FRDIV = 0x7 << 3 # FLL External Reference Divider + CLKS = 0x3 << 6 # Clock Source Select + + IREFS_Pos = 2 + CLKS_Pos = 6 + +class C2(IntEnum): + IRCS = 0x1 << 0 # Internal Reference Clock Select + LP = 0x1 << 1 # Low Power Select + EREFS = 0x1 << 2 # External Reference Select + HGO = 0x1 << 3 # High Gain Oscillator Select + RANGE = 0x3 << 4 # Frequency Range Select + FCFTRIM = 0x1 << 6 # Fast Internal Reference Clock Fine Trim + LOCRE0 = 0x1 << 7 # Loss of Clock Reset Enable + +class C3(IntEnum): + SCTRIM = 0xff << 0 # Slow Internal Reference Clock Trim Setting + +class C4(IntEnum): + SCFTRIM = 0x1 << 0 # Slow Internal Reference Clock Fine Trim + FCTRIM = 0xf << 1 # Fast Internal Reference Clock Trim Setting + DRST_DRS = 0x3 << 5 # DCO Range Select + DMX32 = 0x1 << 7 # DCO Maximum Frequency with 32.768 kHz Reference + +class C5(IntEnum): + PRDIV0 = 0x1f << 0 # PLL External Reference Divider + PLLSTEN0 = 0x1 << 5 # PLL Stop Enable + PLLCLKEN0 = 0x1 << 6 # PLL Clock Enable + +class C6(IntEnum): + VDIV0 = 0x1f << 0 # VCO 0 Divider + CME0 = 0x1 << 5 # Clock Monitor Enable + PLLS = 0x1 << 6 # PLL Select + LOLIE0 = 0x1 << 7 # Loss of Lock Interrrupt Enable + +class S(IntEnum): + IRCST = 0x1 << 0 # Internal Reference Clock Status + OSCINIT0 = 0x1 << 1 # OSC Initialization + CLKST = 0x3 << 2 # Clock Mode Status + IREFST = 0x1 << 4 # Internal Reference Status + PLLST = 0x1 << 5 # PLL Select Status + LOCK0 = 0x1 << 6 # Lock Status + LOLS0 = 0x1 << 7 # Loss of Lock Status + + IREFST_Pos = 4 + CLKST_Pos = 2 + +class SC(IntEnum): + LOCS0 = 0x1 << 0 # OSC0 Loss of Clock Status + FCRDIV = 0x7 << 1 # Fast Clock Internal Reference Divider + FLTPRSRV = 0x1 << 4 # FLL Filter Preserve Enable + ATMF = 0x1 << 5 # Automatic Trim Machine Fail Flag + ATMS = 0x1 << 6 # Automatic Trim Machine Select + ATME = 0x1 << 7 # Automatic Trim Machine Enable + +class ATCVH(IntEnum): + ATCVH = 0xff << 0 # ATM Compare Value High + +class ATCVL(IntEnum): + ATCVL = 0xff << 0 # ATM Compare Value Low + +class C7(IntEnum): + OSCSEL = 0x3 << 0 # MCG OSC Clock Select + +class C8(IntEnum): + LOCS1 = 0x1 << 0 # RTC Loss of Clock Status + CME1 = 0x1 << 5 # Clock Monitor Enable1 + LOLRE = 0x1 << 6 # PLL Loss of Lock Reset Enable + LOCRE1 = 0x1 << 7 # Loss of Clock Reset Enable + diff --git a/qiling/hw/const/mk64f12_port.py b/qiling/hw/const/mk64f12_port.py new file mode 100644 index 000000000..51d16018f --- /dev/null +++ b/qiling/hw/const/mk64f12_port.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +from enum import IntEnum + + +class PCR(IntEnum): + PS = 0x1 << 0 # Pull Select + PE = 0x1 << 1 # Pull Enable + SRE = 0x1 << 2 # Slew Rate Enable + PFE = 0x1 << 4 # Passive Filter Enable + ODE = 0x1 << 5 # Open Drain Enable + DSE = 0x1 << 6 # Drive Strength Enable + MUX = 0x7 << 8 # Pin Mux Control + LK = 0x1 << 15 # Lock Register + IRQC = 0xf << 16 # Interrupt Configuration + ISF = 0x1 << 24 # Interrupt Status Flag + +class InterruptMode(IntEnum): + InterruptOrDMADisabled = 0x0 # Interrupt/DMA request is disabled. + DMARisingEdge = 0x1 # DMA request on rising edge. + DMAFallingEdge = 0x2 # DMA request on falling edge. + DMAEitherEdge = 0x3 # DMA request on either edge. + FlagRisingEdge = 0x5 # Flag sets on rising edge. + FlagFallingEdge = 0x6 # Flag sets on falling edge. + FlagEitherEdge = 0x7 # Flag sets on either edge. + InterruptLogicZero = 0x8 # Interrupt when logic zero. + InterruptRisingEdge = 0x9 # Interrupt on rising edge. + InterruptFallingEdge = 0xA # Interrupt on falling edge. + InterruptEitherEdge = 0xB # Interrupt on either edge. + InterruptLogicOne = 0xC # Interrupt when logic one. diff --git a/qiling/hw/const/mk64f12_spi.py b/qiling/hw/const/mk64f12_spi.py new file mode 100644 index 000000000..2f1d41aae --- /dev/null +++ b/qiling/hw/const/mk64f12_spi.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +from enum import IntEnum + + +class MCR(IntEnum): + HALT = 0x1 << 0 # Halt + SMPL_PT = 0x3 << 8 # Sample Point + CLR_RXF = 0x1 << 10 # Flushes the RX FIFO + CLR_TXF = 0x1 << 11 # Clear TX FIFO + DIS_RXF = 0x1 << 12 # Disable Receive FIFO + DIS_TXF = 0x1 << 13 # Disable Transmit FIFO + MDIS = 0x1 << 14 # Module Disable + DOZE = 0x1 << 15 # Doze Enable + PCSIS0 = 0x1 << 16 # Peripheral Chip Select x Inactive State + PCSIS1 = 0x1 << 17 # Peripheral Chip Select x Inactive State + PCSIS2 = 0x1 << 18 # Peripheral Chip Select x Inactive State + PCSIS3 = 0x1 << 19 # Peripheral Chip Select x Inactive State + PCSIS4 = 0x1 << 20 # Peripheral Chip Select x Inactive State + PCSIS5 = 0x1 << 21 # Peripheral Chip Select x Inactive State + ROOE = 0x1 << 24 # Receive FIFO Overflow Overwrite Enable + PCSSE = 0x1 << 25 # Peripheral Chip Select Strobe Enable + MTFE = 0x1 << 26 # Modified Timing Format Enable + FRZ = 0x1 << 27 # Freeze + DCONF = 0x3 << 28 # SPI Configuration. + CONT_SCKE = 0x1 << 30 # Continuous SCK Enable + MSTR = 0x1 << 31 # Master/Slave Mode Select + +class CTAR(IntEnum): + BR = 0xf << 0 # Baud Rate Scaler + DT = 0xf << 4 # Delay After Transfer Scaler + ASC = 0xf << 8 # After SCK Delay Scaler + CSSCK = 0xf << 12 # PCS to SCK Delay Scaler + PBR = 0x3 << 16 # Baud Rate Prescaler + PDT = 0x3 << 18 # Delay after Transfer Prescaler + PASC = 0x3 << 20 # After SCK Delay Prescaler + PCSSCK = 0x3 << 22 # PCS to SCK Delay Prescaler + LSBFE = 0x1 << 24 # LSB First + CPHA = 0x1 << 25 # Clock Phase + CPOL = 0x1 << 26 # Clock Polarity + FMSZ = 0xf << 27 # Frame Size + DBR = 0x1 << 31 # Double Baud Rate + +class SR(IntEnum): + POPNXTPTR = 0xf << 0 # Pop Next Pointer + RXCTR = 0xf << 4 # RX FIFO Counter + TXNXTPTR = 0xf << 8 # Transmit Next Pointer + TXCTR = 0xf << 12 # TX FIFO Counter + RFDF = 0x1 << 17 # Receive FIFO Drain Flag + RFOF = 0x1 << 19 # Receive FIFO Overflow Flag + TFFF = 0x1 << 25 # Transmit FIFO Fill Flag + TFUF = 0x1 << 27 # Transmit FIFO Underflow Flag + EOQF = 0x1 << 28 # End of Queue Flag + TXRXS = 0x1 << 30 # TX and RX Status + TCF = 0x1 << 31 # Transfer Complete Flag + +class RSER(IntEnum): + RFDF_DIRS = 0x1 << 16 # Receive FIFO Drain DMA or Interrupt Request Select + RFDF_RE = 0x1 << 17 # Receive FIFO Drain Request Enable + RFOF_RE = 0x1 << 19 # Receive FIFO Overflow Request Enable + TFFF_DIRS = 0x1 << 24 # Transmit FIFO Fill DMA or Interrupt Request Select + TFFF_RE = 0x1 << 25 # Transmit FIFO Fill Request Enable + TFUF_RE = 0x1 << 27 # Transmit FIFO Underflow Request Enable + EOQF_RE = 0x1 << 28 # Finished Request Enable + TCF_RE = 0x1 << 31 # Transmission Complete Request Enable + +class PUSHR(IntEnum): + TXDATA = 0xffff << 0 # Transmit Data + PCS0 = 0x1 << 16 # Select which PCS signals are to be asserted for the transfer + PCS1 = 0x1 << 17 # Select which PCS signals are to be asserted for the transfer + PCS2 = 0x1 << 18 # Select which PCS signals are to be asserted for the transfer + PCS3 = 0x1 << 19 # Select which PCS signals are to be asserted for the transfer + PCS4 = 0x1 << 20 # Select which PCS signals are to be asserted for the transfer + PCS5 = 0x1 << 21 # Select which PCS signals are to be asserted for the transfer + CTCNT = 0x1 << 26 # Clear Transfer Counter + EOQ = 0x1 << 27 # End Of Queue + CTAS = 0x7 << 28 # Clock and Transfer Attributes Select + CONT = 0x1 << 31 # Continuous Peripheral Chip Select Enable + +class TXFR(IntEnum): + TXDATA = 0xffff << 0 # Transmit Data + TXCMD_TXDATA = 0xffff << 16 # Transmit Command or Transmit Data diff --git a/qiling/hw/const/mk64f12_uart.py b/qiling/hw/const/mk64f12_uart.py new file mode 100644 index 000000000..9f1538b92 --- /dev/null +++ b/qiling/hw/const/mk64f12_uart.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +from enum import IntEnum + + +class BDH(IntEnum): + SBR = 0x1f << 0 # UART Baud Rate Bits + SBNS = 0x1 << 5 # Stop Bit Number Select + RXEDGIE = 0x1 << 6 # RxD Input Active Edge Interrupt Enable + LBKDIE = 0x1 << 7 # LIN Break Detect Interrupt or DMA Request Enable + +class C1(IntEnum): + PT = 0x1 << 0 # Parity Type + PE = 0x1 << 1 # Parity Enable + ILT = 0x1 << 2 # Idle Line Type Select + WAKE = 0x1 << 3 # Receiver Wakeup Method Select + M = 0x1 << 4 # 9-bit or 8-bit Mode Select + RSRC = 0x1 << 5 # Receiver Source Select + UARTSWAI = 0x1 << 6 # UART Stops in Wait Mode + LOOPS = 0x1 << 7 # Loop Mode Select + +class C2(IntEnum): + SBK = 0x1 << 0 # Send Break + RWU = 0x1 << 1 # Receiver Wakeup Control + RE = 0x1 << 2 # Receiver Enable + TE = 0x1 << 3 # Transmitter Enable + ILIE = 0x1 << 4 # Idle Line Interrupt DMA Transfer Enable + RIE = 0x1 << 5 # Receiver Full Interrupt or DMA Transfer Enable + TCIE = 0x1 << 6 # Transmission Complete Interrupt or DMA Transfer Enable + TIE = 0x1 << 7 # Transmitter Interrupt or DMA Transfer Enable. + +class S1(IntEnum): + PF = 0x1 << 0 # Parity Error Flag + FE = 0x1 << 1 # Framing Error Flag + NF = 0x1 << 2 # Noise Flag + OR = 0x1 << 3 # Receiver Overrun Flag + IDLE = 0x1 << 4 # Idle Line Flag + RDRF = 0x1 << 5 # Receive Data Register Full Flag + TC = 0x1 << 6 # Transmit Complete Flag + TDRE = 0x1 << 7 # Transmit Data Register Empty Flag + +class S2(IntEnum): + RAF = 0x1 << 0 # Receiver Active Flag + LBKDE = 0x1 << 1 # LIN Break Detection Enable + BRK13 = 0x1 << 2 # Break Transmit Character Length + RWUID = 0x1 << 3 # Receive Wakeup Idle Detect + RXINV = 0x1 << 4 # Receive Data Inversion + MSBF = 0x1 << 5 # Most Significant Bit First + RXEDGIF = 0x1 << 6 # RxD Pin Active Edge Interrupt Flag + LBKDIF = 0x1 << 7 # LIN Break Detect Interrupt Flag + +class C3(IntEnum): + PEIE = 0x1 << 0 # Parity Error Interrupt Enable + FEIE = 0x1 << 1 # Framing Error Interrupt Enable + NEIE = 0x1 << 2 # Noise Error Interrupt Enable + ORIE = 0x1 << 3 # Overrun Error Interrupt Enable + TXINV = 0x1 << 4 # Transmit Data Inversion. + TXDIR = 0x1 << 5 # Transmitter Pin Data Direction in Single-Wire mode + T8 = 0x1 << 6 # Transmit Bit 8 + R8 = 0x1 << 7 # Received Bit 8 + +class C4(IntEnum): + BRFA = 0x1f << 0 # Baud Rate Fine Adjust + M10 = 0x1 << 5 # 10-bit Mode select + MAEN2 = 0x1 << 6 # Match Address Mode Enable 2 + MAEN1 = 0x1 << 7 # Match Address Mode Enable 1 + +class C5(IntEnum): + LBKDDMAS = 0x1 << 3 # LIN Break Detect DMA Select Bit + ILDMAS = 0x1 << 4 # Idle Line DMA Select + RDMAS = 0x1 << 5 # Receiver Full DMA Select + TCDMAS = 0x1 << 6 # Transmission Complete DMA Select + TDMAS = 0x1 << 7 # Transmitter DMA Select + +class ED(IntEnum): + PARITYE = 0x1 << 6 # The current received dataword contained in D and C3[R8] was received with a parity error. + NOISY = 0x1 << 7 # The current received dataword contained in D and C3[R8] was received with noise. + +class MODEM(IntEnum): + TXCTSE = 0x1 << 0 # Transmitter clear-to-send enable + TXRTSE = 0x1 << 1 # Transmitter request-to-send enable + TXRTSPOL = 0x1 << 2 # Transmitter request-to-send polarity + RXRTSE = 0x1 << 3 # Receiver request-to-send enable + +class IR(IntEnum): + TNP = 0x3 << 0 # Transmitter narrow pulse + IREN = 0x1 << 2 # Infrared enable + +class PFIFO(IntEnum): + RXFIFOSIZE = 0x7 << 0 # Receive FIFO. Buffer Depth + RXFE = 0x1 << 3 # Receive FIFO Enable + TXFIFOSIZE = 0x7 << 4 # Transmit FIFO. Buffer Depth + TXFE = 0x1 << 7 # Transmit FIFO Enable + +class CFIFO(IntEnum): + RXUFE = 0x1 << 0 # Receive FIFO Underflow Interrupt Enable + TXOFE = 0x1 << 1 # Transmit FIFO Overflow Interrupt Enable + RXOFE = 0x1 << 2 # Receive FIFO Overflow Interrupt Enable + RXFLUSH = 0x1 << 6 # Receive FIFO/Buffer Flush + TXFLUSH = 0x1 << 7 # Transmit FIFO/Buffer Flush + +class SFIFO(IntEnum): + RXUF = 0x1 << 0 # Receiver Buffer Underflow Flag + TXOF = 0x1 << 1 # Transmitter Buffer Overflow Flag + RXOF = 0x1 << 2 # Receiver Buffer Overflow Flag + RXEMPT = 0x1 << 6 # Receive Buffer/FIFO Empty + TXEMPT = 0x1 << 7 # Transmit Buffer/FIFO Empty + +class C7816(IntEnum): + ISO_7816E = 0x1 << 0 # ISO-7816 Functionality Enabled + TTYPE = 0x1 << 1 # Transfer Type + INIT = 0x1 << 2 # Detect Initial Character + ANACK = 0x1 << 3 # Generate NACK on Error + ONACK = 0x1 << 4 # Generate NACK on Overflow + +class IE7816(IntEnum): + RXTE = 0x1 << 0 # Receive Threshold Exceeded Interrupt Enable + TXTE = 0x1 << 1 # Transmit Threshold Exceeded Interrupt Enable + GTVE = 0x1 << 2 # Guard Timer Violated Interrupt Enable + INITDE = 0x1 << 4 # Initial Character Detected Interrupt Enable + BWTE = 0x1 << 5 # Block Wait Timer Interrupt Enable + CWTE = 0x1 << 6 # Character Wait Timer Interrupt Enable + WTE = 0x1 << 7 # Wait Timer Interrupt Enable + +class IS7816(IntEnum): + RXT = 0x1 << 0 # Receive Threshold Exceeded Interrupt + TXT = 0x1 << 1 # Transmit Threshold Exceeded Interrupt + GTV = 0x1 << 2 # Guard Timer Violated Interrupt + INITD = 0x1 << 4 # Initial Character Detected Interrupt + BWT = 0x1 << 5 # Block Wait Timer Interrupt + CWT = 0x1 << 6 # Character Wait Timer Interrupt + WT = 0x1 << 7 # Wait Timer Interrupt + +class WP7816T1(IntEnum): + BWI = 0xf << 0 # Block Wait Time Integer(C7816[TTYPE] = 1) + CWI = 0xf << 4 # Character Wait Time Integer (C7816[TTYPE] = 1) + +class ET7816(IntEnum): + RXTHRESHOLD = 0xf << 0 # Receive NACK Threshold + TXTHRESHOLD = 0xf << 4 # Transmit NACK Threshold diff --git a/qiling/hw/const/sam3xa_adc.py b/qiling/hw/const/sam3xa_adc.py new file mode 100644 index 000000000..567c3d750 --- /dev/null +++ b/qiling/hw/const/sam3xa_adc.py @@ -0,0 +1,314 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +from enum import IntEnum + + +class CR(IntEnum): + SWRST = 0x1 << 0 # Software Reset + START = 0x1 << 1 # Start Conversion + +class MR(IntEnum): + TRGEN = 0x1 << 0 # Trigger Enable + TRGSEL = 0x7 << 1 # Trigger Selection + LOWRES = 0x1 << 4 # Resolution + SLEEP = 0x1 << 5 # Sleep Mode + FWUP = 0x1 << 6 # Fast Wake Up + FREERUN = 0x1 << 7 # Free Run Mode + PRESCAL = 0xff << 8 # Prescaler Rate Selection + STARTUP = 0xf << 16 # Start Up Time + SETTLING = 0x3 << 20 # Analog Settling Time + ANACH = 0x1 << 23 # Analog Change + TRACKTIM = 0xf << 24 # Tracking Time + TRANSFER = 0x3 << 28 # Transfer Period + USEQ = 0x1 << 31 # Use Sequence Enable + +class SEQR1(IntEnum): + USCH1 = 0xf << 0 # User Sequence Number 1 + USCH2 = 0xf << 4 # User Sequence Number 2 + USCH3 = 0xf << 8 # User Sequence Number 3 + USCH4 = 0xf << 12 # User Sequence Number 4 + USCH5 = 0xf << 16 # User Sequence Number 5 + USCH6 = 0xf << 20 # User Sequence Number 6 + USCH7 = 0xf << 24 # User Sequence Number 7 + USCH8 = 0xf << 28 # User Sequence Number 8 + +class SEQR2(IntEnum): + USCH9 = 0xf << 0 # User Sequence Number 9 + USCH10 = 0xf << 4 # User Sequence Number 10 + USCH11 = 0xf << 8 # User Sequence Number 11 + USCH12 = 0xf << 12 # User Sequence Number 12 + USCH13 = 0xf << 16 # User Sequence Number 13 + USCH14 = 0xf << 20 # User Sequence Number 14 + USCH15 = 0xf << 24 # User Sequence Number 15 + USCH16 = 0xf << 28 # User Sequence Number 16 + +class CHER(IntEnum): + CH0 = 0x1 << 0 # Channel 0 Enable + CH1 = 0x1 << 1 # Channel 1 Enable + CH2 = 0x1 << 2 # Channel 2 Enable + CH3 = 0x1 << 3 # Channel 3 Enable + CH4 = 0x1 << 4 # Channel 4 Enable + CH5 = 0x1 << 5 # Channel 5 Enable + CH6 = 0x1 << 6 # Channel 6 Enable + CH7 = 0x1 << 7 # Channel 7 Enable + CH8 = 0x1 << 8 # Channel 8 Enable + CH9 = 0x1 << 9 # Channel 9 Enable + CH10 = 0x1 << 10 # Channel 10 Enable + CH11 = 0x1 << 11 # Channel 11 Enable + CH12 = 0x1 << 12 # Channel 12 Enable + CH13 = 0x1 << 13 # Channel 13 Enable + CH14 = 0x1 << 14 # Channel 14 Enable + CH15 = 0x1 << 15 # Channel 15 Enable + +class CHDR(IntEnum): + CH0 = 0x1 << 0 # Channel 0 Disable + CH1 = 0x1 << 1 # Channel 1 Disable + CH2 = 0x1 << 2 # Channel 2 Disable + CH3 = 0x1 << 3 # Channel 3 Disable + CH4 = 0x1 << 4 # Channel 4 Disable + CH5 = 0x1 << 5 # Channel 5 Disable + CH6 = 0x1 << 6 # Channel 6 Disable + CH7 = 0x1 << 7 # Channel 7 Disable + CH8 = 0x1 << 8 # Channel 8 Disable + CH9 = 0x1 << 9 # Channel 9 Disable + CH10 = 0x1 << 10 # Channel 10 Disable + CH11 = 0x1 << 11 # Channel 11 Disable + CH12 = 0x1 << 12 # Channel 12 Disable + CH13 = 0x1 << 13 # Channel 13 Disable + CH14 = 0x1 << 14 # Channel 14 Disable + CH15 = 0x1 << 15 # Channel 15 Disable + +class CHSR(IntEnum): + CH0 = 0x1 << 0 # Channel 0 Status + CH1 = 0x1 << 1 # Channel 1 Status + CH2 = 0x1 << 2 # Channel 2 Status + CH3 = 0x1 << 3 # Channel 3 Status + CH4 = 0x1 << 4 # Channel 4 Status + CH5 = 0x1 << 5 # Channel 5 Status + CH6 = 0x1 << 6 # Channel 6 Status + CH7 = 0x1 << 7 # Channel 7 Status + CH8 = 0x1 << 8 # Channel 8 Status + CH9 = 0x1 << 9 # Channel 9 Status + CH10 = 0x1 << 10 # Channel 10 Status + CH11 = 0x1 << 11 # Channel 11 Status + CH12 = 0x1 << 12 # Channel 12 Status + CH13 = 0x1 << 13 # Channel 13 Status + CH14 = 0x1 << 14 # Channel 14 Status + CH15 = 0x1 << 15 # Channel 15 Status + +class LCDR(IntEnum): + LDATA = 0xfff << 0 # Last Data Converted + CHNB = 0xf << 12 # Channel Number + +class IER(IntEnum): + EOC0 = 0x1 << 0 # End of Conversion Interrupt Enable 0 + EOC1 = 0x1 << 1 # End of Conversion Interrupt Enable 1 + EOC2 = 0x1 << 2 # End of Conversion Interrupt Enable 2 + EOC3 = 0x1 << 3 # End of Conversion Interrupt Enable 3 + EOC4 = 0x1 << 4 # End of Conversion Interrupt Enable 4 + EOC5 = 0x1 << 5 # End of Conversion Interrupt Enable 5 + EOC6 = 0x1 << 6 # End of Conversion Interrupt Enable 6 + EOC7 = 0x1 << 7 # End of Conversion Interrupt Enable 7 + EOC8 = 0x1 << 8 # End of Conversion Interrupt Enable 8 + EOC9 = 0x1 << 9 # End of Conversion Interrupt Enable 9 + EOC10 = 0x1 << 10 # End of Conversion Interrupt Enable 10 + EOC11 = 0x1 << 11 # End of Conversion Interrupt Enable 11 + EOC12 = 0x1 << 12 # End of Conversion Interrupt Enable 12 + EOC13 = 0x1 << 13 # End of Conversion Interrupt Enable 13 + EOC14 = 0x1 << 14 # End of Conversion Interrupt Enable 14 + EOC15 = 0x1 << 15 # End of Conversion Interrupt Enable 15 + DRDY = 0x1 << 24 # Data Ready Interrupt Enable + GOVRE = 0x1 << 25 # General Overrun Error Interrupt Enable + COMPE = 0x1 << 26 # Comparison Event Interrupt Enable + ENDRX = 0x1 << 27 # End of Receive Buffer Interrupt Enable + RXBUFF = 0x1 << 28 # Receive Buffer Full Interrupt Enable + +class IDR(IntEnum): + EOC0 = 0x1 << 0 # End of Conversion Interrupt Disable 0 + EOC1 = 0x1 << 1 # End of Conversion Interrupt Disable 1 + EOC2 = 0x1 << 2 # End of Conversion Interrupt Disable 2 + EOC3 = 0x1 << 3 # End of Conversion Interrupt Disable 3 + EOC4 = 0x1 << 4 # End of Conversion Interrupt Disable 4 + EOC5 = 0x1 << 5 # End of Conversion Interrupt Disable 5 + EOC6 = 0x1 << 6 # End of Conversion Interrupt Disable 6 + EOC7 = 0x1 << 7 # End of Conversion Interrupt Disable 7 + EOC8 = 0x1 << 8 # End of Conversion Interrupt Disable 8 + EOC9 = 0x1 << 9 # End of Conversion Interrupt Disable 9 + EOC10 = 0x1 << 10 # End of Conversion Interrupt Disable 10 + EOC11 = 0x1 << 11 # End of Conversion Interrupt Disable 11 + EOC12 = 0x1 << 12 # End of Conversion Interrupt Disable 12 + EOC13 = 0x1 << 13 # End of Conversion Interrupt Disable 13 + EOC14 = 0x1 << 14 # End of Conversion Interrupt Disable 14 + EOC15 = 0x1 << 15 # End of Conversion Interrupt Disable 15 + DRDY = 0x1 << 24 # Data Ready Interrupt Disable + GOVRE = 0x1 << 25 # General Overrun Error Interrupt Disable + COMPE = 0x1 << 26 # Comparison Event Interrupt Disable + ENDRX = 0x1 << 27 # End of Receive Buffer Interrupt Disable + RXBUFF = 0x1 << 28 # Receive Buffer Full Interrupt Disable + +class IMR(IntEnum): + EOC0 = 0x1 << 0 # End of Conversion Interrupt Mask 0 + EOC1 = 0x1 << 1 # End of Conversion Interrupt Mask 1 + EOC2 = 0x1 << 2 # End of Conversion Interrupt Mask 2 + EOC3 = 0x1 << 3 # End of Conversion Interrupt Mask 3 + EOC4 = 0x1 << 4 # End of Conversion Interrupt Mask 4 + EOC5 = 0x1 << 5 # End of Conversion Interrupt Mask 5 + EOC6 = 0x1 << 6 # End of Conversion Interrupt Mask 6 + EOC7 = 0x1 << 7 # End of Conversion Interrupt Mask 7 + EOC8 = 0x1 << 8 # End of Conversion Interrupt Mask 8 + EOC9 = 0x1 << 9 # End of Conversion Interrupt Mask 9 + EOC10 = 0x1 << 10 # End of Conversion Interrupt Mask 10 + EOC11 = 0x1 << 11 # End of Conversion Interrupt Mask 11 + EOC12 = 0x1 << 12 # End of Conversion Interrupt Mask 12 + EOC13 = 0x1 << 13 # End of Conversion Interrupt Mask 13 + EOC14 = 0x1 << 14 # End of Conversion Interrupt Mask 14 + EOC15 = 0x1 << 15 # End of Conversion Interrupt Mask 15 + DRDY = 0x1 << 24 # Data Ready Interrupt Mask + GOVRE = 0x1 << 25 # General Overrun Error Interrupt Mask + COMPE = 0x1 << 26 # Comparison Event Interrupt Mask + ENDRX = 0x1 << 27 # End of Receive Buffer Interrupt Mask + RXBUFF = 0x1 << 28 # Receive Buffer Full Interrupt Mask + +class ISR(IntEnum): + EOC0 = 0x1 << 0 # End of Conversion 0 + EOC1 = 0x1 << 1 # End of Conversion 1 + EOC2 = 0x1 << 2 # End of Conversion 2 + EOC3 = 0x1 << 3 # End of Conversion 3 + EOC4 = 0x1 << 4 # End of Conversion 4 + EOC5 = 0x1 << 5 # End of Conversion 5 + EOC6 = 0x1 << 6 # End of Conversion 6 + EOC7 = 0x1 << 7 # End of Conversion 7 + EOC8 = 0x1 << 8 # End of Conversion 8 + EOC9 = 0x1 << 9 # End of Conversion 9 + EOC10 = 0x1 << 10 # End of Conversion 10 + EOC11 = 0x1 << 11 # End of Conversion 11 + EOC12 = 0x1 << 12 # End of Conversion 12 + EOC13 = 0x1 << 13 # End of Conversion 13 + EOC14 = 0x1 << 14 # End of Conversion 14 + EOC15 = 0x1 << 15 # End of Conversion 15 + DRDY = 0x1 << 24 # Data Ready + GOVRE = 0x1 << 25 # General Overrun Error + COMPE = 0x1 << 26 # Comparison Error + ENDRX = 0x1 << 27 # End of RX Buffer + RXBUFF = 0x1 << 28 # RX Buffer Full + +class OVER(IntEnum): + OVRE0 = 0x1 << 0 # Overrun Error 0 + OVRE1 = 0x1 << 1 # Overrun Error 1 + OVRE2 = 0x1 << 2 # Overrun Error 2 + OVRE3 = 0x1 << 3 # Overrun Error 3 + OVRE4 = 0x1 << 4 # Overrun Error 4 + OVRE5 = 0x1 << 5 # Overrun Error 5 + OVRE6 = 0x1 << 6 # Overrun Error 6 + OVRE7 = 0x1 << 7 # Overrun Error 7 + OVRE8 = 0x1 << 8 # Overrun Error 8 + OVRE9 = 0x1 << 9 # Overrun Error 9 + OVRE10 = 0x1 << 10 # Overrun Error 10 + OVRE11 = 0x1 << 11 # Overrun Error 11 + OVRE12 = 0x1 << 12 # Overrun Error 12 + OVRE13 = 0x1 << 13 # Overrun Error 13 + OVRE14 = 0x1 << 14 # Overrun Error 14 + OVRE15 = 0x1 << 15 # Overrun Error 15 + +class EMR(IntEnum): + CMPMODE = 0x3 << 0 # Comparison Mode + CMPSEL = 0xf << 4 # Comparison Selected Channel + CMPALL = 0x1 << 9 # Compare All Channels + CMPFILTER = 0x3 << 12 # Compare Event Filtering + TAG = 0x1 << 24 # TAG of ADC_LDCR register + +class CWR(IntEnum): + LOWTHRES = 0xfff << 0 # Low Threshold + HIGHTHRES = 0xfff << 16 # High Threshold + +class CGR(IntEnum): + GAIN0 = 0x3 << 0 # Gain for channel 0 + GAIN1 = 0x3 << 2 # Gain for channel 1 + GAIN2 = 0x3 << 4 # Gain for channel 2 + GAIN3 = 0x3 << 6 # Gain for channel 3 + GAIN4 = 0x3 << 8 # Gain for channel 4 + GAIN5 = 0x3 << 10 # Gain for channel 5 + GAIN6 = 0x3 << 12 # Gain for channel 6 + GAIN7 = 0x3 << 14 # Gain for channel 7 + GAIN8 = 0x3 << 16 # Gain for channel 8 + GAIN9 = 0x3 << 18 # Gain for channel 9 + GAIN10 = 0x3 << 20 # Gain for channel 10 + GAIN11 = 0x3 << 22 # Gain for channel 11 + GAIN12 = 0x3 << 24 # Gain for channel 12 + GAIN13 = 0x3 << 26 # Gain for channel 13 + GAIN14 = 0x3 << 28 # Gain for channel 14 + GAIN15 = 0x3 << 30 # Gain for channel 15 + +class COR(IntEnum): + OFF0 = 0x1 << 0 # Offset for channel 0 + OFF1 = 0x1 << 1 # Offset for channel 1 + OFF2 = 0x1 << 2 # Offset for channel 2 + OFF3 = 0x1 << 3 # Offset for channel 3 + OFF4 = 0x1 << 4 # Offset for channel 4 + OFF5 = 0x1 << 5 # Offset for channel 5 + OFF6 = 0x1 << 6 # Offset for channel 6 + OFF7 = 0x1 << 7 # Offset for channel 7 + OFF8 = 0x1 << 8 # Offset for channel 8 + OFF9 = 0x1 << 9 # Offset for channel 9 + OFF10 = 0x1 << 10 # Offset for channel 10 + OFF11 = 0x1 << 11 # Offset for channel 11 + OFF12 = 0x1 << 12 # Offset for channel 12 + OFF13 = 0x1 << 13 # Offset for channel 13 + OFF14 = 0x1 << 14 # Offset for channel 14 + OFF15 = 0x1 << 15 # Offset for channel 15 + DIFF0 = 0x1 << 16 # Differential inputs for channel 0 + DIFF1 = 0x1 << 17 # Differential inputs for channel 1 + DIFF2 = 0x1 << 18 # Differential inputs for channel 2 + DIFF3 = 0x1 << 19 # Differential inputs for channel 3 + DIFF4 = 0x1 << 20 # Differential inputs for channel 4 + DIFF5 = 0x1 << 21 # Differential inputs for channel 5 + DIFF6 = 0x1 << 22 # Differential inputs for channel 6 + DIFF7 = 0x1 << 23 # Differential inputs for channel 7 + DIFF8 = 0x1 << 24 # Differential inputs for channel 8 + DIFF9 = 0x1 << 25 # Differential inputs for channel 9 + DIFF10 = 0x1 << 26 # Differential inputs for channel 10 + DIFF11 = 0x1 << 27 # Differential inputs for channel 11 + DIFF12 = 0x1 << 28 # Differential inputs for channel 12 + DIFF13 = 0x1 << 29 # Differential inputs for channel 13 + DIFF14 = 0x1 << 30 # Differential inputs for channel 14 + DIFF15 = 0x1 << 31 # Differential inputs for channel 15 + +class CDR(IntEnum): + DATA = 0xfff << 0 # Converted Data + +class ACR(IntEnum): + TSON = 0x1 << 4 # Temperature Sensor On + IBCTL = 0x3 << 8 # ADC Bias Current Control + +class WPMR(IntEnum): + WPEN = 0x1 << 0 # Write Protect Enable + WPKEY = 0xffffff << 8 # Write Protect KEY + +class WPSR(IntEnum): + WPVS = 0x1 << 0 # Write Protect Violation Status + WPVSRC = 0xffff << 8 # Write Protect Violation Source + +class RPR(IntEnum): + RXPTR = 0xffffffff << 0 # Receive Pointer Register + +class RCR(IntEnum): + RXCTR = 0xffff << 0 # Receive Counter Register + +class RNPR(IntEnum): + RXNPTR = 0xffffffff << 0 # Receive Next Pointer + +class RNCR(IntEnum): + RXNCTR = 0xffff << 0 # Receive Next Counter + +class PTCR(IntEnum): + RXTEN = 0x1 << 0 # Receiver Transfer Enable + RXTDIS = 0x1 << 1 # Receiver Transfer Disable + TXTEN = 0x1 << 8 # Transmitter Transfer Enable + TXTDIS = 0x1 << 9 # Transmitter Transfer Disable + +class PTSR(IntEnum): + RXTEN = 0x1 << 0 # Receiver Transfer Enable + TXTEN = 0x1 << 8 # Transmitter Transfer Enable diff --git a/qiling/hw/const/sam3xa_dac.py b/qiling/hw/const/sam3xa_dac.py new file mode 100644 index 000000000..c0fcf677a --- /dev/null +++ b/qiling/hw/const/sam3xa_dac.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +from enum import IntEnum + + +class CR(IntEnum): + SWRST = 0x1 << 0 # Software Reset + +class MR(IntEnum): + TRGEN = 0x1 << 0 # Trigger Enable + TRGSEL = 0x7 << 1 # Trigger Selection + WORD = 0x1 << 4 # Word Transfer + SLEEP = 0x1 << 5 # Sleep Mode + FASTWKUP = 0x1 << 6 # Fast Wake up Mode + REFRESH = 0xff << 8 # Refresh Period + USER_SEL = 0x3 << 16 # User Channel Selection + TAG = 0x1 << 20 # Tag Selection Mode + MAXS = 0x1 << 21 # Max Speed Mode + STARTUP = 0x3f << 24 # Startup Time Selection + +class CHER(IntEnum): + CH0 = 0x1 << 0 # Channel 0 Enable + CH1 = 0x1 << 1 # Channel 1 Enable + +class CHDR(IntEnum): + CH0 = 0x1 << 0 # Channel 0 Disable + CH1 = 0x1 << 1 # Channel 1 Disable + +class CHSR(IntEnum): + CH0 = 0x1 << 0 # Channel 0 Status + CH1 = 0x1 << 1 # Channel 1 Status + +class IER(IntEnum): + TXRDY = 0x1 << 0 # Transmit Ready Interrupt Enable + EOC = 0x1 << 1 # End of Conversion Interrupt Enable + ENDTX = 0x1 << 2 # End of Transmit Buffer Interrupt Enable + TXBUFE = 0x1 << 3 # Transmit Buffer Empty Interrupt Enable + +class IDR(IntEnum): + TXRDY = 0x1 << 0 # Transmit Ready Interrupt Disable. + EOC = 0x1 << 1 # End of Conversion Interrupt Disable + ENDTX = 0x1 << 2 # End of Transmit Buffer Interrupt Disable + TXBUFE = 0x1 << 3 # Transmit Buffer Empty Interrupt Disable + +class IMR(IntEnum): + TXRDY = 0x1 << 0 # Transmit Ready Interrupt Mask + EOC = 0x1 << 1 # End of Conversion Interrupt Mask + ENDTX = 0x1 << 2 # End of Transmit Buffer Interrupt Mask + TXBUFE = 0x1 << 3 # Transmit Buffer Empty Interrupt Mask + +class ISR(IntEnum): + TXRDY = 0x1 << 0 # Transmit Ready Interrupt Flag + EOC = 0x1 << 1 # End of Conversion Interrupt Flag + ENDTX = 0x1 << 2 # End of DMA Interrupt Flag + TXBUFE = 0x1 << 3 # Transmit Buffer Empty + +class ACR(IntEnum): + IBCTLCH0 = 0x3 << 0 # Analog Output Current Control + IBCTLCH1 = 0x3 << 2 # Analog Output Current Control + IBCTLDACCORE = 0x3 << 8 # Bias Current Control for DAC Core + +class WPMR(IntEnum): + WPEN = 0x1 << 0 # Write Protect Enable + WPKEY = 0xffffff << 8 # Write Protect KEY + +class WPSR(IntEnum): + WPROTERR = 0x1 << 0 # Write protection error + WPROTADDR = 0xff << 8 # Write protection error address + +class TPR(IntEnum): + TXPTR = 0xffffffff << 0 # Transmit Counter Register + +class TCR(IntEnum): + TXCTR = 0xffff << 0 # Transmit Counter Register + +class TNPR(IntEnum): + TXNPTR = 0xffffffff << 0 # Transmit Next Pointer + +class TNCR(IntEnum): + TXNCTR = 0xffff << 0 # Transmit Counter Next + +class PTCR(IntEnum): + RXTEN = 0x1 << 0 # Receiver Transfer Enable + RXTDIS = 0x1 << 1 # Receiver Transfer Disable + TXTEN = 0x1 << 8 # Transmitter Transfer Enable + TXTDIS = 0x1 << 9 # Transmitter Transfer Disable + +class PTSR(IntEnum): + RXTEN = 0x1 << 0 # Receiver Transfer Enable + TXTEN = 0x1 << 8 # Transmitter Transfer Enable diff --git a/qiling/hw/const/sam3xa_spi.py b/qiling/hw/const/sam3xa_spi.py new file mode 100644 index 000000000..5349a51b0 --- /dev/null +++ b/qiling/hw/const/sam3xa_spi.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +from enum import IntEnum + + +class CR(IntEnum): + SPIEN = 0x1 << 0 # SPI Enable + SPIDIS = 0x1 << 1 # SPI Disable + SWRST = 0x1 << 7 # SPI Software Reset + LASTXFER = 0x1 << 24 # Last Transfer + +class MR(IntEnum): + MSTR = 0x1 << 0 # Master/Slave Mode + PS = 0x1 << 1 # Peripheral Select + PCSDEC = 0x1 << 2 # Chip Select Decode + MODFDIS = 0x1 << 4 # Mode Fault Detection + WDRBT = 0x1 << 5 # Wait Data Read Before Transfer + LLB = 0x1 << 7 # Local Loopback Enable + PCS = 0xf << 16 # Peripheral Chip Select + DLYBCS = 0xff << 24 # Delay Between Chip Selects + +class RDR(IntEnum): + RD = 0xffff << 0 # Receive Data + PCS = 0xf << 16 # Peripheral Chip Select + +class TDR(IntEnum): + TD = 0xffff << 0 # Transmit Data + PCS = 0xf << 16 # Peripheral Chip Select + LASTXFER = 0x1 << 24 # Last Transfer + +class SR(IntEnum): + RDRF = 0x1 << 0 # Receive Data Register Full + TDRE = 0x1 << 1 # Transmit Data Register Empty + MODF = 0x1 << 2 # Mode Fault Error + OVRES = 0x1 << 3 # Overrun Error Status + NSSR = 0x1 << 8 # NSS Rising + TXEMPTY = 0x1 << 9 # Transmission Registers Empty + UNDES = 0x1 << 10 # Underrun Error Status (Slave Mode Only) + SPIENS = 0x1 << 16 # SPI Enable Status + +class IER(IntEnum): + RDRF = 0x1 << 0 # Receive Data Register Full Interrupt Enable + TDRE = 0x1 << 1 # SPI Transmit Data Register Empty Interrupt Enable + MODF = 0x1 << 2 # Mode Fault Error Interrupt Enable + OVRES = 0x1 << 3 # Overrun Error Interrupt Enable + NSSR = 0x1 << 8 # NSS Rising Interrupt Enable + TXEMPTY = 0x1 << 9 # Transmission Registers Empty Enable + UNDES = 0x1 << 10 # Underrun Error Interrupt Enable + +class IDR(IntEnum): + RDRF = 0x1 << 0 # Receive Data Register Full Interrupt Disable + TDRE = 0x1 << 1 # SPI Transmit Data Register Empty Interrupt Disable + MODF = 0x1 << 2 # Mode Fault Error Interrupt Disable + OVRES = 0x1 << 3 # Overrun Error Interrupt Disable + NSSR = 0x1 << 8 # NSS Rising Interrupt Disable + TXEMPTY = 0x1 << 9 # Transmission Registers Empty Disable + UNDES = 0x1 << 10 # Underrun Error Interrupt Disable + +class IMR(IntEnum): + RDRF = 0x1 << 0 # Receive Data Register Full Interrupt Mask + TDRE = 0x1 << 1 # SPI Transmit Data Register Empty Interrupt Mask + MODF = 0x1 << 2 # Mode Fault Error Interrupt Mask + OVRES = 0x1 << 3 # Overrun Error Interrupt Mask + NSSR = 0x1 << 8 # NSS Rising Interrupt Mask + TXEMPTY = 0x1 << 9 # Transmission Registers Empty Mask + UNDES = 0x1 << 10 # Underrun Error Interrupt Mask + +class CSR(IntEnum): + CPOL = 0x1 << 0 # Clock Polarity + NCPHA = 0x1 << 1 # Clock Phase + CSNAAT = 0x1 << 2 # Chip Select Not Active After Transfer (Ignored if CSAAT = 1) + CSAAT = 0x1 << 3 # Chip Select Not Active After Transfer (Ignored if CSAAT = 1) + BITS = 0xf << 4 # Bits Per Transfer + SCBR = 0xff << 8 # Serial Clock Baud Rate + DLYBS = 0xff << 16 # Delay Before SPCK + DLYBCT = 0xff << 24 # Delay Between Consecutive Transfers + +class WPMR(IntEnum): + WPEN = 0x1 << 0 # Write Protection Enable + WPKEY = 0xffffff << 8 # Write Protection Key Password + +class WPSR(IntEnum): + WPVS = 0x1 << 0 # Write Protection Violation Status + WPVSRC = 0xff << 8 # Write Protection Violation Source diff --git a/qiling/hw/const/stm32f1xx_adc.py b/qiling/hw/const/stm32f1xx_adc.py new file mode 100644 index 000000000..94bee377f --- /dev/null +++ b/qiling/hw/const/stm32f1xx_adc.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +from enum import IntEnum + + +class ADC_SR(IntEnum): + AWD = 1 << 0 + EOS = 1 << 1 + JEOS = 1 << 2 + JSTRT = 1 << 3 + STRT = 1 << 4 + +class ADC_CR1(IntEnum): + AWDCH = 0x1f << 0 + EOSIE = 1 << 5 + AWDIE = 1 << 6 + JEOSIE = 1 << 7 + SCAN = 1 << 8 + AWDSGL = 1 << 9 + JAUTO = 1 << 10 + DISCEN = 1 << 11 + JDISCEN = 1 << 12 + DISCNUM = 0x7 << 13 + DALMOD = 0xf << 16 + JAWDEN = 1 << 22 + AWDEN = 1 << 23 + +class ADC_CR2(IntEnum): + ADON = 1 << 0 + CONT = 1 << 1 + CAL = 1 << 2 + RSTCAL = 1 << 3 + DMA = 1 << 8 + ALIGN = 1 << 11 + JEXTSEL = 0x7 << 12 + JEXTTRIG = 1 << 15 + EXTSEL = 0x7 << 17 + EXTTRIG = 1 << 20 + JSWSTART = 1 << 21 + SWSTART = 1 << 22 + TSVREFE = 1 << 23 + +class ADC_SMPR1(IntEnum): + SMP10 = 0x7 << 0 + SMP11 = 0x7 << 3 + SMP12 = 0x7 << 6 + SMP13 = 0x7 << 9 + SMP14 = 0x7 << 12 + SMP15 = 0x7 << 15 + SMP16 = 0x7 << 18 + SMP17 = 0x7 << 21 + +class ADC_SMPR2(IntEnum): + SMP0 = 0x7 << 0 + SMP1 = 0x7 << 3 + SMP2 = 0x7 << 6 + SMP3 = 0x7 << 9 + SMP4 = 0x7 << 12 + SMP5 = 0x7 << 15 + SMP6 = 0x7 << 18 + SMP7 = 0x7 << 21 + SMP8 = 0x7 << 24 + SMP9 = 0x7 << 27 + +class ADC_SQR1(IntEnum): + SQ13 = 0x1f << 0 + SQ14 = 0x1f << 5 + SQ15 = 0x1f << 10 + SQ16 = 0x1f << 15 + L = 0xf << 20 + +class ADC_SQR2(IntEnum): + SQ7 = 0x1f << 0 + SQ8 = 0x1f << 5 + SQ9 = 0x1f << 10 + SQ10 = 0x1f << 15 + SQ11 = 0x1f << 20 + SQ12 = 0x1f << 25 + +class ADC_SQR3(IntEnum): + SQ1 = 0x1f << 0 + SQ2 = 0x1f << 5 + SQ3 = 0x1f << 10 + SQ4 = 0x1f << 15 + SQ5 = 0x1f << 20 + SQ6 = 0x1f << 25 + +class ADC_JSQR(IntEnum): + JSQ1 = 0x1f << 0 + JSQ2 = 0x1f << 5 + JSQ3 = 0x1f << 10 + JSQ4 = 0x1f << 15 + JL = 0x3 << 20 + +class ADC_DR(IntEnum): + DATA = 0xffff << 0 + ADC2DATA = 0xffff << 16 diff --git a/qiling/hw/const/stm32f4xx_eth.py b/qiling/hw/const/stm32f4xx_eth.py new file mode 100644 index 000000000..bbafc2945 --- /dev/null +++ b/qiling/hw/const/stm32f4xx_eth.py @@ -0,0 +1,272 @@ +from enum import IntEnum + + +class ETH_MACCR(IntEnum): + WD = 1 << 23 + JD = 1 << 22 + IFG = 0x7 << 17 + CSD = 1 << 16 + FES = 1 << 14 + ROD = 1 << 13 + LM = 1 << 12 + DM = 1 << 11 + IPCO = 1 << 10 + RD = 1 << 9 + APCS = 1 << 7 + BL = 0x3 << 5 + DC = 1 << 4 + TE = 1 << 3 + RE = 1 << 2 + +class ETH_MACFFR(IntEnum): + RA = 1 << 31 + HPF = 1 << 10 + SAF = 1 << 9 + SAIF = 1 << 8 + PCF = 0x3 << 6 + PCF_BlockAll = 1 << 6 + PCF_ForwardAll = 1 << 7 + PCF_ForwardPassedAddrFilter = 0x3 << 6 + BFD = 1 << 5 + PAM = 1 << 4 + DAIF = 1 << 3 + HM = 1 << 2 + HU = 1 << 1 + PM = 1 << 0 + +class ETH_MACMIIAR(IntEnum): + PA = 0x1f << 11 + MR = 0x1f << 6 + CR = 0x7 << 2 + CR_Div62 = 1 << 2 + CR_Div16 = 1 << 3 + CR_Div26 = 0x3 << 2 + CR_Div102 = 1 << 4 + MW = 1 << 1 + MB = 1 << 0 + +class ETH_MACFCR(IntEnum): + PT = 0xffff << 16 + ZQPD = 1 << 7 + PLT = 0x3 << 4 + PLT_Minus28 = 1 << 4 + PLT_Minus144 = 1 << 5 + PLT_Minus256 = 0x3 << 4 + UPFD = 1 << 3 + RFCE = 1 << 2 + TFCE = 1 << 1 + FCBBPA = 1 << 0 + +class ETH_MACVLANTR(IntEnum): + VLANTC = 1 << 16 + VLANTI = 0xffff << 0 + +class ETH_MACPMTCSR(IntEnum): + WFFRPR = 1 << 31 + GU = 1 << 9 + WFR = 1 << 6 + MPR = 1 << 5 + WFE = 1 << 2 + MPE = 1 << 1 + PD = 1 << 0 + +class ETH_MACDBGR(IntEnum): + TFF = 1 << 25 + TFNE = 1 << 24 + TFWA = 1 << 22 + TFRS = 0x3 << 20 + TFRS_WRITING = 0x3 << 20 + TFRS_WAITING = 1 << 21 + TFRS_READ = 1 << 20 + MTP = 1 << 19 + MTFCS = 0x3 << 17 + MTFCS_TRANSFERRING = 0x3 << 17 + MTFCS_GENERATINGPCF = 1 << 18 + MTFCS_WAITING = 1 << 17 + MMTEA = 1 << 16 + RFFL = 0x3 << 8 + RFFL_FL = 0x3 << 8 + RFFL_ABOVEFCT = 1 << 9 + RFFL_BELOWFCT = 1 << 8 + RFRCS = 0x3 << 5 + RFRCS_FLUSHING = 0x3 << 5 + RFRCS_STATUSREADING = 1 << 6 + RFRCS_DATAREADING = 1 << 5 + RFWRA = 1 << 4 + MSFRWCS = 0x3 << 1 + MMRPEA = 1 << 0 + +class ETH_MACSR(IntEnum): + TSTS = 1 << 9 + MMCTS = 1 << 6 + MMMCRS = 1 << 5 + MMCS = 1 << 4 + PMTS = 1 << 3 + +class ETH_MACIMR(IntEnum): + TSTIM = 1 << 9 + PMTIM = 1 << 3 + +class ETH_MACA1HR(IntEnum): + AE = 1 << 31 + SA = 1 << 30 + MBC = 0x3f << 24 + MACA1H = 0xffff << 0 + +class ETH_MACA2HR(IntEnum): + AE = 1 << 31 + SA = 1 << 30 + MBC = 0x3f << 24 + MACA2H = 0xffff << 0 + +class ETH_MACA3HR(IntEnum): + AE = 1 << 31 + SA = 1 << 30 + MBC = 0x3f << 24 + MACA3H = 0xffff << 0 + +class ETH_MMCCR(IntEnum): + MCFHP = 1 << 5 + MCP = 1 << 4 + MCF = 1 << 3 + ROR = 1 << 2 + CSR = 1 << 1 + CR = 1 << 0 + +class ETH_MMCRIR(IntEnum): + RGUFS = 1 << 17 + RFAES = 1 << 6 + RFCES = 1 << 5 + +class ETH_MMCTIR(IntEnum): + TGFS = 1 << 21 + TGFMSCS = 1 << 15 + TGFSCS = 1 << 14 + +class ETH_MMCRIMR(IntEnum): + RGUFM = 1 << 17 + RFAEM = 1 << 6 + RFCEM = 1 << 5 + +class ETH_MMCTIMR(IntEnum): + TGFM = 1 << 21 + TGFMSCM = 1 << 15 + TGFSCM = 1 << 14 + +class ETH_PTPTSCR(IntEnum): + TSCNT = 0x3 << 16 + TSARU = 1 << 5 + TSITE = 1 << 4 + TSSTU = 1 << 3 + TSSTI = 1 << 2 + TSFCU = 1 << 1 + TSE = 1 << 0 + +class ETH_PTPTSSR(IntEnum): + TSSMRME = 1 << 15 + TSSEME = 1 << 14 + TSSIPV4FE = 1 << 13 + TSSIPV6FE = 1 << 12 + TSSPTPOEFE = 1 << 11 + TSPTPPSV2E = 1 << 10 + TSSSR = 1 << 9 + TSSARFE = 1 << 8 + TSTTR = 1 << 5 + TSSO = 1 << 4 + +class ETH_PTPSSIR(IntEnum): + STSSI = 0xff << 0 + +class ETH_PTPTSLR(IntEnum): + STPNS = 1 << 31 + STSS = 0x7fffffff << 0 + +class ETH_PTPTSLUR(IntEnum): + TSUPNS = 1 << 31 + TSUSS = 0x7fffffff << 0 + +class ETH_DMABMR(IntEnum): + AAB = 1 << 25 + FPM = 1 << 24 + USP = 1 << 23 + RDP = 0x3f << 17 + FB = 1 << 16 + RTPR = 0x3 << 14 + PBL = 0x3f << 8 + EDE = 1 << 7 + DSL = 0x1f << 2 + DA = 1 << 1 + SR = 1 << 0 + +class ETH_DMASR(IntEnum): + TSTS = 1 << 29 + PMTS = 1 << 28 + MMCS = 1 << 27 + EBS = 0x7 << 23 + EBS_DescAccess = 1 << 25 + EBS_ReadTransf = 1 << 24 + EBS_DataTransfTx = 1 << 23 + TPS = 0x7 << 20 + TPS_Fetching = 1 << 20 + TPS_Waiting = 1 << 21 + TPS_Reading = 0x3 << 20 + TPS_Suspended = 0x3 << 21 + TPS_Closing = 0x7 << 20 + RPS = 0x7 << 17 + RPS_Fetching = 1 << 17 + RPS_Waiting = 0x3 << 17 + RPS_Suspended = 1 << 19 + RPS_Closing = 0x5 << 17 + RPS_Queuing = 0x7 << 17 + NIS = 1 << 16 + AIS = 1 << 15 + ERS = 1 << 14 + FBES = 1 << 13 + ETS = 1 << 10 + RWTS = 1 << 9 + RPSS = 1 << 8 + RBUS = 1 << 7 + RS = 1 << 6 + TUS = 1 << 5 + ROS = 1 << 4 + TJTS = 1 << 3 + TBUS = 1 << 2 + TPSS = 1 << 1 + TS = 1 << 0 + +class ETH_DMAOMR(IntEnum): + DTCEFD = 1 << 26 + RSF = 1 << 25 + DFRF = 1 << 24 + TSF = 1 << 21 + FTF = 1 << 20 + TTC = 0x7 << 14 + ST = 1 << 13 + FEF = 1 << 7 + FGF = 1 << 6 + RTC = 0x3 << 3 + OSF = 1 << 2 + SR = 1 << 1 + +class ETH_DMAIER(IntEnum): + NISE = 1 << 16 + AISE = 1 << 15 + ERIE = 1 << 14 + FBEIE = 1 << 13 + ETIE = 1 << 10 + RWTIE = 1 << 9 + RPSIE = 1 << 8 + RBUIE = 1 << 7 + RIE = 1 << 6 + TUIE = 1 << 5 + ROIE = 1 << 4 + TJTIE = 1 << 3 + TBUIE = 1 << 2 + TPSIE = 1 << 1 + TIE = 1 << 0 + +class ETH_DMAMFBOCR(IntEnum): + OFOC = 1 << 28 + MFA = 0x7ff << 17 + OMFC = 1 << 16 + MFC = 0xffff << 0 diff --git a/qiling/hw/const/stm32f4xx_pwr.py b/qiling/hw/const/stm32f4xx_pwr.py new file mode 100644 index 000000000..7e9fe07fb --- /dev/null +++ b/qiling/hw/const/stm32f4xx_pwr.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +from enum import IntEnum + + +class PWR_CR(IntEnum): + LPDS = 1 << 0 + PDDS = 1 << 1 + CWUF = 1 << 2 + CSBF = 1 << 3 + PVDE = 1 << 4 + PLS = 0x7 << 5 + DBP = 1 << 8 + FPDS = 1 << 9 + LPLVDS = 1 << 10 + MRLVDS = 1 << 11 + ADCDC1 = 1 << 13 + VOS = 0x3 << 14 + ODEN = 1 << 16 + ODSWEN = 1 << 17 + UDEN = 0x3 << 18 + +class PWR_CSR(IntEnum): + WUF = 1 << 0 + SBF = 1 << 1 + PVDO = 1 << 2 + BRR = 1 << 3 + EWUP = 1 << 8 + BRE = 1 << 9 + VOSRDY = 1 << 14 + ODRDY = 1 << 16 + ODSWRDY = 1 << 17 + UDRDY = 0x3 << 18 diff --git a/qiling/hw/const/stm32f4xx_sdio.py b/qiling/hw/const/stm32f4xx_sdio.py new file mode 100644 index 000000000..e48821845 --- /dev/null +++ b/qiling/hw/const/stm32f4xx_sdio.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +from enum import IntEnum + + +class SDIO_CLKCR(IntEnum): + CLKDIV = 0xff << 0 + CLKEN = 1 << 8 + PWRSAV = 1 << 9 + BYPASS = 1 << 10 + WIDBUS = 0x3 << 11 + NEGEDGE = 1 << 13 + HWFC_EN = 1 << 14 + +class SDIO_CMD(IntEnum): + CMDINDEX = 0x3f << 0 + WAITRESP = 0x3 << 6 + WAITINT = 1 << 8 + WAITPEND = 1 << 9 + CPSMEN = 1 << 10 + SDIOSUSPEND = 1 << 11 + ENCMDCOMPL = 1 << 12 + NIEN = 1 << 13 + CEATACMD = 1 << 14 + +class SDIO_DCTRL(IntEnum): + DTEN = 1 << 0 + DTDIR = 1 << 1 + DTMODE = 1 << 2 + DMAEN = 1 << 3 + DBLOCKSIZE = 0xf << 4 + RWSTART = 1 << 8 + RWSTOP = 1 << 9 + RWMOD = 1 << 10 + SDIOEN = 1 << 11 + +class SDIO_STA(IntEnum): + CCRCFAIL = 1 << 0 + DCRCFAIL = 1 << 1 + CTIMEOUT = 1 << 2 + DTIMEOUT = 1 << 3 + TXUNDERR = 1 << 4 + RXOVERR = 1 << 5 + CMDREND = 1 << 6 + CMDSENT = 1 << 7 + DATAEND = 1 << 8 + STBITERR = 1 << 9 + DBCKEND = 1 << 10 + CMDACT = 1 << 11 + TXACT = 1 << 12 + RXACT = 1 << 13 + TXFIFOHE = 1 << 14 + RXFIFOHF = 1 << 15 + TXFIFOF = 1 << 16 + RXFIFOF = 1 << 17 + TXFIFOE = 1 << 18 + RXFIFOE = 1 << 19 + TXDAVL = 1 << 20 + RXDAVL = 1 << 21 + SDIOIT = 1 << 22 + CEATAEND = 1 << 23 + +class SDIO_ICR(IntEnum): + CCRCFAILC = 1 << 0 + DCRCFAILC = 1 << 1 + CTIMEOUTC = 1 << 2 + DTIMEOUTC = 1 << 3 + TXUNDERRC = 1 << 4 + RXOVERRC = 1 << 5 + CMDRENDC = 1 << 6 + CMDSENTC = 1 << 7 + DATAENDC = 1 << 8 + STBITERRC = 1 << 9 + DBCKENDC = 1 << 10 + SDIOITC = 1 << 22 + CEATAENDC = 1 << 23 + +class SDIO_MASK(IntEnum): + CCRCFAILIE = 1 << 0 + DCRCFAILIE = 1 << 1 + CTIMEOUTIE = 1 << 2 + DTIMEOUTIE = 1 << 3 + TXUNDERRIE = 1 << 4 + RXOVERRIE = 1 << 5 + CMDRENDIE = 1 << 6 + CMDSENTIE = 1 << 7 + DATAENDIE = 1 << 8 + STBITERRIE = 1 << 9 + DBCKENDIE = 1 << 10 + CMDACTIE = 1 << 11 + TXACTIE = 1 << 12 + RXACTIE = 1 << 13 + TXFIFOHEIE = 1 << 14 + RXFIFOHFIE = 1 << 15 + TXFIFOFIE = 1 << 16 + RXFIFOFIE = 1 << 17 + TXFIFOEIE = 1 << 18 + RXFIFOEIE = 1 << 19 + TXDAVLIE = 1 << 20 + RXDAVLIE = 1 << 21 + SDIOITIE = 1 << 22 + CEATAENDIE = 1 << 23 diff --git a/qiling/hw/dma/gd32vf1xx_dma.py b/qiling/hw/dma/gd32vf1xx_dma.py index 065724217..2be44eaf6 100644 --- a/qiling/hw/dma/gd32vf1xx_dma.py +++ b/qiling/hw/dma/gd32vf1xx_dma.py @@ -50,7 +50,7 @@ class Type(ctypes.Structure): def __init__(self, ql, label): super().__init__(ql, label) - self.dma = self.struct( + self.instance = self.struct( INTF = 0x00000000, INTC = 0x00000000, CH0CTL = 0x00000000, diff --git a/qiling/hw/dma/sam3xa_pdc.py b/qiling/hw/dma/sam3xa_pdc.py index d68079a5c..1545cd386 100644 --- a/qiling/hw/dma/sam3xa_pdc.py +++ b/qiling/hw/dma/sam3xa_pdc.py @@ -26,4 +26,4 @@ class Type(ctypes.Structure): def __init__(self, ql, label): super().__init__(ql, label) - self.pdc = self.struct() + self.instance = self.struct() diff --git a/qiling/hw/dma/stm32f1xx_dma.py b/qiling/hw/dma/stm32f1xx_dma.py index 49e2a02e2..7b20ec3fc 100644 --- a/qiling/hw/dma/stm32f1xx_dma.py +++ b/qiling/hw/dma/stm32f1xx_dma.py @@ -102,7 +102,7 @@ def __init__(self, ql, label, ): super().__init__(ql, label) - self.dma = self.struct() + self.instance = self.struct() self.intn = [ stream0_intn, @@ -115,33 +115,10 @@ def __init__(self, ql, label, stream7_intn, ] - def find_field(self, offset: int, size: int) -> str: - field_list = [] - if offset < self.struct.stream.offset: - field_list.append(super().find_field(offset, min(size, self.struct.stream.offset - offset))) - - if offset >= self.struct.stream.offset: - for i in range(8): - prefix_offset = self.struct.stream.offset + ctypes.sizeof(Stream) * i - - for name, _ in Stream._fields_: - field = getattr(Stream, name) - field_offset = field.offset + prefix_offset - - lbound = max(0, offset - field_offset) - ubound = min(offset + size - field_offset, field.size) - if lbound < ubound: - if lbound == 0 and ubound == field.size: - field_list.append(f'stream[{i}].{name}') - else: - field_list.append(f'stream[{i}].{name}[{lbound}:{ubound}]') - - return ','.join(field_list) - @QlPeripheral.monitor(width=15) def read(self, offset: int, size: int) -> int: buf = ctypes.create_string_buffer(size) - ctypes.memmove(buf, ctypes.addressof(self.dma) + offset, size) + ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) return int.from_bytes(buf.raw, byteorder='little') @QlPeripheral.monitor(width=15) @@ -150,21 +127,21 @@ def write(self, offset: int, size: int, value: int): return elif offset == self.struct.IFCR.offset: - self.dma.ISR &= ~value + self.instance.ISR &= ~value else: data = (value).to_bytes(size, byteorder='little') - ctypes.memmove(ctypes.addressof(self.dma) + offset, data, size) + ctypes.memmove(ctypes.addressof(self.instance) + offset, data, size) def transfer_complete(self, id): tc_bits = [1, 5, 9, 13, 17, 21, 25] - self.dma.ISR |= 1 << tc_bits[id] + self.instance.ISR |= 1 << tc_bits[id] if self.intn[id] is not None: self.ql.hw.nvic.set_pending(self.intn[id]) def step(self): - for id, stream in enumerate(self.dma.stream): + for id, stream in enumerate(self.instance.stream): if not stream.enable(): continue diff --git a/qiling/hw/dma/stm32f4xx_dma.py b/qiling/hw/dma/stm32f4xx_dma.py index 93a95c16b..32443ee71 100644 --- a/qiling/hw/dma/stm32f4xx_dma.py +++ b/qiling/hw/dma/stm32f4xx_dma.py @@ -116,7 +116,7 @@ def __init__( super().__init__(ql, label) - self.dma = self.struct() + self.instance = self.struct() self.intn = [ stream0_intn, @@ -132,57 +132,33 @@ def __init__( @QlPeripheral.monitor(width=15) def read(self, offset: int, size: int) -> int: buf = ctypes.create_string_buffer(size) - ctypes.memmove(buf, ctypes.addressof(self.dma) + offset, size) + ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) return int.from_bytes(buf.raw, byteorder='little') @QlPeripheral.monitor(width=15) def write(self, offset: int, size: int, value: int): if offset == self.struct.LIFCR.offset: - self.dma.LISR &= ~value + self.instance.LISR &= ~value elif offset == self.struct.HIFCR.offset: - self.dma.HISR &= ~value + self.instance.HISR &= ~value elif offset > self.struct.HIFCR.offset: data = (value).to_bytes(size, byteorder='little') - ctypes.memmove(ctypes.addressof(self.dma) + offset, data, size) - - def find_field(self, offset: int, size: int) -> str: - field_list = [] - if offset < self.struct.stream.offset: - field_list.append(super().find_field(offset, min(size, self.struct.stream.offset - offset))) - - if offset >= self.struct.stream.offset: - for i in range(8): - prefix_offset = self.struct.stream.offset + ctypes.sizeof(Stream) * i - - for name, _ in Stream._fields_: - field = getattr(Stream, name) - field_offset = field.offset + prefix_offset - - lbound = max(0, offset - field_offset) - ubound = min(offset + size - field_offset, field.size) - if lbound < ubound: - if lbound == 0 and ubound == field.size: - field_list.append(f'stream[{i}].{name}') - else: - field_list.append(f'stream[{i}].{name}[{lbound}:{ubound}]') - - return ','.join(field_list) - + ctypes.memmove(ctypes.addressof(self.instance) + offset, data, size) def transfer_complete(self, id): tc_bits = [5, 11, 21, 27] if id > 4: - self.dma.HISR |= 1 << tc_bits[id - 4] + self.instance.HISR |= 1 << tc_bits[id - 4] else: - self.dma.LISR |= 1 << tc_bits[id] + self.instance.LISR |= 1 << tc_bits[id] if self.intn[id] is not None: self.ql.hw.nvic.set_pending(self.intn[id]) def step(self): - for id, stream in enumerate(self.dma.stream): + for id, stream in enumerate(self.instance.stream): if not stream.enable(): continue diff --git a/qiling/hw/flash/sam3xa_efc.py b/qiling/hw/flash/sam3xa_efc.py index 0a6c6c07d..c4e0a5f4a 100644 --- a/qiling/hw/flash/sam3xa_efc.py +++ b/qiling/hw/flash/sam3xa_efc.py @@ -20,5 +20,5 @@ class Type(ctypes.Structure): def __init__(self, ql, label, intn = None): super().__init__(ql, label) - self.efc = self.struct() + self.instance = self.struct() self.intn = intn diff --git a/qiling/hw/flash/stm32f1xx_flash.py b/qiling/hw/flash/stm32f1xx_flash.py index 46afeed2d..fd69cfdb7 100644 --- a/qiling/hw/flash/stm32f1xx_flash.py +++ b/qiling/hw/flash/stm32f1xx_flash.py @@ -40,16 +40,16 @@ def __init__(self, ql: Qiling, label: str, intn: int = None): super().__init__(ql, label) self.intn = intn - self.flash = self.struct() + self.instance = self.struct() @QlPeripheral.monitor() def read(self, offset: int, size: int) -> int: buf = ctypes.create_string_buffer(size) - ctypes.memmove(buf, ctypes.addressof(self.flash) + offset, size) + ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) return int.from_bytes(buf.raw, byteorder='little') @QlPeripheral.monitor() def write(self, offset: int, size: int, value: int): data = (value).to_bytes(size, 'little') - ctypes.memmove(ctypes.addressof(self.flash) + offset, data, size) + ctypes.memmove(ctypes.addressof(self.instance) + offset, data, size) diff --git a/qiling/hw/flash/stm32f4xx_flash.py b/qiling/hw/flash/stm32f4xx_flash.py index 4d5749604..389dd1322 100644 --- a/qiling/hw/flash/stm32f4xx_flash.py +++ b/qiling/hw/flash/stm32f4xx_flash.py @@ -52,15 +52,15 @@ def __init__(self, ql: Qiling, label: str, intn: int = None): super().__init__(ql, label) self.intn = intn - self.flash = self.struct() + self.instance = self.struct() @QlPeripheral.monitor() def read(self, offset: int, size: int) -> int: buf = ctypes.create_string_buffer(size) - ctypes.memmove(buf, ctypes.addressof(self.flash) + offset, size) + ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) return int.from_bytes(buf.raw, byteorder='little') @QlPeripheral.monitor() def write(self, offset: int, size: int, value: int): data = (value).to_bytes(size, 'little') - ctypes.memmove(ctypes.addressof(self.flash) + offset, data, size) + ctypes.memmove(ctypes.addressof(self.instance) + offset, data, size) diff --git a/qiling/hw/gpio/__init__.py b/qiling/hw/gpio/__init__.py index ecc8c804a..0ec63b03b 100644 --- a/qiling/hw/gpio/__init__.py +++ b/qiling/hw/gpio/__init__.py @@ -8,3 +8,5 @@ from .stm32f4xx_gpio import STM32F4xxGpio from .gd32vf1xx_gpio import GD32VF1xxGpio from .sam3xa_pio import SAM3xaPio +from .mk64f12_gpio import MK64F12Gpio +from .mk64f12_port import MK64F12Port diff --git a/qiling/hw/gpio/gd32vf1xx_gpio.py b/qiling/hw/gpio/gd32vf1xx_gpio.py index 45057f5ba..40be4c669 100644 --- a/qiling/hw/gpio/gd32vf1xx_gpio.py +++ b/qiling/hw/gpio/gd32vf1xx_gpio.py @@ -28,7 +28,7 @@ def __init__(self, ql, label): QlPeripheral.__init__(self, ql, label) GpioHooks.__init__(self, ql, 16) - self.gpio = self.struct( + self.instance = self.struct( CTL0 = 0x44444444, CTL1 = 0x44444444, ISTAT = 0x00000000, @@ -41,7 +41,7 @@ def __init__(self, ql, label): @QlPeripheral.monitor() def read(self, offset: int, size: int) -> int: buf = ctypes.create_string_buffer(size) - ctypes.memmove(buf, ctypes.addressof(self.gpio) + offset, size) + ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) return int.from_bytes(buf.raw, byteorder='little') @QlPeripheral.monitor() @@ -49,7 +49,7 @@ def write(self, offset: int, size: int, value: int): if offset == self.struct.OCTL.offset: for i in range(16): new_bit = (value >> i) & 1 - old_bit = (self.gpio.OCTL >> i) & 1 + old_bit = (self.instance.OCTL >> i) & 1 if new_bit != old_bit: if new_bit: @@ -71,19 +71,19 @@ def write(self, offset: int, size: int, value: int): return data = (value).to_bytes(size, 'little') - ctypes.memmove(ctypes.addressof(self.gpio) + offset, data, size) + ctypes.memmove(ctypes.addressof(self.instance) + offset, data, size) def set_pin(self, i): self.ql.log.debug(f'[{self.label}] Set P{self.label[-1].upper()}{i}') - self.gpio.OCTL |= 1 << i + self.instance.OCTL |= 1 << i self.call_hook_set(i) def reset_pin(self, i): self.ql.log.debug(f'[{self.label}] Reset P{self.label[-1].upper()}{i}') - self.gpio.OCTL &= ~(1 << i) + self.instance.OCTL &= ~(1 << i) self.call_hook_reset(i) def pin(self, index): - return (self.gpio.OCTL >> index) & 1 \ No newline at end of file + return (self.instance.OCTL >> index) & 1 \ No newline at end of file diff --git a/qiling/hw/gpio/mk64f12_gpio.py b/qiling/hw/gpio/mk64f12_gpio.py new file mode 100644 index 000000000..62111a2f9 --- /dev/null +++ b/qiling/hw/gpio/mk64f12_gpio.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import ctypes + +from qiling.hw.peripheral import QlPeripheral +from qiling.hw.gpio.hooks import GpioHooks + + +class MK64F12Gpio(QlPeripheral, GpioHooks): + class Type(ctypes.Structure): + """ General Purpose Input/Output """ + _fields_ = [ + ("PDOR", ctypes.c_uint32), # Port Data Output Register + ("PSOR", ctypes.c_uint32), # Port Set Output Register + ("PCOR", ctypes.c_uint32), # Port Clear Output Register + ("PTOR", ctypes.c_uint32), # Port Toggle Output Register + ("PDIR", ctypes.c_uint32), # Port Data Input Register + ("PDDR", ctypes.c_uint32), # Port Data Direction Register + ] + + def __init__(self, ql, label, intn=None): + QlPeripheral.__init__(self, ql, label) + GpioHooks.__init__(self, ql, 32) + + self.intn = intn + + @QlPeripheral.monitor() + def write(self, offset: int, size: int, value: int): + if offset == self.struct.PSOR.offset: + for i in range(32): + self.set_pin(i) + + elif offset == self.struct.PCOR.offset: + for i in range(32): + self.reset_pin(i) + + elif offset == self.struct.PTOR.offset: + for i in range(32): + if self.pin(i): + self.reset_pin(i) + else: + self.set_pin(i) + + else: + self.raw_write(offset, size, value) + + def set_pin(self, i): + self.ql.log.debug(f'[{self.label}] Set P{self.label[-1].upper()}{i}') + + self.port.send_interrupt(i, self.pin(i), 1) + + if self.instance.PDDR: + self.instance.PDOR |= 1 << i + else: + self.instance.PDIR |= 1 << i + self.call_hook_set(i) + + def reset_pin(self, i): + self.ql.log.debug(f'[{self.label}] Reset P{self.label[-1].upper()}{i}') + + self.port.send_interrupt(i, self.pin(i), 0) + + if self.instance.PDDR: + self.instance.PDOR &= ~(1 << i) + else: + self.instance.PDIR &= ~(1 << i) + self.call_hook_reset(i) + + def pin(self, index): + if self.instance.PDDR: + return (self.instance.PDOR >> index) & 1 + else: + return (self.instance.PDIR >> index) & 1 + + @property + def port(self): + return getattr(self.ql.hw, 'port' + self.label[-1]) diff --git a/qiling/hw/gpio/mk64f12_port.py b/qiling/hw/gpio/mk64f12_port.py new file mode 100644 index 000000000..e4b02cb25 --- /dev/null +++ b/qiling/hw/gpio/mk64f12_port.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import ctypes + +from qiling.hw.peripheral import QlPeripheral +from qiling.hw.const.mk64f12_port import PCR, InterruptMode + + +class MK64F12Port(QlPeripheral): + class Type(ctypes.Structure): + """ Pin Control and Interrupts """ + _fields_ = [ + ("PCR" , ctypes.c_uint32 * 32), # Pin Control Register n + ("GPCLR", ctypes.c_uint32), # Global Pin Control Low Register + ("GPCHR", ctypes.c_uint32), # Global Pin Control High Register + ("RESERVED0", ctypes.c_uint8 * 24), + ("ISFR" , ctypes.c_uint32), # Interrupt Status Flag Register + ("RESERVED1", ctypes.c_uint8 * 28), + ("DFER" , ctypes.c_uint32), # Digital Filter Enable Register + ("DFCR" , ctypes.c_uint32), # Digital Filter Clock Register + ("DFWR" , ctypes.c_uint32), # Digital Filter Width Register + ] + + def __init__(self, ql, label, intn=None): + super().__init__(ql, label) + + self.intn = intn + + def pin_interrupt_config(self, index): + return (self.instance.PCR[index] & PCR.IRQC) >> 16 + + def send_interrupt(self, index, prev, curr): + config = self.pin_interrupt_config(index) + if ( + (config == InterruptMode.InterruptLogicZero and curr == 0) or + (config == InterruptMode.InterruptLogicOne and curr == 1) or + (config == InterruptMode.InterruptRisingEdge and curr == 1 and prev == 0) or + (config == InterruptMode.InterruptFallingEdge and curr == 0 and prev == 1) or + (config == InterruptMode.InterruptEitherEdge and curr != prev) + ): + self.ql.hw.nvic.set_pending(self.intn) diff --git a/qiling/hw/gpio/sam3xa_pio.py b/qiling/hw/gpio/sam3xa_pio.py index 11fa572d4..fc9beafba 100644 --- a/qiling/hw/gpio/sam3xa_pio.py +++ b/qiling/hw/gpio/sam3xa_pio.py @@ -70,7 +70,45 @@ class Type(ctypes.Structure): def __init__(self, ql, label, intn = None): QlPeripheral.__init__(self, ql, label) - GpioHooks.__init__(self, ql, 16) + GpioHooks.__init__(self, ql, 32) - self.pio = self.struct() + self.instance = self.struct() self.intn = intn + + @QlPeripheral.monitor() + def read(self, offset: int, size: int) -> int: + buf = ctypes.create_string_buffer(size) + ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) + return int.from_bytes(buf.raw, byteorder='little') + + @QlPeripheral.monitor() + def write(self, offset: int, size: int, value: int): + if offset in [self.struct.PUER.offset, self.struct.SODR.offset]: + for i in range(32): + if (value >> i) & 1: + self.set_pin(i) + return + + if offset in [self.struct.PUDR.offset, self.struct.CODR.offset]: + for i in range(32): + if (value >> i) & 1: + self.reset_pin(i) + return + + data = (value).to_bytes(size, 'little') + ctypes.memmove(ctypes.addressof(self.instance) + offset, data, size) + + def set_pin(self, i): + self.ql.log.debug(f'[{self.label}] Set P{self.label[-1].upper()}{i}') + + self.instance.PDSR |= 1 << i + self.call_hook_set(i) + + def reset_pin(self, i): + self.ql.log.debug(f'[{self.label}] Reset P{self.label[-1].upper()}{i}') + + self.instance.PDSR &= ~(1 << i) + self.call_hook_reset(i) + + def pin(self, index): + return (self.instance.PDSR >> index) & 1 \ No newline at end of file diff --git a/qiling/hw/gpio/stm32f1xx_afio.py b/qiling/hw/gpio/stm32f1xx_afio.py index c0305833c..ac2ec27ad 100644 --- a/qiling/hw/gpio/stm32f1xx_afio.py +++ b/qiling/hw/gpio/stm32f1xx_afio.py @@ -35,23 +35,23 @@ class Type(ctypes.Structure): def __init__(self, ql, label): super().__init__(ql, label) - self.afio = self.struct() + self.instance = self.struct() @QlPeripheral.monitor() def read(self, offset: int, size: int) -> int: buf = ctypes.create_string_buffer(size) - ctypes.memmove(buf, ctypes.addressof(self.afio) + offset, size) + ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) return int.from_bytes(buf.raw, byteorder='little') @QlPeripheral.monitor() def write(self, offset: int, size: int, value: int): data = (value).to_bytes(size, 'little') - ctypes.memmove(ctypes.addressof(self.afio) + offset, data, size) + ctypes.memmove(ctypes.addressof(self.instance) + offset, data, size) def exti(self, index): """ Get EXTI{index} mapping information """ - port_index = self.afio.EXTICR[index // 4] >> ((index & 3) * 4) + port_index = self.instance.EXTICR[index // 4] >> ((index & 3) * 4) port_name = 'gpio' + 'abcdefg'[port_index] return getattr(self.ql.hw, port_name, None) diff --git a/qiling/hw/gpio/stm32f1xx_gpio.py b/qiling/hw/gpio/stm32f1xx_gpio.py index 5b30c6c87..25a9ee791 100644 --- a/qiling/hw/gpio/stm32f1xx_gpio.py +++ b/qiling/hw/gpio/stm32f1xx_gpio.py @@ -39,7 +39,7 @@ def __init__(self, ql, label): QlPeripheral.__init__(self, ql, label) GpioHooks.__init__(self, ql, 16) - self.gpio = self.struct() + self.instance = self.struct() @QlPeripheral.monitor() def read(self, offset: int, size: int) -> int: @@ -47,7 +47,7 @@ def read(self, offset: int, size: int) -> int: return 0x00 buf = ctypes.create_string_buffer(size) - ctypes.memmove(buf, ctypes.addressof(self.gpio) + offset, size) + ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) return int.from_bytes(buf.raw, byteorder='little') @QlPeripheral.monitor() @@ -69,7 +69,7 @@ def write(self, offset: int, size: int, value: int): if offset == self.struct.ODR.offset: for i in range(16): new_bit = (value >> i) & 1 - old_bit = (self.gpio.ODR >> i) & 1 + old_bit = (self.instance.ODR >> i) & 1 if new_bit != old_bit: if new_bit: @@ -80,19 +80,21 @@ def write(self, offset: int, size: int, value: int): return data = (value).to_bytes(size, 'little') - ctypes.memmove(ctypes.addressof(self.gpio) + offset, data, size) + ctypes.memmove(ctypes.addressof(self.instance) + offset, data, size) def set_pin(self, i): self.ql.log.debug(f'[{self.label}] Set P{self.label[-1].upper()}{i}') - self.gpio.ODR |= 1 << i + self.instance.ODR |= 1 << i + self.instance.IDR |= 1 << i self.call_hook_set(i) def reset_pin(self, i): self.ql.log.debug(f'[{self.label}] Reset P{self.label[-1].upper()}{i}') - self.gpio.ODR &= ~(1 << i) + self.instance.ODR &= ~(1 << i) + self.instance.IDR &= ~(1 << i) self.call_hook_reset(i) def pin(self, index): - return (self.gpio.ODR >> index) & 1 \ No newline at end of file + return (self.instance.ODR >> index) & 1 \ No newline at end of file diff --git a/qiling/hw/gpio/stm32f4xx_gpio.py b/qiling/hw/gpio/stm32f4xx_gpio.py index de00d1726..69d875265 100644 --- a/qiling/hw/gpio/stm32f4xx_gpio.py +++ b/qiling/hw/gpio/stm32f4xx_gpio.py @@ -59,7 +59,7 @@ def __init__(self, ql, label, QlPeripheral.__init__(self, ql, label) GpioHooks.__init__(self, ql, 16) - self.gpio = self.struct( + self.instance = self.struct( MODER = moder_reset, OSPEEDR = ospeedr_reset, PUPDR = pupdr_reset, diff --git a/qiling/hw/hw.py b/qiling/hw/hw.py index 701822b84..33081a052 100644 --- a/qiling/hw/hw.py +++ b/qiling/hw/hw.py @@ -16,29 +16,34 @@ def __init__(self, ql: Qiling): self.ql = ql self.entity = {} - self.region = {} + self.region = {} - def create(self, label: str, struct: "QlPeripheral"=None, base: int=None) -> "QlPeripheral": + self.stepable = {} + + def create(self, label: str, struct: str=None, base: int=None, kwargs: dict={}) -> "QlPeripheral": """ Create the peripheral accroding the label and envs. struct: Structure of the peripheral. Use defualt ql structure if not provide. base: Base address. Use defualt address if not provide. """ - env_struct, env_base, kwargs = self.load_env(label.upper()) - struct = env_struct if struct is None else struct - base = env_base if base is None else base + if struct is None: + struct, base, kwargs = self.load_env(label.upper()) try: - entity = ql_get_module_function('.hw', struct)(self.ql, label, **kwargs) - setattr(self, label, entity) + entity = ql_get_module_function('qiling.hw', struct)(self.ql, label, **kwargs) + self.entity[label] = entity + if hasattr(entity, 'step'): + self.stepable[label] = entity + self.region[label] = [(lbound + base, rbound + base) for (lbound, rbound) in entity.region] + return entity except QlErrorModuleFunctionNotFound: - self.ql.log.warning(f'The {struct}({label}) has not been implemented') + self.ql.log.debug(f'The {struct}({label}) has not been implemented') def delete(self, label: str): """ Remove the peripheral @@ -46,7 +51,8 @@ def delete(self, label: str): if label in self.entity: self.entity.pop(label) self.region.pop(label) - delattr(self, label) + if label in self.stepable: + self.stepable.pop(label) def load_env(self, label: str): """ Get peripheral information (structure, base address, initialization list) from env. @@ -58,54 +64,27 @@ def load_env(self, label: str): args = self.ql.env[label] return args['struct'], args['base'], args.get("kwargs", {}) - + + def load_all(self): + for label, args in self.ql.env.items(): + if args['type'] == 'peripheral': + self.create(label.lower(), args['struct'], args['base'], args.get("kwargs", {})) + def find(self, address: int): """ Find the peripheral at `address` """ for label in self.entity.keys(): for lbound, rbound in self.region[label]: - if lbound <= address <= rbound: + if lbound <= address < rbound: return self.entity[label] def step(self): """ Update all peripheral's state """ - for _, entity in self.entity.items(): + for entity in self.stepable.values(): entity.step() - def setup_bitband(self, base, alias, size, info=""): - """ reference: - https://github.com/qemu/qemu/blob/453d9c61dd5681159051c6e4d07e7b2633de2e70/hw/arm/armv7m.c - """ - - def bitband_addr(offset): - return base | (offset & 0x1ffffff) >> 5 - - def bitband_read_cb(ql, offset, size): - addr = bitband_addr(offset) & (-size) - buf = self.ql.mem.read(addr, size) - - bitpos = (offset >> 2) & ((size * 8) - 1) - bit = (buf[bitpos >> 3] >> (bitpos & 7)) & 1 - - return bit - - def bitband_write_cb(ql, offset, size, value): - addr = bitband_addr(offset) & (-size) - buf = self.ql.mem.read(addr, size) - - bitpos = (offset >> 2) & ((size * 8) - 1) - bit = 1 << (bitpos & 7) - if value & 1: - buf[bitpos >> 3] |= bit - else: - buf[bitpos >> 3] &= ~bit - - self.ql.mem.write(addr, bytes(buf)) - - self.ql.mem.map_mmio(alias, size, bitband_read_cb, bitband_write_cb, info=info) - def setup_mmio(self, begin, size, info=""): mmio = ctypes.create_string_buffer(size) @@ -116,7 +95,7 @@ def mmio_read_cb(ql, offset, size): if hardware: return hardware.read(address - hardware.base, size) else: - ql.log.warning('%s Read non-mapped hardware [0x%08x]' % (info, address)) + ql.log.debug('%s Read non-mapped hardware [0x%08x]' % (info, address)) buf = ctypes.create_string_buffer(size) ctypes.memmove(buf, ctypes.addressof(mmio) + offset, size) @@ -129,20 +108,11 @@ def mmio_write_cb(ql, offset, size, value): if hardware: hardware.write(address - hardware.base, size, value) else: - ql.log.warning('%s Write non-mapped hardware [0x%08x] = 0x%08x' % (info, address, value)) + ql.log.debug('%s Write non-mapped hardware [0x%08x] = 0x%08x' % (info, address, value)) ctypes.memmove(ctypes.addressof(mmio) + offset, (value).to_bytes(size, 'little'), size) self.ql.mem.map_mmio(begin, size, mmio_read_cb, mmio_write_cb, info=info) - def setup_remap(self, base, alias, size, info=""): - def remap_read_cb(ql, offset, size): - return int.from_bytes(ql.mem.read(alias + offset, size), 'little') - - def remap_write_cb(ql, offset, size, value): - ql.mem.write(alias + offset, (value).to_bytes(size, 'little')) - - self.ql.mem.map_mmio(base, size, remap_read_cb, remap_write_cb, info=info) - def show_info(self): self.ql.log.info(f'{"Start":8s} {"End":8s} {"Label":8s} {"Class"}') @@ -155,4 +125,14 @@ def __getitem__(self, key): return self.entity[key] def __setitem__(self, key, value): - self.entity[key] = value \ No newline at end of file + self.entity[key] = value + + def __getattr__(self, key): + return self.entity.get(key) + + def save(self): + return {label : entity.save() for label, entity in self.entity.items()} + + def restore(self, saved_state): + for label, data in saved_state.items(): + self.entity[label].restore(data) diff --git a/qiling/hw/i2c/__init__.py b/qiling/hw/i2c/__init__.py index 28c9da382..dc30ac45b 100644 --- a/qiling/hw/i2c/__init__.py +++ b/qiling/hw/i2c/__init__.py @@ -3,5 +3,6 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # +from .stm32f1xx_i2c import STM32F1xxI2c from .stm32f4xx_i2c import STM32F4xxI2c from .gd32vf1xx_i2c import GD32VF1xxI2c \ No newline at end of file diff --git a/qiling/hw/i2c/gd32vf1xx_i2c.py b/qiling/hw/i2c/gd32vf1xx_i2c.py index c7d4723ea..699d20308 100644 --- a/qiling/hw/i2c/gd32vf1xx_i2c.py +++ b/qiling/hw/i2c/gd32vf1xx_i2c.py @@ -29,7 +29,7 @@ class Type(ctypes.Structure): def __init__(self, ql, label): super().__init__(ql, label) - self.i2c = self.struct( + self.instance = self.struct( CTL0 = 0x00000000, CTL1 = 0x00000000, SADDR0 = 0x00000000, diff --git a/qiling/hw/i2c/stm32f1xx_i2c.py b/qiling/hw/i2c/stm32f1xx_i2c.py new file mode 100644 index 000000000..5d49ddd98 --- /dev/null +++ b/qiling/hw/i2c/stm32f1xx_i2c.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import ctypes + + +from qiling.hw.peripheral import QlPeripheral +from .stm32f4xx_i2c import STM32F4xxI2c + + +class STM32F1xxI2c(STM32F4xxI2c): + class Type(ctypes.Structure): + """ the structure available in : + stm32f100xb + stm32f100xe + stm32f101xb + stm32f101xe + stm32f101xg + stm32f102xb + stm32f103xb + stm32f103xe + stm32f103xg + stm32f105xc + stm32f107xc + """ + + _fields_ = [ + ("CR1" , ctypes.c_uint32), + ("CR2" , ctypes.c_uint32), + ("OAR1" , ctypes.c_uint32), + ("OAR2" , ctypes.c_uint32), + ("DR" , ctypes.c_uint32), + ("SR1" , ctypes.c_uint32), + ("SR2" , ctypes.c_uint32), + ("CCR" , ctypes.c_uint32), + ("TRISE", ctypes.c_uint32), + ] diff --git a/qiling/hw/i2c/stm32f4xx_i2c.py b/qiling/hw/i2c/stm32f4xx_i2c.py index efe4b0751..8d6dbe870 100644 --- a/qiling/hw/i2c/stm32f4xx_i2c.py +++ b/qiling/hw/i2c/stm32f4xx_i2c.py @@ -9,7 +9,7 @@ from qiling.hw.peripheral import QlPeripheral from qiling.hw.connectivity import QlConnectivityPeripheral from qiling.hw.const.stm32f4xx_i2c import I2C_CR1, I2C_CR2, I2C_SR1, I2C_SR2, I2C_DR, I2C_OAR1, I2C_OAR2 -from qiling.hw.utils.access import Access, AccessSequence, Op +from qiling.hw.utils.access import Access, AccessSequence, Action class STM32F4xxI2c(QlConnectivityPeripheral): @@ -60,7 +60,7 @@ def __init__(self, ql, label, ev_intn=None, er_intn=None): self.reset() def reset(self): - self.i2c = self.struct( + self.instance = self.struct( TRISE = 0x0002 ) @@ -68,13 +68,13 @@ def reset(self): @QlPeripheral.monitor() def read(self, offset: int, size: int) -> int: buf = ctypes.create_string_buffer(size) - ctypes.memmove(buf, ctypes.addressof(self.i2c) + offset, size) + ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) if self.history.match([ - Access(Op.READ, self.struct.SR1.offset), - Access(Op.READ, self.struct.SR2.offset) + Access(Action.READ, self.struct.SR1.offset), + Access(Action.READ, self.struct.SR2.offset) ]): - self.i2c.SR1 &= ~I2C_SR1.ADDR + self.instance.SR1 &= ~I2C_SR1.ADDR return int.from_bytes(buf.raw, byteorder='little') @@ -85,7 +85,7 @@ def write(self, offset: int, size: int, value: int): return if offset == self.struct.CR1.offset: - self.i2c.CR1 = value & I2C_CR1.RW_MASK + self.instance.CR1 = value & I2C_CR1.RW_MASK if value & I2C_CR1.START: self.generate_start() @@ -96,12 +96,12 @@ def write(self, offset: int, size: int, value: int): return if offset == self.struct.DR.offset: - self.i2c.DR = value & I2C_DR.DR - self.i2c.SR1 &= ~I2C_SR1.TXE + self.instance.DR = value & I2C_DR.DR + self.instance.SR1 &= ~I2C_SR1.TXE if self.is_master_mode(): if self.is_7bit_mode(): - if self.i2c.SR2 & I2C_SR2.TRA: + if self.instance.SR2 & I2C_SR2.TRA: self.send_data() else: @@ -112,7 +112,7 @@ def write(self, offset: int, size: int, value: int): return data = (value).to_bytes(size, 'little') - ctypes.memmove(ctypes.addressof(self.i2c) + offset, data, size) + ctypes.memmove(ctypes.addressof(self.instance) + offset, data, size) ## I2C Control register 2 (I2C_CR2) def send_event_interrupt(self): @@ -136,16 +136,16 @@ def send_event_interrupt(self): if self.ev_intn is None: return - if not self.i2c.CR2 & I2C_CR2.ITEVTEN: + if not self.instance.CR2 & I2C_CR2.ITEVTEN: return BUF_IT = I2C_SR1.TXE|I2C_SR1.RXNE SLAVE_IT = I2C_SR1.STOPF|I2C_SR1.ADDR|I2C_SR1.BTF MASTER_IT = I2C_SR1.SB|I2C_SR1.ADDR|I2C_SR1.ADD10|I2C_SR1.BTF - if (self.i2c.CR2 & I2C_CR2.ITBUFEN and self.i2c.SR1 & BUF_IT) or \ - (self.is_slave_mode() and self.i2c.SR1 & SLAVE_IT) or \ - (self.is_master_mode() and self.i2c.SR1 & MASTER_IT): + if (self.instance.CR2 & I2C_CR2.ITBUFEN and self.instance.SR1 & BUF_IT) or \ + (self.is_slave_mode() and self.instance.SR1 & SLAVE_IT) or \ + (self.is_master_mode() and self.instance.SR1 & MASTER_IT): self.ql.hw.nvic.set_pending(self.ev_intn) ## I2C Status register 1 (I2C_SR1) @@ -160,33 +160,33 @@ def generate_start(self): # TODO: generate a start condition self.fetch_device_address() - self.i2c.SR1 |= I2C_SR1.SB - self.i2c.CR1 &= ~I2C_CR1.START + self.instance.SR1 |= I2C_SR1.SB + self.instance.CR1 &= ~I2C_CR1.START self.set_master_mode() def generate_stop(self): # TODO: generate a stop condition - self.i2c.CR1 &= ~I2C_CR1.STOP + self.instance.CR1 &= ~I2C_CR1.STOP - self.i2c.SR1 |= I2C_SR1.STOPF - self.i2c.SR1 &= ~I2C_SR1.ADDR + self.instance.SR1 |= I2C_SR1.STOPF + self.instance.SR1 &= ~I2C_SR1.ADDR self.set_slave_mode() - self.i2c.SR2 &= ~I2C_SR2.TRA + self.instance.SR2 &= ~I2C_SR2.TRA def send_address(self): - if self.i2c.DR == self.i2c.OAR1 >> 1: + if self.instance.DR == self.instance.OAR1 >> 1: # TODO: send ACK - self.i2c.SR1 &= ~I2C_SR1.SB - self.i2c.SR1 |= I2C_SR1.ADDR | I2C_SR1.TXE - self.i2c.SR2 |= I2C_SR2.TRA + self.instance.SR1 &= ~I2C_SR1.SB + self.instance.SR1 |= I2C_SR1.ADDR | I2C_SR1.TXE | I2C_SR1.AF + self.instance.SR2 |= I2C_SR2.TRA def send_data(self): - self.i2c.SR1 |= I2C_SR1.BTF | I2C_SR1.TXE + self.instance.SR1 |= I2C_SR1.BTF | I2C_SR1.TXE - self.send_to_user(self.i2c.DR) + self.send_to_user(self.instance.DR) ## I2C Status register 2 (I2C_SR2) def is_master_mode(self): @@ -195,7 +195,7 @@ def is_master_mode(self): 0: Slave Mode 1: Master Mode """ - return self.i2c.SR2 & I2C_SR2.MSL + return self.instance.SR2 & I2C_SR2.MSL def is_slave_mode(self): return not self.is_master_mode() @@ -205,7 +205,7 @@ def set_master_mode(self): I2C Status register 2 (I2C_SR2) MSL bit - Set by hardware as soon as the interface is in Master mode (SB=1) """ - self.i2c.SR2 |= I2C_SR2.MSL + self.instance.SR2 |= I2C_SR2.MSL def set_slave_mode(self): """ @@ -213,25 +213,25 @@ def set_slave_mode(self): - Cleared by hardware after detecting a Stop condition on the bus or a loss of arbitration (ARLO=1), or by hardware when PE=0. """ - self.i2c.SR2 &= ~I2C_SR2.MSL + self.instance.SR2 &= ~I2C_SR2.MSL ## I2C Own address register 1 (I2C_OAR1) def is_7bit_mode(self): - return self.i2c.OAR2 & I2C_OAR2.ENDUAL or not self.i2c.OAR1 & I2C_OAR1.ADDMODE + return self.instance.OAR2 & I2C_OAR2.ENDUAL or not self.instance.OAR1 & I2C_OAR1.ADDMODE def fetch_device_address(self): # dual addressing mode - if self.i2c.OAR2 & I2C_OAR2.ENDUAL: - self.i2c.OAR1 = self.device_list[0].address << 1 - self.i2c.OAR2 = I2C_OAR2.ENDUAL | (self.device_list[1].address << 1) + if self.instance.OAR2 & I2C_OAR2.ENDUAL: + self.instance.OAR1 = self.device_list[0].address << 1 + self.instance.OAR2 = I2C_OAR2.ENDUAL | (self.device_list[1].address << 1) # single device, 10-bit slave address - elif self.i2c.OAR1 & I2C_OAR1.ADDMODE: - self.i2c.OAR1 = I2C_OAR1.ADDMODE | self.device_list[0].address + elif self.instance.OAR1 & I2C_OAR1.ADDMODE: + self.instance.OAR1 = I2C_OAR1.ADDMODE | self.device_list[0].address # single device, 7-bit slave address else: - self.i2c.OAR1 = self.device_list[0].address << 1 + self.instance.OAR1 = self.device_list[0].address << 1 @QlConnectivityPeripheral.device_handler def step(self): diff --git a/qiling/hw/intc/cm_nvic.py b/qiling/hw/intc/cm_nvic.py index f52b31f39..5470a4483 100644 --- a/qiling/hw/intc/cm_nvic.py +++ b/qiling/hw/intc/cm_nvic.py @@ -33,13 +33,13 @@ def __init__(self, ql, label): # https://www.youtube.com/watch?v=uFBNf7F3l60 # https://developer.arm.com/documentation/ddi0439/b/Nested-Vectored-Interrupt-Controller - self.nvic = self.struct() + self.instance = self.struct() ## The max number of interrupt request self.IRQN_MAX = self.struct.ISER.size * 8 ## The ISER unit size - self.MASK = self.IRQN_MAX // len(self.nvic.ISER) - 1 + self.MASK = self.IRQN_MAX // len(self.instance.ISER) - 1 self.OFFSET = self.MASK.bit_length() ## special write behavior @@ -51,32 +51,32 @@ def __init__(self, ql, label): ] self.intrs = [] - self.interrupt_handler = self.ql.arch.hard_interrupt_handler + self.interrupt_handler = self.ql.arch.interrupt_handler def enable(self, IRQn): if IRQn >= 0: - self.nvic.ISER[IRQn >> self.OFFSET] |= 1 << (IRQn & self.MASK) - self.nvic.ICER[IRQn >> self.OFFSET] |= 1 << (IRQn & self.MASK) + self.instance.ISER[IRQn >> self.OFFSET] |= 1 << (IRQn & self.MASK) + self.instance.ICER[IRQn >> self.OFFSET] |= 1 << (IRQn & self.MASK) else: self.ql.hw.scb.enable(IRQn) def disable(self, IRQn): if IRQn >= 0: - self.nvic.ISER[IRQn >> self.OFFSET] &= self.MASK ^ (1 << (IRQn & self.MASK)) - self.nvic.ICER[IRQn >> self.OFFSET] &= self.MASK ^ (1 << (IRQn & self.MASK)) + self.instance.ISER[IRQn >> self.OFFSET] &= self.MASK ^ (1 << (IRQn & self.MASK)) + self.instance.ICER[IRQn >> self.OFFSET] &= self.MASK ^ (1 << (IRQn & self.MASK)) else: self.ql.hw.scb.disable(IRQn) def get_enable(self, IRQn): if IRQn >= 0: - return (self.nvic.ISER[IRQn >> self.OFFSET] >> (IRQn & self.MASK)) & 1 + return (self.instance.ISER[IRQn >> self.OFFSET] >> (IRQn & self.MASK)) & 1 else: return self.ql.hw.scb.get_enable(IRQn) def set_pending(self, IRQn): if IRQn >= 0: - self.nvic.ISPR[IRQn >> self.OFFSET] |= 1 << (IRQn & self.MASK) - self.nvic.ICPR[IRQn >> self.OFFSET] |= 1 << (IRQn & self.MASK) + self.instance.ISPR[IRQn >> self.OFFSET] |= 1 << (IRQn & self.MASK) + self.instance.ICPR[IRQn >> self.OFFSET] |= 1 << (IRQn & self.MASK) else: self.ql.hw.scb.set_pending(IRQn) @@ -85,20 +85,20 @@ def set_pending(self, IRQn): def clear_pending(self, IRQn): if IRQn >= 0: - self.nvic.ISPR[IRQn >> self.OFFSET] &= self.MASK ^ (1 << (IRQn & self.MASK)) - self.nvic.ICPR[IRQn >> self.OFFSET] &= self.MASK ^ (1 << (IRQn & self.MASK)) + self.instance.ISPR[IRQn >> self.OFFSET] &= self.MASK ^ (1 << (IRQn & self.MASK)) + self.instance.ICPR[IRQn >> self.OFFSET] &= self.MASK ^ (1 << (IRQn & self.MASK)) else: self.ql.hw.scb.clear_pending(IRQn) def get_pending(self, IRQn): if IRQn >= 0: - return (self.nvic.ISER[IRQn >> self.OFFSET] >> (IRQn & self.MASK)) & 1 + return (self.instance.ISER[IRQn >> self.OFFSET] >> (IRQn & self.MASK)) & 1 else: return self.ql.hw.scb.get_pending(IRQn) def get_priority(self, IRQn): if IRQn >= 0: - return self.nvic.IPR[IRQn] + return self.instance.IPR[IRQn] else: return self.ql.hw.scb.get_priority(IRQn) @@ -116,7 +116,7 @@ def step(self): @QlPeripheral.monitor() def read(self, offset: int, size: int) -> int: buf = ctypes.create_string_buffer(size) - ctypes.memmove(buf, ctypes.addressof(self.nvic) + offset, size) + ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) return int.from_bytes(buf.raw, byteorder='little') @QlPeripheral.monitor() @@ -133,7 +133,7 @@ def write_byte(ofs, byte): if ipr.offset <= ofs < ipr.offset + ipr.size: byte &= 0xf0 # IPR[3: 0] reserved - ctypes.memmove(ctypes.addressof(self.nvic) + ofs, bytes([byte]), 1) + ctypes.memmove(ctypes.addressof(self.instance) + ofs, bytes([byte]), 1) for ofs in range(offset, offset + size): write_byte(ofs, value & 0xff) diff --git a/qiling/hw/intc/gd32vf1xx_eclic.py b/qiling/hw/intc/gd32vf1xx_eclic.py index 90a2e664f..2c57383bb 100644 --- a/qiling/hw/intc/gd32vf1xx_eclic.py +++ b/qiling/hw/intc/gd32vf1xx_eclic.py @@ -370,7 +370,7 @@ class Type(ctypes.Structure): def __init__(self, ql, label): super().__init__(ql, label) - self.eclic = self.struct( + self.instance = self.struct( CLICCFG = 0x00000000, CLICINFO = 0x00000000, MTH = 0x00000000, @@ -727,10 +727,10 @@ def __init__(self, ql, label): @QlPeripheral.monitor() def read(self, offset: int, size: int) -> int: buf = ctypes.create_string_buffer(size) - ctypes.memmove(buf, ctypes.addressof(self.gpio) + offset, size) + ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) return int.from_bytes(buf.raw, byteorder='little') @QlPeripheral.monitor() def write(self, offset: int, size: int, value: int): data = (value).to_bytes(size, 'little') - ctypes.memmove(ctypes.addressof(self.gpio) + offset, data, size) + ctypes.memmove(ctypes.addressof(self.instance) + offset, data, size) diff --git a/qiling/hw/intc/stm32f1xx_exti.py b/qiling/hw/intc/stm32f1xx_exti.py index cea43ad7a..7dc3e1276 100644 --- a/qiling/hw/intc/stm32f1xx_exti.py +++ b/qiling/hw/intc/stm32f1xx_exti.py @@ -44,7 +44,7 @@ def __init__(self, ql, label, ): super().__init__(ql, label) - self.exti = self.struct() + self.instance = self.struct() self.intn = [ exti0_intn , exti1_intn , exti2_intn , exti3_intn, exti4_intn , exti9_5_intn , exti9_5_intn , exti9_5_intn, @@ -55,31 +55,31 @@ def __init__(self, ql, label, @QlPeripheral.monitor() def read(self, offset: int, size: int) -> int: buf = ctypes.create_string_buffer(size) - ctypes.memmove(buf, ctypes.addressof(self.exti) + offset, size) + ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) return int.from_bytes(buf.raw, byteorder='little') @QlPeripheral.monitor() def write(self, offset: int, size: int, value: int): if offset == self.struct.SWIER.offset: - value = value & self.exti.IMR & 0x7ffff + value = value & self.instance.IMR & 0x7ffff for i in range(20): - if ((self.exti.SWIER >> i) & 1) == 0 and ((value >> i) & 1) == 1: + if ((self.instance.SWIER >> i) & 1) == 0 and ((value >> i) & 1) == 1: self.send_interrupt(i) elif offset == self.struct.PR.offset: for i in range(20): if (value >> i) & 1: - self.exti.PR &= ~(1 << i) - self.exti.SWIER &= ~(1 << i) + self.instance.PR &= ~(1 << i) + self.instance.SWIER &= ~(1 << i) return data = (value).to_bytes(size, 'little') - ctypes.memmove(ctypes.addressof(self.exti) + offset, data, size) + ctypes.memmove(ctypes.addressof(self.instance) + offset, data, size) def send_interrupt(self, index): - if 0 <= index < 20 and (self.exti.IMR >> index) & 1: - self.exti.PR |= 1 << index + if 0 <= index < 20 and (self.instance.IMR >> index) & 1: + self.instance.PR |= 1 << index if index < 16: self.ql.hw.afio.exti(index).set_pin(index) diff --git a/qiling/hw/math/gd32vf1xx_crc.py b/qiling/hw/math/gd32vf1xx_crc.py index ea884c3fd..7224fee4b 100644 --- a/qiling/hw/math/gd32vf1xx_crc.py +++ b/qiling/hw/math/gd32vf1xx_crc.py @@ -23,7 +23,7 @@ class Type(ctypes.Structure): def __init__(self, ql, label): super().__init__(ql, label) - self.crc = self.struct( + self.instance = self.struct( DATA = 0xffffffff, FDATA = 0x00000000, CTL = 0x00000000, diff --git a/qiling/hw/math/stm32f4xx_crc.py b/qiling/hw/math/stm32f4xx_crc.py index bfe136883..9d804697b 100644 --- a/qiling/hw/math/stm32f4xx_crc.py +++ b/qiling/hw/math/stm32f4xx_crc.py @@ -46,30 +46,30 @@ class Type(ctypes.Structure): def __init__(self, ql, label): super().__init__(ql, label) - self.crc = self.struct( + self.instance = self.struct( DR = 0xffffffff, ) @QlPeripheral.monitor() def read(self, offset: int, size: int) -> int: buf = ctypes.create_string_buffer(size) - ctypes.memmove(buf, ctypes.addressof(self.crc) + offset, size) + ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) return int.from_bytes(buf.raw, byteorder='little') @QlPeripheral.monitor() def write(self, offset: int, size: int, value: int): if offset == self.struct.CR.offset: if value & 1: # RESET bit - self.crc.DR = 0xffffffff + self.instance.DR = 0xffffffff return elif offset == self.struct.DR.offset: for i in range(31, -1, -1): - if self.crc.DR & 0x80000000: - self.crc.DR <<= 1 - self.crc.DR ^= 0x04c11db7 + if self.instance.DR & 0x80000000: + self.instance.DR <<= 1 + self.instance.DR ^= 0x04c11db7 else: - self.crc.DR <<= 1 + self.instance.DR <<= 1 if value & (1 << i): - self.crc.DR ^= 0x04c11db7 + self.instance.DR ^= 0x04c11db7 diff --git a/qiling/hw/mem/__init__.py b/qiling/hw/mem/__init__.py new file mode 100644 index 000000000..33086f101 --- /dev/null +++ b/qiling/hw/mem/__init__.py @@ -0,0 +1,8 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +from .cm_bitband import CortexMBitband +from .remap import MemoryRemap +from .kinetis_bme import KinetisBME diff --git a/qiling/hw/mem/cm_bitband.py b/qiling/hw/mem/cm_bitband.py new file mode 100644 index 000000000..d033cf28e --- /dev/null +++ b/qiling/hw/mem/cm_bitband.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +from qiling.hw.peripheral import QlPeripheral + + +class CortexMBitband(QlPeripheral): + def __init__(self, ql, label, base, size): + super().__init__(ql, label) + + self.bitband_base = base + self.bitband_size = size * 32 + + def _bitband_addr(self, offset): + return self.bitband_base | (offset & 0x1ffffff) >> 5 + + @property + def region(self): + return [(0, self.bitband_size)] + + def read(self, offset, size): + addr = self._bitband_addr(offset) & (-size) + buf = self.ql.mem.read(addr, size) + + bitpos = (offset >> 2) & ((size * 8) - 1) + bit = (buf[bitpos >> 3] >> (bitpos & 7)) & 1 + + return bit + + def write(self, offset, size, value): + addr = self._bitband_addr(offset) & (-size) + buf = self.ql.mem.read(addr, size) + + bitpos = (offset >> 2) & ((size * 8) - 1) + bit = 1 << (bitpos & 7) + if value & 1: + buf[bitpos >> 3] |= bit + else: + buf[bitpos >> 3] &= ~bit + + self.ql.mem.write(addr, bytes(buf)) diff --git a/qiling/hw/mem/kinetis_bme.py b/qiling/hw/mem/kinetis_bme.py new file mode 100644 index 000000000..3937626e6 --- /dev/null +++ b/qiling/hw/mem/kinetis_bme.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +from qiling.hw.peripheral import QlPeripheral +from qiling.exception import QlErrorNotImplemented + +class KinetisBME(QlPeripheral): + + def __init__(self, ql, label, base, size): + super().__init__(ql, label) + + self.bme_base = base + self.bme_size = size + + @property + def region(self): + return [(0, 0x10000000)] + + def operand_size_from_alignment(self, addr): + if addr & 1: + return 1 + elif addr & 2: + return 2 + else: + return 4 + + def read(self, offset, size): + raise QlErrorNotImplemented("KinetisBME.read has not been implemented") + + def write(self, offset, size, value): + decorated_addr = offset + self.base + read_size = self.operand_size_from_alignment(decorated_addr) + + op_type = (decorated_addr & 0x1c000000) >> 26 + address = decorated_addr & 0x6007ffff + + raw = self.ql.read(address, read_size) + + if op_type == 0x1: + raw &= value + elif op_type == 0x2: + raw |= value + else: + ## TODO: other operands + raise QlErrorNotImplemented(f"operand ({hex(op_type)}) has not been implemented") + + self.ql.write(address, read_size, raw) + \ No newline at end of file diff --git a/qiling/hw/mem/remap.py b/qiling/hw/mem/remap.py new file mode 100644 index 000000000..03cd6e819 --- /dev/null +++ b/qiling/hw/mem/remap.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +from qiling.hw.peripheral import QlPeripheral + + +class MemoryRemap(QlPeripheral): + def __init__(self, ql, label, base, size): + super().__init__(ql, label) + + self.remap_base = base + self.remap_size = size + + @property + def region(self): + return [(0, self.remap_size)] + + def read(self, offset, size): + return int.from_bytes(self.ql.mem.read(self.remap_base + offset, size), 'little') + + def write(self, offset, size, value): + return self.ql.mem.write(self.remap_base + offset, (value).to_bytes(size, 'little')) diff --git a/qiling/hw/misc/__init__.py b/qiling/hw/misc/__init__.py index 1c8390b8c..83b0e8fa8 100644 --- a/qiling/hw/misc/__init__.py +++ b/qiling/hw/misc/__init__.py @@ -5,6 +5,7 @@ from .cm3_scb import CortexM3Scb from .cm4_scb import CortexM4Scb +from .sam3xa_wdt import SAM3xaWdt from .stm32f1xx_rcc import STM32F1xxRcc from .stm32f4xx_rcc import STM32F4xxRcc from .stm32f4xx_rcc_derive import ( @@ -15,3 +16,7 @@ from .stm32f4xx_syscfg import STM32F4xxSyscfg from .stm32f4xx_dbg import STM32F4xxDbgmcu from .gd32vf1xx_rcu import GD32VF1xxRcu +from .mk64f12_sim import MK64F12Sim +from .mk64f12_smc import MK64F12Smc +from .mk64f12_mcg import MK64F12Mcg +from .mk64f12_wdog import MK64F12Wdog diff --git a/qiling/hw/misc/cm3_scb.py b/qiling/hw/misc/cm3_scb.py index 148bca830..d3d042cc9 100644 --- a/qiling/hw/misc/cm3_scb.py +++ b/qiling/hw/misc/cm3_scb.py @@ -30,7 +30,7 @@ class Type(ctypes.Structure): def __init__(self, ql, label): super().__init__(ql, label) - self.scb = self.struct( + self.instance = self.struct( CPUID = 0x411FC231, AIRCR = 0xFA050000, ) diff --git a/qiling/hw/misc/cm4_scb.py b/qiling/hw/misc/cm4_scb.py index 7cf2de0b7..7f1a8571f 100644 --- a/qiling/hw/misc/cm4_scb.py +++ b/qiling/hw/misc/cm4_scb.py @@ -24,14 +24,21 @@ class Type(ctypes.Structure): ('HFSR' , ctypes.c_uint32), ('DFSR' , ctypes.c_uint32), ('MMFAR' , ctypes.c_uint32), - ('BFSR' , ctypes.c_uint32), + ('BFAR' , ctypes.c_uint32), ('AFSR' , ctypes.c_uint32), + ('PFR' , ctypes.c_uint32 * 4), + ('DFR' , ctypes.c_uint32), + ('ADR' , ctypes.c_uint32), + ('MMFR' , ctypes.c_uint32 * 4), + ('ISAR' , ctypes.c_uint32 * 5), + ('RESERVED0', ctypes.c_uint32 * 5), + ('CPACR' , ctypes.c_uint32), ] def __init__(self, ql, label): super().__init__(ql, label) - self.scb = self.struct( + self.instance = self.struct( CPUID = 0x410FC241, AIRCR = 0xFA050000, CCR = 0x00000200, diff --git a/qiling/hw/misc/cm_scb.py b/qiling/hw/misc/cm_scb.py index a98a0eef6..39899f9a6 100644 --- a/qiling/hw/misc/cm_scb.py +++ b/qiling/hw/misc/cm_scb.py @@ -13,88 +13,88 @@ class CortexMScb(QlPeripheral): def enable(self, IRQn): if IRQn == IRQ.USAGE_FAULT: - self.scb.SHCSR |= 1 << 18 + self.instance.SHCSR |= 1 << 18 if IRQn == IRQ.BUS_FAULT: - self.scb.SHCSR |= 1 << 17 + self.instance.SHCSR |= 1 << 17 if IRQn == IRQ.MEMORY_MANAGEMENT_FAULT: - self.scb.SHCSR |= 1 << 16 + self.instance.SHCSR |= 1 << 16 def disable(self, IRQn): if IRQn == IRQ.USAGE_FAULT: - self.scb.SHCSR &= ~(1 << 18) + self.instance.SHCSR &= ~(1 << 18) if IRQn == IRQ.BUS_FAULT: - self.scb.SHCSR &= ~(1 << 17) + self.instance.SHCSR &= ~(1 << 17) if IRQn == IRQ.MEMORY_MANAGEMENT_FAULT: - self.scb.SHCSR &= ~(1 << 16) + self.instance.SHCSR &= ~(1 << 16) def get_enable(self, IRQn): if IRQn == IRQ.USAGE_FAULT: - return (self.scb.SHCSR >> 18) & 1 + return (self.instance.SHCSR >> 18) & 1 if IRQn == IRQ.BUS_FAULT: - return (self.scb.SHCSR >> 17) & 1 + return (self.instance.SHCSR >> 17) & 1 if IRQn == IRQ.MEMORY_MANAGEMENT_FAULT: - return (self.scb.SHCSR >> 16) & 1 + return (self.instance.SHCSR >> 16) & 1 return 1 def set_pending(self, IRQn): if IRQn == IRQ.NMI: - self.scb.ICSR |= 1 << 31 + self.instance.ICSR |= 1 << 31 if IRQn == IRQ.PENDSV: - self.scb.ICSR |= 3 << 27 # set-bit and clear-bit + self.instance.ICSR |= 3 << 27 # set-bit and clear-bit if IRQn == IRQ.SYSTICK: - self.scb.ICSR |= 3 << 25 # set-bit and clear-bit + self.instance.ICSR |= 3 << 25 # set-bit and clear-bit if IRQn == IRQ.MEMORY_MANAGEMENT_FAULT: - self.scb.SHCSR |= 1 << 13 + self.instance.SHCSR |= 1 << 13 if IRQn == IRQ.BUS_FAULT: - self.scb.SHCSR |= 1 << 14 + self.instance.SHCSR |= 1 << 14 if IRQn == IRQ.USAGE_FAULT: - self.scb.SHCSR |= 1 << 12 + self.instance.SHCSR |= 1 << 12 if IRQn == IRQ.SVCALL: - self.scb.SHCSR |= 1 << 15 + self.instance.SHCSR |= 1 << 15 def clear_pending(self, IRQn): if IRQn == IRQ.NMI: - self.scb.ICSR &= ~(1 << 31) + self.instance.ICSR &= ~(1 << 31) if IRQn == IRQ.PENDSV: - self.scb.ICSR &= ~(3 << 27) + self.instance.ICSR &= ~(3 << 27) if IRQn == IRQ.SYSTICK: - self.scb.ICSR &= ~(3 << 25) + self.instance.ICSR &= ~(3 << 25) if IRQn == IRQ.MEMORY_MANAGEMENT_FAULT: - self.scb.SHCSR &= ~(1 << 13) + self.instance.SHCSR &= ~(1 << 13) if IRQn == IRQ.BUS_FAULT: - self.scb.SHCSR &= ~(1 << 14) + self.instance.SHCSR &= ~(1 << 14) if IRQn == IRQ.USAGE_FAULT: - self.scb.SHCSR &= ~(1 << 12) + self.instance.SHCSR &= ~(1 << 12) if IRQn == IRQ.SVCALL: - self.scb.SHCSR &= ~(1 << 15) + self.instance.SHCSR &= ~(1 << 15) def get_pending(self, IRQn): if IRQn == IRQ.NMI: - return (self.scb.ICSR >> 31) & 1 + return (self.instance.ICSR >> 31) & 1 if IRQn == IRQ.PENDSV: - return (self.scb.ICSR >> 28) & 1 + return (self.instance.ICSR >> 28) & 1 if IRQn == IRQ.SYSTICK: - return (self.scb.ICSR >> 26) & 1 + return (self.instance.ICSR >> 26) & 1 if IRQn == IRQ.MEMORY_MANAGEMENT_FAULT: - return (self.scb.SHCSR >> 13) & 1 + return (self.instance.SHCSR >> 13) & 1 if IRQn == IRQ.BUS_FAULT: - return (self.scb.SHCSR >> 14) & 1 + return (self.instance.SHCSR >> 14) & 1 if IRQn == IRQ.USAGE_FAULT: - return (self.scb.SHCSR >> 12) & 1 + return (self.instance.SHCSR >> 12) & 1 if IRQn == IRQ.SVCALL: - return (self.scb.SHCSR >> 15) & 1 + return (self.instance.SHCSR >> 15) & 1 return 0 def get_priority(self, IRQn): - return self.scb.SHP[(IRQn & 0xf) - 4] + return self.instance.SHP[(IRQn & 0xf) - 4] @QlPeripheral.monitor() def read(self, offset: int, size: int) -> int: buf = ctypes.create_string_buffer(size) - ctypes.memmove(buf, ctypes.addressof(self.scb) + offset, size) + ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) return int.from_bytes(buf.raw, byteorder='little') @QlPeripheral.monitor() @@ -104,4 +104,4 @@ def write(self, offset: int, size: int, value: int): self.ql.hw.nvic.set_pending(IRQ.PENDSV) data = (value).to_bytes(size, 'little') - ctypes.memmove(ctypes.addressof(self.scb) + offset, data, size) + ctypes.memmove(ctypes.addressof(self.instance) + offset, data, size) diff --git a/qiling/hw/misc/gd32vf1xx_rcu.py b/qiling/hw/misc/gd32vf1xx_rcu.py index 4de6b0ce4..364bf4c5b 100644 --- a/qiling/hw/misc/gd32vf1xx_rcu.py +++ b/qiling/hw/misc/gd32vf1xx_rcu.py @@ -33,7 +33,7 @@ class Type(ctypes.Structure): def __init__(self, ql, label, intn=None): super().__init__(ql, label) - self.rcu = self.struct( + self.instance = self.struct( CTL = 0x00000083, CFG0 = 0x00000000, INT = 0x00000000, @@ -54,10 +54,10 @@ def __init__(self, ql, label, intn=None): @QlPeripheral.monitor() def read(self, offset: int, size: int) -> int: buf = ctypes.create_string_buffer(size) - ctypes.memmove(buf, ctypes.addressof(self.rcu) + offset, size) + ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) return int.from_bytes(buf.raw, byteorder='little') @QlPeripheral.monitor() def write(self, offset: int, size: int, value: int): data = (value).to_bytes(size, 'little') - ctypes.memmove(ctypes.addressof(self.rcu) + offset, data, size) + ctypes.memmove(ctypes.addressof(self.instance) + offset, data, size) diff --git a/qiling/hw/misc/mk64f12_mcg.py b/qiling/hw/misc/mk64f12_mcg.py new file mode 100644 index 000000000..d0d5664d5 --- /dev/null +++ b/qiling/hw/misc/mk64f12_mcg.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import ctypes + +from qiling.hw.peripheral import QlPeripheral +from qiling.hw.const.mk64f12_mcg import C1, C5, C6, S + + +class MK64F12Mcg(QlPeripheral): + class Type(ctypes.Structure): + """ Multipurpose Clock Generator module """ + _fields_ = [ + ("C1" , ctypes.c_uint8), # MCG Control 1 Register + ("C2" , ctypes.c_uint8), # MCG Control 2 Register + ("C3" , ctypes.c_uint8), # MCG Control 3 Register + ("C4" , ctypes.c_uint8), # MCG Control 4 Register + ("C5" , ctypes.c_uint8), # MCG Control 5 Register + ("C6" , ctypes.c_uint8), # MCG Control 6 Register + ("S" , ctypes.c_uint8), # MCG Status Register + ("RESERVED0", ctypes.c_uint8), + ("SC" , ctypes.c_uint8), # MCG Status and Control Register + ("RESERVED1", ctypes.c_uint8), + ("ATCVH", ctypes.c_uint8), # MCG Auto Trim Compare Value High Register + ("ATCVL", ctypes.c_uint8), # MCG Auto Trim Compare Value Low Register + ("C7" , ctypes.c_uint8), # MCG Control 7 Register + ("C8" , ctypes.c_uint8), # MCG Control 8 Register + ] + + def __init__(self, ql, label): + super().__init__(ql, label) + + + @QlPeripheral.monitor() + def write(self, offset: int, size: int, value: int): + if offset == self.struct.C1.offset: + self.instance.S &= ~(S.IREFST | S.CLKST) + + self.instance.S |= (value & C1.IREFS) >> C1.IREFS_Pos << S.IREFST_Pos + + clock_source = value & C1.CLKS + if clock_source == 0 and self.instance.S & S.PLLST: + self.instance.S |= S.CLKST + else: + self.instance.S |= clock_source >> C1.CLKS_Pos << S.CLKST_Pos + + elif offset == self.struct.C5.offset: + if value & C5.PLLCLKEN0: + self.instance.S |= S.LOCK0 + + elif offset == self.struct.C6.offset: + if value & C6.PLLS: + self.instance.S |= S.PLLST + self.instance.S |= S.LOCK0 + + else: + self.raw_write(offset, size, value) diff --git a/qiling/hw/misc/mk64f12_sim.py b/qiling/hw/misc/mk64f12_sim.py new file mode 100644 index 000000000..e17c4f6ef --- /dev/null +++ b/qiling/hw/misc/mk64f12_sim.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import ctypes + +from qiling.hw.peripheral import QlPeripheral + + +class MK64F12Sim(QlPeripheral): + class Type(ctypes.Structure): + """ System Integration Module """ + _fields_ = [ + ("SOPT1" , ctypes.c_uint32), # System Options Register 1 + ("SOPT1CFG", ctypes.c_uint32), # SOPT1 Configuration Register + ("RESERVED0", ctypes.c_uint8 * 4092), + ("SOPT2" , ctypes.c_uint32), # System Options Register 2 + ("RESERVED1", ctypes.c_uint8 * 4), + ("SOPT4" , ctypes.c_uint32), # System Options Register 4 + ("SOPT5" , ctypes.c_uint32), # System Options Register 5 + ("RESERVED2", ctypes.c_uint8 * 8), + ("SOPT7" , ctypes.c_uint32), # System Options Register 7 + ("RESERVED3", ctypes.c_uint8 * 4), + ("SDID" , ctypes.c_uint32), # System Device Identification Register + ("SCGC1" , ctypes.c_uint32), # System Clock Gating Control Register 1 + ("SCGC2" , ctypes.c_uint32), # System Clock Gating Control Register 2 + ("SCGC3" , ctypes.c_uint32), # System Clock Gating Control Register 3 + ("SCGC4" , ctypes.c_uint32), # System Clock Gating Control Register 4 + ("SCGC5" , ctypes.c_uint32), # System Clock Gating Control Register 5 + ("SCGC6" , ctypes.c_uint32), # System Clock Gating Control Register 6 + ("SCGC7" , ctypes.c_uint32), # System Clock Gating Control Register 7 + ("CLKDIV1" , ctypes.c_uint32), # System Clock Divider Register 1 + ("CLKDIV2" , ctypes.c_uint32), # System Clock Divider Register 2 + ("FCFG1" , ctypes.c_uint32), # Flash Configuration Register 1 + ("FCFG2" , ctypes.c_uint32), # Flash Configuration Register 2 + ("UIDH" , ctypes.c_uint32), # Unique Identification Register High + ("UIDMH" , ctypes.c_uint32), # Unique Identification Register Mid-High + ("UIDML" , ctypes.c_uint32), # Unique Identification Register Mid Low + ("UIDL" , ctypes.c_uint32), # Unique Identification Register Low + ] \ No newline at end of file diff --git a/qiling/hw/misc/mk64f12_smc.py b/qiling/hw/misc/mk64f12_smc.py new file mode 100644 index 000000000..1582d1757 --- /dev/null +++ b/qiling/hw/misc/mk64f12_smc.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import ctypes + +from qiling.hw.peripheral import QlPeripheral + + +class MK64F12Smc(QlPeripheral): + class Type(ctypes.Structure): + """ System Mode Controller """ + _fields_ = [ + ("PMPROT" , ctypes.c_uint8), # Power Mode Protection register + ("PMCTRL" , ctypes.c_uint8), # Power Mode Control register + ("VLLSCTRL", ctypes.c_uint8), # VLLS Control register + ("PMSTAT" , ctypes.c_uint8), # Power Mode Status register + ] diff --git a/qiling/hw/misc/mk64f12_wdog.py b/qiling/hw/misc/mk64f12_wdog.py new file mode 100644 index 000000000..fa2324427 --- /dev/null +++ b/qiling/hw/misc/mk64f12_wdog.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import ctypes + +from qiling.hw.peripheral import QlPeripheral + + +class MK64F12Wdog(QlPeripheral): + class Type(ctypes.Structure): + """ Generation 2008 Watchdog Timer """ + _fields_ = [ + ("STCTRLH", ctypes.c_uint16), # Watchdog Status and Control Register High + ("STCTRLL", ctypes.c_uint16), # Watchdog Status and Control Register Low + ("TOVALH" , ctypes.c_uint16), # Watchdog Time-out Value Register High + ("TOVALL" , ctypes.c_uint16), # Watchdog Time-out Value Register Low + ("WINH" , ctypes.c_uint16), # Watchdog Window Register High + ("WINL" , ctypes.c_uint16), # Watchdog Window Register Low + ("REFRESH", ctypes.c_uint16), # Watchdog Refresh register + ("UNLOCK" , ctypes.c_uint16), # Watchdog Unlock register + ("TMROUTH", ctypes.c_uint16), # Watchdog Timer Output Register High + ("TMROUTL", ctypes.c_uint16), # Watchdog Timer Output Register Low + ("RSTCNT" , ctypes.c_uint16), # Watchdog Reset Count register + ("PRESC" , ctypes.c_uint16), # Watchdog Prescaler register + ] + + def __init__(self, ql, label, ewm_intn=None): + super().__init__(ql, label) diff --git a/qiling/hw/timer/sam3xa_wdt.py b/qiling/hw/misc/sam3xa_wdt.py similarity index 96% rename from qiling/hw/timer/sam3xa_wdt.py rename to qiling/hw/misc/sam3xa_wdt.py index 0ffe0fd11..e7f1ab3bc 100644 --- a/qiling/hw/timer/sam3xa_wdt.py +++ b/qiling/hw/misc/sam3xa_wdt.py @@ -26,5 +26,5 @@ class Type(ctypes.Structure): def __init__(self, ql, label, intn = None): super().__init__(ql, label) - self.wdt = self.struct() + self.instance = self.struct() self.intn = intn diff --git a/qiling/hw/misc/stm32f1xx_rcc.py b/qiling/hw/misc/stm32f1xx_rcc.py index aff4323e3..434d17240 100644 --- a/qiling/hw/misc/stm32f1xx_rcc.py +++ b/qiling/hw/misc/stm32f1xx_rcc.py @@ -36,7 +36,7 @@ class Type(ctypes.Structure): def __init__(self, ql, label, intn=None): super().__init__(ql, label) - self.rcc = self.struct( + self.instance = self.struct( CR = 0x00000083, AHBENR = 0x00000014, CSR = 0x0C000000, @@ -63,20 +63,20 @@ def __init__(self, ql, label, intn=None): @QlPeripheral.monitor() def read(self, offset: int, size: int) -> int: buf = ctypes.create_string_buffer(size) - ctypes.memmove(buf, ctypes.addressof(self.rcc) + offset, size) + ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) return int.from_bytes(buf.raw, byteorder='little') @QlPeripheral.monitor() def write(self, offset: int, size: int, value: int): data = (value).to_bytes(size, 'little') - ctypes.memmove(ctypes.addressof(self.rcc) + offset, data, size) + ctypes.memmove(ctypes.addressof(self.instance) + offset, data, size) def step(self): for reg, rdyon in self.rdyon.items(): - value = getattr(self.rcc, reg) + value = getattr(self.instance, reg) for rdy, on in rdyon: if value & on: value |= rdy else: value &= ~rdy - setattr(self.rcc, reg, value) + setattr(self.instance, reg, value) diff --git a/qiling/hw/misc/stm32f4xx_dbg.py b/qiling/hw/misc/stm32f4xx_dbg.py index e17217e05..148c375f4 100644 --- a/qiling/hw/misc/stm32f4xx_dbg.py +++ b/qiling/hw/misc/stm32f4xx_dbg.py @@ -47,17 +47,17 @@ class Type(ctypes.Structure): def __init__(self, ql: Qiling, label: str, dev_id: int = 0x400): super().__init__(ql, label) - self.dbg = self.struct( + self.instance = self.struct( IDCODE = dev_id, ) @QlPeripheral.monitor() def read(self, offset: int, size: int) -> int: buf = ctypes.create_string_buffer(size) - ctypes.memmove(buf, ctypes.addressof(self.dbg) + offset, size) + ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) return int.from_bytes(buf.raw, byteorder='little') @QlPeripheral.monitor() def write(self, offset: int, size: int, value: int): data = (value).to_bytes(size, 'little') - ctypes.memmove(ctypes.addressof(self.dbg) + offset, data, size) + ctypes.memmove(ctypes.addressof(self.instance) + offset, data, size) diff --git a/qiling/hw/misc/stm32f4xx_rcc.py b/qiling/hw/misc/stm32f4xx_rcc.py index ac45168ce..8d634cf01 100644 --- a/qiling/hw/misc/stm32f4xx_rcc.py +++ b/qiling/hw/misc/stm32f4xx_rcc.py @@ -54,7 +54,7 @@ class Type(ctypes.Structure): def __init__(self, ql, label, intn=None): super().__init__(ql, label) - self.rcc = self.struct( + self.instance = self.struct( CR = 0x00000083, PLLCFGR = 0x24003010, AHB1LPENR = 0x0061900F, @@ -86,25 +86,25 @@ def __init__(self, ql, label, intn=None): @QlPeripheral.monitor() def read(self, offset: int, size: int) -> int: buf = ctypes.create_string_buffer(size) - ctypes.memmove(buf, ctypes.addressof(self.rcc) + offset, size) + ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) return int.from_bytes(buf.raw, byteorder='little') @QlPeripheral.monitor() def write(self, offset: int, size: int, value: int): if offset == self.struct.CR.offset: - value = (self.rcc.CR & RCC_CR.RO_MASK) | (value & RCC_CR.RW_MASK) + value = (self.instance.CR & RCC_CR.RO_MASK) | (value & RCC_CR.RW_MASK) elif offset == self.struct.CFGR.offset: - value = (self.rcc.CFGR & RCC_CFGR.RO_MASK) | (value & RCC_CFGR.RW_MASK) + value = (self.instance.CFGR & RCC_CFGR.RO_MASK) | (value & RCC_CFGR.RW_MASK) data = (value).to_bytes(size, 'little') - ctypes.memmove(ctypes.addressof(self.rcc) + offset, data, size) + ctypes.memmove(ctypes.addressof(self.instance) + offset, data, size) def step(self): for reg, rdyon in self.rdyon.items(): - value = getattr(self.rcc, reg) + value = getattr(self.instance, reg) for rdy, on in rdyon: if value & on: value |= rdy else: value &= ~rdy - setattr(self.rcc, reg, value) + setattr(self.instance, reg, value) diff --git a/qiling/hw/net/__init__.py b/qiling/hw/net/__init__.py new file mode 100644 index 000000000..596875744 --- /dev/null +++ b/qiling/hw/net/__init__.py @@ -0,0 +1,6 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +from .stm32f4xx_eth import STM32F4xxEth diff --git a/qiling/hw/net/stm32f4xx_eth.py b/qiling/hw/net/stm32f4xx_eth.py new file mode 100644 index 000000000..393601c46 --- /dev/null +++ b/qiling/hw/net/stm32f4xx_eth.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import ctypes + +from qiling.hw.peripheral import QlPeripheral +from qiling.hw.const.stm32f4xx_eth import ETH_DMABMR, ETH_MACMIIAR + + +class STM32F4xxEth(QlPeripheral): + class Type(ctypes.Structure): + """ the structure available in : + stm32f407xx + stm32f417xx + stm32f427xx + stm32f429xx + stm32f437xx + stm32f439xx + stm32f469xx + stm32f479xx + """ + + _fields_ = [ + ("MACCR" , ctypes.c_uint32), + ("MACFFR" , ctypes.c_uint32), + ("MACHTHR" , ctypes.c_uint32), + ("MACHTLR" , ctypes.c_uint32), + ("MACMIIAR" , ctypes.c_uint32), + ("MACMIIDR" , ctypes.c_uint32), + ("MACFCR" , ctypes.c_uint32), + ("MACVLANTR" , ctypes.c_uint32), + ("RESERVED0" , ctypes.c_uint32 * 2), + ("MACRWUFFR" , ctypes.c_uint32), + ("MACPMTCSR" , ctypes.c_uint32), + ("RESERVED1" , ctypes.c_uint32), + ("MACDBGR" , ctypes.c_uint32), + ("MACSR" , ctypes.c_uint32), + ("MACIMR" , ctypes.c_uint32), + ("MACA0HR" , ctypes.c_uint32), + ("MACA0LR" , ctypes.c_uint32), + ("MACA1HR" , ctypes.c_uint32), + ("MACA1LR" , ctypes.c_uint32), + ("MACA2HR" , ctypes.c_uint32), + ("MACA2LR" , ctypes.c_uint32), + ("MACA3HR" , ctypes.c_uint32), + ("MACA3LR" , ctypes.c_uint32), + ("RESERVED2" , ctypes.c_uint32 * 40), + ("MMCCR" , ctypes.c_uint32), + ("MMCRIR" , ctypes.c_uint32), + ("MMCTIR" , ctypes.c_uint32), + ("MMCRIMR" , ctypes.c_uint32), + ("MMCTIMR" , ctypes.c_uint32), + ("RESERVED3" , ctypes.c_uint32 * 14), + ("MMCTGFSCCR" , ctypes.c_uint32), + ("MMCTGFMSCCR", ctypes.c_uint32), + ("RESERVED4" , ctypes.c_uint32 * 5), + ("MMCTGFCR" , ctypes.c_uint32), + ("RESERVED5" , ctypes.c_uint32 * 10), + ("MMCRFCECR" , ctypes.c_uint32), + ("MMCRFAECR" , ctypes.c_uint32), + ("RESERVED6" , ctypes.c_uint32 * 10), + ("MMCRGUFCR" , ctypes.c_uint32), + ("RESERVED7" , ctypes.c_uint32 * 334), + ("PTPTSCR" , ctypes.c_uint32), + ("PTPSSIR" , ctypes.c_uint32), + ("PTPTSHR" , ctypes.c_uint32), + ("PTPTSLR" , ctypes.c_uint32), + ("PTPTSHUR" , ctypes.c_uint32), + ("PTPTSLUR" , ctypes.c_uint32), + ("PTPTSAR" , ctypes.c_uint32), + ("PTPTTHR" , ctypes.c_uint32), + ("PTPTTLR" , ctypes.c_uint32), + ("RESERVED8" , ctypes.c_uint32), + ("PTPTSSR" , ctypes.c_uint32), + ("RESERVED9" , ctypes.c_uint32 * 565), + ("DMABMR" , ctypes.c_uint32), + ("DMATPDR" , ctypes.c_uint32), + ("DMARPDR" , ctypes.c_uint32), + ("DMARDLAR" , ctypes.c_uint32), + ("DMATDLAR" , ctypes.c_uint32), + ("DMASR" , ctypes.c_uint32), + ("DMAOMR" , ctypes.c_uint32), + ("DMAIER" , ctypes.c_uint32), + ("DMAMFBOCR" , ctypes.c_uint32), + ("DMARSWTR" , ctypes.c_uint32), + ("RESERVED10" , ctypes.c_uint32 * 8), + ("DMACHTDR" , ctypes.c_uint32), + ("DMACHRDR" , ctypes.c_uint32), + ("DMACHTBAR" , ctypes.c_uint32), + ("DMACHRBAR" , ctypes.c_uint32), + ] + + def __init__(self, ql, label, intn=None, wkup_intn=None): + super().__init__(ql, label) + + self.instance = self.struct() + + self.intn = intn + self.wkup_intn = wkup_intn + + @QlPeripheral.monitor() + def read(self, offset: int, size: int) -> int: + return self.raw_read(offset, size) + + + @QlPeripheral.monitor() + def write(self, offset: int, size: int, value: int): + self.raw_write(offset, size, value) + + if offset == self.struct.DMABMR.offset: + if value & ETH_DMABMR.SR: + self.instance.DMABMR &= ~ETH_DMABMR.SR + + if offset == self.struct.MACMIIAR.offset: + if value & ETH_MACMIIAR.MB: + self.instance.MACMIIAR &= ~ETH_MACMIIAR.MB + self.instance.MACMIIDR = 0xffff diff --git a/qiling/hw/peripheral.py b/qiling/hw/peripheral.py index 55d36a23c..587a0013d 100644 --- a/qiling/hw/peripheral.py +++ b/qiling/hw/peripheral.py @@ -7,30 +7,89 @@ from typing import List, Tuple from qiling.core import Qiling +from qiling.const import QL_INTERCEPT from qiling.exception import QlErrorBase -from qiling.hw.utils.access import Access, Op +from qiling.hw.utils.access import Access, Action class QlPeripheralUtils: + def __init__(self): + self.verbose = False + + self.user_read = { + QL_INTERCEPT.ENTER: [], + QL_INTERCEPT.CALL: [], + QL_INTERCEPT.EXIT: [], + } + + self.user_write = { + QL_INTERCEPT.ENTER: [], + QL_INTERCEPT.CALL: [], + QL_INTERCEPT.EXIT: [], + } + + def watch(self): + self.verbose = True + + def hook_read(self, callback, user_data=None, intercept=QL_INTERCEPT.ENTER): + hook_function = (callback, user_data) + self.user_read[intercept].append(hook_function) + return (0, intercept, hook_function) + + def hook_write(self, callback, user_data=None, intercept=QL_INTERCEPT.ENTER): + hook_function = (callback, user_data) + self.user_write[intercept].append(hook_function) + return (1, intercept, hook_function) + + def hook_del(self, hook_struct): + hook_type, hook_flag, hook_function = hook_struct + mapper = self.user_read if hook_type else self.user_write + mapper[hook_flag].remove(hook_function) + + def _hook_call(self, hook_list, access, offset, size, value=0): + retval = None + for callback, user_data in hook_list: + if user_data is None: + retval = callback(self, access, offset, size, value) + else: + retval = callback(self, access, offset, size, value, user_data) + + return retval + @staticmethod def monitor(width=4): def decorator(func): def read(self, offset: int, size: int) -> int: - retval = func(self, offset, size) + self._hook_call(self.user_read[QL_INTERCEPT.ENTER], Action.READ, offset, size) + + if self.user_read[QL_INTERCEPT.CALL]: + retval = self._hook_call(self.user_read[QL_INTERCEPT.CALL], Action.READ, offset, size) + else: + retval = func(self, offset, size) + if self.verbose: - self.ql.log.info(f'[{self.label.upper()}] [{hex(self.ql.arch.regs.pc)}] [R] {self.find_field(offset, size):{width}s} = {hex(retval)}') + self.ql.log.info(f'[{self.label.upper()}] [{hex(self.ql.arch.regs.arch_pc)}] [R] {self.field_description(offset, size):{width}s} = {hex(retval)}') + self._hook_call(self.user_read[QL_INTERCEPT.EXIT], Action.READ, offset, size) + return retval def write(self, offset: int, size: int, value: int): + self._hook_call(self.user_write[QL_INTERCEPT.ENTER], Action.WRITE, offset, size, value) + if self.verbose: - field, extra = self.find_field(offset, size), '' + field, extra = self.field_description(offset, size), '' if field.startswith('DR') and value <= 255: extra = f'({repr(chr(value))})' self.ql.log.info(f'[{self.label.upper()}] [{hex(self.ql.arch.regs.pc)}] [W] {field:{width}s} = {hex(value)} {extra}') - return func(self, offset, size, value) + if self.user_write[QL_INTERCEPT.CALL]: + self._hook_call(self.user_write[QL_INTERCEPT.CALL], Action.WRITE, offset, size, value) + else: + func(self, offset, size, value) + + self._hook_call(self.user_write[QL_INTERCEPT.EXIT], Action.WRITE, offset, size, value) funcmap = { 'read' : read, @@ -49,11 +108,11 @@ def write(self, offset: int, size: int, value: int): def recorder(): def decorator(func): def read(self, offset: int, size: int) -> int: - self.history.add(Access(Op.READ, offset)) + self.history.add(Access(Action.READ, offset)) return func(self, offset, size) def write(self, offset: int, size: int, value: int): - self.history.add(Access(Op.WRITE, offset, value)) + self.history.add(Access(Action.WRITE, offset, value)) return func(self, offset, size, value) funcmap = { @@ -88,53 +147,86 @@ class Type(ctypes.Structure): _fields_ = [] def __init__(self, ql: Qiling, label: str): + super().__init__() + self.ql = ql self.label = label self.struct = type(self).Type + self.instance = self.struct() - self.verbose = False + def raw_read(self, offset: int, size: int) -> int: + buf = ctypes.create_string_buffer(size) + ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) - def step(self): - """ Update the state of the peripheral, - called after each instruction is executed - """ - pass + return int.from_bytes(buf.raw, byteorder='little') - def watch(self): - self.verbose = True + def raw_write(self, offset: int, size: int, value: int): + data = (value).to_bytes(size, 'little') + ctypes.memmove(ctypes.addressof(self.instance) + offset, data, size) @QlPeripheralUtils.monitor() def read(self, offset: int, size: int) -> int: - return 0 + return self.raw_read(offset, size) @QlPeripheralUtils.monitor() def write(self, offset: int, size: int, value: int): - pass + self.raw_write(offset, size, value) - def in_field(self, field, offset: int, size: int) -> bool: + def contain(self, field, offset: int, size: int) -> bool: + """ + Returns: + bool: Whether the range [offset: offset+size] is in this field + """ return field.offset <= offset and offset + size <= field.offset + field.size - def find_field(self, offset: int, size: int) -> str: - """ Return field names in interval [offset: offset + size], + def field_description(self, offset: int, size: int) -> str: + """ Return field description in interval [offset: offset + size], the function is designed for logging and debugging. Returns: - str: Field name + str: Field description """ - field_list = [] - for name, _ in self.struct._fields_: - field = getattr(self.struct, name) - - lbound = max(0, offset - field.offset) - ubound = min(offset + size - field.offset, field.size) - if lbound < ubound: - if lbound == 0 and ubound == field.size: - field_list.append(name) - else: - field_list.append(f'{name}[{lbound}:{ubound}]') + result = [] + + def parse_array(struct, left, right, prefix): + inner_struct = struct._type_ + inner_struct_size = ctypes.sizeof(inner_struct) + + for i in range(struct._length_): + offset = inner_struct_size * i - return ','.join(field_list) + lower = max(0, left - offset) + upper = min(right - offset, inner_struct_size) + + if lower < upper: + parse_struct(inner_struct, lower, upper, f'{prefix}[{i}]') + + def parse_struct(struct, left, right, prefix=''): + if hasattr(struct, '_length_'): + parse_array(struct, left, right, prefix) + + elif hasattr(struct, '_fields_'): + if prefix.endswith(']'): + prefix += '.' + + for name, vtype in struct._fields_: + field = getattr(struct, name) + + lower = max(0, left - field.offset) + upper = min(right - field.offset, field.size) + + if lower < upper: + parse_struct(vtype, lower, upper, prefix + name) + + else: + if left == 0 and right == ctypes.sizeof(struct): + result.append(prefix) + else: + result.append(f'{prefix}[{left}:{right}]') + + parse_struct(self.struct, offset, offset + size) + return ','.join(result) @property def region(self) -> List[Tuple]: @@ -162,3 +254,9 @@ def base(self) -> int: int: Peripheral's base address """ return self.ql.hw.region[self.label][0][0] + + def save(self): + return bytes(self.instance) + + def restore(self, data): + ctypes.memmove(ctypes.addressof(self.instance), data, len(data)) diff --git a/qiling/hw/power/sam3xa_pmc.py b/qiling/hw/power/sam3xa_pmc.py index df010a366..b9f0d3e7c 100644 --- a/qiling/hw/power/sam3xa_pmc.py +++ b/qiling/hw/power/sam3xa_pmc.py @@ -62,34 +62,34 @@ class Type(ctypes.Structure): def __init__(self, ql: Qiling, label: str, intn = None): super().__init__(ql, label) - self.pmc = self.struct() + self.instance = self.struct() self.intn = intn @QlPeripheral.monitor() def read(self, offset: int, size: int) -> int: buf = ctypes.create_string_buffer(size) - ctypes.memmove(buf, ctypes.addressof(self.pmc) + offset, size) + ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) return int.from_bytes(buf.raw, byteorder='little') @QlPeripheral.monitor() def write(self, offset: int, size: int, value: int): if offset == self.struct.CKGR_MOR.offset: if value & CKGR_MOR.MOSCXTEN: - self.pmc.SR |= SR.MOSCXTS + self.instance.SR |= SR.MOSCXTS if value & CKGR_MOR.MOSCSEL: - self.pmc.SR |= SR.MOSCSELS + self.instance.SR |= SR.MOSCSELS elif offset == self.struct.MCKR.offset: if value & MCKR.CSS: - self.pmc.SR |= SR.MCKRDY + self.instance.SR |= SR.MCKRDY elif offset == self.struct.CKGR_PLLAR.offset: if value & CKGR_PLLAR.ONE: - self.pmc.SR |= SR.LOCKA + self.instance.SR |= SR.LOCKA elif offset == self.struct.CKGR_UCKR.offset: if value & CKGR_UCKR.UPLLEN: - self.pmc.SR |= SR.LOCKU + self.instance.SR |= SR.LOCKU data = (value).to_bytes(size, 'little') - ctypes.memmove(ctypes.addressof(self.pmc) + offset, data, size) \ No newline at end of file + ctypes.memmove(ctypes.addressof(self.instance) + offset, data, size) \ No newline at end of file diff --git a/qiling/hw/power/stm32f4xx_pwr.py b/qiling/hw/power/stm32f4xx_pwr.py index ad810b034..c00279b67 100644 --- a/qiling/hw/power/stm32f4xx_pwr.py +++ b/qiling/hw/power/stm32f4xx_pwr.py @@ -6,6 +6,7 @@ import ctypes from qiling.core import Qiling from qiling.hw.peripheral import QlPeripheral +from qiling.hw.const.stm32f4xx_pwr import PWR_CR, PWR_CSR class STM32F4xxPwr(QlPeripheral): @@ -44,15 +45,14 @@ class Type(ctypes.Structure): def __init__(self, ql: Qiling, label: str): super().__init__(ql, label) - self.pwr = self.struct() + self.instance = self.struct() - @QlPeripheral.monitor() - def read(self, offset: int, size: int) -> int: - buf = ctypes.create_string_buffer(size) - ctypes.memmove(buf, ctypes.addressof(self.pwr) + offset, size) - return int.from_bytes(buf.raw, byteorder='little') - @QlPeripheral.monitor() def write(self, offset: int, size: int, value: int): - data = (value).to_bytes(size, 'little') - ctypes.memmove(ctypes.addressof(self.pwr) + offset, data, size) \ No newline at end of file + if offset == self.struct.CR.offset: + if value & PWR_CR.ODEN: + self.instance.CSR |= PWR_CSR.ODRDY + if value & PWR_CR.ODSWEN: + self.instance.CSR |= PWR_CSR.ODSWRDY + + self.raw_write(offset, size, value) \ No newline at end of file diff --git a/qiling/hw/sd/stm32f4xx_sdio.py b/qiling/hw/sd/stm32f4xx_sdio.py index 26897075a..95f35da83 100644 --- a/qiling/hw/sd/stm32f4xx_sdio.py +++ b/qiling/hw/sd/stm32f4xx_sdio.py @@ -7,9 +7,11 @@ from qiling.core import Qiling from qiling.hw.peripheral import QlPeripheral +from qiling.hw.connectivity import QlConnectivityPeripheral +from qiling.hw.const.stm32f4xx_sdio import SDIO_CMD, SDIO_STA -class STM32F4xxSdio(QlPeripheral): +class STM32F4xxSdio(QlConnectivityPeripheral): class Type(ctypes.Structure): """ the structure available in : stm32f401xc @@ -61,15 +63,18 @@ def __init__(self, ql: Qiling, label: str, intn: int = None): super().__init__(ql, label) self.intn = intn - self.sdio = self.struct() - - @QlPeripheral.monitor() - def read(self, offset: int, size: int) -> int: - buf = ctypes.create_string_buffer(size) - ctypes.memmove(buf, ctypes.addressof(self.sdio) + offset, size) - return int.from_bytes(buf.raw, byteorder='little') + self.instance = self.struct() @QlPeripheral.monitor() def write(self, offset: int, size: int, value: int): - data = (value).to_bytes(size, 'little') - ctypes.memmove(ctypes.addressof(self.sdio) + offset, data, size) + if offset == self.struct.CMD.offset: + if value & SDIO_CMD.CPSMEN: + waitresp = (value & SDIO_CMD.WAITRESP) >> 6 + if waitresp in [0b00, 0b11]: + self.instance.STA |= SDIO_STA.CMDSENT + else: + self.instance.STA |= SDIO_STA.CMDREND + + self.instance.RESPCMD = value & SDIO_CMD.CMDINDEX + + self.raw_write(offset, size, value) diff --git a/qiling/hw/spi/__init__.py b/qiling/hw/spi/__init__.py index cbde66ce7..7cfda472c 100644 --- a/qiling/hw/spi/__init__.py +++ b/qiling/hw/spi/__init__.py @@ -3,5 +3,8 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # +from .sam3xa_spi import SAM3xaSpi +from .stm32f1xx_spi import STM32F1xxSpi from .stm32f4xx_spi import STM32F4xxSpi -from .gd32vf1xx_spi import GD32VF1xxSpi \ No newline at end of file +from .gd32vf1xx_spi import GD32VF1xxSpi +from .mk64f12_spi import MK64F12Spi diff --git a/qiling/hw/spi/gd32vf1xx_spi.py b/qiling/hw/spi/gd32vf1xx_spi.py index 9e7f1b9c5..5c753027b 100644 --- a/qiling/hw/spi/gd32vf1xx_spi.py +++ b/qiling/hw/spi/gd32vf1xx_spi.py @@ -29,7 +29,7 @@ class Type(ctypes.Structure): def __init__(self, ql, label): super().__init__(ql, label) - self.spi = self.struct( + self.instance = self.struct( CTL0 = 0x00000000, CTL1 = 0x00000000, STAT = 0x00000002, diff --git a/qiling/hw/spi/mk64f12_spi.py b/qiling/hw/spi/mk64f12_spi.py new file mode 100644 index 000000000..f40c3a9ed --- /dev/null +++ b/qiling/hw/spi/mk64f12_spi.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import ctypes + +from qiling.hw.peripheral import QlPeripheral +from qiling.hw.connectivity import QlConnectivityPeripheral +from qiling.hw.const.mk64f12_spi import SR, PUSHR + + +class MK64F12Spi(QlConnectivityPeripheral): + class Type(ctypes.Structure): + """ Serial Peripheral Interface """ + _fields_ = [ + ("MCR" , ctypes.c_uint32), # Module Configuration Register + ("RESERVED0" , ctypes.c_uint8 * 4), + ("TCR" , ctypes.c_uint32), # Transfer Count Register + ("CTAR" , ctypes.c_uint32 * 2), # Clock and Transfer Attributes Register (In Master Mode) + ("RESERVED1" , ctypes.c_uint8 * 24), + ("SR" , ctypes.c_uint32), # Status Register + ("RSER" , ctypes.c_uint32), # DMA/Interrupt Request Select and Enable Register + ("PUSHR" , ctypes.c_uint32), # PUSH TX FIFO Register In Master Mode + ("POPR" , ctypes.c_uint32), # POP RX FIFO Register + ("TXFR" , ctypes.c_uint32 * 4), # Transmit FIFO Registers + ("RESERVED2" , ctypes.c_uint8 * 48), + ("RXFR" , ctypes.c_uint32 * 4), # Receive FIFO Registers + ] + + def __init__(self, ql, label, intn=None): + super().__init__(ql, label) + + self.intn = intn + + @QlPeripheral.monitor() + def read(self, offset, size): + if offset == self.struct.POPR.offset: + if self.has_input(): + self.instance.SR &= ~SR.RFDF + self.instance.SR &= ~SR.RXCTR + return self.recv_from_user() + + return self.raw_read(offset, size) + + @QlPeripheral.monitor() + def write(self, offset, size, value): + if offset == self.struct.PUSHR.offset: + self.send_to_user(value & PUSHR.TXDATA) + + elif offset == self.struct.CTAR.offset: + self.instance.SR |= SR.TFFF + + self.raw_write(offset, size, value) + + def step(self): + if self.has_input(): + self.instance.SR |= SR.RFDF + self.instance.SR |= SR.RXCTR diff --git a/qiling/hw/spi/sam3xa_spi.py b/qiling/hw/spi/sam3xa_spi.py new file mode 100644 index 000000000..6b0f8af84 --- /dev/null +++ b/qiling/hw/spi/sam3xa_spi.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import ctypes + +from qiling.hw.peripheral import QlPeripheral +from qiling.hw.connectivity import QlConnectivityPeripheral +from qiling.hw.const.sam3xa_spi import SR, TDR + + +class SAM3xaSpi(QlConnectivityPeripheral): + class Type(ctypes.Structure): + """ Serial Peripheral Interface (SPI) """ + _fields_ = [ + ("CR" , ctypes.c_uint32), # Control Register + ("MR" , ctypes.c_uint32), # Mode Register + ("RDR" , ctypes.c_uint32), # Receive Data Register + ("TDR" , ctypes.c_uint32), # Transmit Data Register + ("SR" , ctypes.c_uint32), # Status Register + ("IER" , ctypes.c_uint32), # Interrupt Enable Register + ("IDR" , ctypes.c_uint32), # Interrupt Disable Register + ("IMR" , ctypes.c_uint32), # Interrupt Mask Register + ("Reserved1", ctypes.c_uint32 * 4), + ("CSR" , ctypes.c_uint32 * 4), # Chip Select Register + ("Reserved2", ctypes.c_uint32 * 41), + ("WPMR", ctypes.c_uint32), # Write Protection Control Register + ("WPSR", ctypes.c_uint32), # Write Protection Status Register + ] + + def __init__(self, ql, label, intn=None): + super().__init__(ql, label) + + self.intn = intn + self.instance = self.struct( + SR = SR.TDRE | SR.RDRF, + RDR = 0xff, + ) + + @QlPeripheral.monitor() + def read(self, offset, size): + if offset == self.struct.RDR.offset: + if self.has_input(): + return self.recv_from_user() + + return self.raw_read(offset, size) + + @QlPeripheral.monitor() + def write(self, offset, size, value): + if offset == self.struct.TDR.offset: + self.send_to_user(value & TDR.TD) + + self.raw_write(offset, size, value) \ No newline at end of file diff --git a/qiling/hw/spi/stm32f1xx_spi.py b/qiling/hw/spi/stm32f1xx_spi.py new file mode 100644 index 000000000..0f2aac688 --- /dev/null +++ b/qiling/hw/spi/stm32f1xx_spi.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import ctypes + +from qiling.hw.peripheral import QlPeripheral +from qiling.hw.connectivity import QlConnectivityPeripheral +from qiling.hw.const.stm32f4xx_spi import SPI_SR + + +class STM32F1xxSpi(QlConnectivityPeripheral): + class Type(ctypes.Structure): + """ the structure available in : + stm32f101xb + stm32f102xb + stm32f103xb + """ + + _fields_ = [ + ("CR1" , ctypes.c_uint32), + ("CR2" , ctypes.c_uint32), + ("SR" , ctypes.c_uint32), + ("DR" , ctypes.c_uint32), + ("CRCPR" , ctypes.c_uint32), + ("RXCRCR" , ctypes.c_uint32), + ("TXCRCR" , ctypes.c_uint32), + ("I2SCFGR", ctypes.c_uint32), + ] + + def __init__(self, ql, label, intn=None): + super().__init__(ql, label) + self.instance = self.struct( + CR1 = 0x00000000, + CR2 = 0x00000000, + SR = 0x0000000B, + DR = 0x0000000C, + CRCPR = 0x00000007, + RXCRCR = 0x00000000, + TXCRCR = 0x00000000, + I2SCFGR = 0x00000000, + ) + + self.intn = intn + + @QlPeripheral.monitor() + def read(self, offset: int, size: int) -> int: + if self.contain(self.struct.DR, offset, size): + if self.has_input(): + return self.recv_from_user() + + buf = ctypes.create_string_buffer(size) + ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) + data = int.from_bytes(buf.raw, byteorder='little') + + return data + + @QlPeripheral.monitor() + def write(self, offset: int, size: int, value: int): + if self.contain(self.struct.DR, offset, size): + self.send_to_user(value) + + else: + data = (value).to_bytes(size, 'little') + ctypes.memmove(ctypes.addressof(self.instance) + offset, data, size) + + def send_interrupt(self): + self.ql.hw.nvic.set_pending(self.intn) diff --git a/qiling/hw/spi/stm32f4xx_spi.py b/qiling/hw/spi/stm32f4xx_spi.py index 1b07fe18f..1d47e2ff7 100644 --- a/qiling/hw/spi/stm32f4xx_spi.py +++ b/qiling/hw/spi/stm32f4xx_spi.py @@ -52,10 +52,10 @@ class Type(ctypes.Structure): def __init__(self, ql, label, intn=None): super().__init__(ql, label) - self.spi = self.struct( + self.instance = self.struct( CR1 = 0x00000000, CR2 = 0x00000000, - SR = 0x0000000A, + SR = 0x0000000B, DR = 0x0000000C, CRCPR = 0x00000007, RXCRCR = 0x00000000, @@ -68,11 +68,12 @@ def __init__(self, ql, label, intn=None): @QlPeripheral.monitor() def read(self, offset: int, size: int) -> int: - if self.in_field(self.struct.DR, offset, size): - self.spi.SR &= ~SPI_SR.RXNE + if self.contain(self.struct.DR, offset, size): + if self.has_input(): + return self.recv_from_user() buf = ctypes.create_string_buffer(size) - ctypes.memmove(buf, ctypes.addressof(self.spi) + offset, size) + ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) data = int.from_bytes(buf.raw, byteorder='little') return data @@ -98,11 +99,10 @@ def write(self, offset: int, size: int, value: int): value &= SPI_I2SPR.RW_MASK data = (value).to_bytes(size, 'little') - ctypes.memmove(ctypes.addressof(self.spi) + offset, data, size) + ctypes.memmove(ctypes.addressof(self.instance) + offset, data, size) - if self.in_field(self.struct.DR, offset, size): - self.spi.SR |= SPI_SR.RXNE - self.send_to_user(self.spi.DR) + if self.contain(self.struct.DR, offset, size): + self.send_to_user(self.instance.DR) def send_interrupt(self): self.ql.hw.nvic.set_pending(self.intn) diff --git a/qiling/hw/timer/__init__.py b/qiling/hw/timer/__init__.py index cbd21e55d..320249830 100644 --- a/qiling/hw/timer/__init__.py +++ b/qiling/hw/timer/__init__.py @@ -3,10 +3,14 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # +from .sam3xa_tc import SAM3xaTc from .cm3_systick import CortexM3SysTick from .cm4_systick import CortexM4SysTick +from .stm32f1xx_tim import STM32F1xxTim from .stm32f4xx_rtc import STM32F4xxRtc from .stm32f4xx_tim import STM32F4xxTim from .gd32vf1xx_rtc import GD32VF1xxRtc from .gd32vf1xx_timer import GD32VF1xxTimer -from .sam3xa_wdt import SAM3xaWdt +from .mk64f12_ftm import MK64F12Ftm +from .mk64f12_osc import MK64F12Osc +from .mk64f12_rtc import MK64F12Rtc diff --git a/qiling/hw/timer/cm_systick.py b/qiling/hw/timer/cm_systick.py index 81e9bc465..2450f8d02 100644 --- a/qiling/hw/timer/cm_systick.py +++ b/qiling/hw/timer/cm_systick.py @@ -22,30 +22,32 @@ class Type(ctypes.Structure): def __init__(self, ql, label): super().__init__(ql, label) - self.systick = self.struct( + self.instance = self.struct( CALIB = 0xC0000000 ) def step(self): - if not self.systick.CTRL & SYSTICK_CTRL.ENABLE: + if not self.instance.CTRL & SYSTICK_CTRL.ENABLE: return - if self.systick.VAL <= 0: - self.systick.VAL = self.systick.LOAD - self.systick.CTRL |= SYSTICK_CTRL.COUNTFLAG - - if self.systick.CTRL & SYSTICK_CTRL.TICKINT: - self.ql.hw.nvic.set_pending(IRQ.SYSTICK) + if self.instance.VAL <= 0: + self.instance.CTRL |= SYSTICK_CTRL.COUNTFLAG + self.instance.VAL = self.instance.LOAD + else: - self.systick.VAL -= self.ratio + self.instance.VAL -= self.ratio + + if self.instance.VAL <= 0: + if self.instance.CTRL & SYSTICK_CTRL.TICKINT: + self.ql.hw.nvic.set_pending(IRQ.SYSTICK) @QlPeripheral.monitor() def read(self, offset: int, size: int) -> int: buf = ctypes.create_string_buffer(size) - ctypes.memmove(buf, ctypes.addressof(self.systick) + offset, size) + ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) if offset == self.struct.CTRL.offset: - self.systick.CTRL &= ~SYSTICK_CTRL.COUNTFLAG + self.instance.CTRL &= ~SYSTICK_CTRL.COUNTFLAG return int.from_bytes(buf.raw, byteorder='little') @QlPeripheral.monitor() @@ -58,7 +60,7 @@ def write(self, offset: int, size: int, value: int): # restart the timer if offset == self.struct.LOAD.offset: - self.systick.VAL = value + self.instance.VAL = value data = (value).to_bytes(size, 'little') - ctypes.memmove(ctypes.addressof(self.systick) + offset, data, size) + ctypes.memmove(ctypes.addressof(self.instance) + offset, data, size) diff --git a/qiling/hw/timer/gd32vf1xx_rtc.py b/qiling/hw/timer/gd32vf1xx_rtc.py index 9659d7f42..3f8d917ff 100644 --- a/qiling/hw/timer/gd32vf1xx_rtc.py +++ b/qiling/hw/timer/gd32vf1xx_rtc.py @@ -30,7 +30,7 @@ class Type(ctypes.Structure): def __init__(self, ql, label): super().__init__(ql, label) - self.rtc = self.struct( + self.instance = self.struct( INTEN = 0x00000000, CTL = 0x00000020, PSCH = 0x00000000, diff --git a/qiling/hw/timer/gd32vf1xx_timer.py b/qiling/hw/timer/gd32vf1xx_timer.py index 0cf731762..a644a3728 100644 --- a/qiling/hw/timer/gd32vf1xx_timer.py +++ b/qiling/hw/timer/gd32vf1xx_timer.py @@ -42,7 +42,7 @@ class Type(ctypes.Structure): def __init__(self, ql, label): super().__init__(ql, label) - self.timer = self.struct( + self.instance = self.struct( CTL0 = 0x00000000, CTL1 = 0x00000000, SMCFG = 0x00000000, diff --git a/qiling/hw/timer/mk64f12_ftm.py b/qiling/hw/timer/mk64f12_ftm.py new file mode 100644 index 000000000..10408a886 --- /dev/null +++ b/qiling/hw/timer/mk64f12_ftm.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + + +import ctypes +from typing import Optional +from qiling.core import Qiling + +from qiling.hw.peripheral import QlPeripheral +from qiling.hw.timer.timer import QlTimerPeripheral +from qiling.hw.const.mk64f12_ftm import MODE, SC + + +class Control(ctypes.Structure): + _fields_ = [ + ('CnSC', ctypes.c_uint32), # Channel (n) Status And Control + ('CnV' , ctypes.c_uint32), # Channel (n) Value + ] + + +class MK64F12Ftm(QlTimerPeripheral): + class Type(ctypes.Structure): + """ FlexTimer Module """ + _fields_ = [ + ("SC" , ctypes.c_uint32), # Status And Control + ("CNT" , ctypes.c_int32), # Counter + ("MOD" , ctypes.c_uint32), # Modulo + ("CONTROLS", Control * 8), + ("CNTIN" , ctypes.c_uint32), # Counter Initial Value + ("STATUS" , ctypes.c_uint32), # Capture And Compare Status + ("MODE" , ctypes.c_uint32), # Features Mode Selection + ("SYNC" , ctypes.c_uint32), # Synchronization + ("OUTINIT" , ctypes.c_uint32), # Initial State For Channels Output + ("OUTMASK" , ctypes.c_uint32), # Output Mask + ("COMBINE" , ctypes.c_uint32), # Function For Linked Channels + ("DEADTIME", ctypes.c_uint32), # Deadtime Insertion Control + ("EXTTRIG" , ctypes.c_uint32), # FTM External Trigger + ("POL" , ctypes.c_uint32), # Channels Polarity + ("FMS" , ctypes.c_uint32), # Fault Mode Status + ("FILTER" , ctypes.c_uint32), # Input Capture Filter Control + ("FLTCTRL" , ctypes.c_uint32), # Fault Control + ("QDCTRL" , ctypes.c_uint32), # Quadrature Decoder Control And Status + ("CONF" , ctypes.c_uint32), # Configuration + ("FLTPOL" , ctypes.c_uint32), # FTM Fault Input Polarity + ("SYNCONF" , ctypes.c_uint32), # Synchronization Configuration + ("INVCTRL" , ctypes.c_uint32), # FTM Inverting Control + ("SWOCTRL" , ctypes.c_uint32), # FTM Software Output Control + ("PWMLOAD" , ctypes.c_uint32), # FTM PWM Load + ] + + def __init__(self, ql, label, intn=None): + super().__init__(ql, label) + + self.intn = intn + + def step(self): + if self.instance.MODE & MODE.FTMEN and self.instance.SC & SC.CLKS: + if self.instance.CNT <= 0: + self.instance.CNT = 1000000 // ((self.instance.SC & SC.PS) + 1) + + else: + self.instance.CNT -= self.ratio + if self.instance.CNT <= 0: + self.ql.hw.nvic.set_pending(self.intn) diff --git a/qiling/hw/timer/mk64f12_osc.py b/qiling/hw/timer/mk64f12_osc.py new file mode 100644 index 000000000..545066ed9 --- /dev/null +++ b/qiling/hw/timer/mk64f12_osc.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import ctypes + +from qiling.hw.peripheral import QlPeripheral + +class MK64F12Osc(QlPeripheral): + class Type(ctypes.Structure): + """ Oscillator """ + _fields_ = [ + ("CR", ctypes.c_uint8), # OSC Control Register + ] diff --git a/qiling/hw/timer/mk64f12_rtc.py b/qiling/hw/timer/mk64f12_rtc.py new file mode 100644 index 000000000..d133dcce6 --- /dev/null +++ b/qiling/hw/timer/mk64f12_rtc.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import ctypes + +from qiling.hw.peripheral import QlPeripheral + + +class MK64F12Rtc(QlPeripheral): + class Type(ctypes.Structure): + """ Secure Real Time Clock """ + _fields_ = [ + ("TSR", ctypes.c_uint32), # RTC Time Seconds Register + ("TPR", ctypes.c_uint32), # RTC Time Prescaler Register + ("TAR", ctypes.c_uint32), # RTC Time Alarm Register + ("TCR", ctypes.c_uint32), # RTC Time Compensation Register + ("CR" , ctypes.c_uint32), # RTC Control Register + ("SR" , ctypes.c_uint32), # RTC Status Register + ("LR" , ctypes.c_uint32), # RTC Lock Register + ("IER", ctypes.c_uint32), # RTC Interrupt Enable Register + ("WAR", ctypes.c_uint32), # RTC Write Access Register + ("RAR", ctypes.c_uint32), # RTC Read Access Register + ] + + def __init__(self, ql, label, intn=None, seconds_intn=None): + super().__init__(ql, label) + + self.intn = intn \ No newline at end of file diff --git a/qiling/hw/timer/sam3xa_tc.py b/qiling/hw/timer/sam3xa_tc.py new file mode 100644 index 000000000..1d21914c3 --- /dev/null +++ b/qiling/hw/timer/sam3xa_tc.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import ctypes + +from qiling.hw.peripheral import QlPeripheral + + +class TcChannel(ctypes.Structure): + _fields_ = [ + ("CCR" , ctypes.c_uint32), # (TcChannel Offset: 0x0) Channel Control Register + ("CMR" , ctypes.c_uint32), # (TcChannel Offset: 0x4) Channel Mode Register + ("SMMR" , ctypes.c_uint32), # (TcChannel Offset: 0x8) Stepper Motor Mode Register + ("Reserved1", ctypes.c_uint32), # + ("CV" , ctypes.c_uint32), # (TcChannel Offset: 0x10) Counter Value + ("RA" , ctypes.c_uint32), # (TcChannel Offset: 0x14) Register A + ("RB" , ctypes.c_uint32), # (TcChannel Offset: 0x18) Register B + ("RC" , ctypes.c_uint32), # (TcChannel Offset: 0x1C) Register C + ("SR" , ctypes.c_uint32), # (TcChannel Offset: 0x20) Status Register + ("IER" , ctypes.c_uint32), # (TcChannel Offset: 0x24) Interrupt Enable Register + ("IDR" , ctypes.c_uint32), # (TcChannel Offset: 0x28) Interrupt Disable Register + ("IMR" , ctypes.c_uint32), # (TcChannel Offset: 0x2C) Interrupt Mask Register + ("Reserved2", ctypes.c_uint32 * 4), # + ] + +class SAM3xaTc(QlPeripheral): + """ SAM3XA_TC Timer Counter """ + class Type(ctypes.Structure): + _fields_ = [ + ("CHANNEL" , TcChannel * 3), # (Tc Offset: 0x0) channel = 0 .. 2 + ("BCR" , ctypes.c_uint32), # (Tc Offset: 0xC0) Block Control Register + ("BMR" , ctypes.c_uint32), # (Tc Offset: 0xC4) Block Mode Register + ("QIER" , ctypes.c_uint32), # (Tc Offset: 0xC8) QDEC Interrupt Enable Register + ("QIDR" , ctypes.c_uint32), # (Tc Offset: 0xCC) QDEC Interrupt Disable Register + ("QIMR" , ctypes.c_uint32), # (Tc Offset: 0xD0) QDEC Interrupt Mask Register + ("QISR" , ctypes.c_uint32), # (Tc Offset: 0xD4) QDEC Interrupt Status Register + ("FMR" , ctypes.c_uint32), # (Tc Offset: 0xD8) Fault Mode Register + ("Reserved1", ctypes.c_uint32 * 2), # + ("WPMR" , ctypes.c_uint32), # (Tc Offset: 0xE4) Write Protect Mode Register + ] + + def __init__(self, ql, label, intn): + super().__init__(ql, label) + + self.instance = self.struct() + self.intn = intn \ No newline at end of file diff --git a/qiling/hw/timer/stm32f1xx_tim.py b/qiling/hw/timer/stm32f1xx_tim.py new file mode 100644 index 000000000..9ad805fd9 --- /dev/null +++ b/qiling/hw/timer/stm32f1xx_tim.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + + +import ctypes + +from .stm32f4xx_tim import STM32F4xxTim + + +class STM32F1xxTim(STM32F4xxTim): + pass diff --git a/qiling/hw/timer/stm32f4xx_rtc.py b/qiling/hw/timer/stm32f4xx_rtc.py index 844469a7f..34cc91768 100644 --- a/qiling/hw/timer/stm32f4xx_rtc.py +++ b/qiling/hw/timer/stm32f4xx_rtc.py @@ -84,7 +84,7 @@ class Type(ctypes.Structure): def __init__(self, ql, label, wkup_intn=None, alarm_intn=None): super().__init__(ql, label) - self.rtc = self.struct( + self.instance = self.struct( DR = 0x00002101, ISR = 0x00000007, PRER = 0x007F00FF, @@ -97,7 +97,7 @@ def __init__(self, ql, label, wkup_intn=None, alarm_intn=None): @QlPeripheral.monitor() def read(self, offset: int, size: int) -> int: buf = ctypes.create_string_buffer(size) - ctypes.memmove(buf, ctypes.addressof(self.rtc) + offset, size) + ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) return int.from_bytes(buf.raw, byteorder='little') @QlPeripheral.monitor() @@ -113,16 +113,16 @@ def write(self, offset: int, size: int, value: int): RTC_ISR.RSF ]: if value & bitmask == 0: - self.rtc.ISR &= ~bitmask + self.instance.ISR &= ~bitmask - self.rtc.ISR = (self.rtc.ISR & ~RTC_ISR.INIT) | (value & RTC_ISR.INIT) + self.instance.ISR = (self.instance.ISR & ~RTC_ISR.INIT) | (value & RTC_ISR.INIT) return data = (value).to_bytes(size, 'little') - ctypes.memmove(ctypes.addressof(self.rtc) + offset, data, size) + ctypes.memmove(ctypes.addressof(self.instance) + offset, data, size) def step(self): - if self.rtc.ISR & RTC_ISR.INIT: - self.rtc.ISR |= RTC_ISR.INITF + if self.instance.ISR & RTC_ISR.INIT: + self.instance.ISR |= RTC_ISR.INITF - self.rtc.ISR |= RTC_ISR.RSF + self.instance.ISR |= RTC_ISR.RSF diff --git a/qiling/hw/timer/stm32f4xx_tim.py b/qiling/hw/timer/stm32f4xx_tim.py index fa0de5f9e..74ac613e7 100644 --- a/qiling/hw/timer/stm32f4xx_tim.py +++ b/qiling/hw/timer/stm32f4xx_tim.py @@ -66,66 +66,73 @@ class Type(ctypes.Structure): ] def __init__(self, ql: Qiling, label: str, - brk_tim9_intn: Optional[int] = None, + intn: Optional[int] = None, + brk_intn: Optional[int] = None, cc_intn: Optional[int] = None, - trg_com_tim11_intn: Optional[int] = None, - up_tim10_intn: Optional[int] = None): + trg_com_intn: Optional[int] = None, + up_intn: Optional[int] = None): super().__init__(ql, label) - self.brk_tim9_intn = brk_tim9_intn - self.cc_intn = cc_intn - self.trg_com_tim11_intn = trg_com_tim11_intn - self.up_tim10_intn = up_tim10_intn - + self.intn = intn + self.brk_intn = brk_intn if brk_intn else intn + self.cc_intn = cc_intn if cc_intn else intn + self.trg_com_intn = trg_com_intn if trg_com_intn else intn + self.up_intn = up_intn if up_intn else intn + + self.prescale_count = 0 - self.tim = self.struct() + self.instance = self.struct() @QlPeripheral.monitor() def read(self, offset: int, size: int) -> int: buf = ctypes.create_string_buffer(size) - ctypes.memmove(buf, ctypes.addressof(self.tim) + offset, size) + ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size) return int.from_bytes(buf.raw, byteorder='little') @QlPeripheral.monitor() def write(self, offset: int, size: int, value: int): data = (value).to_bytes(size, 'little') - ctypes.memmove(ctypes.addressof(self.tim) + offset, data, size) + ctypes.memmove(ctypes.addressof(self.instance) + offset, data, size) def send_update_interrupt(self): - if self.up_tim10_intn is None: + if self.up_intn is None: return - if not self.tim.DIER & TIM_DIER.UIE: + if not self.instance.DIER & TIM_DIER.UIE: return - self.tim.SR |= TIM_SR.UIF - self.ql.hw.nvic.set_pending(self.up_tim10_intn) + self.instance.SR |= TIM_SR.UIF + self.ql.hw.nvic.set_pending(self.up_intn) def set_ratio(self, ratio): - self.tim.CNT = 0 + self.instance.CNT = 0 self.prescale_count = 0 self._ratio = ratio @property def ratio(self): - return max(round(self._ratio / (self.tim.PSC + 1)), 1) + return max(round(self._ratio / (self.instance.PSC + 1)), 1) + + @ratio.setter + def ratio(self, value): + self.set_ratio(value) @property def prescale(self): - return max(round((self.tim.PSC + 1) / self._ratio) - 1, 0) + return max(round((self.instance.PSC + 1) / self._ratio) - 1, 0) def step(self): - if self.tim.CR1 & TIM_CR1.CEN: - if self.tim.CNT >= self.tim.ARR: - self.tim.CNT = 0 + if self.instance.CR1 & TIM_CR1.CEN: + if self.instance.CNT >= self.instance.ARR: + self.instance.CNT = 0 self.prescale_count = 0 self.send_update_interrupt() elif self.prescale_count == self.prescale: self.prescale_count = 0 - self.tim.CNT += self.ratio + self.instance.CNT += self.ratio else: self.prescale_count += 1 diff --git a/qiling/hw/timer/timer.py b/qiling/hw/timer/timer.py index c2b49464a..f3d5a005a 100644 --- a/qiling/hw/timer/timer.py +++ b/qiling/hw/timer/timer.py @@ -3,6 +3,7 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # +import ctypes from qiling.core import Qiling from qiling.hw.peripheral import QlPeripheral @@ -24,3 +25,10 @@ def ratio(self): @ratio.setter def ratio(self, value): self.set_ratio(value) + + def save(self): + return (self._ratio, bytes(self.instance)) + + def restore(self, data): + self._ratio, raw = data + ctypes.memmove(ctypes.addressof(self.instance), raw, len(raw)) diff --git a/qiling/hw/utils/access.py b/qiling/hw/utils/access.py index 04acd7de5..566374f46 100644 --- a/qiling/hw/utils/access.py +++ b/qiling/hw/utils/access.py @@ -8,14 +8,14 @@ from typing import List -class Op(IntEnum): +class Action(IntEnum): READ = 0 WRITE = 1 class Access: - def __init__(self, op: Op, offset: int, value: int = 0): - self.op = op + def __init__(self, action: Action, offset: int, value: int = 0): + self.action = action self.offset = offset self.value = value @@ -23,10 +23,10 @@ def __eq__(self, o: object) -> bool: if not isinstance(o, Access): return False - if self.op != o.op or self.offset != o.offset: + if self.action != o.action or self.offset != o.offset: return False - return True if self.op == Op.READ else self.value == o.value + return True if self.action == Action.READ else self.value == o.value class AccessSequence: diff --git a/qiling/loader/elf.py b/qiling/loader/elf.py index fba93a018..9a9e67694 100644 --- a/qiling/loader/elf.py +++ b/qiling/loader/elf.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # @@ -26,6 +26,7 @@ from qiling.os.linux.kernel_api.hook import * from qiling.os.linux.kernel_api.kernel_api import hook_sys_open, hook_sys_read, hook_sys_write + # auxiliary vector types # see: https://man7.org/linux/man-pages/man3/getauxval.3.html class AUXV(IntEnum): @@ -53,6 +54,7 @@ class AUXV(IntEnum): AT_HWCAP2 = 26 AT_EXECFN = 31 + # start area memory for API hooking # we will reserve 0x1000 bytes for this (which contains multiple slots of 4/8 bytes, each for one api) API_HOOK_MEM = 0x1000000 @@ -60,6 +62,7 @@ class AUXV(IntEnum): # memory for syscall table SYSCALL_MEM = API_HOOK_MEM + 0x1000 + class QlLoaderELF(QlLoader): def __init__(self, ql: Qiling): super().__init__(ql) @@ -77,16 +80,11 @@ def run(self): return - section = { - 32 : 'OS32', - 64 : 'OS64' - }[self.ql.arch.bits] - - self.profile = self.ql.os.profile[section] + self.profile = self.ql.os.profile[f'OS{self.ql.arch.bits}'] # setup program stack - stack_address = int(self.profile.get('stack_address'), 0) - stack_size = int(self.profile.get('stack_size'), 0) + stack_address = self.profile.getint('stack_address') + stack_size = self.profile.getint('stack_size') self.ql.mem.map(stack_address, stack_size, info='[stack]') self.path = self.ql.path @@ -110,7 +108,7 @@ def run(self): # is it a shared object? elif elftype == 'ET_DYN': - load_address = int(self.profile.get('load_address'), 0) + load_address = self.profile.getint('load_address') self.load_with_ld(elffile, stack_address + stack_size, load_address, self.argv, self.env) @@ -242,7 +240,7 @@ def load_elf_segments(elffile: ELFFile, load_address: int, info: str): # determine interpreter base address # some old interpreters may not be PIE: p_vaddr of the first LOAD segment is not zero # we should load interpreter at the address p_vaddr specified in such situation - interp_address = int(self.profile.get('interp_address'), 0) if min_vaddr == 0 else 0 + interp_address = self.profile.getint('interp_address') if min_vaddr == 0 else 0 self.ql.log.debug(f'Interpreter addr: {interp_address:#x}') # load interpreter segments data to memory @@ -255,7 +253,7 @@ def load_elf_segments(elffile: ELFFile, load_address: int, info: str): entry_point = interp_address + interp['e_entry'] # set mmap addr - mmap_address = int(self.profile.get('mmap_address'), 0) + mmap_address = self.profile.getint('mmap_address') self.ql.log.debug(f'mmap_address is : {mmap_address:#x}') # set info to be used by gdb @@ -658,7 +656,7 @@ def get_elfdata_mapping(self, elffile: ELFFile) -> bytes: # pick up loadable sections for sec in elffile.iter_sections(): if sec['sh_flags'] & SH_FLAGS.SHF_ALLOC: - # pad aggregated elf data to the offset of the current section + # pad aggregated elf data to the offset of the current section elfdata_mapping.extend(b'\x00' * (sec['sh_offset'] - len(elfdata_mapping))) # aggregate section data diff --git a/qiling/loader/macho.py b/qiling/loader/macho.py index 5c0e5c21a..a7e7f87bc 100644 --- a/qiling/loader/macho.py +++ b/qiling/loader/macho.py @@ -80,7 +80,6 @@ def __init__(self, ql, dyld_path=None): self.kext_name = os.path.splitext(basename)[0] filename = self.ql.argv self.ql._argv = [self.ql.argv[0] + "/Contents/MacOS/" + self.kext_name] - self.ql._path = self.ql.argv[0] self.plist = plistlib.load(open(filename[0] + "/Contents/Info.plist", "rb")) if "IOKitPersonalities" in self.plist: self.IOKit = True diff --git a/qiling/loader/mcu.py b/qiling/loader/mcu.py index 2daf8a21a..8a91d6334 100644 --- a/qiling/loader/mcu.py +++ b/qiling/loader/mcu.py @@ -17,6 +17,7 @@ def __init__(self, path): self.mem = [] self.segments = [] + self.base = 0 with open(path, 'r') as f: for line in f.read().splitlines(): self.parse_line(line.strip()) @@ -119,12 +120,6 @@ def load_env(self): alias = args['alias'] self.ql.hw.setup_remap(alias, base, size, info=f'[{name}]') - if memtype == 'bitband': - size = args['size'] * 32 - base = args['base'] - alias = args['alias'] - self.ql.hw.setup_bitband(base, alias, size, info=f'[{name}]') - if memtype == 'mmio': size = args['size'] base = args['base'] @@ -138,6 +133,6 @@ def run(self): self.load_env() ## Handle interrupt from instruction execution - self.ql.hook_intr(self.ql.arch.soft_interrupt_handler) + self.ql.hook_intr(self.ql.arch.unicorn_exception_handler) self.reset() diff --git a/qiling/os/dos/dos.py b/qiling/os/dos/dos.py index fb7f55c17..d1e3a85da 100644 --- a/qiling/os/dos/dos.py +++ b/qiling/os/dos/dos.py @@ -117,6 +117,3 @@ def run(self): except UcError: self.emu_error() raise - - if self.ql._internal_exception != None: - raise self.ql._internal_exception diff --git a/qiling/os/linux/function_hook.py b/qiling/os/linux/function_hook.py index aa2e6cf64..5e7c564d7 100644 --- a/qiling/os/linux/function_hook.py +++ b/qiling/os/linux/function_hook.py @@ -557,8 +557,9 @@ def __init__(self, ql, phoff, phnum, phentsize, load_base, hook_mem): # MIPS32 elif self.ql.arch.type == QL_ARCH.MIPS: - self.GLOB_DAT = 21 - self.JMP_SLOT = 22 + # ref: https://sites.uclouvain.be/SystInfo/usr/include/elf.h.html + self.GLOB_DAT = 51 + self.JMP_SLOT = 127 # add $t9, $t9, $zero ins = b' \xc8 \x03' self.add_function_hook = self.add_function_hook_mips @@ -982,4 +983,4 @@ def add_function_hook_mips(self, funcname, cb, pos, userdata = None): # self.hook_int = True def _load_import(self): - pass \ No newline at end of file + pass diff --git a/qiling/os/linux/linux.py b/qiling/os/linux/linux.py index 4198b2c35..959cf5ab5 100644 --- a/qiling/os/linux/linux.py +++ b/qiling/os/linux/linux.py @@ -3,6 +3,8 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # +from functools import partial + from unicorn import UcError from unicorn.x86_const import UC_X86_INS_SYSCALL @@ -15,12 +17,12 @@ from qiling.os.fcall import QlFunctionCall from qiling.os.const import * from qiling.os.linux.procfs import QlProcFS -from qiling.os.mapper import QlFsMappedCallable from qiling.os.posix.posix import QlOsPosix from . import futex from . import thread + class QlOsLinux(QlOsPosix): type = QL_OS.LINUX @@ -49,7 +51,6 @@ def __init__(self, ql: Qiling): self.elf_mem_start = 0x0 self.load() - def load(self): self.futexm = futex.QlLinuxFutexManagement() @@ -98,7 +99,7 @@ def load(self): self.ql.hook_insn(self.hook_syscall, UC_X86_INS_SYSCALL) # Keep test for _cc #self.ql.hook_insn(hook_posix_api, UC_X86_INS_SYSCALL) - self.thread_class = thread.QlLinuxX8664Thread + self.thread_class = thread.QlLinuxX8664Thread elif self.ql.arch.type == QL_ARCH.RISCV: self.ql.arch.enable_float() @@ -120,28 +121,24 @@ def load(self): if getattr(self.fd[i], 'close_on_exec', 0): self.fd[i] = None - def setup_procfs(self): - self.fs_mapper.add_fs_mapping(r'/proc/self/auxv', QlFsMappedCallable(QlProcFS.self_auxv, self)) - self.fs_mapper.add_fs_mapping(r'/proc/self/cmdline', QlFsMappedCallable(QlProcFS.self_cmdline, self)) - self.fs_mapper.add_fs_mapping(r'/proc/self/environ', QlFsMappedCallable(QlProcFS.self_environ, self)) - self.fs_mapper.add_fs_mapping(r'/proc/self/exe', QlFsMappedCallable(QlProcFS.self_exe, self)) - self.fs_mapper.add_fs_mapping(r'/proc/self/maps', QlFsMappedCallable(QlProcFS.self_map, self.ql.mem)) + self.fs_mapper.add_fs_mapping(r'/proc/self/auxv', partial(QlProcFS.self_auxv, self)) + self.fs_mapper.add_fs_mapping(r'/proc/self/cmdline', partial(QlProcFS.self_cmdline, self)) + self.fs_mapper.add_fs_mapping(r'/proc/self/environ', partial(QlProcFS.self_environ, self)) + self.fs_mapper.add_fs_mapping(r'/proc/self/exe', partial(QlProcFS.self_exe, self)) + self.fs_mapper.add_fs_mapping(r'/proc/self/maps', partial(QlProcFS.self_map, self.ql.mem)) def hook_syscall(self, ql, intno = None): return self.load_syscall() - def register_function_after_load(self, function): if function not in self.function_after_load_list: self.function_after_load_list.append(function) - def run_function_after_load(self): for f in self.function_after_load_list: f() - def run(self): # do not set-up procfs for drivers and shellcode if not self.ql.code and not self.ql.loader.is_driver: @@ -154,20 +151,22 @@ def run(self): if self.ql.code: self.ql.emu_start(self.entry_point, (self.entry_point + len(self.ql.code)), self.ql.timeout, self.ql.count) else: - if self.ql.multithread == True: + if self.ql.multithread: # start multithreading thread_management = thread.QlLinuxThreadManagement(self.ql) self.ql.os.thread_management = thread_management thread_management.run() else: - if self.ql.entry_point is not None: + if self.ql.entry_point is not None: self.ql.loader.elf_entry = self.ql.entry_point elif self.ql.loader.elf_entry != self.ql.loader.entry_point: entry_address = self.ql.loader.elf_entry - if self.ql.arch.type == QL_ARCH.ARM and entry_address & 1 == 1: - entry_address -= 1 + + if self.ql.arch.type == QL_ARCH.ARM: + entry_address &= ~1 + self.ql.emu_start(self.ql.loader.entry_point, entry_address, self.ql.timeout) self.ql.do_lib_patch() self.run_function_after_load() diff --git a/qiling/os/linux/procfs.py b/qiling/os/linux/procfs.py index 6166bf684..9fbf2a338 100644 --- a/qiling/os/linux/procfs.py +++ b/qiling/os/linux/procfs.py @@ -1,6 +1,6 @@ import io -from typing import TYPE_CHECKING, AnyStr, Optional, Sized +from typing import TYPE_CHECKING, AnyStr from qiling.os.mapper import QlFsMappedObject @@ -9,6 +9,16 @@ from qiling.os.memory import QlMemoryManager +class FsMappedStream(io.BytesIO): + """Wrap stream objects to make them look like a QlFsMappedObject. + """ + + def __init__(self, fname: str, *args) -> None: + super().__init__(*args) + + self.name = fname + + class QlProcFS: @staticmethod @@ -27,17 +37,15 @@ def self_auxv(os: 'QlOsLinux') -> QlFsMappedObject: auxv_data.extend(os.ql.mem.read(auxv_addr, nbytes)) auxv_addr += nbytes - - return io.BytesIO(bytes(auxv_data)) + return FsMappedStream(r'/proc/self/auxv', auxv_data) @staticmethod def self_cmdline(os: 'QlOsLinux') -> QlFsMappedObject: entries = (arg.encode('utf-8') for arg in os.ql.argv) cmdline = b'\x00'.join(entries) + b'\x00' - return io.BytesIO(cmdline) - + return FsMappedStream(r'/proc/self/cmdline', cmdline) @staticmethod def self_environ(os: 'QlOsLinux') -> QlFsMappedObject: @@ -50,22 +58,21 @@ def __to_bytes(s: AnyStr) -> bytes: entries = (b'='.join((__to_bytes(k), __to_bytes(v))) for k, v in os.ql.env.items()) environ = b'\x00'.join(entries) + b'\x00' - return io.BytesIO(environ) - + return FsMappedStream(r'/proc/self/environ', environ) @staticmethod def self_exe(os: 'QlOsLinux') -> QlFsMappedObject: with open(os.ql.path, 'rb') as exefile: content = exefile.read() - return io.BytesIO(content) - + return FsMappedStream(r'/proc/self/exe', content) + @staticmethod def self_map(mem: 'QlMemoryManager') -> QlFsMappedObject: - content = b"" + content = bytearray() mapinfo = mem.get_mapinfo() for lbound, ubound, perms, label, container in mapinfo: content += f"{lbound:x}-{ubound:x}\t{perms}p\t0\t00:00\t0\t{container if container else label}\n".encode("utf-8") - return io.BytesIO(content) + return FsMappedStream(r'/proc/self/map', content) diff --git a/qiling/os/linux/thread.py b/qiling/os/linux/thread.py index 46642ce64..0c3864bfd 100644 --- a/qiling/os/linux/thread.py +++ b/qiling/os/linux/thread.py @@ -91,7 +91,7 @@ def __init__(self, ql: Qiling, start_address: int, exit_point: int, context = No @property def ql(self): return self._ql - + @ql.setter def ql(self, q): self._ql = q @@ -107,15 +107,15 @@ def saved_context(self, ctx): @property def exit_point(self): return self._exit_point - + @exit_point.setter def exit_point(self, ep): self._exit_point = ep - + @property def start_address(self): return self._start_address - + @start_address.setter def start_address(self, sa): self._start_address = sa @@ -123,7 +123,7 @@ def start_address(self, sa): @property def status(self): return self._status - + @status.setter def status(self, s): self._status = s @@ -150,18 +150,18 @@ def id(self): def __hash__(self): return self.id - + def __str__(self): return f"[Thread {self.id}]" @property def set_child_tid_address(self): return self._set_child_tid_address - + @set_child_tid_address.setter def set_child_tid_address(self, addr): self._set_child_tid_address = addr - + @property def clear_child_tid_address(self): return self._clear_child_tid_address @@ -169,19 +169,19 @@ def clear_child_tid_address(self): @clear_child_tid_address.setter def clear_child_tid_address(self, addr): self._clear_child_tid_address = addr - + @property def robust_list_head_ptr(self): return self._robust_list_head_ptr - + @robust_list_head_ptr.setter def robust_list_head_ptr(self, p): self._robust_list_head_ptr = p - + @property def robust_list_head_len(self): return self._robust_list_head_len - + @robust_list_head_len.setter def robust_list_head_len(self, l): self._robust_list_head_len = l @@ -189,7 +189,7 @@ def robust_list_head_len(self, l): @property def sched_cb(self) -> Callable: return self._sched_cb - + @sched_cb.setter def sched_cb(self, cb): self._sched_cb = cb @@ -207,7 +207,7 @@ def _run(self): # Within both contexts, our program is single thread. # # The only fail safe: **Never give up control in Unicorn context.** - # + # # In Unicorn context, in other words, in Unicorn callbacks, we do: # - Implement non-blocking syscalls directly. # - Prepare sched_cb for non-unicorn context. @@ -219,7 +219,7 @@ def _run(self): self.ql.arch.regs.arch_pc = self.start_address if not self._saved_context: self.save() - + while self.status != THREAD_STATUS_TERMINATED: # Rewrite our status and the current thread. self.status = THREAD_STATUS_RUNNING @@ -235,18 +235,18 @@ def _run(self): # Run and log the run event start_address = getattr(self.ql.arch, 'effective_pc', self.ql.arch.regs.arch_pc) # For arm thumb. self.sched_cb = QlLinuxThread._default_sched_cb - + self.ql.log.debug(f"Scheduled from {hex(start_address)}.") try: # Known issue for timeout: https://github.com/unicorn-engine/unicorn/issues/1355 - self.ql.emu_start(start_address, self.exit_point, count=30000) + self.ql.emu_start(start_address, self.exit_point, count=31337) except UcError as e: self.ql.os.emu_error() self.ql.log.exception("") raise e self.ql.log.debug(f"Suspended at {hex(self.ql.arch.regs.arch_pc)}") self.save() - + # Note that this callback may be set by UC callbacks. # Some thought on this design: # 1. Never give up control during a UC callback. @@ -275,16 +275,16 @@ def restore(self): @abstractmethod def set_thread_tls(self, tls_addr): pass - + @abstractmethod def clone(self): # This is a workaround to implement our thread based on gevent greenlet. # Core idea: # A gevent greenlet can't re-run if it has finished _run method but our framework requires threads to be resumed anytime. Therefore, a workaround is to # use multiple greenlets to represent a single qiling thread. - # + # # Of course we can make the greenlet run forever and wait for notifications to resume but that would make the design much more complicated. - # + # # Caveat: # Don't use thread id to identify the thread object. new_thread = self.ql.os.thread_class.spawn(self._ql, self._start_address, self._exit_point, self._saved_context, set_child_tid_addr = None, thread_id = self._thread_id) @@ -435,7 +435,7 @@ def restore(self): self.restore_context() self.set_thread_tls(self.tls) self.ql.log.debug(f"Restored context: fs={hex(self.ql.arch.regs.fsbase)} tls={hex(self.tls)}") - + def clone(self): new_thread = super(QlLinuxX8664Thread, self).clone() new_thread.tls = self.tls @@ -458,7 +458,7 @@ def set_thread_tls(self, tls_addr): def save(self): self.save_context() self.tls = self.ql.arch.regs.cp0_userlocal - self.ql.log.debug(f"Saved context. cp0={hex(self.ql.arch.regs.cp0_userlocal)}") + self.ql.log.debug(f"Saved context. cp0={hex(self.ql.arch.regs.cp0_userlocal)}") def restore(self): self.restore_context() @@ -492,7 +492,7 @@ def restore(self): self.restore_context() self.set_thread_tls(self.tls) self.ql.log.debug(f"Restored context. c13_c0_3={hex(self.ql.arch.regs.c13_c0_3)}") - + def clone(self): new_thread = super(QlLinuxARMThread, self).clone() new_thread.tls = self.tls @@ -519,7 +519,7 @@ def restore(self): self.restore_context() self.set_thread_tls(self.tls) self.ql.log.debug(f"Restored context. tpidr_el0={hex(self.ql.arch.regs.tpidr_el0)}") - + def clone(self): new_thread = super(QlLinuxARM64Thread, self).clone() new_thread.tls = self.tls @@ -545,7 +545,7 @@ def cur_thread(self, ct): @property def main_thread(self): return self._main_thread - + @main_thread.setter def main_thread(self, mt): self._main_thread = mt @@ -570,12 +570,14 @@ def _clear_queued_msg(self): self.main_thread.log_file_fd.log(lvl, msg) except AttributeError: pass - + def _prepare_lib_patch(self): if self.ql.loader.elf_entry != self.ql.loader.entry_point: entry_address = self.ql.loader.elf_entry - if self.ql.arch.type == QL_ARCH.ARM and entry_address & 1 == 1: - entry_address -= 1 + + if self.ql.arch.type == QL_ARCH.ARM: + entry_address &= ~1 + self.main_thread = self.ql.os.thread_class.spawn(self.ql, self.ql.loader.entry_point, entry_address) self.cur_thread = self.main_thread self._clear_queued_msg() diff --git a/qiling/os/macos/macos.py b/qiling/os/macos/macos.py index eb7f38ee2..2c700e01f 100644 --- a/qiling/os/macos/macos.py +++ b/qiling/os/macos/macos.py @@ -216,6 +216,3 @@ def callback_ret(ql): raise self.RUN = False - - if self.ql._internal_exception != None: - raise self.ql._internal_exception \ No newline at end of file diff --git a/qiling/os/mapper.py b/qiling/os/mapper.py index bbc226b99..d6e8b170a 100644 --- a/qiling/os/mapper.py +++ b/qiling/os/mapper.py @@ -1,11 +1,10 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -import inspect import os -from typing import Any, MutableMapping, Union +from typing import Any, Callable, MutableMapping, Union from .path import QlOsPath from .filestruct import ql_file @@ -22,34 +21,34 @@ class QlFsMappedObject: def __init__(self): pass - + def read(self, expected_len): raise NotImplementedError("QlFsMappedObject method not implemented: read") - + def write(self, buffer): raise NotImplementedError("QlFsMappedObject method not implemented: write") - + def fileno(self): raise NotImplementedError("QlFsMappedObject method not implemented: fileno") - + def lseek(self, lseek_offset, lseek_origin): raise NotImplementedError("QlFsMappedObject method not implemented: lseek") - + def close(self): raise NotImplementedError("QlFsMappedObject method not implemented: close") - + def fstat(self): raise NotImplementedError("QlFsMappedObject method not implemented: fstat") - + def ioctl(self, ioctl_cmd, ioctl_arg): raise NotImplementedError("QlFsMappedObject method not implemented: ioctl") def tell(self): raise NotImplementedError("QlFsMappedObject method not implemented: tell") - + def dup(self): raise NotImplementedError("QlFsMappedObject method not implemented: dup") - + def readline(self, end = b'\n'): raise NotImplementedError("QlFsMappedObject method not implemented: readline") @@ -57,19 +56,7 @@ def readline(self, end = b'\n'): def name(self): raise NotImplementedError("QlFsMappedObject property not implemented: name") -# This is a helper class to allow users to pass any class to add_fs_mapper -# -# Everytime open is called on the mapped path, cls(*args, **kwargs) will be called. -class QlFsMappedCallable: - - def __init__(self, cls, *args, **kwargs) -> None: - self._args = args - self._kwargs = kwargs - self._cls = cls - - def __call__(self) -> QlFsMappedObject: - return self._cls(*self._args, **self._kwargs) - + class QlFsMapper: def __init__(self, path: QlOsPath): @@ -144,7 +131,7 @@ def _parse_path(self, p: Union[os.PathLike, str]) -> str: return p - def add_fs_mapping(self, ql_path: Union[os.PathLike, str], real_dest: Union[str, QlFsMappedObject, QlFsMappedCallable]) -> None: + def add_fs_mapping(self, ql_path: Union[os.PathLike, str], real_dest: Union[str, QlFsMappedObject, Callable]) -> None: """Map an object to Qiling emulated file system. Args: @@ -159,7 +146,7 @@ def add_fs_mapping(self, ql_path: Union[os.PathLike, str], real_dest: Union[str, real_dest = self._parse_path(real_dest) self._mapping[ql_path] = real_dest - + def remove_fs_mapping(self, ql_path: Union[os.PathLike, str]): """Remove a mapping from the fs mapper. diff --git a/qiling/os/mcu/mcu.py b/qiling/os/mcu/mcu.py index a2f8279a8..eed80a6d3 100644 --- a/qiling/os/mcu/mcu.py +++ b/qiling/os/mcu/mcu.py @@ -1,13 +1,86 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # +from typing import TYPE_CHECKING +from unicorn import UC_ERR_OK, UcError + from qiling.const import QL_OS from qiling.os.os import QlOs +from qiling.extensions.multitask import UnicornTask + +if TYPE_CHECKING: + from qiling import Qiling + + +class MCUTask(UnicornTask): + + def __init__(self, ql: 'Qiling', begin: int, end: int, task_id=None): + super().__init__(ql.uc, begin, end, task_id) + self.ql = ql + + def on_start(self): + # Don't save anything. + return None + + def on_interrupted(self, ucerr: int): + self._begin = self.pc + + # And don't restore anything. + if ucerr != UC_ERR_OK: + raise UcError(ucerr) + + self.ql.hw.step() + class QlOsMcu(QlOs): type = QL_OS.MCU + def __init__(self, ql: 'Qiling'): + self.ql = ql + self.runable = True + self.fast_mode = False + + def stop(self): + self.ql.emu_stop() + self.runable = False + def run(self): - pass + def current_pc() -> int: + if hasattr(self.ql.arch, 'effective_pc'): + return self.ql.arch.effective_pc + + return self.ql.arch.regs.arch_pc + + count = self.ql.count or 0 + end = self.ql.exit_point or -1 + timeout = self.ql.timeout or 0 + + if self.fast_mode: + if count != 0: + self.ql.log.warning("`count` means 'Stop after sceduling *count* times' in fast mode.") + + task = MCUTask(self.ql, current_pc(), end) + self.ql.uc.task_create(task) + self.ql.uc.tasks_start(count=count, timeout=timeout) + + else: + if timeout != 0: + self.ql.log.warning("Timeout is not supported in non-fast mode.") + + self.runable = True + self.counter = 0 + while self.runable: + current_address = current_pc() + + if current_address == end: + break + + self.ql.emu_start(current_address, 0, count=1) + self.ql.hw.step() + + self.counter += 1 + + if count == self.counter: + break diff --git a/qiling/os/memory.py b/qiling/os/memory.py index 21d461e65..a2f01a2f8 100644 --- a/qiling/os/memory.py +++ b/qiling/os/memory.py @@ -1,10 +1,12 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -import os, re -from typing import Any, Callable, Iterator, List, Mapping, MutableSequence, Optional, Pattern, Sequence, Tuple, Union +import bisect +import os +import re +from typing import Any, Callable, Iterator, List, Mapping, Optional, Pattern, Sequence, Tuple, Union from unicorn import UC_PROT_NONE, UC_PROT_READ, UC_PROT_WRITE, UC_PROT_EXEC, UC_PROT_ALL @@ -17,6 +19,7 @@ MmioReadCallback = Callable[[Qiling, int, int], int] MmioWriteCallback = Callable[[Qiling, int, int, int], None] + class QlMemoryManager: """ some ideas and code from: @@ -25,13 +28,13 @@ class QlMemoryManager: def __init__(self, ql: Qiling): self.ql = ql - self.map_info: MutableSequence[MapInfoEntry] = [] + self.map_info: List[MapInfoEntry] = [] self.mmio_cbs = {} bit_stuff = { - 64 : (1 << 64) - 1, - 32 : (1 << 32) - 1, - 16 : (1 << 20) - 1 # 20bit address line + 64: (1 << 64) - 1, + 32: (1 << 32) - 1, + 16: (1 << 20) - 1 # 20bit address line } if ql.arch.bits not in bit_stuff: @@ -91,8 +94,7 @@ def add_mapinfo(self, mem_s: int, mem_e: int, mem_p: int, mem_info: str, is_mmio is_mmio: memory range is mmio """ - self.map_info.append((mem_s, mem_e, mem_p, mem_info, is_mmio)) - self.map_info = sorted(self.map_info, key=lambda tp: tp[0]) + bisect.insort(self.map_info, (mem_s, mem_e, mem_p, mem_info, is_mmio)) def del_mapinfo(self, mem_s: int, mem_e: int): """Subtract a memory range from map. @@ -102,30 +104,33 @@ def del_mapinfo(self, mem_s: int, mem_e: int): mem_e: memory range end """ - tmp_map_info: MutableSequence[MapInfoEntry] = [] + overlap_ranges = [idx for idx, (lbound, ubound, _, _, _) in enumerate(self.map_info) if (mem_s < ubound) and (mem_e > lbound)] - for s, e, p, info, mmio in self.map_info: - if e <= mem_s: - tmp_map_info.append((s, e, p, info, mmio)) - continue + def __split_overlaps(): + for idx in overlap_ranges: + lbound, ubound, perms, label, is_mmio = self.map_info[idx] - if s >= mem_e: - tmp_map_info.append((s, e, p, info, mmio)) - continue + if lbound < mem_s: + yield (lbound, mem_s, perms, label, is_mmio) - if s < mem_s: - tmp_map_info.append((s, mem_s, p, info, mmio)) + if mem_e < ubound: + yield (mem_e, ubound, perms, label, is_mmio) - if s == mem_s: - pass + # indices of first and last overlapping ranges. since map info is always + # sorted, we know that all overlapping rages are consecutive, so i1 > i0 + i0 = overlap_ranges[0] + i1 = overlap_ranges[-1] - if e > mem_e: - tmp_map_info.append((mem_e, e, p, info, mmio)) + # create new entries by splitting overlapping ranges. + # this has to be done before removing overlapping entries + new_entries = tuple(__split_overlaps()) - if e == mem_e: - pass + # remove overlapping entries + del self.map_info[i0:i1 + 1] - self.map_info = tmp_map_info + # add new ones + for entry in new_entries: + bisect.insort(self.map_info, entry) def change_mapinfo(self, mem_s: int, mem_e: int, mem_p: Optional[int] = None, mem_info: Optional[str] = None): tmp_map_info: Optional[MapInfoEntry] = None @@ -295,8 +300,9 @@ def restore(self, mem_dict): for lbound, ubound, perms, label, read_cb, write_cb in mem_dict['mmio']: self.ql.log.debug(f"restoring mmio range: {lbound:#08x} {ubound:#08x} {label}") - #TODO: Handle overlapped MMIO? - self.map_mmio(lbound, ubound - lbound, read_cb, write_cb, info=label) + size = ubound - lbound + if not self.is_mapped(lbound, size): + self.map_mmio(lbound, size, read_cb, write_cb, info=label) def read(self, addr: int, size: int) -> bytearray: """Read bytes from memory. @@ -325,10 +331,10 @@ def read_ptr(self, addr: int, size: int = 0) -> int: size = self.ql.arch.pointersize __unpack = { - 1 : self.ql.unpack8, - 2 : self.ql.unpack16, - 4 : self.ql.unpack32, - 8 : self.ql.unpack64 + 1: self.ql.unpack8, + 2: self.ql.unpack16, + 4: self.ql.unpack32, + 8: self.ql.unpack64 }.get(size) if __unpack is None: @@ -360,10 +366,10 @@ def write_ptr(self, addr: int, value: int, size: int = 0) -> None: size = self.ql.arch.pointersize __pack = { - 1 : self.ql.pack8, - 2 : self.ql.pack16, - 4 : self.ql.pack32, - 8 : self.ql.pack64 + 1: self.ql.pack8, + 2: self.ql.pack16, + 4: self.ql.pack32, + 8: self.ql.pack64 }.get(size) if __pack is None: @@ -422,6 +428,24 @@ def unmap(self, addr: int, size: int) -> None: if (addr, addr + size) in self.mmio_cbs: del self.mmio_cbs[(addr, addr+size)] + def unmap_between(self, mem_s: int, mem_e: int) -> None: + """Reclaim any allocated memory region within the specified range. + + Args: + mem_s: range start + mem_s: range end (exclusive) + """ + + # map info is about to change during the unmapping loop, so we have to + # determine the relevant ranges beforehand + mapped = [(lbound, ubound) for lbound, ubound, _, _, _ in self.map_info if (mem_s < ubound) and (mem_e > lbound)] + + for lbound, ubound in mapped: + lbound = max(mem_s, lbound) + ubound = min(mem_e, ubound) + + self.unmap(lbound, ubound - lbound) + def unmap_all(self) -> None: """Reclaim the entire memory space. """ @@ -513,13 +537,16 @@ def find_free_space(self, size: int, minaddr: Optional[int] = None, maxaddr: Opt assert minaddr < maxaddr + if (maxaddr - minaddr) < size: + raise ValueError('search domain is too small') + # get gap ranges between mapped ones and memory bounds gaps_ubounds = tuple(lbound for lbound, _, _, _, _ in self.map_info) + (mem_ubound,) gaps_lbounds = (mem_lbound,) + tuple(ubound for _, ubound, _, _, _ in self.map_info) - gaps = zip(gaps_lbounds, gaps_ubounds) + gaps = ((lbound, ubound) for lbound, ubound in zip(gaps_lbounds, gaps_ubounds) if lbound < maxaddr and minaddr < ubound) for lbound, ubound in gaps: - addr = self.align_up(lbound, align) + addr = self.align_up(max(minaddr, lbound), align) end = addr + size # is aligned range within gap and satisfying min / max requirements? diff --git a/qiling/os/posix/const.py b/qiling/os/posix/const.py index 7340a758a..49aa56cd5 100644 --- a/qiling/os/posix/const.py +++ b/qiling/os/posix/const.py @@ -1,14 +1,9 @@ #!/usr/bin/env python3 -# -# Cross Platform and Multi Architecture Advanced Binary Emulation Framework # - -#!/usr/bin/env python3 -# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -from qiling.const import * +from enum import Flag # OS Threading Constants THREAD_EVENT_INIT_VAL = 0 @@ -33,7 +28,7 @@ 'SOCK_DCCP' : 0x6, 'SOCK_PACKET' : 0xa, 'SOCK_NONBLOCK' : 0x800, - 'SOCK_CLOEXEC' : 0x80000, + 'SOCK_CLOEXEC' : 0x80000, } linux_x86_socket_domain = { @@ -114,6 +109,45 @@ "IP_MULTICAST_ALL" : 0x0031, } +# https://github.com/torvalds/linux/blob/master/include/uapi/linux/tcp.h +linux_socket_tcp_options = { + "TCP_NODELAY" : 0x1, + "TCP_MAXSEG" : 0x2, + "TCP_CORK" : 0x3, + "TCP_KEEPIDLE" : 0x4, + "TCP_KEEPINTVL" : 0x5, + "TCP_KEEPCNT" : 0x6, + "TCP_SYNCNT" : 0x7, + "TCP_LINGER2" : 0x8, + "TCP_DEFER_ACCEPT" : 0x9, + "TCP_WINDOW_CLAMP" : 0xa, + "TCP_INFO" : 0xb, + "TCP_QUICKACK" : 0xc, + "TCP_CONGESTION" : 0xd, + "TCP_MD5SIG" : 0xe, + "TCP_THIN_LINEAR_TIMEOUTS" : 0x10, + "TCP_THIN_DUPACK" : 0x11, + "TCP_USER_TIMEOUT" : 0x12, + "TCP_REPAIR" : 0x13, + "TCP_REPAIR_QUEUE" : 0x14, + "TCP_QUEUE_SEQ" : 0x15, + "TCP_REPAIR_OPTIONS" : 0x16, + "TCP_FASTOPEN" : 0x17, + "TCP_TIMESTAMP" : 0x18, + "TCP_NOTSENT_LOWAT" : 0x19, + "TCP_CC_INFO" : 0x1a, + "TCP_SAVE_SYN" : 0x1b, + "TCP_SAVED_SYN" : 0x1c, + "TCP_REPAIR_WINDOW" : 0x1d, + "TCP_FASTOPEN_CONNECT" : 0x1e, + "TCP_ULP" : 0x1f, + "TCP_MD5SIG_EXT" : 0x20, + "TCP_FASTOPEN_KEY" : 0x21, + "TCP_FASTOPEN_NO_COOKIE" : 0x22, + "TCP_ZEROCOPY_RECEIVE" : 0x23, + "TCP_INQ" : 0x24, + "TCP_TX_DELAY" : 0x25, +} macos_socket_ip_options = { "IP_TOS" : 0x0003, @@ -178,7 +212,7 @@ 'SOCK_DCCP' : 0x6, 'SOCK_PACKET' : 0xa, 'SOCK_NONBLOCK' : 0x800, - 'SOCK_CLOEXEC' : 0x80000, + 'SOCK_CLOEXEC' : 0x80000, } @@ -248,13 +282,15 @@ linux_arm_socket_options = { "SO_DEBUG" : 0x0001, "SO_REUSEADDR" : 0x0002, - "SO_KEEPALIVE" : 0x0009, + "SO_TYPE" : 0x0003, + "SO_ERROR" : 0x0004, "SO_DONTROUTE" : 0x0005, "SO_BROADCAST" : 0x0006, - "SO_LINGER" : 0x000d, - "SO_OOBINLINE" : 0x000a, "SO_SNDBUF" : 0x0007, "SO_RCVBUF" : 0x0008, + "SO_KEEPALIVE" : 0x0009, + "SO_OOBINLINE" : 0x000a, + "SO_LINGER" : 0x000d, "SO_REUSEPORT" : 0x000f, "SO_SNDLOWAT" : 0x0013, "SO_RCVLOWAT" : 0x0012, @@ -343,6 +379,7 @@ "SO_REUSEADDR" : 0x0004, "SO_KEEPALIVE" : 0x0008, "SO_DONTROUTE" : 0x0010, + "SO_BINDTODEVICE" : 0x0019, "SO_BROADCAST" : 0x0020, "SO_LINGER" : 0x0080, "SO_OOBINLINE" : 0x0100, @@ -587,6 +624,104 @@ 'O_BINARY' : None } + +# see: https://github.com/torvalds/linux/blob/master/include/uapi/asm-generic/mman-common.h +class linux_mmap_flags(Flag): + MAP_FILE = 0x00000000 + MAP_SHARED = 0x00000001 + MAP_PRIVATE = 0x00000002 + + MAP_FIXED = 0x00000010 + MAP_ANONYMOUS = 0x00000020 + MAP_GROWSDOWN = 0x00000100 + MAP_DENYWRITE = 0x00000800 + MAP_EXECUTABLE = 0x00001000 + MAP_LOCKED = 0x00002000 + MAP_NORESERVE = 0x00004000 + MAP_POPULATE = 0x00008000 + MAP_NONBLOCK = 0x00010000 + MAP_STACK = 0x00020000 + MAP_HUGETLB = 0x00040000 + MAP_SYNC = 0x00080000 + MAP_FIXED_NOREPLACE = 0x00100000 + MAP_UNINITIALIZED = 0x04000000 + + +# see: https://github.com/freebsd/freebsd-src/blob/master/sys/sys/mman.h +class freebsd_mmap_flags(Flag): + MAP_FILE = 0x00000000 + MAP_SHARED = 0x00000001 + MAP_PRIVATE = 0x00000002 + + MAP_FIXED = 0x00000010 + MAP_STACK = 0x00000400 + MAP_NOSYNC = 0x00000800 + MAP_ANONYMOUS = 0x00001000 + MAP_GUARD = 0x00002000 + MAP_EXCL = 0x00004000 + MAP_NOCORE = 0x00020000 + + # define this alias for compatibility with other os flags + MAP_FIXED_NOREPLACE = MAP_EXCL + +# see: https://github.com/torvalds/linux/blob/master/arch/mips/include/uapi/asm/mman.h +class mips_mmap_flags(Flag): + MAP_FILE = 0x00000000 + MAP_SHARED = 0x00000001 + MAP_PRIVATE = 0x00000002 + + MAP_FIXED = 0x00000010 + MAP_NORESERVE = 0x00000400 + MAP_ANONYMOUS = 0x00000800 + MAP_GROWSDOWN = 0x00001000 + MAP_DENYWRITE = 0x00002000 + MAP_EXECUTABLE = 0x00004000 + MAP_LOCKED = 0x00008000 + MAP_POPULATE = 0x00010000 + MAP_NONBLOCK = 0x00020000 + MAP_STACK = 0x00040000 + MAP_HUGETLB = 0x00080000 + MAP_FIXED_NOREPLACE = 0x00100000 + + +# see: https://github.com/apple/darwin-xnu/blob/main/bsd/sys/mman.h +class macos_mmap_flags(Flag): + MAP_FILE = 0x00000000 + MAP_SHARED = 0x00000001 + MAP_PRIVATE = 0x00000002 + + MAP_FIXED = 0x00000010 + MAP_RENAME = 0x00000020 + MAP_NORESERVE = 0x00000040 + MAP_NOEXTEND = 0x00000100 + MAP_HASSEMAPHORE = 0x00000200 + MAP_NOCACHE = 0x00000400 + MAP_JIT = 0x00000800 + MAP_ANONYMOUS = 0x00001000 + + +# see: https://github.com/vocho/openqnx/blob/master/trunk/lib/c/public/sys/mman.h +class qnx_mmap_flags(Flag): + MAP_FILE = 0x00000000 + MAP_SHARED = 0x00000001 + MAP_PRIVATE = 0x00000002 + + MAP_FIXED = 0x00000010 + MAP_ELF = 0x00000020 + MAP_NOSYNCFILE = 0x00000040 + MAP_LAZY = 0x00000080 + MAP_STACK = 0x00001000 + MAP_BELOW = 0x00002000 + MAP_NOINIT = 0x00004000 + MAP_PHYS = 0x00010000 + MAP_NOX64K = 0x00020000 + MAP_BELOW16M = 0x00040000 + MAP_ANONYMOUS = 0x00080000 + MAP_SYSRAM = 0x01000000 + + # define this alias for compatibility with other os flags + MAP_UNINITIALIZED = MAP_NOINIT + # fcntl flags F_DUPFD = 0 F_GETFD = 1 diff --git a/qiling/os/posix/const_mapping.py b/qiling/os/posix/const_mapping.py index 99fb31ca5..2fcd2d3c2 100644 --- a/qiling/os/posix/const_mapping.py +++ b/qiling/os/posix/const_mapping.py @@ -1,40 +1,42 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -from typing import Mapping, MutableSequence +from typing import Mapping, TypeVar from qiling import Qiling from qiling.const import QL_ARCH, QL_OS from .const import * -def _invert_dict(d: Mapping) -> Mapping: - return { v:k for k, v in d.items()} +KT = TypeVar('KT') +VT = TypeVar('VT') + +def __invert_dict(d: Mapping[KT, VT]) -> Mapping[VT, KT]: + return {v: k for k, v in d.items()} -def _constant_mapping(bits: int, d_map: Mapping[str, int], ret: MutableSequence[str] = None, single_mapping: bool = False) -> str: - b_map = _invert_dict(d_map) - if single_mapping: - return b_map[bits] +def _constant_mapping(bits: int, consts_map: Mapping[str, int]) -> str: + return __invert_dict(consts_map)[bits] - if ret is None: - ret = [] - for val, sym in b_map.items(): - if val & bits: - bits ^= val - ret.append(sym) +def _flags_mapping(value: int, flags_map: Mapping[str, int]) -> str: + names = [] - if bits: - ret.append(f'{bits:#x}') + for name, flag in flags_map.items(): + if value & flag: + value ^= flag + names.append(name) - return " | ".join(ret) + if value: + names.append(f'{value:#x}') + return ' | '.join(names) -def ql_open_flag_mapping(ql: Qiling, flags): + +def ql_open_flag_mapping(ql: Qiling, flags: int) -> int: def flag_mapping(flags, mapping_name, mapping_from, mapping_to, host_os, virt_os): ret = 0 for n in mapping_name: @@ -77,14 +79,12 @@ def flag_mapping(flags, mapping_name, mapping_from, mapping_to, host_os, virt_os elif virt_os == QL_OS.QNX: f = qnx_arm64_open_flags - if host_os == QL_OS.LINUX: - t = linux_x86_open_flags - elif host_os == QL_OS.MACOS: - t = macos_x86_open_flags - elif host_os == QL_OS.FREEBSD: - t = freebsd_x86_open_flags - elif host_os == QL_OS.WINDOWS: - t = windows_x86_open_flags + t = { + QL_OS.LINUX: linux_x86_open_flags, + QL_OS.MACOS: macos_x86_open_flags, + QL_OS.FREEBSD: freebsd_x86_open_flags, + QL_OS.WINDOWS: windows_x86_open_flags + }.get(host_os, {}) if f == t: return flags @@ -108,106 +108,94 @@ def mmap_flag_mapping(flags): 'MAP_ANON' : 0x00080000, 'MAP_SYSRAM' : 0x01000000 } - return _constant_mapping(flags, mmap_flags) + + return _flags_mapping(flags, mmap_flags) -def mmap_prot_mapping(prots): - if prots == 0x0: +def mmap_prot_mapping(prots: int) -> str: + if prots == 0: return 'PROT_NONE' mmap_prots = { - 'PROT_READ' : 0x1, - 'PROT_WRITE': 0x2, - 'PROT_EXEC' : 0x4, + 'PROT_READ' : 0b001, + 'PROT_WRITE': 0b010, + 'PROT_EXEC' : 0b100, # not supported by unicorn 'PROT_GROWSDOWN' : 0x01000000, 'PROT_GROWSUP' : 0x02000000 } - return _constant_mapping(prots, mmap_prots) - - -def socket_type_mapping(t, archtype, ostype): - if ostype == QL_OS.MACOS: - socket_type_map = { - QL_ARCH.X8664: linux_x86_socket_types, - QL_ARCH.ARM64: linux_arm_socket_types, - }[archtype] - else: - socket_type_map = { - QL_ARCH.X86: linux_x86_socket_types, - QL_ARCH.X8664: linux_x86_socket_types, - QL_ARCH.ARM: linux_arm_socket_types, - QL_ARCH.ARM64: linux_arm_socket_types, - QL_ARCH.MIPS: linux_mips_socket_types, - }[archtype] + + return _flags_mapping(prots, mmap_prots) + + +def socket_type_mapping(t: int, archtype: QL_ARCH) -> str: + socket_type_map = { + QL_ARCH.X86: linux_x86_socket_types, + QL_ARCH.X8664: linux_x86_socket_types, + QL_ARCH.ARM: linux_arm_socket_types, + QL_ARCH.ARM64: linux_arm_socket_types, + QL_ARCH.MIPS: linux_mips_socket_types + }[archtype] # https://code.woboq.org/linux/linux/net/socket.c.html#1363 - t &= SOCK_TYPE_MASK - return _constant_mapping(t, socket_type_map, single_mapping=True) - -def socket_domain_mapping(p, archtype, ostype): - if ostype == QL_OS.MACOS: - socket_domain_map = { - QL_ARCH.X8664: macos_x86_socket_domain, - QL_ARCH.ARM64: linux_arm_socket_domain, - }[archtype] - else: - socket_domain_map = { - QL_ARCH.X86: linux_x86_socket_domain, - QL_ARCH.X8664: linux_x86_socket_domain, - QL_ARCH.ARM: linux_arm_socket_domain, - QL_ARCH.ARM64: linux_arm_socket_domain, - QL_ARCH.MIPS: linux_mips_socket_domain, - }[archtype] - return _constant_mapping(p, socket_domain_map, single_mapping=True) - -def socket_level_mapping(t, archtype, ostype): - if ostype == QL_OS.MACOS: - socket_level_map = { - QL_ARCH.X8664: linux_x86_socket_level, - QL_ARCH.ARM64: linux_arm_socket_level, - }[archtype] - else: - socket_level_map = { - QL_ARCH.X86: linux_x86_socket_level, - QL_ARCH.X8664: linux_x86_socket_level, - QL_ARCH.ARM: linux_arm_socket_level, - QL_ARCH.ARM64: linux_arm_socket_level, - QL_ARCH.MIPS: linux_mips_socket_level, - }[archtype] - return _constant_mapping(t, socket_level_map, single_mapping=True) - - -def socket_ip_option_mapping(t, archtype, ostype): - if ostype == QL_OS.MACOS: - socket_option_map = { - QL_ARCH.X8664: macos_socket_ip_options, - QL_ARCH.ARM64: macos_socket_ip_options, - }[archtype] - else: - socket_option_map = { - QL_ARCH.X86: linux_socket_ip_options, - QL_ARCH.X8664: linux_socket_ip_options, - QL_ARCH.ARM: linux_socket_ip_options, - QL_ARCH.ARM64: linux_socket_ip_options, - QL_ARCH.MIPS: linux_socket_ip_options, - }[archtype] - return _constant_mapping(t, socket_option_map, single_mapping=True) - - -def socket_option_mapping(t, archtype, ostype): - if ostype == QL_OS.MACOS: - socket_option_map = { - QL_ARCH.X8664: linux_x86_socket_options, - QL_ARCH.ARM64: linux_arm_socket_options, - }[archtype] - else: - socket_option_map = { - QL_ARCH.X86: linux_x86_socket_options, - QL_ARCH.X8664: linux_x86_socket_options, - QL_ARCH.ARM: linux_arm_socket_options, - QL_ARCH.ARM64: linux_arm_socket_options, - QL_ARCH.MIPS: linux_mips_socket_options, - }[archtype] - return _constant_mapping(t, socket_option_map, single_mapping=True) \ No newline at end of file + return _constant_mapping(t & SOCK_TYPE_MASK, socket_type_map) + + +def socket_domain_mapping(p: int, archtype: QL_ARCH, ostype: QL_OS) -> str: + socket_domain_map = { + QL_ARCH.X86: linux_x86_socket_domain, + QL_ARCH.X8664: macos_x86_socket_domain if ostype == QL_OS.MACOS else linux_x86_socket_domain, + QL_ARCH.ARM: linux_arm_socket_domain, + QL_ARCH.ARM64: linux_arm_socket_domain, + QL_ARCH.MIPS: linux_mips_socket_domain + }[archtype] + + return _constant_mapping(p, socket_domain_map) + + +def socket_tcp_option_mapping(t: int, archtype: QL_ARCH) -> str: + socket_option_map = { + QL_ARCH.X86: linux_socket_tcp_options, + QL_ARCH.X8664: linux_socket_tcp_options, + QL_ARCH.ARM: linux_socket_tcp_options, + QL_ARCH.ARM64: linux_socket_tcp_options, + QL_ARCH.MIPS: linux_socket_tcp_options, + }[archtype] + return _constant_mapping(t, socket_option_map) + + +def socket_level_mapping(t: int, archtype: QL_ARCH) -> str: + socket_level_map = { + QL_ARCH.X86: linux_x86_socket_level, + QL_ARCH.X8664: linux_x86_socket_level, + QL_ARCH.ARM: linux_arm_socket_level, + QL_ARCH.ARM64: linux_arm_socket_level, + QL_ARCH.MIPS: linux_mips_socket_level + }[archtype] + + return _constant_mapping(t, socket_level_map) + + +def socket_ip_option_mapping(t: int, archtype: QL_ARCH, ostype: QL_OS) -> str: + socket_option_map = { + QL_ARCH.X86: linux_socket_ip_options, + QL_ARCH.X8664: macos_socket_ip_options if ostype == QL_OS.MACOS else linux_socket_ip_options, + QL_ARCH.ARM: linux_socket_ip_options, + QL_ARCH.ARM64: macos_socket_ip_options if ostype == QL_OS.MACOS else linux_socket_ip_options, + QL_ARCH.MIPS: linux_mips_socket_ip_options + }[archtype] + + return _constant_mapping(t, socket_option_map) + + +def socket_option_mapping(t: int, archtype: QL_ARCH) -> str: + socket_option_map = { + QL_ARCH.X86: linux_x86_socket_options, + QL_ARCH.X8664: linux_x86_socket_options, + QL_ARCH.ARM: linux_arm_socket_options, + QL_ARCH.ARM64: linux_arm_socket_options, + QL_ARCH.MIPS: linux_mips_socket_options + }[archtype] + + return _constant_mapping(t, socket_option_map) diff --git a/qiling/os/posix/filestruct.py b/qiling/os/posix/filestruct.py index 0a1ef2a75..13a8fbeb3 100644 --- a/qiling/os/posix/filestruct.py +++ b/qiling/os/posix/filestruct.py @@ -3,7 +3,7 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # import os -from socket import socket, AddressFamily, SocketKind +from socket import socket, AddressFamily, SocketKind, socketpair from typing import Union try: @@ -40,6 +40,12 @@ def open(cls, domain: Union[AddressFamily, int], socktype: Union[SocketKind, int return cls(s) + @classmethod + def socketpair(cls, domain: Union[AddressFamily, int], socktype: Union[SocketKind, int], protocol: int): + a, b = socketpair(domain, socktype, protocol) + + return cls(a), cls(b) + def read(self, length: int) -> bytes: return os.read(self.__fd, length) diff --git a/qiling/os/posix/structs.py b/qiling/os/posix/structs.py new file mode 100644 index 000000000..71851af40 --- /dev/null +++ b/qiling/os/posix/structs.py @@ -0,0 +1,144 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# + +import ctypes + +from qiling.const import QL_ENDIAN +from qiling.os import struct + + +# FIXME: freebsd socket structures differ from the unix ones by specifying the +# sa_len and sa_family fields, one byte each, instead of using one short int +# for sa_family. +# +# using the sturcutres as they defined here causes freebsd socket structures to +# show high (hence unrecognized) values for sa_family. messing all sturctures +# with "if ql.os.type == QL_OS.FREEBSD" is a cumbersome workaround and not +# maintainable, let alone the code should also refer to sa_len and populate it +# appropriately. +# +# unfortunately, until there is an elegant implemetation that takes freebsd +# sockets into account freebsd sockets are broken. +# +# for more details: https://docs.freebsd.org/en/books/developers-handbook/sockets/ + + +def make_sockaddr(archbits: int, endian: QL_ENDIAN): + Struct = struct.get_aligned_struct(archbits, endian) + + class sockaddr(Struct): + _pack_ = 1 + + _fields_ = ( + ('sa_family', ctypes.c_uint16), + ) + + return sockaddr + + +def make_sockaddr_un(archbits: int, endian: QL_ENDIAN, pathlen: int): + Struct = struct.get_aligned_struct(archbits, endian) + + class sockaddr_un(Struct): + _fields_ = ( + ('sun_family', ctypes.c_int16), + ('sun_path', ctypes.c_char * pathlen) + ) + + return sockaddr_un + + +def make_sockaddr_in(archbits: int, endian: QL_ENDIAN): + Struct = struct.get_aligned_struct(archbits, endian) + + class in_addr(Struct): + _fields_ = ( + ('s_addr', ctypes.c_uint32), + ) + + class sockaddr_in(Struct): + _fields_ = ( + ('sin_family', ctypes.c_int16), + ('sin_port', ctypes.c_uint16), + ('sin_addr', in_addr), + ('sin_zero', ctypes.c_byte * 8) + ) + + return sockaddr_in + + +def make_sockaddr_in6(archbits: int, endian: QL_ENDIAN): + Struct = struct.get_aligned_struct(archbits, endian) + + class in6_addr(Struct): + _fields_ = ( + ('s6_addr', ctypes.c_uint8 * 16), + ) + + class sockaddr_in6(Struct): + _fields_ = ( + ('sin6_family', ctypes.c_int16), + ('sin6_port', ctypes.c_uint16), + ('sin6_flowinfo', ctypes.c_uint32), + ('sin6_addr', in6_addr), + ('sin6_scope_id', ctypes.c_uint32) + ) + + return sockaddr_in6 + + +def make_msghdr(archbits: int, endian: QL_ENDIAN): + Struct = struct.get_aligned_struct(archbits, endian) + + class msghdr(Struct): + _fields_ = ( + ('msg_name', ctypes.c_uint64), + ('msg_namelen', ctypes.c_int32), + ('msg_iov', ctypes.c_uint64), + ('msg_iovlen', ctypes.c_int32), + ('msg_control', ctypes.c_uint64), + ('msg_controllen', ctypes.c_int32), + ('msg_flags', ctypes.c_int32) + ) + + return msghdr + + +def make_cmsghdr(archbits: int, endian: QL_ENDIAN): + Struct = struct.get_aligned_struct(archbits, endian) + + class cmsghdr(Struct): + _fields_ = ( + ('cmsg_len', ctypes.c_int32), + ('cmsg_level', ctypes.c_int32), + ('cmsg_type', ctypes.c_int32) + ) + + return cmsghdr + + +def make_iovec(archbits: int, endian: QL_ENDIAN): + Struct = struct.get_aligned_struct(archbits, endian) + + class iovec(Struct): + _fields_ = ( + ('iov_base', ctypes.c_uint64), + ('iov_len', ctypes.c_uint64) + ) + + return iovec + + +def make_pollfd(archbits: int, endian: QL_ENDIAN): + Struct = struct.get_aligned_struct(archbits, endian) + + class pollfd(Struct): + _fields_ = ( + ('fd', ctypes.c_int32), + ('events', ctypes.c_int16), + ('revents', ctypes.c_int16) + ) + + return pollfd diff --git a/qiling/os/posix/syscall/fcntl.py b/qiling/os/posix/syscall/fcntl.py index 54b00555e..bca208863 100644 --- a/qiling/os/posix/syscall/fcntl.py +++ b/qiling/os/posix/syscall/fcntl.py @@ -150,7 +150,8 @@ def ql_syscall_fcntl(ql: Qiling, fd: int, cmd: int, arg: int): regreturn = f.fcntl(cmd, arg) elif cmd == F_SETFL: - f.fcntl(cmd, arg) + flags = ql_open_flag_mapping(ql, arg) + f.fcntl(cmd, flags) regreturn = 0 else: diff --git a/qiling/os/posix/syscall/mman.py b/qiling/os/posix/syscall/mman.py index 5e3eae0bf..6d80a74e1 100755 --- a/qiling/os/posix/syscall/mman.py +++ b/qiling/os/posix/syscall/mman.py @@ -4,30 +4,50 @@ # import os +import re +from enum import IntFlag +from typing import Optional from qiling import Qiling +from qiling.const import QL_ARCH, QL_OS from qiling.exception import QlMemoryMappedError from qiling.os.filestruct import ql_file from qiling.os.posix.const_mapping import * -def ql_syscall_munmap(ql: Qiling, addr: int, length: int): - - # get all mapped fd with flag MAP_SHARED and we definitely dont want to wipe out share library - mapped_fd = [fd for fd in ql.os.fd if fd != 0 and isinstance(fd, ql_file) and fd._is_map_shared and not (fd.name.endswith(".so") or fd.name.endswith(".dylib"))] - if mapped_fd: - all_mem_info = [_mem_info for _, _, _, _mem_info in ql.mem.map_info if _mem_info not in ("[mapped]", "[stack]", "[hook_mem]")] - - for _fd in mapped_fd: - if _fd.name in [each.split()[-1] for each in all_mem_info]: - ql.log.debug("Flushing file: %s" % _fd.name) - # flushes changes to disk file - _buff = ql.mem.read(addr, length) - _fd.lseek(_fd._mapped_offset) - _fd.write(_buff) +def ql_syscall_munmap(ql: Qiling, addr: int, length: int): + try: + # find addr's enclosing memory range + label = next(label for lbound, ubound, _, label, _ in ql.mem.get_mapinfo() if (lbound <= addr < ubound) and label.startswith(('[mmap]', '[mmap anonymous]'))) + except StopIteration: + # nothing to do; cannot munmap what was not originally mmapped + ql.log.debug(f'munmap: enclosing area for {addr:#x} was not mmapped') + else: + # extract the filename from the label by removing the boxed prefix + fname = re.sub(r'^\[.+\]\s*', '', label) - length = ((length + 0x1000 - 1) // 0x1000) * 0x1000 - ql.mem.unmap(addr, length) + # if this is an anonymous mapping, there is no trailing file name + if fname: + try: + # find the file that was originally mmapped into this region, to flush the changes. + # if the fd was already closed, there is nothing left to do + fd = next(fd for fd in ql.os.fd if isinstance(fd, ql_file) and os.path.basename(fd.name) == fname) + except StopIteration: + ql.log.debug(f'munmap: could not find matching fd, it might have been closed') + else: + # flushing memory contents to file is required only if mapping is shared / not private + if fd._is_map_shared: + ql.log.debug(f'munmap: flushing "{fname}"') + content = ql.mem.read(addr, length) + + fd.lseek(fd._mapped_offset) + fd.write(content) + + # unmap the enclosing memory region + lbound = ql.mem.align(addr) + ubound = ql.mem.align_up(addr + length) + + ql.mem.unmap(lbound, ubound - lbound) return 0 @@ -52,111 +72,146 @@ def ql_syscall_mprotect(ql: Qiling, start: int, mlen: int, prot: int): return 0 -def syscall_mmap_impl(ql: Qiling, addr: int, mlen: int, prot: int, flags: int, fd: int, pgoffset: int, ver: int): - MAP_FAILED = -1 - MAP_SHARED = 0x01 - MAP_FIXED = 0x10 - MAP_ANONYMOUS = 0x20 +def syscall_mmap_impl(ql: Qiling, addr: int, length: int, prot: int, flags: int, fd: int, pgoffset: int, ver: int): + def __select_mmap_flags(archtype: QL_ARCH, ostype: QL_OS): + """The mmap flags definitions differ between operating systems and architectures. + This method provides the apropriate flags set based on those properties. + """ + + osflags = { + QL_OS.LINUX: mips_mmap_flags if archtype == QL_ARCH.MIPS else linux_mmap_flags, + QL_OS.FREEBSD: freebsd_mmap_flags, + QL_OS.MACOS: macos_mmap_flags, + QL_OS.QNX: qnx_mmap_flags # FIXME: only for arm? + }[ostype] + + class mmap_flags(IntFlag): + MAP_FILE = osflags.MAP_FILE.value + MAP_SHARED = osflags.MAP_SHARED.value + MAP_FIXED = osflags.MAP_FIXED.value + MAP_ANONYMOUS = osflags.MAP_ANONYMOUS.value + + # the following flags do not exist on all flags sets. + # if not exists, set it to 0 so it would fail all bitwise-and checks + MAP_FIXED_NOREPLACE = osflags.MAP_FIXED_NOREPLACE.value if hasattr(osflags, 'MAP_FIXED_NOREPLACE') else 0 + MAP_UNINITIALIZED = osflags.MAP_UNINITIALIZED.value if hasattr(osflags, 'MAP_UNINITIALIZED') else 0 + + return mmap_flags + + api_name = ('old_mmap', 'mmap', 'mmap2')[ver] + mmap_flags = __select_mmap_flags(ql.arch.type, ql.os.type) pagesize = ql.mem.pagesize - api_name = { - 0 : 'old_mmap', - 1 : 'mmap', - 2 : 'mmap2' - }[ver] + mapping_size = ql.mem.align_up(length + (addr & (pagesize - 1))) + + ################################ + # determine mapping boundaries # + ################################ + + # as opposed to other systems, QNX allows specifying an unaligned base address + # for fixed mappings. to keep it consistent across all systems we allocate the + # enclosing pages of the requested area, while returning the requested fixed + # base address. + # + # to help track this, we use the following variables: + # addr : the address that becomes available, from program point of view + # lbound : lower bound of actual mapping range (aligned to page) + # ubound : upper bound of actual mapping range (aligned to page) + # mapping_size : actual mapping range size + # + # note that on non-QNX systems addr and lbound are equal. + # + # for example, assume requested base address and length are 0x774ec8d8 and 0x1800 + # respectively, then we allocate 3 pages as follows: + # [align(0x7700c8d8), align_up(0x7700c8d8 + 0x1800)] -> [0x7700c000, 0x7700f000] + + # if mapping is fixed, use the base address as-is + if flags & (mmap_flags.MAP_FIXED | mmap_flags.MAP_FIXED_NOREPLACE): + # on non-QNX systems, base must be aligned to page boundary + if addr & (pagesize - 1) and ql.os.type != QL_OS.QNX: + return -1 # errno: EINVAL + + # if not, use the base address as a hint but always above or equal to + # the value specified in /proc/sys/vm/mmap_min_addr (here: mmap_address) + else: + addr = ql.mem.find_free_space(mapping_size, max(addr, ql.loader.mmap_address)) + + # on non-QNX systems addr is already aligned to page boundary + lbound = ql.mem.align(addr) + ubound = lbound + mapping_size + + ################################## + # make sure memory can be mapped # + ################################## + + if flags & mmap_flags.MAP_FIXED_NOREPLACE: + if not ql.mem.is_available(lbound, mapping_size): + return -1 # errno: EEXIST - if ql.arch.bits == 64: - fd = ql.unpack64(ql.pack64(fd)) + elif flags & mmap_flags.MAP_FIXED: + ql.log.debug(f'{api_name}: unmapping memory between {lbound:#x}-{ubound:#x} to make room for fixed mapping') + ql.mem.unmap_between(lbound, ubound) - elif ql.arch.type == QL_ARCH.MIPS: - MAP_ANONYMOUS = 2048 - if ver == 2: - pgoffset = pgoffset * pagesize + ############################# + # determine mapping content # + ############################# - elif ql.arch.type == QL_ARCH.ARM and ql.os.type == QL_OS.QNX: - MAP_ANONYMOUS = 0x00080000 - fd = ql.unpack32s(ql.pack32s(fd)) + if flags & mmap_flags.MAP_ANONYMOUS: + data = b'' if flags & mmap_flags.MAP_UNINITIALIZED else b'\x00' * length + label = '[mmap anonymous]' else: - fd = ql.unpack32s(ql.pack32(fd)) - if ver == 2: - pgoffset = pgoffset * pagesize + fd = ql.unpacks(ql.pack(fd)) - need_mmap = True - mmap_base = addr - mmap_size = ql.mem.align_up(mlen - (addr & (pagesize - 1))) + if fd not in range(NR_OPEN): + return -1 # errno: EBADF - if ql.os.type != QL_OS.QNX: - mmap_base = ql.mem.align(mmap_base) + f: Optional[ql_file] = ql.os.fd[fd] - if (flags & MAP_FIXED) and mmap_base != addr: - return MAP_FAILED + if f is None: + return -1 # errno: EBADF - # initial ql.loader.mmap_address - if mmap_base != 0 and ql.mem.is_mapped(mmap_base, mmap_size): - if (flags & MAP_FIXED) > 0: - ql.log.debug("%s - MAP_FIXED, mapping not needed" % api_name) - try: - ql.mem.protect(mmap_base, mmap_size, prot) - except Exception as e: - ql.log.debug(e) - raise QlMemoryMappedError("Error: change protection at: 0x%x - 0x%x" % (mmap_base, mmap_base + mmap_size - 1)) - need_mmap = False - else: - mmap_base = 0 - - # initialized mapping - if need_mmap: - if mmap_base == 0: - mmap_base = ql.loader.mmap_address - ql.loader.mmap_address = mmap_base + mmap_size - ql.log.debug("%s - mapping needed for 0x%x" % (api_name, mmap_base)) - try: - ql.mem.map(mmap_base, mmap_size, prot, "[syscall_%s]" % api_name) - except Exception as e: - raise QlMemoryMappedError("Error: mapping needed but failed") - ql.log.debug("%s - addr range 0x%x - 0x%x: " % (api_name, mmap_base, mmap_base + mmap_size - 1)) - - # FIXME: MIPS32 Big Endian - try: - ql.mem.write(mmap_base, b'\x00' * mmap_size) - except Exception as e: - raise QlMemoryMappedError("Error: trying to zero memory") + # set mapping properties for future unmap + f._is_map_shared = bool(flags & mmap_flags.MAP_SHARED) + f._mapped_offset = pgoffset - if ((flags & MAP_ANONYMOUS) == 0) and fd in range(NR_OPEN): - f = ql.os.fd[fd] + fname = f.name - if f is not None: - f.seek(pgoffset) - data = f.read(mlen) - mem_info = str(f.name) - f._is_map_shared = flags & MAP_SHARED - f._mapped_offset = pgoffset - ql.log.debug("mem write : " + hex(len(data))) - ql.log.debug("mem mmap : " + mem_info) + if isinstance(fname, bytes): + fname = fname.decode() - ql.mem.change_mapinfo(mmap_base, mmap_base + mmap_size, mem_info=f'[{api_name}] {os.path.basename(mem_info)}') - try: - ql.mem.write(mmap_base, data) - except Exception as e: - ql.log.debug(e) - raise QlMemoryMappedError("Error: trying to write memory: ") + f.seek(pgoffset) + + data = f.read(length) + label = f'[mmap] {os.path.basename(fname)}' + + try: + # finally, we have everything we need to map the memory. + # + # we have to map it first as writeable so we can write data in it. + # permissions are adjusted afterwards with protect. + ql.mem.map(lbound, mapping_size, info=label) + except QlMemoryMappedError: + ql.log.debug(f'{api_name}: out of memory') + return -1 # errono: ENOMEM + else: + if data: + ql.mem.write(addr, data) - return mmap_base + ql.mem.protect(lbound, mapping_size, prot) + + return addr def ql_syscall_old_mmap(ql: Qiling, struct_mmap_args: int): # according to the linux kernel this is only for the ia32 compatibility - def __read_int(address: int) -> int: - return ql.unpack32(ql.mem.read(address, 4)) - - addr = __read_int(struct_mmap_args + 0 * 4) - length = __read_int(struct_mmap_args + 1 * 4) - prot = __read_int(struct_mmap_args + 2 * 4) - flags = __read_int(struct_mmap_args + 3 * 4) - fd = __read_int(struct_mmap_args + 4 * 4) - offset = __read_int(struct_mmap_args + 5 * 4) + addr = ql.mem.read_ptr(struct_mmap_args + 0 * 4, 4) + length = ql.mem.read_ptr(struct_mmap_args + 1 * 4, 4) + prot = ql.mem.read_ptr(struct_mmap_args + 2 * 4, 4) + flags = ql.mem.read_ptr(struct_mmap_args + 3 * 4, 4) + fd = ql.mem.read_ptr(struct_mmap_args + 4 * 4, 4) + offset = ql.mem.read_ptr(struct_mmap_args + 5 * 4, 4) return syscall_mmap_impl(ql, addr, length, prot, flags, fd, offset, 0) @@ -166,8 +221,12 @@ def ql_syscall_mmap(ql: Qiling, addr: int, length: int, prot: int, flags: int, f def ql_syscall_mmap2(ql: Qiling, addr: int, length: int, prot: int, flags: int, fd: int, pgoffset: int): + if ql.os.type != QL_OS.QNX: + pgoffset *= ql.mem.pagesize + return syscall_mmap_impl(ql, addr, length, prot, flags, fd, pgoffset, 2) + def ql_syscall_shmget(ql: Qiling, key: int, size: int, shmflg: int): if shmflg & IPC_CREAT: if shmflg & IPC_EXCL: @@ -181,6 +240,7 @@ def ql_syscall_shmget(ql: Qiling, key: int, size: int, shmflg: int): if key not in ql.os._shms: return ENOENT + def ql_syscall_shmat(ql: Qiling, shmid: int, shmaddr: int, shmflg: int): # shmid == key # dummy implementation diff --git a/qiling/os/posix/syscall/net.py b/qiling/os/posix/syscall/net.py index 01dd7c0e8..3576f900a 100644 --- a/qiling/os/posix/syscall/net.py +++ b/qiling/os/posix/syscall/net.py @@ -3,57 +3,69 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -from typing import Callable, Mapping, Tuple +import inspect +from enum import IntEnum +from typing import Callable, Mapping from qiling import Qiling -from qiling.os.posix.syscall.socket import ql_syscall_socket, ql_syscall_connect, ql_syscall_recv, ql_syscall_send, ql_syscall_bind, ql_syscall_listen, ql_syscall_accept, ql_syscall_getsockname, ql_syscall_setsockopt, ql_syscall_recvfrom, ql_syscall_sendto +from qiling.os.posix.syscall.socket import * + + +class SOCKETCALL(IntEnum): + SYS_SOCKET = 1 + SYS_BIND = 2 + SYS_CONNECT = 3 + SYS_LISTEN = 4 + SYS_ACCEPT = 5 + SYS_GETSOCKNAME = 6 + SYS_GETPEERNAME = 7 + SYS_SOCKETPAIR = 8 + SYS_SEND = 9 + SYS_RECV = 10 + SYS_SENDTO = 11 + SYS_RECVFROM = 12 + SYS_SHUTDOWN = 13 + SYS_SETSOCKOPT = 14 + SYS_GETSOCKOPT = 15 + SYS_SENDMSG = 16 + SYS_RECVMSG = 17 + SYS_ACCEPT4 = 18 + SYS_RECVMMSG = 19 + SYS_SENDMMSG = 20 + def ql_syscall_socketcall(ql: Qiling, call: int, args: int): - SOCKETCALL_SYS_SOCKET = 1 - SOCKETCALL_SYS_BIND = 2 - SOCKETCALL_SYS_CONNECT = 3 - SOCKETCALL_SYS_LISTEN = 4 - SOCKETCALL_SYS_ACCEPT = 5 - SOCKETCALL_SYS_GETSOCKNAME = 6 - SOCKETCALL_SYS_GETPEERNAME = 7 - SOCKETCALL_SYS_SOCKETPAIR = 8 - SOCKETCALL_SYS_SEND = 9 - SOCKETCALL_SYS_RECV = 10 - SOCKETCALL_SYS_SENDTO = 11 - SOCKETCALL_SYS_RECVFROM = 12 - SOCKETCALL_SYS_SHUTDOWN = 13 - SOCKETCALL_SYS_SETSOCKOPT = 14 - SOCKETCALL_SYS_GETSOCKOPT = 15 - SOCKETCALL_SYS_SENDMSG = 16 - SOCKETCALL_SYS_RECVMSG = 17 - SOCKETCALL_SYS_ACCEPT4 = 18 - SOCKETCALL_SYS_RECVMMSG = 19 - SOCKETCALL_SYS_SENDMMSG = 20 - - # map call values to their corresponding handlers and number of arguments they - # should read from the specified base pointer - handlers: Mapping[int, Tuple[Callable, int]] = { - SOCKETCALL_SYS_SOCKET : (ql_syscall_socket, 3), - SOCKETCALL_SYS_CONNECT : (ql_syscall_connect, 3), - SOCKETCALL_SYS_SEND : (ql_syscall_send, 4), - SOCKETCALL_SYS_RECVFROM : (ql_syscall_recvfrom, 6), - SOCKETCALL_SYS_SENDTO : (ql_syscall_sendto, 6), - SOCKETCALL_SYS_RECV : (ql_syscall_recv, 4), - SOCKETCALL_SYS_BIND : (ql_syscall_bind, 3), - SOCKETCALL_SYS_LISTEN : (ql_syscall_listen, 2), - SOCKETCALL_SYS_ACCEPT : (ql_syscall_accept, 3), - SOCKETCALL_SYS_GETSOCKNAME : (ql_syscall_getsockname, 3), - SOCKETCALL_SYS_SETSOCKOPT : (ql_syscall_setsockopt, 5) + # map call values to their corresponding handlers + handlers: Mapping[SOCKETCALL, Callable] = { + SOCKETCALL.SYS_SOCKET: ql_syscall_socket, + SOCKETCALL.SYS_BIND: ql_syscall_bind, + SOCKETCALL.SYS_CONNECT: ql_syscall_connect, + SOCKETCALL.SYS_LISTEN: ql_syscall_listen, + SOCKETCALL.SYS_ACCEPT: ql_syscall_accept, + SOCKETCALL.SYS_GETSOCKNAME: ql_syscall_getsockname, + SOCKETCALL.SYS_GETPEERNAME: ql_syscall_getpeername, + SOCKETCALL.SYS_SOCKETPAIR: ql_syscall_socketpair, + SOCKETCALL.SYS_SEND: ql_syscall_send, + SOCKETCALL.SYS_RECV: ql_syscall_recv, + SOCKETCALL.SYS_SENDTO: ql_syscall_sendto, + SOCKETCALL.SYS_RECVFROM: ql_syscall_recvfrom, + SOCKETCALL.SYS_SHUTDOWN: ql_syscall_shutdown, + SOCKETCALL.SYS_SETSOCKOPT: ql_syscall_setsockopt, + SOCKETCALL.SYS_GETSOCKOPT: ql_syscall_getsockopt, + SOCKETCALL.SYS_RECVMSG: ql_syscall_recvmsg } if call not in handlers: - ql.log.debug(f'socketcall: call {call:d} not implemented') - ql.os.stop() - raise + call_name = next((m.name for m in SOCKETCALL if m.value == call), '') + + raise NotImplementedError(f'socketcall: call {call_name or call} not implemented') + + handler = handlers[call] - handler, nargs = handlers[call] + # determine number of arguments, excluding the first 'ql' arg + nargs = len(inspect.signature(handler).parameters) - 1 # read 'nargs' arguments from the specified base pointer 'args' - params = (ql.unpack(ql.mem.read(args + i * ql.arch.pointersize, ql.arch.pointersize)) for i in range(nargs)) + params = (ql.mem.read_ptr(args + i * ql.arch.pointersize) for i in range(nargs)) return handler(ql, *params) diff --git a/qiling/os/posix/syscall/poll.py b/qiling/os/posix/syscall/poll.py index 1ea5bc3a6..f64f2050d 100644 --- a/qiling/os/posix/syscall/poll.py +++ b/qiling/os/posix/syscall/poll.py @@ -4,6 +4,41 @@ # from qiling import Qiling +from qiling.const import QL_OS, QL_ENDIAN +from qiling.os.posix.structs import * +import select +import ctypes + def ql_syscall_poll(ql: Qiling, fds: int, nfds: int, timeout: int): - return 0 \ No newline at end of file + pollfd = make_pollfd(ql.arch.bits, ql.arch.endian) + + if ql.host.os == QL_OS.LINUX: + fn_map = {} + try: + p = select.poll() + for i in range(nfds): + with pollfd.ref(ql.mem, fds + ctypes.sizeof(pollfd) * i) as pf: + # clear revents field + pf.revents = 0 + + ql.log.debug(f"register poll fd {pf.fd}, event {pf.events}") + fileno = ql.os.fd[pf.fd].fileno() + fn_map[fileno] = i + p.register(fileno, pf.events) + + res_list = p.poll(timeout) + regreturn = len(res_list) + + for fn, revent in res_list: + with pollfd.ref(ql.mem, fds + ctypes.sizeof(pollfd) * fn_map[fn]) as pf: + ql.log.debug(f"receive event on fd {pf.fd}, revent {revent}") + pf.revents = revent + except Exception as e: + ql.log.error(f'{e} {fds=}, {nfds=}, {timeout=}') + regreturn = -1 + + return regreturn + else: + ql.log.warning(f'syscall poll not implemented') + return 0 diff --git a/qiling/os/posix/syscall/resource.py b/qiling/os/posix/syscall/resource.py index f04251bcc..6d26cdbaf 100644 --- a/qiling/os/posix/syscall/resource.py +++ b/qiling/os/posix/syscall/resource.py @@ -28,7 +28,9 @@ def __getrlimit_common(ql: Qiling, res: int, rlim: int) -> int: rlimit = (stack_size, -1) else: rlimit = resource.getrlimit(res) - ql.mem.write(rlim, ql.pack64s(rlimit[0]) + ql.pack64s(rlimit[1])) + + ql.mem.write(rlim, ql.packs(rlimit[0]) + ql.packs(rlimit[1])) + return 0 def ql_syscall_ugetrlimit(ql: Qiling, res: int, rlim: int): diff --git a/qiling/os/posix/syscall/sched.py b/qiling/os/posix/syscall/sched.py index 558e56d0a..407b2b5b8 100644 --- a/qiling/os/posix/syscall/sched.py +++ b/qiling/os/posix/syscall/sched.py @@ -3,7 +3,7 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -import os +import os, gevent from multiprocessing import Process from qiling import Qiling @@ -131,4 +131,8 @@ def ql_syscall_clone(ql: Qiling, flags: int, child_stack: int, parent_tidptr: in return regreturn def ql_syscall_sched_yield(ql: Qiling): + def _sched_yield(cur_thread): + gevent.sleep(0) + ql.emu_stop() + ql.os.thread_management.cur_thread.sched_cb = _sched_yield return 0 diff --git a/qiling/os/posix/syscall/socket.py b/qiling/os/posix/syscall/socket.py index db362b52c..4fd56dafb 100644 --- a/qiling/os/posix/syscall/socket.py +++ b/qiling/os/posix/syscall/socket.py @@ -3,470 +3,668 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -import ctypes import ipaddress -import sys import socket -import struct -from typing import Tuple - -from unicorn.unicorn import UcError +from typing import Optional, Tuple from qiling import Qiling -from qiling.const import QL_ARCH, QL_VERBOSE -from qiling.os.posix.const_mapping import socket_type_mapping, socket_level_mapping, socket_domain_mapping, socket_ip_option_mapping, socket_option_mapping +from qiling.const import QL_ARCH, QL_OS, QL_VERBOSE +from qiling.os.posix.const_mapping import socket_type_mapping, socket_level_mapping, socket_domain_mapping, socket_ip_option_mapping, socket_tcp_option_mapping, socket_option_mapping from qiling.os.posix.const import * from qiling.os.posix.filestruct import ql_socket +from qiling.os.posix.structs import * + + +AF_UNIX = 1 +AF_INET = 2 +AF_INET6 = 10 + + +def inet_aton(ipaddr: str) -> int: + # ipdata = bytes(int(a, 0) for a in ipaddr.split('.', 4)) + ipdata = ipaddress.IPv4Address(ipaddr).packed + + return int.from_bytes(ipdata, byteorder='big') + + +def inet6_aton(ipaddr: str) -> int: + ipdata = ipaddress.IPv6Address(ipaddr).packed + + return int.from_bytes(ipdata, byteorder='big') -class msghdr(ctypes.Structure): - _fields_ = [ - ('msg_name' , ctypes.c_uint64), - ('msg_namelen' , ctypes.c_int32 ), - ('msg_iov' , ctypes.c_uint64), - ('msg_iovlen' , ctypes.c_int32 ), - ('msg_control' , ctypes.c_uint64), - ('msg_controllen', ctypes.c_int32 ), - ('msg_flags' , ctypes.c_int32 ) - ] - _pack_ = 8 +def inet_htoa(ql: Qiling, addr: int) -> str: + abytes = ql.pack32(addr) - @classmethod - def load(cls, ql: Qiling, addr: int): - data = ql.mem.read(addr, ctypes.sizeof(msghdr)) - return msghdr.from_buffer(data) + return ipaddress.IPv4Address(abytes).compressed -class cmsghdr(ctypes.Structure): - _fields_ = [ - ('cmsg_len' , ctypes.c_int32), - ('cmsg_level', ctypes.c_int32), - ('cmsg_type' , ctypes.c_int32), - ] - _pack_ = 8 +def inet_ntoa(addr: int) -> str: + abytes = addr.to_bytes(length=4, byteorder='big') - @classmethod - def load(cls, ql: Qiling, addr: int): - data = ql.mem.read(addr, ctypes.sizeof(cmsghdr)) - return cmsghdr.from_buffer(data) + return ipaddress.IPv4Address(abytes).compressed -class iovec(ctypes.Structure): - _fields_ = [ - ('iov_base', ctypes.c_uint64), - ('iov_len' , ctypes.c_uint64), - ] - _pack_ = 8 +def inet6_htoa(ql: Qiling, addr: bytes) -> str: + # TODO: swap addr bytes order according to ql.arch.endian? - @classmethod - def load(cls, ql: Qiling, addr: int): - data = ql.mem.read(addr, ctypes.sizeof(iovec)) - return iovec.from_buffer(data) + return ipaddress.IPv6Address(addr).compressed -def ql_bin_to_ip(ip): - return ipaddress.ip_address(ip).compressed +def inet6_ntoa(addr: bytes) -> str: + return ipaddress.IPv6Address(addr).compressed + + +def ntohs(ql: Qiling, nval: int) -> int: + ebdata = nval.to_bytes(length=2, byteorder='big') + + return ql.unpack16(ebdata) + + +def htons(ql: Qiling, hval: int) -> int: + ndata = ql.pack16(hval) + + return int.from_bytes(ndata, byteorder='big') def ql_unix_socket_path(ql: Qiling, sun_path: bytearray) -> Tuple[str, str]: - if sun_path[0] == 0: - # Abstract Unix namespace + vpath, _, _ = sun_path.partition(b'\x00') + + # an abstract Unix namespace? + if not vpath: # TODO: isolate from host namespace # TODO: Windows ql.log.warning(f'Beware! Usage of hosts abstract socket namespace {bytes(sun_path)}') return (sun_path.decode(), '') - vpath = sun_path.split(b'\0', maxsplit=1)[0].decode() + vpath = ql.os.path.virtual_abspath(vpath.decode()) hpath = ql.os.path.virtual_to_host_path(vpath) return (hpath, vpath) -def ql_syscall_socket(ql: Qiling, socket_domain, socket_type, socket_protocol): - idx = next((i for i in range(NR_OPEN) if ql.os.fd[i] is None), -1) +def __host_socket_type(vsock_type: int, arch_type: QL_ARCH) -> int: + """Convert emulated socket type value to a host socket type. + """ - if idx != -1: - emu_socket_value = socket_type + try: + vsock_type_name = socket_type_mapping(vsock_type, arch_type) + except KeyError: + raise NotImplementedError(f'Could not convert emulated socket type {vsock_type} to a socket type name') - # ql_socket.open should use host platform based socket_type. - try: - emu_socket_type = socket_type_mapping(socket_type, ql.arch.type, ql.os.type) - except KeyError: - ql.log.error(f'Cannot convert emu_socket_type {emu_socket_value} to host platform based socket_type') - raise + try: + hsock_type = getattr(socket, vsock_type_name) + except AttributeError: + raise NotImplementedError(f'Could not convert emulated socket type name {vsock_type_name} to a host socket type') - try: - socket_type = getattr(socket, emu_socket_type) - except AttributeError: - ql.log.error(f'Cannot convert emu_socket_type {emu_socket_type}:{emu_socket_value} to host platform based socket_type') - raise + return hsock_type + + +def __host_socket_level(vsock_level: int, arch_type: QL_ARCH) -> int: + """Convert emulated socket level value to a host socket level. + """ + + try: + vsock_level_name = socket_level_mapping(vsock_level, arch_type) + except KeyError: + raise NotImplementedError(f'Could not convert emulated socket level {vsock_level} to a socket level name') + + try: + hsock_level = getattr(socket, vsock_level_name) + except AttributeError: + raise NotImplementedError(f'Could not convert emulated socket level name {vsock_level_name} to a host socket level') + + return hsock_level + + +def __host_socket_option(vsock_level: int, vsock_opt: int, arch_type: QL_ARCH, os_type: QL_OS) -> int: + """Convert emulated socket option value to a host socket option. + """ + + try: + if vsock_level == 0x0000: # IPPROTO_IP + vsock_opt_name = socket_ip_option_mapping(vsock_opt, arch_type, os_type) + + elif vsock_level == 0x0006: # IPPROTO_TCP + vsock_opt_name = socket_tcp_option_mapping(vsock_opt, arch_type) + + else: + vsock_opt_name = socket_option_mapping(vsock_opt, arch_type) - ql.log.debug(f'Convert emu_socket_type {emu_socket_type}:{emu_socket_value} to host platform based socket_type {emu_socket_type}:{socket_type}') + # Fix for mips + if arch_type == QL_ARCH.MIPS: + if vsock_opt_name.endswith(('_NEW', '_OLD')): + vsock_opt_name = vsock_opt_name[:-4] + + except KeyError: + raise NotImplementedError(f'Could not convert emulated socket option {vsock_opt} to a socket option name') + + try: + hsock_opt = getattr(socket, vsock_opt_name) + except AttributeError: + raise NotImplementedError(f'Could not convert emulated socket option name {vsock_opt_name} to a host socket option') + + return hsock_opt + + +def ql_syscall_socket(ql: Qiling, domain: int, socktype: int, protocol: int): + idx = next((i for i in range(NR_OPEN) if ql.os.fd[i] is None), -1) + + if idx != -1: + # ql_socket.open should use host platform based socket type + vsock_type = socktype + hsock_type = __host_socket_type(vsock_type, ql.arch.type) + + ql.log.debug(f'Converted emulated socket type {vsock_type} to host socket type {hsock_type}') try: - sock = ql_socket.open(socket_domain, socket_type, socket_protocol) + sock = ql_socket.open(domain, hsock_type, protocol) # set REUSEADDR options under debug mode if ql.verbose >= QL_VERBOSE.DEBUG: sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - ql.os.fd[idx] = sock - # May raise error: Protocol not supported except OSError as e: - ql.log.debug(f'{e}: {socket_domain=}, {socket_type=}, {socket_protocol=}') + ql.log.debug(f'Error opening socket: {e}') idx = -1 + else: + ql.os.fd[idx] = sock - socket_type = socket_type_mapping(socket_type, ql.arch.type, ql.os.type) - socket_domain = socket_domain_mapping(socket_domain, ql.arch.type, ql.os.type) - ql.log.debug("socket(%s, %s, %s) = %d" % (socket_domain, socket_type, socket_protocol, idx)) + s_domain = socket_domain_mapping(domain, ql.arch.type, ql.os.type) + s_socktype = socket_type_mapping(socktype, ql.arch.type) + ql.log.debug("socket(%s, %s, %s) = %d" % (s_domain, s_socktype, protocol, idx)) return idx +def ql_syscall_socketpair(ql: Qiling, domain: int, socktype: int, protocol: int, sv: int): + unpopulated_fd = (i for i in range(NR_OPEN) if ql.os.fd[i] is None) + + idx1 = next(unpopulated_fd, -1) + idx2 = next(unpopulated_fd, -1) + + regreturn = -1 + + if (idx1 != -1) and (idx2 != -1): + # ql_socket.socketpair should use host platform based socket type + vsock_type = socktype + hsock_type = __host_socket_type(vsock_type, ql.arch.type) + + ql.log.debug(f'Converted emulated socket type {vsock_type} to host socket type {hsock_type}') + + try: + sock1, sock2 = ql_socket.socketpair(domain, hsock_type, protocol) + + # May raise error: Protocol not supported + except OSError as e: + ql.log.debug(f'{e}: {domain=}, {socktype=}, {protocol=}, {sv=}') + regreturn = -1 + + else: + ql.os.fd[idx1] = sock1 + ql.os.fd[idx2] = sock2 + + # save fd to &sv + ql.mem.write_ptr(sv + 0, idx1) + ql.mem.write_ptr(sv + 4, idx2) + + regreturn = 0 + + s_domain = socket_domain_mapping(domain, ql.arch.type, ql.os.type) + s_type = socket_type_mapping(socktype, ql.arch.type) + ql.log.debug("socketpair(%s, %s, %d, %d) = %d" % (s_domain, s_type, protocol, sv, regreturn)) + + return regreturn + + def ql_syscall_connect(ql: Qiling, sockfd: int, addr: int, addrlen: int): - AF_UNIX = 1 - AF_INET = 2 + if sockfd not in range(NR_OPEN): + return -1 + + sock: Optional[ql_socket] = ql.os.fd[sockfd] + + if sock is None: + return -1 - sock_addr = ql.mem.read(addr, addrlen) - family = ql.unpack16(sock_addr[:2]) + data = ql.mem.read(addr, addrlen) - sock = ql.os.fd[sockfd] - assert isinstance(sock, ql_socket) + abits = ql.arch.bits + endian = ql.arch.endian + + sockaddr = make_sockaddr(abits, endian) + sockaddr_obj = sockaddr.from_buffer(data) dest = None + regreturn = -1 - if sock.family != family: + if sock.family != sockaddr_obj.sa_family: return -1 if sock.family == AF_UNIX: - hpath, vpath = ql_unix_socket_path(ql, sock_addr[2:]) + hpath, vpath = ql_unix_socket_path(ql, data[2:]) - ql.log.debug(f'connecting to "{vpath}"') + # TODO: support connecting to fs_mapped unix sockets + ql.log.debug(f'Connecting to "{vpath}"') dest = hpath elif sock.family == AF_INET: - port, host = struct.unpack(">HI", sock_addr[2:8]) - ip = ql_bin_to_ip(host) + sockaddr_in = make_sockaddr_in(abits, endian) + sockaddr_obj = sockaddr_in.from_buffer(data) - ql.log.debug(f'connecting to {ip}:{port}') - dest = (ip, port) + port = ntohs(ql, sockaddr_obj.sin_port) + host = inet_htoa(ql, sockaddr_obj.sin_addr.s_addr) - else: - return -1 + ql.log.debug(f'Connecting to {host}:{port}') + dest = (host, port) - try: - sock.connect(dest) - except: - regreturn = -1 - else: - regreturn = 0 + elif sock.family == AF_INET6 and ql.os.ipv6: + sockaddr_in6 = make_sockaddr_in(abits, endian) + sockaddr_obj = sockaddr_in6.from_buffer(data) + + port = ntohs(ql, sockaddr_obj.sin_port) + host = inet6_htoa(ql, sockaddr_obj.sin6_addr.s6_addr) + + ql.log.debug(f'Conecting to {host}:{port}') + dest = (host, port) + + if dest is not None: + try: + sock.connect(dest) + except (ConnectionError, FileNotFoundError): + regreturn = -1 + else: + regreturn = 0 return regreturn -def ql_syscall_getsockopt(ql: Qiling, sockfd, level, optname, optval_addr, optlen_addr): - if sockfd not in range(NR_OPEN) or ql.os.fd[sockfd] is None: - return -EBADF +def ql_syscall_getsockopt(ql: Qiling, sockfd: int, level: int, optname: int, optval_addr: int, optlen_addr: int): + if sockfd not in range(NR_OPEN): + return -1 + + sock: Optional[ql_socket] = ql.os.fd[sockfd] + + if sock is None: + return -1 + + vsock_level = level + hsock_level = __host_socket_level(vsock_level, ql.arch.type) + + ql.log.debug(f'Converted emulated socket level {vsock_level} to host socket level {hsock_level}') + + vsock_opt = optname + hsock_opt = __host_socket_option(vsock_level, vsock_opt, ql.arch.type, ql.os.type) + + ql.log.debug(f'Converted emulated socket option {vsock_opt} to host socket option {hsock_opt}') + + optlen = min(ql.unpack32s(ql.mem.read(optlen_addr, 4)), 1024) + + if optlen < 0: + return -1 try: - optlen = min(ql.unpack32s(ql.mem.read(optlen_addr, 4)), 1024) + optval = sock.getsockopt(hsock_level, hsock_opt, optlen) + except (ConnectionError, OSError): + return -1 - if optlen < 0: - return -EINVAL + ql.mem.write(optval_addr, optval) - emu_level = level + return 0 - try: - emu_level_name = socket_level_mapping(emu_level, ql.arch.type, ql.os.type) - except KeyError: - ql.log.error(f"Can't convert emu_level {emu_level} to host platform based level") - raise - try: - level = getattr(socket, emu_level_name) - except AttributeError: - ql.log.error(f"Can't convert emu_level {emu_level_name}:{emu_level} to host platform based emu_level") - raise +def ql_syscall_setsockopt(ql: Qiling, sockfd: int, level: int, optname: int, optval_addr: int, optlen: int): + if sockfd not in range(NR_OPEN): + return -1 - ql.log.debug(f"Convert emu_level {emu_level_name}:{emu_level} to host platform based level {emu_level_name}:{level}") + sock: Optional[ql_socket] = ql.os.fd[sockfd] - emu_opt = optname + if sock is None: + return -1 - try: - emu_level_name = socket_level_mapping(emu_level, ql.arch.type, ql.os.type) + if optval_addr == 0: + sock.setsockopt(level, optname, None, optlen) + + else: + vsock_level = level + hsock_level = __host_socket_level(vsock_level, ql.arch.type) - # emu_opt_name is based on level - if emu_level_name == "IPPROTO_IP": - emu_opt_name = socket_ip_option_mapping(emu_opt, ql.arch.type, ql.os.type) - else: - emu_opt_name = socket_option_mapping(emu_opt, ql.arch.type, ql.os.type) + ql.log.debug(f'Converted emulated socket level {vsock_level} to host socket level {hsock_level}') - # Fix for mips - if ql.arch.type == QL_ARCH.MIPS: - if emu_opt_name.endswith("_NEW") or emu_opt_name.endswith("_OLD"): - emu_opt_name = emu_opt_name[:-4] + vsock_opt = optname + hsock_opt = __host_socket_option(vsock_level, vsock_opt, ql.arch.type, ql.os.type) - except KeyError: - ql.log.error(f"Can't convert emu_optname {emu_opt} to host platform based optname") - raise + ql.log.debug(f'Converted emulated socket option {vsock_opt} to host socket option {hsock_opt}') + + optval = ql.mem.read(optval_addr, optlen) try: - optname = getattr(socket, emu_opt_name) - except AttributeError: - ql.log.error(f"Can't convert emu_optname {emu_opt_name}:{emu_opt} to host platform based emu_optname") - raise + sock.setsockopt(hsock_level, hsock_opt, optval) + except (ConnectionError, OSError): + return -1 - ql.log.debug(f"Convert emu_optname {emu_opt_name}:{emu_opt} to host platform based optname {emu_opt_name}:{optname}") + return 0 - optval = ql.os.fd[sockfd].getsockopt(level, optname, optlen) - ql.mem.write(optval_addr, optval) - except UcError: - return -EFAULT + +def ql_syscall_shutdown(ql: Qiling, sockfd: int, how: int): + if sockfd not in range(NR_OPEN): + return -1 + + sock: Optional[ql_socket] = ql.os.fd[sockfd] + + if sock is None: + return -1 + + try: + sock.shutdown(how) + except ConnectionError: + return -1 return 0 -def ql_syscall_setsockopt(ql: Qiling, sockfd, level, optname, optval_addr, optlen): - if sockfd not in range(NR_OPEN) or ql.os.fd[sockfd] is None: - return -EBADF +def ql_syscall_bind(ql: Qiling, sockfd: int, addr: int, addrlen: int): + if sockfd not in range(NR_OPEN): + return -1 - regreturn = 0 - if optval_addr == 0: - ql.os.fd[sockfd].setsockopt(level, optname, None, optlen) - else: - try: - emu_level = level + sock: Optional[ql_socket] = ql.os.fd[sockfd] - try: - emu_level_name = socket_level_mapping(emu_level, ql.arch.type, ql.os.type) - except KeyError: - ql.log.error(f"Can't convert emu_level {emu_level} to host platform based level") - raise + if sock is None: + return -1 - try: - level = getattr(socket, emu_level_name) - except AttributeError: - ql.log.error(f"Can't convert emu_level {emu_level_name}:{emu_level} to host platform based emu_level") - raise + data = ql.mem.read(addr, addrlen) - ql.log.debug(f"Convert emu_level {emu_level_name}:{emu_level} to host platform based level {emu_level_name}:{level}") + abits = ql.arch.bits + endian = ql.arch.endian - emu_opt = optname + sockaddr = make_sockaddr(abits, endian) + sockaddr_obj = sockaddr.from_buffer(data) - try: - emu_level_name = socket_level_mapping(emu_level, ql.arch.type, ql.os.type) + sa_family = sockaddr_obj.sa_family - # emu_opt_name is based on level - if emu_level_name == "IPPROTO_IP": - emu_opt_name = socket_ip_option_mapping(emu_opt, ql.arch.type, ql.os.type) - else: - emu_opt_name = socket_option_mapping(emu_opt, ql.arch.type, ql.os.type) + dest = None + regreturn = -1 - # Fix for mips - if ql.arch.type == QL_ARCH.MIPS: - if emu_opt_name.endswith("_NEW") or emu_opt_name.endswith("_OLD"): - emu_opt_name = emu_opt_name[:-4] + if sa_family == AF_UNIX: + hpath, vpath = ql_unix_socket_path(ql, data[2:]) - except KeyError: - ql.log.error(f"Can't convert emu_optname {emu_opt} to host platform based optname") - raise + ql.log.debug(f'Binding socket to "{vpath}"') + dest = hpath - try: - optname = getattr(socket, emu_opt_name) - except AttributeError: - ql.log.error(f"Can't convert emu_optname {emu_opt_name}:{emu_opt} to host platform based emu_optname") - raise + elif sa_family == AF_INET: + sockaddr = make_sockaddr_in(abits, endian) + sockaddr_obj = sockaddr.from_buffer(data) - ql.log.debug(f"Convert emu_optname {emu_opt_name}:{emu_opt} to host platform based optname {emu_opt_name}:{optname}") + port = ntohs(ql, sockaddr_obj.sin_port) + host = inet_ntoa(sockaddr_obj.sin_addr.s_addr) - optval = ql.mem.read(optval_addr, optlen) - ql.os.fd[sockfd].setsockopt(level, optname, optval, None) + if ql.os.bindtolocalhost: + host = '127.0.0.1' - except UcError: - regreturn = -EFAULT + if not ql.os.root and port <= 1024: + port = port + 8000 - except: - regreturn = -1 + ql.log.debug(f'Binding socket to {host}:{port}') + dest = (host, port) - return regreturn + elif sa_family == AF_INET6 and ql.os.ipv6: + sockaddr_in6 = make_sockaddr_in(abits, endian) + sockaddr_obj = sockaddr_in6.from_buffer(data) + port = ntohs(ql, sockaddr_obj.sin_port) + host = inet6_ntoa(sockaddr_obj.sin6_addr.s6_addr) -def ql_syscall_shutdown(ql: Qiling, fd: int, how: int): - regreturn = 0 + if ql.os.bindtolocalhost: + host = '::1' - if fd in range(NR_OPEN): - sock = ql.os.fd[fd] + if not ql.os.root and port <= 1024: + port = port + 8000 - if sock is not None: - try: - sock.shutdown(how) - except: - regreturn = -1 + ql.log.debug(f'Binding socket to {host}:{port}') + dest = (host, port) + + if dest is not None: + try: + sock.bind(dest) + except (ConnectionError, FileNotFoundError): + regreturn = -1 + else: + regreturn = 0 return regreturn -def ql_syscall_bind(ql: Qiling, bind_fd, bind_addr, bind_addrlen): - regreturn = 0 +def ql_syscall_getsockname(ql: Qiling, sockfd: int, addr: int, addrlenptr: int): + if sockfd not in range(NR_OPEN): + return -1 - if ql.arch.type == QL_ARCH.X8664: - data = ql.mem.read(bind_addr, 8) - else: - data = ql.mem.read(bind_addr, bind_addrlen) + sock: Optional[ql_socket] = ql.os.fd[sockfd] - sin_family = ql.unpack16(data[:2]) or ql.os.fd[bind_fd].family - port, host = struct.unpack(">HI", data[2:8]) - host = ql_bin_to_ip(host) + if sock is None: + return -1 - if not ql.os.root and port <= 1024: - port = port + 8000 + addrlen = ql.mem.read_ptr(addrlenptr) if addrlenptr else 0 - if sin_family == 1: - hpath, vpath = ql_unix_socket_path(ql, data[2:]) - ql.log.debug(f'binding socket to "{vpath}"') - ql.os.fd[bind_fd].bind(hpath) + abits = ql.arch.bits + endian = ql.arch.endian - # need a proper fix, for now ipv4 comes first - elif sin_family == 2 and ql.os.bindtolocalhost == True: - host = "127.0.0.1" - ql.os.fd[bind_fd].bind((host, port)) + sockname = sock.getsockname() + obj = None - # IPv4 should comes first - elif ql.os.ipv6 == True and sin_family == 10 and ql.os.bindtolocalhost == True: - host = "::1" - ql.os.fd[bind_fd].bind((host, port)) + if sock.family == AF_UNIX: + hpath = sockname + vpath = ql.os.path.host_to_virtual_path(hpath) - elif ql.os.bindtolocalhost == False: - ql.os.fd[bind_fd].bind((host, port)) + if addrlen: + # addrlen indicates the total obj size allowed to be written. + # that already includes the family field (2) and the path null + # terminator (1) + vpath = vpath[:addrlen - 2 - 1] - else: - regreturn = -1 + sockaddr_un = make_sockaddr_un(abits, endian, len(vpath) + 1) - if ql.code: - regreturn = 0 + obj = sockaddr_un() + obj.sun_family = AF_UNIX + obj.sun_path = vpath.encode() + b'\x00' - if sin_family == 1: - ql.log.debug("bind(%d, %s, %d) = %d" % (bind_fd, vpath, bind_addrlen, regreturn)) - else: - ql.log.debug("bind(%d,%s:%d,%d) = %d" % (bind_fd, host, port, bind_addrlen,regreturn)) - ql.log.debug("syscall bind host: %s and port: %i sin_family: %i" % (ql_bin_to_ip(host), port, sin_family)) + elif sock.family == AF_INET: + sockaddr_in = make_sockaddr_in(abits, endian) + host, port = sockname - return regreturn + obj = sockaddr_in() + obj.sin_family = AF_INET + obj.sin_port = htons(ql, port) + obj.sin_addr.s_addr = inet_aton(str(host)) + elif sock.family == AF_INET6 and ql.os.ipv6: + sockaddr_in6 = make_sockaddr_in6(abits, endian) + host, port = sockname -def ql_syscall_getsockname(ql: Qiling, sockfd: int, addr: int, addrlenptr: int): - if 0 <= sockfd < NR_OPEN: - socket = ql.os.fd[sockfd] + obj = sockaddr_in6() + obj.sin6_family = AF_INET6 + obj.sin6_port = htons(ql, port) + obj.sin6_addr.s6_addr = inet6_aton(str(host)) - if isinstance(socket, ql_socket): - host, port = socket.getpeername() + if obj: + objsize = obj.sizeof() - data = struct.pack("H", port) - data += ipaddress.ip_address(host).packed + if objsize <= addrlen: + obj.save_to(ql.mem, addr) - addrlen = ql.mem.read_ptr(addrlenptr) + if addrlenptr: + ql.mem.write_ptr(addrlenptr, objsize) - ql.mem.write(addr, data[:addrlen]) - regreturn = 0 - else: - regreturn = -EPERM - else: - regreturn = -EPERM + ql.log.debug("getsockname(%d, %#x, %#x) = %d" % (sockfd, addr, addrlenptr, 0)) - ql.log.debug("getsockname(%d, 0x%x, 0x%x) = %d" % (sockfd, addr, addrlenptr, regreturn)) - return regreturn + return 0 def ql_syscall_getpeername(ql: Qiling, sockfd: int, addr: int, addrlenptr: int): - if 0 <= sockfd < NR_OPEN: - socket = ql.os.fd[sockfd] + if sockfd not in range(NR_OPEN): + return -1 - if isinstance(socket, ql_socket): - host, port = socket.getpeername() + sock: Optional[ql_socket] = ql.os.fd[sockfd] - data = struct.pack("H", port) - data += ipaddress.ip_address(host).packed + if sock is None: + return -1 - addrlen = ql.mem.read_ptr(addrlenptr) + addrlen = ql.mem.read_ptr(addrlenptr) if addrlenptr else 0 - ql.mem.write(addr, data[:addrlen]) - regreturn = 0 - else: - regreturn = -EPERM - else: - regreturn = -EPERM + abits = ql.arch.bits + endian = ql.arch.endian - ql.log.debug("getpeername(%d, 0x%x, 0x%x) = %d" % (sockfd, addr, addrlenptr, regreturn)) - return regreturn + peername = sock.getpeername() + obj = None + + if sock.family == AF_UNIX: + hpath = peername + vpath = ql.os.path.host_to_virtual_path(hpath) + + if addrlen: + # addrlen indicates the total obj size allowed to be written. + # that already includes the family field (2) and the path null + # terminator (1) + vpath = vpath[:addrlen - 2 - 1] + + sockaddr_un = make_sockaddr_un(abits, endian, len(vpath) + 1) + + obj = sockaddr_un() + obj.sun_family = AF_UNIX + obj.sun_path = vpath.encode() + b'\x00' + + elif sock.family == AF_INET: + sockaddr_in = make_sockaddr_in(abits, endian) + host, port = peername + + obj = sockaddr_in() + obj.sin_family = AF_INET + obj.sin_port = htons(ql, port) + obj.sin_addr.s_addr = inet_aton(str(host)) + + elif sock.family == AF_INET6 and ql.os.ipv6: + sockaddr_in6 = make_sockaddr_in6(abits, endian) + host, port = peername + + obj = sockaddr_in6() + obj.sin6_family = AF_INET6 + obj.sin6_port = htons(ql, port) + obj.sin6_addr.s6_addr = inet6_aton(str(host)) + + if obj: + objsize = obj.sizeof() + + if objsize <= addrlen: + obj.save_to(ql.mem, addr) + + if addrlenptr: + ql.mem.write_ptr(addrlenptr, objsize) + + ql.log.debug("getpeername(%d, %#x, %#x) = %d" % (sockfd, addr, addrlenptr, 0)) + + return 0 def ql_syscall_listen(ql: Qiling, sockfd: int, backlog: int): if sockfd not in range(NR_OPEN): return -1 - sock = ql.os.fd[sockfd] + sock: Optional[ql_socket] = ql.os.fd[sockfd] if sock is None: return -1 try: sock.listen(backlog) - except: - if ql.verbose >= QL_VERBOSE.DEBUG: - raise - + except ConnectionError: return -1 return 0 -def ql_syscall_accept(ql: Qiling, accept_sockfd, accept_addr, accept_addrlen): - def inet_addr(ip): - ret = b'' - tmp = ip.split('.') - if len(tmp) != 4: - return ret - for i in tmp[ : : -1]: - ret += bytes([int(i)]) - return ret +def ql_syscall_accept(ql: Qiling, sockfd: int, addr: int, addrlenptr: int): + if sockfd not in range(NR_OPEN): + return -1 + + sock: Optional[ql_socket] = ql.os.fd[sockfd] + + if sock is None: + return -1 + try: - conn, address = ql.os.fd[accept_sockfd].accept() + conn, address = sock.accept() + except ConnectionError: + return -1 - if conn is None: - return -1 + if (conn is None) or (address is None): + return -1 - idx = next((i for i in range(NR_OPEN) if ql.os.fd[i] is None), -1) + idx = next((i for i in range(NR_OPEN) if ql.os.fd[i] is None), -1) - if idx == -1: - regreturn = -1 - else: - ql.os.fd[idx] = conn - regreturn = idx - - if ql.code == None and accept_addr !=0 and accept_addrlen != 0: - tmp_buf = ql.pack16(conn.family) - tmp_buf += ql.pack16(address[1]) - tmp_buf += inet_addr(address[0]) - tmp_buf += b'\x00' * 8 - ql.mem.write(accept_addr, tmp_buf) - ql.mem.write_ptr(accept_addrlen, 16, 4) - except: - if ql.verbose >= QL_VERBOSE.DEBUG: - raise - regreturn = -1 + if idx == -1: + return -1 - return regreturn + ql.os.fd[idx] = conn + + if addr: + addrlen = ql.mem.read_ptr(addrlenptr) if addrlenptr else 0 + + abits = ql.arch.bits + endian = ql.arch.endian + + obj = None + + if conn.family == AF_UNIX: + hpath = address + vpath = ql.os.path.host_to_virtual_path(hpath) + + if addrlen: + # addrlen indicates the total obj size allowed to be written. + # that already includes the family field (2) and the path null + # terminator (1) + vpath = vpath[:addrlen - 2 - 1] + + sockaddr_un = make_sockaddr_un(abits, endian, len(vpath) + 1) + + obj = sockaddr_un() + obj.sun_family = AF_UNIX + obj.sun_path = vpath.encode() + b'\x00' + + elif conn.family == AF_INET: + sockaddr_in = make_sockaddr_in(abits, endian) + host, port = address + + obj = sockaddr_in() + obj.sin_family = AF_INET + obj.sin_port = htons(ql, port) + obj.sin_addr.s_addr = inet_aton(str(host)) + + elif conn.family == AF_INET6 and ql.os.ipv6: + sockaddr_in6 = make_sockaddr_in6(abits, endian) + host, port = address + + obj = sockaddr_in6() + obj.sin6_family = AF_INET6 + obj.sin6_port = htons(ql, port) + obj.sin6_addr.s6_addr = inet6_aton(str(host)) + + if obj: + objsize = obj.sizeof() + + if objsize <= addrlen: + obj.save_to(ql.mem, addr) + + if addrlenptr: + ql.mem.write_ptr(addrlenptr, objsize) + + return idx def ql_syscall_recv(ql: Qiling, sockfd: int, buf: int, length: int, flags: int): if sockfd not in range(NR_OPEN): return -1 - sock = ql.os.fd[sockfd] + sock: Optional[ql_socket] = ql.os.fd[sockfd] if sock is None: return -1 @@ -486,74 +684,79 @@ def ql_syscall_send(ql: Qiling, sockfd: int, buf: int, length: int, flags: int): if sockfd not in range(NR_OPEN): return -1 - sock = ql.os.fd[sockfd] + sock: Optional[ql_socket] = ql.os.fd[sockfd] if sock is None: return -1 + content = ql.mem.read(buf, length) + try: - content = bytes(ql.mem.read(buf, length)) regreturn = sock.send(content, flags) - except: + except IOError: regreturn = 0 - ql.log.info(sys.exc_info()[0]) - - if ql.verbose >= QL_VERBOSE.DEBUG: - raise return regreturn def ql_syscall_recvmsg(ql: Qiling, sockfd: int, msg_addr: int, flags: int): - regreturn = 0 - if sockfd not in range(NR_OPEN) and ql.os.fd[sockfd] is not None: - msg = msghdr.load(ql, msg_addr) + if sockfd not in range(NR_OPEN): + return -1 - try: - data, ancdata, mflags, addr = ql.os.fd[sockfd].recvmsg(msg.msg_namelen, msg.msg_controllen, flags) - - # TODO: handle the addr - - iovec_addr = msg.msg_iov - has_written = 0 - for i in range(msg.msg_iovlen): - vec = iovec.load(ql, iovec_addr) - size = min(vec.iov_len, len(data) - has_written) - ql.mem.write( - vec.iov_base, - data[has_written: has_written + size] - ) - iovec_addr += ctypes.sizeof(iovec) - - cmsg_addr = msg.msg_control - for cmsg_level, cmsg_type, cmsg_data in ancdata: - cmsg = cmsghdr.load(ql, cmsg_addr) - cmsg.cmsg_len = len(cmsg_data) - cmsg.cmsg_level = cmsg_level - cmsg.cmsg_type = cmsg_type - cmsg_data_addr = cmsg_addr + ctypes.sizeof(cmsghdr) - - ql.mem.write(cmsg_data_addr, cmsg_data) - ql.mem.write(cmsg_addr, bytes(cmsg)) - - cmsg_addr += cmsg.cmsg_len - - msg.msg_flags = mflags - ql.mem.write(msg_addr, bytes(msg)) - - regreturn = len(data) - except OSError as e: - regreturn = -e.errno - else: - regreturn = -EBADF + sock: Optional[ql_socket] = ql.os.fd[sockfd] + + if sock is None: + return -1 + + abits = ql.arch.bits + endian = ql.arch.endian + + msghdr = make_msghdr(abits, endian) + msg = msghdr.load_from(ql.mem, msg_addr) + + try: + # TODO: handle the addr + data, ancdata, mflags, addr = sock.recvmsg(msg.msg_namelen, msg.msg_controllen, flags) + except ConnectionError: + return -1 + + iovec = make_iovec(abits, endian) + iovec_addr = msg.msg_iov + written = 0 + + for _ in range(msg.msg_iovlen): + with iovec.ref(ql.mem, iovec_addr) as obj: + size = min(obj.iov_len, len(data) - written) + ql.mem.write(obj.iov_base, data[written:written + size]) + + written += size + iovec_addr += iovec.sizeof() + + cmsghdr = make_cmsghdr(abits, endian) + cmsg_addr = msg.msg_control + + for cmsg_level, cmsg_type, cmsg_data in ancdata: + with cmsghdr.ref(ql.mem, cmsg_addr) as obj: + obj.cmsg_len = len(cmsg_data) + obj.cmsg_level = cmsg_level + obj.cmsg_type = cmsg_type + + cmsg_addr += cmsghdr.sizeof() + + ql.mem.write(cmsg_addr, cmsg_data) + cmsg_addr += len(cmsg_data) + + msg.msg_flags = mflags + msg.save_to(ql.mem, msg_addr) + + return len(data) - return regreturn def ql_syscall_recvfrom(ql: Qiling, sockfd: int, buf: int, length: int, flags: int, addr: int, addrlen: int): if sockfd not in range(NR_OPEN): return -1 - sock = ql.os.fd[sockfd] + sock: Optional[ql_socket] = ql.os.fd[sockfd] if sock is None: return -1 @@ -564,39 +767,73 @@ def ql_syscall_recvfrom(ql: Qiling, sockfd: int, buf: int, length: int, flags: i if sock.socktype == SOCK_STREAM: return ql_syscall_recv(ql, sockfd, buf, length, flags) - tmp_buf, tmp_addr = sock.recvfrom(length, flags) + data_buf, address = sock.recvfrom(length, flags) - if tmp_buf: + if data_buf: ql.log.debug("recvfrom() CONTENT:") - ql.log.debug("%s" % tmp_buf) + ql.log.debug("%s" % data_buf) sin_family = int(sock.family) - sockaddr_out = struct.pack("H", tmp_addr[1]) - sockaddr_out += ipaddress.ip_address(tmp_addr[0]).packed - addrlen = ql.mem.read_ptr(addrlen) - sockaddr_out = sockaddr_out[:addrlen] + objlen = 0 - if addr: - ql.mem.write(addr, sockaddr_out) - ql.mem.write(buf, tmp_buf) + # FIXME: only write up to sockaddr_out bytes of obj content? + # + # addrlen = ql.mem.read_ptr(addrlen) + # sockaddr_out = sockaddr_out[:addrlen] + + ql.mem.write(buf, data_buf) - return len(tmp_buf) + return len(data_buf) -def ql_syscall_sendto(ql: Qiling, sockfd: int, sendto_buf, sendto_len, sendto_flags, sendto_addr, sendto_addrlen): +def ql_syscall_sendto(ql: Qiling, sockfd: int, buf: int, length: int, flags: int, addr: int, addrlen: int): if sockfd not in range(NR_OPEN): return -1 - sock = ql.os.fd[sockfd] + sock: Optional[ql_socket] = ql.os.fd[sockfd] if sock is None: return -1 @@ -605,42 +842,56 @@ def ql_syscall_sendto(ql: Qiling, sockfd: int, sendto_buf, sendto_len, sendto_fl # For x8664, sendto() is called finally when calling send() in TCP communications if sock.socktype == SOCK_STREAM: - return ql_syscall_send(ql, sockfd, sendto_buf, sendto_len, sendto_flags) + return ql_syscall_send(ql, sockfd, buf, length, flags) + tmp_buf = ql.mem.read(buf, length) + + ql.log.debug("sendto() CONTENT:") + ql.log.debug("%s" % tmp_buf) + + data = ql.mem.read(addr, addrlen) + + abits = ql.arch.bits + endian = ql.arch.endian + + sockaddr = make_sockaddr(abits, endian) + sockaddr_obj = sockaddr.from_buffer(data) + + sa_family = sockaddr_obj.sa_family + + dest = None regreturn = 0 - try: - ql.log.debug("debug sendto() start") - tmp_buf = ql.mem.read(sendto_buf, sendto_len) + if sa_family == AF_UNIX: + hpath, vpath = ql_unix_socket_path(ql, data[2:]) - if ql.arch.type== QL_ARCH.X8664: - data = ql.mem.read(sendto_addr, 8) - else: - data = ql.mem.read(sendto_addr, sendto_addrlen) + ql.log.debug(f'Sending {len(tmp_buf):d} bytes to {vpath}') + dest = hpath - sin_family, = struct.unpack("HI", data[2:8]) - host = ql_bin_to_ip(host) + elif sa_family == AF_INET: + sockaddr = make_sockaddr_in(abits, endian) + sockaddr_obj = sockaddr.from_buffer(data) - ql.log.debug("fd is " + str(sockfd)) - ql.log.debug("sendto() CONTENT:") - ql.log.debug("%s" % tmp_buf) - ql.log.debug("sendto() flag is " + str(sendto_flags)) - ql.log.debug("sendto() len is " + str(sendto_len)) + port = ntohs(ql, sockaddr_obj.sin_port) + host = inet_ntoa(sockaddr_obj.sin_addr.s_addr) - if sin_family == 1: - hpath, vpath = ql_unix_socket_path(ql, data[2:]) + ql.log.debug(f'Sending {len(tmp_buf):d} bytes to {host}:{port}') + dest = (host, port) - ql.log.debug("sendto() path is " + str(vpath)) - regreturn = sock.sendto(bytes(tmp_buf), sendto_flags, hpath) - else: - ql.log.debug("sendto() addr is %s:%d" % (host, port)) - regreturn = sock.sendto(bytes(tmp_buf), sendto_flags, (host, port)) - ql.log.debug("debug sendto end") - except: - ql.log.debug(sys.exc_info()[0]) - - if ql.verbose >= QL_VERBOSE.DEBUG: - raise + elif sa_family == AF_INET6 and ql.os.ipv6: + sockaddr_in6 = make_sockaddr_in(abits, endian) + sockaddr_obj = sockaddr_in6.from_buffer(data) + + port = ntohs(ql, sockaddr_obj.sin_port) + host = inet6_ntoa(sockaddr_obj.sin6_addr.s6_addr) + + ql.log.debug(f'Sending to {host}:{port}') + dest = (host, port) + + if dest is not None: + try: + regreturn = sock.sendto(tmp_buf, flags, dest) + except (ConnectionError, FileNotFoundError): + regreturn = 0 return regreturn diff --git a/qiling/os/posix/syscall/unistd.py b/qiling/os/posix/syscall/unistd.py index 9d715bfa0..b52f5e4b7 100644 --- a/qiling/os/posix/syscall/unistd.py +++ b/qiling/os/posix/syscall/unistd.py @@ -62,45 +62,76 @@ def ql_syscall_issetugid(ql: Qiling): return 0 -def ql_syscall_getuid(ql: Qiling): +def __getuid(ql: Qiling): return ql.os.uid -def ql_syscall_getuid32(ql: Qiling): +def __setuid(ql: Qiling, uid: int): + # TODO: security checks + ql.os.uid = uid + return 0 -def ql_syscall_getgid32(ql: Qiling): +def __getgid(ql: Qiling): + return ql.os.gid + + +def __setgid(ql: Qiling, gid: int): + # TODO: security checks + ql.os.gid = gid + return 0 -def ql_syscall_geteuid(ql: Qiling): - return ql.os.euid +def ql_syscall_getuid(ql: Qiling): + return __getuid(ql) -def ql_syscall_getegid(ql: Qiling): - return ql.os.egid +def ql_syscall_setuid(ql: Qiling, uid: int): + return __setuid(ql, uid) + + +def ql_syscall_getuid32(ql: Qiling): + return __getuid(ql) + + +def ql_syscall_setuid32(ql: Qiling, uid: int): + return __setuid(ql, uid) def ql_syscall_getgid(ql: Qiling): - return ql.os.gid + return __getgid(ql) -def ql_syscall_setgroups(ql: Qiling, gidsetsize: int, grouplist: int): - return 0 +def ql_syscall_setgid(ql: Qiling, gid: int): + return __setgid(ql, gid) -def ql_syscall_setgid(ql: Qiling): - return 0 +def ql_syscall_getgid32(ql: Qiling): + return __getgid(ql) + + +def ql_syscall_setgid32(ql: Qiling, gid: int): + return __setgid(ql, gid) + + +def ql_syscall_geteuid(ql: Qiling): + return ql.os.euid -def ql_syscall_setgid32(ql: Qiling): +def ql_syscall_seteuid(ql: Qiling): return 0 -def ql_syscall_setuid(ql: Qiling): +def ql_syscall_getegid(ql: Qiling): + return ql.os.egid + + +def ql_syscall_setgroups(ql: Qiling, gidsetsize: int, grouplist: int): return 0 + def ql_syscall_setresuid(ql: Qiling): return 0 @@ -202,17 +233,16 @@ def ql_syscall__llseek(ql: Qiling, fd: int, offset_high: int, offset_low: int, r def ql_syscall_brk(ql: Qiling, inp: int): - # current brk_address will be modified if inp is not NULL(zero) - # otherwise, just return current brk_address - if inp: cur_brk_addr = ql.loader.brk_address new_brk_addr = ql.mem.align_up(inp) - if inp > cur_brk_addr: # increase current brk_address if inp is greater + if new_brk_addr > cur_brk_addr: + ql.log.debug(f'brk: increasing program break from {cur_brk_addr:#x} to {new_brk_addr:#x}') ql.mem.map(cur_brk_addr, new_brk_addr - cur_brk_addr, info="[brk]") - elif inp < cur_brk_addr: # shrink current bkr_address to inp if its smaller + elif new_brk_addr < cur_brk_addr: + ql.log.debug(f'brk: decreasing program break from {cur_brk_addr:#x} to {new_brk_addr:#x}') ql.mem.unmap(new_brk_addr, cur_brk_addr - new_brk_addr) ql.loader.brk_address = new_brk_addr @@ -481,7 +511,7 @@ def __read_str_array(addr: int) -> Iterator[str]: ql.loader.argv = args ql.loader.env = env - ql._path = real_path + ql._argv = [real_path] + args ql.mem.map_info = [] ql.clear_ql_hooks() @@ -752,7 +782,7 @@ def _type_mapping(ent): # For some reason MACOS return int value is 64bit try: packed_d_ino = (ql.pack(d_ino), n) - except: + except: packed_d_ino = (ql.pack64(d_ino), n) if is_64: diff --git a/qiling/os/qnx/message.py b/qiling/os/qnx/message.py index e4621fcf6..3c82f5390 100644 --- a/qiling/os/qnx/message.py +++ b/qiling/os/qnx/message.py @@ -1,32 +1,31 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # import os from struct import pack, unpack from ctypes import c_int32 -from binascii import hexlify from qiling import Qiling -from qiling.os.filestruct import ql_file -from qiling.os.mapper import QlFsMappedObject from qiling.os.qnx.const import IO_FLAG_MASK, PAGESIZE, S_IFMT -from qiling.os.qnx.helpers import get_message_body, QnxConn +from qiling.os.qnx.helpers import get_message_body from qiling.os.qnx.types import file_access, file_stats, file_types, file_open_flags, file_sharing_modes, io_connect_eflag, io_connect_ioflag, io_connect_subtypes, lseek_whence, mem_ctrl_subtypes, mmap_flags, pathconf_names, sysconf_conditions, sysconf_consts, sysconf_names, sysconf_subtypes -from qiling.os.posix.const_mapping import _constant_mapping, mmap_prot_mapping, ql_open_flag_mapping +from qiling.os.posix.const_mapping import _flags_mapping, mmap_prot_mapping from qiling.os.posix.syscall import ql_syscall_close, ql_syscall_fstat, ql_syscall_lseek, ql_syscall_mmap, ql_syscall_open, ql_syscall_read, ql_syscall_write # TODO: move this to qiling.os.qnx.const? _IO_COMBINE_FLAG = 0x8000 -def ql_qnx_msg_io_close(ql:Qiling, coid, smsg, sparts, rmsg, rparts, *args, **kw): + +def ql_qnx_msg_io_close(ql: Qiling, coid, smsg, sparts, rmsg, rparts, *args, **kw): fd = ql.os.connections[coid].fd ql.os.connections[coid].fd = None ql.log.debug(f'msg_io_close(coid = {coid} => fd = {fd})') return ql_syscall_close(ql, fd) + # lib/c/support/_connect_ctrl.c::_connect_io() -def ql_qnx_msg_io_connect(ql:Qiling, coid, smsg, sparts, rmsg, rparts, *args, **kw): +def ql_qnx_msg_io_connect(ql: Qiling, coid, smsg, sparts, rmsg, rparts, *args, **kw): # first iov_t iov_base = ql.unpack32(ql.mem.read(smsg, 4)) iov_len = ql.unpack32(ql.mem.read(smsg + 4, 4)) @@ -40,24 +39,24 @@ def ql_qnx_msg_io_connect(ql:Qiling, coid, smsg, sparts, rmsg, rparts, *args, ** real_path = ql.os.path.transform_to_real_path(path) # check parameters assert (type, reply_max, entry_max, key, handle, zero, eflag, extra_type) == (0x100, 0xa18, 0x10, 0, 0, 0, 0, 0), "io_connect message is wrong" - + if not subtype in io_connect_subtypes: raise NotImplementedError(f'msg_io_connect subtype {subtype} not implemented') - + if not file_type in file_types: raise NotImplementedError(f'msg_io_connect file_type {file_type} not implemented') - + if not sflag in file_sharing_modes: raise NotImplementedError(f'msg_io_connect sharing flag {sflag} not implemented') - + if access != 0 and not access in file_access: raise NotImplementedError(f'msg_io_connect access {access} not implemented') - + ioflag_lo = ioflag & IO_FLAG_MASK ioflag_hi = ioflag & (~IO_FLAG_MASK) real_mode = mode & (~S_IFMT) # ql.log.debug(f'msg_io_connect(subtype = {subtype}, file_type = {file_type}, ioflag = 0x{ioflag:x}, mode = 0x{mode:x}, sflag = 0x{sflag:x}, access = {access}, extra_len = {extra_len})') - ql.log.debug(f'msg_io_connect(subtype = {io_connect_subtypes[subtype]}, file_type = {file_types[file_type]}, ioflag = {_constant_mapping(ioflag_lo, io_connect_ioflag) + _constant_mapping(ioflag_hi, file_open_flags)}, mode = 0x{real_mode:x}, type = {_constant_mapping((mode & S_IFMT), file_stats)}, sflag = {file_sharing_modes[sflag]})') + ql.log.debug(f'msg_io_connect(subtype = {io_connect_subtypes[subtype]}, file_type = {file_types[file_type]}, ioflag = {_flags_mapping(ioflag_lo, io_connect_ioflag) + _flags_mapping(ioflag_hi, file_open_flags)}, mode = 0x{real_mode:x}, type = {_flags_mapping((mode & S_IFMT), file_stats)}, sflag = {file_sharing_modes[sflag]})') # convert _IO_FLAG_? to O_? flag and then to O_? flags of host system ioflag -= 1 #ioflag = ql_open_flag_mapping(ql, ioflag) @@ -133,8 +132,9 @@ def ql_qnx_msg_io_connect(ql:Qiling, coid, smsg, sparts, rmsg, rparts, *args, ** ql.mem.write(iov_base, pack(" 0: raise NotImplementedError("mmap with IOV not implemented") - + assert (c_int32(sparts).value, c_int32(rparts).value) == (-56, -24), "input/output sizes are wrong" assert (type, zero, reserved1) == (0x040, 0, 0), "mem_map message is wrong" # map message fd to underlying fd - + if fd > 0: fd = ql.os.connections[fd].fd - - ql.log.debug(f'mem_map(addr = 0x{addr:x}, len = 0x{len:x}, prot = {mmap_prot_mapping(prot)}, flags = {_constant_mapping(flags, mmap_flags)}, fd = {fd}, preload = 0x{preload:x}, align = 0x{align:x}, offset = 0x{offset:x})') + + ql.log.debug(f'mem_map(addr = 0x{addr:x}, len = 0x{len:x}, prot = {mmap_prot_mapping(prot)}, flags = {_flags_mapping(flags, mmap_flags)}, fd = {fd}, preload = 0x{preload:x}, align = 0x{align:x}, offset = 0x{offset:x})') # map memory ret = ql_syscall_mmap(ql, addr, len, prot, flags, fd, offset) # struct _mem_map_replay in services/system/public/sys/memmsg.h ql.mem.write(rmsg, pack("= (3, 9) else functools.lru_cache(maxsize=2) + + +class BaseStruct(ctypes.Structure): """An abstract class for C structures. - """ - T = TypeVar('T', bound='BaseStruct') + Refrain from subclassing it directly as it does not take the emulated architecture + properties into account. Subclass `BaseStructEL` or `BaseStructEB` instead. + """ def save_to(self, mem: QlMemoryManager, address: int) -> None: """Store structure contents to a specified memory address. @@ -29,7 +41,7 @@ def save_to(self, mem: QlMemoryManager, address: int) -> None: mem.write(address, data) @classmethod - def load_from(cls: Type[T], mem: QlMemoryManager, address: int) -> T: + def load_from(cls, mem: QlMemoryManager, address: int): """Construct and populate a structure from saved contents. Args: @@ -44,7 +56,7 @@ def load_from(cls: Type[T], mem: QlMemoryManager, address: int) -> T: return cls.from_buffer(data) @classmethod - def volatile_ref(cls: Type[T], mem: QlMemoryManager, address: int) -> T: + def volatile_ref(cls, mem: QlMemoryManager, address: int): """Refer to a memory location as a volatile structure variable. Args: @@ -63,7 +75,7 @@ def volatile_ref(cls: Type[T], mem: QlMemoryManager, address: int) -> T: ... if p.x > 10: # x value is read directly from memory ... p.x = 10 # x value is written directly to memory ... # y value in memory remains unchanged - >>> + >>> """ # map all structure field names to their types @@ -120,12 +132,11 @@ def __setattr__(self, name: str, value: Any) -> None: # set attribute value super().__setattr__(name, value) - return VolatileStructRef() @classmethod @contextmanager - def ref(cls: Type[T], mem: QlMemoryManager, address: int) -> Iterator[T]: + def ref(cls, mem: QlMemoryManager, address: int): """A structure context manager to facilitate updating structure contents. On context enter, a structure is created and populated from the specified memory @@ -199,23 +210,41 @@ def memberat(cls, offset: int) -> Optional[str]: return next((fname for fname, *_ in cls._fields_ if cls.offsetof(fname) == offset), None) -# TODO: replace the lru_cache decorator with functools.cache when moving to Python 3.9 -@lru_cache(maxsize=2) -def get_aligned_struct(archbits: int) -> Type[BaseStruct]: - """Provide an aligned version of BaseStruct based on the underlying +class BaseStructEL(BaseStruct, ctypes.LittleEndianStructure): + """Little Endian structure base class. + """ + pass + + +class BaseStructEB(BaseStruct, ctypes.BigEndianStructure): + """Big Endian structure base class. + """ + pass + + +@cache +def get_aligned_struct(archbits: int, endian: QL_ENDIAN = QL_ENDIAN.EL) -> Type[BaseStruct]: + """Provide an aligned version of BaseStruct based on the emulated architecture properties. Args: archbits: required alignment in bits """ - class AlignedStruct(BaseStruct): + Struct = { + QL_ENDIAN.EL: BaseStructEL, + QL_ENDIAN.EB: BaseStructEB + }[endian] + + class AlignedStruct(Struct): _pack_ = archbits // 8 return AlignedStruct + +@cache def get_aligned_union(archbits: int): - """Provide an aligned union class based on the underlying architecture + """Provide an aligned union class based on the emulated architecture properties. This class does not inherit the special BaseStruct methods. FIXME: ctypes.Union endianess cannot be set arbitrarily, rather it depends @@ -231,14 +260,15 @@ class AlignedUnion(ctypes.Union): return AlignedUnion + def get_native_type(archbits: int) -> Type[ctypes._SimpleCData]: """Select a ctypes integer type whose size matches the emulated architecture native size. """ __type = { - 32 : ctypes.c_uint32, - 64 : ctypes.c_uint64 + 32: ctypes.c_uint32, + 64: ctypes.c_uint64 } return __type[archbits] diff --git a/qiling/os/uefi/uefi.py b/qiling/os/uefi/uefi.py index 67163e90b..a3f481cf0 100644 --- a/qiling/os/uefi/uefi.py +++ b/qiling/os/uefi/uefi.py @@ -220,18 +220,13 @@ def run(self): self.PE_RUN = True self.ql.emu_start(self.ql.loader.entry_point, self.exit_point, self.ql.timeout, self.ql.count) - except KeyboardInterrupt as ex: + except KeyboardInterrupt: self.ql.log.critical(f'Execution interrupted by user') - if self.ql._internal_exception is ex: - self.ql._internal_exception = None except UcError: self.emu_error() raise - if self.ql._internal_exception is not None: - raise self.ql._internal_exception - def stop(self) -> None: self.ql.emu_stop() self.PE_RUN = False diff --git a/qiling/os/windows/dlls/kernel32/libloaderapi.py b/qiling/os/windows/dlls/kernel32/libloaderapi.py index 2f0370c22..29b4ce88f 100644 --- a/qiling/os/windows/dlls/kernel32/libloaderapi.py +++ b/qiling/os/windows/dlls/kernel32/libloaderapi.py @@ -134,37 +134,49 @@ def hook_GetProcAddress(ql: Qiling, address: int, params): hModule = params['hModule'] lpProcName = params['lpProcName'] + procname = None + ordinal = None + + # if lpProcName is a short integer, it is an ordinal. otherwise, that is a function name. if lpProcName > MAXUSHORT: - # Look up by name - params["lpProcName"] = ql.os.utils.read_cstring(lpProcName) - lpProcName = bytes(params["lpProcName"], "ascii") - else: - # Look up by ordinal - lpProcName = params["lpProcName"] + procname = ql.os.utils.read_cstring(lpProcName) - # TODO fix for gandcrab - if lpProcName == "RtlComputeCrc32": - return 0 + # let log output reflect a human-readable procname + params["lpProcName"] = procname + + # WORKAROUND for gandcrab + if procname == "RtlComputeCrc32": + return 0 + + procname = procname.encode('latin1') + + else: + ordinal = lpProcName - # Check if dll is loaded + # get dll name by handle (module base) dll_name = next((os.path.basename(image.path).casefold() for image in ql.loader.images if image.base == hModule), None) if dll_name is None: - ql.log.info('Failed to import function "%s" with handle 0x%X' % (lpProcName, hModule)) + ql.log.info(f'Failed to import function "{lpProcName}" with handle {hModule:#x}') return 0 # Handle case where module is self if dll_name == os.path.basename(ql.loader.path).casefold(): - for addr, export in ql.loader.export_symbols.items(): - if export['name'] == lpProcName: - return addr + if procname is not None: + search_func = lambda entry: entry['name'] == procname - iat = ql.loader.import_address_table[dll_name] + elif ordinal is not None: + search_func = lambda entry: entry['ord'] == ordinal + + else: + raise AssertionError + + return next((addr for addr, entry in ql.loader.export_symbols.items() if search_func(entry)), 0) - if lpProcName in iat: - return iat[lpProcName] + # in any other case, look through the import address table for that dll + iat = ql.loader.import_address_table[dll_name] - return 0 + return iat.get(procname or ordinal, 0) def _LoadLibrary(ql: Qiling, address: int, params): lpLibFileName = params["lpLibFileName"] diff --git a/qiling/os/windows/registry.py b/qiling/os/windows/registry.py index 5cd0a6a68..9cc3ac813 100644 --- a/qiling/os/windows/registry.py +++ b/qiling/os/windows/registry.py @@ -178,11 +178,11 @@ def __init__(self, ql: Qiling, hivedir: str): self.reghive = RegHive(hivedir) except FileNotFoundError: if not ql.code: - QlErrorFileNotFound("Windows registry hive not found") + raise QlErrorFileNotFound("Windows registry hive not found") except Exception: if not ql.code: - QlErrorFileNotFound("Windows registry hive format error") + raise QlErrorFileNotFound("Windows registry hive format error") try: self.regconf = RegConf(self.regdiff) diff --git a/qiling/os/windows/structs.py b/qiling/os/windows/structs.py index 433330150..170f534bc 100644 --- a/qiling/os/windows/structs.py +++ b/qiling/os/windows/structs.py @@ -167,7 +167,7 @@ class DRIVER_OBJECT(Struct): return DRIVER_OBJECT -class KSYSTEM_TIME(struct.BaseStruct): +class KSYSTEM_TIME(struct.BaseStructEL): _fields_ = ( ('LowPart', ctypes.c_uint32), ('High1Time', ctypes.c_int32), @@ -175,7 +175,7 @@ class KSYSTEM_TIME(struct.BaseStruct): ) -class _LARGE_INTEGER(struct.BaseStruct): +class _LARGE_INTEGER(struct.BaseStructEL): _fields_ = ( ('LowPart', ctypes.c_uint32), ('HighPart', ctypes.c_int32) @@ -188,11 +188,12 @@ class LARGE_INTEGER(ctypes.Union): ('QuadPart', ctypes.c_int64) ) + # see: # https://www.geoffchappell.com/studies/windows/km/ntoskrnl/structs/kuser_shared_data/index.htm # https://doxygen.reactos.org/d7/deb/xdk_2ketypes_8h_source.html#l01155 -class KUSER_SHARED_DATA(struct.BaseStruct): +class KUSER_SHARED_DATA(struct.BaseStructEL): _fields_ = ( ('TickCountLowDeprecated', ctypes.c_uint32), ('TickCountMultiplier', ctypes.c_uint32), @@ -991,21 +992,23 @@ class LdrDataTableEntry(Struct): return LdrDataTableEntry -class FILETIME(struct.BaseStruct): +class FILETIME(struct.BaseStructEL): _fields_ = ( ('dwLowDateTime', ctypes.c_uint32), ('dwHighDateTime', ctypes.c_int32) ) + # https://docs.microsoft.com/en-us/windows/console/coord-str -class COORD(struct.BaseStruct): +class COORD(struct.BaseStructEL): _fields_ = ( ('X', ctypes.c_uint16), ('Y', ctypes.c_uint16) ) + # https://docs.microsoft.com/en-us/windows/console/small-rect-str -class SMALL_RECT(struct.BaseStruct): +class SMALL_RECT(struct.BaseStructEL): _fields_ = ( ('Left', ctypes.c_uint16), ('Top', ctypes.c_uint16), @@ -1013,8 +1016,9 @@ class SMALL_RECT(struct.BaseStruct): ('Bottom', ctypes.c_uint16) ) + # https://docs.microsoft.com/en-us/windows/console/console-screen-buffer-info-str -class CONSOLE_SCREEN_BUFFER_INFO(struct.BaseStruct): +class CONSOLE_SCREEN_BUFFER_INFO(struct.BaseStructEL): _fields_ = ( ('dwSize', COORD), ('dwCursorPosition', COORD), @@ -1023,6 +1027,7 @@ class CONSOLE_SCREEN_BUFFER_INFO(struct.BaseStruct): ('dwMaximumWindowSize', COORD) ) + # https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntqueryinformationprocess def make_process_basic_info(archbits: int): native_type = struct.get_native_type(archbits) @@ -1040,6 +1045,7 @@ class PROCESS_BASIC_INFORMATION(Struct): return PROCESS_BASIC_INFORMATION + # https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-osversioninfoa def make_os_version_info(archbits: int, *, wide: bool): Struct = struct.get_aligned_struct(archbits) @@ -1182,7 +1188,7 @@ def make_sid(auth_count: int): # byte is actually used. # # see: https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-sid_identifier_authority - class SID_IDENTIFIER_AUTHORITY(ctypes.BigEndianStructure): + class SID_IDENTIFIER_AUTHORITY(struct.BaseStructEB): _pack_ = 1 _fields_ = ( ('Value', ctypes.c_uint32), @@ -1192,7 +1198,7 @@ class SID_IDENTIFIER_AUTHORITY(ctypes.BigEndianStructure): assert ctypes.sizeof(SID_IDENTIFIER_AUTHORITY) == 6 # https://geoffchappell.com/studies/windows/km/ntoskrnl/api/rtl/sertl/sid.htm - class SID(struct.BaseStruct): + class SID(struct.BaseStructEL): _fields_ = ( ('Revision', ctypes.c_uint8), ('SubAuthorityCount', ctypes.c_uint8), @@ -1206,12 +1212,6 @@ class SID(struct.BaseStruct): ('SubAuthority', ctypes.c_uint32 * auth_count) ) - # the need of a big-endian structure forces us to define a non-BaseStruct structure field - # which breaks the 'volatile_ref' mechanism. we here prevent the user from doing that - @classmethod - def volatile_ref(cls, *args): - raise NotImplementedError(f'{cls.__name__} is not capable of volatile references') - # let SID structures be comparable def __eq__(self, other): if not isinstance(other, SID): @@ -1243,7 +1243,7 @@ def isFree(self) -> bool: # _fields_ = ( # ('OriginalFirstThunk', ctypes.c_uint32), # ('TimeDateStamp', ctypes.c_uint32), -# ('ForwarderChain', ctypes.c_uint32), +# ('ForwarderChain', ctypes.c_uint32), # ('Name', ctypes.c_uint32), # ('FirstThunk', ctypes.c_uint32) # ) @@ -1263,7 +1263,7 @@ def isFree(self) -> bool: # ) -class Point(struct.BaseStruct): +class Point(struct.BaseStructEL): _fields_ = ( ('x', ctypes.c_int32), ('y', ctypes.c_int32) @@ -1336,13 +1336,14 @@ class sockaddr_in(ctypes.BigEndianStructure): return sockaddr_in + # https://docs.microsoft.com/en-us/windows/win32/winsock/sockaddr-2 def make_sockaddr_in6(): # https://docs.microsoft.com/en-us/windows/win32/api/in6addr/ns-in6addr-in6_addr class in6_addr(ctypes.BigEndianStructure): _fields_ = ( - ('Byte', ctypes.c_uint8 * 16) + ('Byte', ctypes.c_uint8 * 16), ) class sockaddr_in6(ctypes.BigEndianStructure): @@ -1400,7 +1401,7 @@ class SYSTEM_INFO(Struct): return SYSTEM_INFO -class SYSTEMTIME(struct.BaseStruct): +class SYSTEMTIME(struct.BaseStructEL): _fields_ = ( ('wYear', ctypes.c_uint16), ('wMonth', ctypes.c_uint16), diff --git a/qiling/profiles/dos.ql b/qiling/profiles/dos.ql index 550d0f8d0..2d865a9a5 100644 --- a/qiling/profiles/dos.ql +++ b/qiling/profiles/dos.ql @@ -10,5 +10,4 @@ stack_size = 0x4000 base_address = 0x7000 [MISC] -automatize_input = False current_path = A:\ \ No newline at end of file diff --git a/qiling/utils.py b/qiling/utils.py index 34ce265e1..b3b048019 100644 --- a/qiling/utils.py +++ b/qiling/utils.py @@ -32,15 +32,6 @@ T = TypeVar('T') QlClassInit = Callable[['Qiling'], T] -def catch_KeyboardInterrupt(ql: 'Qiling', func: Callable): - def wrapper(*args, **kw): - try: - return func(*args, **kw) - except BaseException as e: - ql.stop() - ql._internal_exception = e - - return wrapper def __name_to_enum(name: str, mapping: Mapping[str, T], aliases: Mapping[str, str] = {}) -> Optional[T]: key = name.casefold() @@ -473,7 +464,6 @@ def verify_ret(ql: 'Qiling', err): raise __all__ = [ - 'catch_KeyboardInterrupt', 'os_convert', 'arch_convert', 'debugger_convert', diff --git a/qltool b/qltool index 200101e04..be6a52d3f 100755 --- a/qltool +++ b/qltool @@ -8,6 +8,7 @@ import os import sys import ast import pickle +from pprint import pprint from unicorn import __version__ as uc_ver from qiling import __version__ as ql_ver @@ -194,6 +195,10 @@ if __name__ == '__main__': # set "examples" subcommand expl_parser = commands.add_parser('examples', help='show examples and exit', add_help=False) + # set "qltui" subcommand + qltui_parser = commands.add_parser('qltui', help='show qiling Terminal User Interface', add_help=False) + + qltui_enabled = False comm_parser = run_parser if len(sys.argv) > 1 and sys.argv[1] == 'code': @@ -223,12 +228,17 @@ if __name__ == '__main__': if options.subcommand == 'examples': handle_examples(parser) + if options.subcommand == 'qltui': + import qltui + options = qltui.get_data() + qltui_enabled = True + # ql file setup - elif options.subcommand == 'run': + if options.subcommand == 'run': ql = handle_run(options) # ql code setup - elif options.subcommand == 'code': + if options.subcommand == 'code': ql = handle_code(options) # ql execute additional options @@ -251,9 +261,16 @@ if __name__ == '__main__': # ql run with cov_utils.collect_coverage(ql, options.coverage_format, options.coverage_file): + if qltui_enabled: + hook_dictionary = qltui.hook(ql) ql.run(timeout=options.timeout) if options.json: - print(report.generate_report(ql, pretty_print=True)) + report = report.generate_report(ql) + if qltui_enabled: + report["syscalls"] = qltui.transform_syscalls(ql.os.stats.syscalls) + qltui.show_report(ql, report, hook_dictionary) + else: + pprint(report) exit(ql.os.exit_code) diff --git a/qltui.py b/qltui.py new file mode 100644 index 000000000..8e841881f --- /dev/null +++ b/qltui.py @@ -0,0 +1,675 @@ +import os +import ast +import pickle +import re +import six +import argparse +import json + +from pyfx import PyfxApp +from pprint import pprint +from datetime import datetime + +import questionary +from questionary import Validator, ValidationError +try: + from termcolor import colored +except ImportError: + colored = None + +from qiling import Qiling +from qiling.const import os_map, arch_map, verbose_map +from qiling.extensions.coverage import utils as cov_utils + +motd = """ + ██████ ███ ████ ███ + ███░░░░███ ░░░ ░░███ ░░░ + ███ ░░███ ████ ░███ ████ ████████ ███████ +░███ ░███░░███ ░███ ░░███ ░░███░░███ ███░░███ +░███ ██░███ ░███ ░███ ░███ ░███ ░███ ░███ ░███ +░░███ ░░████ ░███ ░███ ░███ ░███ ░███ ░███ ░███ + ░░░██████░██ █████ █████ █████ ████ █████░░███████ + ░░░░░░ ░░ ░░░░░ ░░░░░ ░░░░░ ░░░░ ░░░░░ ░░░░░███ + ███ ░███ + ░░██████ + ░░░░░░ +""" + +ERROR_COLOR = "red" + +HEADING_COLOR = "green" + +OUTPUT_COLOR = "blue" + +TITLE_COLOR = "blue" + +prog = os.path.basename(__file__) + +HEX_REGEX = r'^(0[xX])[a-fA-F0-9]+$' + + +class Callback_Functions(): + """ + Callback Functions for Hook Operation + """ + + @staticmethod + def read_mem(ql: Qiling, *args): + user_data = args[-1] + buff = ql.mem.read(user_data["address"], user_data["bytes_size"]) + ql.log.info(f"Hook was triggered at -> {user_data['address']}") + ql.log.info(buff) + + @staticmethod + def read_reg(ql: Qiling, *args): + user_data = args[-1] + buff = ql.reg.read(user_data["register_name"]) + ql.log.info(f"Hook was triggered at -> {user_data['register_name']}") + ql.log.info(buff) + + @staticmethod + def write_mem(ql: Qiling, *args): + user_data = args[-1] + buff = ql.mem.write(user_data["address"], user_data["value"]) + ql.log.info(f"Hook was triggered at -> {user_data['address']}") + ql.log.info(buff) + + @staticmethod + def write_reg(ql: Qiling, *args): + user_data = args[-1] + buff = ql.reg.write(user_data["register_name"], user_data["value"]) + ql.log.info(f"Hook was triggered at -> {user_data['register_name']}") + ql.log.info(buff) + + @staticmethod + def emu_start(ql: Qiling, *args): + user_data = args[-1] + ql.emu_start(begin=user_data["start"], end=user_data["end"]) + + @staticmethod + def emu_stop(ql: Qiling, *args): + ql.log.info('killer switch found, stopping') + ql.emu_stop() + + @staticmethod + def save(ql: Qiling, *args): + ql.save() + +def env_arg(value): + """ + Function to read env parameter + """ + if value == "{}": + return {} + else: + if os.path.exists(value): + with open(value, 'rb') as f: + env = pickle.load(f) + else: + env = ast.literal_eval(value) + return env + + +def verbose_arg(value): + """ + Function to map Verbose + """ + return verbose_map[value] + + +def read_file(fname: str): + """ + Function to read code from file + """ + with open(fname, "rb") as f: + content = f.read() + + return content + +if colored: + def log(string, color): + """ + Function to beautify terminal output + """ + six.print_(colored(string, color)) +else: + def log(string, color): + """ + Function to beautify terminal output + """ + six.print_(string) + + +class IntValidator(Validator): + """ + Integer validator + """ + def validate(self, value): + try: + int(value.text) + return True + except: + raise ValidationError( + message="Integer required", + cursor_position=len(value.text)) + + +class HexValidator(Validator): + """ + Hex validator + """ + def validate(self, value): + if re.match(HEX_REGEX, value.text): + return True + else: + raise ValidationError( + message="Address required", + cursor_position=len(value.text)) + + +class IntHexValidator(Validator): + """ + Integer/Hex validator + """ + def validate(self, value): + if re.match(HEX_REGEX, str(value.text)): + return True + else: + try: + int(value.text) + return True + except: + raise ValidationError( + message="Integer or Hex required", + cursor_position=len(value.text)) + +class DirectoryPathValidator(Validator): + """ + Required Directory Path validator + """ + def validate(self, value): + if len(value.text): + if os.path.isdir(value.text): + return True + else: + raise ValidationError( + message="Directory not found", + cursor_position=len(value.text)) + else: + return True + + +class RequiredDirectoryPathValidator(Validator): + """ + Directory Path validator + """ + def validate(self, value): + if len(value.text): + if os.path.isdir(value.text): + return True + else: + raise ValidationError( + message="Directory not found", + cursor_position=len(value.text)) + else: + raise ValidationError( + message="You can't leave this blank", + cursor_position=len(value.text)) + + +class FilePathValidator(Validator): + """ + File Path validator + """ + def validate(self, value): + if len(value.text): + if os.path.isfile(value.text): + return True + else: + raise ValidationError( + message="File not found", + cursor_position=len(value.text)) + else: + return True + + +class ENVFilePathValidator(Validator): + """ + File Path validator for env parameter + """ + def validate(self, value): + if value.text == "{}": + return True + if len(value.text): + if os.path.isfile(value.text): + return True + else: + raise ValidationError( + message="File not found", + cursor_position=len(value.text)) + else: + return True + + +def ask_option(): + """ + Ask for operation(run/code) + """ + answer = questionary.select( + "Select an Option:", + choices=['Run', 'Code']).ask() + + return answer.lower() + + +def ask_run_options(): + """ + Ask arguments for run + """ + filename = questionary.path("filename:", validate=FilePathValidator).ask() + + rootfs = questionary.path("rootfs:", only_directories=True, + validate=RequiredDirectoryPathValidator).ask() + + args = questionary.text("args:").ask() + args = args.split() + + run_args = questionary.text("run_args:").ask() + run_args = run_args.split() + + return {"filename": filename, "rootfs": rootfs, "args": args, + "run_args": run_args} + + +def ask_code_options(): + """ + Ask arguments for code + """ + filename = questionary.path("filename:", validate=FilePathValidator).ask() + + input_ = questionary.text("input:").ask() + if not input_: + input_ = None + + format_ = questionary.select( + "format:", + choices=['bin', 'asm', 'hex']).ask() + + arch = questionary.select( + "arch:", + choices=arch_map).ask() + + endian = questionary.select( + "endian:", + choices=['little', 'big']).ask() + + os = questionary.select( + "os:", + choices=os_map).ask() + + rootfs = questionary.path("rootfs:", only_directories=True, + validate=RequiredDirectoryPathValidator, default=".").ask() + + thumb = questionary.confirm("thumb:", + default=False, auto_enter=True).ask() + + return {"filename": filename, "input": input_, "format": format_, + "arch": arch, "endian": endian, "os": os, "rootfs": rootfs, + "thumb": thumb} + + +def ask_additional_options(): + """ + Ask additional options for run/code + """ + options = {} + + verbose = questionary.select( + "verbose:", + choices=list(verbose_map.keys()), + default="default").ask() + verbose = verbose_arg(verbose) + + env = questionary.path("env:", default="{}", validate=ENVFilePathValidator).ask() + env = env_arg(env) + + debug = questionary.confirm("debug:", + default=False, auto_enter=True).ask() + gdb = None + qdb, rr = False, False + if debug: + gdb = questionary.text("\tgdb:").ask() + + qdb = questionary.confirm("\tqdb:", + default=False, auto_enter=True).ask() + + rr = questionary.confirm("\trr:", + default=False, auto_enter=True).ask() + + profile = questionary.text("profile:").ask() + if not profile: + profile = None + + console = questionary.confirm("console:", + default=True, auto_enter=True).ask() + + filter_ = questionary.text("filter:").ask() + if not filter_: + filter_ = None + + log_file = questionary.path("log-file:", validate=FilePathValidator).ask() + if not log_file: + log_file = None + + log_plain = questionary.confirm("log-plain:", + default=False, auto_enter=True).ask() + + root = questionary.confirm("root:", + default=False, auto_enter=True).ask() + + debug_stop = questionary.confirm("debug-stop:", + default=False, auto_enter=True).ask() + + multithread = questionary.confirm("multithread:", + default=False, auto_enter=True).ask() + + timeout = int(questionary.text("profile:", default="0", validate=IntValidator).ask()) + + coverage = questionary.confirm("coverage:", + default=False, auto_enter=True).ask() + coverage_file = None + coverage_format = "drcov" + if coverage: + coverage_file = questionary.path("\tcoverage-file:", validate=FilePathValidator).ask() + + coverage_format = questionary.select( + "\tcoverage-format:", + choices=list(cov_utils.factory.formats), + default="drcov").ask() + + json_ = questionary.confirm("json:", + default=False, auto_enter=True).ask() + + libcache = questionary.confirm("libcache:", + default=False, auto_enter=True).ask() + + options = {"verbose": verbose, "env": env, "gdb": gdb, "qdb": qdb, "rr": rr, "profile": profile, "console": console, + "filter": filter_, "log_file": log_file, + "log_plain": log_plain, "root": root, "debug_stop": debug_stop, + "multithread": multithread, "timeout": timeout, + "coverage_file": coverage_file, "coverage_format": coverage_format, + "json": json_, "libcache": libcache} + + return options + + +def get_data(): + """ + Main Qltui function + """ + print(motd) + log("Welcome to Qiling", HEADING_COLOR) + log("Cross Platform and Multi Architecture Advanced Binary Emulation Framework", HEADING_COLOR) + + command = ask_option() + + if command == 'run': + log("Select Run Options", OUTPUT_COLOR) + command_options = ask_run_options() + + log("Select Additional Options", OUTPUT_COLOR) + additional_options = ask_additional_options() + + elif command == 'code': + log("Select Code Options", OUTPUT_COLOR) + command_options = ask_code_options() + + log("Select Additional Options", OUTPUT_COLOR) + additional_options = ask_additional_options() + + else: + log("Error", ERROR_COLOR) + + command_options.update(additional_options) + options = command_options + options['subcommand'] = command + + namespace = argparse.Namespace(**options) + + return namespace + + +def ask_report(): + """ + Ask for the format of report + """ + answer = questionary.select( + "Select an Option:", + choices=['Report', 'Interactive Report', 'Save to Json', 'Quit']).ask() + + return answer.lower() + + +def show_report(ql: Qiling, report, hook_dictionary): + """ + Ask if user wants to see the report + """ + log("Report", HEADING_COLOR) + + os_map_reverse = dict(zip(os_map.values(), os_map.keys())) + arch_map_reverse = dict(zip(arch_map.values(), arch_map.keys())) + + os_name = os_map_reverse[ql.os.type] + arch_name = arch_map_reverse[ql.arch.type] + + if hook_dictionary: + for key in ['hook_target_address', 'address']: + if key in hook_dictionary: + hook_dictionary[key] = hex(hook_dictionary[key]) + report["hook"] = hook_dictionary + + while True: + command = ask_report() + + if command == 'report': + pprint(report) + elif command == 'interactive report': + PyfxApp(data=report).run() + elif command == 'save to json': + time = datetime.now().strftime("%Y_%m_%d_%H-%M-%S") + report_name = f"report_{ql.targetname.replace('.', '_')}_{os_name}_{arch_name}_{time}.json" + with open(report_name, "w") as json_file: + json_file.write(json.dumps(report)) + print(f"The report was saved in your current directory as {report_name}") + elif command == 'quit': + break + + +def want_to_hook(): + """ + Ask if user wants to hook + """ + answer = questionary.confirm("Want to Hook:", + default=False, auto_enter=True).ask() + + return answer + + +def ask_hook_type(): + """ + Ask for the type of hook + """ + answer = questionary.select( + "Select an Option:", + choices=['hook_address', 'hook_code', 'hook_block', 'hook_intno', + 'hook_mem_unmapped', 'hook_mem_read_invalid', + 'hook_mem_write_invalid', 'hook_mem_fetch_invalid', 'hook_mem_invalid', + 'hook_mem_read', 'hook_mem_write', 'hook_mem_fetch']).ask() + + return answer.lower() + + +def ask_hook_operation(): + """ + Ask for the hook operation + """ + answer = questionary.select( + "Select an Option:", + choices=['read', 'write', 'emu_start', 'emu_stop', 'save']).ask() + + return answer.lower() + + +def get_bytes_size(): + """ + Ask for bytes size + """ + answer = questionary.text("bytes_size:", validate=IntValidator).ask() + + if re.match(HEX_REGEX, str(answer)): + return int(answer, 16) + + return int(answer) + + +def ask_value(): + """ + Ask for value + """ + answer = questionary.text("value:").ask() + + return bytes(answer, 'utf-8') + + +def ask_where(): + """ + Ask what to Hook + """ + answer = questionary.select( + "Select an Option:", + choices=['Memory', 'Register']).ask() + + return answer.lower()[:3] + + +def ask_start_end(): + """ + Ask for start and end points for emulator start + """ + start = questionary.text("address_start:").ask() + end = questionary.text("address_end:", default="0x0").ask() + + return {"start": int(start, 16), "end": int(end, 16)} + + +def ask_address(): + """ + Ask for address to hook + """ + address = questionary.text("address:", validate=HexValidator).ask() + + return int(address, 16) + + +def ask_hook_address(): + """ + Ask for address to hook + """ + address = questionary.text("Hook Traget Address:", validate=HexValidator).ask() + + return int(address, 16) + + +def ask_register_name(): + """ + Ask register name + """ + answer = questionary.text("register_name:").ask() + + return answer + + +def hook(ql: Qiling): + """ + Hook Function + """ + + log("Hook", HEADING_COLOR) + + hook_dictionary = {} + + do_hook = want_to_hook() + + if do_hook: + hook_type = ask_hook_type() + hook_dictionary["hook_type"] = hook_type + + operation = ask_hook_operation() + hook_dictionary["operation"] = operation + + args = [] + user_data = {} + + if hook_type == "hook_address": + hook_target_address = ask_hook_address() + args.append(hook_target_address) + hook_dictionary["hook_target_address"] = hook_target_address + + if operation in ['read', 'write']: + where = ask_where() + hook_dictionary["storage"] = where + if where == 'mem': + address = ask_address() + user_data["address"] = address + hook_dictionary["address"] = address + if operation == 'read': + bytes_size = get_bytes_size() + user_data["bytes_size"] = bytes_size + hook_dictionary["bytes_size"] = bytes_size + operation = 'read_mem' + else: + value = ask_value() + user_data["value"] = value + hook_dictionary["value"] = value + operation = 'write_mem' + else: + register_name = ask_register_name() + user_data["register_name"] = register_name + hook_dictionary["register_name"] = register_name + if operation == 'read': + operation = 'read_reg' + else: + value = ask_value() + user_data["value"] = value + hook_dictionary["value"] = value + operation = 'write_reg' + + if operation == 'emu_start': + start_end = ask_start_end() + user_data["start"] = start_end["start"] + user_data["end"] = start_end["end"] + hook_dictionary["start"] = start + hook_dictionary["end"] = end + + if user_data: + hook_dictionary["user_data"] = user_data + + getattr(ql, hook_type)(getattr(Callback_Functions, operation), *args, user_data=user_data) + + return hook_dictionary + + +def transform_syscalls(syscalls, keys=["address"], func=lambda x: hex(x)): + for i in syscalls: + try: + if isinstance(i, list) or isinstance(i, dict): + transform_syscalls(i, keys, func) + elif isinstance(syscalls[i], list) or isinstance(syscalls[i], dict): + transform_syscalls(syscalls[i], keys, func) + + if i in keys and isinstance(syscalls[i], int): + syscalls[i] = func(syscalls[i]) + except: + pass + + return syscalls diff --git a/setup.py b/setup.py index 8ba0b753e..7a67ad7b6 100644 --- a/setup.py +++ b/setup.py @@ -5,12 +5,12 @@ from setuptools import setup, find_packages # NOTE: use "-dev" for dev branch -#VERSION = "1.4.5" + "-dev" -VERSION = "1.4.4" +#VERSION = "1.4.6" + "-dev" +VERSION = "1.4.5" requirements = [ "capstone>=4.0.1", - "unicorn>=2.0.0", + "unicorn>=2.0.1", "pefile>=2022.5.30", "python-registry>=1.3.1", "keystone-engine>=0.9.2", @@ -19,6 +19,9 @@ "multiprocess>=0.70.12.2", "windows-curses>=2.1.0;platform_system=='Windows'", "pyyaml>=6.0", + "python-fx", + "questionary", + "termcolor", ] extras = { diff --git a/tests/profiles/stm32f411.yml b/tests/profiles/stm32f411.yml deleted file mode 100644 index 400eb410c..000000000 --- a/tests/profiles/stm32f411.yml +++ /dev/null @@ -1,355 +0,0 @@ -{ - "ADC1": { - "base": 0x40012000, - "struct": "STM32F4xxAdc", - "type": "peripheral" - }, - "CRC": { - "base": 0x40023000, - "struct": "STM32F4xxCrc", - "type": "peripheral" - }, - "DBGMCU": { - "base": 0xe0042000, - "struct": "STM32F4xxDbgmcu", - "kwargs": { - "dev_id": 0x413, - }, - "type": "peripheral" - }, - "DMA1": { - "base": 0x40026000, - "struct": "STM32F4xxDma", - "kwargs": { - "stream0_intn": 11, - "stream1_intn": 12, - "stream2_intn": 13, - "stream3_intn": 14, - "stream4_intn": 15, - "stream5_intn": 16, - "stream6_intn": 17, - "stream7_intn": 47 - }, - "type": "peripheral" - }, - "DMA2": { - "base": 0x40026400, - "struct": "STM32F4xxDma", - "kwargs": { - "stream0_intn": 56, - "stream1_intn": 57, - "stream2_intn": 58, - "stream3_intn": 59, - "stream4_intn": 60, - "stream5_intn": 68, - "stream6_intn": 69, - "stream7_intn": 70 - }, - "type": "peripheral" - }, - "EXTI": { - "base": 0x40013c00, - "struct": "STM32F4xxExti", - "type": "peripheral" - }, - "CODE": { - "base": 0x08000000, - "size": 0x10000, - "alias": 0x0, - "type": "remap" - }, - "FLASH": { - "base": 0x08000000, - "size": 0x80000, - "type": "memory" - }, - "FLASH OTP": { - "base": 0x1fff7800, - "size": 0x400, - "type": "memory" - }, - "GPIOA": { - "base": 0x40020000, - "struct": "STM32F4xxGpio", - "type": "peripheral" - }, - "GPIOB": { - "base": 0x40020400, - "struct": "STM32F4xxGpio", - "type": "peripheral" - }, - "GPIOC": { - "base": 0x40020800, - "struct": "STM32F4xxGpio", - "type": "peripheral" - }, - "GPIOD": { - "base": 0x40020c00, - "struct": "STM32F4xxGpio", - "type": "peripheral" - }, - "GPIOE": { - "base": 0x40021000, - "struct": "STM32F4xxGpio", - "type": "peripheral" - }, - "GPIOH": { - "base": 0x40021c00, - "struct": "STM32F4xxGpio", - "type": "peripheral" - }, - "I2C1": { - "base": 0x40005400, - "struct": "STM32F4xxI2c", - "kwargs": { - "er_intn": 32, - "ev_intn": 31 - }, - "type": "peripheral" - }, - "I2C2": { - "base": 0x40005800, - "struct": "STM32F4xxI2c", - "kwargs": { - "er_intn": 34, - "ev_intn": 33 - }, - "type": "peripheral" - }, - "I2C3": { - "base": 0x40005c00, - "struct": "STM32F4xxI2c", - "kwargs": { - "er_intn": 73, - "ev_intn": 72 - }, - "type": "peripheral" - }, - "I2S2ext": { - "base": 0x40003400, - "struct": "STM32F4xxSpi", - "type": "peripheral" - }, - "I2S3ext": { - "base": 0x40004000, - "struct": "STM32F4xxSpi", - "type": "peripheral" - }, - "IWDG": { - "base": 0x40003000, - "struct": "STM32F4xxIwdg", - "type": "peripheral" - }, - "NVIC": { - "base": 0xe000e100, - "struct": "CortexM4Nvic", - "type": "core" - }, - "PERIP": { - "base": 0x40000000, - "size": 0x100000, - "type": "mmio" - }, - "PERIP BB": { - "alias": 0x42000000, - "base": 0x40000000, - "size": 0x100000, - "type": "bitband" - }, - "PPB": { - "base": 0xe0000000, - "size": 0x10000, - "type": "mmio" - }, - "PWR": { - "base": 0x40007000, - "struct": "STM32F4xxPwr", - "type": "peripheral" - }, - "RCC": { - "base": 0x40023800, - "struct": "STM32F4xxRcc", - "kwargs": { - "intn": 5 - }, - "type": "peripheral" - }, - "RTC": { - "base": 0x40002800, - "struct": "STM32F4xxRtc", - "kwargs": { - "alarm_intn": 41, - "wkup_intn": 3 - }, - "type": "peripheral" - }, - "SCB": { - "base": 0xe000ed00, - "struct": "CortexM4Scb", - "type": "core" - }, - "SDIO": { - "base": 0x40012c00, - "struct": "STM32F4xxSdio", - "kwargs": { - "intn": 49 - }, - "type": "peripheral" - }, - "SPI1": { - "base": 0x40013000, - "struct": "STM32F4xxSpi", - "kwargs": { - "intn": 35 - }, - "type": "peripheral" - }, - "SPI2": { - "base": 0x40003800, - "struct": "STM32F4xxSpi", - "kwargs": { - "intn": 36 - }, - "type": "peripheral" - }, - "SPI3": { - "base": 0x40003c00, - "struct": "STM32F4xxSpi", - "kwargs": { - "intn": 51 - }, - "type": "peripheral" - }, - "SPI4": { - "base": 0x40013400, - "struct": "STM32F4xxSpi", - "kwargs": { - "intn": 84 - }, - "type": "peripheral" - }, - "SPI5": { - "base": 0x40015000, - "struct": "STM32F4xxSpi", - "kwargs": { - "intn": 85 - }, - "type": "peripheral" - }, - "SRAM": { - "base": 0x20000000, - "size": 0x20000, - "type": "memory" - }, - "SRAM BB": { - "alias": 0x22000000, - "base": 0x20000000, - "size": 0x100000, - "type": "bitband" - }, - "SYSCFG": { - "base": 0x40013800, - "struct": "STM32F4xxSyscfg", - "type": "peripheral" - }, - "SYSTEM": { - "base": 0x1fff0000, - "size": 0x7800, - "type": "memory" - }, - "SYSTICK": { - "base": 0xe000e010, - "struct": "CortexM4SysTick", - "type": "core" - }, - "TIM1": { - "base": 0x40010000, - "struct": "STM32F4xxTim", - "kwargs": { - "brk_tim9_intn": 24, - "cc_intn": 27, - "trg_com_tim11_intn": 26, - "up_tim10_intn": 25 - }, - "type": "peripheral" - }, - "TIM10": { - "base": 0x40014400, - "struct": "STM32F4xxTim", - "type": "peripheral" - }, - "TIM11": { - "base": 0x40014800, - "struct": "STM32F4xxTim", - "type": "peripheral" - }, - "TIM2": { - "base": 0x40000000, - "struct": "STM32F4xxTim", - "kwargs": { - "intn": 28 - }, - "type": "peripheral" - }, - "TIM3": { - "base": 0x40000400, - "struct": "STM32F4xxTim", - "kwargs": { - "intn": 29 - }, - "type": "peripheral" - }, - "TIM4": { - "base": 0x40000800, - "struct": "STM32F4xxTim", - "kwargs": { - "intn": 30 - }, - "type": "peripheral" - }, - "TIM5": { - "base": 0x40000c00, - "struct": "STM32F4xxTim", - "kwargs": { - "intn": 50 - }, - "type": "peripheral" - }, - "TIM9": { - "base": 0x40014000, - "struct": "STM32F4xxTim", - "type": "peripheral" - }, - "USART1": { - "base": 0x40011000, - "struct": "STM32F4xxUsart", - "kwargs": { - "intn": 37 - }, - "type": "peripheral" - }, - "USART2": { - "base": 0x40004400, - "struct": "STM32F4xxUsart", - "kwargs": { - "intn": 38 - }, - "type": "peripheral" - }, - "USART6": { - "base": 0x40011400, - "struct": "STM32F4xxUsart", - "kwargs": { - "intn": 71 - }, - "type": "peripheral" - }, - "WWDG": { - "base": 0x40002c00, - "struct": "STM32F4xxWwdg", - "kwargs": { - "intn": 0 - }, - "type": "peripheral" - } -} \ No newline at end of file diff --git a/tests/test_android.py b/tests/test_android.py index 04407433b..1556bc02d 100644 --- a/tests/test_android.py +++ b/tests/test_android.py @@ -3,7 +3,7 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -import os, platform, sys, unittest +import platform, sys, unittest from collections import defaultdict sys.path.append("..") @@ -13,47 +13,69 @@ class Fake_maps(QlFsMappedObject): - def __init__(self, ql): + def __init__(self, ql: Qiling): self.ql = ql + def read(self, size): - stack = next(filter(lambda x : x[3]=='[stack]', self.ql.mem.map_info)) - return ('%x-%x %s\n' % (stack[0], stack[1], stack[3])).encode() + return ''.join(f'{lbound:x}-{ubound:x} {perms}p {label}\n' for lbound, ubound, perms, label, _ in self.ql.mem.get_mapinfo()).encode() + def fstat(self): return defaultdict(int) + def close(self): return 0 -def my_syscall_close(ql, fd): - if fd in [0, 1, 2]: + +def my_syscall_close(ql: Qiling, fd: int) -> int: + if fd in (0, 1, 2): return 0 + return syscall.ql_syscall_close(ql, fd) +# addresses specified on non-fixed mmap calls are used as hints, where the allocated +# address can never be less than the value set for mmap_address. nevertheless, android +# uses a non-fixed mmap call to map "/system/framework/arm64/boot.art" at 0x70000000 +# and fails if mmap allocates it elsewhere. +# +# this override sets a lower value for mmap_address to allow android map the file using +# a non-fixed mmap call to exactly where it wants it to be. +OVERRIDES = {'mmap_address': 0x68000000} + + class TestAndroid(unittest.TestCase): @unittest.skipUnless(platform.system() == 'Linux', 'run only on Linux') def test_android_arm64(self): - test_binary = "../examples/rootfs/arm64_android6.0/bin/arm64_android_jniart" rootfs = "../examples/rootfs/arm64_android6.0" - env = {"ANDROID_DATA":"/data", "ANDROID_ROOT":"/system"} + env = { + 'ANDROID_DATA': r'/data', + 'ANDROID_ROOT': r'/system' + } + + ql = Qiling([test_binary], rootfs, env, profile={'OS64': OVERRIDES}, multithread=True) - ql = Qiling([test_binary], rootfs, env, multithread=True) ql.os.set_syscall("close", my_syscall_close) ql.add_fs_mapper("/proc/self/task/2000/maps", Fake_maps(ql)) ql.run() - del ql + del ql @unittest.skipUnless(platform.system() == 'Linux', 'run only on Linux') def test_android_arm(self): test_binary = "../examples/rootfs/arm64_android6.0/bin/arm_android_jniart" rootfs = "../examples/rootfs/arm64_android6.0" - env = {"ANDROID_DATA":"/data", "ANDROID_ROOT":"/system"} + env = { + 'ANDROID_DATA': r'/data', + 'ANDROID_ROOT': r'/system' + } + + ql = Qiling([test_binary], rootfs, env, profile={'OS32': OVERRIDES}, multithread=True) - ql = Qiling([test_binary], rootfs, env, multithread=True) ql.os.set_syscall("close", my_syscall_close) ql.add_fs_mapper("/proc/self/task/2000/maps", Fake_maps(ql)) ql.run() + del ql diff --git a/tests/test_elf_multithread.py b/tests/test_elf_multithread.py index fc7a62f3a..2121deb46 100644 --- a/tests/test_elf_multithread.py +++ b/tests/test_elf_multithread.py @@ -3,7 +3,7 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -import platform, sys, unittest, os, threading, time +import http.client, platform, socket, sys, os, threading, time, unittest sys.path.append("..") from qiling import Qiling @@ -15,7 +15,7 @@ class ELFTest(unittest.TestCase): @unittest.skipIf(platform.system() == "Darwin" and platform.machine() == "arm64", 'darwin host') def test_elf_linux_execve_x8664(self): - ql = Qiling(["../examples/rootfs/x8664_linux/bin/posix_syscall_execve"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) + ql = Qiling(["../examples/rootfs/x8664_linux/bin/posix_syscall_execve"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG) ql.run() for key, value in ql.loader.env.items(): @@ -27,12 +27,8 @@ def test_elf_linux_execve_x8664(self): del QL_TEST del ql - def test_elf_linux_cloexec_x8664(self): - ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_cloexec_test"], - "../examples/rootfs/x8664_linux", - verbose=QL_VERBOSE.DEBUG, - multithread=True) + ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_cloexec_test"], "../examples/rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG, multithread=True) filename = 'output.txt' err = ql_file.open(filename, os.O_RDWR | os.O_CREAT, 0o777) @@ -51,7 +47,6 @@ def test_elf_linux_cloexec_x8664(self): del ql - def test_multithread_elf_linux_x86(self): def check_write(ql, write_fd, write_buf, write_count, *args, **kw): nonlocal buf_out @@ -70,7 +65,6 @@ def check_write(ql, write_fd, write_buf, write_count, *args, **kw): del ql - def test_multithread_elf_linux_arm64(self): def check_write(ql, write_fd, write_buf, write_count, *args, **kw): nonlocal buf_out @@ -89,7 +83,6 @@ def check_write(ql, write_fd, write_buf, write_count, *args, **kw): del ql - def test_multithread_elf_linux_x8664(self): def check_write(ql, write_fd, write_buf, write_count, *args, **kw): nonlocal buf_out @@ -108,7 +101,6 @@ def check_write(ql, write_fd, write_buf, write_count, *args, **kw): del ql - def test_multithread_elf_linux_mips32eb(self): def check_write(ql, write_fd, write_buf, write_count, *args, **kw): nonlocal buf_out @@ -119,7 +111,7 @@ def check_write(ql, write_fd, write_buf, write_count, *args, **kw): except: pass buf_out = None - ql = Qiling(["../examples/rootfs/mips32_linux/bin/mips32_multithreading"], "../examples/rootfs/mips32_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + ql = Qiling(["../examples/rootfs/mips32_linux/bin/mips32_multithreading"], "../examples/rootfs/mips32_linux", verbose=QL_VERBOSE.DEBUG, multithread=True) ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) ql.run() @@ -127,7 +119,6 @@ def check_write(ql, write_fd, write_buf, write_count, *args, **kw): del ql - def test_multithread_elf_linux_mips32el(self): def check_write(ql, write_fd, write_buf, write_count, *args, **kw): nonlocal buf_out @@ -146,7 +137,6 @@ def check_write(ql, write_fd, write_buf, write_count, *args, **kw): del ql - def test_multithread_elf_linux_arm(self): def check_write(ql, write_fd, write_buf, write_count, *args, **kw): nonlocal buf_out @@ -165,25 +155,24 @@ def check_write(ql, write_fd, write_buf, write_count, *args, **kw): del ql - - def test_multithread_elf_linux_armeb(self): - def check_write(ql, write_fd, write_buf, write_count, *args, **kw): - nonlocal buf_out - try: - buf = ql.mem.read(write_buf, write_count) - buf = buf.decode() - buf_out = buf - except: - pass - buf_out = None - ql = Qiling(["../examples/rootfs/armeb_linux/bin/armeb_multithreading"], "../examples/rootfs/armeb_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) - ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) - ql.run() - - self.assertTrue("thread 2 ret val is" in buf_out) - - del ql - + # unicorn.unicorn.UcError: Invalid instruction (UC_ERR_INSN_INVALID) + # def test_multithread_elf_linux_armeb(self): + # def check_write(ql, write_fd, write_buf, write_count, *args, **kw): + # nonlocal buf_out + # try: + # buf = ql.mem.read(write_buf, write_count) + # buf = buf.decode() + # buf_out = buf + # except: + # pass + # buf_out = None + # ql = Qiling(["../examples/rootfs/armeb_linux/bin/armeb_multithreading"], "../examples/rootfs/armeb_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + # ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) + # ql.run() + + # self.assertTrue("thread 2 ret val is" in buf_out) + + # del ql def test_tcp_elf_linux_x86(self): def check_write(ql, write_fd, write_buf, write_count, *args, **kw): @@ -194,7 +183,7 @@ def check_write(ql, write_fd, write_buf, write_count, *args, **kw): ql.buf_out = buf except: pass - ql = Qiling(["../examples/rootfs/x86_linux/bin/x86_tcp_test","20001"], "../examples/rootfs/x86_linux", multithread=True) + ql = Qiling(["../examples/rootfs/x86_linux/bin/x86_tcp_test", "20001"], "../examples/rootfs/x86_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) ql.run() @@ -202,7 +191,6 @@ def check_write(ql, write_fd, write_buf, write_count, *args, **kw): del ql - def test_tcp_elf_linux_x8664(self): def check_write(ql, write_fd, write_buf, write_count, *args, **kw): try: @@ -212,7 +200,7 @@ def check_write(ql, write_fd, write_buf, write_count, *args, **kw): ql.buf_out = buf except: pass - ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_tcp_test","20002"], "../examples/rootfs/x8664_linux", multithread=True) + ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_tcp_test", "20002"], "../examples/rootfs/x8664_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) ql.run() @@ -220,7 +208,6 @@ def check_write(ql, write_fd, write_buf, write_count, *args, **kw): del ql - def test_tcp_elf_linux_arm(self): def check_write(ql, write_fd, write_buf, write_count, *args, **kw): try: @@ -230,7 +217,7 @@ def check_write(ql, write_fd, write_buf, write_count, *args, **kw): ql.buf_out = buf except: pass - ql = Qiling(["../examples/rootfs/arm_linux/bin/arm_tcp_test","20003"], "../examples/rootfs/arm_linux", multithread=True) + ql = Qiling(["../examples/rootfs/arm_linux/bin/arm_tcp_test", "20003"], "../examples/rootfs/arm_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) ql.run() @@ -248,7 +235,7 @@ def check_write(ql, write_fd, write_buf, write_count, *args, **kw): ql.buf_out = buf except: pass - ql = Qiling(["../examples/rootfs/arm64_linux/bin/arm64_tcp_test","20004"], "../examples/rootfs/arm64_linux", multithread=True) + ql = Qiling(["../examples/rootfs/arm64_linux/bin/arm64_tcp_test", "20004"], "../examples/rootfs/arm64_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) ql.run() @@ -266,7 +253,7 @@ def check_write(ql, write_fd, write_buf, write_count, *args, **kw): ql.buf_out = buf except: pass - ql = Qiling(["../examples/rootfs/armeb_linux/bin/armeb_tcp_test","20003"], "../examples/rootfs/armeb_linux", multithread=True) + ql = Qiling(["../examples/rootfs/armeb_linux/bin/armeb_tcp_test", "20003"], "../examples/rootfs/armeb_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) ql.run() @@ -276,13 +263,13 @@ def check_write(ql, write_fd, write_buf, write_count, *args, **kw): def test_tcp_elf_linux_mips32eb(self): - ql = Qiling(["../examples/rootfs/mips32_linux/bin/mips32_tcp_test","20005"], "../examples/rootfs/mips32_linux", multithread=True) + ql = Qiling(["../examples/rootfs/mips32_linux/bin/mips32_tcp_test", "20005"], "../examples/rootfs/mips32_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) ql.run() del ql def test_tcp_elf_linux_mips32el(self): - ql = Qiling(["../examples/rootfs/mips32el_linux/bin/mips32el_tcp_test","20005"], "../examples/rootfs/mips32el_linux", multithread=True) + ql = Qiling(["../examples/rootfs/mips32el_linux/bin/mips32el_tcp_test", "20005"], "../examples/rootfs/mips32el_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) ql.run() del ql @@ -297,7 +284,7 @@ def check_write(ql, write_fd, write_buf, write_count, *args, **kw): except: pass - ql = Qiling(["../examples/rootfs/x86_linux/bin/x86_udp_test","20007"], "../examples/rootfs/x86_linux", multithread=True) + ql = Qiling(["../examples/rootfs/x86_linux/bin/x86_udp_test", "20007"], "../examples/rootfs/x86_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) ql.run() @@ -316,7 +303,7 @@ def check_write(ql, write_fd, write_buf, write_count, *args, **kw): except: pass - ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_udp_test","20008"], "../examples/rootfs/x8664_linux", multithread=True) + ql = Qiling(["../examples/rootfs/x8664_linux/bin/x8664_udp_test", "20008"], "../examples/rootfs/x8664_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) ql.run() @@ -334,7 +321,7 @@ def check_write(ql, write_fd, write_buf, write_count, *args, **kw): except: pass - ql = Qiling(["../examples/rootfs/arm64_linux/bin/arm64_udp_test","20009"], "../examples/rootfs/arm64_linux", multithread=True) + ql = Qiling(["../examples/rootfs/arm64_linux/bin/arm64_udp_test", "20009"], "../examples/rootfs/arm64_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) ql.run() @@ -352,7 +339,7 @@ def check_write(ql, write_fd, write_buf, write_count, *args, **kw): except: pass - ql = Qiling(["../examples/rootfs/armeb_linux/bin/armeb_udp_test","20010"], "../examples/rootfs/armeb_linux", multithread=True) + ql = Qiling(["../examples/rootfs/armeb_linux/bin/armeb_udp_test", "20010"], "../examples/rootfs/armeb_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) ql.os.set_syscall("write", check_write, QL_INTERCEPT.ENTER) ql.run() @@ -362,45 +349,51 @@ def check_write(ql, write_fd, write_buf, write_count, *args, **kw): def test_http_elf_linux_x8664(self): def picohttpd(): - ql = Qiling(["../examples/rootfs/x8664_linux/bin/picohttpd","12911"], "../examples/rootfs/x8664_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + ql = Qiling(["../examples/rootfs/x8664_linux/bin/picohttpd", "12911"], "../examples/rootfs/x8664_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) ql.run() - picohttpd_therad = threading.Thread(target=picohttpd, daemon=True) picohttpd_therad.start() time.sleep(1) - f = os.popen("curl http://127.0.0.1:12911") - self.assertEqual("httpd_test_successful", f.read()) + f = http.client.HTTPConnection('localhost', 12911, timeout=10) + f.request("GET", "/") + response = f.getresponse() + self.assertEqual("httpd_test_successful", response.read().decode()) def test_http_elf_linux_arm(self): def picohttpd(): - ql = Qiling(["../examples/rootfs/arm_linux/bin/picohttpd","12912"], "../examples/rootfs/arm_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + ql = Qiling(["../examples/rootfs/arm_linux/bin/picohttpd", "12912"], "../examples/rootfs/arm_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) ql.run() - picohttpd_therad = threading.Thread(target=picohttpd, daemon=True) picohttpd_therad.start() time.sleep(1) - f = os.popen("curl http://127.0.0.1:12912") - self.assertEqual("httpd_test_successful", f.read()) + f = http.client.HTTPConnection('localhost', 12912, timeout=10) + f.request("GET", "/") + response = f.getresponse() + self.assertEqual("httpd_test_successful", response.read().decode()) def test_http_elf_linux_armeb(self): def picohttpd(): - ql = Qiling(["../examples/rootfs/armeb_linux/bin/picohttpd"], "../examples/rootfs/armeb_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) + ql = Qiling(["../examples/rootfs/armeb_linux/bin/picohttpd", "12913"], "../examples/rootfs/armeb_linux", multithread=True, verbose=QL_VERBOSE.DEBUG) ql.run() - picohttpd_thread = threading.Thread(target=picohttpd, daemon=True) picohttpd_thread.start() time.sleep(1) - f = os.popen("curl http://127.0.0.1:12913") - self.assertEqual("httpd_test_successful", f.read()) + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + s.connect(("localhost", 12913)) + s.sendall(b"GET / HTTP/1.1\r\nHost: 127.0.0.1:12913\r\nUser-Agent: curl/7.74.0\r\nAccept: */*\r\n\r\n") + data = s.recv(1024) + + res = data.decode("UTF-8",'replace') + self.assertIn("httpd_test_successful", res) if __name__ == "__main__": diff --git a/tests/test_evm.py b/tests/test_evm.py index 79cf062bc..4e8c1d4f9 100644 --- a/tests/test_evm.py +++ b/tests/test_evm.py @@ -13,12 +13,18 @@ if platform.system() == "Darwin" and platform.machine() == "arm64": sys.exit(0) +# python 3.10 has not been supported yet in the latest blake2b-py release +if sys.version_info >= (3,10): + sys.exit(0) + + class Checklist: def __init__(self) -> None: self.visited_hookcode = False self.visited_hookinsn = False self.visited_hookaddr = False + class EVMTest(unittest.TestCase): def test_underflow_code(self): ql = Qiling(code="0x6060604052341561000f57600080fd5b60405160208061031c833981016040528080519060200190919050508060018190556000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050610299806100836000396000f300606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806318160ddd1461005c57806370a0823114610085578063a9059cbb146100d2575b600080fd5b341561006757600080fd5b61006f61012c565b6040518082815260200191505060405180910390f35b341561009057600080fd5b6100bc600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610132565b6040518082815260200191505060405180910390f35b34156100dd57600080fd5b610112600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061017a565b604051808215151515815260200191505060405180910390f35b60015481565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600080826000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205403101515156101cb57600080fd5b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555060019050929150505600a165627a7a7230582098f1551a391a3e65b3ce45cfa2b3fa5f91eea9a3e7181a81454e025ea0d7151c0029",archtype="evm", verbose=4) @@ -145,5 +151,6 @@ def test_abi_encoding(self): result_data = ql.arch.evm.abi.decode_params(['string'], result.output) self.assertEqual(call_param[0], result_data[0]) + if __name__ == "__main__": unittest.main() \ No newline at end of file diff --git a/tests/test_mcu.py b/tests/test_mcu.py index 563924f0c..8fa7500e1 100644 --- a/tests/test_mcu.py +++ b/tests/test_mcu.py @@ -9,7 +9,7 @@ from qiling.core import Qiling from qiling.const import QL_VERBOSE -from qiling.extensions.mcu.stm32f4 import stm32f407, stm32f411 +from qiling.extensions.mcu.stm32f4 import stm32f407, stm32f411, stm32f429 from qiling.extensions.mcu.stm32f1 import stm32f103 from qiling.extensions.mcu.atmel import sam3x8e from qiling.extensions.mcu.gd32vf1 import gd32vf103 @@ -17,30 +17,44 @@ class MCUTest(unittest.TestCase): def test_mcu_led_stm32f411(self): ql = Qiling(["../examples/rootfs/mcu/stm32f411/rand_blink.hex"], - archtype="cortex_m", env=stm32f411, verbose=QL_VERBOSE.DISASM) + archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DISASM) # Set verbose=QL_VERBOSE.DEFAULT to find warning ql.run(count=1000) del ql - def test_mcu_usart_output_stm32f411(self): - ql = Qiling(["../examples/rootfs/mcu/stm32f411/hello_usart.hex"], - archtype="cortex_m", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) + def test_mcu_snapshot_stm32f411(self): + def create_qiling(): + ql = Qiling(["../examples/rootfs/mcu/stm32f411/hello_usart.hex"], + archtype="cortex_m", ostype="mcu", env=stm32f411) - ql.hw.create('usart2') - ql.hw.create('rcc') + ql.hw.create('usart2') + ql.hw.create('rcc') - ql.run(count=2000) - buf = ql.hw.usart2.recv() - print('[1] Received from usart: ', buf) - self.assertEqual(buf, b'Hello USART\n') + return ql - del ql + ql1 = create_qiling() + ql1.run(count=1500) + buf1 = ql1.hw.usart2.recv() + print('[1] Received from usart: ', buf1) + + snapshot = ql1.save(hw=True) + + ql2 = create_qiling() + ql2.restore(snapshot) + + ql2.run(count=500) + buf2 = ql2.hw.usart2.recv() + print('[2] Received from usart: ', buf2) + + self.assertEqual(buf1 + buf2, b'Hello USART\n') + + del ql1, ql2 def test_mcu_usart_input_stm32f411(self): ql = Qiling(["../examples/rootfs/mcu/stm32f411/md5_server.hex"], - archtype="cortex_m", env=stm32f411, verbose=QL_VERBOSE.OFF) + archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.OFF) ql.hw.create('usart2') ql.hw.create('rcc') @@ -61,7 +75,7 @@ def test_mcu_usart_input_stm32f411(self): def test_mcu_patch_stm32f411(self): ql = Qiling(["../examples/rootfs/mcu/stm32f411/patch_test.hex"], - archtype="cortex_m", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) + archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) ql.hw.create('usart2') ql.hw.create('rcc') @@ -74,7 +88,7 @@ def test_mcu_patch_stm32f411(self): def test_mcu_freertos_stm32f411(self): ql = Qiling(["../examples/rootfs/mcu/stm32f411/os-demo.elf"], - archtype="cortex_m", env=stm32f411, verbose=QL_VERBOSE.DEBUG) + archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DISABLED) ql.hw.create('usart2') ql.hw.create('rcc') @@ -87,7 +101,8 @@ def counter(): ql.hw.gpioa.hook_set(5, counter) - ql.run(count=200000) + ql.hw.systick.ratio = 0xff + ql.run(count=100000) self.assertTrue(count >= 5) self.assertTrue(ql.hw.usart2.recv().startswith(b'Free RTOS\n' * 5)) @@ -96,7 +111,7 @@ def counter(): def test_mcu_dma_stm32f411(self): ql = Qiling(["../examples/rootfs/mcu/stm32f411/dma-clock.elf"], - archtype="cortex_m", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) + archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) ql.hw.create('usart2') ql.hw.create('dma1') @@ -114,7 +129,7 @@ def test_mcu_dma_stm32f411(self): def test_mcu_i2c_stm32f411(self): ql = Qiling(["../examples/rootfs/mcu/stm32f411/i2c-lcd.bin", 0x8000000], - archtype="cortex_m", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) + archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) ql.hw.create('i2c1') ql.hw.create('rcc') @@ -146,7 +161,7 @@ def step(self): def test_mcu_spi_stm32f411(self): ql = Qiling(["../examples/rootfs/mcu/stm32f411/spi-test.bin", 0x8000000], - archtype="cortex_m", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) + archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) ql.hw.create('spi1') ql.hw.create('rcc') @@ -160,7 +175,7 @@ def test_mcu_spi_stm32f411(self): def test_mcu_led_rust_stm32f411(self): ql = Qiling(["../examples/rootfs/mcu/stm32f411/led-rust.hex"], - archtype="cortex_m", env=gd32vf103, profile="profiles/stm32f411.yml", verbose=QL_VERBOSE.DEFAULT) + archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) count = 0 def counter(): @@ -175,26 +190,10 @@ def counter(): del ql - def test_mcu_uart_rust_stm32f411(self): - ql = Qiling(["../examples/rootfs/mcu/stm32f411/uart-rust.hex"], - archtype="cortex_m", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) - - ## cover env by profiles - - ql.hw.create('rcc') - ql.hw.create('gpioa') - ql.hw.create('usart2') - - ql.hw.usart2.send(b'123') - ql.run(count=10000) - self.assertTrue(ql.hw.usart2.recv() == b'1') - - del ql - def test_mcu_hacklock_stm32f407(self): def crack(passwd): ql = Qiling(["../examples/rootfs/mcu/stm32f407/backdoorlock.hex"], - archtype="cortex_m", env=stm32f407, verbose=QL_VERBOSE.OFF) + archtype="cortex_m", ostype="mcu", env=stm32f407, verbose=QL_VERBOSE.OFF) ql.hw.create('spi2') ql.hw.create('gpioe') @@ -223,7 +222,7 @@ def crack(passwd): def test_mcu_tim_speed_stm32f411(self): ql = Qiling(['../examples/rootfs/mcu/stm32f411/basic-timer.elf'], - archtype="cortex_m", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) + archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) ql.hw.create('rcc') ql.hw.create('flash interface') @@ -262,7 +261,7 @@ def counter(): def test_mcu_i2c_interrupt_stm32f411(self): ql = Qiling(['../examples/rootfs/mcu/stm32f411/i2cit-lcd.elf'], - archtype="cortex_m", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) + archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEFAULT) ql.hw.create('i2c1') ql.hw.create('rcc').watch() @@ -296,8 +295,8 @@ def skip_delay(ql): def test_mcu_blink_gd32vf103(self): - ql = Qiling(['../examples/rootfs/mcu/gd32vf103/blink.hex'], - ostype="mcu", archtype="riscv64", env=gd32vf103, verbose=QL_VERBOSE.DEFAULT) + ql = Qiling(['../examples/rootfs/mcu/gd32vf103/blink.hex'], archtype="riscv", + env=gd32vf103, ostype="mcu", verbose=QL_VERBOSE.DEFAULT) ql.hw.create('rcu') ql.hw.create('gpioa') @@ -323,7 +322,7 @@ def counter(): def test_mcu_crc_stm32f407(self): ql = Qiling(["../examples/rootfs/mcu/stm32f407/ai-sine-test.elf"], - archtype="cortex_m", env=stm32f407, verbose=QL_VERBOSE.DEFAULT) + archtype="cortex_m", ostype="mcu", env=stm32f407, verbose=QL_VERBOSE.DEFAULT) ql.hw.create('rcc') ql.hw.create('pwr') @@ -351,7 +350,7 @@ def indicator(ql): def test_mcu_usart_stm32f103(self): ql = Qiling(["../examples/rootfs/mcu/stm32f103/sctf2020-password-lock-plus.hex"], - archtype="cortex_m", env=stm32f103, verbose=QL_VERBOSE.DEFAULT) + archtype="cortex_m", ostype="mcu", env=stm32f103, verbose=QL_VERBOSE.DEFAULT) ql.hw.create('rcc') ql.hw.create('flash interface') @@ -379,7 +378,7 @@ def gpio_set_cb(pin): def test_mcu_serial_sam3x8e(self): ql = Qiling(["../examples/rootfs/mcu/sam3x8e/serial.ino.hex"], - archtype="cortex_m", env=sam3x8e, verbose=QL_VERBOSE.DEFAULT) + archtype="cortex_m", ostype="mcu", env=sam3x8e, verbose=QL_VERBOSE.DEFAULT) ql.hw.create('wdt') ql.hw.create('efc0') @@ -400,6 +399,46 @@ def test_mcu_serial_sam3x8e(self): del ql + def test_mcu_hackme_stm32f429(self): + ql = Qiling(["../examples/rootfs/mcu/stm32f429/bof.elf"], + archtype="cortex_m", env=stm32f429, ostype='mcu', verbose=QL_VERBOSE.DISABLED) + + ql.hw.create('rcc') + ql.hw.create('usart2') + ql.hw.create('usart3') + + snapshot = ql.save(hw=True) + + ql.restore(snapshot) + ql.hw.usart3.send(b'hbckme\nabc\n') + ql.run(count=20000) + + self.assertEqual(ql.hw.usart2.recv(), b'') + self.assertEqual(ql.hw.usart3.recv(), b'Wrong password!\n') + + ql.restore(snapshot) + ql.hw.usart3.send(b'hackme\naaaaaaaaaaaaaaaaaaaa\xa9\x05\n') + ql.run(count=40000) + + self.assertEqual(ql.hw.usart2.recv(), b'Nice Hack!\n') + self.assertEqual(ql.hw.usart3.recv(), b'Welcome to the world of Hacking!\naaaaaaaaaaaaaaaaaaaa\xa9\x05\n') + + def test_mcu_fastmode_stm32f429(self): + ql = Qiling(["../examples/rootfs/mcu/stm32f429/bof.elf"], + archtype="cortex_m", env=stm32f429, ostype='mcu', verbose=QL_VERBOSE.DEFAULT) + + ql.hw.create('rcc') + ql.hw.create('usart2') + ql.hw.create('usart3') + + ql.hw.usart3.send(b'hackme\naaaaaaaaaaaaaaaaaaaa\xa9\x05\n') + + ql.os.fast_mode = True + ql.run(timeout=400) + + self.assertEqual(ql.hw.usart2.recv(), b'Nice Hack!\n') + self.assertEqual(ql.hw.usart3.recv(), b'Welcome to the world of Hacking!\naaaaaaaaaaaaaaaaaaaa\xa9\x05\n') + if __name__ == "__main__": unittest.main() diff --git a/tests/test_onlinux.sh b/tests/test_onlinux.sh index 176693cbf..52bd95e26 100755 --- a/tests/test_onlinux.sh +++ b/tests/test_onlinux.sh @@ -17,4 +17,5 @@ python3 ./test_mcu.py && python3 ./test_evm.py && python3 ./test_blob.py && python3 ./test_qdb.py && +python3 ./test_tendaac15_httpd.py && echo "Done Test" diff --git a/tests/test_r2.py b/tests/test_r2.py index 97c180288..b25681089 100644 --- a/tests/test_r2.py +++ b/tests/test_r2.py @@ -5,12 +5,18 @@ sys.path.append("..") from qiling import Qiling from qiling.const import QL_VERBOSE -from qiling.extensions.r2.r2 import R2 +try: + from qiling.extensions.r2.r2 import R2 +except ImportError: + test_r2 = False +else: + test_r2 = True EVM_CODE = bytes.fromhex("6060604052341561000f57600080fd5b60405160208061031c833981016040528080519060200190919050508060018190556000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050610299806100836000396000f300606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806318160ddd1461005c57806370a0823114610085578063a9059cbb146100d2575b600080fd5b341561006757600080fd5b61006f61012c565b6040518082815260200191505060405180910390f35b341561009057600080fd5b6100bc600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610132565b6040518082815260200191505060405180910390f35b34156100dd57600080fd5b610112600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061017a565b604051808215151515815260200191505060405180910390f35b60015481565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600080826000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205403101515156101cb57600080fd5b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555060019050929150505600a165627a7a7230582098f1551a391a3e65b3ce45cfa2b3fa5f91eea9a3e7181a81454e025ea0d7151c0029") +@unittest.skipUnless(test_r2, 'libr is missing') class R2Test(unittest.TestCase): def test_shellcode_disasm(self): ql = Qiling(code=EVM_CODE, archtype="evm", verbose=QL_VERBOSE.DISABLED) diff --git a/tests/test_tendaac15_httpd.py b/tests/test_tendaac15_httpd.py new file mode 100644 index 000000000..fd8632b98 --- /dev/null +++ b/tests/test_tendaac15_httpd.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python3 +# +# Cross Platform and Multi Architecture Advanced Binary Emulation Framework +# Built on top of Unicorn emulator (www.unicorn-engine.org) + + +# 1. Download AC15 Firmware from https://down.tenda.com.cn/uploadfile/AC15/US_AC15V1.0BR_V15.03.05.19_multi_TD01.zip +# 2. unzip +# 3. binwalk -e US_AC15V1.0BR_V15.03.05.19_multi_TD01.bin +# 4. locate squashfs-root +# 5. rm -rf webroot && mv webroot_ro webroot +# +# notes: we are using rootfs in this example, so rootfs = squashfs-root +# + +import http.client, json, os, socket, sys, time, threading, unittest + +sys.path.append("..") +from qiling import Qiling +from qiling.const import QL_VERBOSE + +class ELFTest(unittest.TestCase): + + def test_tenda_ac15_arm(self): + + def nvram_listener(): + server_address = '../examples/rootfs/arm_tendaac15/var/cfm_socket' + data = "" + + try: + os.unlink(server_address) + except OSError: + if os.path.exists(server_address): + raise + + # Create UDS socket + sock = socket.socket(socket.AF_UNIX,socket.SOCK_STREAM) + sock.bind(server_address) + sock.listen(1) + + while True: + connection, client_address = sock.accept() + try: + while True: + data += str(connection.recv(1024)) + + if "lan.webiplansslen" in data: + connection.send('192.168.170.169'.encode()) + else: + break + data = "" + finally: + connection.close() + + def patcher(ql): + br0_addr = ql.mem.search("br0".encode() + b'\x00') + for addr in br0_addr: + ql.mem.write(addr, b'lo\x00') + + def my_tenda(): + ql = Qiling(["../examples/rootfs/arm_tendaac15/bin/httpd"], "../examples/rootfs/arm_tendaac15", verbose=QL_VERBOSE.DEBUG) + ql.add_fs_mapper("/dev/urandom","/dev/urandom") + ql.hook_address(patcher, ql.loader.elf_entry) + ql.run() + del ql + + if __name__ == "__main__": + + threadLock = threading.Lock() + threads = [] + + nvram_listener_therad = threading.Thread(target=nvram_listener, daemon=True) + mytenda_therad = threading.Thread(target=my_tenda, daemon=True) + + nvram_listener_therad.start() + mytenda_therad.start() + + threads.append(nvram_listener_therad) + threads.append(mytenda_therad) + + time.sleep(5) + + conn = http.client.HTTPConnection('localhost', 8080, timeout=10) + headers = {'X-Requested-With': 'XMLHttpRequest', 'Content-Type': 'application/x-www-form-urlencoded'} + web_data = {'page': 'CCCCAAAA', 'entrys':'sync'} + json_data = json.dumps(web_data) + conn.request('POST', '/goform/addressNat', json_data, headers) + response = conn.getresponse() + self.assertIn("Please update your documents to reflect the new location.", response.read().decode()) + + +if __name__ == "__main__": + unittest.main() \ No newline at end of file