ASCII値の合計を比較する簡単な暗号アルゴリズムを用いて、自らリバースエンジニアリングするためのパスワード認証プログラムを作成します。
はじめに
おはよう。@bioerrorlogです。
このリバースエンジニアリングシリーズの初回には、単純に入力文字と正規パスワードを比較するパスワード認証プログラムをCで作成しました。
#include <string.h> #include <stdio.h> int main(int argc, char *argv[]) { if(argc==2) { printf("Checking Your Pass: %s\n", argv[1]); if(strcmp(argv[1], "Antoine-Marie-Jean-Baptiste-Roger_comte-de-Saint-Exupery")==0) { printf("Hello, Master.\n"); } else { printf("Access Denied.\n"); } } else { printf("Access Denied.\n"); } return 0; }
前回まではこのCコードのバイナリコードを解析してきましたが、コード上に正規パスワードが直接記述されているため、strings
コマンドなどで簡単にパスワードを調べることができてしまいました1。
そこで、今回は簡単な暗号アルゴリズムを用いて、パスワード認証プログラムをこれまでより少し破りにくいものに改良します2。
作業環境
Ubuntu18.04.1 LTS を
Windows10の上に、VMwareによって構築した仮想環境で起動しています。
www.bioerrorlog.work
パスワード認証の暗号化
簡単な暗号アルゴリズム
ごく簡単な暗号アルゴリズムとして、パスワードのASCII3値の合計を比較するやり方を使用します。 たとえば、パスワードが"PASS"だった場合、
パスワード: | P | A | S | S | 合計 |
---|---|---|---|---|---|
ASCII値: | 0x50 | 0x41 | 0x53 | 0x53 | 311 |
ASCII値の合計は10進数で311となります。 この値を正規パスワードと入力パスワードで比較することで、パスワードの認証を行います。
正規パスワードの合計ASCII値を算出する
それでは、正規パスワードのASCII値の合計を算出します。 上記のパスワード認証プログラムのソースコードでは、正規パスワードが"Antoine-Marie-Jean-Baptiste-Roger_comte-de-Saint-Exupery"となっています。 この正規パスワードのASCII値の合計を算出するために、次のようなCコード"ascii_sum.c"を書きました。
#include <string.h> #include <stdio.h> int main(int argc, char *argv[]) { if(argc==2) { int sum = 0; for (int i=0; i<strlen(argv[1]); i++) { sum += (int)argv[1][i]; } printf("ASCII sum: %d\n", sum); } else { printf("Usage: <key>\n"); } return 0; }
これで、引数に渡した文字列の合計ASCII値が出力されるはずです。 コンパイルしてから、試しに上に示した"PASS"を渡してみると、
$ ./ascii_sum PASS ASCII sum: 311
正しく合計値311が表示され、プログラムが予想通りに機能することが伺えます。
そこで、正規パスワードのASCII合計値を調べると、
$ ./ascii_sum Antoine-Marie-Jean-Baptiste-Roger_comte-de-Saint-Exupery ASCII sum: 5345
5345であることが分かりました。
パスワード認証プログラムを作成する
それでは、パスワード認証プログラムを変更して、渡された文字列の合計ASCII値を5345と比較することでアクセス可否を判断するプログラムに書き換えます。
#include <string.h> #include <stdio.h> int main(int argc, char *argv[]) { if(argc==2) { printf("Checking Your Pass: %s\n", argv[1]); int sum = 0; for (int i=0; i<strlen(argv[1]); i++) { sum += (int)argv[1][i]; } if(sum==5345) { printf("Hello, Master.\n"); } else { printf("Access Denied.\n"); } } else { printf("Access Denied.\n"); } return 0; }
これを"your_pass_2.c"とし、コンパイルしてプログラムの挙動を確認します。
まずは間違ったパスワード"WRONG-PASS"を渡して実行します。
$ ./your_pass_2 WRONG-PASS Checking Your Pass: WRONG-PASS Access Denied.
予想通りにアクセスが拒否されました。
次に、正規パスワード"Antoine-Marie-Jean-Baptiste-Roger_comte-de-Saint-Exupery"を渡して実行します。
$ ./your_pass_2 Antoine-Marie-Jean-Baptiste-Roger_comte-de-Saint-Exupery Checking Your Pass: Antoine-Marie-Jean-Baptiste-Roger_comte-de-Saint-Exupery Hello, Master.
見事、アクセスが承認されました。 これで、ソースコードに直接正規パスワードを記述しない簡単なパスワード認証プログラムができました。
おわりに
今回は、ごく簡単な暗号アルゴリズムを用いて、パスワード認証プログラムを改良しました。
次回は、このバイナリコードをリバースエンジニアリングし、正解パスワードを生成する"Keygen"プログラムを作成します。
それにしても、少し調べてみると暗号アルゴリズムというものは大変奥が深そうです。 今回は可能な限り簡単なやり方をしましたが、現代においても暗号技術は一つの学問として日々研究成果が報告されています。
ハードウェアについてまるで知識がありませんが、たとえば量子コンピュータが飛躍的に高い性能で実現した場合、現在使われている暗号技術が解読可能になったりはしないのでしょうか。 仮に解読可能になった場合、この複雑にシステムが絡み合うIT社会の中で、新しい暗号技術への移行はスムーズに行えるものなのでしょうか。
妄想は膨らみます。
[関連記事]
-
ハードコードされたパスワードを読み出す | リバースエンジニアリング入門#4 - 生物系がゼロから始めるTech Blogを参照。↩
-
LiveOverflow氏の動画https://youtu.be/qS4VWL5R_OMを参考にしています。↩
-
ASCIIとは、最もよく使用される文字コードです。数値と文字が対応したASCIIコードによって、コンピュータによる文字の表示を実現します。ASCIIコードは、ターミナルで
$ man ascii
とすることで見ることができます。↩