← Reports

Ransomware · Ransomworm · Worm

WannaCry - invoice_greenanimals.pdf.exe

Author
Moise Medici
Updated
15 Feb 2026 · Completed
Difficulty
Medium
Platform
Windows
Capabilities
Command and Control C2 CommunicationCommand Execution via Powershell Cmd BashFile EncryptionPersistence Mechanisms
Tags
C++WannaCryptor

Question 6 and Question 10

Opening the sample with Ghidra, Windows → Defined Strings can be used to locate the URL. From there, searching the URL, clicking on the reference found, and following it lands in the .data area of the PE file that stores the URL.

The hardcoded URL at 004313d0 in Ghidra's Defined Strings, with three cross references into FUN_00408140.
Fig. 12: The hardcoded URL at 004313d0 in Ghidra's Defined Strings, with three cross references into FUN_00408140.

Right click on the address of the reference (in this case 004313d0): References → Show References To Addresses. There will be 3 entries:

  1. The one marked as “DATA” is the reference just clicked on.
  2. The two other entries marked as “READ” are addresses where the URL is read.
The three references to that string, one DATA at 0040814a and two READ at 00408155 and 00408157.
Fig. 13: The three references to that string, one DATA at 0040814a and two READ at 00408155 and 00408157.

In this case it is safe to double-click on any of the “READ” addresses; if you look at the “location” address, they are just one instruction apart, the first at 00408155 and the second at 00408157.

This reveals a list of assembly instructions like this:

The URL copied onto the stack with MOVSD and MOVSB, a few instructions before the InternetOpenA and InternetOpenUrlA calls.
Fig. 14: The URL copied onto the stack with MOVSD and MOVSB, a few instructions before the InternetOpenA and InternetOpenUrlA calls.

Notice that the URL has been saved in a memory space using MOVSD and MOVSB, which are just string versions of MOV 10.

Also notice that just a few lines after the MOV of the URL, there is an InternetOpenUrlA call. To confirm which URL the CALL is using, Ghidra usually helps by showing the arguments of functions that it is able to identify, but in this case it is not. This can be improved by going to the “Data Type Manager” (usually on the left side of the window), clicking on winapi_32 → Apply Function Data Types. Once that is done, go to Analysis → One Shot → WindowsPE x86 Propagate External Parameters.

Now all the parameters should be clearly named.

The same listing after applying the winapi_32 data types, with every PUSH now labelled with the parameter it fills.
Fig. 15: The same listing after applying the winapi_32 data types, with every PUSH now labelled with the parameter it fills.

Before proceeding, looking at the Microsoft documentation 11 the parameters used are:

HINTERNET InternetOpenUrlA(
[in] HINTERNET hInternet,
[in] LPCSTR lpszUrl,
[in] LPCSTR lpszHeaders,
[in] DWORD dwHeadersLength,
[in] DWORD dwFlags,
[in] DWORD_PTR dwContext
);

The function “returns a valid handle to the URL if the connection is successfully established, or NULL if the connection fails.”

The first two parameters are those of most interest. The first one, hInternet, is a handle provided by InternetOpenA, which is called a couple of lines before InternetOpenUrlA. The second parameter of interest is lpszUrl, which is the actual URL. From here, it is useful to go backwards: look at which register contains the lpszUrl content, and see how it gets initialized.

This is the full function code up to the call under investigation:

invoice_greenanimals.pdf.exe
*******************************************************
* FUNCTION *
*******************************************************
undefined FUN_00408140()
assume FS_OFFSET = 0xffdff000
undefined AL:1 <RETURN>
undefined1 Stack[-0x1] local_1 XREF[1]: 00408177(W)
undefined2 Stack[-0x3] local_3 XREF[1]: 0040816c(W)
undefined4 Stack[-0x7] local_7 XREF[1]: 00408168(W)
undefined4 Stack[-0xb] local_b XREF[1]: 00408164(W)
undefined4 Stack[-0xf] local_f XREF[1]: 00408160(W)
undefined4 Stack[-0x13 local_13 XREF[1]: 0040815c(W)
undefined4 Stack[-0x17 local_17 XREF[1]: 00408158(W)
undefined1 Stack[-0x50 local_50 XREF[2]: 0040814f(*),
0040818a(*)
FUN_00408140 XREF[1]: entry:00409b45(c)
00408140 SUB ESP, 0x50
00408143 PUSH ESI
00408144 PUSH EDI ; HINTERNET hInternet for InternetCloseHandle
00408145 MOV ECX, 0xe
0040814a MOV ESI, s_http://www.iuqerfsodp9ifjaposdfj_004313 ; =
; "http://www.iuqerfsodp9ifjaposdfjhgosurijfaewrwergw
; ea.com"
0040814f LEA EDI=>local_50, [ESP + 0x8]
00408153 XOR EAX, EAX
00408155 MOVSD. ES:EDI, ESI=>s_http://www.iuqerfsodp9ifjaposdf ; =
; "http://www.iuqerfsodp9ifjaposdfjhgosurijfaewrwergw
; ea.com"
00408157 MOVSB ES:EDI, ESI=>s_http://www.iuqerfsodp9ifjaposdf ; =
; "http://www.iuqerfsodp9ifjaposdfjhgosurijfaewrwergw
; ea.com"
00408158 MOV dword ptr [ESP + local_17], EAX
0040815c MOV dword ptr [ESP + local_13], EAX
00408160 MOV dword ptr [ESP + local_f], EAX
00408164 MOV dword ptr [ESP + local_b], EAX
00408168 MOV dword ptr [ESP + local_7], EAX
0040816c MOV word ptr [ESP + local_3], AX
00408171 PUSH EAX ; DWORD dwFlags for InternetOpenA
00408172 PUSH EAX ; LPCSTR lpszProxyBypass for InternetOpenA
00408173 PUSH EAX ; LPCSTR lpszProxy for InternetOpenA
00408174 PUSH 0x1 ; DWORD dwAccessType for InternetOpenA
00408176 PUSH EAX ; LPCSTR lpszAgent for InternetOpenA
00408177 MOV byte ptr [ESP + local_1], AL
0040817b CALL dword ptr [->WININET.DLL::InternetOpenA] ; = 0000a7dc
00408181 PUSH 0x0 ; DWORD_PTR dwContext for InternetOpenUrlA
00408183 PUSH 0x84000000 ; DWORD dwFlags for InternetOpenUrlA
00408188 PUSH 0x0 ; DWORD dwHeadersLength for InternetOpenUrlA
0040818a LEA ECX=>local_50, [ESP + 0x14]
0040818e MOV ESI, EAX
00408190 PUSH 0x0 ; LPCSTR lpszHeaders for InternetOpenUrlA
00408192 PUSH ECX ; LPCSTR lpszUrl for InternetOpenUrlA
00408193 PUSH ESI ; HINTERNET hInternet for InternetOpenUrlA
00408194 CALL dword ptr [->WININET.DLL::InternetOpenUrlA] ; = 0000a7c8
0040819a MOV EDI, EAX

lpszUrl is contained in ECX. At line 0040818a ECX is loaded with the address of local_50. Tracing local_50 back shows that ESI is first initialized with the URL string at 0040814a, and that string is then copied into the buffer pointed to by EDI (local_50) via MOVSD and MOVSB at 00408155 and 00408157.

invoice_greenanimals.pdf.exe
0040814a MOV ESI, s_http://www.iuqerfsodp9ifjaposdfj_004313 ; =
; "http://www.iuqerfsodp9ifjaposdfjhgosurijfaewrwergwea.com"
0040814f LEA EDI=>local_50, [ESP + 0x8]
00408155 MOVSD. ES:EDI, ESI=>s_http://www.iuqerfsodp9ifjaposdf ; =
; "http://www.iuqerfsodp9ifjaposdfjhgosurijfaewrwergwea.com"

This shows how local_50 is populated and then used by InternetOpenUrlA as the URL parameter.

After the InternetOpenUrlA call, to understand what is done with the return value, the surrounding code is followed, focusing on the highlighted lines:

invoice_greenanimals.pdf.exe
00408194 CALL dword ptr [->WININET.DLL::InternetOpenUrlA] ; = 0000a7c8
0040819a MOV EDI, EAX
0040819c PUSH ESI ; HINTERNET hInternet for InternetCloseHandle
0040819d MOV ESI, dword ptr [->WININET.DLL::InternetCloseHandle] ; = 0000a7b2
004081a3 TEST EDI, EDI
004081a5 JNZ LAB_004081bc
004081a7 CALL ESI=>WININET.DLL::InternetCloseHandle
004081a9 PUSH 0x0 ; HINTERNET hInternet for InternetCloseHandle
004081ab CALL ESI=>WININET.DLL::InternetCloseHandle
004081ad CALL FUN_00408090 ; undefined FUN_00408090()
004081b2 POP EDI
004081b3 XOR EAX, EAX
004081b5 POP ESI
004081b6 ADD ESP, 0x50
004081b9 RET 0x10
;004081bc is below here

The return value of InternetOpenUrlA is in EAX, which is immediately moved into EDI and then tested. Since TEST is an implied AND instruction (it does not change the value of EDI but just computes EDI AND EDI and sets flags), the JNZ is used to check the zero flag set by TEST EDI, EDI, meaning:

  • If the connection was successful → EDI is not zero → TEST EDI, EDI sets ZF to 0 → jump to LAB_004081bc.
  • If the connection was not successful → EDI is zero → TEST EDI, EDI sets ZF to 1 → execution continues to 004081a7 and FUN_00408090 is executed.

When the connection is successful, the code at LAB_004081bc is straightforward: a call to InternetCloseHandle and end of the function.

invoice_greenanimals.pdf.exe
LAB_004081bc XREF[1]: 004081a5(j)
004081bc CALL ESI=>WININET.DLL::InternetCloseHandle
004081be PUSH EDI ; HINTERNET hInternet for InternetCloseHandle
004081bf CALL ESI=>WININET.DLL::InternetCloseHandle
004081c1 POP EDI
004081c2 XOR EAX, EAX
004081c4 POP ESI
004081c5 ADD ESP, 0x50
004081c8 RET 0x10

To see where it returns, Window → Function Call Tree shows the Incoming Calls menu containing entry. Double-clicking it shows the code that calls the function under examination, from the entry function. This shows that if the connection is successful, the program is terminated by calling MSVCRT.DLL::exit.

invoice_greenanimals.pdf.exe
00409b45 CALL FUN_00408140 ; undefined FUN_00408140()
00409b4a MOV dword ptr [EBP + local_6c], EAX
00409b4d PUSH EAX ; int _Code for exit
00409b4e CALL dword ptr [->MSVCRT.DLL::exit] ; = 0000a8c2

If the connection fails, FUN_00408090 is executed. Looking briefly at this function shows calls to OpenSCManagerA, OpenServiceA, etc., implying that the rest of the program is executed.

This shows that the URL is actually used as a kill switch: if there is a connection to the URL, the program is terminated. The sample can be stopped from fully executing by simply allowing it to resolve the domain name.