diff --git a/pykd/dbgengine.h b/pykd/dbgengine.h index 82b5ecf..3010872 100644 --- a/pykd/dbgengine.h +++ b/pykd/dbgengine.h @@ -16,7 +16,10 @@ ULONG ptrSize(); ULONG64 findModuleBase( const std::string &moduleName ); ULONG64 findModuleBase( ULONG64 offset ); std::string getModuleName( ULONG64 baseOffset ); +std::string getModuleImageName( ULONG64 baseOffset ); std::string getModuleSymbolFileName( ULONG64 baseOffset ); +ULONG getModuleTimeStamp( ULONG64 baseOffset ); +ULONG getModuleCheckSum( ULONG64 baseOffset ); //manage access to target memory ULONG64 addr64( ULONG64 offset ); diff --git a/pykd/module.cpp b/pykd/module.cpp index c5daa5b..e97d78f 100644 --- a/pykd/module.cpp +++ b/pykd/module.cpp @@ -21,6 +21,10 @@ Module::Module(const std::string &moduleName ) { m_base = findModuleBase( moduleName ); m_name = moduleName; + m_symfile = getModuleSymbolFileName( m_base ); + m_imageName = getModuleImageName( m_base ); + m_timeDataStamp = getModuleTimeStamp( m_base ); + m_checkSum = getModuleCheckSum( m_base ); } ///////////////////////////////////////////////////////////////////////////////////// @@ -29,6 +33,10 @@ Module::Module(ULONG64 offset ) { m_base = findModuleBase( addr64(offset) ); m_name = getModuleName( m_base ); + m_symfile = getModuleSymbolFileName( m_base ); + m_imageName = getModuleImageName( m_base ); + m_timeDataStamp = getModuleTimeStamp( m_base ); + m_checkSum = getModuleCheckSum( m_base ); } ///////////////////////////////////////////////////////////////////////////////////// @@ -40,11 +48,10 @@ SymbolPtr& Module::getSymScope() if ( m_symScope ) break; - std::string symbolName = getModuleSymbolFileName( m_base ); - if ( symbolName.empty() ) + if ( m_symfile.empty() ) break; - m_symScope = loadSymbolFile( symbolName ); + m_symScope = loadSymbolFile( m_symfile ); } while( false ); @@ -56,6 +63,14 @@ SymbolPtr& Module::getSymScope() ///////////////////////////////////////////////////////////////////////////////////// +void Module::reloadSymbols() +{ + m_symfile = getModuleSymbolFileName( m_base ); + m_symScope.reset(); +} + +///////////////////////////////////////////////////////////////////////////////////// + ULONG Module::getRvaByName(const std::string &symName) { SymbolPtr &symScope = getSymScope(); @@ -65,6 +80,22 @@ ULONG Module::getRvaByName(const std::string &symName) ///////////////////////////////////////////////////////////////////////////////////// +std::string Module::print() +{ + std::stringstream sstr; + + sstr << "Module: " << m_name << std::endl; + sstr << "Start: " << std::hex << m_base << " End: " << getEnd() << " Size: " << m_size << std::endl; + sstr << "Image: " << m_imageName << std::endl; + sstr << "Symnol: " << m_symfile << std::endl; + //sstr << "Timestamp: " << m_timeDataStamp << std::endl; + //sstr << "Check Sum: " << m_checkSum << std::endl; + + return sstr.str(); +} + +///////////////////////////////////////////////////////////////////////////////////// + }; // end of namespace pykd diff --git a/pykd/module.h b/pykd/module.h index 2a19164..9b65632 100644 --- a/pykd/module.h +++ b/pykd/module.h @@ -44,11 +44,17 @@ public: return m_size; } - void - reloadSymbols() - { + std::string getSymFile() const { + return m_symfile; } + std::string getImageName() const { + return m_imageName; + } + + void + reloadSymbols(); + ULONG64 getSymbol( const std::string &symbolname ) { return m_base + getRvaByName(symbolname); @@ -59,6 +65,16 @@ public: return getRvaByName(symbolname); } + ULONG getCheckSum() const { + return m_checkSum; + } + + ULONG getTimeDataStamp() const { + return m_timeDataStamp; + } + + std::string print(); + private: SymbolPtr& getSymScope(); @@ -70,8 +86,12 @@ private: ULONG getRvaByName(const std::string &symName); std::string m_name; + std::string m_imageName; + std::string m_symfile; ULONG64 m_base; ULONG m_size; + ULONG m_timeDataStamp; + ULONG m_checkSum; SymbolPtr m_symScope; }; diff --git a/pykd/pymod.cpp b/pykd/pymod.cpp index 4fc11f4..e02df50 100644 --- a/pykd/pymod.cpp +++ b/pykd/pymod.cpp @@ -176,19 +176,14 @@ BOOST_PYTHON_MODULE( pykd ) "Return name of the module" ) .def("reload", &Module::reloadSymbols, "(Re)load symbols for the module" ) - .def("__getattr__", &Module::getSymbol, - "Return address of the symbol" ); - - //.def("image", &Module::getImageName, - // "Return name of the image of the module" ) - //.def("pdb", &Module::getPdbName, - // "Return the full path to the module's pdb file ( symbol information )" ) - //.def("reload", &Module::reloadSymbols, - // "(Re)load symbols for the module" ) - //.def("offset", &Module::getSymbol, - // "Return offset of the symbol" ) - //.def("rva", &Module::getSymbolRva, - // "Return rva of the symbol" ) + .def("image", &Module::getImageName, + "Return name of the image of the module" ) + .def("symfile", &Module::getSymFile, + "Return the full path to the module's symbol information" ) + .def("offset", &Module::getSymbol, + "Return offset of the symbol" ) + .def("rva", &Module::getSymbolRva, + "Return rva of the symbol" ) //.def( "sizeof", &Module::getSymbolSize, // "Return a size of the type or variable" ) //.def("type", &Module::getTypeByName, @@ -215,13 +210,13 @@ BOOST_PYTHON_MODULE( pykd ) //.def("containingRecord", &Module::containingRecordByType, // "Return instance of the typedVar class. It's value are loaded from the target memory." // "The start address is calculated by the same method as the standard macro CONTAINING_RECORD does" ) - //.def("checksum",&Module::getCheckSum, - // "Return a image file checksum: IMAGE_OPTIONAL_HEADER.CheckSum" ) - //.def("timestamp",&Module::getTimeDataStamp, - // "Return a low 32 bits of the time stamp of the image: IMAGE_FILE_HEADER.TimeDateStamp" ) - //.def("__getattr__", &Module::getSymbol, - // "Return address of the symbol" ) - //.def( "__str__", &Module::print ); + .def("checksum",&Module::getCheckSum, + "Return a image file checksum: IMAGE_OPTIONAL_HEADER.CheckSum" ) + .def("timestamp",&Module::getTimeDataStamp, + "Return a low 32 bits of the time stamp of the image: IMAGE_FILE_HEADER.TimeDateStamp" ) + .def("__getattr__", &Module::getSymbol, + "Return address of the symbol" ) + .def( "__str__", &Module::print ); pykd::exception( "BaseException", "Pykd base exception class" ); pykd::exception( "MemoryException", "Target memory access exception class" ); diff --git a/pykd/win/dbgeng.cpp b/pykd/win/dbgeng.cpp index 9f5d963..ae71c49 100644 --- a/pykd/win/dbgeng.cpp +++ b/pykd/win/dbgeng.cpp @@ -174,6 +174,29 @@ std::string getModuleName( ULONG64 baseOffset ) /////////////////////////////////////////////////////////////////////////////////// +std::string getModuleImageName( ULONG64 baseOffset ) +{ + PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); + + HRESULT hres; + char imageName[0x100]; + + hres = g_dbgEng->symbols->GetModuleNameString( + DEBUG_MODNAME_IMAGE, + DEBUG_ANY_ID, + baseOffset, + imageName, + sizeof( imageName ), + NULL ); + + if ( FAILED( hres ) ) + throw DbgException( "IDebugSymbol::GetModuleNameString failed" ); + + return std::string( imageName ); +} + +/////////////////////////////////////////////////////////////////////////////////// + std::string getModuleSymbolFileName( ULONG64 baseOffset ) { PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); @@ -227,6 +250,38 @@ std::string getModuleSymbolFileName( ULONG64 baseOffset ) /////////////////////////////////////////////////////////////////////////////////// +ULONG getModuleTimeStamp( ULONG64 baseOffset ) +{ + PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); + + HRESULT hres; + DEBUG_MODULE_PARAMETERS moduleParam = { 0 }; + + hres = g_dbgEng->symbols->GetModuleParameters( 1, &baseOffset, 0, &moduleParam ); + if ( FAILED( hres ) ) + throw DbgException( "IDebugSymbol::GetModuleParameters failed" ); + + return moduleParam.TimeDateStamp; +} + +/////////////////////////////////////////////////////////////////////////////////// + +ULONG getModuleCheckSum( ULONG64 baseOffset ) +{ + PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); + + HRESULT hres; + DEBUG_MODULE_PARAMETERS moduleParam = { 0 }; + + hres = g_dbgEng->symbols->GetModuleParameters( 1, &baseOffset, 0, &moduleParam ); + if ( FAILED( hres ) ) + throw DbgException( "IDebugSymbol::GetModuleParameters failed" ); + + return moduleParam.Checksum; +} + +/////////////////////////////////////////////////////////////////////////////////// + ULONG ptrSize() { PyThread_StateRestore pyThreadRestore( g_dbgEng->pystate ); diff --git a/test/scripts/moduletest.py b/test/scripts/moduletest.py index 20830e4..90b974b 100644 --- a/test/scripts/moduletest.py +++ b/test/scripts/moduletest.py @@ -26,40 +26,26 @@ class ModuleTest( unittest.TestCase ): def testEnd( self ): self.assertEqual( target.module.size(), target.module.end() - target.module.begin() ) -# def testPdb( self ): -# self.assertNotEqual( "", target.module.pdb() ) + def testPdb( self ): + self.assertNotEqual( "", target.module.symfile() ) -# def testImage( self ): -# self.assertEqual( target.module.name() + ".exe", target.module.image() ) + def testImage( self ): + self.assertEqual( target.module.name() + ".exe", target.module.image() ) -# def testFindModule( self ): - -# try: -# pykd.loadModule( target.module.begin() - 0x10 ) -# self.assertTrue( False ) -# except pykd.BaseException: -# self.assertTrue( True ) + def testFindModule( self ): + self.assertRaises( pykd.BaseException, pykd.module, target.module.begin() - 0x10 ) -# self.assertNotEqual( None, pykd.loadModule( target.module.begin() ) ) -# self.assertNotEqual( None, pykd.loadModule( target.module.begin() + 0x10) ) + self.assertNotEqual( None, pykd.module( target.module.begin() ) ) + self.assertNotEqual( None, pykd.module( target.module.begin() + 0x10) ) -# try: -# pykd.loadModule( target.module.end() ) -# self.assertTrue( False ) -# except pykd.BaseException: -# self.assertTrue( True ) - -# try: -# pykd.loadModule( target.module.end() + 0x10 ) -# self.assertTrue( False ) -# except pykd.BaseException: -# self.assertTrue( True ) + self.assertRaises( pykd.BaseException, pykd.module, target.module.end() ) + self.assertRaises( pykd.BaseException, pykd.module, target.module.end() + 0x10 ) -# def testSymbol( self ): -# self.assertEqual( target.module.rva("FuncWithName0"), target.module.offset("FuncWithName0") - target.module.begin() ) -# self.assertEqual( target.module.rva("FuncWithName0"), target.module.FuncWithName0 - target.module.begin() ) + def testSymbol( self ): + self.assertEqual( target.module.rva("FuncWithName0"), target.module.offset("FuncWithName0") - target.module.begin() ) + self.assertEqual( target.module.rva("FuncWithName0"), target.module.FuncWithName0 - target.module.begin() ) -# def testType( self ): -# self.assertEqual( "structTest", target.module.type("structTest").name() ); -# self.assertEqual( "structTest", target.module.type("g_structTest").name() ); + def testType( self ): + self.assertEqual( "structTest", target.module.type("structTest").name() ); + self.assertEqual( "structTest", target.module.type("g_structTest").name() ); diff --git a/test/scripts/pykdtest.py b/test/scripts/pykdtest.py index 7393a2f..367b3f1 100644 --- a/test/scripts/pykdtest.py +++ b/test/scripts/pykdtest.py @@ -55,6 +55,9 @@ if __name__ == "__main__": + + + #import target #import moduletest