はじめに
CTFのreversing問ではFLAGを実行ファイル内に隠すものがありますが,平文でFLAGを置くわけにはいきません.
作問時にFLAGをどうやって難読化するかで悩まないよう,簡単なメモを作っておきます.
入れ替え
文字列のインデックスを入れ替える.逆順は普通に目grepでばれる.
最低限FLAGが平文にならないように.
void shuffleStr(char *input, char *output) {
size_t len = strlen(input);
for (size_t i = 0; i < len; ++i) {
output[(i * 7) % len] = input[i];
}
output[len] = '\0';
}
XOR
Ghidraで見れば普通に分かる.
void xor(char *input, char *output, char key) {
size_t len = strlen(input);
for (size_t i = 0; i < len; ++i) {
output[i] = input[i] ^ key;
}
output[len] = '\0';
}
size_t len = strlen(input);
size_t keyLen = strlen(key);
for (size_t i = 0; i < len; ++i) {
output[i] = input[i] ^ key[i % keyLen];
}
シーザー
FLAGのROT13がSYNTなのはよく見る.
void caesar(char *input, char *output, int shift) {
size_t len = strlen(input);
for (size_t i = 0; i < len; ++i) {
if (input[i] >= 'a' && input[i] <= 'z') {
output[i] = (input[i] - 'a' + shift) % 26 + 'a';
} else if (input[i] >= 'A' && input[i] <= 'Z') {
output[i] = (input[i] - 'A' + shift) % 26 + 'A';
} else {
output[i] = input[i];
}
}
output[len] = '\0';
}
文字コードシフト
Ghidraで見れば分かる.
void shiftChar(char *str, int shift) {
for (int i = 0; str[i] != '\0'; i++) {
str[i] += shift;
}
}
OpenSSL
opensslに入ってる物を色々使う.
aes, sha, des, rsa ...
#include <openssl/aes.h>
#include <openssl/sha.h>
void aesEncrypt(const unsigned char *key, const unsigned char *input, unsigned char *output) {
AES_KEY aesKey;
AES_set_encrypt_key(key, 128, &aesKey);
AES_encrypt(input, output, &aesKey);
}
void aesDecrypt(const unsigned char *key, const unsigned char *input, unsigned char *output) {
AES_KEY aesKey;
AES_set_decrypt_key(key, 128, &aesKey);
AES_decrypt(input, output, &aesKey);
}
void sha256Hash(const unsigned char *input, unsigned char *output) {
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, input, strlen((char *)input));
SHA256_Final(output, &sha256);
}
One-Time
keyをランダム生成する.
このコードは多分使わないが,キーをランダム生成するのはたまによくやる
void generateKey(char *key, size_t len) {
srand(time(NULL));
for (size_t i = 0; i < len; ++i) {
key[i] = rand() % 256;
}
key[len] = '\0';
}
Obfuscator-LLVM
しっかり難読化して,読ませたくないときに.
FLAGを構築する単純な関数などを,このツールで難読化する.
無駄な if や while がたくさん挿入され,Ghidraでデコンパイルしてもまともに読む気を無くすようなコードになる.
build/bin/clang -c flag.c -fPIE
-mllvm -sub
-mllvm -bcf
-mllvm -fla
難読化のオプションを3種類つけられる.論文ではオプションの違いやその比較をしているが,使う側としては全部載せでいい……はず.