void idaapi term(void) { msg(PLUGIN_NAME": collabREate is being unloaded\n"); authenticated = false; if (is_connected()) { msg(PLUGIN_NAME": calling cleanup\n"); cleanup(); msg(PLUGIN_NAME": back from cleanup\n"); } msg(PLUGIN_NAME": closing status form\n"); close_chooser("Collab form:1"); msg(PLUGIN_NAME": status form closed\n"); if (msgHistory.size() > 0) { qstring temp; for (unsigned int i = 0; i < msgHistory.size(); i++) { temp += msgHistory[i]; temp += '\n'; } cnn.setblob(temp.c_str(), temp.length() + 1, 1, COLLABREATE_MSGHISTORY_TAG); msgHistory.clear(); } if (changeCache != NULL && changeCache->length() > 0) { cnn.setblob(changeCache->c_str(), changeCache->length() + 1, 1, COLLABREATE_CACHE_TAG); delete changeCache; changeCache = NULL; } unhookAll(); }
//-------------------------------------------------------------------------- // // Initialize. // // IDA will call this function only once. // If this function returns PLGUIN_SKIP, IDA will never load it again. // If this function returns PLUGIN_OK, IDA will unload the plugin but // remember that the plugin agreed to work with the database. // The plugin will be loaded again if the user invokes it by // pressing the hotkey or selecting it from the menu. // After the second load the plugin will stay on memory. // If this function returns PLUGIN_KEEP, IDA will keep the plugin // in the memory. In this case the initialization function can hook // into the processor module and user interface notification points. // See the hook_to_notification_point() function. // // In this example we check the input file format and make the decision. // You may or may not check any other conditions to decide what you do: // whether you agree to work with the database or not. // int idaapi init(void) { unsigned char md5[MD5_LEN]; msg(PLUGIN_NAME": collabREate has been loaded\n"); //while the md5 is not used here, it has the side effect of ensuring //that the md5 is taken at the earliest opportunity for storage in //the database in the event that the original binary is deleted getFileMd5(md5, sizeof(md5)); unsigned char gpid[GPID_SIZE]; ssize_t sz = getGpid(gpid, sizeof(gpid)); if (sz > 0) { msg(PLUGIN_NAME": Operating in caching mode until connected.\n"); if (changeCache == NULL) { size_t sz = 0; void *tcache = cnn.getblob(NULL, &sz, 1, COLLABREATE_CACHE_TAG); if (tcache != NULL && sz > 0) { changeCache = new qstring((char*)tcache); } else { changeCache = new qstring(); } qfree(tcache); hookAll(); } } if (msgHistory.size() == 0) { size_t sz = 0; void *thist = cnn.getblob(NULL, &sz, 1, COLLABREATE_MSGHISTORY_TAG); if (thist != NULL && sz > 1) { char *sptr, *endp; sptr = (char*)thist; while ((endp = strchr(sptr, '\n')) != NULL) { msgHistory.push_back(qstring(sptr, endp - sptr)); sptr = endp + 1; } } qfree(thist); } build_handler_map(); if (init_network()) { return PLUGIN_KEEP; } else { return PLUGIN_SKIP; } }
void on_get_line(int lineno, char * const *line_arr) { // Called from s_getl, which itself can be called from the kernel. Ensure GIL PYW_GIL_GET; // Get headers? if ( lineno == 0 ) { // Copy the pre-parsed columns for ( size_t i=0; i < cols.size(); i++ ) qstrncpy(line_arr[i], cols[i].c_str(), MAXSTR); return; } // Clear buffer int ncols = int(cols.size()); for ( int i=ncols-1; i>=0; i-- ) line_arr[i][0] = '\0'; // Call Python PYW_GIL_CHECK_LOCKED_SCOPE(); newref_t list(PyObject_CallMethod(self, (char *)S_ON_GET_LINE, "i", lineno - 1)); if ( list == NULL ) return; // Go over the List returned by Python and convert to C strings for ( int i=ncols-1; i>=0; i-- ) { borref_t item(PyList_GetItem(list.o, Py_ssize_t(i))); if ( item == NULL ) continue; const char *str = PyString_AsString(item.o); if ( str != NULL ) qstrncpy(line_arr[i], str, MAXSTR); } }
//-------------------------------------------------------------------------- static int idaapi callback(void *, int code, va_list va) { int result = 0; switch ( code ) { case grcode_calculating_layout: // calculating user-defined graph layout // in: mutable_graph_t *g // out: 0-not implemented // 1-graph layout calculated by the plugin msg("calculating graph layout...\n"); break; case grcode_changed_current: // a new graph node became the current node // in: graph_viewer_t *gv // int curnode // out: 0-ok, 1-forbid to change the current node { graph_viewer_t *v = va_arg(va, graph_viewer_t *); int curnode = va_argi(va, int); msg("%p: current node becomes %d\n", v, curnode); } break; case grcode_clicked: // a graph has been clicked // in: graph_viewer_t *gv // selection_item_t *current_item // out: 0-ok, 1-ignore click { /*graph_viewer_t *v =*/ va_arg(va, graph_viewer_t *); va_arg(va, selection_item_t *); graph_item_t *m = va_arg(va, graph_item_t *); msg("clicked on "); switch ( m->type ) { case git_none: msg("background\n"); break; case git_edge: msg("edge (%d, %d)\n", m->e.src, m->e.dst); break; case git_node: msg("node %d\n", m->n); break; case git_tool: msg("toolbutton %d\n", m->b); break; case git_text: msg("text (x,y)=(%d,%d)\n", m->p.x, m->p.y); break; case git_elp: msg("edge layout point (%d, %d) #%d\n", m->elp.e.src, m->elp.e.dst, m->elp.pidx); break; } } break; case grcode_dblclicked: // a graph node has been double clicked // in: graph_viewer_t *gv // selection_item_t *current_item // out: 0-ok, 1-ignore click { graph_viewer_t *v = va_arg(va, graph_viewer_t *); selection_item_t *s = va_arg(va, selection_item_t *); msg("%p: %sclicked on ", v, code == grcode_clicked ? "" : "dbl"); if ( s == NULL ) msg("background\n"); else if ( s->is_node ) msg("node %d\n", s->node); else msg("edge (%d, %d) layout point #%d\n", s->elp.e.src, s->elp.e.dst, s->elp.pidx); } break; case grcode_creating_group: // a group is being created // in: mutable_graph_t *g // intset_t *nodes // out: 0-ok, 1-forbid group creation { mutable_graph_t *g = va_arg(va, mutable_graph_t *); intset_t &nodes = *va_arg(va, intset_t *); msg("%p: creating group", g); for ( intset_t::iterator p=nodes.begin(); p != nodes.end(); ++p ) msg(" %d", *p); msg("...\n"); } break; case grcode_deleting_group: // a group is being deleted // in: mutable_graph_t *g // int old_group // out: 0-ok, 1-forbid group deletion { mutable_graph_t *g = va_arg(va, mutable_graph_t *); int group = va_argi(va, int); msg("%p: deleting group %d\n", g, group); } break; case grcode_group_visibility: // a group is being collapsed/uncollapsed // in: mutable_graph_t *g // int group // bool expand // out: 0-ok, 1-forbid group modification { mutable_graph_t *g = va_arg(va, mutable_graph_t *); int group = va_argi(va, int); bool expand = va_argi(va, bool); msg("%p: %scollapsing group %d\n", g, expand ? "un" : "", group); } break; case grcode_gotfocus: // a graph viewer got focus // in: graph_viewer_t *gv // out: must return 0 { graph_viewer_t *g = va_arg(va, graph_viewer_t *); msg("%p: got focus\n", g); } break; case grcode_lostfocus: // a graph viewer lost focus // in: graph_viewer_t *gv // out: must return 0 { graph_viewer_t *g = va_arg(va, graph_viewer_t *); msg("%p: lost focus\n", g); } break; case grcode_user_refresh: // refresh user-defined graph nodes and edges // in: mutable_graph_t *g // out: success { mutable_graph_t *g = va_arg(va, mutable_graph_t *); msg("%p: refresh\n", g); // our graph is like this: // 0 -> 1 -> 2 // \-> 3 -> 4 -> 5 -> 6 // ^ / // \-------/ if ( g->empty() ) g->resize(7); g->add_edge(0, 1, NULL); g->add_edge(1, 2, NULL); g->add_edge(1, 3, NULL); g->add_edge(3, 4, NULL); g->add_edge(4, 5, NULL); g->add_edge(5, 3, NULL); g->add_edge(5, 6, NULL); result = true; } break; case grcode_user_gentext: // generate text for user-defined graph nodes // in: mutable_graph_t *g // out: must return 0 { mutable_graph_t *g = va_arg(va, mutable_graph_t *); msg("%p: generate text for graph nodes\n", g); graph_text.resize(g->size()); for ( node_iterator p=g->begin(); p != g->end(); ++p ) { int n = *p; graph_text[n] = get_node_name(n); } result = true; } break; case grcode_user_text: // retrieve text for user-defined graph node // in: mutable_graph_t *g // int node // const char **result // bgcolor_t *bg_color (maybe NULL) // out: must return 0, result must be filled // NB: do not use anything calling GDI! { mutable_graph_t *g = va_arg(va, mutable_graph_t *); int node = va_arg(va, int); const char **text = va_arg(va, const char **); bgcolor_t *bgcolor = va_arg(va, bgcolor_t *); *text = graph_text[node].c_str(); if ( bgcolor != NULL ) *bgcolor = DEFCOLOR; result = true; qnotused(g); } break; case grcode_user_size: // calculate node size for user-defined graph // in: mutable_graph_t *g // int node // int *cx // int *cy // out: 0-did not calculate, ida will use node text size // 1-calculated. ida will add node title to the size msg("calc node size - not implemented\n"); // ida will calculate the node size based on the node text break; case grcode_user_title: // render node title of a user-defined graph // in: mutable_graph_t *g // int node // rect_t *title_rect // int title_bg_color // HDC dc // out: 0-did not render, ida will fill it with title_bg_color // 1-rendered node title // ida will draw the node title itself break; case grcode_user_draw: // render node of a user-defined graph // in: mutable_graph_t *g // int node // rect_t *node_rect // HDC dc // out: 0-not rendered, 1-rendered // NB: draw only on the specified DC and nowhere else! // ida will draw the node text itself break; case grcode_user_hint: // retrieve hint for the user-defined graph // in: mutable_graph_t *g // int mousenode // int mouseedge_src // int mouseedge_dst // char **hint // 'hint' must be allocated by qalloc() or qstrdup() // out: 0-use default hint, 1-use proposed hint { mutable_graph_t *g = va_arg(va, mutable_graph_t *); int mousenode = va_argi(va, int); int mouseedge_src = va_argi(va, int); int mouseedge_dst = va_argi(va, int); char **hint = va_arg(va, char **); char buf[MAXSTR]; buf[0] = '\0'; if ( mousenode != -1 ) qsnprintf(buf, sizeof(buf), "My fancy hint for node %d", mousenode); else if ( mouseedge_src != -1 ) qsnprintf(buf, sizeof(buf), "Hovering on (%d,%d)", mouseedge_src, mouseedge_dst); if ( buf[0] != '\0' ) *hint = qstrdup(buf); result = true; // use our hint qnotused(g); } break; } return result; }
//--------------------------------------------------------------------------- bool PyW_PyListToStrVec(PyObject *py_list, qstrvec_t &strvec) { strvec.clear(); return pyvar_walk_list(py_list, pylist_to_strvec_cb, &strvec) != CIP_FAILED; }