Deconstructing TinyLoader

Wednesday, July 5, 2017

Researchers have observed TinyLoader, a well-known backdoor, delivering point-of-sale and banking trojan malware over the past few years. Fidelis Cybersecurity Threat Research happened to notice it delivered from a site that hosted a variety of other malware and that was an association we had not seen previously so it prompted us to take a deeper look. This post covers our malware analysis and then describes how our research allows for direct interaction with the command-and-control server.

Tinyloader has a few unique characteristics

  • It is, in fact, tiny -- typically weighing in under 5 KB.
  • Its command-and-control (C2) server runs on Microsoft Windows, which is fairly uncommon in malware today.
  • Finally, it is extremely versatile due to its modular C2 mechanism. This mechanism allows the C2 server to pass custom bytecode directly into the running memory of the bot making it easy to load new malware or augment additional malicious behaviors.

Understanding how TinyLoader functions allows us to mimic bot functionality. Doing this then provides a mechanism to connect directly to malicious C2 servers to monitor commands issued, modules sent, and the running processes targeted by the operators.

In this post, we will discuss TinyLoader delivery vectors, various characteristics of its C2, and finally, how to create a script to mimic the bot functions to monitor C2 activity. We have made our script available on Fidelis Cybersecurity Github(.


The TinyLoader sample we observed was as a secondary infection. A machine that had been infected with Nymaim was later found to be downloading “”. What’s also interesting about that IP is that the Nymaim malware was downloaded by a BetaBot sample that also came from the IP “”. The BetaBot was found downloading Nymaim from “”.


For this research, we analyzed this TinyLoader sample: 037c675489bb0faeab114bbd6cf3067a -- though any of the TinyLoader samples mentioned in the IOC section below will provide a similar outcome.

The main part of the bot is XOR encoded and wrapped in a similar fashion. The bot brute forces the XOR key out by comparing it against a known value. The brute force loop provides a custom sleep routine that was likely put in place to cause sandboxes to time out.

Figure 1. XOR key brute.


The first C2 transmission is a sort of checkin:

Figure 2. C2 transmission


The data is in the form of:

struct c2_data
int req_num;
int campaign_id;
short length;
byte unknown;
byte bit_version;

The ‘req_num’ or request number is initially set to all NULLs but is then changed by the subsequent downloaded bytecode. This lets the C2 fully control the bot as it sets up what the bot will request next. The ‘campaign_id’ is hardcoded in the bot which is why it is labeled as such. The 0x0c in the picture is the length of the data, while the ‘bit_version’ is set by the bot after a call to IsWow64Process.

Figure 3. Version Check.


The C2 responses are sets of code sequences containing bytecode blobs that will be executed. This is an interesting way to control infections. We broke out the responses into a list (below). Due to the nature of this capability, the bot could essentially download any code to run on the infected machines.


C2 traffic responses(commands):

  • Gather process list
  • Update Binary
  • Install Code Module
  • Checkin
Gather process list command

The initial blob of bytecode returned is used to copy a second handler bytecode blob into the memory address provided. The bot then sets req_num to 00 01 00 00. Each new request returns the same sort of setup where bytecode is sequentially written and then a handler is eventually added to initialize the code.

Figure 4. Gather process list command.


This sequence continues in a list of request numbers.

Request Number:

è 00 03 00 00
è 00 04 00 00
è 00 05 00 00
è 00 06 00 00
è 00 07 00 00 -> this sections detonates the blob of data that’s been copied

Figure 5. Bytecode to copy data and set next request.


When detonated, this copied over bytecode has a whitelist of process names and a mutex. It will attempt to create the mutex and then enumerate all running processes while building a list of those not in the whitelist.

Figure 6. Mutex name in last block of code.


Below we can see a snippet of the code to check each process name to see if it contains a 4 byte string.

Figure 7. Process Name check snippet.


We can get a list of all the strings the bot uses to check if it’s not interested in that process.

Figure 8. Process Name string list.


Data is sent back to C2 with a req_num of 00 0a 00 00 along with the process list appended to the previously mentioned structure. There is also a hardcoded string that is prepended to the data which can be seen in both the bytecode and the traffic.

Figure 9. Hardcoded traffic data in bytecode.


Figure 10. Example of Process List Sent to C2.


Update binary

If the bot sends an Update Binary command, the return is bytecode to copy over a PE updated TinyLoader binary. It then sets the req num to 00 00 c1 00 to begin the next sequence.

The bot then downloads chunks through the following sequence.

Request Number:

  • 00 00 c2 00
  • 00 00 c3 00
  • 00 00 c4 00
  • 00 00 c5 00
  • 00 00 c6 00
  • 00 00 c7 00
  • 00 00 c8 00
  • 00 00 01 72
  • 00 00 02 72
  • 00 00 55 01    - restarts after file is written and persistence setup

Next, the newly downloaded bot begins running through the same C2 process again before continuing with the following sequence.

Install Code Module

The bot then goes through the following sequence to download code. The code chunks are saved for later. The code module normally downloaded contains the bytecode that can be used to download other files.

Request Number:

  • 01 6e 77 d4
  • 02 6e 77 d4
  • 03 6e 77 d4
  • 04 6e 77 d4

The next step begins a recurring sequence between the bot and the C2 that will do one of two things: It will cause the bot to sleep before its next checkin, or the C2 will issue a command for the bot to do something. In this manner, the C2 can use this as both a way to tell if a bot is 'alive' and either tell the bot to checkin again later or issue some other command.[JR1] 

Request Number:

  • 00 00 00 54 
Figure 11. Snippet from sleep loop code.


Understanding the C2 structure can help automate the monitoring of these C2s as we find them and allow us to test certain elements of the traffic.  For this part, we’ll be primarily focusing on the ‘\x00\x00\x00\x54’ request because that appears to be the generic checkin request as the bot waits for additional commands. It’s also the request that other PCAPs from previous reports show as returning commands to download additional files.

Let’s start with some basic Python code for sending and receiving data.

Now we just need to account for receiving the data. Since the data length from the C2 is sent within the first 12 bytes we can just receive the first 12 bytes, pull out the length and then account for how much more we should read. Adding the below to our send_msg function.

For the C2 message itself we can just use a Python class to mimic the structure we have previously laid out.

This leaves us with decoding the traffic and then pulling out the relevant data we want. The decode function is a simple XOR loop.

Now we just need to see if this data is the same as the sleep routine but for demonstration purposes we’ll just try to find the next command if it exists and log the data received to screen. For all the recent versions of TinyLoader we’ve gone through the received bytecode appears to always have the ‘mov edx, dword [ebp]’ command right before it loads the next C2 command in place, this could be different for other versions and since we are dealing with bytecode being executed dynamically via C2 it could technically be anything.

The full script will be included with this post. For testing we used a currently live C2 of port 40020.

Decoded this gives us the commonly delivered bytecode that will sleep and then perform the same request again, this makes the bot perform this 'checkin' over and over again until it is given another command.

Awesome, so now we can either expand on this by accounting for all possible commands from the C2 or simply use this script as a way to test for payloads on a live C2 without having to actually run the bot the entire time.


TinyLoader continues to be a widespread threat to global organizations. Here we have discussed TinyLoader capabilities, infector vectors, and how to craft a script to monitor ongoing C2 commands.

Fidelis customers are protected from TinyLoader by a variety of mechanisms designed to detect malware throughout the infection chain.


Nymaim from BetaBot:

Cerber from BetaBot:

Pivoting off IP we can find a large number of exe files being downloaded from this IP.

01eef6f633d5c0e234de5149ffd46e8c            file1.exe

037c675489bb0faeab114bbd6cf3067a          pos.exe

06446f3aa3abe01f761003a6d88350f8           bbcrypt.exe

06e01e694ea6faa8d9971187760b69d7          file1.exe

08a0635de60adc56637ffb733632d74d          bbcrypt.exe

08b3e12693107b139d166cf004ee69c6          file1.exe

09f040baeb18dd4dbb2892315bbc2a74         file1.exe

0a445b8527db0f645bb26381b3ea121b         bbcrypt.exe

0f00309e831e2de35f830f271019561e          bbcrypt.exe

1227bf7476a60099d50500097da2f62f          bbcrypt.exe

133f4ddd6587342f3b2e7df344cddd84          file11.exe

15e9f391ed79ee67c3dfef4186e61c93           file1.exe

17aa0b3bdb21d2a4456096a408374847         bbcrypt.exe

17cbe09f9c75a497b4f440d874e9433a          file1.exe

18aa8578fc4c1f28580cb0539314f0c4           bbcrypt.exe

1a1bf6a037fc8872af04a634a8350106           file1.exe

1c34903b4b0f15b371bc79993d3d3b69         file1.exe

1e5d0cb43f14a9f234b1bd3a702b180d          file1.exe

1f66d882cd7353d53c336e4cded7a88f          file1.exe

202e98702cc5417b9b3bc6582403aa0d         bbcrypt.exe

203ea8613c6bcf4b00349e79057df64e          bbcrypt.exe

22ac8b47d9bfaa37771fb8b5960591a3          file1.exe

23392d31732116f676da8d86a6a792d1         bbcrypt.exe

23fd4eede972e67a929bc22efb0a3f6f            bbcrypt.exe

264ec404e3f8b998eb2c5e371cf57566           bbcrypt.exe

278ba01eb01ae1915995b139e9e44c8d          bbcrypt.exe

2806c76e30b30e27dc9c2c44afae2421           bbcrypt.exe

2afda33879ff3362389bd4c7278bbccc           bbcrypt.exe

2cfb09816d25ca8bf750c3d71b81bc73          file1.exe

307a3d0591126d91768248fef407bc0c          bbcrypt.exe

3095aac456a760269e662f2a8b850807          file1.exe

31a94cd639f31ec104bb5e0f6d52ba97          bbcrypt.exe

348943966fd92ec68b67891b2aaadcef          file1.exe

34b5e2bf2f8f4808ad2afdf9b7c818af            bbcrypt.exe

382ef22d698d7ca31ab40d4477def648          diablo.exe

39ed54bd2f81af790398e76819dceab6          bbcrypt.exe

3b6807cff5e0b259dc7f8934941cd270          file1.exe

3ce23461e15c48785716ecef4a2f9be8           file1.exe

4417d04466c94be002ec1319cb6963d9         bbcrypt.exe

4460468f06890d6dd50ad39f7935b66e         bbcrypt.exe

4568b93a5a61666b4cae9bd92861ca9b          bbcrypt.exe

46cfafb4e49835f989f49d9605368fc8            file1.exe

4f0095efe732df35e5fdca48effd0ed0             diablo.exe

54c2f5b380df43b0da649cd7118b0e8a          bbcrypt.exe

564b12ef14968096fce401450766c850          bbcrypt.exe

57c3a19cc82c565f374031b6146eeecb           file1.exe

58078ba2941f787afdf1277bcb73e10d          file1.exe

5b4362c9cca45132fddffef66f0f86cc             bbcrypt.exe

5ba6fba029815441b9b6bf9141587b2d         file1.exe

5ed6a7906319dcdc63a9a42acd04e89a          file1.exe

660e2ed1b3ed3fbd6723371a17cb5e8f          bbcrypt.exe

666b43bd3085644dfa465817f1eeeabf          bbcrypt.exe

66bf885615062d0d0c975929d1cfcd78         file1.exe

671de81cd315901cd345e597136717cc         bbcrypt.exe

6764bab6681d8c79a8f04cb331edfaa4          file1.exe

6768e98b4fd0480d28f98f250c56aa81          file1.exe

6929a050973f88e605ecfff2d9a32710           file1.exe

6a620166fd6c46c654f0700b9c6176fa           bbcrypt.exe

6c5ce2db6a5a5575aff5eb76cf7b8079           bbcrypt.exe

71760870c2867df833511fedfbd47016          bbcrypt.exe

71fef8e6944f516de0b5f001804d0125           file1.exe

770f736f54269b59825bdd63afe69674          bbcrypt.exe

784628c5e11a7afa9b844494a0bb0a4e           bbcrypt.exe

7efa1049dbe632489de7a1020b6ef3a8          bbcrypt.exe

7f9c0d816f41d8f746f5490778babe38           bbcrypt.exe

7ff716b819b147849b5f58030fa435c0           bbcrypt.exe

865ad7924c7734617a30d5c98176f551         bbcrypt.exe

8726bfef33c8e26360059e03c518df88           bbcrypt.exe

88d476af67813490d2fc5073f719ce8f           file1.exe

8a3f3a144a71b0d813453edb3c4fd6d8          bbcrypt.exe

8ad61159772403d62d9cbe19d5aebff5          file1.exe

8e0a7b73a3e2e0a24218299e8ac10b84          bbcrypt.exe

8fe749c3bb54d41a41adbbe127d41056         file1.exe

922273ab07f43c1b74432e03b835b910         bbcrypt.exe

93c6b9230cf273f7d8cc225cda497610          bbcrypt.exe

9ce851a9818b482e63dfa8b76d2027b9         bbcrypt.exe

9df6d2bfdc079e5e7b75c79c62c9e0c8           file1.exe

a1e137f7c9c3e77f5984c1b509618654           file1.exe

a429ada759f01b4cf03a04273f053c29           bbcrypt.exe

a73381725799dc7a8e5e589c2720b981         bbcrypt.exe

a9e42466fae3c6431b57b0b71a941127          file1.exe

aae23f544a3bd55e636e92d05a6c506e          file1.exe

abe28a4d652bfe964f977ba6c7f7f238                       file1.exe

ad521ea0d6ac85da951e93a7e587f3a4          file1.exe

adcc46856a8b23367ca14fd0fe9e3590           bbcrypt.exe

af6bb23635adb72b06472ae068dd9ace          file1.exe

af97678035cdb7abece1b2948f264ea9           file1.exe

b0a8715cdc389e734e8520007f543e25          bbcrypt.exe

b21195fa096f183355d95623be3b0b0b         file1.exe

b2657e68dd05916685e4f3fe0c8e1e2a          file1.exe

b5b9551018eb3bedffd661aeb3668426          bbcrypt.exe

b75e530d9b92e03e02739e452ac33690         bbcrypt.exe

b96528677db7d432f9c7b0e51ccd9d08         file1.exe

b9bf04d5b241a01ddbd5a43da368a708         bbcrypt.exe

bbea51ea37aa1b84365005987c131da5          bbcrypt.exe

be8f8ab76620f02dec7dc9b999271d11          file1.exe

c05bc7a032823415819697926fafb16b          bbcrypt.exe

c0c75098126d2273ba97c50492e88d04         bbcrypt.exe

c0e42e01ed6208ae6e1f49362dc0d0d3          bbcrypt.exe

c279e52b01635fc53c872b882089b54c          bbcrypt.exe

c58040264dc14e7d1034bf45f80b925f          file1.exe

ca6c277da5ef8e2f6769af35c5f3da62            bbcrypt.exe

ce6c0cee1ed5c6a60bf7159152734291           file1.exe

d1b0fd26318d2f5609207d98ede83df6          bbcrypt.exe

d7002a10efe01df6e87e496fabc6dcd6           file1.exe

d8da9596c2aea62e5e3f6ab2d9b50b09          bbcrypt.exe

da65f374e62d79f0bef1d76050ff0c8a            file1.exe

dfa4f4a0be28f18d41026d786395a094          bbcrypt.exe

e36d9f1267f363b55aa803a57a17d015          bbcrypt.exe

e76626cc4b23e2b5d8d90e031ff51f10          file1.exe

eeef3596818c9b566abbda6c288f271a           bbcrypt.exe

f03b105bcc8fc8e1f7e56c92fbd9b2e2            bbcrypt.exe

f4cef44721a9f484b12d65dd17a90400          file1.exe

f69ae0dc9b0587a5651e7ce286adad53          bbcrypt.exe

f805232a4ac1d49309bfb7216e9a4960          bbcrypt.exe

fa12b8c288ac8177180f9d4758c40be9          file1.exe

fc5af82d8370e248c14765070a1ed1fa           bbcrypt.exe

Running through one of the betabots: fc5af82d8370e248c14765070a1ed1fa

Gives us C2 structure for the campaigns.

Also seen later being used by both SmokeLoader and BetaBot

Also some macro document campaigns related to this IP:



TinyLoader samples:

037c675489bb0faeab114bbd6cf3067a          pos.exe

553eb8235557a5569f31ecb598bac871                    PickerHost.x32.exe

553eb8235557a5569f31ecb598bac871                    printui.x32.exe

81f31223f92bf7a21a0776aad8a207d7                      igfxEM.x32.exe

19a0f00423015e6493440183fcc051da                     dellqmgr.exe