Twitterで一時期さんざん騒がれていた(一部のアカウントが情報を拡散していた)、AppleScript Disasemblerについて調べてみました。
いわく、
「Macには5年前からウィルス(マイニングツール?)が出回っている。というのも、実行専用のAppleScript appletはAppleのウィルスチェックの対象から外れており、中身を確認できないからである。この脅威に対処するためのツールはXXに問い合わせるとよい。aevt disassemblerなどのツールを用意している」
という内容のものでした。分かりやすい恫喝です。「5年前からウィルスが」云々の是非は知りませんし、それにAppleScriptが使われているのかどうかなども知りません。見たことがないものについては、批評も判断も不可能です。
実行専用のAppleScript AppletだとAppleのチェックを免れる、という点については疑問が残ります。ただ、仮にそうしたものがあったとして、その実行内容をいちいちOS側がチェックしているとも考えにくいので、その可能性は否定できません。
そして、「aevt disassemblerなどのツール」という点、ここが問題です。本当にできるのか? 冗談ツールみたいなもの(特定条件では使えるが実用性がない)はあるのかもしれませんが、そんなに、現代の高度化しているAppleScriptのプログラムの内容を、実行専用バイナリから元ソース取り出しができるものなのか?????? これは、試してみないとなんとも言えません。
えーーー、AppleScriptはAppleEventのバイトコードに翻訳されて実行されます。
この、AppleEventのバイトコードから元のAppleScriptを戻せるかどうかについては、かなり初期から「イベントのコードと実際のAppleScriptの対処表を作れば、元のコードを取り出すことは原理上不可能ではないだろう」という推測が行われてきました。
ただ、その対処表を作るという手間がバカバカしく、苦労の割に得るものが少ないため誰も本気で取り組んでこなかったテーマでもあります。
とりあえず実行専用のAppleScriptでなければ「osadecompile」コマンドがOSに標準装備されているので、これでソースを取得することは可能です。
では、実行専用のAppleScriptやAppletからソースを取得できるのでしょうか?
Github上でそれらしきソフトウェアをみつけました。aevt_decompileとapplescript-disassemblerです。それぞれ実際に試してみました。
確認対象ファイルは、
①普通の(スクリプトエディタで)読める通常形式のAppleScript(.scpt)
②「実行専用」の通常形式のAppleScript(.scpt)
③「実行専用」のAppleScriptアプレット
④「実行専用」のAppleScriptアプレット(コード署名つき)
の4つです。主に、decompilerについて(確認もしないで)騒いでいる連中が槍玉に挙げているのは、③④のはずなので、①②はあくまで比較用です。
aevt_decompile
まず、aevt_decompileを実際にXcode上でビルドし、/usr/local/binにコピーしたうえでTerminal上から実行してみました。
Mac:bin me$ ./aevt_decompile /Users/me/Desktop/copy\ files\ to\ target\ folder.app 2021-01-23 20:39:21.622 aevt_decompile[10457:2398389] The file “copy files to target folder” couldn’t be opened because you don’t have permission to view it. Mac:bin me$ ./aevt_decompile /Users/me/Desktop/copy\ files\ to\ target\ folder.app/Contents/Resources/Scripts/main.scpt 2021-01-23 20:39:55.375 aevt_decompile[10469:2400520] The file “main.scpt” couldn’t be opened using text encoding Unicode (UTF-8). Mac:bin me$ ./aevt_decompile /Users/me/Desktop/copy\ files\ to\ target\ folder_no_sign.app/Contents/Resources/Scripts/main.scpt 2021-01-23 20:41:02.693 aevt_decompile[10482:2405472] The file “main.scpt” couldn’t be opened using text encoding Unicode (UTF-8). Mac:bin me$ ./aevt_decompile /Users/me/Desktop/copy\ files\ to\ target\ folder.scpt 2021-01-23 20:41:47.007 aevt_decompile[10488:2407982] The file “copy files to target folder.scpt” couldn’t be opened using text encoding Unicode (UTF-8).
結果は、ことごとく「couldn’t be opened」でデスクトップフォルダ上に置いた①〜④のScriptをオープンできませんでした。
applescript-disassembler
Pythonで書かれたこのツールは実行権限を与えるだけで簡単に動きました。また、①〜④のファイルに対してアクセスすることができました。
こちらは結果が出てきました。かなり膨大な内容です。オリジナルのAppleScriptが、
set fileTexts to paragraphs of (the clipboard) set chkFol to choose folder with prompt "[From] Select Check folder" set moveTargFol to choose folder with prompt "[To] Select Copy Trget folder" repeat with i in fileTexts set j to contents of i set fromPath to (chkFol as string) & j try tell application "Finder" duplicate file fromPath to moveTargFol end tell end try end repeat
の程度のひじょうに簡単なものであったのですが、実際に出力されたのは、
# 注:HTMLタグと間違えられてしまう<>については全角記号に置き換えました
--Applet without Code Sign③ Mac:applescript-disassembler-master me$ ./disassembler.py /Users/me/Desktop/copy\ files\ to\ target\ folder_no_sign.app/Contents/Resources/Scripts/main.scpt === data offset 2 === Function name : <Value type=object value=<Value type=event_identifier value=b'aevt'-b'oapp'-b'null'-b'\x00\x00\x80\x00'-b'****'-b'\x00\x00\x90\x00'>> Function arguments: <empty or unknown> 00000 PushIt 00001 Push0 00002 MessageSend 0 # <Value type=object value=<Value type=event_identifier value=b'Jons'-b'gClp'-b'****'-b'\x00\x00\x00\x00'-b'null'-b'\xff\xff\x80\x00'>> 00005 PushLiteral 1 # <Value type=object value=<Value type=constant value=0x63706172>> 00006 MakeObjectAlias 22 # GetEvery 00007 GetData 00008 PopGlobal b'fileTexts' 00009 StoreResult 0000a PushIt 0000b PushLiteral 3 # <Value type=object value=<Value type=constant value=0x70726d70>> 0000c PushLiteral 4 # [<Value type=special value=nil>, <Value type=string value=b'\x00[\x00F\x00r\x00o\x00m\x00]\x00 \x00S\x00e\x00l\x00e\x00c\x00t\x00 \x00C\x00h\x00e\x00c\x00k\x00 \x00f\x00o\x00l\x00d\x00e\x00r'>] 0000d Push2 0000e MessageSend 5 # <Value type=object value=<Value type=event_identifier value=b'syso'-b'stfl'-b'alis'-b'\x00\x00\x00\x00'-b'null'-b'\xff\xff\x80\x00'>> 00011 GetData 00012 PopGlobal b'chkFol' 00013 StoreResult 00014 PushIt 00015 PushLiteral 3 # <Value type=object value=<Value type=constant value=0x70726d70>> 00016 PushLiteral 7 # [<Value type=special value=nil>, <Value type=string value=b'\x00[\x00T\x00o\x00]\x00 \x00S\x00e\x00l\x00e\x00c\x00t\x00 \x00C\x00o\x00p\x00y\x00 \x00T\x00r\x00g\x00e\x00t\x00 \x00f\x00o\x00l\x00d\x00e\x00r'>] 00017 Push2 00018 MessageSend 5 # <Value type=object value=<Value type=event_identifier value=b'syso'-b'stfl'-b'alis'-b'\x00\x00\x00\x00'-b'null'-b'\xff\xff\x80\x00'>> 0001b GetData 0001c PopGlobal b'moveTargFol' 0001d StoreResult 0001e LinkRepeat 0x64 00021 PushGlobal b'fileTexts' 00022 Dup 00023 PushLiteral 9 # <Value type=object value=<Value type=constant value=0x6b6f636c>> 00024 PushLiteral 10 # <Value type=object value=<Value type=constant value=0x636f626a>> 00025 Push2 00026 MessageSend 11 # <Value type=object value=<Value type=event_identifier value=b'core'-b'cnte'-b'****'-b'\x00\x00\x00\x00'-b'****'-b'\x00\x00\x10\x00'>> 00029 Push1 0002a PushUndefined 0002b RepeatInCollection <disassembler not implemented> 0002c Equal 0002d Equal 0002e PushVariable [var_0] 0002f PushLiteral 12 # <Value type=object value=<Value type=constant value=0x70636e74>> 00030 MakeObjectAlias 21 # GetProperty 00031 GetData 00032 PopGlobal b'j' 00033 StoreResult 00034 PushGlobal b'chkFol' 00035 PushLiteral 14 # <Value type=object value=<Value type=constant value=0x54455854>> 00036 Coerce 00037 PushGlobal b'j' 00038 Concatenate 00039 GetData 0003a PopGlobal b'fromPath' 0003b StoreResult 0003c ErrorHandler 87 0003f PushLiteralExtended 16 # <Descriptor type=b'alis' content=b'\x00\x00\x00\x00\x014\x00\x02\x00\x01\x06Cherry\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00BD\x00\x01\xff\xff\xff\xff\nFinder.app\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\n cu\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0cCoreServices\x00\x02\x00)/:System:Library:CoreServices:Finder.app/\x00\x00\x0e\x00\x16\x00\n\x00F\x00i\x00n\x00d\x00e\x00r\x00.\x00a\x00p\x00p\x00\x0f\x00\x0e\x00\x06\x00C\x00h\x00e\x00r\x00r\x00y\x00\x12\x00&System/Library/CoreServices/Finder.app\x00\x13\x00\x01/\x00\xff\xff\x00\x00'> 00042 Tell 16 00045 PushIt 00046 PushLiteralExtended 17 # <Value type=object value=<Value type=constant value=0x66696c65>> 00049 PushGlobal b'fromPath' 0004a MakeObjectAlias 24 # GetIndexed (item A of B) 0004b PushLiteralExtended 18 # <Value type=object value=<Value type=constant value=0x696e7368>> 0004e PushGlobal b'moveTargFol' 0004f Push2 00050 MessageSend 19 # <Value type=object value=<Value type=event_identifier value=b'core'-b'clon'-b'****'-b'\x00\x00\x00\x00'-b'****'-b'\x00\x00\x90\x00'>> 00053 EndTell 00054 EndErrorHandler 93 00057 HandleError 20 21 0005c PushUndefined 0005d Dup 0005e StoreResult 0005f Jump 0x2b 00062 Return
のような、膨大な内容です。まるで、アセンブラのニーモニックを読んでいるかのような感覚です。
10行程度のScriptから14倍の内容が出力されています。一応、一部の処理内容については(エラートラップ部分など)推測することは可能ですが、前半部分はさっぱりです。断片的に変数名などがわかったり、後半のインデント構造的なものが見えたりするあたりはソースのように見えなくもありませんが、この出力から元のAppleScriptの内容を理解できたりするのでしょうか?
もしかすると、Classic Mac OSの開発経験があるとこの内容を「読む」ことが可能なのかもしれませんが、この内容では自分にはさっぱり分かりません。
現状では、AppleEventを人間が読んでも理解できそうな命令語に置き換え、パラメータともども一覧表示しているというものに見えます。そのレベルの機能については間違いなく実現しているでしょう。ただ、そのAppleEventニーモニックの展開ができたからといって、元のAppleScriptのプログラムを復元できるようには見えません。
# じっと眺めていると「スタック操作を頻繁に行っている」ように見えますが、それでもそれ以上の情報は読み取れません
applescript-disassemblerの機能は同梱のドキュメントのとおりで、実行専用のアプレットから元のAppleScriptのプログラムソースが得られるといったものではありませんでした。その動作内容についても確認できましたし、処理レベルも確認できました。
自分が行った検証のかぎりでは(検証前からおぼろげにわかっていましたが)、一部の人間が他の多くのユーザーの警戒心を煽っているような状況では「ない」と思います。おそらく、その解決ツールという名目でそれらしい動作を行うツールを(AppleScriptを読めない顧客に)売りつけ、お金を巻き上げようという魂胆なのでしょう。