14杯目セキュリティうどん（かまたま）勉強会

14杯目セキュリティうどん（かまたま）勉強会のまとめ
----

# 000 はじめに

「Python入門と機械学習によるマルウェア検知」というタイトルでトレンドマイクロのエンジニア
トレンドマイクロ株式会社 上級スレットディフェンスエキスパート 新井 悠 氏によるハンズオン形式のワークショップが開催されました。

14杯目セキュリティうどん（かまたま）勉強会
http://sec-udon.jpn.org/doku.php?id=workshop:14th

# 001 自己紹介

定員50名（満員御礼）の参加者がそれぞれ自己紹介をしました。開催地香川の他、
千葉、熊本、島根、愛媛、徳島など全国各地から集まりました。
職種もさまざまですが、セキュリティ関連業務の方や、官公庁の方もいらっしゃいました。

# 010 Python入門

何はともあれ Python入門 です。Python3 をインストールし、Anaconda も入れます。
jupyter notebook で説明されます。

```
> jupyter notebook
```

コマンドで実行し、何はともあれ "Hello World!" ですね。はい、入門終了。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/47058/900fc5ff-b53a-962b-99ff-aae0b4b6e6e8.png)

# 011 マルウェア解析

次にマルウェアを解析するのですが、ここで、pefile というライブラリが必要になりますので、以下のようにしてインストールします。

```
> pip install pefile
```

その後、以下のようにすると、exe のヘッダが丸見えです。

```python
# coding: utf-8
import pefile

# ファイルパスは各自
PATH=u'/Users/taniokah/Projects/udon/data/PE-samples/TestApp.exe'
pe = pefile.PE(PATH)
print("{0}".format(pe.FILE_HEADER))
```

    [IMAGE_FILE_HEADER]
    0xE4       0x0   Machine:                       0x14C     
    0xE6       0x2   NumberOfSections:              0x7       
    0xE8       0x4   TimeDateStamp:                 0x59194A4D [Mon May 15 06:27:25 2017 UTC]
    0xEC       0x8   PointerToSymbolTable:          0x0       
    0xF0       0xC   NumberOfSymbols:               0x0       
    0xF4       0x10  SizeOfOptionalHeader:          0xE0      
    0xF6       0x12  Characteristics:               0x102     



```python
print("{0}".format(pe.DOS_HEADER))
```

    [IMAGE_DOS_HEADER]
    0x0        0x0   e_magic:                       0x5A4D    
    0x2        0x2   e_cblp:                        0x90      
    0x4        0x4   e_cp:                          0x3       
    0x6        0x6   e_crlc:                        0x0       
    0x8        0x8   e_cparhdr:                     0x4       
    0xA        0xA   e_minalloc:                    0x0       
    0xC        0xC   e_maxalloc:                    0xFFFF    
    0xE        0xE   e_ss:                          0x0       
    0x10       0x10  e_sp:                          0xB8      
    0x12       0x12  e_csum:                        0x0       
    0x14       0x14  e_ip:                          0x0       
    0x16       0x16  e_cs:                          0x0       
    0x18       0x18  e_lfarlc:                      0x40      
    0x1A       0x1A  e_ovno:                        0x0       
    0x1C       0x1C  e_res:                         
    0x24       0x24  e_oemid:                       0x0       
    0x26       0x26  e_oeminfo:                     0x0       
    0x28       0x28  e_res2:                        
    0x3C       0x3C  e_lfanew:                      0xE0      



```python
# IMAGE_FILE_EXECUTABLE_IMAGE 0x0002
if pe.FILE_HEADER.Characteristics & 0x0002:
    print("IMAGE_FILE_EXECUTABLE_IMAGE")
#IMAGE_FILE_32BIT_MACHINE 0x0100
if pe.FILE_HEADER.Characteristics & 0x0100:
    print("IMAGE_FILE_32BIT_MACHINE")
```

    IMAGE_FILE_EXECUTABLE_IMAGE
    IMAGE_FILE_32BIT_MACHINE

```python
print("{0}".format(pe.OPTIONAL_HEADER))
```

    [IMAGE_OPTIONAL_HEADER]
    0xF8       0x0   Magic:                         0x10B     
    0xFA       0x2   MajorLinkerVersion:            0xB       
    0xFB       0x3   MinorLinkerVersion:            0x0       
    0xFC       0x4   SizeOfCode:                    0x4400    
    0x100      0x8   SizeOfInitializedData:         0x4000    
    0x104      0xC   SizeOfUninitializedData:       0x0       
    0x108      0x10  AddressOfEntryPoint:           0x11131   
    0x10C      0x14  BaseOfCode:                    0x1000    
    0x110      0x18  BaseOfData:                    0x1000    
    0x114      0x1C  ImageBase:                     0x400000  
    0x118      0x20  SectionAlignment:              0x1000    
    0x11C      0x24  FileAlignment:                 0x200     
    0x120      0x28  MajorOperatingSystemVersion:   0x6       
    0x122      0x2A  MinorOperatingSystemVersion:   0x0       
    0x124      0x2C  MajorImageVersion:             0x0       
    0x126      0x2E  MinorImageVersion:             0x0       
    0x128      0x30  MajorSubsystemVersion:         0x6       
    0x12A      0x32  MinorSubsystemVersion:         0x0       
    0x12C      0x34  Reserved1:                     0x0       
    0x130      0x38  SizeOfImage:                   0x1D000   
    0x134      0x3C  SizeOfHeaders:                 0x400     
    0x138      0x40  CheckSum:                      0x0       
    0x13C      0x44  Subsystem:                     0x3       
    0x13E      0x46  DllCharacteristics:            0x8140    
    0x140      0x48  SizeOfStackReserve:            0x100000  
    0x144      0x4C  SizeOfStackCommit:             0x1000    
    0x148      0x50  SizeOfHeapReserve:             0x100000  
    0x14C      0x54  SizeOfHeapCommit:              0x1000    
    0x150      0x58  LoaderFlags:                   0x0       
    0x154      0x5C  NumberOfRvaAndSizes:           0x10      

# 100 主成分分析

機械学習は、データ駆動の手法です。pandasとnumpyでデータを読み込んで加工しましょう。

```python
import glob
import pandas as pd

df = pd.DataFrame(columns=["malware","VirtualAddress","ResourceSize","DebugSize","IATSize"])

# 特徴抽出対象ファイルの列挙
PATH = u'/Users/taniokah/Projects/udon/data/PE-samples/*'
files = glob.glob(PATH)

# PEで特徴量の抽出 pefile.DIRECTORY_ENTRY['IMAGE_DIRECTORY_ENTRY_IMPORT']
for file in files:
    data = pefile.PE(file)
    VA = data.OPTIONAL_HEADER.DATA_DIRECTORY[1].VirtualAddress
    RS = data.OPTIONAL_HEADER.DATA_DIRECTORY[2].Size
    DS = data.OPTIONAL_HEADER.DATA_DIRECTORY[6].Size
    IATSize = data.OPTIONAL_HEADER.DATA_DIRECTORY[1].Size
    newdf = pd.DataFrame([[0, VA, RS, DS, IATSize]], columns=["malware", "VirtualAddress", "ResourceSize", "DebugSize", "IATSize"])
    
    df = df.append(newdf, ignore_index=True)

df
```




<div>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>malware</th>
      <th>VirtualAddress</th>
      <th>ResourceSize</th>
      <th>DebugSize</th>
      <th>IATSize</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>0</td>
      <td>106496</td>
      <td>1084</td>
      <td>56</td>
      <td>60</td>
    </tr>
    <tr>
      <th>1</th>
      <td>0</td>
      <td>102400</td>
      <td>1084</td>
      <td>56</td>
      <td>60</td>
    </tr>
    <tr>
      <th>2</th>
      <td>0</td>
      <td>106496</td>
      <td>1084</td>
      <td>56</td>
      <td>80</td>
    </tr>
    <tr>
      <th>3</th>
      <td>0</td>
      <td>102400</td>
      <td>1084</td>
      <td>56</td>
      <td>80</td>
    </tr>
    <tr>
      <th>4</th>
      <td>0</td>
      <td>106496</td>
      <td>1084</td>
      <td>56</td>
      <td>80</td>
    </tr>
  </tbody>
</table>
</div>


さらに、主成分分析(PCA)を使ってテストデータを可視化します。


```python
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA

PATH= '/Users/taniokah/Projects/udon/data/'

df1 = pd.read_csv(PATH+'malware.csv')
df2 = pd.read_csv(PATH+'benign.csv')

X_reduced = PCA(n_components=2).fit_transform(np.array(df1)[:,2:])
Y_reduced = PCA(n_components=2).fit_transform(np.array(df2)[:,2:])

plt.scatter(X_reduced[:,0], X_reduced[:,1], c="red")
plt.scatter(Y_reduced[:,0], Y_reduced[:,1], c="blue")
plt.show()
```


![image.png](https://qiita-image-store.s3.amazonaws.com/0/47058/f9d53cac-fd94-d29f-4002-6c1c421032ee.png)



# 101 線形分離

線形分離（LDA）で2次元データを1次元に次元縮約してみます。

```python
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA

df = pd.read_csv(PATH+'union.csv')

X_reduced = LDA(n_components=1).fit_transform(np.array(df)[:,2:], np.array(df)[:,1])

plt.plot(X_reduced[:,0], c="red")
plt.hlines(y=0.2, xmin=0, xmax=355, linestyle="dashed")
plt.show()
```

    /Users/taniokah/.pyenv/versions/anaconda3-5.0.1/lib/python3.6/site-packages/sklearn/discriminant_analysis.py:388: UserWarning: Variables are collinear.
      warnings.warn("Variables are collinear.")



![image.png](https://qiita-image-store.s3.amazonaws.com/0/47058/ffac1e66-584a-ceda-0984-60a14db594c3.png)


# 110 k近傍法

いよいよ、本格的に機械学習によるマルウェアの識別をします。ここでは、k近傍法(kNN)を使います。

```python
from sklearn.neighbors import KNeighborsClassifier

df = pd.read_csv(PATH+'union.csv')
clf_k = KNeighborsClassifier(n_neighbors=3)
clf_k.fit(np.array(df)[:,2:], np.array(df)[:,1])

test_df = pd.read_csv(PATH+'test2.csv')
output = clf_k.predict(np.array(test_df)[:,2:])

for i in output:
    if i == 0:
        print("not malware")
    elif i == 1: 
        print("malware")

```

    malware
    not malware
    malware
    malware
    not malware
    not malware
    malware
    not malware
    not malware
    not malware
    not malware
    not malware
    not malware
    not malware
    malware
    not malware
    not malware
    not malware
    not malware
    not malware
    not malware
    malware
    not malware
    not malware
    not malware


学習用のデータを読み込んで、テスト用で判定してみます。
結果は、malwere と not malware と分類できました。どの程度の精度が出ているか見てみます。


```python
from sklearn.metrics import accuracy_score
accuracy_score(np.array(test_df)[:,1], output)
```




    0.56000000000000005




```python
df = pd.read_csv(PATH+'union.csv')
test_df = pd.read_csv(PATH+'test2.csv')

for i in range(1, 20):
    clf_k = KNeighborsClassifier(n_neighbors=i)
    clf_k.fit(np.array(df)[:,2:], np.array(df)[:,1])
    output = clf_k.predict(np.array(test_df)[:,2:])
    print("n_neighbors={0} {1}".format(i, accuracy_score(np.array(test_df)[:,1], output)))
```

    n_neighbors=1 0.32
    n_neighbors=2 0.4
    n_neighbors=3 0.56
    n_neighbors=4 0.52
    n_neighbors=5 0.52
    n_neighbors=6 0.52
    n_neighbors=7 0.52
    n_neighbors=8 0.52
    n_neighbors=9 0.52
    n_neighbors=10 0.52
    n_neighbors=11 0.52
    n_neighbors=12 0.52
    n_neighbors=13 0.76
    n_neighbors=14 0.76
    n_neighbors=15 0.76
    n_neighbors=16 0.76
    n_neighbors=17 0.76
    n_neighbors=18 0.76
    n_neighbors=19 0.76



```python
for i in range(1, 30):
    clf_k = KNeighborsClassifier(n_neighbors=i)
    clf_k.fit(np.array(df)[:,2:], np.array(df)[:,1])
    output = clf_k.predict(np.array(test_df)[:,2:])
    print("n_neighbors={0} {1}".format(i, accuracy_score(np.array(test_df)[:,1], output)))
```

    n_neighbors=1 0.32
    n_neighbors=2 0.4
    n_neighbors=3 0.56
    n_neighbors=4 0.52
    n_neighbors=5 0.52
    n_neighbors=6 0.52
    n_neighbors=7 0.52
    n_neighbors=8 0.52
    n_neighbors=9 0.52
    n_neighbors=10 0.52
    n_neighbors=11 0.52
    n_neighbors=12 0.52
    n_neighbors=13 0.76
    n_neighbors=14 0.76
    n_neighbors=15 0.76
    n_neighbors=16 0.76
    n_neighbors=17 0.76
    n_neighbors=18 0.76
    n_neighbors=19 0.76
    n_neighbors=20 0.72
    n_neighbors=21 0.68
    n_neighbors=22 0.68
    n_neighbors=23 0.6
    n_neighbors=24 0.6
    n_neighbors=25 0.6
    n_neighbors=26 0.56
    n_neighbors=27 0.6
    n_neighbors=28 0.4
    n_neighbors=29 0.36



# 111 まとめ

Pythonや機械学習初心者が多かったようなので、ちょうどよい内容かな？と思った。
個人的には、もうちょっと機械学習に踏み込んで欲しかったです。

時間があまったので、LDAでも予測してみた。

```python
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA

df = pd.read_csv(PATH+'union.csv')
test_df = pd.read_csv(PATH+'test2.csv')

clf = LDA()
clf.fit(np.array(df)[:,2:], np.array(df)[:,1])
output = clf.predict(np.array(test_df)[:,2:])
print("lda accuracy = {0}".format(accuracy_score(np.array(test_df)[:,1], output)))
    
```

    lda accuracy = 0.64


64%ということで、kNNより悪い。残念。SVMやNB、DNNを使えばもっとあげられるかな？