JSONを扱いやすくするコマンド(jq, gron)のメモ

JSONを扱いやすくするコマンドのjqgronのメモ。

jq コマンド

jq コマンドはJSON向けのawkのようなコマンド。

インストール方法(on Mac

$ brew install jq

使い方

パイプで渡されたJSONデータにフィルターをかけることができる。

GitHub APIを使ってリポジトリ名を列挙する例

$ curl -s `curl -s https://api.github.com/users/tkmru | jq -r .repos_url`  | jq '.[].name'
"anarchy_proof"
"anti_debugging_test"
"aoj"
"awesome-linux-rootkits"
"a_and_d_web_nara"
"biwx"
...
"isucon4-qualifier-mokumoku"
"isucon6-qual-practice"
"isucon_pixv"
"ldap3"
"linux-driver-playground"
"linux-insides"
"linux-insides-ja"
"machine-learning-playground"

GitHub APIを使って最新コミット情報を取って来る例

$ curl 'https://api.github.com/repos/tkmru/dotfiles/commits?per_page=1' | jq '.[0]'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  7328  100  7328    0     0   9488      0 --:--:-- --:--:-- --:--:--  9492
{
  "sha": "c764b1baad95cb18cec14a1b7f84b460b6f0b3cc",
  "commit": {
    "author": {
      "name": "tkmru",
      "email": "i.am.tkmru@gmail.com",
      "date": "2018-04-10T14:33:34Z"
    },
    "committer": {
      "name": "tkmru",
      "email": "i.am.tkmru@gmail.com",
      "date": "2018-04-10T14:33:34Z"
    },
    "message": "Merge branch 'master' of github.com:tkmru/dotfiles",
  ...
  "parents": [
    {
      "sha": "495ddbfd8c19564a5c72260eb9c857f2d7f3a6d5",
      "url": "https://api.github.com/repos/tkmru/dotfiles/commits/495ddbfd8c19564a5c72260eb9c857f2d7f3a6d5",
      "html_url": "https://github.com/tkmru/dotfiles/commit/495ddbfd8c19564a5c72260eb9c857f2d7f3a6d5"
    },
    {
      "sha": "7f0f75610a2856c6cc97a3b1d949f5a4345a53df",
      "url": "https://api.github.com/repos/tkmru/dotfiles/commits/7f0f75610a2856c6cc97a3b1d949f5a4345a53df",
      "html_url": "https://github.com/tkmru/dotfiles/commit/7f0f75610a2856c6cc97a3b1d949f5a4345a53df"
    }
  ]
}

GitHub APIを使ってコミットメッセージ、名前を列挙する例

$ curl 'https://api.github.com/repos/tkmru/dotfiles/commits?per_page=2' | jq '[.[] | {message: .commit.message, name: .commit.committer.name}]'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  7328  100  7328    0     0   9382      0 --:--:-- --:--:-- --:--:--  9382
[
  {
    "message": "Merge branch 'master' of github.com:tkmru/dotfiles",
    "name": "tkmru"
  },
  {
    "message": "add ungron",
    "name": "tkmru"
  }
]

gron コマンド

JSONgrepしやすい形式、JavaScriptで扱える形式に変換してくれるコマンド。 Golang製。

インストール方法(on Mac

$ brew install gron

使い方

URLもしくはJSONファイルを指定すると変換してくれる。

$ gron "https://api.github.com/repos/tkmru/dotfiles/commits?per_page=1"
json = [];
json[0] = {};
json[0].author = {};
json[0].author.avatar_url = "https://avatars3.githubusercontent.com/u/1628214?v=4";
json[0].author.events_url = "https://api.github.com/users/tkmru/events{/privacy}";
json[0].author.followers_url = "https://api.github.com/users/tkmru/followers";
json[0].author.following_url = "https://api.github.com/users/tkmru/following{/other_user}";
....
json[0].parents[1].html_url = "https://github.com/tkmru/dotfiles/commit/7f0f75610a2856c6cc97a3b1d949f5a4345a53df";
json[0].parents[1].sha = "7f0f75610a2856c6cc97a3b1d949f5a4345a53df";
json[0].parents[1].url = "https://api.github.com/repos/tkmru/dotfiles/commits/7f0f75610a2856c6cc97a3b1d949f5a4345a53df";
json[0].sha = "c764b1baad95cb18cec14a1b7f84b460b6f0b3cc";
json[0].url = "https://api.github.com/repos/tkmru/dotfiles/commits/c764b1baad95cb18cec14a1b7f84b460b6f0b3cc";

これによってgrepしやすくなる。

$ gron "https://api.github.com/repos/tkmru/dotfiles/commits?per_page=1" | grep commit.message
json[0].commit.message = "Merge branch 'master' of github.com:tkmru/dotfiles";

ungron

gronの出力結果をJSONに戻すには--ungronオプションを付ければいい。 以下のようにaliasを設定するよう、READMEで推奨されている。

alias norg="gron --ungron"
alias ungron="gron --ungron"

grepした結果をJSONで欲しいときに使える。

$ gron "https://api.github.com/repos/tkmru/dotfiles/commits?per_page=1" | grep commit.message | ungron
[
  {
    "commit": {
      "message": "Merge branch 'master' of github.com:tkmru/dotfiles"
    }
  }
]

diffもgronを使えば見やすい結果で取れる。

$ diff <(gron http://echo.jsontest.com/number/one) <(gron http://echo.jsontest.com/number/two)
2c2
< json.number = "one";
---
> json.number = "two";

JavaScriptから出力結果をさわる

出力されたテキストはJavaScriptのObjectとして扱える。

$ gron http://headers.jsontest.com/ > tmp.js
$ echo "console.log(json);" >> tmp.js
$ node tmp.js
{ Accept: 'application/json',
  Host: 'headers.jsontest.com',
  'User-Agent': 'gron/dev',
  'X-Cloud-Trace-Context': '0f152eb1d17dc08fd257b8b4383faaa6/9190834354357706108' }

IDAプラグインの更新をサボっていたら割れIDAへのリンクを貼られた

IDA 7.0が昨年9月くらいに出たので、IDA 6.xのプラグインはIDA 7.xに対応するべく更新する必要がありました。 更新されたAPIへの差し替え、32bitアプリケーションだったのが64bitアプリケーションになったことによる変更などなど....

www.hex-rays.com

naoというプラグインを昔つくっていて、これをIDA 7.xに対応させる必要があり、 GitHubリポジトリにIssueをたてられたりしましたが、 IDA 7.0を当時は持ってなかったのでその旨を返信して放置していました。 すると、これを使えよ〜というノリで割れIDAへのリンクを貼られてしまった!!!! 治安が悪い!!!!!

f:id:TAKEmaru:20180214060412p:plain

社会性の塊なので、このスクショでは割れIDAへのURLの一部をマスクしています。偉い!

github.com

その裏でIDA 7.xに対応するプルリクを投げてくれた親切な人がおり、今ではIDA 7.xに対応しています。めでたしめでたし。

https://github.com/tkmru/nao/pull/39github.com

Rails appのコードを変更したときに、Guardに自動でRuboCop、RSpecを実行してもらう

Guardとは

Guardはファイルに変更があったときに、タスクを走らせてくれるgemで、コードを変更したときに、静的なコードチェックをしてくれるRuboCopやRSpecで書かれたテストを実行させることができる。RuboCopやテストコードを随時走らせてコーディングしていくと、問題を即座に把握できるので、プルリク前にあわててテストコードを走らせて修正....というハメに陥らなくて済む。

導入方法

Gemfile

Gemfileに以下のgemを追加。RSpec、RuboCopの導入はすでに終わっているものとする。

group :development do
  ...
  gem 'guard-rspec'
  gem 'guard-rubocop'
  ...
end

インストールも忘れずに。

$ bundle install

Guardfile

Guardの設定ファイルを作成する必要がある。以下のコマンドで生成できる。

$ bundle exec guard init rspec
$ bundle exec guard init rubocop

このようなGuardfileになる。このファイルを変更することで、監視対象とするファイルを変更したり、rspecが落ちた時の RuboCopの実行をスキップしたりできる。

guard :rubocop, cli: '--rails' do
  watch(/.+\.rb$/)
  watch(%r{(?:.+/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) }
end

guard :rspec, cmd: 'bundle exec rspec' do
  require 'guard/rspec/dsl'
  dsl = Guard::RSpec::Dsl.new(self)

  # RSpec files
  rspec = dsl.rspec
  watch(rspec.spec_helper) { rspec.spec_dir }
  watch(rspec.spec_support) { rspec.spec_dir }
  watch(rspec.spec_files)

  # Ruby files
  ruby = dsl.ruby
  dsl.watch_spec_files_for(ruby.lib_files)

  # Rails files
  rails = dsl.rails(view_extensions: %w(erb haml slim))
  dsl.watch_spec_files_for(rails.app_files)
  dsl.watch_spec_files_for(rails.views)

  watch(rails.controllers) do |m|
    [
      rspec.spec.call("routing/#{m[1]}_routing"),
      rspec.spec.call("controllers/#{m[1]}_controller"),
      rspec.spec.call("acceptance/#{m[1]}")
    ]
  end

  watch(%r{^app/api/(.+)\.rb$}) { |m| "spec/api/#{m[1]}_spec.rb" }

  # Rails config changes
  watch(rails.spec_helper)     { rspec.spec_dir }
  watch(rails.routes)          { "#{rspec.spec_dir}/routing" }
  watch(rails.app_controller)  { "#{rspec.spec_dir}/controllers" }

  # Turnip features and steps
  watch(%r{^spec/features/(.+)\.feature$})
  watch(%r{^spec/steps/(.+)_steps\.rb$}) do |m|
    Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/features'
  end
end

rspecが落ちた時に RuboCopの実行をスキップしたい場合は、 以下のようにGuardfileを変更するとよい。

# This group allows to skip running RuboCop when RSpec failed.
group :red_green_refactor, halt_on_fail: true do
  guard :rspec do
    # ...
  end

  guard :rubocop do
    # ...
  end
end

Guardを実行してファイルを監視

実行するだけ。

$ bundle exec guard

おわりに

Guardを使って開発しているとプルリクする前にあわててテストを実行しなくてよくて便利。 快適railsライフを送りましょう。

LLVM bitcodeのCFGを生成する

LLVM bitcodeとは

LLVM内ではLLVM IRという中間言語表現が用いられる。 ソースコードLLVM IRコードに変換したあと、そのLLVM IRコードをターゲットのアーキテクチャのバイナリに変換...という流れでコンパイルは行われる。 LLVM bitcode は LLVMの独自バイナリフォーマットで、LLVM IRと相互変換可能である。 LLVM IRは.llファイル、LLVM bitcodeは.bcファイルでそれぞれ表される。

$ llvm-as sample.ll # LLVM IRをLLVM bitcodeに変換
$ llvm-dis sample.bc # LLVM bitcodeをLLVM IRに変換

LLVM bitcodeはclangに-emit-llvmオプションを指定することで生成できる。

$ clang -emit-llvm -c -g test.c

CFGを生成する

optコマンドにより、dot-cfg passを実行することでLLVM bitcodeからdotファイルを生成する。 passはLLVM内で機能を構成する1単位であり、 最適化機構などはpassとして実装され、各passはoptコマンドのオプションで指定することで実行できる。 dotファイルにはグラフ構造が書き込まれており、Graphviz内のdotコマンドを使うことで画像として出力することができる。 macだとGraphvizのインストールはHomebrewでできる。

ソースコード

ここではたまたま手元にあったDynamic Opaque Predicateを施されたCのソースを使った。 Dynamic Opaque Predicateは難読化の一種で、どの分岐を通っても最終的に同じ処理を行うよう分岐を施す難読化である。 Opaque Predicateについては、 LOOPGeneralized Dynamic Opaque Predicatesがくわしい。

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
  if(argc != 2)
    exit(1);

  int x = atoi(argv[1]); 
  int y = 0;

  if (x % 2 == 0) {
    y = x + 2;
  } else {
    y = x + 100;
  }

  if (y % 2 == 0) {
    y = y + 100;
  } else {
    y = y + 2;
  }

  printf("y = %d\n", y);

  return 0;
}

コマンド

$ clang -emit-llvm -m32 -c -g test.c 
$ opt test.bc  -dot-cfg
$ dot -Tpng cfg.main.dot > test.png

生成されたCFG

f:id:TAKEmaru:20180124003448p:plain

死んだサーバーで動いていたアプリの引っ越しの歌

記憶の欠片に描いたnginx.confを見つめて
跡切れた想い出重ねる 変わらない夢に 
Oh 死んだHDD

どれだけ涙を流せば
貴方を忘れられるだろう
Just tell me my life
何処まで歩いてみても
涙で明日が見えない

以上、X JAPANのRusty Nailの替え歌でした。

www.youtube.com

We are X!!

2017年のOSSへのコントリビューションまとめ

年末ということで今年のOSSへのコントリビューションを振り返る。来年はもっとやっていきたい。

Metasploit

github.com

GSoCにMetasploitで参加していたので、それで結構プルリクを送った。 GSoC 2017にmetasploitで採択された。 - 脱力系日記

Pull Requests · rapid7/metasploit-framework

後半でかいissueを解決しようとしてたけど、ハマって期間中にプルリクを送れなかった。再度トライしたい。

casein

caseinはRuby on RailsCMSを作るためのgemである。

github.com

scaffoldをするときに指定した名詞が複数形だったときエラーが出るので修正するプルリクを送った。 このgemはバイト先でよく使っている。

Pull Requests · russellquinn/casein

ldap3

ldap3はPythonからLDAPを扱うためのライブラリである。

github.com

サンプルコードが間違っていたのでプルリクを送った。

Pull Requests · cannatag/ldap3

dagger

daggerはMachO、ELF向けのLLVM IRへのデコンパイラLLVMをforkして作られている。

github.com

ビルド方法が間違ってたので修正した。

Pull Requests · repzret/dagger

McSema

IDAのAPIを使ったLLVM IRへのデコンパイラである。 「funded by and used in research for DARPA and the US Department of Defense.」なので強そう。

github.com

READMEのリンク切れを修正した。

Pull Requests · trailofbits/mcsema

Linux Insides

Linux Insideはlinuxの内部構造についてのフリーの本で有志の手でロシア語や中国語への翻訳が進められている。

github.com

これはOSSにプルリクを送ったというわけではないけど、日本語版のリポジトリを作って翻訳を進めている。

github.com

最近やれてないので、誰かプルリクしてほしい。