Skip to content

Commit

Permalink
- some code cleanup before redesign
Browse files Browse the repository at this point in the history
It seems that IDA 8.x broke this plugin and climacros no longer can receive CLI installations before Python.
I will have to use the direct hook / pointer manipulation approach if it work73
  • Loading branch information
0xeb committed May 15, 2023
1 parent dea4dc2 commit b7672af
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 121 deletions.
9 changes: 6 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ cmake_minimum_required(VERSION 3.2 FATAL_ERROR)

project(climacros)

include($ENV{IDASDK}/ida-cmake/common.cmake)

# Included file
list(APPEND DISABLED_SOURCES utils_impl.cpp)

set(PLUGIN_NAME climacros)
set(PLUGIN_SOURCES climacros.cpp ${DISABLED_SOURCES})
set(PLUGIN_SOURCES climacros.cpp macros.hpp idasdk.h ${DISABLED_SOURCES})
set(PLUGIN_RUN_ARGS "-t") # Debug messages for the debugger
set(PLUGIN_OUTPUT_NAME "00${PROJECT_NAME}")

include($ENV{IDASDK}/ida-cmake/plugins.cmake)
set_source_files_properties(${DISABLED_SOURCES} PROPERTIES LANGUAGE "")

set_source_files_properties(${DISABLED_SOURCES} PROPERTIES LANGUAGE "")
generate()
179 changes: 63 additions & 116 deletions climacros.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,76 +16,15 @@ All expressions should resolve to a string (i.e. have a __str__ magic method).
#include <regex>
#include <functional>

#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4267 4244)
#endif
#include <ida.hpp>
#include <loader.hpp>
#include <kernwin.hpp>
#include <expr.hpp>
#include <registry.hpp>
#include <diskio.hpp>
#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "idasdk.h"
#include "utils_impl.cpp"

constexpr char IDAREG_CLI_MACROS[] = "CLI_Macros";
constexpr int MAX_CLI_MACROS = 200;

constexpr char SER_SEPARATOR[] = "\x1";

//-------------------------------------------------------------------------
// Macro definition
struct macro_def_t
{
std::string macro;
std::string expr;
std::string desc;

bool operator==(const macro_def_t &rhs) const
{
return macro == rhs.macro;
}

void to_string(std::string &str) const
{
str = macro + SER_SEPARATOR + expr + SER_SEPARATOR + desc;
}
};
typedef qvector<macro_def_t> macros_t;

// Default macros
static macro_def_t DEFAULT_MACROS[] =
{
{"$!", "${'0x%x' % idc.here()}$", "Current cursor location (0x...)"},
{"$!!", "${'%x' % idc.here()}$", "Current cursor location"},
{"$<", "${'0x%x' % idc.get_segm_start(idc.here())}$", "Current segment start (0x...)"},
{"$>", "${'0x%x' % idc.get_segm_end(idc.here())}$", "Current segment end (0x...)"},
{"$<<", "${'%x' % idc.get_segm_start(idc.here())}$", "Current segment start"},
{"$>>", "${'%x' % idc.get_segm_end(idc.here())}$", "Current segment end"},
{"$@b", "${'0x%x' % idc.get_wide_byte(idc.here())}$", "Byte value at current cursor location (0x...)" },
{"$@B", "${'%x' % idc.get_wide_byte(idc.here())}$", "Byte value at current cursor location"},
{"$@d", "${'0x%x' % idc.get_wide_dword(idc.here())}$", "Dword value at current cursor location (0x...)"},
{"$@D", "${'%x' % idc.get_wide_dword(idc.here())}$", "Dword value at current cursor location"},
{"$@q", "${'0x%x' % idc.get_qword(idc.here())}$", "Qword value at current cursor location (0x...)"},
{"$@Q", "${'%x' % idc.get_qword(idc.here())}$", "Qword value at current cursor location"},
{"$*b", "${'0x%x' % idc.read_dbg_byte(idc.here())}$", "Debugger byte value at current cursor location (0x...)" },
{"$*B", "${'%x' % idc.read_dbg_byte(idc.here())}$", "Debugger byte value at current cursor location"},
{"$*d", "${'0x%x' % idc.read_dbg_dword(idc.here())}$", "Debugger dword value at current cursor location (0x...)"},
{"$*D", "${'%x' % idc.read_dbg_dword(idc.here())}$", "Debugger dword value at current cursor location"},
{"$*q", "${'0x%x' % idc.read_dbg_qword(idc.here())}$", "Debugger qword value at current cursor location (0x...)"},
{"$*Q", "${'%x' % idc.read_dbg_qword(idc.here())}$", "Debugger qword value at current cursor location"},
{"$[", "${'0x%x' % idc.read_selection_start()}$", "Selection start (0x...)"},
{"$]", "${'0x%x' % idc.read_selection_end()}$", "Selection end (0x...)"},
{"$[[", "${'%x' % idc.read_selection_start()}$", "Selection start"},
{"$]]", "${'%x' % idc.read_selection_end()}$", "Selection end"},
{"$#", "${'0x%x' % (idc.read_selection_end() - idc.read_selection_start())}$", "Selection size (0x...)"},
{"$##", "${'%x' % (idc.read_selection_end() - idc.read_selection_start())}$", "Selection size"},
{"$cls", "${idaapi.msg_clear()}$", "Clears the output window"}
};
#include "macros.hpp"

//-------------------------------------------------------------------------
// Macro replace and expand via Python expression evaluation
Expand Down Expand Up @@ -172,36 +111,6 @@ const cli_t *unhook_cli(const cli_t *cli)
return nullptr;
}

//---------------------------------------------------------------------------
// UI callback to help us capture CLI registration
static ssize_t idaapi ui_callback(void *, int notification_code, va_list va)
{
switch (notification_code)
{
case ui_install_cli:
{
// Only capture CLIs requests not originating internally
if (g_b_ignore_ui_notification)
break;

auto cli = va_arg(va, const cli_t *);
auto install = bool(va_arg(va, int));

auto hooked_cli = install ? hook_cli(cli) : unhook_cli(cli);
if (hooked_cli != nullptr)
{
// [Un]install the replacement CLI
request_install_cli(hooked_cli, install);

// Do not accept this CLI [un]registration
return 1;
}
}
}
// Pass-through...
return 0;
}

//-------------------------------------------------------------------------
// Modal macro editor
struct macro_editor_t: public chooser_t
Expand Down Expand Up @@ -414,33 +323,72 @@ inline macro_editor_t::macro_editor_t(const char *title_ = "CLI macros editor")
{
}

macro_editor_t g_macro_editor;

//--------------------------------------------------------------------------
plugmod_t *idaapi init(void)
class climacros_plg_t : public plugmod_t, public event_listener_t
{
if (!is_idaq())
return PLUGIN_SKIP;
macro_editor_t macro_editor;

msg("IDA Command Line Interface macros initialized\n");
public:
climacros_plg_t() : plugmod_t()
{
msg("IDA Command Line Interface macros initialized\n");

hook_to_notification_point(HT_UI, ui_callback);
g_macro_editor.build_macros_list();
macro_editor.build_macros_list();
hook_event_listener(HT_UI, this, HKCB_GLOBAL);
}

bool idaapi run(size_t) override
{
macro_editor.choose();
return true;
}

ssize_t idaapi on_event(ssize_t code, va_list va) override
{
//if (code != ui_msg)
//{
// msg("got event: %d\n", int(code));
// return 0;
//}

return PLUGIN_KEEP;
}
switch (code)
{
case ui_install_cli:
{
// Only capture CLIs requests not originating internally
if (g_b_ignore_ui_notification)
break;

//--------------------------------------------------------------------------
void idaapi term(void)
{
unhook_from_notification_point(HT_UI, ui_callback);
}
auto cli = va_arg(va, const cli_t*);
auto install = bool(va_arg(va, int));

auto hooked_cli = install ? hook_cli(cli) : unhook_cli(cli);
if (hooked_cli != nullptr)
{
// [Un]install the replacement CLI
request_install_cli(hooked_cli, install);

// Do not accept this CLI [un]registration
return 1;
}
}
}
// Pass-through...
return 0;
}

~climacros_plg_t()
{
unhook_event_listener(HT_UI, this);
}
};

//--------------------------------------------------------------------------
bool idaapi run(size_t)
plugmod_t *idaapi init(void)
{
g_macro_editor.choose();
return true;
if (!is_idaq())
return nullptr;

return new climacros_plg_t;
}

#ifdef _DEBUG
Expand Down Expand Up @@ -469,12 +417,11 @@ static const char help[] =
plugin_t PLUGIN =
{
IDP_INTERFACE_VERSION,
PLUGIN_FIX, // plugin flags: load once and stay until IDA exits
PLUGIN_FIX | PLUGIN_MULTI,
init, // initialize
nullptr, // terminate. this pointer may be NULL.

term, // terminate. this pointer may be NULL.

run, // invoke plugin
nullptr, // invoke plugin

comment, // long comment about the plugin
// it could appear in the status line
Expand Down
13 changes: 13 additions & 0 deletions idahdr.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4267 4244 4146)
#endif
#include <ida.hpp>
#include <loader.hpp>
#include <kernwin.hpp>
#include <expr.hpp>
#include <registry.hpp>
#include <diskio.hpp>
#ifdef _MSC_VER
#pragma warning(pop)
#endif
15 changes: 15 additions & 0 deletions idasdk.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once

#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4267 4244 4146)
#endif
#include <ida.hpp>
#include <loader.hpp>
#include <kernwin.hpp>
#include <expr.hpp>
#include <registry.hpp>
#include <diskio.hpp>
#ifdef _MSC_VER
#pragma warning(pop)
#endif
49 changes: 49 additions & 0 deletions macros.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//-------------------------------------------------------------------------
// Macro definition
struct macro_def_t
{
std::string macro;
std::string expr;
std::string desc;

bool operator==(const macro_def_t& rhs) const
{
return macro == rhs.macro;
}

void to_string(std::string& str) const
{
str = macro + SER_SEPARATOR + expr + SER_SEPARATOR + desc;
}
};
typedef qvector<macro_def_t> macros_t;

// Default macros
static macro_def_t DEFAULT_MACROS[] =
{
{"$!", "${'0x%x' % idc.here()}$", "Current cursor location (0x...)"},
{"$!!", "${'%x' % idc.here()}$", "Current cursor location"},
{"$<", "${'0x%x' % idc.get_segm_start(idc.here())}$", "Current segment start (0x...)"},
{"$>", "${'0x%x' % idc.get_segm_end(idc.here())}$", "Current segment end (0x...)"},
{"$<<", "${'%x' % idc.get_segm_start(idc.here())}$", "Current segment start"},
{"$>>", "${'%x' % idc.get_segm_end(idc.here())}$", "Current segment end"},
{"$@b", "${'0x%x' % idc.get_wide_byte(idc.here())}$", "Byte value at current cursor location (0x...)" },
{"$@B", "${'%x' % idc.get_wide_byte(idc.here())}$", "Byte value at current cursor location"},
{"$@d", "${'0x%x' % idc.get_wide_dword(idc.here())}$", "Dword value at current cursor location (0x...)"},
{"$@D", "${'%x' % idc.get_wide_dword(idc.here())}$", "Dword value at current cursor location"},
{"$@q", "${'0x%x' % idc.get_qword(idc.here())}$", "Qword value at current cursor location (0x...)"},
{"$@Q", "${'%x' % idc.get_qword(idc.here())}$", "Qword value at current cursor location"},
{"$*b", "${'0x%x' % idc.read_dbg_byte(idc.here())}$", "Debugger byte value at current cursor location (0x...)" },
{"$*B", "${'%x' % idc.read_dbg_byte(idc.here())}$", "Debugger byte value at current cursor location"},
{"$*d", "${'0x%x' % idc.read_dbg_dword(idc.here())}$", "Debugger dword value at current cursor location (0x...)"},
{"$*D", "${'%x' % idc.read_dbg_dword(idc.here())}$", "Debugger dword value at current cursor location"},
{"$*q", "${'0x%x' % idc.read_dbg_qword(idc.here())}$", "Debugger qword value at current cursor location (0x...)"},
{"$*Q", "${'%x' % idc.read_dbg_qword(idc.here())}$", "Debugger qword value at current cursor location"},
{"$[", "${'0x%x' % idc.read_selection_start()}$", "Selection start (0x...)"},
{"$]", "${'0x%x' % idc.read_selection_end()}$", "Selection end (0x...)"},
{"$[[", "${'%x' % idc.read_selection_start()}$", "Selection start"},
{"$]]", "${'%x' % idc.read_selection_end()}$", "Selection end"},
{"$#", "${'0x%x' % (idc.read_selection_end() - idc.read_selection_start())}$", "Selection size (0x...)"},
{"$##", "${'%x' % (idc.read_selection_end() - idc.read_selection_start())}$", "Selection size"},
{"$cls", "${idaapi.msg_clear()}$", "Clears the output window"}
};
17 changes: 15 additions & 2 deletions prep-cmake.bat
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,33 @@ if not defined IDASDK (
goto :eof
)

if not exist %IDASDK%\include\idax\xkernwin.hpp (
echo IDAX framework not properly installed in the IDA SDK folder.
echo See: https://github.com/0xeb/idax
goto :eof
)

if not exist build (
mkdir build
pushd build
cmake -A x64 -G "Visual Studio 16 2019" ..
cmake -A x64 ..
popd
)

if not exist build64 (
mkdir build64
pushd build64
cmake -A x64 -DEA64=YES -G "Visual Studio 16 2019" ..
cmake -A x64 -DEA64=YES ..
popd
)

if "%1"=="build" (
pushd build
cmake --build . --config Release
popd
pushd build64
cmake --build . --config Release
)
echo.
echo All done!
echo.

0 comments on commit b7672af

Please sign in to comment.