718 文字
4 分
シングルバイトXORエンコーディングを簡易的に実装
「初めてのマルウェア解析」でXORエンコーディングについて学習したので、実装して色々実際に試してみました。
シングルバイトXORについて
シングルバイトXORは、平文の各バイトと暗号化キーでXORされます。
シンプルなXORエンコーディング
ファイルを読み込み、シンプルなシングルバイトXORを行うプログラムをC言語で実装しました。
実装
#include <stdio.h>#include <stdlib.h>
void xor_encrypt_decrypt(char* data, size_t len, unsigned char key) { for (size_t i = 0; i < len; i++) { data[i] ^= key; }}
int main(int argc, char* argv[]) { if (argc != 4) { printf("Usage: %s <input> <output> <key_byte>\n", argv[0]); return 1; }
FILE* in = fopen(argv[1], "rb"); FILE* out = fopen(argv[2], "wb"); unsigned char key = (unsigned char)strtoul(argv[3], NULL, 0);
fseek(in, 0, SEEK_END); size_t size = ftell(in); rewind(in);
char* buffer = malloc(size); fread(buffer, 1, size, in);
xor_encrypt_decrypt(buffer, size, key); fwrite(buffer, 1, size, out);
fclose(in); fclose(out); free(buffer);
return 0;}
実行
$ gcc -g xor_crypt.c -o xor_crypt
$ cat ./input/input.txthello_xor_crypt
$ xxd ./input/input.txt00000000: 6865 6c6c 6f5f 786f 725f 6372 7970 74 hello_xor_crypt
$ ./xor_crypt.exe ./input/input.txt ./output/encrypted.bin 0x7A
XORエンコーディングの確認
平文がわからなくなりました。
$ xxd ./output/encrypted.bin00000000: 121f 1616 1525 0215 0825 1908 030a 0e .....%...%.....
NULLバイトを無視するXORエンコーディング
XORでは、NULLバイト(0x00)が暗号化キーとXORされると、暗号化キーにエンコードされます。
また、暗号キーと同じ値とXORされた場合は、NULLバイトになります。
$ python
>>> c = 0x00>>> key = 0x7a>>> hex(c ^ key)'0x7a'>>> hex(key ^ key)'0x0'
NULLバイトを含めたXORエンコーディングの確認
先ほどで作成した、xor_crypt.exe
でNULLバイトを含めたファイルをXORエンコーディングしてみます。
$ printf 'hello_xor_crypt\00\00\00\00\00' >> ./input/input_null.txt
$ xxd ./input/input_null.txt00000000: 6865 6c6c 6f5f 786f 725f 6372 7970 7400 hello_xor_crypt.00000010: 0000 0000 ....
$ ./xor_crypt.exe ./input/input_null.txt ./output/encrypted_null.bin 0x7A
下記のように、NULLバイトが暗号キーの値になっています。そのため、暗号キーの特定が容易になります。
$ xxd ./output/encrypted_null.bin00000000: 121f 1616 1525 0215 0825 1908 030a 0e7a .....%...%.....z00000010: 7a7a 7a7a zzzz
実装
暗号キーの特定を回避するため、NULLバイトと暗号キーのXORを無視する実装をしてみます。
#include <stdio.h>#include <stdlib.h>
void xor_encrypt_decrypt(char* data, size_t len, unsigned char key) { for (size_t i = 0; i < len; i++) { if (data[i] == '\00' || data[i] == key) { continue; } data[i] ^= key; }}
int main(int argc, char* argv[]) { if (argc != 4) { printf("Usage: %s <input> <output> <key_byte>\n", argv[0]); return 1; }
FILE* in = fopen(argv[1], "rb"); FILE* out = fopen(argv[2], "wb"); unsigned char key = (unsigned char)strtoul(argv[3], NULL, 0);
fseek(in, 0, SEEK_END); size_t size = ftell(in); rewind(in);
char* buffer = malloc(size); fread(buffer, 1, size, in);
xor_encrypt_decrypt(buffer, size, key); fwrite(buffer, 1, size, out);
fclose(in); fclose(out); free(buffer);
return 0;}
実行
$ gcc -g ignore_null_xor_crypt.c -o ignore_null_xor_crypt
$ xxd ./input/input_null.txt00000000: 6865 6c6c 6f5f 786f 725f 6372 7970 7400 hello_xor_crypt.00000010: 0000 0000 ....
$ ./ignore_null_xor_crypt.exe ./input/input_null.txt ./output/encrypted_null.bin 0x7A
NULLバイト無視の確認
NULLバイトを無視するつくりのため、0x00
のままになっています。
$ xxd ./output/encrypted_null.bin00000000: 121f 1616 1525 0215 0825 1908 030a 0e00 .....%...%......00000010: 0000 0000
終わりに
実際に試してみようとすると、C言語を書いたり、NULLバイトを含むファイルの作成方法を調べたり、参考書を読むだけでは得られない情報も得られるため、積極的に続けていきたいです。