NonSoft

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

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

パスワード表示&管理ツールはこのサンプルを元にブラウザ(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