Skip to content
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

Improve shellcode flexibility #1153

Open
wants to merge 8 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions examples/shellcode_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@
ql = Qiling(code=ARM64_LIN, archtype="arm64", ostype="linux", verbose=QL_VERBOSE.DEBUG)
ql.run()

print("\nCreate shellcode after creating Qiling instance")
ql = Qiling(archtype="arm64", ostype="linux", verbose=QL_VERBOSE.DEBUG)
addr = ql.mem.map_anywhere(0x1000)
ql.mem[addr:] = ARM64_LIN
stack = ql.mem.map_anywhere(0x1000)
ql.arch.regs.arch_sp = stack
ql.run(begin=addr, end=addr + len(ARM64_LIN))

print("\nLinux ARM 32bit Shellcode")
ql = Qiling(code=ARM_LIN, archtype="arm", ostype="linux", verbose=QL_VERBOSE.DEBUG)
ql.run()
Expand Down
6 changes: 3 additions & 3 deletions qiling/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,14 +88,14 @@ def __init__(
# argv setup #
##############
if argv is None:
argv = ['qilingcode']
argv = []

elif not os.path.exists(argv[0]):
raise QlErrorFileNotFound(f'Target binary not found: "{argv[0]}"')

self._argv = argv
self._path = self.argv[0]
self._targetname = os.path.basename(self.path)
self._path = self.argv[0] if len(self.argv) != 0 else ""
self._targetname = os.path.basename(self.path) if self.path is not None else ""

################
# rootfs setup #
Expand Down
7 changes: 4 additions & 3 deletions qiling/debugger/gdb/gdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import struct, os, socket
from binascii import unhexlify
from sys import argv
from typing import Iterator, Literal

from qiling import Qiling
Expand Down Expand Up @@ -41,7 +42,7 @@ def __init__(self, ql: Qiling, ip: str = '127.0.01', port: int = 9999):

self.ql = ql
self.last_pkt = None
self.exe_abspath = os.path.abspath(self.ql.argv[0])
self.exe_abspath = os.path.abspath(self.ql.argv[0] if len(self.ql.argv) else "shellcode")
self.rootfs_abspath = os.path.abspath(self.ql.rootfs)
self.gdb = QlGdbUtils()

Expand All @@ -54,7 +55,7 @@ def __init__(self, ql: Qiling, ip: str = '127.0.01', port: int = 9999):
if self.ql.baremetal:
load_address = self.ql.loader.load_address
exit_point = load_address + os.path.getsize(ql.path)
elif self.ql.code:
elif self.ql.code or len(self.ql.argv) == 0:
load_address = self.ql.os.entry_point
exit_point = load_address + len(ql.code)
else:
Expand Down Expand Up @@ -503,7 +504,7 @@ def handle_q(subcmd):
self.send("l" + file_contents)

elif subcmd.startswith('Xfer:auxv:read::'):
if self.ql.code:
if self.ql.code or len(self.ql.argv) == 0:
return

if self.ql.os.type in (QL_OS.LINUX, QL_OS.FREEBSD):
Expand Down
5 changes: 5 additions & 0 deletions qiling/loader/blob.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ def __init__(self, ql: Qiling):
self.load_address = 0

def run(self):

# Shellcode case.
if len(self.ql.argv) == 0:
return

self.load_address = self.ql.os.entry_point # for consistency

self.ql.mem.map(self.ql.os.entry_point, self.ql.os.code_ram_size, info="[code]")
Expand Down
5 changes: 5 additions & 0 deletions qiling/loader/dos.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ def excepthook(self, tp, value, tb):
self.old_excepthook(tp, value, tb)

def run(self):

# Shellcode case.
if len(self.ql.argv) == 0:
return

path = self.ql.path
profile = self.ql.profile

Expand Down
5 changes: 4 additions & 1 deletion qiling/loader/elf.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,17 @@ def run(self):
if self.ql.code:
self.ql.mem.map(self.ql.os.entry_point, self.ql.os.code_ram_size, info="[shellcode_stack]")

shellcode_base = self.ql.os.entry_point + 0x200000 - 0x1000
shellcode_base = self.ql.os.entry_point + self.ql.os.code_ram_size // 2
self.ql.mem.write(shellcode_base, self.ql.code)

self.ql.arch.regs.arch_sp = shellcode_base
self.ql.os.entry_point = shellcode_base
self.load_address = shellcode_base

return
elif len(self.ql.argv) == 0:
self.load_address = 0
return

section = {
32 : 'OS32',
Expand Down
2 changes: 1 addition & 1 deletion qiling/loader/evm.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def __init__(self, ql:Qiling):
super(QlLoaderEVM, self).__init__(ql)
self.ql = ql

if self.ql.code is None:
if len(self.ql.argv) == 0:
with open(self.ql.path) as f:
self.code = f.read()
else:
Expand Down
5 changes: 5 additions & 0 deletions qiling/loader/macho.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ def __init__(self, ql, dyld_path=None):
self.kext_name = None

def run(self):

# Shellcode case.
if len(self.ql.argv) == 0:
return

self.profile = self.ql.profile
stack_address = int(self.profile.get("OS64", "stack_address"), 16)
stack_size = int(self.profile.get("OS64", "stack_size"), 16)
Expand Down
5 changes: 5 additions & 0 deletions qiling/loader/mcu.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,11 @@ def load_env(self):
self.ql.hw.create(name.lower())

def run(self):

# Shellcode case.
if len(self.ql.argv) == 0:
return

self.load_profile()
self.load_env()

Expand Down
2 changes: 1 addition & 1 deletion qiling/loader/pe.py
Original file line number Diff line number Diff line change
Expand Up @@ -660,7 +660,7 @@ def run(self):
'ucrtbase.dll'
)

if self.ql.code:
if self.ql.code or len(self.ql.argv) == 0:
pe = None
self.is_driver = False
else:
Expand Down
5 changes: 5 additions & 0 deletions qiling/loader/pe_uefi.py
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,11 @@ def __init_smm_environment(self, ql: Qiling) -> SmmContext:
return context

def run(self):

# Shellcode case.
if len(self.ql.argv) == 0:
return

ql = self.ql

# intel architecture uefi implementation only
Expand Down
2 changes: 2 additions & 0 deletions qiling/os/linux/linux.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ def run(self):
try:
if self.ql.code:
self.ql.emu_start(self.entry_point, (self.entry_point + len(self.ql.code)), self.ql.timeout, self.ql.count)
elif len(self.ql.argv) == 0:
self.ql.emu_start(self.ql.entry_point, self.ql.exit_point, self.ql.timeout, self.ql.count)
else:
if self.ql.multithread == True:
# start multithreading
Expand Down
5 changes: 3 additions & 2 deletions qiling/os/macos/macos.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ def load_kext(self):


def load(self):
if self.ql.code:
if self.ql.code or len(self.ql.argv) == 0:
return

if self.ql.arch.type == QL_ARCH.ARM64:
Expand Down Expand Up @@ -202,7 +202,8 @@ def callback_ret(ql):
try:
if self.ql.code:
self.ql.emu_start(self.entry_point, (self.entry_point + len(self.ql.code)), self.ql.timeout, self.ql.count)

elif len(self.ql.argv) == 0:
self.ql.emu_start(self.ql.entry_point, self.ql.exit_point, self.ql.timeout, self.ql.count)
else:
self.ql.emu_start(self.ql.loader.entry_point, self.exit_point, self.ql.timeout, self.ql.count)
except UcError:
Expand Down
39 changes: 38 additions & 1 deletion qiling/os/memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#

import os, re
from typing import Any, Callable, List, MutableSequence, Optional, Sequence, Tuple
from typing import Any, Callable, List, MutableSequence, Optional, Sequence, Tuple, Union

from unicorn import UC_PROT_NONE, UC_PROT_READ, UC_PROT_WRITE, UC_PROT_EXEC, UC_PROT_ALL

Expand Down Expand Up @@ -63,6 +63,43 @@ def __read_string(self, addr: int) -> str:
def __write_string(self, addr: int, s: str, encoding: str):
self.write(addr, bytes(s, encoding) + b'\x00')

def __getitem__(self, key: Union[slice, int]) -> bytearray:
if isinstance(key, slice):
start = key.start
stop = key.stop
step = key.step

if step is not None and step != 1:
# step != 1 means we have to do copy, don't allow it.
raise IndexError("Only support slicing continous memory")

return self.ql.mem.read(start, max(0, stop - start))
elif isinstance(key, int):
return self.ql.mem.read(key, 1)[0]
else:
raise KeyError("Wrong type of key")

def __setitem__(self, key: Union[slice, int], value: bytes):
if isinstance(key, int):
self.ql.mem.write(key, bytes([value]))
elif isinstance(key, slice):
start = key.start
stop = key.stop
step = key.step

if step is not None and step != 1:
raise IndexError("Only support slicing continous memory")

if start is None:
raise IndexError("The start of memory is not supplied")

if stop is not None and len(value) > stop - start:
raise IndexError("Bytes to write are more than sliced memory")

self.ql.mem.write(start, value)
else:
raise KeyError("Wrong type of key")

# TODO: this is an obsolete utility method that should not be used anymore
# and here for backward compatibility. use QlOsUtils.read_cstring instead
def string(self, addr: int, value=None, encoding='utf-8') -> Optional[str]:
Expand Down
2 changes: 1 addition & 1 deletion qiling/os/os.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def __init__(self, ql: Qiling, resolvers: Mapping[Any, Resolver] = {}):
64: 0xffffffffffffffff
}.get(self.ql.arch.bits, None)

if self.ql.code:
if self.ql.code or len(self.ql.argv) == 0:
# this shellcode entrypoint does not work for windows
# windows shellcode entry point will comes from pe loader
self.entry_point = self.profile.getint('CODE', 'entry_point')
Expand Down
2 changes: 1 addition & 1 deletion qiling/os/posix/syscall/unistd.py
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ def __read_str_array(addr: int) -> Iterator[str]:
# Clean debugger to prevent port conflicts
# ql.debugger = None

if ql.code:
if ql.code or len(ql.argv) == 0:
return

# recreate cached uc
Expand Down
4 changes: 3 additions & 1 deletion qiling/os/qnx/qnx.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def __init__(self, ql: Qiling):
self.connections[SYSMGR_COID] = QnxConn(SYSMGR_PID, SYSMGR_CHID)

def load(self):
if self.ql.code:
if self.ql.code or len(self.ql.argv) == 0:
return

# ARM
Expand Down Expand Up @@ -126,6 +126,8 @@ def run(self):
try:
if self.ql.code:
self.ql.emu_start(self.entry_point, (self.entry_point + len(self.ql.code)), self.ql.timeout, self.ql.count)
elif len(self.ql.argv) == 0:
self.ql.emu_start(self.ql.entry_point, self.ql.exit_point, self.ql.timeout, self.ql.count)
else:
if self.ql.loader.elf_entry != self.ql.loader.entry_point:
entry_address = self.ql.loader.elf_entry
Expand Down