CpawCTF - Question20 [Crypto] Block Cipher
与えられたC言語のソースコードを読み解いて復号してフラグを手にれましょう。
暗号文:cpaw{ruoYced_ehpigniriks_i_llrg_stae}
crypto100.c
**#include <stdio.h>
# include <stdlib.h>
# include <string.h>
int main(int argc, char* argv[]){
int i;
int j;
int key = atoi(argv[2]);
const char* flag = argv[1];
printf("cpaw{");
for(i = key - 1; i <= strlen(flag); i+=key)
for(j = i; j>= i - key + 1; j--)
printf("%c", flag[j]);
printf("}");
return 0;
}
**
まあ、とりあえずターミナルで実行してみよ
$gcc cypto100.c //コンパイル
$./a.out ruoYced_ehpigniriks_i_llrg_stae //実行
Segmentation fault: 11
これは11行目でエラーが起こっているらしい
(C初心者すぎて一旦ここで詰まった)
そもそもブロック暗号とはなにかというのが曖昧(ブロックに分けて処理する、代表的なのはDES,TripleDESなどらしい)だったので、
シーザー暗号とブロック暗号の違いでggると...
-シーザー暗号:文字を置き換える
-ブロック暗号:文字を並び替える
らしい
プログラム読まないとだめそうなので、
1つずつggりながらcの勉強と思ってやっていきます。
name | Description |
--------------------|------------------|-----------------------
argc | argument count(引数の個数) |
argv | argument vector(引数の配列) | Much wow |
atoi | 整数値の文字列型データをint型に変換する関数(ファイルから内容を読み込んだ際に数値データを文字列として認識するのが通常らしく、計算処理につかえない状態からint型に変換する方法) | So doge
const|定数である(その変数の値を変更してはいけない)ということを示す修飾子。宣言の型名の部分の前か後につける|
strlen|文字列の長さをバイトで返す
引数につかっている、char*も不思議なので調べる。
C 言語では、文字を取り扱う場合に、char 型を利用する。char 型の変数のサイズは 1 バイトと決められているので、1 つの変数には 1 文字しか保存できない。
char a = 'D';
char b = 'N';
char c = 'A';
printf("%c%c%c\n", a, b, c);
まじか!
複数個の文字からなる文字列の場合は、char 型の配列を利用する。この場合、配列のサイズは、変数を宣言するときに決める必要がある。char 型の配列に文字列を格納する場合、文字列の最後にヌル文字 \0 を入れる必要がある。次のようにダブルクオーテーションマークで変数を作成する場合は、自動的にヌル文字が文字列の終端に挿入されるが、シングルクオーテーションマークの場合は自動的に挿入されない。
char str1[] = "DNA";
char str2[] = {'R', 'N', 'A', '\0'};
printf("%s\n", str1);
printf("%lu\n", sizeof(str1));
printf("%s\n", str2);
printf("%lu\n", sizeof(str1));
そして本題のchar*型
*は「ポインター」のことだそう。
配列の引数にニュアンスが似ているけれども、以下サイトを見ると、少々構造が違う(ポインタに1加算するとデータ型ひとかたまり分加算されるなど)
以下サイトでわかりやすく説明されていました。
超初心者向けプログラミング入門:ポインタの活用例2、メリットデメリット
本題に戻る。
argv[0]:a.out
argv[1]:暗号文
argb[2]:なにか入れないとダメ←keyにあたる
↓
さっきのコマンドのあとにさらに数字いれればいいのでは($~1)($~2)
↓
みため変わるな
↓
($ ~4)
あ。
<追記>
プログラムのきちんとした読み方がわかったので、ポイントを記載する。
for文が入れ子になっているので頭がこんがらがりやすいが、
たとえばkey=4だったら、
iが3で始まり、4ずつ増える。条件はiがフラグの文字数に達するまでの間。
(基本的に、はじまり→増えかた→条件で考えるとよい)
次に j は、3ではじまり、1つずつ減る。i-key+1より大きい間。つまり最初のi=3のなかだと3-4=0になるまでの間。
で、該当するのをプリント。
想像すると、3,2,1,0,(3+4たして)7,6,5,4,
と文字列をプリント。それで文字が順番に移り変わっていくようになっている。このような文字の並び替えを行なっているのでブロック暗号というのだ。