インタプリタを作っている

Go言語でつくるインタプリタを読んでいる。 前々から何かプログラミング言語を作ってみたかったので買ってみた。 まだハッシュマップとかマクロとか実装していないけど一旦紹介。

本の目次

内容

本書ではmonkeyというC言語風の言語を実装していく。 実装の仕方はmonkeyのインタプリタ実装に必要な物を 1. テストを書く 2. テストをする 3. 最小限必要な単位で実装する 4. テストをする 5. 実用的な範囲まで拡張して実装する

といったテスト駆動開発の手法を用いて進めていく。 テスト内容もGolangのスライスで管理しているため、簡単にテストケースを増やせる。 そのため新しく機能を実装しようと思った時でも簡単にテストと実装を繰り返すことができる。

字句解析

この章では入力されたソースコードトークンへ変換する。 主に入力されたソースコードをどこまで読んだか、どのトークンへ変換するか機能を実装する。

構文解析

前章で作成した字句解析器を利用しASTを作れるよう実装していく。

評価

ASTを解釈、評価していく。 このあたりで計算や関数の作成ができるようになる。

インタプリタの拡張

真偽値や数値以外に文字列や配列、ハッシュマップを実装する。 今はここまでやった。

終わりに

まだもう少しだけ実装する内容が残っているので早く読み進める。

LeetCode TwoSum をテストしながら解く

LeetCodeという競技プログラミングサービスがある。 まだ始めたばかりなのだがとっつきやすい作りになっていて良い。 そんなLeetCodeの問題 TwoSum を解いてみた。 ただ解いてみたというのも面白くないので今回はテストコードも書きながら解答してみる。

TwoSum

問題はへのリンク https://leetcode.com/problems/two-sum/。 問いは下記の通り。

数値の入った配列と整数値targetが与えられるので、配列の中から足すとtargetになる値の組み合わせを見つけ、その要素がどこにあるかを答えよ。 必ず答えは存在するものとする。 また別々の位置の値を必ず使用する事

以下に例を書く

Given nums = [2, 7, 11, 15], target = 9,

Because nums[0] + nums[1] = 2 + 7 = 9, return [0, 1].

テストコードを書く

コードを弄ってブラウザ上でテストしても問題はないが遅い。 なので今回は手元ですぐに動作するテストコードを書いた。

package twosum

import (
    "reflect"
    "testing"
)

type testCase struct {
    array  []int
    target int
}

func TestTwoSum(t *testing.T) {
    tests := []struct {
        input  testCase
        output []int
    }{
        {testCase{[]int{2, 7, 11, 15}, 9}, []int{0, 1}},
        {testCase{[]int{2, 3, 4, 11, 15}, 6}, []int{0, 2}},
    }

    for i, tt := range tests {
        sum := twoSum(tt.input.array, tt.input.target)
        if !reflect.DeepEqual(sum, tt.output) {
            t.Errorf("tests[%d] failed - input: %+v - answer: %+v output: %d¥n", i, tt.input.array, tt.output, sum)
        }
    }
}

$GOPATH/src/leetcode/twosum/か何か適当なディレクトリでこれを書きgo test ./twosums/と入力すればお手軽テスト環境の完成。

あとはこのテストを通るような解答を考える。

解答

いくつか解法がある。 2つループを書いて総当たりする方法なんかは簡単だが、渡されるスライスが大きくなればなるほど時間計算量が増える。 今回は一旦ハッシュテーブルを作成してその中から値の組み合わせを見つける解法で解いた。

package twosum

func twoSum(nums []int, target int) []int {
    var res []int
    res = make([]int, 2)

    numMap := make(map[int]int)
    for i, num := range nums {
        numMap[num] = i
    }

    for j, firstNum := range nums {
        comp := target - firstNum
        value, ok := numMap[comp]
        if !ok {
            continue
        }
        if value == j {
            continue
        }

        res[0] = j
        res[1] = value

        return res
    }

    return res
}
  1. 数値とその位置をハッシュテーブル化
  2. targetからスライスから取り出した数値を引き、足してtargetになる数値を取り出す
  3. ハッシュテーブルを確認し、足してtargetになる値があればその位置を返す
  4. 見つけるまで1-3を繰り返す

終わりに

Goのtest機能、楽に使えて良いですね。 まだLeetCode始めたばかりなのでもっと問題を解いていこうと思います。

RPISEC Malware Lab#01 をやった その2

RPISEC/Malwareとはマルウェア解析について体系的に学ぶことができる教材のこと。 今回はその中のLab_01-2.malwareを解析した。

Lab_01-2.malware

1. これのMD5ハッシュ値は何?

02658bc9801f98dfdf167accf57f6a36

2. インポートされた関数やそれらのまとまりをいくつか取り上げてマルウェアでどのように使われているか説明せよ

  1. ネットワーク関連(特にHTTP)のAPI - HTTPでファイルか何かをやりとりしている予想される
  2. ファイルを読み書きするAPI - ファイルを読み込んだり書き換えたりしていると予想される
  3. Sleep - 一定時間実行を遅らせることで解析を妨害していると予想される

3. ファイルの文字列で手がかりになりそうなものはどれか

  1. cmd /c - コマンドを実行する
  2. wuauclt.exe - 実行されるファイル名
  3. 69.25.50.10 - 接続先

4. このマルウェアを動かした時に予想される挙動はどのようなものか

ネットワーク越しにファイル(おそらくマルウェア)をダウンロードしサービスとして登録する

5. procmonでフィルタをかける際に使う名前とそれを使う理由

実行時のプロセス名。プロセスの挙動を追うため。

6. ホストベースのシグネチャとなりそうなものは何か(ファイルやレジストリキー、プロセスやらサービス、その他)。もしも存在していたらどのようなものか

wuauclt.exe use error! putf [transpeed] [filepath] 他にも文字列を見ているとコマンドを受け取り実行しそうな感じがする。 stringsで見ただけなのであくまで予想。

7. ネットワークベースのシグネチャとなりそうなものは何か(URL, 通信, その他)。もしも存在していたらどのようなものか

69.25.50.10

8. 解析を妨害する機能は存在するか。存在していた場合、どのようにそれを回避するか

sleep これを回避する方法 * sleep に飛ぶ命令をnopで潰す * 実行時にsleep命令を書き換えるを変更する * 実行時に時間計測系APIへの戻り値を書き換える

9. このマルウェアの目的は何か

ネットワークから他のマルウェアをダウンロードしサービスとして登録する

参考

Practical Malware Analysis

RPISEC Malware Lab#01 をやった

RPISEC Malware Lab#01 をやった

RPISEC/Malwareとはマルウェア解析について体系的に学ぶことができる教材のこと。 今回はその中のLab_01-1.malwareを解析した。

Lab_01-1.malware

1. このファイルはいつコンパイルされたか答えよ

コンパイル時間を確認するときはPEviewを利用する。 f:id:famasoon:20190115234151p:plain 画像のようにPEviewにファイルを読み込ませたあとIMAGE_NT_HEADERS->IMAGE_FILE_HEADER->TimeDataStampを確認する。 ここにはコンパイルされた時間が格納されている。 2009/05/14 Thu 17:12:41 UTCコンパイルされた時間だ。

2. インポートされた関数やそれらのまとまりをいくつか取り上げてマルウェアでどのように使われているか説明せよ

インポートされた関数を確認してみる。 CFF Explorer でLab01_01-1.malware を開く。 次に画面左のImport Directory を選ぶ。 下の画像のようにインポートに使われているdllが一覧表示される。 f:id:famasoon:20190115234244p:plain あとは気になるdllをクリックするだけで、そのdllからインポートされている関数を確認することができる。 回答としては下のようになる。

  1. SHELL32.dllからインポートされている"ShellExecuteExA" - プロセスを起動させる
  2. ソケット関連のAPI - ネットワーク通信をする際に用いられる。
  3. ファイル関連のAPI - ファイルを読みこんだり書き換えたりする。マルウェアをディスクに書き込むときに使われたりする。

3. ファイルの文字列で手がかりになりそうなものはどれか

PowerShell上でstringsコマンドを実行しファイル内の文字列を確認する。 f:id:famasoon:20190115234325p:plain (本当はfileinsightでstringsスクリプトを実行して文字列を抽出しようと思っていたが、なぜか動かなかった。あとで原因を調べる) 結果としては以下の文字列が気になった

  1. http://www.ueopen.com/test.html - 通信先っぽい
  2. 60.248.52.95:443 - 同様に通信先っぽい
  3. cmd.exe - コマンドを実行しそう

他には

*(SY)# cmd
*(SY)#
send = %d
*(SY)#
cmd.exe
exit
Open
 > nul
/c del

といった文字列が気になった。 何かしら受け取ったコマンドを実行しそう。

4. このマルウェアを動かした時に予想される挙動はどのようなものか

問2の回答より、インポートされたAPIから察するにネットワーク通信をしファイルを書き込みマルウェアを実行させる。 通信先は問3の回答で抽出した通信先と予想。

5. procmonでフィルタをかける際に使う名前とそれを使う理由

procmonとはプロセスのイベントを取得しログとして残してくれるツールのこと。 ログを取得する際にフィルタを利用することで特定のイベント/プロセスについて情報を抽出できる。 今回はプロセスの名前を使うと適切だと考えられる。 理由としてはマルウェアの挙動を追うにはプロセス単位で見たほうが効率的だから。

6. ホストベースのシグネチャとなりそうなものは何か(ファイルやレジストリキー、プロセスやらサービス、その他)。もしも存在していたらどのようなものか

抽出した文字列から考えるに cmd.exe /c del でファイル削除をしそう。

7. ネットワークベースのシグネチャとなりそうなものは何か(URL, 通信, その他)。もしも存在していたらどのようなものか

抽出した文字列から下記のURLとIPアドレスがネットワークベースのシグネチャになりそう * http://www.ueopen.com/test.html * 60.248.52.95:443

8. 解析を妨害する機能は存在するか。存在していた場合、どのようにそれを回避するか

このファイルは自身を削除することで解析を妨害してくる。 回避するには2つ手段が存在する。 1. ファイルをコピーして保存しておく 2. ファイルを削除する箇所の命令を無効化しておく

9. このマルウェアの目的は何か

抽出した文字列からネットワーク越しに何かしらのコマンドを実行する。 いわゆるバックドアだと考えられる。

参考

Practical Malware Analysis