PR
私が使っているPCガジェット類
作業環境で実際に使っている・気になっている周辺機器などをまとめました
※ 一部のリンクは広告(アフィリエイト)を含みます
作業環境で実際に使っている・気になっている周辺機器などをまとめました
※ 一部のリンクは広告(アフィリエイト)を含みます
理由はさておきVBAのパスワードを解除したくなることってありませんか?
自分で作ったマクロにパスワードをかけたのに肝心の合言葉を忘れてしまって中身を直せない、なんて話は私も身に覚えがあります
ここで扱うのはVBAProject(マクロのコードを束ねている入れ物)にかけた保護パスワードで、これを知らないまま強制解除してコードを開く話です
古くはバイナリエディタで書き換える手もありましたが、今はVBAのプログラムを実行するだけでロックされたコードを確認できます
ひとつだけ先に整理しておくと、ファイルを開くときに求められる読み取りパスワードはこれとは別物です
あちらは中身をまるごと暗号化していて、忘れると誰も開けないので、この記事の手ではどうにもなりません、そこは混同しないでほしいところです
このページでは自分のファイル(自作マクロのパスワード忘れ)を救済する前提で手順をまとめます、他人や業務で受け取ったファイルへ無断で使うものではないので、そこだけ先にお伝えしておきますね
解除に使うプログラムは記事の下のほうに置いてあります、先にコードだけ見たい方はそちらまで飛んでください
手順に入る前に、なぜパスワードがかかっているのに回避できてしまうのかを軽く押さえておきます
VBAProject(マクロのコードを束ねている入れ物)にかけるパスワードは、ファイルの中身をガッチリ暗号化しているわけではなくて、エディタ上でコードを表示させないための制限に近い仕組みです
正しいパスワードを入れたかどうかをExcel側が確認して、合っていればコードを開く、という判定をしているだけなんですね
裏を返すと、その判定の部分に「もう正解が入りましたよ」と思い込ませることができれば、パスワードを知らなくてもコードが開けてしまうわけです
今回紹介するプログラムは、まさにこの判定をすり抜けるアプローチをとっています、つまりVBAのパスワードはセキュリティとしては弱めで、おまけ程度の鍵だと思っておくのが現実的です
VBAProjectのパスワードは「コードの表示を抑える程度の保護」です、機密データを守る暗号化とは別物なので、本当に見られたくない情報をマクロ内に直書きするのは避けるのがおすすめです
細かい操作はほとんどないので、サクッと4ステップにまとめました
とりあえず対象のファイルを開いておきます、このあと操作するExcelと同じウィンドウで開いている状態にしておくのがポイントです
プログラムを実行するための作業用ファイルを新しく作ります、対象ファイル自体をいじるのではなく、別のブックから操作する形ですね
新規ファイルのVBエディタを開いて標準モジュールを挿入し、このあと載せるプログラムをまるごと貼り付けます
プログラムは記事の下にあるので、そこからコピペしてください
貼り付けたVBAProjectパスワード解除のプロシージャを実行して、成功のメッセージが出れば完了です
本来ならパスワードを入れないと展開されないはずの対象ファイルのプロジェクトが、そのまま開けるようになっています
実際に使うプログラムはこちらなので、新規ファイルの標準モジュールにコピペでどうぞ↓↓
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このコードがやっているのは、Windowsがダイアログを出すときに呼び出すDialogBoxParamAという関数の動きを横取りすることです
VBAのパスワード入力ダイアログが出ようとした瞬間に「もう正解が返ってきたことにする」よう差し替えるイメージで、専門的にはAPIフックと呼ばれる手法ですね
差し替えのためにVirtualProtectやMoveMemoryといったメモリ操作の関数を使っていて、ここがエラーになりやすいので軽くだけ補足しておきます
掲載しているのは64bit版Excelに対応したPtrSafe版です、各宣言にPtrSafeが付いていて型がLongPtrになっているのがその印で、Microsoft 365を含む今どきの64bit版Excelでも動いたという報告が多いです
ただExcelのビルドや環境によっては実行時に落ちる・うまく効かないこともあるので、いきなり本番で試さずコピーで確認するのがおすすめです
もし古い32bit環境でコンパイルエラーが出る場合は、宣言の書き方を32bit向けに直す必要があります、このあたりはFAQでも触れるので、エラーで止まった方はそちらも見てみてください
手順を動画化しただけですが、文字だけだと伝わりにくい時の参考にどうぞ
便利な手順ですが、いくつか性質を知っておかないと「あれ?元に戻ってる?」と戸惑うことになります
大事なのは、この手順を使ってもパスワードそのものが消えるわけではないという点です
あくまでメモリ上で一時的にダイアログを回避しているだけなので、上書き保存をしてもファイルを閉じて開き直すと、また同じパスワードが効いた状態に戻ります
そういう意味では「パスワードを解除する」というよりこっそり中身を覗くと言ったほうがしっくりくるかもしれないですね
この方法は恒久的な解除ではなく一時的な閲覧です、開き直すとロックが戻るので、見られたコードは別ファイルに控えておくのがおすすめです
「一時的なら困る、ちゃんと外したい」という場合は、フックで開けているあいだに保護を外すのが手です
VBエディタの「プロジェクトのプロパティ」から保護タブのパスワードのチェックを外して上書き保存すれば、次からは普通に開けます
つまり見るだけなら一時/保護を外して保存すれば恒久の二段構えです
まずは一時的に開いて中身を確認し、必要なら保護そのものを外す、と考えておくと分かりやすいと思います
もう一点、メモリを直接書き換える手法なので、環境によっては実行時にExcelが落ちることもあります
大事なファイルでいきなり試すのは怖いので、事前にコピーをとってから作業するのが安心です

APIフック以外に昔から知られているのが、バイナリを直接いじってDPBキーを書き換える方法です
DPBはVBAProjectの保護状態にひもづくキーで、ここのキー名を崩すとExcelが保護を無視してプロジェクトを開くようになります
古い.xls形式なら、バイナリエディタでvbaProject.bin相当の中の「DPB」を別の文字列(例 DPx)に書き換えるだけです
開いたあとにパスワードを空にして保存し直せば、そのまま恒久的に外せます
「これは古い.xls専用でしょ?」と思いがちですが、.xlsmでも同じことができます
xlsm(やxlsx)は中身がZIPなので、拡張子を.zipに変えて展開し、中のxl/vbaProject.binを取り出して同じDPB書き換えをして戻す、という流れです
バイナリ書き換えは1バイト間違えるとファイルごと壊れるので、コピーを取ってから作業するのが原則です
手軽さと安全さなら先ほどのプログラム実行(APIフック)のほうが上なので、慣れないうちはそちらがおすすめです
似た発想の「あとから保護を外す・中身を覗く」話として、PythonのExe化を逆コンパイルで開く記事も書いています
PyInstallerでExe化したPythonを逆コンパイルする方法もどうぞ
仕組みを知ると応用したくなるところですが、使いどころは落ち着いて見極めたいですね
この手順が役に立つのは、自分で作ったマクロのパスワードを忘れてしまったような、自分のファイルを救済する場面です
一方で、他人が作ったファイルや業務で配布されたファイルにはパスワードをかけた人の意図があります、中を見たいときは作成者や権利者に許可をとるのが筋だと思います
このあたりは時点や状況によって考え方も変わりうるところなので、断定はしませんが、少なくとも無断で他人のロックを外して回るような使い方は避けておくのが無難です
つまずきやすいポイントをQ&A形式でまとめておきます
掲載コードは64bit版に合わせたPtrSafe版です、32bit環境でコンパイルエラーが出る場合は、宣言部のLongPtrをLongに置き換えるなど32bit向けの書き方に直すと動くことが多いです、両対応にしたいときはVBA7で条件分岐させる書き方も知られています
このAPIフック方式はファイルの拡張子に依存せず、VBエディタ上のダイアログを回避する仕組みなのでxlsmでも考え方は同じです、なおxlsxはマクロを保存できない形式なのでVBAProject自体が入っていないことが多く、その場合はそもそも保護を外す対象がない点だけ覚えておいてください
まずコンパイルエラーなら32bit/64bitの宣言が環境と合っているかを確認します、実行時に落ちる場合は、対象ファイルと作業用ファイルが同じExcelで開かれているか、対象ファイルを先に開いているかをチェックしてみてください、メモリ操作を伴う性質上、念のため作業前にファイルのコピーをとっておくと安心です
今回の方法はメモリ上で一時的にダイアログを回避するものなので、開き直すとパスワードは戻ります、恒久的に外したいなら、開けている間にVBエディタのプロジェクトのプロパティから保護のチェックを外して保存し直す、あるいは古い形式向けには前述のDPBキー書き換えといった方法が知られています、ただし書き換え系はファイル破損のリスクがあるので、コピーで試すのがおすすめです
このコードはWindowsのkernel32やuser32といったDLLを呼び出すので、Mac版Excelではそのままでは動きません、Mac環境ではWindows用のAPI宣言が使えないため、別のアプローチを探すか、Windows環境で作業するのが現実的だと思います
このプログラムはメモリを直接書き換えるので、Excelのビルドや環境によっては実行時に落ちることがあります、まず対象ファイルと作業用ファイルを同じExcelで開いているか、PtrSafe版の宣言が64bitと合っているかを確認してみてください、それでも落ちる場合は、コピーしたファイルで前述のDPBキー書き換えのほうを試す手もあります
VBAProjectの保護は暗号化ではないので、総当たりツールを持ち出すまでもなく今回のプログラム実行やDPB書き換えで開けます、総当たり系のフリーソフトや有料ツールが本領を発揮するのはファイルを開くパスワード(暗号化)のほうで、そちらは短く単純なら現実的でも、長くて記号混じりだと事実上いつまでも終わりません、用途が別物なので目的に合った手段を選ぶのがコツです
いいえ、今回のAPIフックはVBAProject(マクロのコード)の保護専用です、シート保護やブック構造の保護はまた別の仕組みで、こちらも暗号化ではないため外せますが、やり方が違います(xlsxをZIP展開して該当タグを消す等)、こちらは別記事で改めてまとめる予定です
VBAパスワードの解除方法は調べるといくつか出てきますが、今回のプログラム実行が一番手軽な気がします
解除して開いたコードをこれから直す・書き足すなら、VBE(Visual Basic Editor)のおすすめ設定やVBAの変数と定数の基本もあわせてどうぞ
仕組みとしてはパスワード入力の判定をすり抜けているだけなので、過信せず自分のファイルの救済に役立ててもらえたら嬉しいです

PythonとExcelを中心に仕事に役立つ業務ツールや自動化、スクレイピングツールの作成を受注していて、クラウドワークスでは気が付けば100件以上のお仕事を受注してきました!
会社員をやりながらの副業なので時間の捻出は相応ですが、クライアントの方々と近い立場でこちらからも提案しながら活動していますのでお悩みあれば是非ご相談ください
VBAとPythonを中心にユーザー側でできるITを自己学習しているので備忘録半分、学習履歴を残して同じ道を辿る人の参考になればとブログを始めました
副業でスクレイピングツール作成を中心にできることを色々やっていますのでご相談いただけるとありがたいです!
クラウドワークスのページへ
ココナラのページへ
コメント