qilingframework / qiling

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

Qiling can not emulate mips program with lwx instruction which is supported by unicorn #1344

Open DockTree opened 1 year ago

DockTree commented 1 year ago

*Describe the bug Qiling can not emulate mips program with lwx instruction which is supported by unicorn

Sample Code

from qiling import Qiling
from qiling.const import QL_VERBOSE

if __name__ == "__main__":
    argv = r'./usr/sbin/miniupnpd'.split()#r'./usr/sbin/lighttpd -f ./etc/lighttpd/lighttpd.conf'.split()
    rootfs = r'./'

    ql = Qiling(argv, rootfs, verbose=QL_VERBOSE.DISASM)
    #ql.debugger = "gdb:127.0.0.1:9999"
    ql.run()

Screenshots image

Additional context This program is lighttpd in totolink_C8540R-1C_A7100RU_IP04365_MT7621AMT7615Ex2_SPI_16M128M_V7.4cu.2313_B20191024_ALL.web the bug is lwx can not be handled and unicorn solved it https://github.com/unicorn-engine/unicorn/issues/1314

DockTree commented 1 year ago

*Describe the bug Qiling can not emulate mips program with lwx instruction which is supported by unicorn

Sample Code

from qiling.const import QL_VERBOSE

if __name__ == "__main__":
    argv = r'./usr/sbin/miniupnpd'.split()#r'./usr/sbin/lighttpd -f ./etc/lighttpd/lighttpd.conf'.split()
    rootfs = r'./'

    ql = Qiling(argv, rootfs, verbose=QL_VERBOSE.DISASM)
    #ql.debugger = "gdb:127.0.0.1:9999"
    ql.run()

Screenshots image

Additional context This program is lighttpd in totolink_C8540R-1C_A7100RU_IP04365_MT7621AMT7615Ex2_SPI_16M128M_V7.4cu.2313_B20191024_ALL.web the bug is lwx can not be handled and unicorn solved it unicorn-engine/unicorn#1314

I solved it by add

reg = self.uc.reg_read(UC_MIPS_REG_CP0_STATUS)
reg |= (1 << 24)
self.uc.reg_write(UC_MIPS_REG_CP0_STATUS, reg)

before self.uc.emu_start(begin, end, timeout, count) in qiling/core.py

but I think there would be preferable way to add this feature

elicn commented 1 year ago

Hi there, I am not a MIPS expert, but as far as I understand lwx just loads a value to memory or register. The exception shown here is Qiling telling you that the CPU got an interrupt, but there is no hook that handles it. Interrupts cannot be left unhandled, and this is why it complains.

I don't think this is related to the issue you linked, and to be honest, I didn't udnerstand the workaround. My guess is that the following instruction triggers the interrupt, and Qiling didn't get the chance to show it before it crashed. To my undertanding, the fix should be adding a hook that handles that interrupt. Do you know what interrupt 0x21 stands for in MIPS?

wtdcode commented 1 year ago

Hi there, I am not a MIPS expert, but as far as I understand lwx just loads a value to memory or register. The exception shown here is Qiling telling you that the CPU got an interrupt, but there is no hook that handles it. Interrupts cannot be left unhandled, and this is why it complains.

I don't think this is related to the issue you linked, and to be honest, I didn't udnerstand the workaround. My guess is that the following instruction triggers the interrupt, and Qiling didn't get the chance to show it before it crashed. To my undertanding, the fix should be adding a hook that handles that interrupt. Do you know what interrupt 0x21 stands for in MIPS?

For the brief context to save your time (me taking more than 2 hours to figure this out), lwx is included in the DSP module, something like instruction set extension (imagine ARM VFP), which is controlled by this register. Without enabling this bit, qemu refuses to decode lwx instruction.

Regarding the proper way to fix this, I suggest switching the default CPU model to MAX if any or just try to set it for mips arch by default before everything else.

elicn commented 1 year ago

Thanks for the clarification. I would expect Unicorn to fail on an illegal instruction in this case, but here we see an unhandled interrupt. Does the CPU raise this interrupt to indicate there was an invalid intruction (like #UD on Intel architecture)? I haven't found documentation about this specific interrupt, so I don't know if this is the way an illegal instruction should be handled by this specific arch.

As for the fix, if this is a toggleable deature (from the CPU perspective, not Unicorn's) then that should stay as-is, maybe define a utility method for that. If that is considered as "different CPU model", then we should indeed support selecting the desired CPU model on Qiling initialization.