diff --git a/.vscode/launch.json b/.vscode/launch.json index 942fb136f4bcde72df28aea83279a604f7226684..d870f5078aa1e573ecf6fb4feb751b0a9fa173c9 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -48,6 +48,29 @@ ], "preLaunchTask": "ELF Dump Build", "miDebuggerPath": "/usr/bin/gdb" + }, + { + "name": "Run proc_mem", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/build/examples/proc_mem/proc_mem", + "args": [ + "2919", + "/usr/bin/bash" + ], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ], + "miDebuggerPath": "/usr/bin/gdb" } ] } \ No newline at end of file diff --git a/elfio/elfio.hpp b/elfio/elfio.hpp index e84bd7f28c041074cae7da5d41d83d4762690f89..d983ea5d89af4295065e84959ce14e12cf83e1ca 100644 --- a/elfio/elfio.hpp +++ b/elfio/elfio.hpp @@ -124,6 +124,11 @@ class elfio create_mandatory_sections(); } + void set_address_translation( std::vector<address_translation>& addr_trans ) + { + addr_translator.set_address_translation( addr_trans ); + } + //------------------------------------------------------------------------------ bool load( const std::string& file_name ) { @@ -143,6 +148,7 @@ class elfio unsigned char e_ident[EI_NIDENT]; // Read ELF file signature + stream.seekg( addr_translator( 0 ) ); stream.read( reinterpret_cast<char*>( &e_ident ), sizeof( e_ident ) ); // Is it ELF file? @@ -394,12 +400,12 @@ class elfio elf_header* new_header = nullptr; if ( file_class == ELFCLASS64 ) { - new_header = - new elf_header_impl<Elf64_Ehdr>( &convertor, encoding ); + new_header = new elf_header_impl<Elf64_Ehdr>( &convertor, encoding, + &addr_translator ); } else if ( file_class == ELFCLASS32 ) { - new_header = - new elf_header_impl<Elf32_Ehdr>( &convertor, encoding ); + new_header = new elf_header_impl<Elf32_Ehdr>( &convertor, encoding, + &addr_translator ); } else { return nullptr; @@ -1023,6 +1029,7 @@ class elfio std::vector<section*> sections_; std::vector<segment*> segments_; endianess_convertor convertor; + address_translator addr_translator; Elf_Xword current_file_pos; }; diff --git a/elfio/elfio_header.hpp b/elfio/elfio_header.hpp index 058b5ec5637fbb2106e43a211e9664ca63b166a7..fabca5a8cbfe00698760b965145ccd6fddd1c25c 100644 --- a/elfio/elfio_header.hpp +++ b/elfio/elfio_header.hpp @@ -75,9 +75,12 @@ template <class T> class elf_header_impl : public elf_header { public: //------------------------------------------------------------------------------ - elf_header_impl( endianess_convertor* convertor, unsigned char encoding ) + elf_header_impl( endianess_convertor* convertor, + unsigned char encoding, + const address_translator* translator ) { - this->convertor = convertor; + this->convertor = convertor; + this->translator = translator; std::fill_n( reinterpret_cast<char*>( &header ), sizeof( header ), '\0' ); @@ -104,7 +107,7 @@ template <class T> class elf_header_impl : public elf_header //------------------------------------------------------------------------------ bool load( std::istream& stream ) override { - stream.seekg( 0 ); + stream.seekg( ( *translator )( 0 ) ); stream.read( reinterpret_cast<char*>( &header ), sizeof( header ) ); return ( stream.gcount() == sizeof( header ) ); @@ -113,7 +116,7 @@ template <class T> class elf_header_impl : public elf_header //------------------------------------------------------------------------------ bool save( std::ostream& stream ) const override { - stream.seekp( 0 ); + stream.seekp( ( *translator )( 0 ) ); stream.write( reinterpret_cast<const char*>( &header ), sizeof( header ) ); @@ -145,8 +148,9 @@ template <class T> class elf_header_impl : public elf_header ELFIO_GET_SET_ACCESS( Elf64_Off, segments_offset, header.e_phoff ); private: - T header; - endianess_convertor* convertor; + T header; + endianess_convertor* convertor; + const address_translator* translator; }; } // namespace ELFIO diff --git a/elfio/elfio_utils.hpp b/elfio/elfio_utils.hpp index 4b168546e31c01d6b88b2a804b1ddf342df9ae6e..bb7885873a1110050af66e7d4a6bca2d56686cb7 100644 --- a/elfio/elfio_utils.hpp +++ b/elfio/elfio_utils.hpp @@ -160,6 +160,48 @@ class endianess_convertor bool need_conversion; }; +//------------------------------------------------------------------------------ +struct address_translation +{ + address_translation( uint64_t start, uint64_t end, uint64_t map_to ) + : start( start ), end( end ), map_to( map_to ){}; + std::streampos start; + std::streampos end; + std::streampos map_to; +}; + +//------------------------------------------------------------------------------ +class address_translator +{ + public: + //------------------------------------------------------------------------------ + void set_address_translation( std::vector<address_translation>& addr_trans ) + { + translation = addr_trans; + } + + //------------------------------------------------------------------------------ + std::streampos operator()( std::streampos value ) const + { + if ( translation.empty() ) { + return value; + } + + for ( auto& t : translation ) { + if ( t.map_to <= value && + ( ( value - t.map_to ) < ( t.end - t.start ) ) ) { + std::cout << std::hex << t.start - t.map_to + value << std::endl; + return t.start - t.map_to + value; + } + } + + return value; + } + + private: + std::vector<address_translation> translation; +}; + //------------------------------------------------------------------------------ inline uint32_t elf_hash( const unsigned char* name ) { diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index ea12382864cfa7a67a8f45b72f025f1717544831..7433be39234967c87094c2939072705b0e4897ef 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,6 +1,7 @@ add_subdirectory(add_section) add_subdirectory(anonymizer) add_subdirectory(elfdump) +add_subdirectory(proc_mem) add_subdirectory(tutorial) add_subdirectory(write_obj) add_subdirectory(writer) diff --git a/examples/proc_mem/CMakeLists.txt b/examples/proc_mem/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..3f8c1432a4b89817ac768e83f4ca7fec5e048185 --- /dev/null +++ b/examples/proc_mem/CMakeLists.txt @@ -0,0 +1,3 @@ + +add_executable(proc_mem proc_mem.cpp) +target_link_libraries(proc_mem PRIVATE elfio::elfio) diff --git a/examples/proc_mem/proc_mem.cpp b/examples/proc_mem/proc_mem.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3f35122cdeddf4396e5caf75af9b1a85d7edffab --- /dev/null +++ b/examples/proc_mem/proc_mem.cpp @@ -0,0 +1,101 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include <iostream> +#include <fstream> +#include <sstream> +#include <regex> + +#include <elfio/elfio.hpp> +#include <elfio/elfio_dump.hpp> + +using namespace ELFIO; + +void get_translation_ranges( std::ifstream& proc_maps, + const std::string& file_name, + std::vector<address_translation>& result ) +{ + result.clear(); + + const std::regex rexpr( + "([0-9A-Fa-f]+)-([0-9A-Fa-f]+) ([-r]...) ([0-9A-Fa-f]+) (.....) " + "([0-9]+)([[:blank:]]*)([[:graph:]]*)" ); + std::smatch match; + while ( proc_maps ) { + std::string line; + std::getline( proc_maps, line ); + + if ( std::regex_match( line, match, rexpr ) ) { + if ( match.size() == 9 && match[8].str() == file_name ) { + result.emplace_back( address_translation( + std::stoul( match[1].str(), 0, 16 ), + std::stoul( match[2].str(), 0, 16 ), + std::stoul( match[4].str(), 0, 16 ) ) ); + } + } + } + + std::sort( result.begin(), result.end(), + []( address_translation& a, address_translation& b ) -> bool { + return a.map_to < b.map_to; + } ); +} + +int main( int argc, char** argv ) +{ + if ( argc != 3 ) { + std::cout << "Usage: proc_mem pid full_file_path" << std::endl; + return 1; + } + + // Process file translation regions for the ELF file from /proc/pid/maps + std::ifstream proc_maps( std::string( "/proc/" ) + argv[1] + "/maps" ); + if ( !proc_maps ) { + std::cout << "Can't open " + << std::string( "/proc/" ) + argv[1] + "/maps" + << " file" << std::endl; + return 2; + } + + std::vector<address_translation> ranges; + get_translation_ranges( proc_maps, argv[2], ranges ); + // for ( auto& range : ranges ) { + // std::cout << std::hex << range.start << " " << range.end << " " + // << range.map_to << std::endl; + // } + + elfio elffile; + elffile.set_address_translation( ranges ); + + if ( elffile.load( std::string( "/proc/" ) + argv[1] + "/mem" ) ) { + dump::header( std::cout, elffile ); + dump::section_headers( std::cout, elffile ); + dump::segment_headers( std::cout, elffile ); + dump::symbol_tables( std::cout, elffile ); + } + else { + std::cout << "Can't open " << std::string( "/proc/" ) + argv[1] + "/mem" + << " file" << std::endl; + } + + return 0; +} diff --git a/tests/ELFIOTest2.cpp b/tests/ELFIOTest2.cpp index 72cf726fa0f7bfc45de3ebfd3504bdd735530f5e..bfbfaf4ad72b0f076aafad4f3f2fc29d458788be 100644 --- a/tests/ELFIOTest2.cpp +++ b/tests/ELFIOTest2.cpp @@ -428,3 +428,30 @@ BOOST_AUTO_TEST_CASE( move_constructor_and_assignment ) BOOST_CHECK_EQUAL( r2.sections[".text"]->get_name(), sec_name ); BOOST_CHECK_EQUAL( r2.segments[1]->get_memory_size(), seg_size ); } + +BOOST_AUTO_TEST_CASE( address_translation_test ) +{ + std::vector<address_translation> ranges; + + ranges.emplace_back( 500, 600, 0 ); + ranges.emplace_back( 1000, 2000, 500 ); + ranges.emplace_back( 3000, 4000, 2000 ); + + address_translator tr; + tr.set_address_translation( ranges ); + + BOOST_CHECK_EQUAL( tr( 0 ), 500 ); + BOOST_CHECK_EQUAL( tr( 510 ), 1010 ); + BOOST_CHECK_EQUAL( tr( 1710 ), 1710 ); + BOOST_CHECK_EQUAL( tr( 2710 ), 3710 ); + BOOST_CHECK_EQUAL( tr( 3710 ), 3710 ); + + ranges.clear(); + tr.set_address_translation( ranges ); + + BOOST_CHECK_EQUAL( tr( 0 ), 0 ); + BOOST_CHECK_EQUAL( tr( 510 ), 510 ); + BOOST_CHECK_EQUAL( tr( 1710 ), 1710 ); + BOOST_CHECK_EQUAL( tr( 2710 ), 2710 ); + BOOST_CHECK_EQUAL( tr( 3710 ), 3710 ); +}