# Ransomware *this is solved after score board freeze* 這題裡面包含 `1~143.jpg`, `wannaSleep.exe`, `readme.txt`, `ransomware.jpg` decompile wannaSleep 後可以看到一個 function **FUN_0040177b** ```cpp= void FUN_0040177b(LPCSTR param_1,LPCSTR param_2) { BOOL BVar1; DWORD local_26c; _WIN32_FIND_DATAA local_268; CHAR local_128 [272]; HANDLE local_18; HANDLE local_10; PathCombineA(local_128,param_1,param_2); local_10 = FindFirstFileA(local_128,(LPWIN32_FIND_DATAA)&local_268); if (local_10 != (HANDLE)0xffffffffffffffff) { do { if ((local_268.dwFileAttributes & 0x10) == 0) { PathCombineA(local_128,param_1,local_268.cFileName); printf_s("%s\n",local_128); FUN_00401560(local_128); } BVar1 = FindNextFileA(local_10,(LPWIN32_FIND_DATAA)&local_268); } while (BVar1 != 0); FindClose(local_10); } local_18 = CreateFileA("ransomeware.jpg",0x10000000,0,(LPSECURITY_ATTRIBUTES)0x0,1,0x80, (HANDLE)0x0); if (local_18 != (HANDLE)0xffffffffffffffff) { WriteFile(local_18,&JPEG_00408040,DAT_004660b4,&local_26c,(LPOVERLAPPED)0x0); CloseHandle(local_18); } return; } ``` 可以看到 PathCombineA 然後 FindFirstFileA 接著在 while loop 中 call FUN_00401560 然後 FindNextFileA => 一個把所有檔案加密的循環 **FUN_00401560** ```cpp= void FUN_00401560(LPCSTR param_1) { DWORD local_2c; LPVOID file_buf; uint allocate_size; DWORD file_size; HANDLE file_fp; uint local_10; uint offset; file_fp = CreateFileA(param_1,0x10000000,0,(LPSECURITY_ATTRIBUTES)0x0,3,0x80,(HANDLE)0x0); if (file_fp != (HANDLE)0xffffffffffffffff) { file_size = GetFileSize(file_fp,(LPDWORD)0x0); allocate_size = (file_size & 0xfffff000) + 0x1000; file_buf = VirtualAlloc((LPVOID)0x0,(ulonglong)allocate_size,0x3000,4); ReadFile(file_fp,file_buf,file_size,&local_2c,(LPOVERLAPPED)0x0); offset = ((allocate_size + file_size + (int)*(char *)((longlong)file_buf + 0xc0U % (ulonglong)file_size)) % 0x4000_const + (int)*(char *)((longlong)file_buf + 0xc79U % (ulonglong)file_size)) % 0x4000_const; local_10 = 0; while (local_10 < allocate_size) { *(byte *)((longlong)file_buf + (longlong)(int)local_10) = *(byte *)((longlong)file_buf + (longlong)(int)local_10) ^ (&xor_arr)[offset % 0x4000_const]; local_10 = local_10 + 1; offset = offset + 1; } SetFilePointer(file_fp,0,(PLONG)0x0,0); WriteFile(file_fp,file_buf,allocate_size,&local_2c,(LPOVERLAPPED)0x0); VirtualFree(file_buf,0,0x8000); CloseHandle(file_fp); } return; } ``` 可以看到把原檔案讀進來 計算 new size 跟 offset 用檔案跟 xor_arr xor 寫到新檔案 **recover file** jpg 前 4 byte 是 magic number `0xff` `0xd8` `0xff` `0xe0` 利用加密後的前 4 byte 嘗試 xor 不同 offset 的 xor_arr 就能找到 offset 把檔案還原 ```cpp= void extract(string filename, char *xor_buf, int offset) { fstream in(filename, fstream::in | fstream::binary); fstream out("e" + filename, fstream::out | fstream::binary); char c; while(in.get(c)){ out.put((char)(xor_buf[offset] ^ c)); offset = (offset + 1) % 0x4000; } in.close(); out.close(); } int main() { fstream game_bin("wannaSleep.exe", fstream::in | fstream::binary); game_bin.seekg(0x2620); char buf[0x4000]; game_bin.read(buf, 0x4000); for(int i = 1; i < 144; i++) { string filename = to_string(i) + ".jpg"; cout << filename << '\n'; fstream file_bin(filename, fstream::in | fstream::binary); char filebuf[4]; file_bin.read(filebuf, 0x4); int target[] = {0xff, 0xd8, 0xff, 0xe0}; int know_offset; for (int offset = 0; offset < 0x4000; offset++) { if(((char)(filebuf[0] ^ buf[offset])) != (char)target[0]) { continue; } if(((char)(filebuf[1] ^ buf[(offset + 1) % 0x4000])) != (char)target[1]) { continue; } if(((char)(filebuf[2] ^ buf[(offset + 2) % 0x4000])) != (char)target[2]) { continue; } if(((char)(filebuf[3] ^ buf[(offset + 3) % 0x4000])) != (char)target[3]) { continue; } cout << "yeah" << '\n'; know_offset = offset; break; } file_bin.close(); extract(filename, buf, know_offset); } game_bin.close(); } ``` 解出來是 flag 拼圖 能用 python 拔掉 padding byte 但其實沒啥意義 txt 沒有 magic number 但推測其大小不會剛好 0x1000 加密會在後面有 padding 0x0 所以最後面會等於 xor_arr, 比對後就能找出 offset 4432 用前面的 extract 解 解出來是 >Sort them by size to get the right order, >and there are 11*13 pieces of images. >.PIL may save your life 然後照檔案大小排序後能發現 就是數字排序大到小 然後來拼圖 我用 opencv ```python= import cv2 import numpy as np canvas = np.zeros((80 * 13, 80 * 11, 3), np.uint8) for i in range(143): img = cv2.imread(f"e{143 - i}.jpg") img = cv2.resize(img, (80, 80)) canvas[(i // 11) * 80: ((i // 11) + 1) * 80, (i % 11) * 80: ((i % 11) + 1) * 80, :] = img cv2.imwrite("pic.jpg", canvas) ``` 然後手抄 flag 一直抄錯 == ![](https://i.imgur.com/nKSYgIv.png) ###### tags: `solved`