セキュリティ・キャンプ全国大会2019に参加した

タイトルの通りなのですが、セキュリティ・キャンプ全国大会2019を修了したのでその参加記的なのを書いていきます。 前に応募用紙晒しをしたときにも書きましたが私はYトラックのOS開発ゼミのフルスクラッチOSを書こう!というテーマで参加しました。 集中開発コースなのでずっとOSを開発してたわけですが、OSの機能など細かい解説は復習も兼ねてじっくりとやっていきたいので追々scrapboxのほうにまとめていきます。この記事は開発日誌的なものだと思っていただければ良いと思います。

1日目

1日目は顔合わせの日なので開発はしませんでしたが、特別講演やLT大会、それとグループワークがありました。 余談ですが、実はこの日お昼くらいから偏頭痛をこじらせていて、ずっと痛い頭を抱えていたので何があったのかよく覚えていません。悲しい。こんなことにならないようにキャンプ前日はちゃんと休みましょう。

2日目

2日目は開発時間が一番長い日でした。

午前中はuchan先生つきっきりでOSのデバッグをしていました。

バグの内容は割り込みハンドラの設定後、割り込みがあると再起動してしまうというものでした。再起動の直接的原因はトリプルフォルトというもので、x86の場合ダブルフォルトまでであればダブルフォルト例外を発行しますが、トリプルフォルトの場合は再起動します。おそらく目的の割り込みハンドラだけでなく、例外ハンドラも正しく設定できていないためトリプルフォルトとなっているのだろうと検討をつけ、まずはIDTを設定するコードにバグがないか静的解析を試みました。しかし問題がなさそうに見えたので、今度はsidt命令を使って登録したIDTRやディスクリプタが正しいか確認したところ、ディスクリプタに登録したハンドラ関数のアドレスが正しくないことが判明。実はこの事象、数日前に同じくOS開発ゼミに参加していた突撃隊さんも遭遇していたものを踏んでいたことがわかったのです。結論としてはコンパイルオプションに-fno-picをつければ解決するということだったのですが、もっと詳しく知りたいという方はこちらをご覧ください。

バグが取れてうれしい私↓

例外ハンドラが正しく登録出来たことでデバッグもしやすくなりました↓

そして午後からはメモリ管理をしてみようと思い勉強や実装を始めました。メモリ管理をするためには、メモリマップを知らなければなりません。メモリマップはUEFIのBoot ServicesのgetMemoryMap()によって取得できます。

上記の通りメモリマップを取得するプログラムを書いていたのですが、ここで「配列の先頭アドレスのアドレス」を渡さなければいけない箇所を誤って「配列の先頭アドレス」を渡してしまっていたが為に、次の日の午前まで時間を溶かしてしまいました。

3日目

この日は寝坊して、IPAの方と看護師さんが起こしにきました。本当に申し訳ないです。

起床技術者試験に落ちた後、朝食抜きで始まった開発ですが午前中は先程言ったバグのデバッグをチューターのPG_MANAさんとやっていました。C言語はもう少し人間に優しくなってほしいです。

同じくOS開発ゼミに参加していて、Rustで組み込みOSを自作していたikubakuさんからこんなこんなお言葉を頂きました↓

取得できたメモリマップ↓

午後は取得できたメモリマップをもとにメモリ管理を実装していくのですが、ページングを利用しているOSではまずページ単位でメモリの割当をするページフレームアロケーターを使い、その中でmalloc()などが細かくメモリの割当をするということがほとんどなそうなので私もそれにならうことにしました。

せっかくページフレームアロケーターを実装するのであればページテーブルの設定も出来たほうがいいと思い、PG_MANAさんに教えてもらいながらページテーブルの設定をしました。

この日の開発は夕食前までで、夕食後は企業紹介やグループワークがありました。

4日目

4日目はしっかり6:30に起床し朝食にありつくことができました。

そして午前は3日目に設定したページテーブルに合わせて空き領域を4KiBにアラインメントしページフレームのブロックを作りました。

また、簡単な実装ではありますがページフレームアロケーターも午前中にできました。

Yトラックでは昼食後に成果発表会を行うことになっていたので、午後はその準備をしました。 発表時間は一人2分ととても少なく、あまりいい発表が出来ずお見苦しいところをお見せしてしまいました。

発表会が終わってから夕食まではとりあえず今まで実装してきた機能がすべてちゃんと動作するか確かめてみようと思い、コメントアウトしていた関数をすべてもとに戻し動作確認してみたところ、シリアル通信がqemuでは動くものの実機では正しく動いていないことがわかりそのデバッグをしました。

しかし原因はよく分からずそのまま夕食、企業紹介、グループワークへ。

シリアル通信の設定が悪いのかなと思い、シリアル通信に詳しそうな坂井弘亮師匠に見てもらったところ、コンパイラの最適化でシリアル通信の送信が可能かどうか判断する関数の呼び出しが、1回しか行われていない(ソースコード上ではbusy loopで呼び出してる)のではないかというアドバイスを頂きました。

そこでコンパイルオプションに-O0を追加し動かしてみたのですがこれでもまだ動かず。 講師のuchan先生にも見てもらい、最終的に原因はアセンブリで定義していたinb()関数が間違っていたことであることがわかりました。悲しい。

5日目

5日目は最終日です。他のトラックも含めた成果発表を聞きました。 井上root取っ太郎が面白かったです。

全体を通しての感想

色んな人が自分のOSのデバッグを手伝ってくれるのが本当に心強いなと思いました。こんな機会なかなかないです。

今までは30日OS自作本やブログ記事、同人誌を見て写してただ動作を確認してみるということが多かったのですが、キャンプではオリジナルなコードもたくさん生やせてやっと自分でOSを作るということがわかった気がします。

5日間お疲れ様でした。

6日目?

7日目??

セキュリティ・キャンプ全国大会2019へ参加することになった(応募用紙晒し)

中間試験が一段落したので少し出遅れた感はあるけれど、この記事を書いています。

題名のとおりセキュリティ・キャンプ全国大会2019のシステムプログラミングトラックOS開発ゼミに参加することになったので、恒例の応募用紙晒しをしてみようと思います。 ちなみにセキュキャンに応募するのは今回が2回目です。実はリバースエンジニアリングゼミにも興味があってそちらの応募用紙も完成させてはいたのですが、最終的にOS開発ゼミのほうで提出することにしました。

あらためて自分の応募用紙を見直してみると結構はずかしいです。そういえば書いている最中も自分の文章にあまり自信がもてなくて何回も消したり書いたりしてたなあなんて思いだしました。

以下で掲載している応募用課題はこちらで公開されています https://www.ipa.go.jp/files/000073173.txt

セキュリティ・キャンプ全国大会2019のホームページはこちら https://www.ipa.go.jp/jinzai/camp/2019/zenkoku2019_index.html

応募用紙

  • 共通問題A
我々講師は、普段いくつかのOSを使っていますが、使い込むうちに色々な発見をします。
皆さんもきっとそういう体験があると思います。
あなたが普段使っているOSで、好きな機能と改善してほしい部分について、思いのたけを聞かせてください。
この問では、皆さんが普段どの程度興味を持って既存OSを観察しているかを評価します。

私が使っているOSで好きな部分は、OSのソースコードが大変に簡潔に記述されていること、そして余計な機能を一切入れないこと、またそれらによってOSに存在する脆弱性を限りなく少なくすることを目的にしていることです。 このOSのソースコードは本当にびっくりするくらいにきれいです。私はOSというものにそこまで深く触れたことがなく、C言語C++でのプログラミングを少ししたことがある程度なのですが、それでも他のOSのソースコードを読もうとしたときより「これは楽に読めるぞ」と感じたのでトリッキーなコードが少なく素直なのだと思います。また、余計な機能を一切入れないこともコードの単純化に寄与しています。普段ほとんどの人が使わないような機能のためにOSの開発がより困難なものになってしまうのは私は良くないと思います。このようにOSの構造を簡潔に、わかりやすくすることで見通しを良くすることに私はとても共感しています。 しかし、これらは決していいことづくしというわけではありません。このOSはソースコードの単純さや余計な機能を一切入れないことによってパフォーマンスを犠牲にしています。ハードウェアの性能向上を待てばパフォーマンスは良くなると思いますが、ハードウェアの性能向上にそこまで期待していいのかという問題もありますから、なかなか難しい問題だなと思います。

  • 共通問題B
皆さんが仮にOSを作るとしたら、「どんなOS(やOSの機能)を作ってみたい」でしょうか?
(既にOSを作った事がある人は、その特徴を書いてくれても構いません。)
そして、なぜそれを作ってみたいと思ったのでしょうか?
皆さんが心の中で夢描いているであろう、ワクワクするようなOS像を教えてください。
※「Linux開発者を目指そう!」テーマを受講したいと思っている方は「どんなLinuxカーネルの機能を作ってみたいか」を答えてください。
※「Raspberry Pi向け組み込みOSを作ろう!」テーマを受講したいと思っている方は「どんな組み込みシステムを作ってみたいか」を答えてください。

Linuxでは現在Linux向けにコンパイルされたプログラムしか実行することができなかったと思いますが、他のOS向けにコンパイルされたプログラムを動かすことができるバイナリエミュレーションの機能をつくってみたいです。 動機としては、この機能が特別ほしいなと思ったというわけではなく、単に実装してみたいなと思ったからです。私は数多くあるOSの機能のうちユーザーアプリケーションを実行する機能が好きです。もともと私がOSに興味をもったきっかけが、自分の書いたプログラムがどのように動いているのか知りたかったことにあるのが影響しているのかもしれません。ユーザープログラムを実行するに際してはいろんなOSでいろんな工夫がされているなと思います。例えば、LinuxにはVDSOというものがありますが、これはシステムコールはkernel側で処理されるものだという常識を覆すおもしろい発明だなと思います。

  • 共通問題C
C言語で双方向リンクリストとそれを操作する関数を作り、ソースコードを提出してください。
  リンクリストを生成する関数、要素を任意の場所に挿入する関数、全ての要素を順に標準出力に印字する関数、の3つがあれば十分です。
  やる気があればもっとたくさんの機能を実装しても構いません!
#include <stdio.h>
#include <stdlib.h>

int init(void);
void end(void);
struct node * search_tail(void);
int insert_tail(int value);
void delete_tail(void);
int insert_index(int value, unsigned int index);
void print_list(void);

struct node {
    int value;
    struct node *next;
    struct node *prev;
};

struct node *head;

int
init(void)
{
    head = malloc(sizeof(struct node));
    if(head == NULL) return -1;
    head->value = 0;
    head->next  = NULL;
    head->prev  = NULL;
    return 0;
}

void
end(void)
{
    struct node *tail = search_tail();
    while(tail != head) {
        delete_tail();
        tail = search_tail();
    }
    free(head);
    return;
}

struct node *
search_tail(void)
{
    struct node *search = head;
    while(1) {
        if(search->next == NULL) return search;
        search = search->next;
    }
}

int
insert_tail(int value)
{
    struct node *ins;
    struct node *tail = search_tail();
    
    ins = malloc(sizeof(struct node));
    if(ins == NULL) return -1;
    
    ins->value = value;
    ins->next = NULL;
    ins->prev = tail;
    tail->next = ins;
    return 0;
}

void
delete_tail(void)
{
    struct node *tail = search_tail();
    if(tail == head) return;
    tail->prev->next = NULL;
    free(tail);
    return;
}

int
insert_index(int value, unsigned int index)
{
    unsigned int counter = 0;
    struct node *current = head;
    struct node *ins;

    ins = malloc(sizeof(struct node));
    if(ins == NULL) return -1;
    
    if(index < 0) return -1;
    while(counter < index) {
        if(current == NULL) return -1;
        current = head->next;
        counter++;
    }
    if(current == NULL) return -1;

    ins->value = value;
    ins->prev  = current;
    ins->next = current->next;

    current->next = ins;
    return 0;
}

void
print_list(void)
{
    struct node *current = head->next;
    while(current != NULL) {
        printf("%d\n", current->value);
        current = current->next;
    }
    return;
}

int
main(int argc, char *argv[])
{
    if(init() < 0) return -1;
    if(insert_index(5, 0) < 0) puts("error");
    if(insert_tail(6) < 0) puts("error");
    if(insert_index(3, 1) < 0) puts("error");
    print_list();
    end();
    return 0;
}
設計・実装で工夫した点を述べてください。

整数型の符号の有無や関数の引数などを最小限に抑え、簡潔な実装を心がけました。また、メモリリークなどのバグがないようエラーチェックをしっかりと行ったつもりです。

  • 選択問題S3
Linuxカーネルについて知りたいこと、それについてこれまで調べたこと、
つまづいたことを教えてください。最終的に解決しなかったとしてもOKです。
技術力が優れているかではなく、どれだけ試行錯誤したかという観点で採点をします。
「この機能のこのコードの意味がわからなかった」という高度なものでもいいですし、
「そもそも何から手を付けていいのかもわからなかった」というものでも構いません。

共通課題でも述べたのですが、私はプログラムを実行する仕組みに興味があるのでそれに関連するコードを少しだけ読んだことがあります。そこで不思議に思ったことなのですが、linuxのローダーの実装はfsというディレクトリの下に配置されています。fsというのはおそらくfilesystemのことをさしているのだと思いますが、自分にはこの理由がよくわかりませんでしたし、調べてもこれについて述べているものは探した限りなかったです。また、実際にLinuxにコントリビュートするとして、どういう機能を実装するかというアイデアをどうやって思いつくのか知りたいです。Linuxは多くの優秀な人がコントリビュートしていると思いますが、そのなかで必要とされる実装をどうやって生み出すのか私には全然分かりません。

  • 共通問題D
その他、書ききれなかったことを好きなだけ書いてください。

いままで自分一人では解決できなかった疑問をこの機会にぜひ解消していきたいです。そして、自分もLinuxや他のOSも含め貢献出来るような人になれるように努めていきたいです。

Emacsの設定@Gentoo&X11

春休みで時間があるので環境づくりに勤しんでおります。 今回は、前から気になっていたEmacsをインストールしたのでその設定方法を備忘録として残しておきます。

一番苦労したのはGUIのフォントの設定でした。ですから、まずはフォントの設定について述べておこうと思います。

フォントの設定@GUI

まず、Emacsのインストールですが「xft」のコンパイルオプションをpackage.useで有効にしておきます。

app-editors/emacs xft

次に~/.Xresourcesを以下のように編集します。

Xft.antialias: true

最後に、~/.emacs.d/init.elに以下の文字列を追加します。

(cond ((display-graphic-p)
       (set-default-font "{FontName}")
       (set-fontset-font (frame-parameter nil 'font)
             'japanese-jisx0208
             '("{FontName}" . "unicode-bmp")) )
      (t 0))

これで、GUIEmacsのフォントがいい感じになって幸せです。

package.elの設定

~/.emacs.d/init.elに以下を追加。

(require 'package)

(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/"))

(add-to-list 'package-archives '("melpa-stable" . "https://stable.melpa.org/packages/"))

(add-to-list 'package-archives  '("marmalade" . "https://marmalade-repo.org/packages/"))

(add-to-list 'package-archives '("org" . "http://orgmode.org/elpa/"))

Mozcインストール

M-x package-list-packages
mozc i
x

~/.emacs.d/init.elに以下を追加。

(require 'mozc)
(set-language-environment "Japanese")
(setq default-input-mothod "japanese-mozc")
(prefer-coding-system 'utf-8)
(global-set-key (kbd "C-j") 'toggle-input-method)

mewインストール

SMTP: STARTTLS, IMAP: STARTTLSで設定。

stunnelをコンパイルしておきます。

~/.emacs.d/init.elに以下を追加。

(autoload 'mew "mew" nil t)
(autoload 'mew-send "mew" nil t)

(setq read-mail-command 'mew)

;; Optional setup (e.g. C-xm for sending a message):
(autoload 'mew-user-agent-compose "mew" nil t)
(if (boundp 'mail-user-agent)
    (setq mail-user-agent 'mew-user-agent))
(if (fboundp 'define-mail-user-agent)
    (define-mail-user-agent
      'mew-user-agent
      'mew-user-agent-compose
      'mew-draft-send-message
      'mew-draft-kill
      'mew-send-hook))

(setq mew-prog-ssl "/usr/bin/stunnel")
(setq mew-name "{Name}")
(setq mew-user "{Name}")
(setq mew-mail-domain "{Domain}")
(setq mew-smtp-user "{Name}")
(setq mew-smtp-server "{Domain}")
(setq mew-smtp-auth t)
(setq mew-smtp-ssl t)
(setq mew-smtp-port {Port})
(setq mew-smtp-ssl-port mew-smtp-port)
(setq mew-proto "%")
(setq mew-imap-user "{Name}")
(setq mew-imap-server "{Domain}")
(setq mew-imap-auth t)
(setq mew-imap-ssl t)
(setq mew-imap-port {Port})
(setq mew-imap-ssl-port mew-imap-port)
(setq mew-use-cached-passwd t)
(setq mew-ssl-verify-level 0)

以上。

Gentoo Linuxを使い始めた

TL;DR

前々からsystemdから抜け出したいなーという気持ちがあったので、initシステムを含め随所で選択の自由が与えられているLinuxディストリビューションGentoo Linuxを使い始めました。 この記事は、Firefoxコンパイル中に暇だから書こうと思い立ち、とりあえずインストール手順をまとめてみたポエムです。

さてインストールですが、基本はwikiに忠実にやっていけば大丈夫です。とても親切にわかりやすくまとめられているなと感動しました。

wiki.gentoo.org

以下、自分で選択する必要があったところについて簡単に書いていきます。

インストール環境

手順

Live Mediaを用意し、起動する

自分はminimalのやつをUSB Memoryに書き込みました。起動するとおなじみのgrubが出てくるので適当に選んで進みます。

インストールの準備をする

  • ネットワーク

自分のPCにはRJ45がささらない(かつUSBtoRJ45を持ってなかった)のでWiFiでインストールしました。 Live環境にはもとからwpa_supplicantが入っているのでこれでよしなに繋いでdhcpcdでip addressを貰えばいい感じです。

% ifconfig {interface} up
% wpa_supplicant -B -i {interface} -c <(wpa_passphrase {SSID} {PASSWORD})
% dhcpcd
  • ストレージ

自分のPCのSSDにはすでにOpenBSDとArchLinuxとUbuntuが入っていて一杯だったのでUbuntuの入っているパーティションをmkfs.ext4して使うことにしました。

  • 日時

ntpがちゃんと降ってくる恵まれた環境だったのでntpdで時間を合わせました。

  • stage tarballのダウンロード&展開

current-stage3-amd64を選択しました。tar.xzの展開方法が分からなかったので調べました。

  • make.conf

CFLAGSに-march=nativeを足して、MAKEOPTSに-j3を指定しました。

  • mirror serverの選択

北陸先端科学技術大学院大学にお世話になります。

  • DNS情報のコピー

これ最初忘れてて、あれ?インターネットにつながらないぞ!!を20分くらいやってました。

あとは適当にマウントしてchrootすればベース環境に入れます。

ベース環境の整備

よくわからないのでwikiに従って適当にやりました。eselectでprofileを選ぶところ、変にgnomeとかついているやつを選んでしまったので@worldの更新に3時間くらい取られました。まいった。

カーネルビルド

Gentooの象徴とも言えるカーネルビルドのお時間です。 まともに使えるLinuxカーネルのビルドはいままでに一度もやったことがなかったので結構苦戦しました。 とりあえず大事なのは、使うファイルシステムのドライバとUSBドライバをちゃんと選択しておくことです。これだけクリアしてればあとから何度でもやり直しできます。

自分がいじった設定としては、MMCとSCSI周りとUSBのNetworking Frameworkの有効化、それとNICのドライバをカーネルに含めてしまう設定くらいのものです。

今後いじってみて足りない機能は追加してみます。

設定が終わったらmakeしてカーネルモジュールとbzimageのインストールをして終わりです。このとき、/bootをマウントするのをお忘れなく。

fstab

必要に応じて書きます。最低限、/と/bootがあれば良さそう。

Hostname

かっこいい名前をつけましょう。モテるための秘訣です。

あとはwiki通りにやってumountして、grubのコンフィグをいじるとブートできます。 ブートしたあとはx11とwmを入れてstartxすると幸せになれます。

(ポエム書き終えたけどまだFirefoxコンパイル終わってない...)

InterKosenCTF Writeup [初のイベント型CTFに参戦]

学校の先輩に誘われて、初めてリアルタイムで開催されているCTFに参加してみました(といっても、ksnctfのVillager Aくらいしか解いたことがないので実質CTF処女です)。 3日間の開催でしたが、1日目は早々にして寝落ちしたため、3日目はアマチュア無線の試験を受けに行っていたため取り組めたのは1日だけでした。その1日は先輩と一緒に新宿のルノアールで一日中CTFをやっていました(ルノアールさん長居してごめんなさい)。

webとかcryptoとかはそもそも全く見たこともなかったので解法の検討が全くつきませんでした。なので先輩に任せっきりでした(ごめんなさい)。私が唯一行けそうだなーと思ったのはreversingとpwnだけだったので基本的にその2つだけに集中して取り組みました。 それで、結局解けたのはreversingの100pt問題、「flag generator」だけでした。他の人の参考に、というよりかは解いただけで放置してしまうのはもったいない気がするのでこうして記録しておこうと思った次第です。

問題で渡されたのはx86_64 Linux向けのELFバイナリでした。 実行しても何も表示されず... とりあえず逆アセンブルして読んで見る。

0000000000401152 <r>:
  401152:  55                     push   rbp
  401153:  48 89 e5               mov    rbp,rsp
  401156:  8b 05 f0 2e 00 00      mov    eax,DWORD PTR [rip+0x2ef0]        # 40404c <s>
  40115c:   69 c0 6d 4e c6 41       imul   eax,eax,0x41c64e6d
  401162:  05 39 30 00 00           add    eax,0x3039
  401167:  25 ff ff ff 7f        and    eax,0x7fffffff
  40116c:   89 05 da 2e 00 00     mov    DWORD PTR [rip+0x2eda],eax        # 40404c <s>
  401172:  8b 05 d4 2e 00 00      mov    eax,DWORD PTR [rip+0x2ed4]        # 40404c <s>
  401178:  5d                      pop    rbp
  401179:  c3                       ret

000000000040117a <main>:
  40117a:   55                     push   rbp
  40117b:   48 89 e5               mov    rbp,rsp
  40117e:   48 83 ec 50           sub    rsp,0x50
  401182:  64 48 8b 04 25 28 00   mov    rax,QWORD PTR fs:0x28
  401189:  00 00 
  40118b:   48 89 45 f8           mov    QWORD PTR [rbp-0x8],rax
  40118f:   31 c0                   xor    eax,eax
  401191:  c7 45 d0 35 59 8f 60  mov    DWORD PTR [rbp-0x30],0x608f5935
  401198:  c7 45 d4 91 64 50 57     mov    DWORD PTR [rbp-0x2c],0x57506491
  40119f:   c7 45 d8 57 55 36 27     mov    DWORD PTR [rbp-0x28],0x27365557
  4011a6:   c7 45 dc a1 de e3 54   mov    DWORD PTR [rbp-0x24],0x54e3dea1
  4011ad:   c7 45 e0 d5 4e 5a 75     mov    DWORD PTR [rbp-0x20],0x755a4ed5
  4011b4:   c7 45 e4 b7 2e f4 17  mov    DWORD PTR [rbp-0x1c],0x17f42eb7
  4011bb:   c7 45 e8 59 90 4f 4a   mov    DWORD PTR [rbp-0x18],0x4a4f9059
  4011c2:   c7 45 ec 27 e8 08 1a    mov    DWORD PTR [rbp-0x14],0x1a08e827
  4011c9:   c7 45 f0 1f 39 9d 0d     mov    DWORD PTR [rbp-0x10],0xd9d391f
  4011d0:   c7 45 f4 aa 33 e5 59     mov    DWORD PTR [rbp-0xc],0x59e533aa
  4011d7:   c7 45 c8 7e 16 dc 25    mov    DWORD PTR [rbp-0x38],0x25dc167e
  4011de:   c7 45 cc 0a 00 00 00     mov    DWORD PTR [rbp-0x34],0xa
  4011e5:   c7 45 c0 00 00 00 00    mov    DWORD PTR [rbp-0x40],0x0
  4011ec:   c7 45 c4 00 00 00 00    mov    DWORD PTR [rbp-0x3c],0x0
  4011f3:   c7 45 bc 00 00 00 00    mov    DWORD PTR [rbp-0x44],0x0
  4011fa:   83 7d c4 00            cmp    DWORD PTR [rbp-0x3c],0x0
  4011fe:   75 10                 jne    401210 <main+0x96>
  401200:  bf 00 00 00 00          mov    edi,0x0
  401205:  e8 46 fe ff ff         call   401050 <time@plt>
  40120a:   89 05 3c 2e 00 00     mov    DWORD PTR [rip+0x2e3c],eax        # 40404c <s>
  401210:  b8 00 00 00 00          mov    eax,0x0
  401215:  e8 38 ff ff ff         call   401152 <r>
  40121a:   89 45 bc               mov    DWORD PTR [rbp-0x44],eax
  40121d:   8b 45 bc                mov    eax,DWORD PTR [rbp-0x44]
  401220:  39 45 c8               cmp    DWORD PTR [rbp-0x38],eax
  401223:  75 07                 jne    40122c <main+0xb2>
  401225:  c7 45 c4 01 00 00 00    mov    DWORD PTR [rbp-0x3c],0x1
  40122c:   83 7d c4 00            cmp    DWORD PTR [rbp-0x3c],0x0
  401230:  74 35                 je     401267 <main+0xed>
  401232:  8b 45 c0                mov    eax,DWORD PTR [rbp-0x40]
  401235:  48 98                 cdqe   
  401237:  8b 54 85 d0            mov    edx,DWORD PTR [rbp+rax*4-0x30]
  40123b:   8b 45 bc                mov    eax,DWORD PTR [rbp-0x44]
  40123e:   31 d0                   xor    eax,edx
  401240:  89 45 bc               mov    DWORD PTR [rbp-0x44],eax
  401243:  48 8d 45 bc            lea    rax,[rbp-0x44]
  401247:  48 89 c6               mov    rsi,rax
  40124a:   48 8d 3d b3 0d 00 00    lea    rdi,[rip+0xdb3]        # 402004 <_IO_stdin_used+0x4>
  401251:  b8 00 00 00 00          mov    eax,0x0
  401256:  e8 e5 fd ff ff           call   401040 <printf@plt>
  40125b:   83 45 c0 01           add    DWORD PTR [rbp-0x40],0x1
  40125f:   8b 45 c0                mov    eax,DWORD PTR [rbp-0x40]
  401262:  3b 45 cc                cmp    eax,DWORD PTR [rbp-0x34]
  401265:  74 0c                   je     401273 <main+0xf9>
  401267:  bf 01 00 00 00          mov    edi,0x1
  40126c:   e8 ef fd ff ff           call   401060 <sleep@plt>
  401271:  eb 87                   jmp    4011fa <main+0x80>
  401273:  90                     nop
  401274:  b8 00 00 00 00          mov    eax,0x0
  401279:  48 8b 4d f8             mov    rcx,QWORD PTR [rbp-0x8]
  40127d:   64 48 33 0c 25 28 00   xor    rcx,QWORD PTR fs:0x28
  401284:  00 00 
  401286:  74 05                 je     40128d <main+0x113>
  401288:  e8 a3 fd ff ff           call   401030 <__stack_chk_fail@plt>
  40128d:   c9                       leave  
  40128e:   c3                       ret    
  40128f:   90                     nop

適当にジャンプ命令をnopで埋めてみたりしていたら、何やらよくわからない文字が出力されました。 この文字は一体どこからきているのだろうとアセンブラを見てみると 40121aでr()の返り値がDWORD PTR [rbp-0x44]に代入されてそれを元に演算した結果が出力されていると分かりました。 なのでDWORD PTR [rbp-0x44]が正しい文字になるようにしてあげればよいのです。

じゃあ正しい文字になるような値ってなんだよとまたアセンブラを見直してみると最初にnopで埋めていたジャンプ命令の前にcmp DWORD PTR [rbp-0x38],eaxというのがあったのでここからDWORD PTR [rbp-0x38]がその値であると分かりました。

それでこの値をDWORD PTR [rbp-0x44]に入れてstep実行してみると「KOSE」という文字が出力されたのでよっしゃと思い続く処理もステップ実行してみたのですが、その後の文字はうまくASCIIにはなっていませんでした。

それでなにがいけないのかともう一度見直して、そもそもこのr()の返り値は40404cを元に計算されていることを発見し、またこの40404cはループ毎に変化する値であることが分かりました。それで、じゃあ最初のr()を実行し終わった後だけ手動で40404cとDWORD PTR [rbp-0x44]にDWORD PTR [rbp-0x38]の値をいれてステップ実行してみると次のような出力を得られました。

0x45534f4b
0x14654434e
0x25f53497b
0x353494854
0x44145525f
0x55f594c4c
0x645525f41
0x753524556
0x83f474e49
0x90000007d

最後の7dは「}」なので、これはFLAGだ!と思いどうにかこねくり回してFLAGにするのだと思い眺めてみると、MSBが0から9の値で変化していることに気づきました。これがあるせいでうまく文字に出来なかったのですが、これを除いて文字にしてみると見事FLAGが取得できました。

KOSENCTF{IS_THIS_REALLY_A_REVERSING?}

結局1問しか解けませんでしたが、初めて自力で解けたので結構感動しました。CTF面白いね!運営の皆さんありがとうございました。

Majestouch Convertible 2を買った

この記事はプロコンゼミ(SPC同好会) その1 Advent Calendar 2018の18日目の記事です。 夢の中で宇宙旅行を楽しんでいたら、地球のタイムゾーンをすっかり失念していました。ごめんなさい!!! というか、このアドベントカレンダー担当者はほぼ埋まっていたのに全然投稿されていないですねーなんででしょうか。

本来なら、この記事は高速ナベアツの続きを書く予定だったのですが、忙しくて続きがあまり出来ていないのと他のネタが出来たので、ネタ替えをすることにしました。重ねてごめんなさい!! 高速ナベアツの続きは年度内に書ければなーと思います。

yukium.hatenablog.jp

さて、弊部のアドベントカレンダーには他にもキーボードの記事が投稿されていました。

h2so4.hatenablog.com

これです。彼いわく、このキーボードはHHKBより良いらしいです。

さて、まあキーボードと言えどもピンキリですよね。高いものは学生には手が出せないくらいの値段しますし、秋葉原で投げ売られているものを買えば100円とか、ひょっとしたらもっと安く手に入るかもしれません。 筆者はしがない三流ソフトウェアエンジニアではあるものの、やはり良いキーボードというものに憧憬を抱くわけです。そこで、今回タイトルの通りMajestouch Convertible 2というキーボードを買ったという次第です。

それで、まずこのMajestouch Convertible 2(以下、MC2と呼ぶ)を買うにあたって重要になるのは軸の色です。 MC2はメカニカルキーボードと呼ばれるキーボードの一つで、キーのひとつひとつが独立したスイッチになっています。 MC2ではこのスイッチにCherry MXというブランドのスイッチを使っています。詳しくは、次のページを見てみてください。

DIATEC|ダイヤテック株式会社 製品情報

このページを見ると分かるように、キースイッチには幾つか種類がありその種類が軸の色によって決まっています。 筆者は、茶軸を買おうと決めました。

そして、アマゾンで注文して届きました。

それで、よく見ると赤軸を注文してしまっていました。間違えてしまった。まあ、違いはクリック感だけらしいのでそんなに気にしてません。

この日はちょうど友人とNTTの技術史料館に行く用事があったのでこのキーボードを持ち歩いてみることにしました。もともとキーボードは色々なところに持ち歩いて使おうと思っていたので良い機会です。

重量は電池を入れると1kgくらいあるので結構重かったです。リュックサックじゃなかったら持っていくのは迷いますね。

それで、打鍵感についてですが、赤軸でもけっこう良かったです。打っていて楽しいです。さっそくAtCoderの問題も解いてみました↓

atcoder.jp atcoder.jp

Enterキーが今まで使っていたキーボードより長くてこのあたりの慣れが必要です。あ、キーボードの写真が未掲載でした。載せます。

f:id:yuhki0223:20181229100544j:plain

こちらが今回買ったMC2のキーボード。

f:id:yuhki0223:20181229101029j:plain

こちらが普段使っているThinkPad Yoga 260の内蔵キーボード。

初めて手にしたノートパソコンのキー配列がUS配列だったので、それからずっとUS配列を使ってます。プログラミングをするときは記号のキーがいいかんじの所にあるので打ちやすいです。

見ての通り、配列自体はほぼ一緒(MC2のCapital LockとControlは入れ替えた)ですが、キートップの表面積が結構違うので前述の通り慣れが必要です。

HHKBは矢印キーが独立して存在していないですが、MC2にはあるので全体長は少し長めです。まあギリギリ持ち運べるサイズです。

あ、あとBluetooth機能もついています。ペアリングも簡単でした。

# systemctl start bluetooth
# bluetoothctl
[bluetooth]# power on
[bluetooth]# agent KeyboardOnly
[bluetooth]# default-agent
[bluetooth]# pairable on
[bluetooth]# scan on
[bluetooth]# pair [MAC address]
[bluetooth]# trust [MAC address]
[bluetooth]# connect [MAC address]

こんな感じだと思います。信頼したデバイスに登録しておくと、次回以降接続時にconnectを実行するだけなので楽です。

他のブログ記事を見ていると、キーの遅延があるだとかそういうレビューもあったのですが今の所僕の環境では起きていないです。bluetoothも好調に使えます。

という感じで、雑多なレビューをしてみました。 もしMC2の購入、あるいはキーボードの購入を検討している人がいたら参考にしていただけると幸いです。

お気に入りのキーボードを買って進捗を爆上げしていきましょう!!!