Skip to content

Instantly share code, notes, and snippets.

@Wenzel
Last active September 18, 2018 19:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Wenzel/25530c175111a834a959fab2ca8bca26 to your computer and use it in GitHub Desktop.
Save Wenzel/25530c175111a834a959fab2ca8bca26 to your computer and use it in GitHub Desktop.
/* The LibVMI Library is an introspection library that simplifies access to
* memory in a target virtual machine or in a file containing a dump of
* a system's physical memory. LibVMI is based on the XenAccess Library.
*
* Author: Tamas K Lengyel (tamas.lengyel@zentific.com)
*
* This file is part of LibVMI.
*
* LibVMI is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* LibVMI is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with LibVMI. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/mman.h>
#include <stdio.h>
#include <inttypes.h>
#include <signal.h>
#include <libvmi/libvmi.h>
#include <libvmi/events.h>
static int interrupted = false;
event_response_t cb_on_make_sstep(vmi_instance_t vmi, vmi_event_t *event)
{
printf("user single step !\n");
return VMI_EVENT_RESPONSE_NONE;
}
bool make_single_step(vmi_instance_t vmi, vmi_event_t *event, int vcpu_id, int nb_steps)
{
vmi_event_t ss_event;
status_t status;
// clear original event
// relax permissions
printf("clear mem event\n");
status = vmi_clear_event(vmi, event, NULL);
if (VMI_FAILURE == status)
{
printf("%s: fail to clear event\n", __func__);
return false;
}
// prepare single step
memset(&ss_event, 0, sizeof(vmi_event_t));
ss_event.version = VMI_EVENTS_VERSION;
ss_event.type = VMI_EVENT_SINGLESTEP;
ss_event.callback = cb_on_make_sstep;
ss_event.ss_event.enable = 1;
SET_VCPU_SINGLESTEP(ss_event.ss_event, vcpu_id);
// register event
printf("register single step\n");
status = vmi_register_event(vmi, &ss_event);
if (VMI_FAILURE == status)
{
printf("%s: registering single step event failed\n", __func__);
return false;
}
// listen
for (int counter = 1; counter <= nb_steps; counter++)
{
printf("%s: step %d, Listening on VMI events...(%d)\n", __func__, counter, vmi_are_events_pending(vmi));
status = vmi_events_listen(vmi, 1000);
if (VMI_FAILURE == status)
{
printf("%s: Listening failed\n", __func__);
return false;
}
}
// clear singlestep
printf("clear singlestep event\n");
status = vmi_clear_event(vmi, &ss_event, NULL);
if (VMI_FAILURE == status)
{
printf("%s: fail to clear event\n", __func__);
return false;
}
// register original event
printf("register mem event\n");
status = vmi_register_event(vmi, event);
if (VMI_FAILURE == status)
{
printf("%s: registering event failed\n", __func__);
return false;
}
return true;
}
void print_event(vmi_event_t *event)
{
printf("PAGE ACCESS: %c%c%c for GFN %"PRIx64" (offset %06"PRIx64") gla %016"PRIx64" (vcpu %"PRIu32")\n",
(event->mem_event.out_access & VMI_MEMACCESS_R) ? 'r' : '-',
(event->mem_event.out_access & VMI_MEMACCESS_W) ? 'w' : '-',
(event->mem_event.out_access & VMI_MEMACCESS_X) ? 'x' : '-',
event->mem_event.gfn,
event->mem_event.offset,
event->mem_event.gla,
event->vcpu_id
);
}
event_response_t cb_on_mem_event(vmi_instance_t vmi, vmi_event_t *event)
{
print_event(event);
// singlestep
make_single_step(vmi, event, event->vcpu_id, 5);
// stop loop
interrupted = true;
return VMI_EVENT_RESPONSE_NONE;
}
int main (int argc, char **argv)
{
vmi_instance_t vmi = NULL;
status_t status = VMI_SUCCESS;
if (argc < 3) {
fprintf(stderr, "Usage: xen-emulate-response <name of VM> <kernel API>\n");
return 1;
}
addr_t addr;
char *name, *symbol = NULL;
// Arg 1 is the VM name.
name = argv[1];
symbol = argv[2];
// Initialize the libvmi library.
if (VMI_FAILURE ==
vmi_init_complete(&vmi, (void*)name, VMI_INIT_DOMAINNAME | VMI_INIT_EVENTS,
NULL, VMI_CONFIG_GLOBAL_FILE_ENTRY, NULL, NULL)) {
printf("Failed to init LibVMI library.\n");
return 1;
}
printf("LibVMI init succeeded!\n");
vmi_event_t event;
memset(&event, 0, sizeof(vmi_event_t));
event.version = VMI_EVENTS_VERSION;
event.type = VMI_EVENT_MEMORY;
vmi_translate_ksym2v(vmi, symbol, &addr);
vmi_translate_kv2p(vmi, addr, &event.mem_event.gfn);
event.mem_event.gfn >>= 12;
event.mem_event.in_access = VMI_MEMACCESS_X;
event.callback = cb_on_mem_event;
if ( VMI_FAILURE == vmi_register_event(vmi, &event) )
goto leave;
while (!interrupted) {
printf("Waiting for events...\n");
status = vmi_events_listen(vmi,500);
if (status != VMI_SUCCESS) {
printf("Error waiting for events, quitting...\n");
interrupted = -1;
}
};
printf("Finished with test.\n");
leave:
// cleanup any memory associated with the libvmi instance
vmi_destroy(vmi);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment