270 lines
6.7 KiB
C++
270 lines
6.7 KiB
C++
/*
|
|
* This is a sample plugin to demonstrate the snapshot management API
|
|
*/
|
|
|
|
#include <ida.hpp>
|
|
#include <idp.hpp>
|
|
#include <loader.hpp>
|
|
#include <kernwin.hpp>
|
|
|
|
//--------------------------------------------------------------------------
|
|
class snapman_t : public chooser_t
|
|
{
|
|
struct snapdesc_t
|
|
{
|
|
snapshot_t *ss;
|
|
qstring title;
|
|
qstring date;
|
|
};
|
|
typedef qvector<snapdesc_t> sdlist_t;
|
|
snapshot_t root;
|
|
sdlist_t sdlist;
|
|
|
|
static const int widths_[2];
|
|
static const char *const header_[2];
|
|
|
|
static void idaapi done_restore(const char *err_msg, void *)
|
|
{
|
|
if ( err_msg != NULL )
|
|
warning("ICON ERROR\nError restoring: %s", err_msg);
|
|
else
|
|
warning("Restored successfully!");
|
|
}
|
|
|
|
void build_tree_list(snapshot_t *n, int level = 0)
|
|
{
|
|
if ( n != &root )
|
|
{
|
|
// Insert new description record
|
|
snapdesc_t &sd = sdlist.push_back();
|
|
|
|
// Compute title
|
|
for ( int i=0; i < level; i++ )
|
|
sd.title += " ";
|
|
if ( n->id == root.id )
|
|
sd.title += "->";
|
|
sd.title += n->desc;
|
|
|
|
// Compute date
|
|
char ss_date[MAXSTR];
|
|
qstrftime64(ss_date, sizeof(ss_date), "%Y-%m-%d %H:%M:%S", n->id);
|
|
sd.date = ss_date;
|
|
// Store ss
|
|
sd.ss = n;
|
|
}
|
|
for ( snapshots_t::iterator it=n->children.begin(); it != n->children.end(); ++it )
|
|
build_tree_list(*it, level+1);
|
|
}
|
|
|
|
snapdesc_t *get_item(uint32 n)
|
|
{
|
|
return n >= sdlist.size() ? NULL : &sdlist[n];
|
|
}
|
|
const snapdesc_t *get_item(uint32 n) const
|
|
{
|
|
return n >= sdlist.size() ? NULL : &sdlist[n];
|
|
}
|
|
|
|
public:
|
|
bool init() override
|
|
{
|
|
sdlist.clear();
|
|
root.clear();
|
|
if ( !build_snapshot_tree(&root) )
|
|
{
|
|
warning("Snapshot tree cannot be built.\nNo snapshots exist?");
|
|
return false;
|
|
}
|
|
|
|
// Convert the tree to a list
|
|
build_tree_list(&root);
|
|
if ( sdlist.empty() )
|
|
{
|
|
warning("Snapshot tree empty!");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
snapman_t()
|
|
: chooser_t(CH_MODAL | CH_KEEP | CH_CAN_INS | CH_CAN_DEL | CH_CAN_EDIT,
|
|
qnumber(widths_), widths_, header_,
|
|
"Simple snapshot manager"),
|
|
root(),
|
|
sdlist() {}
|
|
|
|
virtual size_t idaapi get_count() const override
|
|
{
|
|
return sdlist.size();
|
|
}
|
|
|
|
virtual void idaapi get_row(
|
|
qstrvec_t *cols_,
|
|
int *,
|
|
chooser_item_attrs_t *,
|
|
size_t n) const override
|
|
{
|
|
const snapdesc_t *sd = get_item(n);
|
|
QASSERT(561, sd != NULL);
|
|
|
|
qstrvec_t &cols = *cols_;
|
|
cols[0] = sd->date;
|
|
cols[1] = sd->title;
|
|
}
|
|
|
|
virtual cbret_t idaapi ins(ssize_t n) override
|
|
{
|
|
qstring desc = "snapshot description";
|
|
if ( !ask_str(&desc, HIST_CMT, "Enter snapshot description") )
|
|
return cbret_t(); // nothing changed
|
|
|
|
qstring err_msg;
|
|
snapshot_t new_attr;
|
|
qstrncpy(new_attr.desc, desc.c_str(), sizeof(new_attr.desc));
|
|
if ( !take_database_snapshot(&new_attr, &err_msg) )
|
|
{
|
|
warning("Failed to create a snapshot, error: %s", err_msg.c_str());
|
|
return cbret_t(); // nothing changed
|
|
}
|
|
msg("Created new snapshot: %s\n", new_attr.filename);
|
|
init();
|
|
// we preserve the selection
|
|
// FIXME use get_item_index()
|
|
return n;
|
|
}
|
|
|
|
virtual cbret_t idaapi del(size_t n) override
|
|
{
|
|
const snapdesc_t *sd = get_item(n);
|
|
if ( sd == NULL )
|
|
return cbret_t();
|
|
|
|
// Simply delete the file
|
|
qunlink(sd->ss->filename);
|
|
|
|
// Rebuild the list
|
|
init();
|
|
|
|
return adjust_last_item(n); // take in account deleting of the last item
|
|
}
|
|
|
|
virtual cbret_t idaapi edit(size_t n) override
|
|
{
|
|
snapdesc_t *sd = get_item(n);
|
|
if ( sd == NULL )
|
|
return cbret_t();
|
|
|
|
qstring desc = sd->ss->desc;
|
|
if ( !ask_str(&desc, HIST_CMT, "Enter new snapshot description") )
|
|
return cbret_t();
|
|
|
|
// Update the description
|
|
qstrncpy(sd->ss->desc, desc.c_str(), sizeof(sd->ss->desc));
|
|
update_snapshot_attributes(sd->ss->filename, &root, sd->ss, SSUF_DESC);
|
|
return n;
|
|
}
|
|
|
|
// calculate the location of the default item only,
|
|
// `item_data` is a pointer to a snapshot ID
|
|
virtual ssize_t idaapi get_item_index(const void *item_data) const override
|
|
{
|
|
qtime64_t item_id = *(const qtime64_t *)item_data;
|
|
for ( size_t i = 0; i < sdlist.size(); ++i )
|
|
{
|
|
if ( sdlist[i].ss->id == item_id )
|
|
return i;
|
|
}
|
|
return NO_SELECTION;
|
|
}
|
|
|
|
void show()
|
|
{
|
|
// now open the window
|
|
ssize_t n = ::choose(this, &root.id);
|
|
if ( n >= 0 )
|
|
{
|
|
snapdesc_t *sd = get_item(n);
|
|
if ( sd != NULL && sd->ss != NULL )
|
|
restore_database_snapshot(sd->ss, done_restore, NULL);
|
|
}
|
|
}
|
|
};
|
|
DECLARE_TYPE_AS_MOVABLE(snapman_t::snapdesc_t);
|
|
|
|
// column widths
|
|
const int snapman_t::widths_[2] =
|
|
{
|
|
12, // Date
|
|
70, // Description
|
|
};
|
|
|
|
// column headers
|
|
const char *const snapman_t::header_[2] =
|
|
{
|
|
"Date", // 0
|
|
"Description", // 1
|
|
};
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
struct plugin_ctx_t : public plugmod_t
|
|
{
|
|
virtual bool idaapi run(size_t) override;
|
|
};
|
|
|
|
//--------------------------------------------------------------------------
|
|
bool idaapi plugin_ctx_t::run(size_t)
|
|
{
|
|
snapman_t sm;
|
|
if ( !sm.init() )
|
|
return false;
|
|
|
|
sm.show();
|
|
return true;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
static plugmod_t *idaapi init()
|
|
{
|
|
// Display help
|
|
msg(
|
|
"Simple snapshot manager loaded!\n"
|
|
"Press Shift+F8 to toggle the plugin\n"
|
|
"Inside the snapshots window, press:\n"
|
|
" - Insert: to take a snapshot\n"
|
|
" - Delete: to delete\n"
|
|
" - Edit: to edit the snapshot description\n"
|
|
"\n"
|
|
"Click on:\n"
|
|
" - Ok: to restore the selected snapshot\n"
|
|
" - Cancel: close without doing anything\n");
|
|
|
|
// The plugin flags must include PLUGIN_FIX as well
|
|
return new plugin_ctx_t;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// PLUGIN DESCRIPTION BLOCK
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
plugin_t PLUGIN =
|
|
{
|
|
IDP_INTERFACE_VERSION,
|
|
// plugin flags
|
|
PLUGIN_FIX // Load plugin when IDA starts and keep it in the
|
|
// memory until IDA stops
|
|
| PLUGIN_MULTI, // The plugin can work with multiple idbs in parallel
|
|
init, // initialize
|
|
nullptr,
|
|
nullptr,
|
|
"This is a sample plugin. It displays the list of snapshots",
|
|
// long comment about the plugin
|
|
"A snapshot manager sample plugin\n"
|
|
"\n"
|
|
"This plugin allows you to list and restore snapshots.\n",
|
|
// multiline help about the plugin
|
|
"Simple snapshot manager", // the preferred short name of the plugin
|
|
"Shift-F8", // the preferred hotkey to run the plugin
|
|
};
|