Excelのパスワードを解除する方法

Excelのパスワードを解除する裏技を求めて、当WEBに来る方が少なくない。 「ブックの保護を強制的に解除する」は保護をすることで安全に隠せている気になっている記事への警告の意味で書いたので、パスワードが分からなくて困っている人へと補足情報を載せておこうと思う。

避けては通れない法律的な話し

まず法律的なことを覚えておいて欲しい。

何らかの方法でパスワードを調べたり、調べたパスワードを保管したりする行為は「不正アクセス行為の禁止等に関する法律」に抵触し、刑事罰の対象となる。例えファイルの中味を閲覧しなかったとしても、パスワードを調べたり、保管しているだけで処罰の対象となる。

裏技などを使ってパスワード(技術的利用制限手段)を迂回したりする行為は「著作権法」に抵触し、これまた刑事罰の対象となる。 著作権侵害の多くは親告罪だが、技術的利用制限手段の回避は非親告罪となる。

また裏技をつかってパスワード (技術的利用制限手段) を迂回するためのツールを提供する行為は「不正競争防止法」に抵触する。平成30年からはツールを提供するだけではなく、依頼を受けて役務を提供する事も処罰の対象となる。

以上のような法律があるので、いくら探しても「パスワードを解除して欲しい」という依頼を受けてくれる人は見つからない。Excelのファイルを解析してパスワードを解除するようなツールも見つからない。仮に技術的かつ予算的に可能であっても、家族や親友からの依頼でも無い限り、リスクが大きすぎて受けられないのだ。

とはいえ、パスワードが分からなくて途方に暮れている様もよく分かる。解決方法はただひとつしかない。技術的な知識と、法律的な知識を自ら身につけ、自らの手で作業するしかないのだ。

裏技による迂回方法

ブックやシートの保護パスワードや、VBAのソースコード閲覧パスワードなどは裏技的な方法で解除できる。実際に解除する方法は「Excel の各種パスワードを突破する方法まとめ」に良くまとまっている。新たに追記することはしない。

読み取りパスワードの解除

読み取りパスワードだけは総当たりで解除するしかない。だが、辞書に載っているような単語だけであるとか、あるいは6~7文字程度のパスワードであれば、解除できなくもない。

パスワードの解析によく使われるのは「John the Ripper password cracker」と言うツールだ。

私の使っている20万程度のパソコンでもGPUを使うと3,000パスフレーズ/秒程度のスピードで解析を進めてくれる。英数だけで構成される5文字程度のパスワードなら、最悪でも60時間程度で解析が終わる計算になる。辞書に載っているような単語、十万語程度を対象とするならば、数分で終わってしまう。

最高スペックのGPUを使うなら1桁程度は早くなる。IaaSで高速なサーバを複数台レンタルするなら2桁程度は早くなる 。6文字程度のパスワードなら総当たりでも 数日程度で 割り出すことが出来るし、そのために発生する費用は10万円にもみたない。

Postscript #1

そんな分けだからパスワードの分からなくなったファイルのことはキッパリと諦めて、ファイルをゼロから作り直すことを第一選択肢として考えたほうが良い。

Postscript #2

いまどき7文字程度のパスワードしか設定していないのは、実効性が無いので止めておいたほうが良い。無駄な仕事を増やしているだけに過ぎない。

Access Runtimeをインストールしようとしたら32bit版も64bit版もエラーになる

Access Runtime 2016 64bit版のインストールを行おうとすると「次の32ビットバージョンのOfficeプログラムががインストールされているため、64ビットバージョンのOfficeはインストールできません:Office 16 Click-to-Run Extensibility Component」とのエラーになる。

この環境は32bit版だったかと思い直し、 Access 2016 Runtime 32bit版のインストールを行おうとすると 「次の64ビットバージョンのOfficeプログラムががインストールされているため、32ビットバージョンのOfficeはインストールできません:Office 16 Click-to-Run Extensibility Component」とのエラーになる。

・・・どうしろとorz

Access Runtimeインストールの基本制約

Office 2016(2019にも)にはClick-to-Runインストール版 (以下C2R版) とMSIインストール版(以下MSI版)がある。ライセンス上はどちらをインストールしても構わないが、それぞれインストール方法が異なる。プレインストールの場合、昔はMSI版が多かったが、最近は C2R版が入って居ることが多い。そしてC2R版とMSI版には、それぞれ32bit版と64bit版がある。

Access RuntimeにもC2R 版とMSI版がある。C2R版はOffice 365 Access Runtimeと言う名称で、MSI版はAccess 2016 Runtime (ないし2019)と言う名称で提供されており、それぞれ32bit版と64bit版がある。

Access RuntimeをインストールするにはC2R版かMSI版か、32bit版か64bit版かの区分が完全に一致している必要がある。さらにMSI版の場合には2013と2016、2019は混在できないのでバージョンを統一する必要がある。

過去にプレインストール版が入っていた

当該環境はプレインストール版(C2R版)でインストールされていたため、アンインストールしてMSI版を入れ直していた。だが、どうもC2R版の残骸が残ってしまっているのが原因のようである。

アンインストールが完全に行われていないためにトラブルが発生することが度々あるようで、Microsoftのホームページに完全にアンインストールするための方法が書かれている。

PC から Office をアンインストールするの「オプション 2 – アンインストール サポート ツールを使用して Office を完全にアンインストールする」に従って、アンインストール補助用の実行プログラムをダウンロードして、実行することで残骸も含めて消せるようである。無論現在インストールされているMSI版も含めてアンインストールされてしまうのであろうけど・・・

余り褒められた話しではないが、作業時間も押してきているので、Access Runtime 2010のインストールでお茶を濁してしまった。でも恐らくは上記手順でOffice 2016の残骸を削除すればインストール出来るものと思われる。

Linux上のClosedXMLで画像データを扱うときにSystem.DllNotFoundExceptionが発生する

Linux(Ubuntu 18.04)環境に.NET Core SDK 2.2をインストールし、ClosedXmlで画像を含むExcelファイルを扱おうとしたところ、下記の様な例外が発生して実行出来ません。

System.TypeInitializationException: The type initializer for 'Gdip' threw an exception. ---> System.DllNotFoundException: Unable to load shared library 'libdl' or one of its dependencies. In order to help diagnose loading problems, consider setting th
 e LD_DEBUG environment variable: liblibdl: cannot open shared object file: No such file or directory at Interop.Libdl.dlopen(String fileName, Int32 flag)
     at System.Drawing.SafeNativeMethods.Gdip.LoadNativeLibrary()
     at System.Drawing.SafeNativeMethods.Gdip..cctor()
     --- End of inner exception stack trace ---
     at System.Drawing.SafeNativeMethods.Gdip.GdipLoadImageFromDelegate_linux(StreamGetHeaderDelegate getHeader, StreamGetBytesDelegate getBytes, StreamPutBytesDelegate putBytes, StreamSeekDelegate doSeek, StreamCloseDelegate close, StreamSizeDelegate size, IntPtr& image)
     at System.Drawing.Image.InitFromStream(Stream stream)
     at ClosedXML.Excel.Drawings.XLPicture..ctor(IXLWorksheet worksheet, Stream stream)
     at ClosedXML.Excel.Drawings.XLPictures.Add(Stream stream)
     at ClosedXML.Excel.XLWorkbook.LoadDrawings(WorksheetPart wsPart, IXLWorksheet ws)
     at ClosedXML.Excel.XLWorkbook.LoadSpreadsheetDocument(SpreadsheetDocument dSpreadsheet)
     at ClosedXML.Excel.XLWorkbook.LoadSheets(Stream stream)

.NET Core Runtimeインストール時に依存関係が処理されていないことが原因です。下記のコマンドを実行してGDI+関連のライブラリをインストールすると解決します。

sudo apt install libc6-dev 
sudo apt install libgdiplus
cd /usr/lib
sudo ln -s <a rel="noreferrer noopener" target="_blank" href="http://libgdiplus.so/">libgdiplus.so</a> gdiplus.dll

環境によってはLD_LIBRARY_PATHの設定も必要になるようです。

ASP.NET COREを使ったWEBサービス作成(習作)

習作としてASP.NET COREを使用したWEBサービスを作成してみた。
もちろんLinux(Ubuntu 18.04)上で動作している。

Excelファイルをアップロードすると、適当な文字列部分をバーコード画像に置き換えてくれる。

https://barcode.code-lab.net/

expdpで「ORA-31634: ジョブはすでに存在します」になる

Oracleのバックアップにexpdpを使用している。expdpを実行したところ「ORA-31634: ジョブはすでに存在します」と「ORA-31664: デフォルト設定時に一意のジョブ名を構成できません」と見慣れないエラーが表示される。

以下のSQLでDATAPUMP_JOBSにあるジョブ名を確認する。

> select * from DBA_DATAPUMP_JOBS ORDER BY JOB_NAME
>
> OWNER_NAME JOB_NAME OPERATION JOB_MODE STATE DEGREE ATTACHED_SESSIONS DATAPUMP_SESSIONS
> SYSTEM SYS_EXPORT_SCHEMA_01 EXPORT                         SCHEMA                         NOT RUNNING 0 0 0
> SYSTEM SYS_EXPORT_SCHEMA_02 EXPORT                         SCHEMA                         NOT RUNNING 0 0 0
>... 

なんと・・・SYS_EXPORT_SCHEMA_01~99まで、全部で99個のジョブが溜まっている。実はexp先の容量不足から一部スキーマのバックアップに失敗していた時期があって、どうやらその時に失敗したexpdpのジョブが消えること無く溜まっていたらしい。

こういう時にはexpdpにattachオプションを指定して起動し、コマンプロンプトからkill_jobを実行すれば良い。でも残念ながら下記のようなエラーになってしまい、既存ジョブにアタッチする事が出来ない。

 C:\>expdp SYSTEM/****@ORA attach=SYS_EXPORT_SCHEMA_01

Export: Release 11.2.0.1.0 - Production on 金 6月 21 09:43:34 2019

Copyright (c) 1982, 2009, Oracle and/or its affiliates.  All rights reserved.

接続先: Oracle Database 11g Release 11.2.0.2.0 - 64bit Production
ORA-39002: 操作が無効です
ORA-39000: ダンプ・ファイル指定が無効です
ORA-31640: ダンプ・ファイル"C:\dmp\XXX.dmp"を読取りのためにオープンできません
ORA-27041: ファイルをオープンできません。
OSD-04002: ファイルをオープンできません
O/S-Error: (OS 2) 指定されたファイルが見つかりません。 

既存ジョブにアタッチできないので、仕方なく以下のSQLでジョブを廃棄することにする。

> DROP TABLE SYS_EXPORT_SCHEMA_01;
> ...
> DROP TABLE SYS_EXPORT_SCHEMA_99; 

これで溜まっていたジョブが削除されたので、expdpは正常に戻った。

「VBAを覚えようと思うんだけど」と聞かれた話の続き

日付をまたいで「『VBAを覚えようと思うんだけど』と聞かれた話」の続きなど。

VBAを進められない理由・・・それは2025年以降、Microsoft Officeが月額制ライセンスのみとなることで、どのパソコンにもExcelが入っている時代が終わりそうだからだ。現在のMicrosoft Officeのライセンスは大きく分けて2種類、月額制ライセンスと買切りライセンスにわけられる。このうち買切りライセンスはOffice 2019を最後のバージョンとして2025年10月にサポートが終了する。

Microsoft Officeの買切りライセンスにはユーザーライセンスとデバイスライセンスの2種類に分かれる。ユーザーライセンスは使うユーザが同じなら複数台にインストールできるが、1台のPCを複数人で共有するなら人数分のライセンスが必要だ。デバイスライセンスはインストールするPCの台数分購入する必要があるが、1台のPCを複数人で共有してもOKだ。

対して月額制ライセンスはユーザーライセンスしか用意されていない。 PCの台数より従業員の人数の方が多いという職場は少なくない。小売業とか、製造業とか。1台のPCを10人程度で共有していた場合、デバイスライセンスだったら5万円で済んだのが、月額制ライセンスだと5年で50万円くらいに膨れ上がる。この金額増を避けるためMicrosoft Officeを全部のPCにはインストールしなくなると考えている。

一般家庭向けだと法人ライセンスより高くて年間1万2千円。4人家族なら年間4万8千円。現在はプレインストールモデルのOffice Personalを1万7千円の価格差で買えるから大抵の人はインストールしている。ライセンス料が5年で24万円と言われたら、利用頻度の低いだろう一般家庭は躊躇するのではなからろうか。海外だともうちょっと安いファミリー向けライセンスもあるらしいのだが、そうだとしても結構厳しい。

僕は 上記の理由から2025年になるとMicrosoft Officeの利用が減り、比較的安いコストで使える互換製品に移る動きが再び起こると思っている。互換OfficeソフトはMicrosoft Officeのファイルをほぼ問題なく扱うことが出来る。だがVBAだけは互換ソフトで動作しない。今むやみにVBAでプログラムを作りすぎると、5年後に追い詰められる予感がするのだ。

「VBAを覚えようと思うんだけど」と聞かれた話

事務系の同僚女子に「VBAを覚えようと思うんだけど」と言われて唸ったことがある。

ITリテラシーの高い従業員が増えることや、業務が効率化されること自体は喜ばしいのだが、ことVBAだけは手放しで勧められないのだ。

VBAはVisual Basicという言語が元になっている。このVisual Basicは1998年発売の6.0を最後に、2008年4月にサポートを終了している。Office製品の一部として提供されているためセキュリティアップデートこそ提供されているが、機能面では更新されていない。20年前で進化が止まっている。

そのためVBAでは、新しいバージョンのDB利用や、WEBサービスとの連携に無理が出ているのだ。MicrosoftのSQLServerで扱うデータ型の一部は取り扱えないし、WEB APIを呼び出そうとすると恐ろしく冗長なコードを書かざる得ない。

さらにVBAはインターネットが普及してセキュリティが重要視される以前の設計なので、セキュリティ面がどうしても弱い。標準では電子署名なしのマクロを実行できないように設定されているのは、セキュリティ的に弱く攻撃の対象にされやすいためだ。

セキュリティ面ではVBAを電子署名必須として運用するか、それが出来ないなら社内から無くしたいのが実情だ。でも実態は彼方此方で活用しているので、止めるに止められないので、セキュリティ担当者は困っていたりする。

ではどうしたら良いかというと、実は代案がない。ExcelやWordのファイルを扱うことができて、ライセンス料がかからず、平易に学習できて、完璧に日本語化されていて、どのWindowsパソコンでもそのまま動かせる言語・・・というのが見当たらない。

というわけで、VBAに関する愚痴でした。ちなみに私自身は、VBAを使って、新規にはマクロを作らないことにしています。 新たに作るときにはC#+Closed XMLで書きます。もしくはPower Query+Excelの数式だけで作ります。

Microsoftにも早く今後のLoadmapを考えてほしい。

.NET Coreで実行可能ファイルを作る

最近はちょっとしたプログラムを作るときに.NET Coreコンソールアプリケーションを選択するようにしている。今のところ実際にLinuxで動かすような機会はないが、クロスプラットフォームに出来るからだ。ただ通常はDLLとしてビルドされるため、PCに詳しくない人には起動手順を説明しにくい。

第三者向けにインストーラを作成して使用手順を書こうとした時に、ふと.NET Core 2.2からはDLLではなくて、実行ファイル(EXEファイル)としてビルド出来ることを思い出した。第三者向けに配布するなら実行ファイルとしてビルドしておいた方が便利そうだ。

コマンドラインから実行ファイルを生成するのは以下のように”-r win-x64 –self-contained true”指定するだけである。

dotnet publish -c release -r win-x64 --self-contained true

win-x64はRID(Runtime Identifier)でビルドするターゲットとなるプラットフォームを示します。linux-x64とかwin-arm64などと指定すれば異なるOSやCPUアーキテクチャをターゲットとしたバイナリを簡単に作れて便利です。

URL:
https://docs.microsoft.com/ja-jp/dotnet/core/deploying/deploy-with-cli
https://docs.microsoft.com/ja-jp/dotnet/core/rid-catalog

僕の経験した最悪の糞コードの話

ツイッターで久しぶりに糞コードの話を見かけたので、僕の知る最悪の糞コードの話を書いておこうと思う。

そのコードはGeneric Programmingによって実装されていました。クラスはきちんと整理されており、テンプレートを最大限に活用したコードは必要最小限の記述となっています。整然とひとつの思想によって実装された素晴らしいコードでした。いくつかの致命的な問題を除いては・・・

一つ目の致命的な問題は、このプロダクトがWindows向けであり、開発環境にVisual C++を使用していたことです。当時のVC++コンパイラにはバグがありました。複雑なテンプレートを定義すると、コンパイラがジェネラルプロテクションエラーを起こして終了してしまうのです。

知っていれば回避可能な、実用上は問題ないバグをBy Design(仕様)と称していた時代の話です。コンパイラのバグが近日中に修正される可能性はありません。この問題を根本的に解決するには、プログラムの根幹を構成しているGeneric Programmingを、互換性を維持し挙動を変えることなく取り除く・・・・って、ほぼリメイクですヤン!

実際には既にリリースしてしまっているので互換性維持は絶対、修正や機能追加は待ったなし、そんな大規模修正できません。影響の少なさそなところからGeneric Programmingを取り除き、VC++が落ちない程度までテンプレートの使用量を減らしては、修正をするって作業に明け暮れたのでした。

一つ目の・・・と書いたからには二つ目以降もあるわけで、DLLの引数としてクラスを何の考えもなく受け渡してる。それもDLL側で確保して呼び出し元で解放させたり。C++はコードや変数がどのようにメモリ上に展開されるかは仕様として定められていません。したがってクラスを引数として受け渡そうとするなら、全てのモジュールを同じコンパイラ、同じヘッダファイル、同じコンパイルオプションでビルドするのが必須です。ちょっと直すだけでも全モジュールをビルドし直して置き換えないと動作を保証できないという困難さ。

このコードを書いたエンジニア、どうやらJavaのスペシャリストであったようです。JavaのプログラマとしてOOな設計やコーディング技法には精通しており、その技をしっかりと使いこなしていました。でもC++固有の言語仕様には非常に疎く、おそらくはほぼ初心者。newしてもdeleteを呼んでいる場所が全くない。C++の言語仕様上の地雷をことごとく踏み抜いてく、そんなクソースでした。

Windows7でWindowsUpdateの再起動中に15%程度でとまってしまう

Windows 7 Professional (x64)の環境において、Windows Updateで繰り返しエラーが発生。OSの再起動中に毎回15%程度のところでエラーが発生して、巻き戻されてしまいます。久しぶりにC:\Windows\Logs\CBS\CBS.LOGの出番です。

2019-01-22 10:17:51, Info                  CBS    Waiting for poqexec.exe to complete...
2019-01-22 10:17:56, Info                  CBS    Waiting for poqexec.exe to complete...
2019-01-22 10:18:01, Info                  CBS    Waiting for poqexec.exe to complete...
2019-01-22 10:18:10, Info                  CBS    SQM: Reporting poqexec status with status: 0xc0000043, failed file: conhost.exe, interfering process: tmbmsrv.exe,conhost.exe,conhost.exe, context: Startup, first merged sequence: 1613
2019-01-22 10:18:10, Info                  CBS    SQM: Upload requested for report: PoqexecStatus, session id: 142861, sample type: Standard
2019-01-22 10:18:10, Info                  CBS    SQM: Ignoring upload request because the sample type is not enabled: Standard
2019-01-22 10:18:10, Info                  CBS    Failure in poqexec.exe while processing updates. [HRESULT = 0x80070020 - ERROR_SHARING_VIOLATION]
2019-01-22 10:18:12, Info                  CBS    Set the CCP impactful-commit disabling value
2019-01-22 10:18:12, Error                 CBS    Startup: Failed while processing critical primitive operations queue. [HRESULT = 0x80070020 - ERROR_SHARING_VIOLATION]
2019-01-22 10:18:12, Info                  CBS    Setting ExecuteState key to: CbsExecuteStateResolvePending | CbsExecuteStateFlagRollback
2019-01-22 10:18:12, Info                  CBS    Progress: UI message updated. Operation type: Update. Stage: 1 out of 1. Rollback.
2019-01-22 10:18:12, Info                  CBS    Startup: Processing advanced operation queue, startupPhase: 0
2019-01-22 10:18:12, Info                  CSI    00000006 IAdvancedInstallerAwareStore_ResolvePendingTransactions (call 1) (flags = 0000000a, progress = NULL, phase = 0, pdwDisposition = @0x1e0f9e0
2019-01-22 10:18:12, Info                  CBS    Startup: Changing logon timeout to a static timeout: 10800000
2019-01-22 10:18:13, Error                 CSI    00000007 (F) Error: ResolvePendingTransactions called after poqexec failure (call 1)
  Status = STATUS_SHARING_VIOLATION, Operation = DeleteFile, DiagString = [l:70{35}]"\??\C:\windows\System32\conhost.exe"
[gle=0x80004005]
2019-01-22 10:18:59, Error                 CBS    Startup: Primitive operations failed, startupPhase: 0.  The transaction will be cancelled. [HRESULT = 0x80004005 - E_FAIL]
2019-01-22 10:18:59, Info                  CBS    Setting ExecuteState key to: CbsExecuteStateInitiateRollback | CbsExecuteStateFlagPrimitivesFailed
2019-01-22 10:18:59, Info                  CSI    00000008 Creating NT transaction (seq 1), objectname [6]"(null)"
2019-01-22 10:18:59, Info                  CSI    00000009 Created NT transaction (seq 1) result 0x00000000, handle @0x12c
2019-01-22 10:19:05, Info                  CSI    0000000a@2019/1/22:01:19:05.296 CSI perf trace:
CSIPERF:TXCOMMIT;2808573

Errorが発生している箇所を見ると、conhost.exeのところでERROR_SHARING_VIOLATION(0x80070020)が発生しているようです。
ERROR_SHARING_VIOLATION はほかのプロセスとの排他処理によってエラーが発生していることを示しています。

注目するのはErrorの少し手前の行。”SQM: Reporting poqexec status with status: 0xc0000043, failed file: conhost.exe, interfering process: tmbmsrv.exe,conhost.exe,conhost.exe, context: Startup, first merged sequence: 1613″のところです。 “failed file: conhost.exe”に続く”interfering process: “のところで、原因となった可能性のあるプロセスが列挙されています。そこには”tmbmsrv.exe”の表記が・・・・

“tmbmsrv.exe”ってトレンドマイクロのアンチウィルス・・・セーフモードで起動して、コントロールパネルのサービスから アンチウィルス のサービスを無効にして再起動。アンチウィルスが動作しない状態にして、Windows Updateを実行すると・・・成功しました。