qilingframework / qiling

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

UEFI module cannot print using Print() or DEBUG() function #1266

Open Sunxingzhezhexingsun opened 2 years ago

Sunxingzhezhexingsun commented 2 years ago

Describe the bug UEFI module cannot print using Print() or DEBUG() function. When I tried to print strings using Print() or DEBUG() in UEFI code, I didn't get the desired output and Qiling didn't report any errors.

UEFI Module code:

Print(L"[%d]My UEFI Helloworld.\n", Index);
# Or use DEBUG()
# DEBUG((DEBUG_INFO, "[%a][%d]: MyHelloWorldDxe saying Hi\n", __FUNCTION__, i));

Qiling code:

    with open(r'./lzx_uefi/rom2_nvar.pickel', 'rb') as f:
        env = pickle.load(f)

    ql = Qiling(["./lzx_uefi/bin/MyHelloWorldApp.efi"], "./lzx_uefi/", env=env, verbose=QL_VERBOSE.DEBUG)
    # ql.debugger = True

    class MyMapper:
        def add_fs_mapping(self, ql_path, real_dest):
            pass

    ql.os.fs_mapper = MyMapper()
    ql.run()

Expected behavior Outut the specific string.

Nothing is printed: image

[=]     Module ./lzx_uefi/bin/MyHelloWorldApp.efi loaded to 0x100000
[=]     Module entry point at 0x1003a8
[=]     Initializing EFI_LOADED_IMAGE_PROTOCOL
[=]
[=]     Done loading modules
[=]     Running from 0x001003a8 of ./lzx_uefi/bin/MyHelloWorldApp.efi
[+]     0x00000000040001b8: LocateProtocol(Protocol = EfiDevicePathUtilitiesProtocolGuid, Registration = NULL, Interface = 0x00101840) = 0x800000000000000e
[+]     0x00000000040000b8: AllocatePool(PoolType = 0x4, Size = 0x282, Buffer = 0x0507ff38) = 0x0
[+]     0x00000000040000c0: FreePool(Buffer = 0x04011098) = 0x0
[+]     0x00000000040000b8: AllocatePool(PoolType = 0x4, Size = 0x282, Buffer = 0x0507ff38) = 0x0
[+]     0x00000000040000c0: FreePool(Buffer = 0x04011098) = 0x0
[+]     0x00000000040000b8: AllocatePool(PoolType = 0x4, Size = 0x282, Buffer = 0x0507ff38) = 0x0
[+]     0x00000000040000c0: FreePool(Buffer = 0x04011098) = 0x0
[+]     0x00000000040000b8: AllocatePool(PoolType = 0x4, Size = 0x282, Buffer = 0x0507ff38) = 0x0
[+]     0x00000000040000c0: FreePool(Buffer = 0x04011098) = 0x0
[+]     0x00000000040000b8: AllocatePool(PoolType = 0x4, Size = 0x282, Buffer = 0x0507ff38) = 0x0
[+]     0x00000000040000c0: FreePool(Buffer = 0x04011098) = 0x0
[+]     0x00000000040000b8: AllocatePool(PoolType = 0x4, Size = 0x282, Buffer = 0x0507ff38) = 0x0
[+]     0x00000000040000c0: FreePool(Buffer = 0x04011098) = 0x0
[+]     0x00000000040000b8: AllocatePool(PoolType = 0x4, Size = 0x282, Buffer = 0x0507ff38) = 0x0
[+]     0x00000000040000c0: FreePool(Buffer = 0x04011098) = 0x0
[+]     0x00000000040000b8: AllocatePool(PoolType = 0x4, Size = 0x282, Buffer = 0x0507ff38) = 0x0
[+]     0x00000000040000c0: FreePool(Buffer = 0x04011098) = 0x0
[=]     No more modules to run
elicn commented 2 years ago

That is probably due to the missing protocol EfiDevicePathUtilitiesProtocolGuid. It looks like the application you are emulating is trying to locate this protocol, and when it fails (note the return value of LocateProtocol) the program exits. You don't see any prints because your program doesn't get there.

That said, Qiling doesn't support UEFI Applications yet, so even if you overcome the missing protocol problem you may bump into another one when printing the messages.

Sunxingzhezhexingsun commented 2 years ago

That is probably due to the missing protocol EfiDevicePathUtilitiesProtocolGuid. It looks like the application you are emulating is trying to locate this protocol, and when it fails (note the return value of LocateProtocol) the program exists. You don't see any prints because your program doesn't get there.

That said, Qiling doesn't support UEFI Applications yet, so even if you overcome the missing protocol probleam you may bump into another one when printing the messages.

@elicn Thancks for your reply. But I tested upon DXE_DRIVER, same result. LocateProtocol() does fail but the program does not exit. AllocatePool and FreePool are the behavior of Print() (I loop calling Print() 8 times).

elicn commented 2 years ago

There are multiple implementations of PrintLib, so maybe this one writes to MMIO or COM port instead of ConOut. To debug this a bit further, you could use the following snippet:

from qiling import Qiling
from qiling.const import QL_VERBOSE
from qiling.extensions import trace

ql = Qiling([r"./lzx_uefi/bin/MyHelloWorldApp.efi"], r"./lzx_uefi/", verbose=QL_VERBOSE.DEBUG)

setattr(ql.loader, 'symsmap', {
    # to make tracing more friendly, you may map offsets to symbols here.
    # those symbols can be either functions or variables. symbols are usually available in the map file
    # produced during compilation.
    #
    # for example:
    0x10234 : 'SomeSymbol'
})

trace.enable_full_trace(ql)
ql.run()
Sunxingzhezhexingsun commented 2 years ago
iling import Qiling
from qiling.const import QL_VERBOSE

@elicn Well, I ran the test code again using your method, and it appears to be a complete output of all executed assembly code, so what should I focus on now to troubleshoot this problem?

elicn commented 2 years ago

Could you please pipe all output to a file and attach it here? e.g. python3 my_script.py 2>&1 | tee trace.log

Ristovski commented 1 year ago

Printing not working is possibly a dupe of #720 - missing ConOut implementation