Excel VBA マクロ パスワードを解除する方法 32ビット 64ビット

Excel VBAでパスワードロックを解除する方法です。コードをコピペすれば簡単に解除できます。

VBA マクロ パスワードを解除する方法 Excel 2019 2016 32ビット 64ビット

VBAProjectのパスワードは、プログラムの解析を保護するために設定することができます。

ずいぶん前にも同様の内容で記事を書きましたが、今回久しぶりに「VBAパスワード解除の案件」があったので、改めて記事にしておきたいと思います。

ここでは Excel VBAでパスワードロックを解除する方法 を紹介します。


VBAProject パスワードとは?

VBAProject パスワードとは、VBAProjectのプロパティから設定できる「プロジェクトのロック」に設定されたパスワードのことです。

VBAProjectのプロパティ

パスワードが設定されると、プロジェクトのプロパティが見れなくなります。

VBAProjectのプロパティによるパスワード設定

ソースコードの解析を保護できる反面、設定した人しかパスワードがわからないため、トラブルの原因にもなります。「パスワードを忘れてしまった」「開発者が退職し、パスワードがわからない」が主な理由です。

本記事でできること

VBAProjectパスワードを解除することができます。概要を簡単に説明します。

  1. 新たにマクロ有効ブック(xlsm)を作る。
  2. 標準モジュールを挿入し、コードを貼り付ける。
  3. コードを実行してパスワードを解除する。

基本的には、後述するコードをコピペすればOKです。プログラムによって解除するというものです。パスワードを解除し、ソースコードは確認できますが、パスワードがなんだったのかは把握できません。

くれぐれも悪用したり、他人の著作物を覗き見るような不正はしないでください。

検証したExcelのバージョン

VBAProject パスワードの解除について、検証したOSはWindows 10です。Excelのバージョンは、Excel 2019 / 2016で検証しています。ファイル形式は xlsm / xls です。

検証したExcelのバージョン

以前の記事でExcel 2010 / 2013でも動作検証済です。

Excelが32ビット版か64ビット版か確認する

パスワード解除の方法は、32ビット版と64ビット版でやり方が違います。事前にどちらか確認しておきましょう。

Excelを開いて「ファイル」-「アカウント」から「Excelのバージョン情報」をクリックすると、下記の画面が出てきます。

Excelのバージョン情報

赤枠の部分に詳細なバージョンが書いてあるので確認してください。

バックアップをする

万が一に備え、移行の操作をする前に、該当の Excel ブックはどこかにコピーをバックアップしておいてください。ファイルが破損する可能性があります。

全て自己責任において実施してください。当方では一切の責任を負いません。

VBAパスワードを解除する

準備が整ったらVBAのパスワードを解除しましょう。

まずは「ロック解除用のExcelブック(xlsm)」を作り、「ロックされたExcelブック」と同じフォルダに入れます。

ロック解除用のExcelブックとロックされたExcelブックを同じフォルダへ入れるロックされたExcelブック

ロックされたExcelブックは元のファイル名のままでOKです。

下図のように「ロックされたExcelブック」はパスワードロックがかかっています。

ロックされたExcelブックはパスワードロックがかかっている

次に「ロック解除用の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キー」を押します。

VBAコードを実行する

「VBAProjectパスワード解除」のメソッドを実行します。

VBAProjectパスワード解除のメソッドを実行する

「VBAProjectのパスワード解除成功!」メッセージが出ればパスワードロックは解除されています。

VBAProjectのパスワード解除成功のメッセージ

パスワードロックされたVBAProjectを開いてみると・・・。

パスワードロックされたVBAProjectを開いてみると解除されていた

おおおおー、パスワードロックが解除されたー。

VBAパスワードロック解除後にやること

VBAProjectのパスワードロックが解除されたら、必ず下図のように「プロジェクトのロック」のチェックを外してください。

プロジェクトのロックのチェックを外す

これをやらないと、保存して閉じてもパスワードが再度設定されてしまいます。

ちなみに、新しいパスワードを設定して保存はできません。パスワードを再設定して閉じて開くと、新しいパスワードでは解除できず、古いパスワードが必要となります。どうやら前のパスワードが内部で残るようですね。ふしぎ・・。

64ビット版のコードを実行すると強制終了となる

パスワード解除成功のメッセージが出た後に、パスワードがかかっているVBA Projectを開こうとした際、「Microsft Excelは動作を停止しました」となるケースがあるようです。

メッセージなしで強制終了するパターンもあり

どうも64ビット版のコードは動作不安定なようです。こちらで検証した結果、64ビット版で作ったファイルでも、32ビット版のコードでパスワード解除できました。周囲にExcel 32ビット版を使われている方がいれば、その方に頼んでみてください。

本ページのコードが動作しない上に、周囲にExcel 32ビット版を使ってる人がいない、という方はご相談ください。コメントからでもお問い合わせページからでも可能です。

バイナリエディタを使ってVBAパスワードを解除する

その後の検証で、別の方法でもVBAパスワードを解除する方法があることがわかりました。具体的には、バイナリエディタを使って別のパスワードに置換するという方法となります。詳しくくは「Excel VBA(マクロ)のパスワードはバイナリエディタで解除できる」をチェックしてみてください。

新しいパスワードを設定したいときは?

ロック解除後に、新しいパスワードを設定したいときには、ブックを移行しなければなりません。

下図のように、ロック解除後にファイルを開くと、ソースコードは確認できるものの、パスワードが再設定されている状態となります。つまり、VBAProjectのプロパティが設定できない状態となります。

VBAProjectのプロパティが設定できない状態

この場合、ロック解除したブックからソースコードをエクスポートし、新しいブックを作って、そっちへインポートすることで解決できます。

ファイルのエクスポート

ソースコードをエクスポートするには、プロジェクトから該当オブジェクトを選択し、右クリックで「ファイルのエクスポート」をクリックします。

ファイルのエクスポートをクリック

保存場所を指定して「保存」ボタンをクリックします。

保存場所を指定して保存ボタンをクリックする

以上でエクスポートは完了です。

ファイルのインポート

続いて移行用のExcelブックを新規作成します。

該当VBAProjectを右クリックして「ファイルのインポート」をクリックします。

ファイルのインポートをクリックする

インポートしたいファイルを選んで「開く」ボタンをクリックします。

ファイルを選んで開くボタンをクリックする

以上でインポートは完了です。

コピペしても同じ

エクスポート・インポートを使わなくても、VBAのソースコードをコピペしてもOKです。シートはExcel上でコピーすればOKですし、ThisWorkbookに何か記述していた場合もコピペでOK。フォームを使っている場合は、エクスポート・インポートを利用しましょう。

参考サイト

まとめ

Excel VBAでパスワードロックを解除する方法を紹介しました。

VBAProjectのパスワードって、手軽に設定できる反面、管理が安易におこなわれているケースが多いですね。企業の大小にかかわらず、開発者任せのパスワード管理となっており、共有されていないことで被害が大きくなっている気がします。

今回も同じような内容の案件で「プログラムを変更したいがVBAProjectのパスワードがわからなくなって途方にくれている」といったものでした。

この方法で解除して、新たなブックへ移行することで解決に至りましたが、パスワードがわかっていれば不要な作業ですからね。

パスワードを紛失しないように皆さんも気をつけて運用してください。

おつかれさまでした。

この記事がお役に立ちましたら シェア をお願いいたします。