LabyREnthセキュリティ コンテスト: モバイル種目の解答

By , , and

Category: Events, Unit 42

Tags: , ,

概要

今回このブログシリーズでは、LabyREnth、Unit 42セキュリティ コンテストの課題の解答を明らかにします。週に1種目ずつ解答を公開しますが、次はモバイル種目です。

モバイル課題1: これが最後のチャンスだ。賢く選びたまえ

課題作成者: Jeff White @noottrak

この課題用のiOSアプリが与えられています。エミュレーターで実行してみると、四角形がいくつかあり、それにタッチするようになっています。正しい四角形を選ぶと緑色に変わりますが、正しくないものを選ぶと黄色に変わります。正しくないものにもう一度タッチすると赤色に変わり、プレーヤーの負けとなります。

目標はすべての四角形を緑色にしてゲームに勝ちフラグを手に入れることです。もしかしたらゲームをしてみて幸運に恵まれるということがあるかもしれません。あるいは、このプログラムをリバース エンジニアリングしてキーを手に入れることができるかもしれません。このバイナリをIDAで開くと、関数をいろいろ拾い読みすることができ、人目を引く興味深い関数にすぐ気付きます。詳細に述べると、それらの1つは、関数の最初で、複数バイトからなる長い配列を、移動先となるRDXのオフセットをインクリメントしながら移動しています。IDA内の各バイト上で‘R’を押せば、キーの移動が進行中であることが分かります。

PAN{EZE_S41d_Th15_w4s_Ea5y}

モバイル課題2: 複数の選択肢って、あなたは言ったかな

課題作成者: Juan Cortes @kongo_86

APKファイル‘EZfill.apk’が与えられています。このファイルの分析を始めるためには、zipツールを使ってファイルを解凍するか、apktoolを使ってリソース、Manifestファイル、およびsmaliコードを調べることができます。私はapktoolの方が好みです。

AndroidManifest.xmlファイルを調べると、このファイルが比較的小さなAPKであり、main activityを1つ伴っていることが分かります。

次のステップはこのAPKをエミュレーターにロードすることです。

アプリのリストの中にあったアプリが現れます。

アプリを開くとログイン画面が表示されます。偽のデータを少し入力して何が得られるか見てみましょう。

電子メールとパスワードの何らかのチェックをしているようです。この時点でこのアプリのコードの解析を始めることができます。直ちにsmaliコードを見ることもできますし、あるいはBytecodeviewerを使うこともできます。

コードを調べると、逆コンパイルされたコードがjavaで書かれていることが分かります。直ちにある関数が目に留まりますが、この関数はchar型配列をパラメーターに取り、char型配列を返します。この関数の内部にはint型配列がありますが、ひょっとしたらこの配列はフラグがエンコードされたものではないでしょうか。この関数を呼び出している箇所と、引数として渡されるchar型配列を見つける必要があります。トレースして遡るためにonCreate関数を探す必要があります。これはAndroidアプリケーションが開始する際の最初のコールバックです。アプリをエミュレーターにロードするところから呼び戻すとボタンがひとつ見えましたので、ボタンをクリックする動作をある関数が扱っているのだと確信できます。onCreate関数の中にはsetOnClickListenerがあります。setOnClickListenerに渡されるものを辿ってみると、それがOnClick関数を持つクラス‘b’をポイントしています。

onClickはCupsLogin内の関数にコールバックします。コードが少しばかり難読化されていてトレースするのがいささか難しいので、これをトレースするのに重要な点に的を絞ります。次の2つの小さな関数に注目しました。

文字‘@’と長さが4であることのチェックをしていると思われることから、電子メールまたはパスワード、あるいはその両方をチェックしているものと結論付けました。遡ってトレースしていくと、private void m()の中でこれが使われていることがわかります。

その関数の内部にあるコードを調べると、‘string’および‘string2’がオブジェクトに渡されているところが見つかります。

作成中のオブジェクトはAsyncTaskを拡張しています。ここでAsyncTaskに関するAndroidのドキュメンテーションによれば、AsyncTaskは実行されると4つのステップを踏んで行きます。

このクラスの内部にはcharに関するチェックがさらにいくつかありました。コードを分析して、doInBackgroundが関数‘a’を呼び出していることが分かります。この関数内部にもやはり呼び出しがあります。

この関数を分析すると、これがチェックとchar型配列の構築を行った後にその配列を関数に渡していることが分かります。この関数がどんな値を待っているのか調べてみましょう。

どんなcharの値が期待されているのだろうかと考えながら時間を過ごしてみれば、パスワードに関する二、三の値をスタティックに見極めることができます。

それ以外のcharに関しては、総当たり攻撃をするPythonスクリプトを書くことができます。すでに発見してあるデコード処理関数をPythonに入れ替えることを忘れないでください。下記はこれをデコードするサンプル スクリプトです。

このスクリプトにより約1,500個の異なるバリエーションが生成されます。そうしてから‘PAN{‘が含まれている行をgrepで検索して16個に絞り込むことができます。興味深いことに、8個の異なるキーを持つフラグが得られます。

正しい組み合せをどれでもかまわないのでアプリに入力してみるとこんなことになります。

PAN{da_cups_is_halfEmpty_||_halfFull}

モバイル課題3: この実行形式ファイルは、出回っている最高のスマホ15個ならどれでも動作できるぞ

課題作成者: Josh Grunzweig @jgrunzweig

この課題向けに、Windows Mobileプラットフォーム用に作成されたアプリケーションが与えられています。この課題に取り掛かるのには方法が二、三ありますが、スタティックな方法の方が、Microsoft Windowsのモバイル エミュレーターをセットアップしたり、実際のスマートフォンでコードをデバッグするのに比べたら一番簡単だと言っていいでしょう。エミュレートされた環境でアプリケーションを実行したならば、次のようなものが表示されます。

図1 エミュレートされた環境で実行中のアプリケーション
図1 エミュレートされた環境で実行中のアプリケーション

与えられたバイナリを調べる際、このファイルを2回unzip処理を行うと以下のファイルが得られます。

図2 Windows Mobileアプリケーションからunzip処理で得られたファイル
図2 Windows Mobileアプリケーションからunzip処理で得られたファイル

問題の実行形式ファイルは.NETライブラリなので、これをdnSpyのようなプログラムを使って逆コンパイルすることができます。基底をなすコードを調べると、難読化が行われているため内容を読み取って理解するのがいっそう困難になっています。

図3 Windows Mobileアプリケーション内の逆コンパイルされたコード
図3 Windows Mobileアプリケーション内の逆コンパイルされたコード

このコードを1ステップずつ読み進め、その過程で関数をリネームすれば何が起きているのか理解することができます。コードは以下のことを行います。

  1. SystemProductNameが‘Virtual’であるかチェックする。‘Virtual’であれば、コードはエミュレーターの中で動いていることを示しています。
  2. 常にTrueを返す関数に対してブーリアンのチェックを行う。返す値の変更は手動で行う必要があります。
  3. 画面の解像度をチェックし、幅が1000より大きく高さが5よりも大きいものを探す。

これらの条件がすべて満たされた場合、コードは実行を続けます。そうでない場合、‘Hounds Released!’(猟犬が放たれた!)という応答が返ってきます。

図4 たくさんあるエラー メッセージの中で目にする1つ
図4 たくさんあるエラー メッセージの中で目にする1つ

ここまで来れば、コードは与えられたユーザー入力の検査を開始し、正しいキーが与えられたか否か判断します。まず、キーの長さが検査されます。キーが長さ12に満たない場合、ランダムなエラー メッセージが返ってきます。しかし、キーの長さが12であれば、コードの実行がさらに進められます。次にコードは下記のチェックを行います。

  1. SystemProductNameが‘V’で始まっているかチェックする(上述のチェックは‘Virtual’を探すものだったので‘V’で始まっていなければなりません)。この文字列の第6バイト(‘a’)が保存され、後でキーの中で使われます。
  2. 与えられたキーの第1バイトが順序数66すなわち文字‘B’であるかチェックする。
  3. 埋め込まれているMrBurns.jpgファイルがロードされ、第7バイトが読み込まれ、後でキーの中で使われる(‘J’)。
  4. SystemManufacturerの長さが5であり、最後の3文字が‘kia’であることをチェックする。推定される全メーカーに基づけば、このコードが文字列‘Nokia’を探しているものと結論付けることができます。最初の2文字は変数に保存され、後でキーに使われます(‘No’)。
  5. 与えられたキーの2番目から4番目までの文字について、あるキーに対するXOR(排他的論理和)演算処理を行い、‘DIE’という結果になるかチェックする。この手順に対してリバースエンジニアリングを行うと、与えられたキーの2番目から4番目までのバイト範囲にアプリケーションが‘AdP’という入力文字列を探しているのだと結論付けることができます。
  6. 与えられたキーの5番目から8番目までの文字を、埋め込まれた長い文字列でチェックし、‘uzzl’という値を探す。
  7. 同じチェックを9番目と10番目の文字に対して行い、‘3’と‘r’をそれぞれに対して探す。
  8. 最後に、与えられたキーの最後の2バイトに対してさらにチェックを行い、‘!’および‘?’を探す。
  9. これらの条件がすべて満たされると、埋め込まれているGarbage.jpgが読まれ、与えられたキーに対して復号化が試みられる。

出くわしたすべてのことに加え、リバース エンジニアの時間を浪費させるために、さまざまな偽装コード スニペットが含まれています。また、l1()関数とllll()関数を介して文字列の難読化が使用されていました。これらの関数は、それぞれ文字列のunhexとXORに相当します。わずかながらより複雑にするために、関数多重定義も使用され、リバースをさらに扱いずらいものにしています。

学習したすべてのことに基づいて、アプリケーションが長さ12のキーを探していると結論付けることができます。その後、文字列‘aNoJ’が末尾に連結されます。検出したチェックに基づいて、提供されたキーが‘BAdPuzzl3r!?’でなければならないことがわかります。このキーを使用すると、次の結果が得られます。

図5 正しい入力文字列を使用した後のキー
図5 正しい入力文字列を使用した後のキー

PAN{Th4t’s_My_S3cr3t_N0boDy_Def34ts_th3_HOUNDS}

モバイル4課題: (ウォークかスワイプか)そして(赤ちゃんとあなたと泣き声)

課題作成者: Juan Cortes @kongo_86

このモバイル課題では、‘Swip3r’という名前のAPKが提供されています。以前のAPKと同様に、apktoolを使用した分析から開始し、それをエミュレータにロードして、アプリケーションを把握します。私たちは、Androidのadbツールを使用してアプリケーションをインストールします。以下は、これらの手順を強調したスクリーンショットです。

(APKツール)
(APKツール)
(adbによるインストール)
(adbによるインストール)
(エミュレータ内のアプリ アイコン)
(エミュレータ内のアプリ アイコン)

続けて、アプリケーションの基本的な動的分析を実行します。これにより、課題を解決するために何が必要となるかをさらに理解できます。アプリは、“Give me the child (子供をください)”というボタンで起動します。それをクリックすると、画面が変わり、画面下部の文字‘Jared’が“Your eyes can se so cruel…”になります。画面をクリックしても、何かを実行しているようには見えません。APKの名前が示唆するとおり、スワイプすると、赤ちゃんが泣いている画面に変わり、テキスト“0oo0oopps!: 1”が示されます。続けて異なる方向にスワイプすると、テキスト““0oo0oopps: 2”が示されます。再度スワイプすると、テキストの後の数字が増えます。そのため、アプリがスワイプした回数を追跡しているように見えます。何か悪いことを実行していると推測しているようです。

(アプリの起動)
(アプリの起動)
(Jaredの表示)
(Jaredの表示)
(泣いている赤ちゃん)
(泣いている赤ちゃん)

この時点で、動的な分析のおかげで、アプリをある程度は把握できます。APK構造の静的な分析を実行し、何か興味深いものが見つかるかどうかを確認してみましょう。

AndroidManifest.xmlは、APK分析用の重要なファイルですが、この特定のアプリのマニフェストでは、興味深いものは何も明らかになりませんでした。ただし、libフォルダに移動すると、以下の2つのフォルダが見つかり、それぞれがネイティブのライブラリ、“libswiipiin.so”を保持していることがわかります。私の推測では、これは通常のAndroidライブラリではなく、カスタム ライブラリです。

(ライブラリ)
(ライブラリ)

この時点で、ライブラリをIDAにロードするか、またはバイトコード ビューアーを使用してAPKのコードの逆コンパイルを試すか、いずれかを実行できます。なぜ両方ではないのでしょうか?

まず、逆コンパイルされたJavaコードを調べてみましょう。アプリケーションには、MainActivity.classとSwip3r.classの2つのクラスのみがあります。Swip3r classはどちらかと言うと小さく、それがタイトルを設定し、アクティビティ‘MainActivity”を開始していることがわかります。

(Swip3r.class)
(Swip3r.class)

ここで、MainActivity.class内のコードを調べてみましょう。すぐに、基本的な動的分析で観察された興味深い文字列が見つかります。アプリがライブラリ‘swiipiin’のロードを試みていることがわかります。最後に、クラス ファイルの終わりで、2つのネイティブ メソッド、‘wel()’と‘well()’が呼び出されていることを確認できます。一方はパラメータが指定されておらず、他方は8つのパラメータが指定されています。

(oops文字列)
(oops文字列)
(ライブラリのロード)
(ライブラリのロード)
(ネイティブ メソッド)
(ネイティブ メソッド)

この時点で、アプリが2つのネイティブ メソッドとともに、ネイティブ ライブラリを使用していることがわかりました。これらの2つのメソッドが使用されている場所を見つけ、その後、ネイティブ ライブラリ メソッドの分析に移ることに的を絞ります。荒削りながら簡単な方法は、逆コンパイルされたコードをNotepad++にコピーし、これらのネイティブ メソッドを検索することです。‘wel()’がOnCreate()メソッド内で1回使用され、‘well()’がonFling()メソッド内で3回使用されていることがわかりました。最後に、両方のメソッドが、呼び出された後に、テキストを表示するために使用される値を返していることを確認できました。

(wel())
(wel())
(well())
(well())

少しの間、IDAに切り替えて、ネイティブ ライブラリを調べてみましょう。Exports (エクスポート)の下に、以前に逆コンパイルしたJavaコードで見つけたネイティブ メソッドが表示されています。ARMアセンブリを調べると、x86アセンブリを見るよりかなり目が痛くなりますが、これらのメソッドの分析を少々試みます。コードを見ることで、文字列“Your eyes can se so cruel”をロードしてから、それを返していることがわかります。覚えているでしょうか? このテキストは、アプリをエミュレータにロードしたときに見たものです。これは、このメソッドが、呼び出された後に、表示テキストで文字列として使用される値を返すという事実に一致します。他のメソッド‘well()’を見ると、それが関数(注: 私がこの関数の名前を変更しています)‘well_func1_F8C’を呼び出していることがわかります。その関数を調べ、IDAの‘Xrefs from’を使用すると、他にも10の関数を呼び出していることを確認できます。それら10の関数を見ると、ほとんどがある種のビット単位操作を使用したループを持っています。それは、デコードが進行中のものがいくつかあることを示しています。前述のとおり、ARMアセンブリを調べるのは、x86ほど楽しくありません。別のアプローチで、逆コンパイルされたJavaコードを調べます。

(IDA Exports (エクスポート))
(IDA Exports (エクスポート))
(Xref)
(Xref)
(関数ループの例)
(関数ループの例)
(関数ループの例2)
(関数ループの例2)

バイトコード ビューアーの良い点は、異なるJava逆コンパイラからオプションを取得できることです。たとえば、JD-GUI逆コンパイラを使用して‘OnFling()’メソッドに的を絞ると、厄介にネストされたwhileループを取得します。Procyon逆コンパイラを選択すると、うまくネストされたIF…ELSE文のセットが得られ、遥かにコードが読みやすくなります。逆コンパイルされたコードをNotepad++にコピーすると、コードを縮小して、何が起こっているかという‘全体像’をより容易に把握できます。

(全体像)
(全体像)

すばやくGoogle検索すると、何がOnFling()メソッドとそのパラメータのポイントであるかを理解するために役立ちます。これによって、この課題の完了を簡易化するために、何を実行する必要があるかを理解できます。この時点で、各IFおよびELSE IFを調べてコードを分析し、どの値が必要であるか判別できます。最初の条件文のセットから開始して、コードがmotionEvent.getY()、motionEvent.getX()、motionEvent2.getY()、motionEvent2.getX()からの値をチェックしていることがわかります。これらの値は、X軸とY軸を使用して画面上の動きを検出し、引いては、ユーザーがいつ上、下、左、右に動いたかを検出するために使用されます。各条件文の中で、アプリはいくつかのintに、このOnFling()メソッドを通じてチェックされた値を設定しています。やりたいことは、アプリケーションにネイティブ メソッド‘well()’を呼び出させることなので、右へのスワイプの動きでどの値が設定されるか分析を開始し、“0oo0oopps!”メッセージを呼び出す値を設定する動きを避けることができます。コードの学習後、適切な組み合わせは、上、左、下、右、上であるという結論に至ります。いくつかのJaredの写真を楽しめますが、最後のイメージにキーが示されます。PAN{jAr3d_sayz_’swwip3r_!NO!_swipp11nn’}

(開始)

(上)

(左)

(下)

(右)

(上)

もしアプリがメソッド‘onLongPress()’を検出したことに気付いたとしたら、それは隠れキャラの発見です。画面のエミュレータ上を長押しすると、ちょっとした文字列が画面上部に現れます。これはbase64であることを表していますが、それぞれ、https://goo.gl/VgmUUyにデコードされる3つの異なるbase64文字列です。これは、ラビリンスの歌である“Within you – David Bowie 1986”のYouTubeビデオに繋がるGoogleの短縮URLです。残念ながら、インターネットの神は、このビデオを削除してしまっています。興味深いことに、このURLは、さまざまな国から合計で26回クリックされています。注: テスト中に1回クリックしたため、実際には27回です。URLの詳細についてはこちらをご覧ください。

(隠れキャラ)

(デコードされたURL)

PAN{jAr3d_sayz_’swwip3r_!NO!_swipp11nn’}

モバイル5課題: 迷路を無事脱出することができるか

課題作成者: Jeff White @noottrak

1番目のiOSの課題と同様に、ARMコンパイル済みのバイナリとシミュレータ バージョンが提供されています。

シミュレータ フォルダを見ると、death_01.jpg、tunnel_01.jpg、win_01.jpgなど、不吉な名前の付いた画像ファイルが多数あります。バイナリをIDAにロードして文字列を見ると、LOSEやWIN、あるいはURLの先頭部分が含まれた興味深いメッセージが確認できます。

また複数のbase64エンコード文字列も確認できます。

base64エンコード文字列を取り出してデコードすると、単語や文が逆さまになっていたことがわかります。

これらの文字列に基づくと、このアプリケーションは一種のゲームのようです。そこで先に進み、それをシミュレータでブートアップし、動作を確認します。迅速かつ簡潔なシミュレーションなので、iOSまたはAPKシミュレーション用のウェブサイトappetize.ioを使用します。

矢印キーを使用して、「迷路」の中を移動できます。base64デコード文字列の一部が各画面に表示されます。

最終的に失敗して、***LOSE***メッセージが表示されます。

何回かリセットして、迷宮の外に出られました。経路はランダムのようです。同じ手順を繰り返しても、違う場所に着いて失敗するためです。

成功すると、High Score!というメッセージが表示され、http://pansecretloot.comにスコアを送信することができます。スコアを送信すると、以下のメッセージが表示されます。

エラー メッセージには、ドメインを解決できなかった旨と、「no flag for you」が表示されます。ドメイン、pansecretloot.comを確認すると、実際に解決できません。おそらくメッセージはそのことを示していると思われます。ゲームをもう一度プレイすると、今度は別のドメイン http://panlostspace.comを使用しているのが確認されましたが、これもまた解決できないと示されます。

数回プレイしてみると、次のパターンが単純に繰り返されていました。

前述のbase64エンコード文字列を思い浮かべてください。ゲームで表示されるすべてのメッセージの後に、単語のみの短いリストが表示されています。

それらとの関連は簡単にわかります。リストの中から2つの単語がhttp://panの後ろに追加されてドメインが作成されます。いわゆるDGA (ドメイン生成アルゴリズム)です。これが12個の単語の最終的なリストであるなら、同じ単語を2つ並べることもできるため(lostlostなど)、組み合わせは12x12通りとなります。この組み合わせは、簡単に生成してチェックできます。

生成されたリストを繰り返し、DNSルックアップを実施した結果、次の答えを得ました。

このドメインを閲覧すると、文字列M4z3Cub3が返されます。

このように、このアプリケーションは単語リストからドメインを作成するものの、解決エラーのために先に進めないようです。すべてのドメインを既知の存在するサイトに解決されるようにホストのルックアップを変更するとどうなるでしょうか。

Appetize.ioは、アプリケーションを手早く考察するには適していますが、デバッグの観点からは役に立ちません。ロードできるiOSデバイスを実際に保有するほどの余裕はないので、ローカル シミュレータにロードして、ドメイン解決を何とかする方法を考える必要があります。

次のパートは若干複雑ですので、わかりやすくするためにここで説明しておきたいと思います。基本的に、Xcodeプロジェクトを作成し、シミュレータで実行すると、シミュレートされたデバイス用の.appファイルが生成されます。XcodeでProductsの下にある、この.appファイルを右クリックすると、ファイルが含まれたフォルダが開いて、この課題に含まれた.appを簡単に移動することができます。ディレクトリ パスは次のようになります。

labyREnth_mobile5-XXXというディレクトリ名は、プロジェクト名と、シミュレートされたデバイス用にXcodeで作成されたデバイス IDを組み合わせたものです。シミュレータをロードすると、コピーしたアプリケーションとともに空のプロジェクト アプリケーションが表示されます。

アプリケーションはローカルで実行されています。列挙したすべてのドメインを使用して/etc/hostsファイルを変更し、panspacedungeon.comに解決されるIPを指すようにします。

次に、アプリケーションを実行し、成功条件をトリガーできるまでゲームを進めます。

成功です!

PAN{G3t_Sch1f7y}

モバイル6課題: 最高のハンドヘルド

課題作成者: Richard Wartell @wartortell

この課題では、.86pという拡張子を持つファイルが提供されます。一般的な拡張子ではなく、ファイルは2kbしかないので、16進エディタで開きます。

面白い文字列がすぐに見つかりますが、最初にあって最も重要な文字列は**TI86**です。TI86アセンブリ プログラムかもしれません。このファイルを実行できるエミュレータを見つけましょう。

Wabbitemuが役に立ちます。Wabbitemuによって、TI電卓アセンブリ プログラムを実行できるようになります。このプログラムはTI86電卓用であるため、電卓用のTI86 ROMをインストールします。次に、OGMob.86pを開いて、以下の一連のキーを実行して、プログラムをロードします。

これでAsm(OGMob)という行が作成されます。これは、TI86電卓でアセンブリ プログラムを実行する方法です。このプログラムを実行すると下記の情報が得られます。

いくつかのキーを押して色々と試してみると、キーを押すことで表示が変化するようですが、操作内容に関わらずFAILUREという画面に戻ります。次に、逆アセンブラで見てみましょう。TI86バイナリのリバースに関するリソースを探すと、役立つブログの投稿を見つけました。

ただ、ここで推奨されているアドレスをロードしてもうまくいきません。Wabbitemuデバッガで色々と操作しているうちに、バイナリを0xD6FDにロードしなければならないことがわかりました。単に試行錯誤を繰り返してわかったのですが、デバッガで表示されるものと合致するバイトを得ることができました。

正常にロードされると、最終的にグラフ モードで見ることができます。このプログラムのメイン グラフは次のようになります。

ただ、デバッガでは場所を指していても、IDAでどこにも参照する場所がない関数呼び出しが多くあります。そのため、TI86でアドレスをGoogle検索しました。すると定数に関するリンクが見つかりました。また、これらはすべて、電卓の内部関数であることがわかりました。新しいセグメントを作成し、定数をそこに格納することで、IDBにうまくラベルを付けて、動作を確認できます。

すべてをつなぎあわせると、_getkey、比較、条件分岐など、多くの順序があることがわかります。最終的に、前述のキーを入力してFAILUREが表示されたときの表示内容のロジックがわかります。おそらく、正しいキーの組み合わせを入力すれば、課題の鍵を手に入れることができるでしょう。

_getKey呼び出しのロジックを色々と試して、主要な定数に関して前に参照したサイトを使用すると、以下の順序になります。

ENTER CLEAR ( 8 6 7 – 5 3 0 9 )

これを正しい順序で入力すると、画面にこのように表示されます。

これが鍵です。

PAN{dis_C@1c’s_Ju51_4_YOUZ?!?}

ボーナス ラウンド

押すキーを色々と試しているうちに、大規模なコードの実行や、キーを押すたびに画面が変わることがわかりました。コードが参照しているデータを見ると、すべて定数を指しており、この定数を使用して画面上に描画していることがわかります。各定数は、ギャップをベースとした8バイトから構成されているようです。

これらを単なる文字や数字として見ると何もわかりません。例えば、これは8バイト定数の最初の2つです。

しかしこれらをバイナリで見ると、より興味深いものが見えてきます。

01110111  00100100

01010101  00100101

01010101  00110100

01010101  00110101

01101111  10101101

01001000  10101100

01001000  10100101

01001000  10100100

すぐにはわかりませんが、一歩離れて眺めて、白と黒のスペースに変えて見てみると、課題の鍵が中にあることがわかります。前述の最初の2つの定数には、PANという文字の8X8バイトのバイナリ表記が含まれています。すべての定数について同じことをすれば、完全な鍵が手に入るでしょう。

以下にコメントを入力してこれらの課題について感じたことを共有しましょう。他の脅威リサーチャーがこれらの課題をどのように解決したかも確認してください。

モバイル1

モバイル2

モバイル3

モバイル4

モバイル5

モバイル6