qilingframework / qilingframework/qiling

Cortex-M Vector Table Offset Register not used during mcu emulation

Open
#1,548 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

os mcu
Dominant language
Python
Stars
6.1k
Forks
798
Avg merge
1d 1h
Merged PRs (30d)
9

Description

Describe the bug
When emulating an mcu based on the cortex-m, Qiling never uses the value stored in the Vector Table Offset Register. This register is used to indicate an offset for the base address of the vector table. This produces a bug when emulating a firmware that is using this register to indicate an offset to use its vector table. In my case the vector table is used in the firmware to fetch interrupt handler, the bug makes the firmware trying to fetch interrupt handlers from wrong address.

Sample Code

ql = Qiling(["./toto.elf"],
                archtype=QL_ARCH.CORTEX_M, ostype=QL_OS.MCU, env=stm32f103, verbose=QL_VERBOSE.DISABLED)

    ql.hw.create('scb')
    ql.hw.create('gpioa')
    ql.hw.create('usart2').watch()
    ql.hw.create('rcc')
    ql.hw.create('afio')
    ql.hw.create('exti')
    ql.hw.create('gpioc')

    ql.hw.show_info()

    ql.hw.usart2.send("totototo".encode())

    ql.run(count=1000000)

Expected behavior
Just take into account the value present in the register.

Additional context
Tested on the dev branch.
This register is laying in the SCB part of the CPU memory, as shown in the code above once scb hardware added to the emulation, the memory is perfectly handled, read and write to it works fine (checked by using DISASM debug log).

Suggested correction
For me this was problematic when the firmware uses interruption so here is how I corrected the problem. It has been tested and worked perfectly but I'm not sure this is the right place to implement this correction plus I've hardcoded the address which is very ugly.
In qiling/arch/cortex_m.py in interrupt_handler function :

def interrupt_handler(self, ql: Qiling, intno: int):
        basepri = self.regs.basepri & 0xf0

        if basepri and basepri <= ql.hw.nvic.get_priority(intno):
            return

        if intno > IRQ.HARD_FAULT and (self.regs.primask & 0x1):
            return

        if intno != IRQ.NMI and (self.regs.faultmask & 0x1):
            return

        if ql.verbose >= QL_VERBOSE.DISASM:
            ql.log.debug(f'Handle the intno: {intno}')

        with QlInterruptContext(ql):
            isr = intno + 16
            offset = isr * 4
            
            # ============= personnal modifications ============= 
            #Here qiling doesn't care about the SCB_VTOR which is not normal for the cortex M 
            SCB_VTOR = int.from_bytes(ql.mem.read(0xe000ed08,4), byteorder='little')

            entry = ql.mem.read_ptr(offset + SCB_VTOR)
            # ======================================= 

            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)

            ql.log.debug(hex(self.effective_pc))

            self.uc.emu_start(self.effective_pc, 0, 0, 0xffffff)

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in qiling/arch/cortex_m.py, specifically interrupt_handler, and review how the vector-table entry is read. Reproduce the issue with the supplied Cortex-M STM32F103 setup and verify that interrupt handlers are fetched using the SCB Vector Table Offset Register. Done means firmware using a relocated vector table reaches the correct handler.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
embedded-iot, reverse-engineering
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.