mirror of
https://github.com/qilingframework/qiling.git
synced 2026-10-12 02:21:40 +00:00
@@ -42,7 +42,7 @@ def main(input_file, enable_trace=False):
|
||||
addr = ql.mem.search("HTTP_COOKIE=uid=1234&password=".encode())
|
||||
ql.target_addr = addr[0]
|
||||
|
||||
main_addr = ql.os.elf_entry
|
||||
main_addr = ql.loader.elf_entry
|
||||
ql.hook_address(callback=start_afl, address=main_addr)
|
||||
|
||||
try:
|
||||
|
||||
+2
-2
@@ -694,8 +694,8 @@ class Qiling(QlCoreHooks, QlCoreStructs):
|
||||
if "fd" in saved_states:
|
||||
self.os.fd.restore(saved_states["fd"])
|
||||
|
||||
if "os_context" in saved_states:
|
||||
self.os.restore(saved_states["os_context"])
|
||||
if "os" in saved_states:
|
||||
self.os.restore(saved_states["os"])
|
||||
|
||||
if "loader" in saved_states:
|
||||
self.loader.restore(saved_states["loader"])
|
||||
|
||||
@@ -83,7 +83,7 @@ class QlGdb(QlDebugger):
|
||||
entry_point = ql.loader.entry_point
|
||||
|
||||
elif ql.os.type in (QL_OS.LINUX, QL_OS.FREEBSD) and not ql.code:
|
||||
entry_point = ql.os.elf_entry
|
||||
entry_point = ql.loader.elf_entry
|
||||
|
||||
else:
|
||||
entry_point = ql.os.entry_point
|
||||
|
||||
+21
-22
@@ -58,9 +58,11 @@ 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_SIZE = 0x1000
|
||||
|
||||
# memory for syscall table
|
||||
SYSCALL_MEM = API_HOOK_MEM + 0x1000
|
||||
SYSCALL_SIZE = 0x1000
|
||||
|
||||
|
||||
class QlLoaderELF(QlLoader):
|
||||
@@ -85,6 +87,7 @@ class QlLoaderELF(QlLoader):
|
||||
# setup program stack
|
||||
stack_address = self.profile.getint('stack_address')
|
||||
stack_size = self.profile.getint('stack_size')
|
||||
top_of_stack = stack_address + stack_size
|
||||
self.ql.mem.map(stack_address, stack_size, info='[stack]')
|
||||
|
||||
self.path = self.ql.path
|
||||
@@ -97,20 +100,20 @@ class QlLoaderELF(QlLoader):
|
||||
|
||||
# is it a driver?
|
||||
if elftype == 'ET_REL':
|
||||
self.load_driver(elffile, stack_address + stack_size, loadbase=0x8000000)
|
||||
self.load_driver(elffile, top_of_stack, loadbase=0x8000000)
|
||||
self.ql.hook_code(hook_kernel_api)
|
||||
|
||||
# is it an executable?
|
||||
elif elftype == 'ET_EXEC':
|
||||
load_address = 0
|
||||
|
||||
self.load_with_ld(elffile, stack_address + stack_size, load_address, self.argv, self.env)
|
||||
self.load_with_ld(elffile, top_of_stack, load_address, self.argv, self.env)
|
||||
|
||||
# is it a shared object?
|
||||
elif elftype == 'ET_DYN':
|
||||
load_address = self.profile.getint('load_address')
|
||||
|
||||
self.load_with_ld(elffile, stack_address + stack_size, load_address, self.argv, self.env)
|
||||
self.load_with_ld(elffile, top_of_stack, load_address, self.argv, self.env)
|
||||
|
||||
else:
|
||||
raise QlErrorELFFormat(f'unexpected elf type value (e_type = {elftype})')
|
||||
@@ -373,7 +376,6 @@ class QlLoaderELF(QlLoader):
|
||||
self.init_sp = self.ql.arch.regs.arch_sp
|
||||
|
||||
self.ql.os.entry_point = self.entry_point = entry_point
|
||||
self.ql.os.elf_entry = self.elf_entry
|
||||
self.ql.os.function_hook = FunctionHook(self.ql, elf_phdr, elf_phnum, elf_phent, load_address, mem_end)
|
||||
|
||||
# If there is a loader, we ignore exit
|
||||
@@ -574,44 +576,41 @@ class QlLoaderELF(QlLoader):
|
||||
def load_driver(self, elffile: ELFFile, stack_addr: int, loadbase: int = 0) -> None:
|
||||
elfdata_mapping = self.get_elfdata_mapping(elffile)
|
||||
|
||||
# FIXME: determine true memory boundaries, taking relocation into account (if requested)
|
||||
mem_start = 0
|
||||
mem_end = mem_start + self.ql.mem.align_up(len(elfdata_mapping), 0x1000)
|
||||
mem_start = self.ql.mem.align(loadbase)
|
||||
mem_end = self.ql.mem.align_up(loadbase + len(elfdata_mapping))
|
||||
|
||||
# map some memory to intercept external functions of Linux kernel
|
||||
self.ql.mem.map(API_HOOK_MEM, 0x1000, info="[api_mem]")
|
||||
self.ql.mem.map(API_HOOK_MEM, API_HOOK_SIZE, info="[api_mem]")
|
||||
|
||||
self.ql.log.debug(f'loadbase : {loadbase:#x}')
|
||||
self.ql.log.debug(f'mem_start : {mem_start:#x}')
|
||||
self.ql.log.debug(f'mem_end : {mem_end:#x}')
|
||||
|
||||
self.ql.mem.map(loadbase + mem_start, mem_end - mem_start, info=self.ql.path)
|
||||
self.ql.mem.write(loadbase + mem_start, elfdata_mapping)
|
||||
self.ql.mem.map(mem_start, mem_end - mem_start, info=os.path.basename(self.ql.path))
|
||||
self.ql.mem.write(loadbase, elfdata_mapping)
|
||||
|
||||
init_module = self.lkm_get_init(elffile) + loadbase + mem_start
|
||||
self.images.append(Image(mem_start, mem_end, os.path.abspath(self.path)))
|
||||
|
||||
init_module = loadbase + self.lkm_get_init(elffile)
|
||||
self.ql.log.debug(f'init_module : {init_module:#x}')
|
||||
|
||||
self.brk_address = mem_end + loadbase
|
||||
self.brk_address = mem_end
|
||||
|
||||
# Set MMAP addr
|
||||
mmap_address = self.profile.getint('mmap_address')
|
||||
self.ql.log.debug(f'mmap_address is : {mmap_address:#x}')
|
||||
|
||||
# self.ql.os.elf_entry = self.elf_entry = loadbase + elfhead['e_entry']
|
||||
self.ql.os.entry_point = self.entry_point = init_module
|
||||
self.elf_entry = self.ql.os.elf_entry = self.ql.os.entry_point
|
||||
# there is no interperter so emulation entry point is also elf entry
|
||||
self.elf_entry = self.entry_point = init_module
|
||||
self.ql.os.entry_point = self.entry_point
|
||||
|
||||
self.stack_address = self.ql.mem.align(stack_addr, self.ql.arch.pointersize)
|
||||
self.load_address = loadbase
|
||||
|
||||
# remember address of syscall table, so external tools can access to it
|
||||
# self.ql.os.syscall_addr = SYSCALL_MEM
|
||||
|
||||
# setup syscall table
|
||||
self.ql.mem.map(SYSCALL_MEM, 0x1000, info="[syscall_mem]")
|
||||
self.ql.mem.write(SYSCALL_MEM, b'\x00' * 0x1000)
|
||||
self.ql.mem.map(SYSCALL_MEM, SYSCALL_SIZE, info="[syscall_mem]")
|
||||
self.ql.mem.write(SYSCALL_MEM, b'\x00' * SYSCALL_SIZE)
|
||||
|
||||
rev_reloc_symbols = self.lkm_dynlinker(elffile, mem_start + loadbase)
|
||||
rev_reloc_symbols = self.lkm_dynlinker(elffile, loadbase)
|
||||
|
||||
# iterate over relocatable symbols, but pick only those who start with 'sys_'
|
||||
for sc, addr in rev_reloc_symbols.items():
|
||||
|
||||
@@ -19,6 +19,9 @@ AF_UNIX = 1
|
||||
AF_INET = 2
|
||||
AF_INET6 = 10
|
||||
|
||||
SOCK_STREAM = 1
|
||||
SOCK_DGRAM = 2
|
||||
SOCK_SEQPACKET = 5
|
||||
|
||||
def inet_aton(ipaddr: str) -> int:
|
||||
# ipdata = bytes(int(a, 0) for a in ipaddr.split('.', 4))
|
||||
@@ -765,10 +768,9 @@ def ql_syscall_recvfrom(ql: Qiling, sockfd: int, buf: int, length: int, flags: i
|
||||
if sock is None:
|
||||
return -1
|
||||
|
||||
SOCK_STREAM = 1
|
||||
|
||||
# For x8664, recvfrom() is called finally when calling recv() in TCP communications
|
||||
if sock.socktype == SOCK_STREAM:
|
||||
# calling recvfrom with a NULL addr argument is identical to calling recv, which is normally used only on a connected socket
|
||||
if sock.socktype == SOCK_STREAM or (addr == 0 and addrlen == 0):
|
||||
return ql_syscall_recv(ql, sockfd, buf, length, flags)
|
||||
|
||||
data_buf, address = sock.recvfrom(length, flags)
|
||||
@@ -842,10 +844,9 @@ def ql_syscall_sendto(ql: Qiling, sockfd: int, buf: int, length: int, flags: int
|
||||
if sock is None:
|
||||
return -1
|
||||
|
||||
SOCK_STREAM = 1
|
||||
|
||||
# For x8664, sendto() is called finally when calling send() in TCP communications
|
||||
if sock.socktype == SOCK_STREAM:
|
||||
# if sendto is used on a connection-mode socket, the arguments addr and addrlen are ignored.
|
||||
# also, calling sendto(sockfd, buf, length, flags, NULL, 0) is equivalent to send(sockfd, buf, length, flags)
|
||||
if sock.socktype in (SOCK_STREAM, SOCK_SEQPACKET) or (addr == 0 and addrlen == 0):
|
||||
return ql_syscall_send(ql, sockfd, buf, length, flags)
|
||||
|
||||
tmp_buf = ql.mem.read(buf, length)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
@@ -81,12 +81,23 @@ def __RegQueryValue(ql: Qiling, address: int, params, wstring: bool):
|
||||
ql.log.debug("Key value not found")
|
||||
return ERROR_FILE_NOT_FOUND
|
||||
|
||||
# read how many bytes we are allowed to write into lpData, however this arg is optional
|
||||
if lpcbData:
|
||||
max_size = ql.mem.read_ptr(lpcbData, 4)
|
||||
else:
|
||||
max_size = 0
|
||||
|
||||
# lpcbData may be null only if lpData is also null. if lpData is allocated, but lpcbData is
|
||||
# set to null, it means we have an out buffer without knowing its size
|
||||
if lpData:
|
||||
return ERROR_INVALID_PARAMETER
|
||||
|
||||
# set lpData
|
||||
length = ql.os.registry_manager.write_reg_value_into_mem(reg_type, lpData, value, wstring)
|
||||
length = ql.os.registry_manager.write_reg_value_into_mem(reg_type, lpData, value, max_size, wstring)
|
||||
|
||||
# set lpcbData
|
||||
max_size = ql.mem.read_ptr(lpcbData, 4)
|
||||
ql.mem.write_ptr(lpcbData, length, 4)
|
||||
if lpcbData:
|
||||
ql.mem.write_ptr(lpcbData, length, 4)
|
||||
|
||||
if max_size < length:
|
||||
ret = ERROR_MORE_DATA
|
||||
@@ -134,6 +145,9 @@ def __RegSetValue(ql: Qiling, address: int, params, wstring: bool):
|
||||
# this is done so the print_function would print the correct value
|
||||
params["hKey"] = s_hKey
|
||||
|
||||
if not lpData:
|
||||
return ERROR_INVALID_PARAMETER
|
||||
|
||||
# dwType is expected to be REG_SZ and lpData to point to a null-terminated string
|
||||
ql.os.registry_manager.write(s_hKey, lpSubKey, dwType, lpData, cbData, wstring)
|
||||
|
||||
@@ -147,8 +161,12 @@ def __RegSetValueEx(ql: Qiling, address: int, params, wstring: bool):
|
||||
cbData = params["cbData"]
|
||||
|
||||
s_hKey = ql.os.handle_manager.get(hKey).obj
|
||||
# this is done so the print_function would print the correct value
|
||||
params["hKey"] = s_hKey
|
||||
|
||||
if not lpData:
|
||||
return ERROR_INVALID_PARAMETER
|
||||
|
||||
ql.os.registry_manager.write(s_hKey, lpValueName, dwType, lpData, cbData, wstring)
|
||||
|
||||
return ERROR_SUCCESS
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import json, os
|
||||
import json
|
||||
import os
|
||||
|
||||
from Registry import Registry
|
||||
from typing import Any, MutableMapping, Optional, Tuple, Union
|
||||
|
||||
@@ -15,11 +17,11 @@ from qiling.exception import *
|
||||
# Registry Manager reads data from two places
|
||||
# 1. config.json
|
||||
# if you want to modify the registry key/value, you can modify config.json
|
||||
# If there is a registry entry in config.json that needs to be read,
|
||||
# If there is a registry entry in config.json that needs to be read,
|
||||
# Registry Manager will read from config.json first.
|
||||
# 2. windows hive files
|
||||
|
||||
# Registry Manager will only write registry changes to config.json
|
||||
# Registry Manager will only write registry changes to config.json
|
||||
# and will not modify the hive file.
|
||||
|
||||
class RegConf:
|
||||
@@ -208,14 +210,14 @@ class RegistryManager:
|
||||
self.ql.os.stats.log_reg_access(key, name, type, value)
|
||||
|
||||
def create(self, key: str) -> None:
|
||||
self.regconf.create(key)
|
||||
self.reghive.create(key)
|
||||
self.regconf.create(key)
|
||||
self.reghive.create(key)
|
||||
|
||||
def delete(self, key: str, subkey: str) -> None:
|
||||
self.regconf.delete(key, subkey)
|
||||
self.reghive.delete(key, subkey)
|
||||
self.regconf.delete(key, subkey)
|
||||
self.reghive.delete(key, subkey)
|
||||
|
||||
def __reg_mem_read(self, data_type: int, data_addr: int, data_size: int, wide: bool) -> Optional[Union[str, bytes, int]]:
|
||||
def __reg_mem_read(self, data_type: int, data_addr: int, data_size: int, wide: bool) -> Union[str, bytes, int]:
|
||||
if data_type in (Registry.RegSZ, Registry.RegExpandSZ):
|
||||
os_utils = self.ql.os.utils
|
||||
read_string = os_utils.read_wstring if wide else os_utils.read_cstring
|
||||
@@ -232,11 +234,11 @@ class RegistryManager:
|
||||
data = bytes(self.ql.mem.read(data_addr, data_size))
|
||||
|
||||
else:
|
||||
data = None
|
||||
raise QlErrorNotImplemented(f'registry type {REG_TYPES[data_type]} not implemented')
|
||||
|
||||
return data
|
||||
|
||||
def __reg_mem_write(self, data_type: int, data_addr: int, data_val: Union[str, bytes, int], wide: bool) -> Optional[int]:
|
||||
def __reg_mem_write(self, data_type: int, data_addr: int, data_val: Union[str, bytes, int], max_size: int, wide: bool) -> int:
|
||||
if data_type in (Registry.RegSZ, Registry.RegExpandSZ):
|
||||
assert type(data_val) is str
|
||||
|
||||
@@ -259,28 +261,22 @@ class RegistryManager:
|
||||
data = data_val
|
||||
|
||||
else:
|
||||
return None
|
||||
raise QlErrorNotImplemented(f'registry type {REG_TYPES[data_type]} not implemented')
|
||||
|
||||
self.ql.mem.write(data_addr, data)
|
||||
# in case the out buffer is set to null or it is too small, skip data writing
|
||||
if data_addr and max_size >= len(data):
|
||||
self.ql.mem.write(data_addr, data)
|
||||
|
||||
return len(data)
|
||||
|
||||
def write(self, key: str, subkey: str, reg_type: int, data_addr: int, data_size: int, wide: bool) -> None:
|
||||
data = self.__reg_mem_read(reg_type, data_addr, data_size, wide)
|
||||
|
||||
if data is None:
|
||||
raise QlErrorNotImplemented(f'registry type {REG_TYPES[reg_type]} not implemented')
|
||||
|
||||
self.regconf.write(key, subkey, reg_type, data)
|
||||
self.reghive.write(key, subkey, reg_type, data)
|
||||
|
||||
def write_reg_value_into_mem(self, data_type: int, data_addr: int, data_val: Union[str, bytes, int], wide: bool) -> int:
|
||||
length = self.__reg_mem_write(data_type, data_addr, data_val, wide)
|
||||
|
||||
if length is None:
|
||||
raise QlErrorNotImplemented(f'registry type {REG_TYPES[data_type]} not implemented')
|
||||
|
||||
return length
|
||||
def write_reg_value_into_mem(self, data_type: int, data_addr: int, data_val: Union[str, bytes, int], max_size: int, wide: bool) -> int:
|
||||
return self.__reg_mem_write(data_type, data_addr, data_val, max_size, wide)
|
||||
|
||||
def save(self):
|
||||
self.regconf.save(self.regdiff)
|
||||
|
||||
Reference in New Issue
Block a user