---
# System prepended metadata

title: Ransomware
tags: [solved]

---

# 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`