718 文字
4 分
シングルバイトXORエンコーディングを簡易的に実装

初めてのマルウェア解析」でXORエンコーディングについて学習したので、実装して色々実際に試してみました。

シングルバイトXORについて#

シングルバイトXORは、平文の各バイトと暗号化キーでXORされます。

シンプルなXORエンコーディング#

ファイルを読み込み、シンプルなシングルバイトXORを行うプログラムをC言語で実装しました。

実装#

xor_crypt.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;
}

実行#

Terminal window
$ gcc -g xor_crypt.c -o xor_crypt
$ cat ./input/input.txt
hello_xor_crypt
$ xxd ./input/input.txt
00000000: 6865 6c6c 6f5f 786f 725f 6372 7970 74 hello_xor_crypt
$ ./xor_crypt.exe ./input/input.txt ./output/encrypted.bin 0x7A

XORエンコーディングの確認#

平文がわからなくなりました。

Terminal window
$ xxd ./output/encrypted.bin
00000000: 121f 1616 1525 0215 0825 1908 030a 0e .....%...%.....

NULLバイトを無視するXORエンコーディング#

XORでは、NULLバイト(0x00)が暗号化キーとXORされると、暗号化キーにエンコードされます。

また、暗号キーと同じ値とXORされた場合は、NULLバイトになります。

Terminal window
$ python
>>> c = 0x00
>>> key = 0x7a
>>> hex(c ^ key)
'0x7a'
>>> hex(key ^ key)
'0x0'

NULLバイトを含めたXORエンコーディングの確認#

先ほどで作成した、xor_crypt.exeでNULLバイトを含めたファイルをXORエンコーディングしてみます。

Terminal window
$ printf 'hello_xor_crypt\00\00\00\00\00' >> ./input/input_null.txt
$ xxd ./input/input_null.txt
00000000: 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バイトが暗号キーの値になっています。そのため、暗号キーの特定が容易になります。

Terminal window
$ xxd ./output/encrypted_null.bin
00000000: 121f 1616 1525 0215 0825 1908 030a 0e7a .....%...%.....z
00000010: 7a7a 7a7a zzzz

実装#

暗号キーの特定を回避するため、NULLバイトと暗号キーのXORを無視する実装をしてみます。

ignore_null_xor_crypt.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++) {
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;
}

実行#

Terminal window
$ gcc -g ignore_null_xor_crypt.c -o ignore_null_xor_crypt
$ xxd ./input/input_null.txt
00000000: 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のままになっています。

Terminal window
$ xxd ./output/encrypted_null.bin
00000000: 121f 1616 1525 0215 0825 1908 030a 0e00 .....%...%......
00000010: 0000 0000

終わりに#

実際に試してみようとすると、C言語を書いたり、NULLバイトを含むファイルの作成方法を調べたり、参考書を読むだけでは得られない情報も得られるため、積極的に続けていきたいです。