├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── src ├── IDAStringList.cpp ├── IDAStringList.hpp ├── Plugin.cpp ├── Plugin.hpp └── PluginInterface.cpp ├── x64 └── CMakeLists.txt └── x86 └── CMakeLists.txt /.gitignore: -------------------------------------------------------------------------------- 1 | bin/* 2 | build/* 3 | *.vcxproj 4 | *.filters 5 | *.sln 6 | *.suo 7 | *.sdf -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | 3 | add_subdirectory(x86) 4 | add_subdirectory(x64) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 praydog 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IDA-String-Reference-Locator 2 | Finds all first occurring string references near another reference 3 | -------------------------------------------------------------------------------- /src/IDAStringList.cpp: -------------------------------------------------------------------------------- 1 | #include "IDAStringList.hpp" 2 | 3 | #include 4 | #include 5 | 6 | IDAStringList::IDAStringList() 7 | : m_lastKnownQuantity(0) 8 | { 9 | 10 | } 11 | 12 | void IDAStringList::Populate() 13 | { 14 | auto currentQuantity = get_strlist_qty(); 15 | 16 | if (!m_stringList.size() || m_lastKnownQuantity != currentQuantity) 17 | { 18 | Refresh(); 19 | currentQuantity = get_strlist_qty(); 20 | } 21 | 22 | m_lastKnownQuantity = currentQuantity; 23 | m_stringList.clear(); 24 | 25 | for (size_t i = 0; i < currentQuantity; i++) 26 | { 27 | std::shared_ptr si = std::make_shared(); 28 | get_strlist_item(si.get(), i); 29 | 30 | m_stringList[si->ea] = si; 31 | } 32 | } 33 | 34 | void IDAStringList::Refresh() 35 | { 36 | //refresh_strlist(inf.minEA, inf.maxEA); 37 | get_strlist_options()->display_only_existing_strings = 0; 38 | build_strlist(); 39 | } 40 | 41 | IDAString::IDAString() 42 | { 43 | type = -1; 44 | ea = 0; 45 | length = 0; 46 | } 47 | 48 | std::string IDAString::Read() const 49 | { 50 | if (type == 0) 51 | return ReadA(); 52 | else 53 | { 54 | auto wrap = ReadW(); 55 | return std::string(wrap.begin(), wrap.end()); 56 | } 57 | } 58 | 59 | std::string IDAString::ReadA() const 60 | { 61 | std::unique_ptr buf(new unsigned char[length]); 62 | get_bytes(buf.get(), length, ea); 63 | 64 | 65 | for (int i = 0; i < length; ++i) 66 | { 67 | if (buf.get()[i] == '\0') 68 | break; 69 | 70 | if (buf.get()[i] > 127) 71 | { 72 | auto wrap = ReadW(); 73 | return std::string(wrap.begin(), wrap.end()); 74 | } 75 | } 76 | 77 | return std::string((char*)buf.get(), length); 78 | } 79 | 80 | std::wstring IDAString::ReadW() const 81 | { 82 | std::unique_ptr buf(new wchar_t[length]); 83 | get_bytes(buf.get(), length, ea); 84 | 85 | return std::wstring(buf.get(), length); 86 | } 87 | -------------------------------------------------------------------------------- /src/IDAStringList.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | class IDAString : public string_info_t 11 | { 12 | public: 13 | IDAString(); 14 | 15 | std::string Read() const; 16 | std::string ReadA() const; 17 | std::wstring ReadW() const; 18 | }; 19 | 20 | // Purpose: faster than looping through the entire string list every time we want to check something. 21 | class IDAStringList 22 | { 23 | public: 24 | IDAStringList(); 25 | 26 | void Populate(); 27 | void Refresh(); 28 | 29 | auto operator[](ea_t key) { 30 | return m_stringList[key]; 31 | } 32 | 33 | private: 34 | std::map> m_stringList; 35 | unsigned int m_lastKnownQuantity; 36 | }; -------------------------------------------------------------------------------- /src/Plugin.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "Plugin.hpp" 11 | 12 | #include "IDAStringList.hpp" 13 | 14 | Plugin plugin; 15 | 16 | Plugin::Plugin() 17 | { 18 | 19 | } 20 | 21 | void Plugin::OnRun(size_t arg) 22 | { 23 | if (arg == -1) 24 | PLUGIN.flags |= PLUGIN_UNL; 25 | 26 | msg("Stringref plugin ran.\n"); 27 | 28 | std::vector references; 29 | FillReferences(references); 30 | SortAndPrint(references); 31 | 32 | msg("Stringref plugin finished. Double click any of the addresses to go to them.\n"); 33 | } 34 | 35 | int Plugin::OnInit() 36 | { 37 | return PLUGIN_KEEP; 38 | } 39 | 40 | void Plugin::OnTerminate() 41 | { 42 | 43 | } 44 | 45 | void Plugin::FillReferences(std::vector& references) 46 | { 47 | m_stringList.Populate(); 48 | 49 | xrefblk_t xref; 50 | 51 | for (bool refFound = xref.first_to(get_screen_ea(), XREF_ALL); refFound; refFound = xref.next_to()) 52 | OnXRef(&xref, references); 53 | } 54 | 55 | void Plugin::OnXRef(xrefblk_t* xref, std::vector& references) 56 | { 57 | auto xrefFlags = get_flags(xref->from); 58 | 59 | if (!is_code(xrefFlags)) 60 | return; 61 | 62 | auto functionArea = get_func(xref->from); 63 | 64 | if (!functionArea) 65 | return; 66 | 67 | insn_t cmd; 68 | 69 | for (auto instruction = functionArea->start_ea; instruction < functionArea->end_ea; instruction += cmd.size) 70 | { 71 | // bail out (maybe some obfuscation will break this?) 72 | if (!decode_insn(&cmd, instruction)) 73 | break; 74 | 75 | for (const auto& op : cmd.ops) 76 | { 77 | ea_t opcodeRef; 78 | 79 | // check op.addr if it's valid, and then op.value as the fallback 80 | for (opcodeRef = op.addr; opcodeRef != op.value; opcodeRef = op.value) 81 | { 82 | if (opcodeRef && is_data(get_flags(opcodeRef))) 83 | break; 84 | 85 | opcodeRef = 0; 86 | } 87 | 88 | if (!opcodeRef) 89 | continue; 90 | 91 | auto strInfo = m_stringList[opcodeRef]; 92 | 93 | if (!strInfo || strInfo->type == -1) 94 | continue; 95 | 96 | xrefblk_t stringXref; 97 | 98 | if (stringXref.first_to(opcodeRef, XREF_ALL) && (stringXref.from >= cmd.ea) && (stringXref.from <= cmd.ea + op.offb)) 99 | { 100 | auto str = strInfo->Read(); 101 | 102 | if (!str.length()) 103 | continue; 104 | 105 | references.emplace_back(str, cmd.ea + op.offb, (int)(xref->from - (cmd.ea + op.offb))); 106 | } 107 | } 108 | } 109 | } 110 | 111 | void Plugin::SortAndPrint(std::vector& references) 112 | { 113 | std::sort(references.begin(), references.end(), [](const RefInfo& a, const RefInfo& b) 114 | { 115 | return std::abs(a.offset) > std::abs(b.offset); 116 | }); 117 | 118 | for (auto& i : references) 119 | { 120 | if (i.offset < 0) 121 | msg("%a - 0x%X %s\n", i.stringRef, std::abs(i.offset), i.str.c_str()); 122 | else 123 | msg("%a + 0x%X %s\n", i.stringRef, i.offset, i.str.c_str()); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/Plugin.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "IDAStringList.hpp" 7 | 8 | struct RefInfo 9 | { 10 | RefInfo(const std::string& a, ea_t b, int c) 11 | : str(a), 12 | stringRef(b), 13 | offset(c) 14 | { 15 | 16 | } 17 | 18 | std::string str; 19 | ea_t stringRef; 20 | int offset; 21 | }; 22 | 23 | class Plugin 24 | { 25 | public: 26 | Plugin(); 27 | 28 | // IDA required functions 29 | void OnRun(size_t arg); 30 | 31 | int OnInit(); 32 | void OnTerminate(); 33 | 34 | private: 35 | void FillReferences(std::vector& references); 36 | void OnXRef(struct xrefblk_t* xref, std::vector& references); 37 | void SortAndPrint(std::vector& references); 38 | 39 | public: 40 | static constexpr uint32 flags = 0; 41 | static constexpr char* comment = "Finds string references near a reference."; 42 | static constexpr char* name = "String Reference Locator"; 43 | static constexpr char* help = "Finds string references near a reference."; 44 | static constexpr char* hotkey = "Ctrl+Alt+Q"; 45 | 46 | private: 47 | IDAStringList m_stringList; 48 | 49 | }; 50 | 51 | extern Plugin plugin; -------------------------------------------------------------------------------- /src/PluginInterface.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "Plugin.hpp" 5 | 6 | // Interface to IDA. 7 | plugin_t PLUGIN 8 | { 9 | IDP_INTERFACE_VERSION, 10 | 11 | plugin.flags, 12 | 13 | // lambdas let us use class objects to do this instead of C-style standalone/static functions. 14 | []() { return plugin.OnInit(); }, 15 | []() { return plugin.OnTerminate(); }, 16 | [](size_t arg) { plugin.OnRun(arg); return true; }, 17 | 18 | plugin.comment, 19 | plugin.help, 20 | plugin.name, 21 | plugin.hotkey 22 | }; -------------------------------------------------------------------------------- /x64/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | 3 | set(PROJECT_NAME64 IDA_StringRef_Locator64) 4 | set(CMAKE_CONFIGURATION_TYPES Release) 5 | 6 | project(${PROJECT_NAME64} CXX) 7 | 8 | set(LIBRARY_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/bin) 9 | 10 | file(GLOB_RECURSE SOURCES "../src/*.cpp") 11 | file(GLOB_RECURSE HEADERS "../src/*.hpp") 12 | 13 | LINK_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/bin) 14 | 15 | include_directories("../src") 16 | 17 | add_definitions(-D__EA64__ -D__IDP__ -D__X64__) 18 | add_library(${PROJECT_NAME64} SHARED ${HEADERS} ${SOURCES}) 19 | 20 | if (WIN32) 21 | add_definitions(-D__NT__) 22 | target_link_libraries(${PROJECT_NAME64} x86_win_vc_64/ida) 23 | elseif (UNIX AND NOT APPLE) 24 | add_definitions(-D__LINUX__) 25 | elseif (APPLE) 26 | add_definitions(-D__MAC__) 27 | ENDIF() 28 | 29 | set_target_properties(${PROJECT_NAME64} PROPERTIES SUFFIX ".p64") 30 | target_link_options(${PROJECT_NAME64} PUBLIC /EXPORT:PLUGIN) -------------------------------------------------------------------------------- /x86/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | 3 | set(PROJECT_NAME IDA_StringRef_Locator) 4 | set(CMAKE_CONFIGURATION_TYPES Release) 5 | 6 | project(${PROJECT_NAME} CXX) 7 | 8 | set(LIBRARY_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/bin) 9 | 10 | file(GLOB_RECURSE SOURCES "../src/*.cpp") 11 | file(GLOB_RECURSE HEADERS "../src/*.hpp") 12 | 13 | include_directories("../src") 14 | 15 | add_definitions(-D__IDP__) 16 | add_library(${PROJECT_NAME} SHARED ${HEADERS} ${SOURCES}) 17 | 18 | if (WIN32) 19 | add_definitions(-D__NT__) 20 | target_link_libraries(${PROJECT_NAME} x86_win_vc_32/ida) 21 | elseif (UNIX AND NOT APPLE) 22 | add_definitions(-D__LINUX__) 23 | elseif (APPLE) 24 | add_definitions(-D__MAC__) 25 | ENDIF() 26 | 27 | set_target_properties(${PROJECT_NAME} PROPERTIES SUFFIX ".plw") --------------------------------------------------------------------------------