Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sysinject hacks #1283

Draft
wants to merge 29 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
9b9a1ba
prepping for PR. 32 bit systems work, 64 do not.
ryandmaggio Feb 23, 2023
b163209
README
ryandmaggio Feb 23, 2023
6c91980
Reapplying changes
ryandmaggio Feb 23, 2023
1a06344
cleaned up stray comments, commented out 64 bit broken code
ryandmaggio Feb 23, 2023
c84ba33
added wrapper around inject_syscall for access specifically
ryandmaggio Mar 1, 2023
f3c454a
cleaned up the readme
ryandmaggio Mar 1, 2023
0e7c6b6
more README cleaning
ryandmaggio Mar 1, 2023
e2d4b08
Update README.md
ryandmaggio Mar 1, 2023
bafc6dd
Update README.md
ryandmaggio Mar 1, 2023
6f6d37e
Update README.md
ryandmaggio Mar 1, 2023
ffae528
added sysinject functionality to panda.py to the user doesn't have to…
ryandmaggio Mar 1, 2023
e9ffa7f
Update README.md
ryandmaggio Mar 1, 2023
a3bc793
Update README.md
ryandmaggio Mar 1, 2023
d7e8966
renamed sysinject_rs to sysinject
ryandmaggio Mar 1, 2023
e64a57d
Update README.md
ryandmaggio Mar 1, 2023
53734e0
Updated README, added mistakenly ommited makefile
ryandmaggio Mar 1, 2023
a067c6f
Cleaned up some bugs in panda.py functions, added example, fleshed ou…
ryandmaggio Mar 3, 2023
e971947
breaking things locally so hopefully PR build works
ryandmaggio Mar 6, 2023
0616da4
fixed references to non-supported x64 so that hopefully the build wor…
ryandmaggio Mar 7, 2023
cd45dba
Maybe fixed it now?
ryandmaggio Mar 8, 2023
1efe9e4
have to make sure x86_64 is defined
ryandmaggio Mar 8, 2023
0f33e42
Fixed return type error
ryandmaggio Mar 13, 2023
9608497
maybe have all the archs covered now
ryandmaggio Mar 13, 2023
1c3faa4
rectifying mipsel misspell
ryandmaggio Mar 13, 2023
43cf710
Realized we do actually support mipsel and mips64
ryandmaggio Mar 13, 2023
cb9732e
actually looked at what archs were expected instead of poking around …
ryandmaggio Mar 13, 2023
cc4c1f5
Maybe now it will build
ryandmaggio Mar 14, 2023
f4c0573
Fix broken bullet in README.md
ryandmaggio Jul 17, 2023
076edda
Update README.md for clarity around sys_access
ryandmaggio Jul 17, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions panda/plugins/config.panda
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ snake_hook
stringsearch
syscalls2
syscalls_logger
sysinject
textprinter
trace
track_intexc
Expand Down
31 changes: 31 additions & 0 deletions panda/plugins/sysinject/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
[package]
name = "sysinject"
version = "0.1.0"
authors = ["Zak Estrada <Zachary.Estrada@ll.mit.edu", "Luke Craig <Luke.Craig@ll.mit.edu>", "Ryan Maggio <Ryan.Maggio@ll.mit.edu>"]
edition = "2018"

[lib]
crate-type = ["cdylib"]

[dependencies]
panda-re = { version = "0.42.1", default-features = false }
#panda-re = { path = "/out/panda-rs/panda-rs", default-features = false }

[features]
#default = ["mips"]
default = ["arm"]
#default = ["i386"]
#default = ["x86_64"]
#default = ["ppc"]

i386 = ["panda-re/i386"]
x86_64 = ["panda-re/x86_64"]

arm = ["panda-re/arm"]
aarch64 = ["panda-re/aarch64"]

ppc = ["panda-re/ppc"]

mips = ["panda-re/mips"]
mipsel = ["panda-re/mipsel"]
mips64 = ["panda-re/mips64"]
17 changes: 17 additions & 0 deletions panda/plugins/sysinject/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Don't forget to add your plugin to config.panda!

# Build rust plugins with make!

# The main rule for your plugin. List all object-file dependencies.

PLUGIN_DIR = $(realpath $(join $(SRC_PATH), /panda/plugins/$(PLUGIN_NAME)/))
RUST_SOURCE = $(wildcard $(PLUGIN_DIR)/src/*.rs)
PLUGIN_ARTIFACTS_DIR = $(PLUGIN_TARGET_DIR)/$(PLUGIN_NAME)/target

$(PLUGIN_TARGET_DIR)/panda_$(PLUGIN_NAME).so : $(RUST_SOURCE) $(PLUGIN_DIR)/Cargo.toml
@echo " CARGO $(PLUGIN_DIR)"
@CARGO_TERM_PROGRESS_WHEN=never cargo build --release \
--no-default-features --features=$(TARGET_NAME) \
--manifest-path=$(PLUGIN_DIR)/Cargo.toml \
--target-dir=$(PLUGIN_ARTIFACTS_DIR)
@cp -p $(PLUGIN_ARTIFACTS_DIR)/release/lib$(PLUGIN_NAME).so $@
111 changes: 111 additions & 0 deletions panda/plugins/sysinject/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
Plugin: sysinject
===========

Summary - Raw API
------
`sysinject` allows for the injection of syscalls into the guest at arbitrary points.

The function `inject_syscall` takes 4 arguments

1. `cpu`, the cpu state. This is standard for panda plugins.

2. `callno`, the syscall number. This number will vary for each syscall dependant on the cpu architecture of the guest, so make sure that you have the right one.

3. `nargs`, the number of arguments to your syscall.

4. `raw_args`, the arguments to pass to your syscall, given as type `target_ulong[nargs]`.
From python, you'll want to use `panda.ffi.new("target_ulong[]", arglist])`, where `arglist` is a list of each of your arguments.
Likewise, each element in `arglist` will need to be converted from its original type to `target_ulong` through `panda.ffi.cast("target_ulong", orig_arg)`.

To use the plugin, simply put the call to `inject_syscall` where you want it to be triggered. For `mips`, if you are having it triggered at a certain address, you will need to somehow gate the function call to avoid repeated calls, since for that architecture the PC is backed up one instruction at the end of `inject_syscall`.

The function `sys_access` simply wraps `inject_syscall` for the `access` syscall, which we expect to be a common use of this plugin. It takes two arguments

1. `cpu`, the cpu state. This is standard for panda plugins.

2. `raw_args`, the arguments to pass to your syscall, given as type `target_ulong[nargs]`.
From python, you'll want to use `panda.ffi.new("target_ulong[]", arglist])`, where `arglist` is a list of each of your arguments.
Likewise, each element in `arglist` will need to be converted from its original type to `target_ulong` through `panda.ffi.cast("target_ulong", orig_arg)`.

This function can be used identially to `inject_syscall`

Summary - Simplified Interface
------

The functionallity of `sysinject` can be alternately accessed through pypanda (as opposed to directly using the plugin), which offloads the work of casting variables and thinking about the number of arguments. To use `sysinject` this way, simply use `panda.inject_syscall` or `panda.sys_access` instead of `panda.plugins["sysinject"].inject_syscall` or `panda.plugins["sysinject"].sys_access`.

The function `inject_syscall` here instead takes 3 arguments:

1. `cpu`, the cpu state.

2. `num`, the syscall number.

3. `args`, a list of arguments to pass to the syscall.

The function `sys_access` here takes 2 arguments:

1. `cpu`, the cpu state.

2. `args`, a list of arguments, namely `pathname` and `mode`.



Example
------

The following is small example of how to use this plugin, it functions if you replace `ptr` with an address you know will actually be hit.


```from pandare import Panda
panda = Panda(generic="arm")
@panda.queue_blocking
def run_cmd():
panda.revert_sync("root")
# print out the exit code, which should be 0xaa if everything worked
print(panda.run_serial_cmd('printf "Exit code: %x" $?'))
panda.end_analysis()

ptr = 0xface0ff

# Hook some known address where we want the syscall to fire
# This hook uses the base plugin interface, which is clunky and likely not what you want,
# but is presented here for completeness
panda.hook(ptr)
def hook(cpu, tb, h):
# need to cast the arguments to the syscall to types rust can handle, namely *const target_ulong
raw_args = panda.ffi.new("target_ulong[]", [panda.ffi.cast("target_ulong",0xaa)])
# call inject_syscall through sysinject, passing:
# cpu
# 248 (syscall num for exit_group in arm)
# 1 (since exit_group takes one argument)
# raw_args: the arguments to pass to the syscall, in this case 0xaa since it's a non-standard exit code
panda.plugins["sysinject"].inject_syscall(cpu, 248, 1, raw_args)

# Only one of this or the previous will actually run, since the syscall is exiting, but both work
panda.hook(ptr)
def hook2(cpu, tb, h):
# Using this interface, you do not need to do the casting yourself
# call inject_syscall through panda, passing:
# cpu: cpu state
# args: list of arguments, in this case just 0xab since it's a non-standard exit code
panda.inject_syscall(cpu, [0xab])

# This hook will call sys_access through the base plugin interface
panda.hook(ptr)
def access(cpu, tb, h):
raw_args = panda.ffi.new("target_ulong[]", [panda.ffi.cast("target_ulong", 0xfeedbeef), panda.ffi.cast("taret_ulong", 0x0)])
# call sys_access, passing a pointer to the file name to access (the pointer can instead be used to page in memory containing that address)
# as well as the mode
panda.plugins["sysinject"].sys_access(cpu, raw_args)

panda.hook(ptr)
def access2(cpu, tb, h):
# basically the same as the previous hook, with fewer steps
panda.sys_access(cpu, [0xfeedbeef, 0x0])

panda.enable_precise_pc()
panda.disable_tb_chaining()
panda.run()
```

A more complete, runnable, example can be found in `panda/python/examples/sysinject`.
Loading