-
Notifications
You must be signed in to change notification settings - Fork 745
Implement kernel ARM emulation #1531
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,6 +21,7 @@ | |
from qiling.const import QL_ARCH, QL_ENDIAN, QL_OS | ||
from qiling.exception import QlErrorELFFormat, QlMemoryMappedError | ||
from qiling.loader.loader import QlLoader, Image | ||
from qiling.os.memory import QlMemoryHeap | ||
from qiling.os.linux.function_hook import FunctionHook | ||
from qiling.os.linux.syscall_nums import SYSCALL_NR | ||
from qiling.os.linux.kernel_api.hook import * | ||
|
@@ -57,7 +58,7 @@ class AUXV(IntEnum): | |
|
||
# start area memory for API hooking | ||
# we will reserve 0x1000 bytes for this (which contains multiple slots of 4/8 bytes, each for one api) | ||
API_HOOK_MEM = 0x1000000 | ||
API_HOOK_MEM = 0x2000000 | ||
|
||
# memory for syscall table | ||
SYSCALL_MEM = API_HOOK_MEM + 0x1000 | ||
|
@@ -87,6 +88,9 @@ def run(self): | |
stack_size = self.profile.getint('stack_size') | ||
self.ql.mem.map(stack_address, stack_size, info='[stack]') | ||
|
||
# Setup heap | ||
self.ql.os.heap = QlMemoryHeap(self.ql, 0x3000000, 0x3000000 + 0x1000000) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Heap base and size should be set based on the value configured in the profile file. Using hardcoded values is not a good idea. |
||
|
||
self.path = self.ql.path | ||
|
||
with open(self.path, 'rb') as infile: | ||
|
@@ -97,7 +101,7 @@ def run(self): | |
|
||
# is it a driver? | ||
if elftype == 'ET_REL': | ||
self.load_driver(elffile, stack_address + stack_size, loadbase=0x8000000) | ||
self.load_driver(elffile, stack_address + stack_size, loadbase=0x1000000) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any reason for this change here? |
||
self.ql.hook_code(hook_kernel_api) | ||
|
||
# is it an executable? | ||
|
@@ -414,10 +418,19 @@ def lkm_get_init(self, elffile: ELFFile) -> int: | |
raise QlErrorELFFormat('invalid module: symbol init_module not found') | ||
|
||
def lkm_dynlinker(self, elffile: ELFFile, mem_start: int) -> Mapping[str, int]: | ||
self._symbol_name_map = None | ||
def __get_symbol(name: str) -> Optional[Symbol]: | ||
_symtab = elffile.get_section_by_name('.symtab') | ||
_sym = _symtab.get_symbol_by_name(name) | ||
|
||
# Cache | ||
if self._symbol_name_map == None: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This could be simplified with an internal function decorated with from functools import cache
@cache
def __get_cached_symbol(name: str) -> int:
# access symtab symbol here and return the result
... Also, I am not sure that |
||
self._symbol_name_map = {} | ||
for i, sym in enumerate(_symtab.iter_symbols()): | ||
if sym.name not in self._symbol_name_map: | ||
self._symbol_name_map[sym.name] = [] | ||
self._symbol_name_map[sym.name].append(sym) | ||
|
||
_sym = None if name not in self._symbol_name_map else self._symbol_name_map[name] | ||
return _sym[0] if _sym else None | ||
|
||
ql = self.ql | ||
|
@@ -555,6 +568,22 @@ def __get_symbol(name: str) -> Optional[Symbol]: | |
ql.mem.write_ptr(prev_mips_hi16_loc + 2, (val >> 16), 2) | ||
ql.mem.write_ptr(loc + 2, (val & 0xFFFF), 2) | ||
|
||
elif desc in ('R_ARM_CALL', 'R_ARM_JUMP24'): | ||
ins = ql.mem.read_ptr(loc, 4) & 0xFF000000 | ||
val = (((rev_reloc_symbols[symbol_name] - loc) >> 2) - 2) & 0x00FFFFFF | ||
ql.mem.write_ptr(loc, ins | val) | ||
|
||
elif desc == "R_ARM_ABS32": | ||
val = ql.mem.read_ptr(loc, 4) | ||
val += rev_reloc_symbols[symbol_name] | ||
ql.mem.write_ptr(loc, (val & 0xFFFFFFFF), 4) | ||
|
||
elif desc == "R_ARM_PREL31": | ||
ql.log.warning(f'Ignoring relocation type {desc} at 0x{loc:x} for symbol "{symbol_name}" (0x{rev_reloc_symbols[symbol_name]:x})') | ||
|
||
elif desc == "R_ARM_NONE": | ||
ql.log.warning(f'Ignoring relocation type {desc} at 0x{loc:x} for symbol "{symbol_name}" (0x{rev_reloc_symbols[symbol_name]:x})') | ||
|
||
else: | ||
raise NotImplementedError(f'Relocation type {desc} not implemented') | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,7 +4,7 @@ | |
# | ||
|
||
from qiling import Qiling | ||
from qiling.const import QL_INTERCEPT | ||
from qiling.const import QL_INTERCEPT, QL_ARCH | ||
from qiling.exception import QlErrorSyscallError, QlErrorSyscallNotFound | ||
|
||
# import all kernel api hooks to global namespace | ||
|
@@ -25,6 +25,11 @@ def hook_kernel_api(ql: Qiling, address: int, size): | |
if api_func: | ||
try: | ||
api_func(ql, address, api_name) | ||
|
||
# Restore PC | ||
if ql.arch.type == QL_ARCH.ARM: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think function calls are automatically unwinded. |
||
ql.arch.regs.arch_sp -= ql.arch.pointersize | ||
ql.arch.regs.arch_pc = ql.arch.regs.lr | ||
except Exception: | ||
ql.log.exception("") | ||
ql.log.debug("%s Exception Found" % api_name) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason for the change?