Excel VBA マクロ パスワードを解除する方法 32ビット 64ビット
Excel VBAでパスワードロックを解除する方法です。コードをコピペすれば簡単に解除できます。
VBAProjectのパスワードは、プログラムの解析を保護するために設定することができます。
ずいぶん前にも同様の内容で記事を書きましたが、今回久しぶりに「VBAパスワード解除の案件」があったので、改めて記事にしておきたいと思います。
ここでは Excel VBAでパスワードロックを解除する方法 を紹介します。
目次
VBAProject パスワードとは?
VBAProject パスワードとは、VBAProjectのプロパティから設定できる「プロジェクトのロック」に設定されたパスワードのことです。
パスワードが設定されると、プロジェクトのプロパティが見れなくなります。
ソースコードの解析を保護できる反面、設定した人しかパスワードがわからないため、トラブルの原因にもなります。「パスワードを忘れてしまった」「開発者が退職し、パスワードがわからない」が主な理由です。
本記事でできること
VBAProjectパスワードを解除することができます。概要を簡単に説明します。
- 新たにマクロ有効ブック(xlsm)を作る。
- 標準モジュールを挿入し、コードを貼り付ける。
- コードを実行してパスワードを解除する。
基本的には、後述するコードをコピペすればOKです。プログラムによって解除するというものです。パスワードを解除し、ソースコードは確認できますが、パスワードがなんだったのかは把握できません。
くれぐれも悪用したり、他人の著作物を覗き見るような不正はしないでください。
検証したExcelのバージョン
VBAProject パスワードの解除について、検証したOSはWindows 10です。Excelのバージョンは、Excel 2019 / 2016で検証しています。ファイル形式は xlsm / xls です。
以前の記事でExcel 2010 / 2013でも動作検証済です。
Excelが32ビット版か64ビット版か確認する
パスワード解除の方法は、32ビット版と64ビット版でやり方が違います。事前にどちらか確認しておきましょう。
Excelを開いて「ファイル」-「アカウント」から「Excelのバージョン情報」をクリックすると、下記の画面が出てきます。
赤枠の部分に詳細なバージョンが書いてあるので確認してください。
バックアップをする
万が一に備え、移行の操作をする前に、該当の Excel ブックはどこかにコピーをバックアップしておいてください。ファイルが破損する可能性があります。
全て自己責任において実施してください。当方では一切の責任を負いません。
VBAパスワードを解除する
準備が整ったらVBAのパスワードを解除しましょう。
まずは「ロック解除用のExcelブック(xlsm)」を作り、「ロックされたExcelブック」と同じフォルダに入れます。
ロックされたExcelブックは元のファイル名のままでOKです。
下図のように「ロックされたExcelブック」はパスワードロックがかかっています。
次に「ロック解除用のExcelブック」を開きます。プロジェクトを右クリックして「挿入」-「標準モジュール」を追加します。
Excelのバージョンに合わせてコードを貼り付けます。
32ビット版のVBAパスワード解除コード
32ビット版のコードです。
Option Explicit
Private Const PAGE_EXECUTE_READWRITE = &H40
Private Declare Sub MoveMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Long, Source As Long, ByVal Length As Long)
Private Declare Function VirtualProtect Lib "kernel32" (lpAddress As Long, ByVal dwSize As Long, ByVal flNewProtect As Long, lpflOldProtect As Long) As Long
Private Declare Function GetModuleHandleA Lib "kernel32" (ByVal lpModuleName As String) As Long
Private Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As Long
Private Declare Function DialogBoxParam Lib "user32" Alias "DialogBoxParamA" (ByVal hInstance As Long, ByVal pTemplateName As Long, ByVal hWndParent As Long, ByVal lpDialogFunc As Long, ByVal dwInitParam As Long) As Integer
Dim HookBytes(0 To 5) As Byte
Dim OriginBytes(0 To 5) As Byte
Dim pFunc As Long
Dim Flag As Boolean
Private Function GetPtr(ByVal Value As Long) As Long
GetPtr = Value
End Function
Private Sub RecoverBytes()
If Flag Then MoveMemory ByVal pFunc, ByVal VarPtr(OriginBytes(0)), 6
End Sub
Private Function Hook() As Boolean
Dim TmpBytes(0 To 5) As Byte
Dim p As Long
Dim OriginProtect As Long
Hook = False
pFunc = GetProcAddress(GetModuleHandleA("user32.dll"), "DialogBoxParamA")
If VirtualProtect(ByVal pFunc, 6, PAGE_EXECUTE_READWRITE, OriginProtect) <> 0 Then
MoveMemory ByVal VarPtr(TmpBytes(0)), ByVal pFunc, 6
If TmpBytes(0) <> &H68 Then
MoveMemory ByVal VarPtr(OriginBytes(0)), ByVal pFunc, 6
p = GetPtr(AddressOf MyDialogBoxParam)
HookBytes(0) = &H68
MoveMemory ByVal VarPtr(HookBytes(1)), ByVal VarPtr(p), 4
HookBytes(5) = &HC3
MoveMemory ByVal pFunc, ByVal VarPtr(HookBytes(0)), 6
Flag = True
Hook = True
End If
End If
End Function
Private Function MyDialogBoxParam(ByVal hInstance As Long, ByVal pTemplateName As Long, ByVal hWndParent As Long, ByVal lpDialogFunc As Long, ByVal dwInitParam As Long) As Integer
If pTemplateName = 4070 Then
MyDialogBoxParam = 1
Else
RecoverBytes
MyDialogBoxParam = DialogBoxParam(hInstance, pTemplateName, _
hWndParent, lpDialogFunc, dwInitParam)
Hook
End If
End Function
Public Sub VBAProjectパスワード解除()
If Hook Then
MsgBox "VBAProjectのパスワード解除成功!", vbInformation, "Congratulations"
End If
End Sub
64ビット版のVBAパスワード解除コード
64ビット版のコードです。
Option Explicit
Private Const PAGE_EXECUTE_READWRITE = &H40
Private Declare PtrSafe Sub MoveMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As LongPtr, Source As LongPtr, ByVal Length As LongPtr)
Private Declare PtrSafe Function VirtualProtect Lib "kernel32" (lpAddress As LongPtr, ByVal dwSize As LongPtr, ByVal flNewProtect As LongPtr, lpflOldProtect As LongPtr) As LongPtr
Private Declare PtrSafe Function GetModuleHandleA Lib "kernel32" (ByVal lpModuleName As String) As LongPtr
Private Declare PtrSafe Function GetProcAddress Lib "kernel32" (ByVal hModule As LongPtr, ByVal lpProcName As String) As LongPtr
Private Declare PtrSafe Function DialogBoxParam Lib "user32" Alias "DialogBoxParamA" (ByVal hInstance As LongPtr, ByVal pTemplateName As LongPtr, ByVal hWndParent As LongPtr, ByVal lpDialogFunc As LongPtr, ByVal dwInitParam As LongPtr) As Integer
Dim HookBytes(0 To 5) As Byte
Dim OriginBytes(0 To 5) As Byte
Dim pFunc As LongPtr
Dim Flag As Boolean
Private Function GetPtr(ByVal Value As LongPtr) As LongPtr
GetPtr = Value
End Function
Private Sub RecoverBytes()
If Flag Then MoveMemory ByVal pFunc, ByVal VarPtr(OriginBytes(0)), 6
End Sub
Public Function Hook() As Boolean
Dim TmpBytes(0 To 5) As Byte
Dim p As LongPtr
Dim OriginProtect As LongPtr
Hook = False
pFunc = GetProcAddress(GetModuleHandleA("user32.dll"), "DialogBoxParamA")
If VirtualProtect(ByVal pFunc, 6, PAGE_EXECUTE_READWRITE, OriginProtect) <> 0 Then
MoveMemory ByVal VarPtr(TmpBytes(0)), ByVal pFunc, 6
If TmpBytes(0) <> &H68 Then
MoveMemory ByVal VarPtr(OriginBytes(0)), ByVal pFunc, 6
p = GetPtr(AddressOf MyDialogBoxParam)
HookBytes(0) = &H68
MoveMemory ByVal VarPtr(HookBytes(1)), ByVal VarPtr(p), 4
HookBytes(5) = &HC3
MoveMemory ByVal pFunc, ByVal VarPtr(HookBytes(0)), 6
Flag = True
Hook = True
End If
End If
End Function
Private Function MyDialogBoxParam(ByVal hInstance As LongPtr, ByVal pTemplateName As LongPtr, ByVal hWndParent As LongPtr, ByVal lpDialogFunc As LongPtr, ByVal dwInitParam As LongPtr) As Integer
If pTemplateName = 4070 Then
MyDialogBoxParam = 1
Else
RecoverBytes
MyDialogBoxParam = DialogBoxParam(hInstance, pTemplateName, hWndParent, lpDialogFunc, dwInitParam)
Hook
End If
End Function
Public Sub VBAProjectパスワード解除()
If Hook Then
MsgBox "VBAProjectのパスワード解除成功!", vbInformation, "Congratulations"
End If
End Sub
コードを実行する
保存したら「Sub/ユーザー フォームの実行」ボタンをクリックするか、「F5キー」を押します。
「VBAProjectパスワード解除」のメソッドを実行します。
「VBAProjectのパスワード解除成功!」メッセージが出ればパスワードロックは解除されています。
パスワードロックされたVBAProjectを開いてみると・・・。
おおおおー、パスワードロックが解除されたー。
VBAパスワードロック解除後にやること
VBAProjectのパスワードロックが解除されたら、必ず下図のように「プロジェクトのロック」のチェックを外してください。
これをやらないと、保存して閉じてもパスワードが再度設定されてしまいます。
ちなみに、新しいパスワードを設定して保存はできません。パスワードを再設定して閉じて開くと、新しいパスワードでは解除できず、古いパスワードが必要となります。どうやら前のパスワードが内部で残るようですね。ふしぎ・・。
64ビット版のコードを実行すると強制終了となる
パスワード解除成功のメッセージが出た後に、パスワードがかかっているVBA Projectを開こうとした際、「Microsft Excelは動作を停止しました」となるケースがあるようです。
メッセージなしで強制終了するパターンもあり
どうも64ビット版のコードは動作不安定なようです。こちらで検証した結果、64ビット版で作ったファイルでも、32ビット版のコードでパスワード解除できました。周囲にExcel 32ビット版を使われている方がいれば、その方に頼んでみてください。
本ページのコードが動作しない上に、周囲にExcel 32ビット版を使ってる人がいない、という方はご相談ください。コメントからでもお問い合わせページからでも可能です。
バイナリエディタを使ってVBAパスワードを解除する
その後の検証で、別の方法でもVBAパスワードを解除する方法があることがわかりました。具体的には、バイナリエディタを使って別のパスワードに置換するという方法となります。詳しくくは「Excel VBA(マクロ)のパスワードはバイナリエディタで解除できる」をチェックしてみてください。
新しいパスワードを設定したいときは?
ロック解除後に、新しいパスワードを設定したいときには、ブックを移行しなければなりません。
下図のように、ロック解除後にファイルを開くと、ソースコードは確認できるものの、パスワードが再設定されている状態となります。つまり、VBAProjectのプロパティが設定できない状態となります。
この場合、ロック解除したブックからソースコードをエクスポートし、新しいブックを作って、そっちへインポートすることで解決できます。
ファイルのエクスポート
ソースコードをエクスポートするには、プロジェクトから該当オブジェクトを選択し、右クリックで「ファイルのエクスポート」をクリックします。
保存場所を指定して「保存」ボタンをクリックします。
以上でエクスポートは完了です。
ファイルのインポート
続いて移行用のExcelブックを新規作成します。
該当VBAProjectを右クリックして「ファイルのインポート」をクリックします。
インポートしたいファイルを選んで「開く」ボタンをクリックします。
以上でインポートは完了です。
コピペしても同じ
エクスポート・インポートを使わなくても、VBAのソースコードをコピペしてもOKです。シートはExcel上でコピーすればOKですし、ThisWorkbookに何か記述していた場合もコピペでOK。フォームを使っている場合は、エクスポート・インポートを利用しましょう。
参考サイト
まとめ
Excel VBAでパスワードロックを解除する方法を紹介しました。
VBAProjectのパスワードって、手軽に設定できる反面、管理が安易におこなわれているケースが多いですね。企業の大小にかかわらず、開発者任せのパスワード管理となっており、共有されていないことで被害が大きくなっている気がします。
今回も同じような内容の案件で「プログラムを変更したいがVBAProjectのパスワードがわからなくなって途方にくれている」といったものでした。
この方法で解除して、新たなブックへ移行することで解決に至りましたが、パスワードがわかっていれば不要な作業ですからね。
パスワードを紛失しないように皆さんも気をつけて運用してください。
おつかれさまでした。