A look at a bmp file with embedded shellcode

The sample today is from PaulM @melsonp

While watching his BSIDES Augusta talk from 2018  Here,  at that the end he shows a picture file that gets downloaded from a layered PowerShell script. He was kind enough to send me a copy of a similar one to take a closer look.

I originally thought it was one of the PowerShell only decoder scripts for picture files but here is what we first see. This is the first layer .


After Base64 Decoding this we get.


Here we can see this is base64 –> decompress to get the next level. But they have one more trick.


Before we can Bas64 Decode –> Decompress this we first have to do a string replacement of  “!” with “A” in order to get a proper Base 64 encoded string.

After Decoding we get this.


This appears to be a normal Meterpreter PowerShell Shellcode loader but in this case it is only downloading a bmp file.

The other ones I have looked into have either had the Shellcode on this page base64 encoded or hex encoded or downloaded it as this has with the picture file.

After a discussion with Paul he was able to locate the pdf of the presentation of the builder for this here and I found the video for the presentation  here and the Github for the project is  here.

Here is what we see when we open the downloaded file.


The first 2 bytes are normal for the bmp file format. If we open the file as a picture it is indeed the the default picture of a cat from the builder  “flipping you off”. (Which I won’t show)

So lets dig into the pdf to see how this works.

Note: I’m still learning how to read assembly. But we learn by doing.

On this page we see we have the 2 byte header “BM” 0x424D then a Jump instruction of 0xE9 then a 3 byte offset. According to This page there are more possible “jmp”  instructions that could possibly be used.


In our file we have the offset in  little Endian byte order of 0x30C403 ,and if we reverse that to 0x03C430 that is our offset to jump to.

If we jump to that offset we can see it is at the end of the file.


Now scrolling down the pdf a little bit more we see that they also attempted to obfuscate the decoding key.


What this is doing is setting ebx to Zero and then looping a counter until it matches the “Magic” value that was randomly generated on build.

After it matches, it reverses that hex value and will use that value to xor the first 4 bytes of the encoded data to produce a decoding key which will get reversed again for decoding the remainder of the bytes.

I first wrote a brute forcer to work like the function here but after looking at this longer and getting a better understanding of what was in the registers I finally realized that this entire brute force routine was a waste of time and CPU power. No matter what the Random “Magic value” turns out to be the index value will always end up equal to the “Magic value”.

So when building an offline decoder we can just bypass this and and just use that found value for the “Magic” in our calculations saving a lot of time and CPU cycles.

In order to figure this out I also had to take a closer look at the builder.

If we look in the source file of gen.py we can see the layout of the decoder bytes.


So lets just use this CyberChef recipe Here to get the assembly for the bytes starting at the offset we jumped to in our downloaded file.

And we get this.


For me this is a little harder to understand so lets go back and just put the data starting with the decoding routine to the end of the data  into CyberChef and see what we have.

This looks a little different.


In order to get a better handle on what was in what registers I ran it thru Scdbg.


If we look close at this report we see it fails at the op code 0x0FC9 . The “BSWAP ECX”

It was still enough to help me understand the values in the registers at the time.

I may not fully understand all of what the assembly is doing but I’m able to understand enough to work out how to decode it.

If you look at the above screenshot of the assembly you can see the notes from what I think I  understand on how it works.

If we look back at the the source code we can see it lines up where I have commented as random.

Here are my notes on how the function works to decode the bytes.


Here I am just reversing the first 4 bytes of the encoded data instead of the “Magic” Value” as it appears in the assembly.

The next step is to build a tool to extract the shell code.

I first start by importing the entire bmp file into the tool. I then extract the offset. Next Jump to the offset.

Next I extract the data from the offset to the end of the file. We no longer need the bytes before the offset.

Since I write all of my tools in vb.net and I have not found a good way to do byte array searches in byte arrays. So I will convert these remaining bytes to a hex string and work with the data as a hex string.

Just a note It is very resource intensive to convert a file that size to a hex string to try and parse it that way. (I tried)

Since I am now working with strings of hex I can now search for the unique byte sequence as a string instead of a byte array to do the compare with the byte code before the “Magic value” in order to find and extract it.


Since this sequence will be in every file we can do a search for it and then locate the Magic value in the hex string. Once we find that sequence before the “Magic” we can then extract the next  4 bytes (8 Chars) for the “Magic”.

Next we have to locate the start of the encoded data. For that we can find what this function ends with.


You may also notice another value we could extract. The size of the encoded data. We could get that so there is not extra nonsense data in the decoded shellcode.

So after we put all of this together we end up with the new tool.


If we load the hex string shellcode into another tool I’m working on we get.


One thing to note. For this type of shellcode the first byte is always 0xFC and the second byte will vary depending on if it is a 32 bit or 64 bit shellcode.

So the question would be how do you find a file encoded with this.

With a few pointers from Florian Roth @cyb3rops I was able to create this Yara rule.

rule DKMC_Picture_File {
  description = “Detects DKMC encoded bmp file with shell code”
  author = “David Ledbetter @Ledtech3”
  reference = “https://github.com/Mr-Un1k0d3r/DKMC”
  date = “2019-27-02”

     $my_hex_string1 = { 424DE9 }
     $my_hex_string2 = { 31D981F9 }
     $my_hex_string3 = { E8B7FFFFFF }

$my_hex_string1 at 0 and $my_hex_string2 and $my_hex_string3


After sending this to him he modified it to do the first 3 byte search as  UInteger.

Here is the modified version.

rule DKMC_Picture_File {
      description = “Detects DKMC encoded bmp file with shell code”
      author = “David Ledbetter @Ledtech3”
      author = “Florian Roth @cyb3rops” // modified first 3 bytes to be detected as Uint.
      reference = “http://github.com/Mr-Un1k0d3r/DK …”
      date = “2019-27-02”
      $my_hex_string2 = { 31D981F9 }
      $my_hex_string3 = { E8B7FFFFFF }
      uint16(0) == 0x4d42 and uint8(2) == 0xE9 and
      $my_hex_string2 and $my_hex_string3

I’m not sure if it is faster or not but both do find the sample I have.

A Search on Hybrid Analysis didn’t find anything using  the yara rules.

A retro hunt by Florian Roth @cyb3rops On VirusTotal resulted in several hits for this rule.

Here is the Pastebin of the found hashes here .

Well that is it for this time I hope you learned as much as I did.


About pcsxcetrasupport3

My part time Business, I mainly do system building and system repair. Over the last several years I have been building system utility's in vb script , HTA applications and VB.Net to be able to better find the information I need to better understand the systems problems in order to get the systems repaired and back to my customers quicker.
This entry was posted in Malware, PowerShell, security and tagged , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s