|
| 1 | +# Core — the Qiling facade and plumbing |
| 2 | + |
| 3 | +## Goal |
| 4 | + |
| 5 | +Own the public API and object lifecycle of an emulation: the `Qiling` class |
| 6 | +composes arch, loader, memory, OS, and (for bare-metal) hardware components, |
| 7 | +and exposes hooks, memory/register access, patching, and save/restore to |
| 8 | +users. No roadmap milestone applies — this is mature released infrastructure; |
| 9 | +status is maturity-based per the control center. |
| 10 | + |
| 11 | +## Status |
| 12 | + |
| 13 | +`done` — exercised by the whole test suite; the How to Test command below |
| 14 | +boots shellcode end-to-end through `Qiling.__init__` → `run()` → `emu_start`. |
| 15 | + |
| 16 | +## Code Structure |
| 17 | + |
| 18 | +| File | Role | |
| 19 | +| ---- | ---- | |
| 20 | +| `qiling/core.py` | `Qiling` class: constructor/composition root, `run`, `emu_start/stop`, `save/restore`, `patch`, properties | |
| 21 | +| `qiling/core_hooks.py` | `QlCoreHooks` mixin: wraps Unicorn hooks, dispatches to `Hook` lists | |
| 22 | +| `qiling/core_hooks_types.py` | `Hook`, `HookAddr`, `HookIntr`, `HookRet` records | |
| 23 | +| `qiling/core_struct.py` | `QlCoreStructs` mixin: endian/bit-width-aware pack/unpack helpers | |
| 24 | +| `qiling/utils.py` | Name→class resolution: `select_arch/loader/os/component/debugger`, binary format sniffing, profile loading | |
| 25 | +| `qiling/const.py` | Enums: `QL_ARCH`, `QL_OS`, `QL_VERBOSE`, `QL_INTERCEPT`, `QL_STATE`, groupings `QL_OS_POSIX`/`QL_OS_BAREMETAL` | |
| 26 | +| `qiling/exception.py` | `QlErrorBase` and ~20 subclasses (`QlErrorArch`, `QlSyscallError`, …) | |
| 27 | +| `qiling/host.py` | `QlHost`: describes the *hosting* platform (for pass-through features) | |
| 28 | +| `qiling/log.py` | Logger setup, colored/plain formatters, regex filtering behind `Qiling.filter` | |
| 29 | +| `qiling/profiles/*.ql` | Default per-OS config (memory layout, kernel uid/gid/pid) merged with user overrides | |
| 30 | + |
| 31 | +## Key Types and Entry Points |
| 32 | + |
| 33 | +- `qiling/core.py:35` - `Qiling(QlCoreHooks, QlCoreStructs)` - the facade; `__init__` composes components in fixed order: arch (`:154`) → mixins (`:157`) → logger → profile (`:178`) → loader (`:183`) → memory (`:188`) → OS (`:189`) → hw if bare-metal (`:191`) → `loader.run()` (`:195`). |
| 34 | +- `qiling/core.py:561` - `Qiling.run(begin, end, timeout, count)` - attaches debugger, applies patches, writes exit trap, delegates to `os.run()`. |
| 35 | +- `qiling/core.py:743` - `Qiling.emu_start(begin, end, timeout, count)` - thin wrapper over `uc.emu_start`; manages thumb bit, `QL_STATE`, exception re-raise. |
| 36 | +- `qiling/core.py:609` / `:658` - `save()` / `restore()` - snapshot regs/mem/fd/os per-component. |
| 37 | +- `qiling/core_hooks.py:150` - `QlCoreHooks` - hook registration API: `hook_code` (`:400`), `hook_block` (`:422`), `hook_address` (`:550`), `hook_intno` (`:575`), `hook_mem_read/write` (`:592`/`:610`), `hook_insn` (`:646`), `hook_del` (`:686`). |
| 38 | +- `qiling/utils.py:278` - `ql_guess_emu_env(path)` - sniffs arch/OS/endian from pathname, ELF, Mach-O, or PE headers when not given. |
| 39 | +- `qiling/utils.py:297,376,409,323,332` - `select_loader/arch/os/component/debugger` - dynamic-import factories; core never imports concrete subclasses. |
| 40 | +- `qiling/utils.py:419` - `profile_setup(ostype, user_config)` - YAML for MCU, else ConfigParser over `qiling/profiles/<os>.ql` + user overrides. |
| 41 | + |
| 42 | +## Interactions |
| 43 | + |
| 44 | +- Instantiates every other subsystem: [arch.md](arch.md), [loader.md](loader.md), [os-base.md](os-base.md) (memory + OS), [hw.md](hw.md) (bare-metal only). |
| 45 | +- Lazily instantiates [debugger.md](debugger.md) inside `run()` via `select_debugger`. |
| 46 | +- [extensions.md](extensions.md) and [cli.md](cli.md) consume only this public API. |
| 47 | +- Hook dispatch protocol (`QL_HOOK_BLOCK`, `qiling/const.py:77`) is honored by the OS layers when they intercept syscalls/APIs. |
| 48 | + |
| 49 | +## How to Test |
| 50 | + |
| 51 | +```sh |
| 52 | +cd tests && python3 test_shellcode.py # pass = unittest "OK", exit code 0 |
| 53 | +``` |
| 54 | + |
| 55 | +- Exercises `Qiling(code=...)` construction and `run()` across x86/x86-64/ARM/ARM64/MIPS shellcode for Linux and Windows. |
| 56 | + |
| 57 | +## Open Gaps / Roadmap |
| 58 | + |
| 59 | +- `ChangeLog` lags the released version (1.4.6 vs 1.4.8 in `pyproject.toml`). |
| 60 | +- `unicorn` is hard-pinned to 2.1.3; upgrading Unicorn is a project-wide event. |
| 61 | +- Feature wishlist lives in GitHub issue [#333](https://github.com/qilingframework/qiling/issues/333). |
0 commit comments