Skip to content

Commit

Permalink
hypercaller plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
lacraig2 committed May 10, 2024
1 parent 14c4f55 commit ce2ba3c
Show file tree
Hide file tree
Showing 6 changed files with 163 additions and 0 deletions.
17 changes: 17 additions & 0 deletions panda/plugins/hypercaller/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!

# If you need custom CFLAGS or LIBS, set them up here
# CFLAGS+=
# LIBS+=

# Example: this plugin has runtime symbol dependencies on plugin_x:
# LIBS+=-L$(PLUGIN_TARGET_DIR) -l:panda_plugin_x.so
# Also create a plugin_plugin.d file in this directory to ensure plugin_x
# gets compiled before this plugin, example contents:
# plugin-this_plugins_name : plugin-plugin_x
# or if you're using the extra plugins dir:
# extra-plugin-this_plugins_name : extra-plugin-plugin_x

# The main rule for your plugin. List all object-file dependencies.
$(PLUGIN_TARGET_DIR)/panda_$(PLUGIN_NAME).so: \
$(PLUGIN_OBJ_DIR)/$(PLUGIN_NAME).o
17 changes: 17 additions & 0 deletions panda/plugins/hypercaller/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
Plugin: NAME
===========

Summary
-------

Arguments
---------

Dependencies
------------

APIs and Callbacks
------------------

Example
-------
76 changes: 76 additions & 0 deletions panda/plugins/hypercaller/hypercaller.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/* PANDABEGINCOMMENT
*
* Authors:
* Luke Craig luke.craig@ll.mit.edu
*
* This work is licensed under the terms of the GNU GPL, version 2.
* See the COPYING file in the top-level directory.
*
PANDAENDCOMMENT */
// This needs to be defined before anything is included in order to get
// the PRIx64 macro
#define __STDC_FORMAT_MACROS

#include "panda/plugin.h"
#include <unordered_map>

// These need to be extern "C" so that the ABI is compatible with
// QEMU/PANDA, which is written in C
extern "C" {
bool init_plugin(void *);
void uninit_plugin(void *);
bool hypercall(CPUState *cpu);
#include "hypercaller.h"
}

std::unordered_map<target_ulong, hypercall_t> hypercalls;

void register_hypercall(target_ulong magic, hypercall_t hyp){
if (hypercalls.find(magic) == hypercalls.end()){
hypercalls[magic] = hyp;
}else{
assert(false && "Hypercall already registered");
}
}

void unregister_hypercall(target_ulong magic){
hypercalls.erase(magic);
}

target_ulong get_magic(CPUState *cpu){
target_ulong magic;
CPUArchState * env = (CPUArchState *)cpu->env_ptr;
#if defined(TARGET_ARM)
// r0
magic =env->regs[0];
#elif defined(TARGET_MIPS)
// a0
magic =env->active_tc.gpr[4];
#elif defined(TARGET_I386)
// eax
magic = env->regs[R_EAX];
#elif defined(TARGET_PPC)
// r0
magic = env->gpr[0];
#else
#error "Unsupported target architecture"
#endif
return magic;
}

bool guest_hypercall(CPUState *cpu) {
target_ulong magic = get_magic(cpu);
if (hypercalls.find(magic) != hypercalls.end()){
hypercalls[magic](cpu);
return true;
}
return false;
}

bool init_plugin(void *self) {
panda_cb pcb = { .guest_hypercall = guest_hypercall};
panda_register_callback(self, PANDA_CB_GUEST_HYPERCALL, pcb);
return true;
}

void uninit_plugin(void *self) {}
14 changes: 14 additions & 0 deletions panda/plugins/hypercaller/hypercaller.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#ifndef __HYPERCALLER_H
#define __HYPERCALLER_H
// BEGIN_PYPANDA_NEEDS_THIS -- do not delete this comment bc pypanda
// api autogen needs it. And don't put any compiler directives
// between this and END_PYPANDA_NEEDS_THIS except includes of other
// files in this directory that contain subsections like this one.

typedef void (*hypercall_t)(CPUState *cpu);
void register_hypercall(target_ulong magic, hypercall_t);
void unregister_hypercall(target_ulong magic);

// END_PYPANDA_NEEDS_THIS -- do not delete this comment!

#endif
1 change: 1 addition & 0 deletions panda/python/core/create_panda_datatypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,7 @@ def main(install=False,recompile=True):
copy_ppp_header("%s/%s" % (PLUGINS_DIR+"/forcedexec", "forcedexec_ppp.h"))
copy_ppp_header("%s/%s" % (PLUGINS_DIR+"/stringsearch", "stringsearch_ppp.h"))
create_pypanda_header("%s/%s" % (PLUGINS_DIR+"/hooks2", "hooks2.h"))
create_pypanda_header("%s/%s" % (PLUGINS_DIR+"/hypercaller", "hypercaller.h"))

copy_ppp_header("%s/%s" % (PLUGINS_DIR+"/proc_start_linux", "proc_start_linux_ppp.h"))
create_pypanda_header("%s/%s" % (PLUGINS_DIR+"/proc_start_linux", "proc_start_linux.h"))
Expand Down
38 changes: 38 additions & 0 deletions panda/python/core/pandare/panda.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ def __init__(self, arch="i386", mem="128M",
self.hook_list2 = {}
self.mem_hooks = {}
self.sr_hooks = []
self.hypercalls = {}

# Asid stuff
self.current_asid_name = None
Expand Down Expand Up @@ -3482,5 +3483,42 @@ def hook_virt_mem_write(self, start_address, end_address, on_before=True, on_aft
Decorator to hook virtual memory writes with the mem_hooks plugin
'''
return self._hook_mem(start_address,end_address,on_before,on_after, False, True, True, False, True)

# HYPERCALLS
def hypercall(self, magic):
def decorator(fun):
hypercall_cb_type = self.ffi.callback("hypercall_t")

def _run_and_catch(*args, **kwargs): # Run function but if it raises an exception, stop panda and raise it
if not hasattr(self, "exit_exception"):
try:
r = fun(*args, **kwargs)
return r
except Exception as e:
# exceptions wont work in our thread. Therefore we print it here and then throw it after the
# machine exits.
if self.catch_exceptions:
self.exit_exception = e
self.end_analysis()
else:
raise e
return None

hook_cb_passed = hypercall_cb_type(_run_and_catch)

self.plugins['hypercaller'].register_hypercall(magic, hook_cb_passed)

def wrapper(*args, **kw):
_run_and_catch(args,kw)
self.hypercalls[wrapper] = [hook_cb_passed,magic]
return wrapper
return decorator

def disable_hypercall(self, fn):
if fn in self.hypercalls:
self.plugins['hypercaller'].unregister_hypercall(self.hypercalls[fn][1])
else:
breakpoint()
print("ERROR: Your hypercall was not in the hook list")

# vim: expandtab:tabstop=4:

0 comments on commit ce2ba3c

Please sign in to comment.