NonSoft

PasswordChar(*)に隠れた実際のパスワードを表示
するサンプル(VB.NET)


 サンプル(ソース/コード)
<このサンプルの概要>
以前自分で入力したパスワードを忘れてしまい困った事が無いでしょうか?
パスワードの設定画面を見てもパスワードがアスタリスク(***)に変換されて表示されるため
確認出来ません。そんな時に役立つのが「パスワードを見るツール」ですが、
ブラウザ以外のウィンドウで表示されているパスワードは意外に簡単に表示する事が出来ます。
このサンプルはその「パスワードを見るサンプル」です。

パスワード表示ツール(SeePasswd)はこのサンプルを元にブラウザ(IE)のパスワードを表示出来る
ようにしたツールです。パスワードが見れた後はパスワードをデータベースに登録して管理
したくなると思うので、パスワード管理ツールと連携する機能があります。

具体的にはPasswordChar(*)が設定されたTextBoxから実際のパスワードを取得し表示します。
このサンプルのポイントとなるキーワードは以下の通りです。
(1)PostMessage
(2)SendMessage
(3)EM_GETPASSWORDCHAR
(4)EM_SETPASSWORDCHAR

このサンプルには含まれていませんが、IEのパスワードを調べる方法の概略は以下の通りです。
(1)ブラウザ(IE)のクラス名[Internet Explorer_Server]を探す。
(2)[WM_HTML_GETOBJECT]メッセージを[Internet Explorer_Server]に送る。
(3)[IID_IHTMLDocument]オブジェクトを取得する。
(4)[IID_IHTMLDocument]オブジェクトの[getElementsByTagName]で全てのタグを取得する。
(5)[INPUT]タグの[TYPE]が[password]のものからパスワードを取得する。
ただし(4)、(5)の処理を全てのフレームに対し実行する必要があります。
IEのパスワードを表示するツールの中にはフレーム未対応のものがあり、
そのツールでは表示出来無いパスワードがありました。

※転載等色々禁止させてください。
※個人利用の参考としてのみご覧ください。
※決して悪用はしないでください。

★標準モジュール(Module1.vb)
Module Module1
    ' APIの定義
    Private Const WM_GETTEXT = &HD
    Private Const EM_GETPASSWORDCHAR = &HD2
    Private Const EM_SETPASSWORDCHAR = &HCC
    Private Delegate Function D_EnumWindowsProc *** As Integer
    Private Delegate Function D_EnumChildWindowsProc *** As Integer
    Private Declare Function EnumWindows Lib "user32.dll" _
        (ByVal lpEnumFunc As D_EnumWindowsProc, ByVal lParam As Integer) As Integer
    Private Declare Function EnumChildWindows Lib "user32.dll" _
        (ByVal hwndParent As Integer, ByVal lpEnumFunc As D_EnumChildWindowsProc, _
         ByVal lParam As Integer) As Integer
    Private Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" _
        (ByVal hWnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, _
         ByVal lParam As Byte()) As Integer
    Private Declare Function PostMessage Lib "user32.dll" Alias "PostMessageA" _
        (ByVal hWnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, _
         ByVal lParam As Byte()) As Integer

    ' パスワードを取得するコレクション
    Private colPasswd As New Collection

    ' 表示中の全てのパスワードを取得
    Public Function GetAllPasswd() As Collection
        Try
            ' パスワードを取得するコレクション初期化
            colPasswd.Clear()

            ' トップレベルウィンドウの全てハンドル取得して、そこに属するパスワードを全て取得
            Dim intRet As Integer = EnumWindows(AddressOf EnumWindowsProc, 0)
        Catch ex As Exception
        End Try

        ' リターン
        Return colPasswd
    End Function

    ' トップレベルウィンドウの全てハンドル取得して、そこに属するパスワードを全て取得
    Public Function EnumWindowsProc( _
        ByVal hWnd As Integer, ByVal lParam As Integer) As Integer
        Try
            ' 指定された親ウィンドウに属するパスワードを全て取得
            Dim intRet As Integer = EnumChildWindows(hWnd, AddressOf EnumChildWindowsProc, 0)
        Catch ex As Exception
        End Try

        ' リターン
        Return 1
    End Function

    ' 指定された親ウィンドウに属するパスワードを全て取得
    Private Function EnumChildWindowsProc( _
        ByVal hWnd As Integer, ByVal lParam As Integer) As Integer
        Try
            Dim bytPasswd As Byte() = New Byte(255) {}
            Dim strPasswd As String = ""
            Dim intRet As Integer

            ' パスワード文字が設定されているかチェック
            Dim pch As Integer = SendMessage(hWnd, EM_GETPASSWORDCHAR, 0, Nothing)
            If pch <> 0 Then
                ' パスワード文字を無効
                For i As Integer = 0 To 10
                    PostMessage(hWnd, EM_SETPASSWORDCHAR, 0, Nothing)
                    Application.DoEvents()
                    If SendMessage(hWnd, EM_GETPASSWORDCHAR, 0, Nothing) = 0 Then Exit For
                    System.Threading.Thread.Sleep(100)
                Next

                ' パスワード文字列取得
                intRet = SendMessage(hWnd, WM_GETTEXT, 255, bytPasswd)
                strPasswd = StripNulls(bytPasswd)

                ' パスワード文字を有効
                For i As Integer = 0 To 10
                    PostMessage(hWnd, EM_SETPASSWORDCHAR, pch, Nothing)
                    Application.DoEvents()
                    If SendMessage(hWnd, EM_GETPASSWORDCHAR, 0, Nothing) = pch Then Exit For
                    System.Threading.Thread.Sleep(100)
                Next

                ' パスワードを取得するコレクションにパスワードを追加
                If strPasswd <> "" Then
                    colPasswd.Add(strPasswd)
                End If
            End If
        Catch ex As Exception
        End Try

        ' リターン
        Return 1
    End Function

    ' 文字列からNULL文字以降をカット
    Private Function StripNulls(ByVal bytOrg As Byte()) As String
        Dim strOrg As String = ""
        Try
            strOrg = System.Text.Encoding.GetEncoding("SHIFT-JIS").GetString(bytOrg)
            Dim pt As Integer = strOrg.IndexOf(Chr(0))
            If pt >= 0 Then
                strOrg = strOrg.Substring(0, pt)
            End If
        Catch ex As Exception
        End Try
        Return strOrg
    End Function
End Module

★フォームモジュール(Form1.vb)
Public Class Form1
    Private Sub Button1_Click( _
        ByVal sender As System.Object, ByVal e As System.EventArgs) _
        Handles Button1.Click
        ' 表示中の全てのパスワードを取得
        Dim colPasswd As Collection
        colPasswd = GetAllPasswd()

        ' パスワード有無チェック
        If colPasswd.Count <= 0 Then
            MessageBox.Show("パスワードはありませんでした。")
            Return
        End If

        ' パスワード毎のコレクションループ
        For i As Integer = 1 To colPasswd.Count
            ' パスワードの表示
            MessageBox.Show(colPasswd.Item(i))
        Next i
    End Sub
End Class