Beispiel #1
0
HRESULT GetImageInfoFromPEHeader( HANDLE hProcess, void* dllBase, uint16_t& machine, uint32_t& size, Address& prefBase )
{
    IMAGE_DOS_HEADER    dosHeader = { 0 };
    SIZE_T              cActual = 0;

    if ( !::ReadProcessMemory( hProcess, dllBase, &dosHeader, sizeof dosHeader, &cActual ) ) 
    {
        _ASSERT( !"Failed to read IMAGE_DOS_HEADER from loaded module" );
        return GetLastHr();
    }

    IMAGE_NT_HEADERS    ntHeaders = { 0 };
    void*               ntHeadersAddr = (void*) ((DWORD_PTR) dosHeader.e_lfanew + (DWORD_PTR) dllBase);
    
    if ( !::ReadProcessMemory( hProcess, ntHeadersAddr, &ntHeaders, sizeof ntHeaders, &cActual ) ) 
    {
        _ASSERT( !"Failed to read IMAGE_NT_HEADERS from loaded module" );
        return GetLastHr();
    }

    // These fields line up for 32 and 64-bit IMAGE_NT_HEADERS; make sure of it
    // otherwise, we would have had to check fileHeader.Characteristics & IMAGE_FILE_32BIT_MACHINE
    C_ASSERT( &((IMAGE_NT_HEADERS32*) 0)->OptionalHeader.SizeOfImage == 
              &((IMAGE_NT_HEADERS64*) 0)->OptionalHeader.SizeOfImage );
    C_ASSERT( &((IMAGE_NT_HEADERS32*) 0)->FileHeader.Machine == 
              &((IMAGE_NT_HEADERS64*) 0)->FileHeader.Machine );

    machine = ntHeaders.FileHeader.Machine;
    size = ntHeaders.OptionalHeader.SizeOfImage;
    prefBase = ntHeaders.OptionalHeader.ImageBase;

    return S_OK;
}
Beispiel #2
0
    HRESULT DebuggerProxy::Init( IEventCallback* callback )
    {
        _ASSERT( callback != NULL );
        if ( (callback == NULL ) )
            return E_INVALIDARG;
        if ( (mCallback != NULL ) )
            return E_ALREADY_INIT;

        HandlePtr   hReadyEvent;
        HandlePtr   hCommandEvent;
        HandlePtr   hResultEvent;

        hReadyEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
        if ( hReadyEvent.IsEmpty() )
            return GetLastHr();

        hCommandEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
        if ( hCommandEvent.IsEmpty() )
            return GetLastHr();

        hResultEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
        if ( hResultEvent.IsEmpty() )
            return GetLastHr();

        mhReadyEvent = hReadyEvent.Detach();
        mhCommandEvent = hCommandEvent.Detach();
        mhResultEvent = hResultEvent.Detach();

        mCallback = callback;
        mCallback->AddRef();

        return S_OK;
    }
Beispiel #3
0
    HRESULT DebuggerProxy::InvokeCommand( CommandFunctor& cmd )
    {
        if ( mWorkerTid == GetCurrentThreadId() )
        {
            // since we're on the poll thread, we can run the command directly
            cmd.Run();
        }
        else
        {
            GuardedArea area( mCommandGuard );

            mCurCommand = &cmd;

            ResetEvent( mhResultEvent );
            SetEvent( mhCommandEvent );

            DWORD   waitRet = 0;
            HANDLE  handles[2] = { mhResultEvent, mhThread };

            waitRet = WaitForMultipleObjects( _countof( handles ), handles, FALSE, INFINITE );
            mCurCommand = NULL;
            if ( waitRet == WAIT_FAILED )
                return GetLastHr();

            if ( waitRet == WAIT_OBJECT_0 + 1 )
                return CO_E_REMOTE_COMMUNICATION_FAILURE;
        }

        return S_OK;
    }
Beispiel #4
0
    HRESULT ImageDebugContainer::LockDebugSection( BYTE*& bytes, DWORD& size )
    {
        HRESULT     hr = S_OK;
        HandlePtr   hMapping;
        DWORD       viewAlignedAddr = 0;
        DWORD       viewDiff = 0;
        MappedPtr   view;

        if ( mImage.get() != NULL )
        {
            hr = mImage->GetMappingHandle( hMapping.Ref() );
        }
        else if ( mDbg.get() != NULL )
        {
            hr = mDbg->GetMappingHandle( hMapping.Ref() );
        }
        else
            hr = E_FAIL;

        if ( FAILED( hr ) )
            return hr;

        AlignAddress( mDebugDir.PointerToRawData, viewAlignedAddr, viewDiff );

        view = MapViewOfFile( hMapping, FILE_MAP_READ, 0, viewAlignedAddr, mDebugDir.SizeOfData + viewDiff );
        if ( view.IsEmpty() )
            return GetLastHr();

        bytes = (BYTE*) view.Detach() + viewDiff;
        size = mDebugDir.SizeOfData;

        return S_OK;
    }
Beispiel #5
0
    HRESULT ImageDebugContainer::UnlockDebugSection( BYTE* bytes )
    {
        BOOL    bRet = UnmapViewOfFile( bytes );
        if ( !bRet )
            return GetLastHr();

        return S_OK;
    }
Beispiel #6
0
    HRESULT DebuggerProxy::Start()
    {
        _ASSERT( mCallback != NULL );
        if ( (mCallback == NULL ) )
            return E_UNEXPECTED;
        if ( mhThread != NULL )
            return E_UNEXPECTED;

        HandlePtr   hThread;

        hThread = (HANDLE) _beginthreadex(
            NULL,
            0,
            (CrtThreadProc) DebugPollProc,
            this,
            0,
            NULL );
        if ( hThread.IsEmpty() )
            return GetLastHr();

        HANDLE      waitObjs[2] = { mhReadyEvent, hThread.Get() };
        DWORD       waitRet = 0;

        // TODO: on error, thread will be shutdown from Shutdown method

        waitRet = WaitForMultipleObjects( _countof( waitObjs ), waitObjs, FALSE, INFINITE );
        if ( waitRet == WAIT_FAILED )
            return GetLastHr();

        if ( waitRet == WAIT_OBJECT_0 + 1 )
        {
            DWORD   exitCode = (DWORD) E_FAIL;

            // the thread ended because of an error, let's get the return exit code
            GetExitCodeThread( hThread.Get(), &exitCode );

            return (HRESULT) exitCode;
        }
        _ASSERT( waitRet == WAIT_OBJECT_0 );

        mhThread = hThread.Detach();

        return S_OK;
    }
Beispiel #7
0
    HRESULT ImageDebugContainer::LoadExe( const wchar_t* filename, ILoadCallback* callback )
    {
        HRESULT     hr = S_OK;
        auto_ptr<ImageFile>   image( new ImageFile() );
        DataDirInfo dirInfo = { 0 };
        HandlePtr   hMapping;
        DWORD       viewAlignedAddr = 0;
        DWORD       viewDiff = 0;
        MappedPtr   view;
        DWORD       debugDirCount = 0;
        IMAGE_DEBUG_DIRECTORY*  debugDir = NULL;

        if ( image.get() == NULL )
            return E_OUTOFMEMORY;

        hr = image->LoadFile( filename );
        if ( FAILED( hr ) )
            return hr;

        if ( !image->FindDataDirectoryData( IMAGE_DIRECTORY_ENTRY_DEBUG, dirInfo ) )
            return E_FAIL;

        hr = image->GetMappingHandle( hMapping.Ref() );
        if ( FAILED( hr ) )
            return hr;

        AlignAddress( dirInfo.FileOffset, viewAlignedAddr, viewDiff );

        view = MapViewOfFile( hMapping, FILE_MAP_READ, 0, viewAlignedAddr, dirInfo.Size + viewDiff );
        if ( view.IsEmpty() )
            return GetLastHr();

        debugDir = (IMAGE_DEBUG_DIRECTORY*) ((BYTE*) view.Get() + viewDiff);

        if ( callback != NULL )
            callback->NotifyDebugDir( true, dirInfo.Size, (BYTE*) debugDir );

        for ( debugDirCount = dirInfo.Size / sizeof *debugDir; debugDirCount > 0; debugDirCount--, debugDir++ )
        {
            if ( (debugDir->Type == IMAGE_DEBUG_TYPE_CODEVIEW)
                || (debugDir->Type == IMAGE_DEBUG_TYPE_MISC) )
                break;
        }

        if ( debugDirCount == 0 )
            return HRESULT_FROM_WIN32( ERROR_NOT_FOUND );

        if ( debugDir->Type == IMAGE_DEBUG_TYPE_MISC )
            return LoadDbg( image.get(), debugDir, callback );

        mDebugDir = *debugDir;
        mImage.reset( image.release() );

        return S_OK;
    }
Beispiel #8
0
    HRESULT DebuggerProxy::CheckMessage()
    {
        HRESULT hr = S_OK;
        DWORD   waitRet = 0;

        waitRet = WaitForSingleObject( mhCommandEvent, CommandTimeoutMillis );
        if ( waitRet == WAIT_FAILED )
            return GetLastHr();

        if ( waitRet == WAIT_TIMEOUT )
            return S_OK;

        hr = ProcessCommand( mCurCommand );
        if ( FAILED( hr ) )
            return hr;

        ResetEvent( mhCommandEvent );
        SetEvent( mhResultEvent );

        return S_OK;
    }
Beispiel #9
0
HRESULT ReadMemory( 
   HANDLE hProcess, 
   UINT_PTR address, 
   SIZE_T length, 
   SIZE_T& lengthRead, 
   SIZE_T& lengthUnreadable, 
   uint8_t* buffer )
{
    _ASSERT( hProcess != NULL );
    _ASSERT( buffer != NULL );
    _ASSERT( length < limit_max( length ) );

    HRESULT hr = S_OK;
    BOOL    bRet = FALSE;

    MEMORY_BASIC_INFORMATION    memInfo = { 0 };
    SIZE_T      sizeRet = 0;
    SIZE_T      lenReadable = 0;
    SIZE_T      lenUnreadable = 0;
    UINT_PTR    nextAddr = address;

    while ( ((lenReadable + lenUnreadable) < length) && (nextAddr >= address) )
    {
        bool    readable = true;

        sizeRet = VirtualQueryEx( hProcess, (void*) nextAddr, &memInfo, sizeof memInfo );
        if ( sizeRet == 0 )
            return HRESULT_FROM_WIN32( ERROR_PARTIAL_COPY );

        if ( (memInfo.State != MEM_COMMIT)
            || (memInfo.Protect == 0)
            || ((memInfo.Protect & PAGE_NOACCESS) != 0) )
            readable = false;

        SIZE_T  curSize = memInfo.RegionSize - (nextAddr - (UINT_PTR) memInfo.BaseAddress);

        if ( readable )
        {
            // we went from (readable to) unreadable to readable, 
            // this last readable won't be returned, so we finished
            if ( lenUnreadable > 0 )
                break;

            lenReadable += curSize;
        }
        else
        {
            lenUnreadable += curSize;
        }

        nextAddr = (UINT_PTR) memInfo.BaseAddress + memInfo.RegionSize;
    }
    
    // cap the length to read to the length the user asked for
    SIZE_T  lenToRead = (lenReadable > length) ? length : lenReadable;

    bRet = ::ReadProcessMemory( 
        hProcess, 
        (const void*) address, 
        buffer, 
        lenToRead, 
        &lengthRead );
    if ( !bRet )
        return GetLastHr();

    lengthUnreadable = (lenUnreadable > (length - lengthRead)) ? length - lengthRead : lenUnreadable;

    _ASSERT( lengthRead <= length );
    _ASSERT( lengthUnreadable <= length );
    _ASSERT( (lengthRead + lengthUnreadable) <= length );

    return hr;
}
Beispiel #10
0
    HRESULT ImageDebugContainer::LoadDbg( 
        BinImage::ImageFile* image, 
        const IMAGE_DEBUG_DIRECTORY* miscDebugDir, 
        ILoadCallback* callback )
    {
        _ASSERT( image != NULL );
        _ASSERT( miscDebugDir != NULL );

        HRESULT     hr = S_OK;
        HandlePtr   hMapping;
        DWORD       viewAlignedAddr = 0;
        DWORD       viewDiff = 0;
        MappedPtr   view;
        IMAGE_DEBUG_MISC*       misc = NULL;
        UniquePtr<wchar_t[]>    strBuf;
        DWORD       dataLen = 0;

        if ( miscDebugDir->SizeOfData < sizeof( IMAGE_DEBUG_MISC ) )
            return E_FAIL;

        hr = image->GetMappingHandle( hMapping.Ref() );
        if ( FAILED( hr ) )
            return hr;

        AlignAddress( miscDebugDir->PointerToRawData, viewAlignedAddr, viewDiff );

        view = MapViewOfFile( hMapping, FILE_MAP_READ, 0, viewAlignedAddr, miscDebugDir->SizeOfData + viewDiff );
        if ( view.IsEmpty() )
            return GetLastHr();

        misc = (IMAGE_DEBUG_MISC*) view.Get();
        dataLen = misc->Length - offsetof( IMAGE_DEBUG_MISC, Data );

        if ( misc->DataType != IMAGE_DEBUG_MISC_EXENAME )
            return E_FAIL;

        // I don't know that the string in data is definitely \0 terminated, so we force it
        if ( misc->Unicode )
        {
            size_t  charCount = wcsnlen( (wchar_t*) misc->Data, dataLen / sizeof( wchar_t ) );

            // TODO: why were we calling wcsnlen twice?
            //charCount = wcsnlen( (wchar_t*) misc->Data, charCount );
            strBuf.Attach( new wchar_t[ charCount + 1 ] );
            if ( strBuf.Get() == NULL )
                return E_OUTOFMEMORY;

            // adds terminator
            wcsncpy_s( strBuf.Get(), charCount + 1, (wchar_t*) misc->Data, charCount );
        }
        else
        {
            size_t  charCount = strnlen( (char*) misc->Data, dataLen );
            int     nChars = 0;

            nChars = MultiByteToWideChar( 
                CP_ACP, 
                MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
                (char*) misc->Data,
                charCount,
                NULL,
                0 );
            if ( nChars == 0 )
                return GetLastHr();

            strBuf.Attach( new wchar_t[ nChars + 1 ] );
            if ( strBuf.Get() == NULL )
                return E_OUTOFMEMORY;

            nChars = MultiByteToWideChar( 
                CP_ACP, 
                MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
                (char*) misc->Data,
                charCount,
                strBuf.Get(),
                nChars + 1 );
            if ( nChars == 0 )
                return GetLastHr();

            strBuf[nChars] = L'\0';
        }

        hr = LoadDbg( strBuf.Get(), callback );

        return hr;
    }