オルトプラスエンジニアの日常をお伝えします!

サンフランシスコでお仕事してきた

 

サンフランシスコの街並み


※この記事は Altplus Advent Calendar 2017 の22日目のエントリです。

41歳、日々体力の衰えにおびえながら独り酒を飲んでいるtoshihiko-honmaです。

今年は厄年ということもあり、目立たぬように、はしゃがぬように、この会社の片隅にひっそり生きていこうと心に決めていましたが、ひょんなことから20年ぶり2回目の海外出張が舞い込みました。

残暑厳しい9月の初頭、期間は1か月、行先はサンフランシスコです。

 

サンフランシスコってどんなとこ?

エンジニアなら誰でも知ってる(と思われる)シリコンバレーがある街です。
アメリカ西海岸、カリフォルニア州に属した大都市で、羽田からだと飛行機で9時間半。タイムゾーンはPSTで日本との時差17時間という位置にあります。

温暖な気候で雨が少なく、とても過ごしやすい環境でした。

AT&Tパーク付近のカモメ共

AT&Tパーク付近のカモメ共

日々の暮らし

  • 宿泊
    滞在中はパウェル駅近くのホテルに宿泊していました。宿泊費は一泊$200~$300とお高め。設備は古いですが部屋が広く中々快適でした。
    ただ壁が薄いのが難点で、深夜に度たび聞こえてくる「Oh Yeah~!!」の叫びには参りました。ホントにオーイエー言うのね、アメリカの人って・・・

  • 食事
    ホテル付近のレストラン、バーガーショップ、寿司屋をローテーションしてた感じです。どの店も普通においしいですが、バーガーに関してはボリュームがアメリカサイズなのでとにかくデカい!そしてイモが多い!!

    食べ飽きたバーガー達

    食べ飽きたバーガー達

    さらに、総じて高い!日本の二倍くらいでしょうか?お店に入って何を買うにも食べるにも最低$20が羽のように飛んでいきます。

    シリコンバレーの給料は日本の二倍なんて記事をよく見かけますが、物価が倍なんだから当然っちゃ当然ですね。

  • 通信環境
    「イモトのWiFi」を利用しました。電波良好で何の不便もありませんでしたが、ちょっと遠出したときに電池切れした時の絶望感は半端じゃないです。充電はちゃんとすることをお勧めします。

  • 日常の出来事
    あまり不便なことはないのですが、いくつか日本とは勝手が違うことも。
    ホテルに給湯器が無くてカップラーメンが作れないとか、サンダルが欲しくて靴屋何件も回ったけどスリッパしか売ってないとか、風邪薬が「Matrixかよ!」って見た目だったりは印象的でした。

    風邪薬

    市販の風邪薬(赤は昼用、緑は夜用)

     

コミュニケーションとか

出張なので、当然仕事もしています。
そこで発生するのが現地エンジニアとのコミュニケーション。みなさんアメリカ人なので英語ペラペラですが、彼らは日本語は話せません。
私はというと、英語は小学生レベルなので会話が成立するはずもなく、この点が最大の課題になっていました。

まぁ、私も日本語はペラペラなので負けてませんけどね。・・・負けてないし! 

とはいえお仕事です。勝ち負けで話しても前に進みません。
そんな状況を打開するために、ミーティング時には通訳をお願いすることになりました。TVやカンファレンスでは見かけますが、自分の発言が同時通訳されるのは初体験です。破格の待遇、まさにVIP扱い。感動です。

会話内容はゲーム開発・運営に関する技術的な話が大半です。通訳の方はエンジニアではないので、技術系の用語は無理に訳さずに原文のままでお願いしましたが、スムーズに意思疎通ができたように思います。

ミーティングで印象的だったのは、問題点の指摘や質問、反論を大歓迎してくれること。逆に、何も発言しないと失望されます。議論することが当たり前の文化は良いなと感じました。 

Google翻訳

「今に見てろ」が「Mitero now」に変換されるなんてネタのあるGoogle翻訳ですが、Slackでのやり取りでは重宝しました。

技術文書は文法がシンプルで、箇条書きで説明できることも多く、短いセンテンスで表現することができます。つまり、翻訳対象に適しているんですね。
読み上げ機能を使えば日常会話もそこそこ可能で、現地エンジニアとアニメ談義できたのは良い思い出です。  

現地に行ってから気づきましたが、専門用語の類は事前にディクショナリーを用意しておけば翻訳精度を高められたなと反省してます。次回があれば活かしたいノウハウです。 

ちなみに、レストランの注文程度なら通訳・翻訳なしでも何とかなります。勘と気合と根性でメニューを指さしましょう。それっぽいのが提供されます。後は笑顔で食べるだけ。

 まとめ

振り返るとあっという間の1か月でしたが、学びや気付きを多く得られた貴重な体験でした。特に印象に残っている点をまとめてみます。

  • とにかく物価が高い。裏返すと日本の経済成長が遅れてる。頑張らないとね。
  • 意思表示は明確に。行間読むとか遠慮するとかは美徳になりません。
  • 英語力はあったほうが良い。が、なくても気合で何とかなる。

出発前、特に語学に関して不安もありましたが、飛び込んでみれば意外と何とかなりました。(オルトプラスが誇る英語堪能なメンバーが同行していたので、日常生活のお作法を学べたというのも大きいです。Fさん、Aさん、ありがとね)


英語が苦手で海外に抵抗のある方も、チャンスがあれば是非海外に足を運んでみてください。新しい何かが開けるかもしれませんよ?

 

Folsom Street Fair

白昼の路上で金蹴りプレイを楽しむお二人
この国自由すぎだろw(Folsom Street Fairにて)

 

 

 

 

APIフックに負けない強い体づくり

この記事は Altplus Advent Calendar 2017 の19日目のエントリです。

※Qiitaに書いた記事を転載しています。

こんにちわ。id:takuya-kikuchiです。

前回notepad.exeにAPIフックをしかけてイタズラする手法を紹介しました。 今回は、そういったAPIフックによる攻撃からいかに身を守るか、という方法を紹介したいと思います。方法は色々とありますが、APIフックの脅威からはAPIフックで身を守ることにしましょう。俺はこの力を正しい方向に使うんだ。notepadは俺が守る。

とりあえずDLLインジェクション

APIフックしたいので、とりあえずDLLをインジェクションさせてもらいましょう。正義のためだからいいよね。手法は前回と同様、SetWindowsHookExを使います。

また、今回は守る側が先にDLLインジェクションを仕掛けることとします。一般的に、この種の戦いは先手を取られるとかなり不利です。

さて、では具体的にどのような方法でnotepad.exeを守るか考えましょう。

特定のAPIがフックされていることを検知する

実際に危害を加えてきた場合にそれを検知するパターンです。今回、敵はCreateFileWをフックして悪事に及ぶことはわかっているので、こちらもCreateFileWをフックして対処しましょう。

dllの初期化処理はこちらです。 フックと、後々行うStackWalk64のための初期化処理(SymInitialize)を行なっています。

void ShieldNotepad() {
    TCHAR fileNameBuf[MAX_PATH];

    // notepad.exeのみを対象にする
    if (GetModuleFileName(GetModuleHandle(NULL), fileNameBuf, MAX_PATH) > 0) {
        if (_tcsstr(fileNameBuf, TEXT("notepad.exe")) != NULL) {
            // StackWalk用の初期化処理
            SymInitialize(GetCurrentProcess(), NULL, TRUE);
            // フックする。戻り値は本来のCreateFileWのアドレス
            createFileWPtr = (fpCreateFileW)RewriteFunction("kernel32.dll", "CreateFileW", ShieldedCreateFileW);
        }
    }
}

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        ShieldNotepad();
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

フックした関数はこちら。フックされてたら死ぬ覚悟です。

HANDLE
WINAPI
ShieldedCreateFileW(
    _In_ LPCWSTR lpFileName,
    _In_ DWORD dwDesiredAccess,
    _In_ DWORD dwShareMode,
    _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
    _In_ DWORD dwCreationDisposition,
    _In_ DWORD dwFlagsAndAttributes,
    _In_opt_ HANDLE hTemplateFile
)
{
    TerminateIfHooked();
    return createFileWPtr(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
}

さて、TerminateIfHookedの実装はこちらです。

void TerminateIfHooked() {
    CONTEXT context;
    STACKFRAME64 stackFrame;

    // StackWalkのためのコンテキストの準備。
    RtlCaptureContext(&context);

    // StackWalkのために、現在のスタックフレームの状態を設定。
    ZeroMemory(&stackFrame, sizeof(STACKFRAME64));
    stackFrame.AddrPC.Offset = context.Rip;
    stackFrame.AddrPC.Mode = AddrModeFlat;
    stackFrame.AddrFrame.Offset = context.Rsp;
    stackFrame.AddrFrame.Mode = AddrModeFlat;
    stackFrame.AddrStack.Offset = context.Rsp;
    stackFrame.AddrStack.Mode = AddrModeFlat;

    auto frameCount = 0;

    // 深さ10くらいまで探索。特に意味はない
    while (frameCount < 10)
    {
        // 1個上のスタックフレームを取得
        if (!StackWalk64(IMAGE_FILE_MACHINE_AMD64, GetCurrentProcess(), GetCurrentThread(), &stackFrame, &context, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL)) {
            break;
        }

        // ただしく取得できていたら、モジュール情報をチェック
        if (stackFrame.AddrPC.Offset != 0)
        {
            HMODULE mod;
            // アドレスから、属するモジュールベースを取得してくれるAPI
            if (GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)stackFrame.AddrPC.Offset, &mod)) {
                TCHAR fileNameBuf[MAX_PATH];
                // モジュール名を取得
                if (GetModuleFileNameW(mod, fileNameBuf, sizeof(fileNameBuf)) > 0) {
                    if (wcsstr(fileNameBuf, TEXT("WaruiDll.dll")) != NULL) {
                        // アラートを表示して
                        MessageBoxW(NULL, TEXT("API Hooking Detected!"), TEXT("Good bye."), MB_OK);
                        // さようなら
                        TerminateProcess(GetCurrentProcess(), 0);
                    }
                }
            }
            frameCount++;
        }
        else {
            break;
        }
    }
    return;
}

少しわかりづらいのですが、やりたいことは、スタックトレースを1個ずつ上っていき、モジュール名を取得。気にくわない名前が見つかったら自害する、というかんじです。

もちろん、きちんと対策するのであれば、StackWalk64がフックされている可能性も考えなければなりません。

他にも方法はある

悪意あるDLLのロード自体を妨害することも有効でしょうし、わざわざCreateFileWが呼ばれなくとも、主要なAPIがフックされてる時点で自害するという手もあります。もうちょっと色々試したかったのですが、今回はここまで。

今回のコードはこちらにアップしてあります。くれぐれもご利用は慎重に、自己責任でよろしくお願いします。

おわりに

今回は、APIフックに対してAPIフックで応える形で、notepad.exeを守る方法について検討しました。

なお今回は守る側が先にフックを仕掛けている前提でしたが、逆の場合もあるでしょう。そうなると、また方針も変わってきます。DLLのロード順序の先取り合戦も、熾烈な争いが繰り広げられていることでしょう。さらには、CreateRemoteThread等による、DLL Injectionを伴わないような攻撃も当然考えられます。

また、今回はユーザ空間のみについて考えましたが、カーネルドライバが混ざってくるとより戦いは激化することになります。悪意あるハッカーにカーネルドライバを混入させられたら負けだ。気をつけましょう。

ともあれ、攻撃も防御も完璧などありえません。この戦いに終わりもありません。セキュリティいたちごっこは今日も続きます

あなたのアプリも狙われているかもしれませんよ。 それではまた。

Franz5でさくっとアプリをつくる

こんにちわ。 id:xshimadaです。

オルトプラスでエンジニアの身の回りの世話をしています。

ところで、いろんなプロジェクトやコミュニティに関わっているとたくさんのSlackやChatowrkなどにアクセスしなきゃいけない時があってたいへんですよね。

わたしはいろんなメッセンジャーをまとめるためにFranz を利用しています。

meetfranz.com

FranzはWindows、Mac、Linuxに対応しており、Slack、Chatwork、Telegramなど、さまざまなサービスが利用できる便利アプリです。 またGithubにも公開されています。

FranzではChatwork サービスもサポートしているのですが、オルトプラスで使っているKDDI ChatworkではURLが異なるせいかセッションが切れやすい気がします。

今日はサンプルとして、KDDI Chatworkに対応させてみましょう。

まず、Franz 5からは追加したサービスは以下のフォルダに格納されます。

Windows:
C:\Users\[ユーザ名]\AppData\Roaming\Franz\recipes

Mac
/Users/[ユーザ名]/Library/Application Support/Franz/recipes

recipesの下にdevというフォルダを作ってください。

そうすると、FranzのSettingsのAvailable ServicesにDevelopmentというカテゴリが追加されます。

f:id:xshimada:20171218100309p:plain

Settingsからサービスとしてchatworkを登録するとrecipesの下のchatworkフォルダができます。 今回はさくっとおわらずために、recipesの下のchatworkフォルダをdev配下にkddichatworkとしてコピーしてきます。

フォルダの構成としては、

  • Configuration (package.json)
  • Frontend API (webview.js)
  • Backend API (index.js)
  • Icons (icon.svg、icon.png)

となっています。

試しにpackage.jsonを開いてみます。

package.json

{
  "id": "chatwork",
  "name": "chatwork",
  "version": "1.0.1",
  "description": "chatwork",
  "main": "index.js",
  "author": "Koma",
  "license": "MIT",
  "config": {
    "serviceURL": "https://www.chatwork.com"
  }
}

idは「kddichatwork」などユニークな名前にして、nameは表示名なので、「KDDI Chatwork」とします。 serviceURLは、「kcw.kddi.ne.jp」などご契約のURLに変更してください。

あとは、Franzをリロードするとアプリが使えるようになります。

f:id:xshimada:20171218101005p:plain

今回は試しにさくっとしましたが、Franz serviceの詳しい作り方は、こちらにドキュメントがありますので、日本のサービスのrecipeをいろいろ作ってみると楽しいと思います。

FranzのCommunityもありますので興味のある方は参加するのもよいでしょう。

Franzで社内のポータル、メール、メッセンジャーなどもrecipeにしておいて、入社時に一括導入してあげると便利かもしれませんね!!

それでは、楽しいFranz生活を!