Added basic python-based load scripts
This commit is contained in:
parent
16f885f469
commit
c6134bc038
@ -11,10 +11,11 @@ pkg_search_module(CAPSTONE REQUIRED capstone)
|
||||
find_package(OpenGL REQUIRED)
|
||||
find_package(LLVM REQUIRED CONFIG)
|
||||
find_package(nlohmann_json REQUIRED)
|
||||
find_package(Python COMPONENTS Interpreter Development)
|
||||
|
||||
llvm_map_components_to_libnames(demangler)
|
||||
|
||||
include_directories(include ${GLFW_INCLUDE_DIRS} ${CAPSTONE_INCLUDE_DIRS} ${LLVM_INCLUDE_DIRS} libs/ImGui/include libs/glad/include)
|
||||
include_directories(include ${GLFW_INCLUDE_DIRS} ${CAPSTONE_INCLUDE_DIRS} ${LLVM_INCLUDE_DIRS} libs/ImGui/include libs/glad/include ${Python_INCLUDE_DIRS})
|
||||
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -DIMGUI_IMPL_OPENGL_LOADER_GLAD")
|
||||
|
||||
@ -34,6 +35,7 @@ add_executable(ImHex
|
||||
source/helpers/patches.cpp
|
||||
source/helpers/math_evaluator.cpp
|
||||
source/helpers/project_file_handler.cpp
|
||||
source/helpers/loader_script_handler.cpp
|
||||
|
||||
source/lang/preprocessor.cpp
|
||||
source/lang/lexer.cpp
|
||||
@ -71,9 +73,9 @@ add_executable(ImHex
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(ImHex libglfw3.a libgcc.a libstdc++.a libmagic.a libgnurx.a libtre.a libintl.a libiconv.a shlwapi.lib libcrypto.a libwinpthread.a libcapstone.a libLLVMDemangle.a nlohmann_json::nlohmann_json)
|
||||
target_link_libraries(ImHex libglfw3.a libgcc.a libstdc++.a libmagic.a libgnurx.a libtre.a libintl.a libiconv.a shlwapi.lib libcrypto.a libwinpthread.a libcapstone.a libLLVMDemangle.a ${Python_LIBRARIES} nlohmann_json::nlohmann_json)
|
||||
endif (WIN32)
|
||||
|
||||
if (UNIX)
|
||||
target_link_libraries(ImHex libglfw.so libmagic.so libcrypto.so libdl.so libcapstone.so libLLVMDemangle.so nlohmann_json::nlohmann_json)
|
||||
target_link_libraries(ImHex libglfw.so libmagic.so libcrypto.so libdl.so libcapstone.so libLLVMDemangle.so ${Python_LIBRARIES} nlohmann_json::nlohmann_json)
|
||||
endif (UNIX)
|
30
include/helpers/loader_script_handler.hpp
Normal file
30
include/helpers/loader_script_handler.hpp
Normal file
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
struct _object;
|
||||
typedef struct _object PyObject;
|
||||
|
||||
namespace hex {
|
||||
|
||||
namespace prv { class Provider; }
|
||||
|
||||
class LoaderScript {
|
||||
public:
|
||||
LoaderScript() = delete;
|
||||
|
||||
static bool processFile(std::string_view scriptPath);
|
||||
|
||||
static void setFilePath(std::string_view filePath) { LoaderScript::s_filePath = filePath; }
|
||||
static void setDataProvider(prv::Provider* provider) { LoaderScript::s_dataProvider = provider; }
|
||||
private:
|
||||
static inline std::string s_filePath;
|
||||
static inline prv::Provider* s_dataProvider;
|
||||
|
||||
static PyObject* Py_getFilePath(PyObject *self, PyObject *args);
|
||||
static PyObject* Py_addPatch(PyObject *self, PyObject *args);
|
||||
static PyObject* Py_addBookmark(PyObject *self, PyObject *args);
|
||||
};
|
||||
|
||||
}
|
@ -47,6 +47,9 @@ namespace hex {
|
||||
|
||||
std::vector<u8> m_dataToSave;
|
||||
|
||||
std::string m_loaderScriptScriptPath;
|
||||
std::string m_loaderScriptFilePath;
|
||||
|
||||
void drawSearchPopup();
|
||||
void drawGotoPopup();
|
||||
|
||||
|
99
source/helpers/loader_script_handler.cpp
Normal file
99
source/helpers/loader_script_handler.cpp
Normal file
@ -0,0 +1,99 @@
|
||||
#include "helpers/loader_script_handler.hpp"
|
||||
|
||||
#include "views/view.hpp"
|
||||
#include "helpers/utils.hpp"
|
||||
#include "providers/provider.hpp"
|
||||
|
||||
#define PY_SSIZE_T_CLEAN
|
||||
#include <Python.h>
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
|
||||
namespace hex {
|
||||
|
||||
PyObject* LoaderScript::Py_getFilePath(PyObject *self, PyObject *args) {
|
||||
return PyUnicode_FromString(LoaderScript::s_filePath.c_str());
|
||||
}
|
||||
|
||||
PyObject* LoaderScript::Py_addPatch(PyObject *self, PyObject *args) {
|
||||
u64 address;
|
||||
u8 *patches;
|
||||
Py_ssize_t count;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "K|y#", &address, &patches, &count)) {
|
||||
PyErr_BadArgument();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (patches == nullptr || count == 0) {
|
||||
PyErr_SetString(PyExc_TypeError, "Invalid patch provided");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (address >= LoaderScript::s_dataProvider->getActualSize()) {
|
||||
PyErr_SetString(PyExc_IndexError, "address out of range");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LoaderScript::s_dataProvider->write(address, patches, count);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyObject* LoaderScript::Py_addBookmark(PyObject *self, PyObject *args) {
|
||||
Bookmark bookmark;
|
||||
|
||||
char *name = nullptr;
|
||||
char *comment = nullptr;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "K|n|s|s", &bookmark.region.address, &bookmark.region.size, &name, &comment)) {
|
||||
PyErr_BadArgument();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (name == nullptr || comment == nullptr) {
|
||||
PyErr_SetString(PyExc_IndexError, "address out of range");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::copy(name, name + std::strlen(name), std::back_inserter(bookmark.name));
|
||||
std::copy(comment, comment + std::strlen(comment), std::back_inserter(bookmark.comment));
|
||||
|
||||
View::postEvent(Events::AddBookmark, &bookmark);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
bool LoaderScript::processFile(std::string_view scriptPath) {
|
||||
Py_SetProgramName(Py_DecodeLocale(__argv[0], nullptr));
|
||||
|
||||
Py_SetPythonHome(Py_DecodeLocale(std::filesystem::path(__argv[0]).parent_path().string().c_str(), nullptr));
|
||||
|
||||
PyImport_AppendInittab("imhex", []() -> PyObject* {
|
||||
static PyMethodDef ImHexMethods[] = {
|
||||
{ "get_file_path", &LoaderScript::Py_getFilePath, METH_NOARGS, "Returns the path of the file being loaded." },
|
||||
{ "patch", &LoaderScript::Py_addPatch, METH_VARARGS, "Patches a region of memory" },
|
||||
{ "add_bookmark", &LoaderScript::Py_addBookmark, METH_VARARGS, "Adds a bookmark" },
|
||||
{ nullptr, nullptr, 0, nullptr }
|
||||
};
|
||||
|
||||
static PyModuleDef ImHexModule = {
|
||||
PyModuleDef_HEAD_INIT, "imhex", nullptr, -1, ImHexMethods, nullptr, nullptr, nullptr, nullptr
|
||||
};
|
||||
|
||||
return PyModule_Create(&ImHexModule);
|
||||
});
|
||||
|
||||
Py_Initialize();
|
||||
|
||||
FILE *scriptFile = fopen(scriptPath.data(), "r");
|
||||
PyRun_SimpleFile(scriptFile, scriptPath.data());
|
||||
|
||||
fclose(scriptFile);
|
||||
|
||||
Py_Finalize();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -9,15 +9,17 @@ namespace hex {
|
||||
|
||||
ViewBookmarks::ViewBookmarks(prv::Provider* &dataProvider) : View("Bookmarks"), m_dataProvider(dataProvider) {
|
||||
View::subscribeEvent(Events::AddBookmark, [this](const void *userData) {
|
||||
Bookmark bookmark;
|
||||
bookmark.region = *reinterpret_cast<const Region*>(userData);
|
||||
Bookmark bookmark = *reinterpret_cast<const Bookmark*>(userData);
|
||||
bookmark.name.resize(64);
|
||||
bookmark.comment.resize(0xF'FFFF);
|
||||
|
||||
std::memset(bookmark.name.data(), 0x00, 64);
|
||||
std::memset(bookmark.comment.data(), 0x00, 0xF'FFFF);
|
||||
if (bookmark.name.empty()) {
|
||||
std::memset(bookmark.name.data(), 0x00, 64);
|
||||
std::strcpy(bookmark.name.data(), ("Bookmark " + std::to_string(this->m_bookmarks.size() + 1)).c_str());
|
||||
}
|
||||
|
||||
std::strcpy(bookmark.name.data(), ("Bookmark " + std::to_string(this->m_bookmarks.size() + 1)).c_str());
|
||||
if (bookmark.comment.empty())
|
||||
std::memset(bookmark.comment.data(), 0x00, 0xF'FFFF);
|
||||
|
||||
this->m_bookmarks.push_back(bookmark);
|
||||
ProjectFile::markDirty();
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "helpers/crypto.hpp"
|
||||
#include "helpers/patches.hpp"
|
||||
#include "helpers/project_file_handler.hpp"
|
||||
#include "helpers/loader_script_handler.hpp"
|
||||
|
||||
#undef __STRICT_ANSI__
|
||||
#include <cstdio>
|
||||
@ -151,6 +152,53 @@ namespace hex {
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
if (ImGui::BeginPopupModal("Load File with Loader Script", nullptr, ImGuiWindowFlags_NoResize)) {
|
||||
constexpr auto Message = "Load a file using a Python loader script.";
|
||||
ImGui::NewLine();
|
||||
if (ImGui::BeginChild("##scrolling", ImVec2(500, 20))) {
|
||||
ImGui::SetCursorPosX(10);
|
||||
ImGui::TextWrapped("%s", Message);
|
||||
ImGui::EndChild();
|
||||
}
|
||||
|
||||
ImGui::NewLine();
|
||||
ImGui::InputText("##nolabel", this->m_loaderScriptScriptPath.data(), this->m_loaderScriptScriptPath.length(), ImGuiInputTextFlags_ReadOnly);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Script"))
|
||||
ImGui::OpenPopup("Loader Script: Open Script");
|
||||
ImGui::InputText("##nolabel", this->m_loaderScriptFilePath.data(), this->m_loaderScriptFilePath.length(), ImGuiInputTextFlags_ReadOnly);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("File"))
|
||||
ImGui::OpenPopup("Loader Script: Open File");
|
||||
|
||||
|
||||
if (this->m_fileBrowser.showFileDialog("Loader Script: Open Script", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, ImVec2(0, 0), ".py")) {
|
||||
this->m_loaderScriptScriptPath = this->m_fileBrowser.selected_path;
|
||||
}
|
||||
if (this->m_fileBrowser.showFileDialog("Loader Script: Open File", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN)) {
|
||||
this->m_loaderScriptFilePath = this->m_fileBrowser.selected_path;
|
||||
}
|
||||
|
||||
ImGui::NewLine();
|
||||
|
||||
ImGui::SetCursorPosX(40);
|
||||
if (ImGui::Button("Load", ImVec2(100, 20))) {
|
||||
if (!this->m_loaderScriptScriptPath.empty() && !this->m_loaderScriptFilePath.empty()) {
|
||||
this->openFile(this->m_loaderScriptFilePath);
|
||||
LoaderScript::setFilePath(this->m_loaderScriptFilePath);
|
||||
LoaderScript::setDataProvider(this->m_dataProvider);
|
||||
LoaderScript::processFile(this->m_loaderScriptScriptPath);
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::SetCursorPosX(160);
|
||||
if (ImGui::Button("Cancel", ImVec2(100, 20))) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
|
||||
if (this->m_fileBrowser.showFileDialog("Open File", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN)) {
|
||||
this->openFile(this->m_fileBrowser.selected_path);
|
||||
@ -279,6 +327,13 @@ namespace hex {
|
||||
View::doLater([]{ ImGui::OpenPopup("Apply IPS32 Patch"); });
|
||||
}
|
||||
|
||||
if (ImGui::MenuItem("File with Loader Script")) {
|
||||
this->getWindowOpenState() = true;
|
||||
this->m_loaderScriptFilePath.clear();
|
||||
this->m_loaderScriptScriptPath.clear();
|
||||
View::doLater([]{ ImGui::OpenPopup("Load File with Loader Script"); });
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
@ -363,9 +418,9 @@ namespace hex {
|
||||
if (ImGui::MenuItem("Create bookmark", nullptr, false, this->m_memoryEditor.DataPreviewAddr != -1 && this->m_memoryEditor.DataPreviewAddrEnd != -1)) {
|
||||
size_t start = std::min(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd);
|
||||
size_t end = std::max(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd);
|
||||
Region selectionRegion = { start, end - start + 1 };
|
||||
Bookmark bookmark = { start, end - start + 1, { }, { } };
|
||||
|
||||
View::postEvent(Events::AddBookmark, &selectionRegion);
|
||||
View::postEvent(Events::AddBookmark, &bookmark);
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
|
Loading…
Reference in New Issue
Block a user