diff --git a/kdar/cmd.py b/kdar/cmd.py new file mode 100644 index 0000000..b43f101 --- /dev/null +++ b/kdar/cmd.py @@ -0,0 +1,5 @@ +from pykd import * + +s = dbgCommand( "dt nt!_DRIVER_OBJECT" ) + +dprintln( s ) \ No newline at end of file diff --git a/kdar/drvobj.py b/kdar/drvobj.py new file mode 100644 index 0000000..9b60816 --- /dev/null +++ b/kdar/drvobj.py @@ -0,0 +1,11 @@ +from pykd import * + + +drvObj = typedVar( "nt", "_DRIVER_OBJECT", addr64( 0x82000c08 ) ) + +dprintln( "DriverName.Length = %(1)d" % { "1" : drvObj.DriverName.Length } ) + +for i,f in drvObj.MajorFunction.iteritems(): + + dprintln( "MajorFunction[%(1)d] = " % { "1" : i } + findSymbol( addr64( f ) ) ) + diff --git a/kdar/idt.py b/kdar/idt.py new file mode 100644 index 0000000..5f8e2b3 --- /dev/null +++ b/kdar/idt.py @@ -0,0 +1,62 @@ +from pykd import * + + +if not is64bitSystem(): + + dprintln( "check interrupt handlers...\n" ) + + idtr = reg( "idtr" ) + + nt = loadModule( "nt" ) + nt.KiInterruptDispatch = getOffset( "nt", "KiInterruptDispatch" ) + nt.KiChainedDispatch = getOffset( "nt", "KiChainedDispatch" ) + nt.KiInterruptTemplate = getOffset( "nt", "KiInterruptTemplate" ) + + hal = loadModule( "hal" ) + + + ErrorCount = 0 + + for i in range(0,255): + + idtEntry = typedVar( "nt", "_KIDTENTRY", idtr + i*8 ) + + if idtEntry.Selector == 8: + + InterruptHandler = ( idtEntry.ExtendedOffset * 0x10000 ) + idtEntry.Offset + + if InterruptHandler != 0 and not nt.contain( InterruptHandler ) and not hal.contain( InterruptHandler ): + + kinterrupt = containingRecord( InterruptHandler, "nt", "_KINTERRUPT", "DispatchCode" ) + + dprintln ( "KINTERRUPT: %(1)x" % { "1" : kinterrupt.getAddress() } ) + + if addr64( kinterrupt.DispatchAddress ) != nt.KiInterruptDispatch and addr64( kinterrupt.DispatchAddress ) != nt.KiChainedDispatch: + dprintln ( "Threat!!! KINTERRUPT::DispatchAddress PATCHED" ) + ErrorCount += 1 + + if findModule( kinterrupt.ServiceRoutine ) == None: + dprintln ( "Threat!!! KINTERRUPT::ServiceRoutine (%(1)x) out of any module" % { "1" : kinterrupt.ServiceRoutine } ) + ErrorCount += 1 + + if not compareMemory( nt.KiInterruptTemplate, InterruptHandler, 98 ): + dprintln ( "Threat!!! KINTERRUPT::DispatchCode area PATCHED" ) + ErrorCount += 1 + + + dprintln ( "" ) + + + dprintln( "check end: %(1)d threats" % { "1" : ErrorCount } ) + + +else: + + dprintln( "x64 is not supported" ) + + + + + + + diff --git a/pykd.sln b/pykd.sln new file mode 100644 index 0000000..9a06613 --- /dev/null +++ b/pykd.sln @@ -0,0 +1,30 @@ +п»ї +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pykd", "pykd\pykd.vcproj", "{C0A12E93-4B76-4B17-B837-37020F957AD2}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C0A12E93-4B76-4B17-B837-37020F957AD2}.Debug|Win32.ActiveCfg = Debug|Win32 + {C0A12E93-4B76-4B17-B837-37020F957AD2}.Debug|Win32.Build.0 = Debug|Win32 + {C0A12E93-4B76-4B17-B837-37020F957AD2}.Debug|x64.ActiveCfg = Debug|x64 + {C0A12E93-4B76-4B17-B837-37020F957AD2}.Debug|x64.Build.0 = Debug|x64 + {C0A12E93-4B76-4B17-B837-37020F957AD2}.Release|Win32.ActiveCfg = Release|Win32 + {C0A12E93-4B76-4B17-B837-37020F957AD2}.Release|Win32.Build.0 = Release|Win32 + {C0A12E93-4B76-4B17-B837-37020F957AD2}.Release|x64.ActiveCfg = Release|x64 + {C0A12E93-4B76-4B17-B837-37020F957AD2}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/pykd.suo b/pykd.suo new file mode 100644 index 0000000..e3a1c78 Binary files /dev/null and b/pykd.suo differ diff --git a/pykd/dbgcmd.cpp b/pykd/dbgcmd.cpp new file mode 100644 index 0000000..d76b8a7 --- /dev/null +++ b/pykd/dbgcmd.cpp @@ -0,0 +1,127 @@ +#include "stdafx.h" + +#include + +#include "dbgcmd.h" +#include "dbgexcept.h" + +/////////////////////////////////////////////////////////////////////////////// + +// класс для перехвата вывода в отладчик + +class OutputReader : public IDebugOutputCallbacks { + +public: + + OutputReader( IDebugClient *debugClient ) + { + HRESULT hres; + + try { + + m_debugClient = debugClient; + m_debugClient->AddRef(); + + hres = m_debugClient->GetOutputCallbacks( &m_previousCallback ); + if ( FAILED( hres ) ) + { + throw hres; + } + + hres = m_debugClient->SetOutputCallbacks( this ); + if ( FAILED( hres ) ) + { + throw hres; + } + + } catch( ... ) + { + m_debugClient->Release(); + m_debugClient = NULL; + } + } + + ~OutputReader() + { + if ( m_debugClient ) + { + m_debugClient->SetOutputCallbacks( m_previousCallback ); + m_debugClient->Release(); + } + } + + const std::string& + Line() const { + return m_readLine; + } + +private: + + // IUnknown. + STDMETHOD(QueryInterface)( + __in REFIID InterfaceId, + __out PVOID* Interface ) { + return E_NOINTERFACE; + } + + STDMETHOD_(ULONG, AddRef)() { + return 1L; + } + + + STDMETHOD_(ULONG, Release)() { + return 0L; + } + + STDMETHOD(Output)( + __in ULONG Mask, + __in PCSTR Text ) + { + if ( Mask == DEBUG_OUTPUT_NORMAL ) + { + m_readLine += std::string( Text ); + } + + return S_OK; + } + +private: + + std::string m_readLine; + + IDebugClient *m_debugClient; + + IDebugOutputCallbacks *m_previousCallback; +}; + + +/////////////////////////////////////////////////////////////////////////////// + +std::string +dbgCommand( const std::string &command ) +{ + HRESULT hres; + + try { + + OutputReader outReader( g_Ext->m_Client ); + + hres = g_Ext->m_Control->Execute( DEBUG_OUTCTL_THIS_CLIENT, command.c_str(), 0 ); + if ( FAILED( hres ) ) + throw DbgException( "IDebugControl::Execute failed" ); + + return std::string( outReader.Line() ); + } + catch( std::exception &e ) + { + g_Ext->Out( "pykd error: %s\n", e.what() ); + } + catch(...) + { + g_Ext->Out( "pykd unexpected error\n" ); + } + + return "error"; +} + +/////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/pykd/dbgcmd.h b/pykd/dbgcmd.h new file mode 100644 index 0000000..b34637f --- /dev/null +++ b/pykd/dbgcmd.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +#include +#include + +///////////////////////////////////////////////////////////////////////////////// + +std::string +dbgCommand( const std::string &command ); + + + +///////////////////////////////////////////////////////////////////////////////// + diff --git a/pykd/dbgexcept.h b/pykd/dbgexcept.h new file mode 100644 index 0000000..83a7701 --- /dev/null +++ b/pykd/dbgexcept.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +///////////////////////////////////////////////////////////////////////////////// + +class DbgException : public std::exception +{ +public: + + DbgException( const char* desc ) : + std::exception( desc ) + {} +}; + +///////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/pykd/dbgext.cpp b/pykd/dbgext.cpp new file mode 100644 index 0000000..dd3133b --- /dev/null +++ b/pykd/dbgext.cpp @@ -0,0 +1,143 @@ +#include "stdafx.h" + +#include + +#include +#include +#include +#include + +#include "dbgprint.h" +#include "dbgreg.h" +#include "dbgtype.h" +#include "dbgmodule.h" +#include "dbgsym.h" +#include "dbgmem.h" +#include "dbgsystem.h" +#include "dbgcmd.h" + +///////////////////////////////////////////////////////////////////////////////// + +BOOST_PYTHON_MODULE( pykd ) +{ + boost::python::def( "dprint", &DbgPrint::dprint ); + boost::python::def( "dprintln", &DbgPrint::dprintln ); + boost::python::def( "dbgCommand", &dbgCommand ); + boost::python::def( "is64bitSystem", is64bitSystem ); + boost::python::def( "reg", &loadRegister ); + boost::python::def( "typedVar", &loadTypedVar ); + boost::python::def( "containingRecord", &containingRecord ); + boost::python::def( "loadModule", &loadModule ); + boost::python::def( "findSymbol", &findSymbolForAddress ); + boost::python::def( "getOffset", &findAddressForSymbol ); + boost::python::def( "findModule", &findModule ); + boost::python::def( "addr64", &addr64 ); + boost::python::def( "compareMemory", &compareMemory ); + boost::python::class_( "typedVarClass" ) + .def("getAddress", &typedVarClass::getAddress ); + boost::python::class_( "dbgModuleClass" ) + .add_property("begin", &dbgModuleClass::getBegin ) + .add_property("end", &dbgModuleClass::getEnd ) + .def("contain", &dbgModuleClass::contain ); +} + +///////////////////////////////////////////////////////////////////////////////// + +class EXT_CLASS : public ExtExtension +{ +public: + + virtual HRESULT Initialize(void) { + + HRESULT hr = ExtExtension::Initialize(); + if ( FAILED( hr ) ) + return hr; + + Py_Initialize(); + + PyImport_AppendInittab("pykd",initpykd ); + + return hr; + } + + virtual void Uninitialize(void) { + + Py_Finalize(); + } + + +public: + EXT_COMMAND_METHOD( info ); + EXT_COMMAND_METHOD( exec ); +}; + +EXT_DECLARE_GLOBALS(); + +///////////////////////////////////////////////////////////////////////////////// + +EXT_COMMAND( + info, + "Python Info", + "" ) +{ + Out( "Python Info" ); +} + +///////////////////////////////////////////////////////////////////////////////// + +EXT_COMMAND( + exec, + "Execute python code", + "{f;b;;quite mode}{;x}" ) +{ + bool fromFile = false; + + if ( HasArg( "f" ) ) + fromFile = true; + + try { + + + boost::python::object main = boost::python::import("__main__"); + + boost::python::object global(main.attr("__dict__")); + + boost::python::object result; + + if ( fromFile ) + { + result = boost::python::exec_file( GetUnnamedArgStr( 0 ), global, global ); + } + else + { + result = boost::python::exec( GetUnnamedArgStr( 0 ), global, global ); + } + } + catch( boost::python::error_already_set const & ) + { + // ошибка в скрипте + PyObject *errtype = NULL, *errvalue = NULL, *traceback = NULL; + + PyErr_Fetch( &errtype, &errvalue, &traceback ); + + if(errvalue != NULL) + { + PyObject *s = PyObject_Str(errvalue); + + DbgPrint::dprintln( PyString_AS_STRING( s ) ); + + Py_DECREF(s); + } + + Py_XDECREF(errvalue); + Py_XDECREF(errtype); + Py_XDECREF(traceback); + } + catch(...) + { + } + + + } + +///////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/pykd/dbgmem.cpp b/pykd/dbgmem.cpp new file mode 100644 index 0000000..3eb3547 --- /dev/null +++ b/pykd/dbgmem.cpp @@ -0,0 +1,92 @@ +#include "stdafx.h" + +#include + +#include "dbgexcept.h" +#include "dbgmem.h" + +using namespace std; + +/////////////////////////////////////////////////////////////////////////////////// + +bool +loadMemory( ULONG64 address, PVOID dest, ULONG length ) +{ + address = addr64( address ); + + try { + + HRESULT hres = g_Ext->m_Data->ReadVirtual( address, dest, length, NULL ); + if ( FAILED( hres ) ) + throw DbgException( "IDebugDataSpace::ReadVirtual failed" ); + + return true; + + } + catch( std::exception &e ) + { + g_Ext->Out( "pykd error: %s\n", e.what() ); + } + catch(...) + { + g_Ext->Out( "Kd2Lua unexpected error\n" ); + } + + return false; +} + +/////////////////////////////////////////////////////////////////////////////////// + +ULONG64 +addr64( ULONG64 addr ) +{ + if ( *( (ULONG*)&addr + 1 ) == 0 ) + *( (ULONG*)&addr + 1 ) = 0xFFFFFFFF; + + return addr; +} + +/////////////////////////////////////////////////////////////////////////////////// + +bool +compareMemory( ULONG64 addr1, ULONG64 addr2, ULONG length ) +{ + HRESULT hres; + bool result = false; + + addr1 = addr64( addr1 ); + addr2 = addr64( addr2 ); + + char* m1 = new char[length]; + char* m2 = new char[length]; + + try { + + hres = g_Ext->m_Data->ReadVirtual( addr1, m1, length, NULL ); + if ( FAILED( hres ) ) + throw DbgException( "IDebugDataSpace::ReadVirtual failed" ); + + hres = g_Ext->m_Data->ReadVirtual( addr2, m2, length, NULL ); + if ( FAILED( hres ) ) + throw DbgException( "IDebugDataSpace::ReadVirtual failed" ); + + result = memcmp( m1, m2, length ) == 0; + + } + catch( std::exception &e ) + { + g_Ext->Out( "pykd error: %s\n", e.what() ); + } + catch(...) + { + g_Ext->Out( "Kd2Lua unexpected error\n" ); + } + + delete[] m1; + delete[] m2; + + return result; +} + +/////////////////////////////////////////////////////////////////////////////////// + diff --git a/pykd/dbgmem.h b/pykd/dbgmem.h new file mode 100644 index 0000000..be5b270 --- /dev/null +++ b/pykd/dbgmem.h @@ -0,0 +1,14 @@ +#pragma once + +///////////////////////////////////////////////////////////////////////////////// + +bool +loadMemory( ULONG64 address, PVOID dest, ULONG length ); + +bool +compareMemory( ULONG64 addr1, ULONG64 addr2, ULONG length ); + +ULONG64 +addr64( ULONG64 addr ); + +///////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/pykd/dbgmodule.cpp b/pykd/dbgmodule.cpp new file mode 100644 index 0000000..722157e --- /dev/null +++ b/pykd/dbgmodule.cpp @@ -0,0 +1,84 @@ +#include "stdafx.h" + +#include + +#include "dbgmodule.h" +#include "dbgexcept.h" +#include "dbgmem.h" + +///////////////////////////////////////////////////////////////////////////////// + +boost::python::object +loadModule( const std::string &moduleName ) +{ + HRESULT hres; + + try { + ULONG64 moduleBase; + hres = g_Ext->m_Symbols->GetModuleByModuleName( moduleName.c_str(), 0, NULL, &moduleBase ); + if ( FAILED( hres ) ) + throw DbgException( "IDebugSymbol::GetModuleByModuleName failed" ); + + DEBUG_MODULE_PARAMETERS moduleParam = { 0 }; + hres = g_Ext->m_Symbols->GetModuleParameters( 1, &moduleBase, 0, &moduleParam ); + if ( FAILED( hres ) ) + throw DbgException( "IDebugSymbol::GetModuleParameters failed" ); + + + return boost::python::object( dbgModuleClass( moduleBase, moduleParam.Size ) ); + + } + catch( std::exception &e ) + { + g_Ext->Out( "pykd error: %s\n", e.what() ); + } + catch(...) + { + g_Ext->Out( "pykd unexpected error\n" ); + } + + return boost::python::object(); +} + +///////////////////////////////////////////////////////////////////////////////// + +boost::python::object +findModule( ULONG64 addr ) +{ + HRESULT hres; + + addr = addr64( addr ); + + try { + + ULONG moduleIndex; + ULONG64 moduleBase; + hres = g_Ext->m_Symbols->GetModuleByOffset( addr, 0, &moduleIndex, &moduleBase ); + + if ( FAILED( hres ) ) + { + return boost::python::object(); + } + + DEBUG_MODULE_PARAMETERS moduleParam = { 0 }; + hres = g_Ext->m_Symbols->GetModuleParameters( 1, &moduleBase, 0, &moduleParam ); + if ( FAILED( hres ) ) + throw DbgException( "IDebugSymbol::GetModuleParameters failed" ); + + + return boost::python::object( dbgModuleClass( moduleBase, moduleParam.Size ) ); + + } + catch( std::exception &e ) + { + g_Ext->Out( "pykd error: %s\n", e.what() ); + } + catch(...) + { + g_Ext->Out( "pykd unexpected error\n" ); + } + + return boost::python::object(); +} + +///////////////////////////////////////////////////////////////////////////////// diff --git a/pykd/dbgmodule.h b/pykd/dbgmodule.h new file mode 100644 index 0000000..8711dcd --- /dev/null +++ b/pykd/dbgmodule.h @@ -0,0 +1,58 @@ +#pragma once + +#include + +#include +#include + +///////////////////////////////////////////////////////////////////////////////// + +class dbgModuleClass { + +public: + + dbgModuleClass() : + m_base( 0 ), + m_end( 0 ) + {} + + dbgModuleClass( ULONG64 base, ULONG size ) : + m_base( base ), + m_end( base + size ) + {} + + ULONG64 + getBegin() const { + return m_base; + } + + ULONG64 + getEnd() const { + return m_end; + } + + bool + contain( ULONG64 addr ) const { + if ( *( (ULONG*)&addr + 1 ) == 0 ) + *( (ULONG*)&addr + 1 ) = 0xFFFFFFFF; + + return m_base <= addr && addr <= m_end; + } + + +private: + + ULONG64 m_base; + ULONG64 m_end; +}; + +///////////////////////////////////////////////////////////////////////////////// + +boost::python::object +loadModule( const std::string &moduleName ); + + +boost::python::object +findModule( ULONG64 addr ); + +///////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/pykd/dbgprint.cpp b/pykd/dbgprint.cpp new file mode 100644 index 0000000..d7c9a98 --- /dev/null +++ b/pykd/dbgprint.cpp @@ -0,0 +1,16 @@ +#include "stdafx.h" +#include "dbgprint.h" +#include + +using namespace std; + +void DbgPrint::dprint( const string& str ) +{ + g_Ext->Out( str.c_str() ); +} + +void DbgPrint::dprintln( const std::string& str ) +{ + g_Ext->Out( str.c_str() ); + g_Ext->Out( "\r\n" ); +} \ No newline at end of file diff --git a/pykd/dbgprint.h b/pykd/dbgprint.h new file mode 100644 index 0000000..d3b0f6e --- /dev/null +++ b/pykd/dbgprint.h @@ -0,0 +1,15 @@ +// вывод информации в отладчик + +#pragma once + +#include + +class DbgPrint { + +public: + + static void dprint( const std::string& str ); + + static void dprintln( const std::string& str ); +}; + diff --git a/pykd/dbgreg.cpp b/pykd/dbgreg.cpp new file mode 100644 index 0000000..ee48e00 --- /dev/null +++ b/pykd/dbgreg.cpp @@ -0,0 +1,62 @@ +#include "stdafx.h" + +#include + +#include "dbgreg.h" +#include "dbgexcept.h" + +using namespace std; + +/////////////////////////////////////////////////////////////////////////////////// + +boost::python::object +loadRegister( const std::string ®isterName ) +{ + HRESULT hres; + + + try { + + ULONG registerIndex = 0; + + hres = g_Ext->m_Registers->GetIndexByName( registerName.c_str(), ®isterIndex ); + if ( FAILED( hres ) ) + throw DbgException( "IDebugRegister::GetIndexByName failed" ); + + DEBUG_VALUE debugValue; + hres = g_Ext->m_Registers->GetValue( registerIndex, &debugValue ); + if ( FAILED( hres ) ) + throw DbgException( "IDebugRegister::GetValue failed" ); + + switch( debugValue.Type ) + { + case DEBUG_VALUE_INT8: + return boost::python::long_( debugValue.I8 ); + break; + + case DEBUG_VALUE_INT16: + return boost::python::long_( debugValue.I16 ); + break; + + case DEBUG_VALUE_INT32: + return boost::python::long_( debugValue.I32 ); + break; + + case DEBUG_VALUE_INT64: + return boost::python::long_(debugValue.I64 ); + break; + } + } + catch( std::exception &e ) + { + g_Ext->Out( "pykd error: %s\n", e.what() ); + } + catch(...) + { + g_Ext->Out( "pykd unexpected error\n" ); + } + + return boost::python::str( "REG_ERR" ); +} + +/////////////////////////////////////////////////////////////////////////////////// diff --git a/pykd/dbgreg.h b/pykd/dbgreg.h new file mode 100644 index 0000000..b43ef27 --- /dev/null +++ b/pykd/dbgreg.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +#include +#include + +///////////////////////////////////////////////////////////////////////////////// + +boost::python::object +loadRegister( const std::string ®isterName ); + +///////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/pykd/dbgsym.cpp b/pykd/dbgsym.cpp new file mode 100644 index 0000000..9d63ad9 --- /dev/null +++ b/pykd/dbgsym.cpp @@ -0,0 +1,105 @@ +#include "stdafx.h" + +#include + +#include "dbgsym.h" +#include "dbgexcept.h" + +///////////////////////////////////////////////////////////////////////////////// + +boost::python::object +findSymbolForAddress( ULONG64 addr ) +{ + HRESULT hres; + + try { + + DEBUG_MODULE_AND_ID debugId; + ULONG64 displace = 0; + + if ( *( (ULONG*)&addr + 1 ) == 0 ) + *( (ULONG*)&addr + 1 ) = 0xFFFFFFFF; + + ULONG moduleIndex; + ULONG64 moduleBase; + hres = g_Ext->m_Symbols->GetModuleByOffset( addr, 0, &moduleIndex, &moduleBase ); + + if ( FAILED( hres ) ) + { + return boost::python::object( "out of module" ); + } + + char moduleName[0x100]; + hres = g_Ext->m_Symbols2->GetModuleNameString( DEBUG_MODNAME_MODULE, moduleIndex, moduleBase, + moduleName, sizeof( moduleName ), NULL ); + + if ( FAILED( hres ) ) + throw DbgException( "IDebugSymbol2::GetModuleNameString failed" ); + + ULONG entries = 0; + hres = g_Ext->m_Symbols3->GetSymbolEntriesByOffset( addr, 0, &debugId, &displace, 1, &entries ); + if ( FAILED( hres ) ) + throw DbgException( "IDebugSymbol3::GetSymbolEntriesByOffset failed" ); + + std::stringstream ss; + + if ( entries == 0 ) + { + ss << moduleName << "+" << std::hex << ( addr - moduleBase ); + return boost::python::object( ss.str() ); + } + + char symbolName[0x100]; + hres = g_Ext->m_Symbols3->GetSymbolEntryString( &debugId, 0, symbolName, sizeof(symbolName ), NULL ); + if ( FAILED( hres ) ) + throw DbgException( "IDebugSymbol3::GetSymbolEntryString failed" ); + + ss << moduleName << "!" << symbolName; + return boost::python::object( ss.str() ); + + } + catch( std::exception &e ) + { + g_Ext->Out( "pykd error: %s\n", e.what() ); + } + catch(...) + { + g_Ext->Out( "pykd unexpected error\n" ); + } + + return boost::python::object( addr ); +} + +///////////////////////////////////////////////////////////////////////////////// + +ULONG64 +findAddressForSymbol( const std::string &moduleName, const std::string &symbolName ) +{ + HRESULT hres; + + try { + + std::string ModuleSymName = moduleName; + ModuleSymName += "!"; + ModuleSymName += symbolName; + + ULONG64 offset = 0ULL; + hres = g_Ext->m_Symbols->GetOffsetByName( ModuleSymName.c_str(), &offset ); + if ( FAILED( hres ) ) + throw DbgException( "IDebugSymbol::GetOffsetByName failed" ); + + return offset; + } + catch( std::exception &e ) + { + g_Ext->Out( "pykd error: %s\n", e.what() ); + } + catch(...) + { + g_Ext->Out( "pykd unexpected error\n" ); + } + + return (ULONG64)~0; +} + +///////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/pykd/dbgsym.h b/pykd/dbgsym.h new file mode 100644 index 0000000..864d441 --- /dev/null +++ b/pykd/dbgsym.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +#include +#include + +///////////////////////////////////////////////////////////////////////////////// + +boost::python::object +findSymbolForAddress( ULONG64 addr ); + +ULONG64 +findAddressForSymbol( const std::string &moduleName, const std::string &symbolName ); + +///////////////////////////////////////////////////////////////////////////////// diff --git a/pykd/dbgsystem.cpp b/pykd/dbgsystem.cpp new file mode 100644 index 0000000..d51f058 --- /dev/null +++ b/pykd/dbgsystem.cpp @@ -0,0 +1,33 @@ +#include "stdafx.h" + +#include +#include + +#include "dbgsystem.h" + +///////////////////////////////////////////////////////////////////////////////// + +bool +is64bitSystem() +{ + HRESULT hres; + + try { + hres = g_Ext->m_Control->IsPointer64Bit(); + + return hres == S_OK; + + } + catch( std::exception &e ) + { + g_Ext->Out( "pykd error: %s\n", e.what() ); + } + catch(...) + { + g_Ext->Out( "pykd unexpected error\n" ); + } + + return false; +} + +///////////////////////////////////////////////////////////////////////////////// diff --git a/pykd/dbgsystem.h b/pykd/dbgsystem.h new file mode 100644 index 0000000..7342852 --- /dev/null +++ b/pykd/dbgsystem.h @@ -0,0 +1,14 @@ +#pragma once + +///////////////////////////////////////////////////////////////////////////////// + +bool +is64bitSystem(); + +inline +int +ptrSize() { + return is64bitSystem() ? 8 : 4; +} + +///////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/pykd/dbgtype.cpp b/pykd/dbgtype.cpp new file mode 100644 index 0000000..ebdf3e4 --- /dev/null +++ b/pykd/dbgtype.cpp @@ -0,0 +1,266 @@ +#include "stdafx.h" + +#include + +#include "dbgtype.h" +#include "dbgexcept.h" +#include "dbgmem.h" +#include "dbgsystem.h" + +using namespace std; + +bool +isBaseType( const std::string &typeName ); + +boost::python::object +loadBaseType( const std::string &typeName, ULONG64 address, ULONG size ); + +typedef +boost::python::object +(*basicTypeLoader)( ULONG64 address, ULONG size ); + +boost::python::object +voidLoader( ULONG64 address, ULONG size ) { + return boost::python::object(); +} + +template< typename valType> +boost::python::object +valueLoader( ULONG64 address, ULONG size ); + +template<> +boost::python::object +valueLoader( ULONG64 address, ULONG size ) +{ + if ( is64bitSystem() ) + return valueLoader<__int64>( address, size ); + else + return valueLoader( address, size ); +} + +static const char* +basicTypeNames[] = { + "unsigned char", + "char", + "unsigned short", + "short", + "unsigned long", + "long", + "", + "void" +}; + +basicTypeLoader basicTypeLoaders[] = { + valueLoader, + valueLoader, + valueLoader, + valueLoader, + valueLoader, + valueLoader, + valueLoader, + voidLoader }; + +/////////////////////////////////////////////////////////////////////////////////// +// +boost::python::object +loadTypedVar( const std::string &moduleName, const std::string &typeName, ULONG64 address ) +{ + HRESULT hres; + + try { + + ULONG64 moduleBase; + + if ( typeName.find("*") < typeName.size() ) + { + return valueLoader( address, ptrSize() ); + } + + hres = g_Ext->m_Symbols->GetModuleByModuleName( moduleName.c_str(), 0, NULL, &moduleBase ); + if ( FAILED( hres ) ) + throw DbgException( "IDebugSymbol::GetModuleByModuleName failed" ); + + ULONG typeId; + hres = g_Ext->m_Symbols->GetTypeId( moduleBase, typeName.c_str(), &typeId ); + if ( FAILED( hres ) ) + throw DbgException( "IDebugSymbol::GetTypeId failed" ); + + typedVarClass temp( address ); + boost::python::object var( temp ); + + for ( ULONG i = 0; ; ++i ) + { + char fieldName[100]; + hres = g_Ext->m_Symbols2->GetFieldName( moduleBase, typeId, i, fieldName, sizeof(fieldName), NULL ); + + if ( FAILED( hres ) ) + break; + + ULONG fieldTypeId; + ULONG fieldOffset; + hres = g_Ext->m_Symbols3->GetFieldTypeAndOffset( moduleBase, typeId, fieldName, &fieldTypeId, &fieldOffset ); + + if ( FAILED( hres ) ) + throw DbgException( "IDebugSymbol3::GetFieldTypeAndOffset failed" ); + + char fieldTypeName[100]; + hres = g_Ext->m_Symbols->GetTypeName( moduleBase, fieldTypeId, fieldTypeName, sizeof(fieldTypeName), NULL ); + + ULONG fieldSize; + hres = g_Ext->m_Symbols->GetTypeSize( moduleBase, fieldTypeId, &fieldSize ); + + if ( FAILED( hres ) ) + throw DbgException( "IDebugSymbol::GetTypeName failed" ); + + if ( isBaseType( fieldTypeName ) ) + { + var.attr( fieldName ) = loadBaseType( fieldTypeName, address + fieldOffset, fieldSize ); + } + else + { + var.attr( fieldName ) = loadTypedVar( moduleName, fieldTypeName, address + fieldOffset ); + } + } + + return var; + } + + catch( std::exception &e ) + { + g_Ext->Out( "pykd error: %s\n", e.what() ); + } + catch(...) + { + g_Ext->Out( "pykd unexpected error\n" ); + } + + return boost::python::str( "VAR_ERR" ); +} + +/////////////////////////////////////////////////////////////////////////////////// + +boost::python::object +containingRecord( ULONG64 address, const std::string &moduleName, const std::string &typeName, const std::string &fieldName ) +{ + HRESULT hres; + + try { + + ULONG64 moduleBase; + + hres = g_Ext->m_Symbols->GetModuleByModuleName( moduleName.c_str(), 0, NULL, &moduleBase ); + if ( FAILED( hres ) ) + throw DbgException( "IDebugSymbol::GetModuleByModuleName failed" ); + + ULONG typeId; + hres = g_Ext->m_Symbols->GetTypeId( moduleBase, typeName.c_str(), &typeId ); + if ( FAILED( hres ) ) + throw DbgException( "IDebugSymbol::GetTypeId failed" ); + + ULONG fieldTypeId; + ULONG fieldOffset; + hres = g_Ext->m_Symbols3->GetFieldTypeAndOffset( moduleBase, typeId, fieldName.c_str(), &fieldTypeId, &fieldOffset ); + + return loadTypedVar( moduleName, typeName, address - fieldOffset ); + } + + catch( std::exception &e ) + { + g_Ext->Out( "pykd error: %s\n", e.what() ); + } + catch(...) + { + g_Ext->Out( "pykd unexpected error\n" ); + } + + return boost::python::str( "VAR_ERR" ); +} + +/////////////////////////////////////////////////////////////////////////////////// + +bool +isBaseType( const std::string &typeName ) +{ + for ( int i = 0; i < sizeof( basicTypeNames ) / sizeof( char* ); ++i ) + { + if ( typeName == basicTypeNames[i] ) + return true; + + if ( typeName == ( std::string( basicTypeNames[i] ) + "*" ) ) + return true; + + if ( typeName == ( std::string( basicTypeNames[i] ) + "[]" ) ) + return true; + + if ( typeName == ( std::string( basicTypeNames[i] ) + "*[]" ) ) + return true; + } + + return false; +} + +/////////////////////////////////////////////////////////////////////////////////// + +boost::python::object +loadBaseType( const std::string &typeName, ULONG64 address, ULONG size ) +{ + for ( int i = 0; i < sizeof( basicTypeNames ) / sizeof( char* ); ++i ) + { + if ( typeName == basicTypeNames[i] ) + return basicTypeLoaders[i]( address, size ); + + if ( typeName == ( std::string( basicTypeNames[i] ) + "*" ) ) + return valueLoader( address, size ); + + if ( typeName == ( std::string( basicTypeNames[i] ) + "[]" ) ) + return basicTypeLoaders[i]( address, size ); + + if ( typeName == ( std::string( basicTypeNames[i] ) + "*[]" ) ) + return valueLoader( address, size ); + } + + return boost::python::object(); +} + +/////////////////////////////////////////////////////////////////////////////////// + + + +template< typename valType> +boost::python::object +valueLoader( ULONG64 address, ULONG size ) +{ + if ( size == sizeof(valType) ) + { + valType v; + if ( loadMemory( address, &v, sizeof(v) ) ) + return boost::python::long_( (unsigned __int64)v ); + } + else + { + boost::python::dict arr; + + for ( int i = 0; i < size / sizeof(valType); ++i ) + { + valType v; + if ( !loadMemory( address + i * sizeof(valType), &v, sizeof(v) ) ) + return boost::python::object(); + + arr[i] = boost::python::long_( (unsigned __int64)v ); + } + + return arr; + } + + return boost::python::object(); +} + +/////////////////////////////////////////////////////////////////////////////////// + +boost::python::object +loadComplexType( const std::string &typeName, ULONG64 address, ULONG size ) +{ + return boost::python::object(); +} + +/////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/pykd/dbgtype.h b/pykd/dbgtype.h new file mode 100644 index 0000000..631e1ab --- /dev/null +++ b/pykd/dbgtype.h @@ -0,0 +1,41 @@ +#pragma once + +#include + +#include +#include + +///////////////////////////////////////////////////////////////////////////////// + +class typedVarClass { + +public: + + typedVarClass() + {} + + typedVarClass( ULONG64 addr ) : + m_addr( addr ) + {} + + ULONG64 + getAddress() const { + return m_addr; + } + +private: + + ULONG64 m_addr; + +}; + +///////////////////////////////////////////////////////////////////////////////// + +boost::python::object +loadTypedVar( const std::string &moduleName, const std::string &typeName, ULONG64 address ); + +boost::python::object +containingRecord( ULONG64 address, const std::string &moduleName, const std::string &typeName, const std::string &fieldName ); + + +///////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/pykd/pykd.cpp b/pykd/pykd.cpp new file mode 100644 index 0000000..e69de29 diff --git a/pykd/pykd.def b/pykd/pykd.def new file mode 100644 index 0000000..38ab092 --- /dev/null +++ b/pykd/pykd.def @@ -0,0 +1,6 @@ +EXPORTS + DebugExtensionInitialize + DebugExtensionUninitialize + + info + exec \ No newline at end of file diff --git a/pykd/pykd.suo b/pykd/pykd.suo new file mode 100644 index 0000000..21746f0 Binary files /dev/null and b/pykd/pykd.suo differ diff --git a/pykd/pykd.vcproj b/pykd/pykd.vcproj new file mode 100644 index 0000000..1e3e898 --- /dev/null +++ b/pykd/pykd.vcproj @@ -0,0 +1,488 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pykd/stdafx.cpp b/pykd/stdafx.cpp new file mode 100644 index 0000000..b1373b9 --- /dev/null +++ b/pykd/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// pykd.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/pykd/stdafx.h b/pykd/stdafx.h new file mode 100644 index 0000000..b1739cf --- /dev/null +++ b/pykd/stdafx.h @@ -0,0 +1,35 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +// Modify the following defines if you have to target a platform prior to the ones specified below. +// Refer to MSDN for the latest info on corresponding values for different platforms. +#ifndef WINVER // Allow use of features specific to Windows XP or later. +#define WINVER 0x0501 // Change this to the appropriate value to target other versions of Windows. +#endif + +#ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later. +#define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows. +#endif + +#ifndef _WIN32_WINDOWS // Allow use of features specific to Windows 98 or later. +#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later. +#endif + +#ifndef _WIN32_IE // Allow use of features specific to IE 6.0 or later. +#define _WIN32_IE 0x0600 // Change this to the appropriate value to target other versions of IE. +#endif + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files: +#include + +#define __field_ecount_opt(x) + + +#define BOOST_PYTHON_STATIC_LIB + +// TODO: reference additional headers your program requires here diff --git a/test/print.py b/test/print.py new file mode 100644 index 0000000..e2b4b4f --- /dev/null +++ b/test/print.py @@ -0,0 +1,8 @@ +from pykd import * + +dprint ( "hello windbg!\n" ) +dprintln ( "hello windbg!" ) +hello = "hello windbg!" +dprintln( hello ) +dprintln( hello + " from python" ) + diff --git a/test/regs.py b/test/regs.py new file mode 100644 index 0000000..f990d79 --- /dev/null +++ b/test/regs.py @@ -0,0 +1,16 @@ +from pykd import * + + +dprintln( "regs tests begin" ) + +al = reg("al") +ax = reg("ax") +eax = reg("eax") + + +dprintln( "al: " + str(al) ) +dprintln( "ax: " + str(ax) ) +dprintln( "eax: " + str(eax) ) + + +dprintln( "regs tests end" ) \ No newline at end of file diff --git a/test/type.py b/test/type.py new file mode 100644 index 0000000..04390ec --- /dev/null +++ b/test/type.py @@ -0,0 +1,13 @@ +from pykd import * + +dprintln( "type test begin" ) + +idtr=reg("idtr") + +var = typedVar( "nt", "_KIDTENTRY", idtr ) + +for t, v in var.iteritems(): + dprintln( t + " : " + str(v) ) + + +dprintln( "type test end" ) \ No newline at end of file