qilingframework / qiling

A True Instrumentable Binary Emulation Framework
https://qiling.io
GNU General Public License v2.0
5.07k stars 739 forks source link

Creating a Cortex M Linux Qiling instance causes `AttributeError`. #1215

Open LukeSerne opened 2 years ago

LukeSerne commented 2 years ago

Describe the bug Creating a Cortex M Qiling instance with a Linux ostype causes an AttributeError.

Sample Code

import qiling
qiling.Qiling(code=b"\0", archtype=qiling.const.QL_ARCH.CORTEX_M, ostype='linux')

Expected behavior No error.

Result

Traceback (most recent call last):
  File "test.py", line 2, in <module>
    qiling.Qiling(code=b"\0", archtype=qiling.const.QL_ARCH.CORTEX_M, ostype='linux')
  File "~/.local/lib/python3.8/site-packages/qiling/core.py", line 179, in __init__
    self._os = select_os(ostype)(self)
  File "~/.local/lib/python3.8/site-packages/qiling/os/linux/linux.py", line 48, in __init__
    self.load()
  File "~/.local/lib/python3.8/site-packages/qiling/os/linux/linux.py", line 56, in load
    self.ql.arch.enable_vfp()
  File "~/.local/lib/python3.8/site-packages/qiling/arch/arm.py", line 104, in enable_vfp
    self.regs.c1_c0_2 = self.regs.c1_c0_2 | (0b11 << 20) | (0b11 << 22)
  File "~/.local/lib/python3.8/site-packages/qiling/arch/register.py", line 41, in __getattr__
    return super().__getattribute__(name)
AttributeError: 'QlRegisterManager' object has no attribute 'c1_c0_2'
elicn commented 2 years ago

@wtdcode, the enable_vfp method is called whenever the arch is recognized as ARM. Should QlArchCORTEX_M have this method (inherited from QlArchARM)? If not, we can have Cortex M nullify its method.

wtdcode commented 2 years ago

@wtdcode, the enable_vfp method is called whenever the arch is recognized as ARM. Should QlArchCORTEX_M have this method (inherited from QlArchARM)? If not, we can have Cortex M nullify its method.

Not sure, probably depends on the underlying cpu model.

LukeSerne commented 2 years ago

@wtdcode, the enable_vfp method is called whenever the arch is recognized as ARM. Should QlArchCORTEX_M have this method (inherited from QlArchARM)? If not, we can have Cortex M nullify its method.

Removing the enable_vfp call results in no error when creating the qiling object, but instead, Unicorn thows an UC_ERR_INSN_INVALID error when trying to execute some code.

For example, consider the bytecode 80 b5 00 af 00 f0 3e fe. The below script:

import qiling
ql = qiling.Qiling(code=bytes.fromhex("80 b5 00 af 00 f0 3e fe"), archtype=qiling.const.QL_ARCH.CORTEX_M, ostype="linux")
ql.run()

Gives as output:

[x]     CPU Context:
[x]     r0  : 0x0
[x]     r1  : 0x0
[x]     r2  : 0x0
[x]     r3  : 0x0
[x]     r4  : 0x0
[x]     r5  : 0x0
[x]     r6  : 0x0
[x]     r7  : 0x0
[x]     r8  : 0x0
[x]     r9  : 0x0
[x]     r10 : 0x0
[x]     r11 : 0x0
[x]     r12 : 0x0
[x]     sp  : 0x11ff000
[x]     lr  : 0x0
[x]     pc  : 0x11ff000
[x]     msp : 0x11ff000
[x]     psp : 0x0
[x]     xpsr    : 0x40000000
[x]     apsr    : 0x40000000
[x]     ipsr    : 0x0
[x]     epsr    : 0x0
[x]     primask : 0x0
[x]     faultmask   : 0x0
[x]     basepri : 0x0
[x]     control : 0x0
[x]     xpsr_nzcvqg : 0x0
[x]     Hexdump:
[x]     80 b5 00 af 00 f0 3e fe
[x]     Disassembly:
[=]     011ff000 [[shellcode_stack]    + 0x1ff000]  80 b5                push                 {r7, lr}
[=]     011ff002 [[shellcode_stack]    + 0x1ff002]  00 af                add                  r7, sp, #0
[=]     011ff004 [[shellcode_stack]    + 0x1ff004]  00 f0 3e fe          bl                   #0x11ffc84
[=]     011ff008 [[shellcode_stack]    + 0x1ff008]  00 00                movs                 r0, r0
[=]     011ff00a [[shellcode_stack]    + 0x1ff00a]  00 00                movs                 r0, r0
[=]     011ff00c [[shellcode_stack]    + 0x1ff00c]  00 00                movs                 r0, r0
[=]     011ff00e [[shellcode_stack]    + 0x1ff00e]  00 00                movs                 r0, r0
[=]     011ff010 [[shellcode_stack]    + 0x1ff010]  00 00                movs                 r0, r0
[=]     011ff012 [[shellcode_stack]    + 0x1ff012]  00 00                movs                 r0, r0
[=]     011ff014 [[shellcode_stack]    + 0x1ff014]  00 00                movs                 r0, r0
[=]     011ff016 [[shellcode_stack]    + 0x1ff016]  00 00                movs                 r0, r0
[=]     011ff018 [[shellcode_stack]    + 0x1ff018]  00 00                movs                 r0, r0
[=]     011ff01a [[shellcode_stack]    + 0x1ff01a]  00 00                movs                 r0, r0
[=]     011ff01c [[shellcode_stack]    + 0x1ff01c]  00 00                movs                 r0, r0
[=]     011ff01e [[shellcode_stack]    + 0x1ff01e]  00 00                movs                 r0, r0
[=]     011ff020 [[shellcode_stack]    + 0x1ff020]  00 00                movs                 r0, r0
[=]     011ff022 [[shellcode_stack]    + 0x1ff022]  00 00                movs                 r0, r0
[=]     011ff024 [[shellcode_stack]    + 0x1ff024]  00 00                movs                 r0, r0
[=]     011ff026 [[shellcode_stack]    + 0x1ff026]  00 00                movs                 r0, r0
[=]     011ff028 [[shellcode_stack]    + 0x1ff028]  00 00                movs                 r0, r0
[=]     011ff02a [[shellcode_stack]    + 0x1ff02a]  00 00                movs                 r0, r0
[=]     011ff02c [[shellcode_stack]    + 0x1ff02c]  00 00                movs                 r0, r0
[=]     011ff02e [[shellcode_stack]    + 0x1ff02e]  00 00                movs                 r0, r0
[=]     011ff030 [[shellcode_stack]    + 0x1ff030]  00 00                movs                 r0, r0
[=]     011ff032 [[shellcode_stack]    + 0x1ff032]  00 00                movs                 r0, r0
[=]     011ff034 [[shellcode_stack]    + 0x1ff034]  00 00                movs                 r0, r0
[=]     011ff036 [[shellcode_stack]    + 0x1ff036]  00 00                movs                 r0, r0
[=]     011ff038 [[shellcode_stack]    + 0x1ff038]  00 00                movs                 r0, r0
[=]     011ff03a [[shellcode_stack]    + 0x1ff03a]  00 00                movs                 r0, r0
[=]     011ff03c [[shellcode_stack]    + 0x1ff03c]  00 00                movs                 r0, r0
[=]     011ff03e [[shellcode_stack]    + 0x1ff03e]  00 00                movs                 r0, r0
[x]     PC = 0x011ff000

[x]     Memory map:
[x]     Start        End          Perm    Label               Image
[x]     0001000000 - 0001a00000   rwx     [shellcode_stack]   
[x]     00ffff0000 - 00ffff1000   rwx     [arm_traps]         
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "~/.local/lib/python3.8/site-packages/qiling/core.py", line 573, in run
    self.os.run()
  File "~/.local/lib/python3.8/site-packages/qiling/os/linux/linux.py", line 141, in run
    self.ql.emu_start(self.entry_point, (self.entry_point + len(self.ql.code)), self.ql.timeout, self.ql.count)
  File "~/.local/lib/python3.8/site-packages/qiling/core.py", line 706, in emu_start
    self.uc.emu_start(begin, end, timeout, count)
  File "~/.local/lib/python3.8/site-packages/unicorn/unicorn.py", line 525, in emu_start
    raise UcError(status)
unicorn.unicorn.UcError: Invalid instruction (UC_ERR_INSN_INVALID)

This output shows that qiling can correctly disassemble the bytecode, but unicorn cannot.

LukeSerne commented 2 years ago

@elicn @wtdcode Are there any updates on this issue? Do you know what the cause of the issue is and how it should be fixed?