{
	"id": "a521ad8a-3584-4f15-84fd-ed44ba0279ec",
	"created_at": "2026-04-06T00:14:12.338757Z",
	"updated_at": "2026-04-10T03:21:51.181447Z",
	"deleted_at": null,
	"sha1_hash": "1154d254301a3eb5f0e49db783a89ff07351bf23",
	"title": "Zero2Automated – Complete Custom Sample Challenge Analysis - 0x0d4y Malware Research",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 6293729,
	"plain_text": "Zero2Automated – Complete Custom Sample Challenge Analysis -\r\n0x0d4y Malware Research\r\nBy 0x0d4y\r\nPublished: 2024-02-02 · Archived: 2026-04-05 21:58:53 UTC\r\nThe road so far…\r\nIn this post, I will analyze the customized sample of the Zero2Automated: The Advanced Malware Analysis course,\r\nwhich is presented to us when we reach the halfway point of the course. At this point, the course has already explored in a\r\ndeep and practical way subjects such as Cryptography Algorithms, Unpacking Methods, In-depth analysis of first and second\r\nstages, development of automations for configuration extraction and communication emulation, in addition to various\r\nmethods of evading defenses such as Process Injections (a lot of them) and Anti-Debug, Anti-VM and Anti-Analysis\r\nmethods, and persistence methods.\r\nTherefore, despite being halfway there, a lot of content was given until we reached this first challenge. And in this article,\r\nwe will explore customized sampling, with all the knowledge acquired in the course so far.\r\nIncident Response Team Email (Storytelling)\r\nHi there,\r\nDuring an ongoing investigation, one of our IR team members managed to locate an unknown sample on an infected\r\nWe're not too sure how much the binary has changed, though developing some automation tools might be a good id\r\nI have uploaded the sample alongside this email.\r\nThanks, and Good Luck!\r\nBinary Triage\r\nIn this section I will start my binary analysis triage methodology.\r\nThis triage that I do before carrying out more in-depth analyses, aims to identify some important information to identify\r\ninitial characteristics of the binaries, and answer some questions, such as:\r\nIs the binary packed/encrypted? Which sections of the PE binary contain these clues?\r\nAre there cryptographic operations using XOR, with the purpose of obfuscating code, strings, etc.?\r\nAre there some interesting strings, such as artifact names, commands, URLs, IP addresses, etc.?\r\nWith the answers to these questions, I begin to make decisions for the next phases of the analysis.\r\nTo collect this information, I used a tool that I developed (and am still developing), called re_triage, which aims to collect\r\nprimary information.\r\nAnd when executing it, as we can see below, we are able to identify two sections (.text and .rsrc) of the binary that have\r\nhigh entropy, and this can be a strong indication that the binary is packed.\r\nhttps://0x0d4y.blog/zero2automated-custom-sample/\r\nPage 1 of 28\n\nDue to the difference in entropy between the .text and .rsrc sections, we can assume that the .rsrc section contains the\r\nsecond packed stage, while the .text may contain cryptographic operations, which consequently increase its entropy.\r\nThis assumption gains a little more strength, even when analyzing the output of my script, which shows several XOR\r\noperations that resemble cryptographic operations, exactly in the .text section (with low entropy compared to .rsrc).\r\nIn addition to the information focused on entropy, possible cryptographic operations and packing patterns, it is also possible\r\nto observe in the output of my script, that this sample contains some functions related to Anti-Debug techniques,\r\nProcess/Thread Enumeration and possible execution of some technique Process Injection, in addition to functions that\r\nmay have the ability to drop other stages of the infection.\r\nhttps://0x0d4y.blog/zero2automated-custom-sample/\r\nPage 2 of 28\n\nNow that we have an overview of the sample’s possible capabilities and characteristics, we will validate this information and\r\nidentify new capabilities in more depth.\r\nIdentifying the Anti-Debug Implementation\r\nIn order to identify the sample flow, and identify if it is packed, and if before reaching the unpacking process it will\r\nimplement any of the Anti-Debug techniques that we identified in the previous section, we will start the reverse engineering\r\nprocess , to identify the current stream of this sample.\r\nWhen opening the sample in IDA, we are redirected directly to the sample’s main function. However, before the main\r\nfunction, there is a function that executes Anti-VM and Anti-Debug techniques, before loading the main function. In the\r\nimage below, we can see that mainly the anti_debug function, if true, the program goes to the exit flow of the process.\r\nAt the beginning of the anti_debug function, the sample executes the IsProcessorFeaturePresent function, to collect\r\navailability information about the _fastfail feature.\r\nhttps://0x0d4y.blog/zero2automated-custom-sample/\r\nPage 3 of 28\n\nAt the end of the anti_debug function, this is where the execution of the IsDebuggerPresent function is found, in addition\r\nto the use of the SetUnhandledExceptionFilter and UnhandledExceptionFilter functions, also as complements in the\r\nexecution of the tactical objective of Anti-Debugging.\r\nReversing the Main Function\r\nAfter identifying the implementation of Anti-Debugging techniques, in this section we will focus on analyzing the main\r\nfunction of the sample.\r\nAs soon as we open the main function, we come across the implementation of API Hashing/String Encryption, with the\r\npurpose of obfuscating API calls and consequently hiding their main capabilities.\r\nJust for the purpose of clarifying what API Hashing or String Encryption is, and how adversaries implement this evasion\r\ntechnique, below is an illustration of the hashing process using the Sleep API as an example.\r\nNow that we know the API hashing process, below we can see this same technique being implemented in the main function.\r\nAs you can see, the API Hashing technique is implemented in the main function, along with the technique for resolving\r\nthese APIs dynamically (through LoadLibraryA and GetProcAddress) with the purpose of making analysis more difficult\r\nand trying to evade defenses.\r\nAbove we can see the following pattern:\r\nThe sub_401300 function is executed, receiving an encrypted string as an argument.\r\nAfter this, the return from the execution of LoadLibraryA and GetProcAddress is received in variables, which\r\nreceive the string, possibly decrypted, as one of the arguments. Thus, carrying out the execution of the library and\r\nfunction that refer to these encrypted strings.\r\nThis is repeated throughout the main function code. If we check the Microsoft documentation regarding the LoadLibraryA\r\nfunction, we can see that the purpose of loading a library (DLL) in the process’s memory scope, in which its name must be\r\npassed as an argument.\r\nhttps://0x0d4y.blog/zero2automated-custom-sample/\r\nPage 4 of 28\n\nHMODULE LoadLibraryA(\r\n [in] LPCSTR lpLibFileName\r\n);\r\nWe can see this exact pattern in the pseudo-code above, where LoadLibraryA is receiving the string ‘a5ea5Qpy4‘ (or\r\n‘.5ea5/QPY4//‘) as a parameter. Therefore, we can assume that this string is a library that will be decrypted by the\r\nsub_401300 function, and passed as an argument to LoadLibraryA to load it.\r\nIf we also look at Microsoft’s documentation regarding the GetProcAddress function, we can see that it also follows the\r\npattern observed in the pseudo-code.\r\nFARPROC GetProcAddress(\r\n [in] HMODULE hModule,\r\n [in] LPCSTR lpProcName\r\n);\r\nIn other words, through the GetProcAddress implementation code, we can validate that in the main function, the following\r\nflow is followed:\r\nThe name of a library is decrypted;\r\nThe name of a function is decrypted;\r\nThe LoadLibraryA function receives the decrypted name of the library as an argument, with the aim of loading it\r\ninto the process’s memory scope;\r\nThe GetProcMemory function receives the handle of the library loaded by the LoadLibraryA function, and the\r\ndecrypted name of a certain function belonging to the library in question.\r\nIf we check the xrefs of the sub_401300 function, we are able to observe that it is widely used, repetitively in the main and\r\nsub_401000 functions.\r\nPerfect. But without knowing exactly which library and functions are being used, our analysis will be a little difficult to\r\ncarry out. Therefore, let’s analyze the sub_401300 function, to understand how this function performs the string decryption\r\nprocess. Below is the pseudo-code of the API decryption function.\r\nhttps://0x0d4y.blog/zero2automated-custom-sample/\r\nPage 5 of 28\n\nIf we look closely, the algorithm is very simple to understand, it consists of a table of strings and the use of this table as an\r\nindex to perform substitutions throughout the code.\r\nI developed the Python version of this algorithm, and you can find the code below.\r\ndef decode_string(encrypted_string):\r\n \r\n index = 0\r\n substitution_table = \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890./=\"\r\n \r\n while index \u003c len(encrypted_string): # Main loop to decode each character in the string\r\n current_char = encrypted_string[index] # Get the current character\r\n new_char = substitution_table[0] # Obtain the new character based on the substitution table\r\n char_index = substitution_table.index(current_char) if current_char in substitution_table else None\r\n \r\n if char_index is not None: # Update the new character based on the substitution logic\r\n table_index = char_index\r\n table_length = len(substitution_table)\r\n new_index = (table_index + 13) if (table_index + 13) \u003c table_length else (table_index - table_length + 13)\r\n new_char = substitution_table[new_index]\r\n \r\n encrypted_string = encrypted_string[:index] + new_char + encrypted_string[index+1:] # Modify the original stri\r\n index += 1 # Move to the next character\r\n \r\n return encrypted_string\r\nencrypted_string = input(\"\\n\\033[1;35mPut here the encrypted strings (multiple strings separated by comma):\\033[m \")\r\nlist_encryp_strings = encrypted_string.split(',')\r\nfor decrypt in list_encryp_strings:\r\n decrypt_strings = decode_string(decrypt)\r\n print(f\"\\nThe encrypted string \\033[1;34m{decrypt}\\033[m is \\033[1;31m{decrypt_strings}\\033[m\\n\")\r\nBelow, we can observe the execution of this script, to decrypt all strings decrypted by the sub_401300 function.\r\nhttps://0x0d4y.blog/zero2automated-custom-sample/\r\nPage 6 of 28\n\nNow that we know which libraries (DLLs) and functions are being loaded and called by the main function code, we can\r\nrename variables and strings in order to make the code more readable. Below is the documented version of the main\r\nfunction.\r\nIn the pseudo-code above, the main function loads the kernel32 library, and calls several functions to locate and manipulate\r\na certain resource, which cannot be identified statically, and allocates it in a memory space through the VirtualAlloc\r\nfunction.\r\nNow let’s move on to the second and final part of the main function code, which can be seen below.\r\nIn the pseudo-code above, we can observe that after carrying out the process of resource manipulation and allocation of this\r\nresource in memory, said resource is decrypted using an algorithm that contains the RC4 pattern (the 0x100 value in a loop).\r\nAfter the decryption process, the function (named by me, and was tagged as sub_401000, previously identified in the xrefs\r\nof the string decryption function) dynamic_string_decrypt_create_proc is called, which receives the resource as an\r\nargument. The name I gave the function is very suggestive, but below, we will explore it in more detail.\r\nhttps://0x0d4y.blog/zero2automated-custom-sample/\r\nPage 7 of 28\n\nReversing the dynamic_string_decrypt_create_proc function\r\nIn this section, I will describe the analysis of the dynamic_string_decrypt_create_proc function.\r\nIn this function, we see the use of the string decryption function equally used as in the main function. However, this function\r\nhas a specific purpose as we will identify throughout this section.\r\nBelow, we can see that at the beginning of the pseudo-code of the dynamic_string_decrypt_create_proc function, it loads\r\nthe CreateProcessA API and executes it, creating a process in a suspended state. The code then loads and executes the\r\nVirtualAlloc API to allocate memory space with read, write, and execute permissions. The return from VirtualAlloc\r\nexecution is the base address of the allocated memory space, which is passed as an argument to the GetThreadContext API\r\nexecution (also decrypted and loaded).\r\nAfter executing the activities above, the function will read, allocate and write to the memory space of the process in a\r\nsuspended state, as we can see below.\r\nAnd as a final action, the function will finally execute the Thread of the suspended process.\r\nhttps://0x0d4y.blog/zero2automated-custom-sample/\r\nPage 8 of 28\n\nThe flow of actions performed in this function is very similar to the Process Hollowing technique.\r\nI think that so far, we can understand that this sample we are analyzing is the first stage that will decrypt the second stage\r\nand inject it into the memory space of a child process, created by itself.\r\nLet’s continue with our dynamic analysis, with the purpose of identifying the second stage and extracting it from memory,\r\nwith the aim of reversing it and understanding the actions that will be performed in the second stage.\r\nIdentifying and Extracting the Second Stage\r\nAs we were able to identify in the previous section, sampling is just a first stage, which will decrypt a second stage via the\r\nRC4 algorithm, create a child process, and inject the second stage into its memory scope.\r\nNow that we know how the first stage code works, let’s set some strategic breakpoints, to identify the second stage before it\r\nis injected into another process, and identify which process is the target of this injection.\r\nTo do this, we need to set some breakpoints in:\r\nBefore performing decryption using the RC4 algorithm, with the purpose of monitoring the decryption process, and\r\nidentifying the decrypted binary in memory so that we can extract them.\r\nCreateProcessA: as we know, this API is called indirectly, with the purpose of complicating our analysis and\r\nevading detection. However, as we already know the code for this sample, we know the address where we will set our\r\nbreakpoint.\r\nVirtualAllocEx: to try to extract the second stage.\r\nWriteProcessMemory: for the purpose of identifying which data will be written to the memory scope of which\r\nprocess.\r\nResumeThread: with the aim of identifying the exact moment when the second stage will be executed in the remote\r\nprocess.\r\nIsDebuggerPresent: as we saw that it will be executed, before the main function is executed\r\nBelow we can observe the selected breakpoints.\r\nNow that we have established each breakpoint, let’s move on to the dynamic analysis.\r\nInterestingly, our IsDebuggerPresent breakpoint was not triggered, and we went directly to the breakpoint before the RC4\r\nroutine loop.\r\nhttps://0x0d4y.blog/zero2automated-custom-sample/\r\nPage 9 of 28\n\nIt is possible to identify that at the address ss:[ebp+eax-108], the first loop writes data during its execution.\r\nAt the end of the loop, we see two character structures, the first appears to be the alphabet, and the second a set of\r\napparently random data.\r\nAt the end of the second loop, the entire possible alphabet that we saw previously was transformed into pseudo-random data.\r\nhttps://0x0d4y.blog/zero2automated-custom-sample/\r\nPage 10 of 28\n\nAt the end of the entire loop, the data continued to appear pseudo-random, so we moved on to the next breakpoint, the\r\nindirect call via the CreateProcessA API.\r\nWhen executing the CreateProcessA call, you can see that it creates a process with the same name as itself.\r\nJust in case, let’s dump this new process created.\r\nhttps://0x0d4y.blog/zero2automated-custom-sample/\r\nPage 11 of 28\n\nHaving saved the second process as a precaution, we will continue executing the sample, until the next breakpoint triggers.\r\nAnd the VirtualAllocEx breakpoint has worked, now we can know what the allocated space will be, and what can be\r\nwritten in the scope of this allocated memory.\r\nIf we take a look at the stack before executing the VirtualAllocEx call, we can understand what is happening.\r\nBelow we can see the parameters passed to VirtualAllocEx to be executed. The first parameter is the most interesting\r\n(identified as 0000010c), as it refers to the Handle of the process that will suffer from this action, that is, the process that\r\nwill have space allocated in memory.\r\nWhen we look at the handles of the current process that we are debugging, we can see that handle 0x10c is the handle for the\r\nchild process created in suspended state.\r\nhttps://0x0d4y.blog/zero2automated-custom-sample/\r\nPage 12 of 28\n\nWe continue execution until our next breakpoint triggers. The breakpoint in is the indirect call to the WriteProcessMemory\r\nAPI.\r\nAs we can see below, in the WriteProcessMemory implementation structure, the third parameter that must be in the Stack\r\nis the lpBuffer, which must contain the memory address for the data that will be written to the process indicated in the first\r\nparameter (hProcess), which will contain the process handle.\r\nBOOL WriteProcessMemory(\r\n [in] HANDLE hProcess,\r\n [in] LPVOID lpBaseAddress,\r\n [in] LPCVOID lpBuffer,\r\n [in] SIZE_T nSize,\r\n [out] SIZE_T *lpNumberOfBytesWritten\r\n);\r\nIn the image below, in addition to being able to identify the indirect call to the WriteProcessMemory API, we are also able\r\nto validate the target process (the same handle identified in the previous call) and the payload of the second stage that will be\r\nwritten to the remote process.\r\nNow that we have identified the second stage payload, we can move on to the memory address that contains this data,\r\nthrough x32dbg.\r\nhttps://0x0d4y.blog/zero2automated-custom-sample/\r\nPage 13 of 28\n\nWhen we identify the location where the second stage is stored, we simply extract the dump as a file\r\nIn this section, we analyze the first stage of the ‘sent by the IR team‘ malware. In this first stage, we identify the use of API\r\nhashing encryption techniques to resolve them in memory, and call them indirectly. Furthermore, we identified that the first\r\nhttps://0x0d4y.blog/zero2automated-custom-sample/\r\nPage 14 of 28\n\nstage executes the PE Injection technique in a remote process (a child process of the same binary, however, with the second\r\nstage injected into its memory scope).\r\nIn the next section, we will perform the same analysis on the second stage extracted from the first stage.\r\nReversing Second Stage\r\nIn this section we will perform the analysis of the second stage, extracted during the analysis of the first stage.\r\nBelow, we can see the overall image of the flowchart of the execution of the main function code.\r\nAnd right at the beginning of the function, we are presented with some conditionals that perform decryption using the RC4\r\nalgorithm, and perform Hashed API resolution.\r\nhttps://0x0d4y.blog/zero2automated-custom-sample/\r\nPage 15 of 28\n\nWe can check the xrefs referring to the rc4_routine function, with the aim of identifying when this function is called, and\r\ntrying to understand the contexts of its execution.\r\nAnd as we can see in the image below, this function is performed in two functions:\r\nmain – current function;\r\ndynamic_library_load – function seen in the previous image.\r\nIf we check the use of the rc4_routine function within the dynamic_library_load function, we will see that this function is\r\nresponsible for decrypting the libraries that will be loaded at run time.\r\nThe most interesting thing is to understand that both functions will only be executed depending on the conditional met. If the\r\nresult of the rc4_routine function is as expected, the sample execution flow will execute the sub_401DC0 function.\r\nAnd within this function, we are presented with another execution of the Hashing API technique, using the\r\ndynamic_library_load function\r\nhttps://0x0d4y.blog/zero2automated-custom-sample/\r\nPage 16 of 28\n\nWhen identifying a function, which receives a hash as a parameter, it is a strong indication that the API Hashing technique is\r\nbeing applied. Therefore, we need to use tools like HashDB to identify which API these hashes are applied to.\r\nWe could use the HashDB plugin for IDA or Binary Ninja, but thinking about new future malware researchers, who don’t\r\nhave money to buy a license (for now), I developed and still update a script that automates the basic task of HashDB, called\r\nhashdb_automated. This is because API Hashing is extremely common in malware, and these young malware researchers\r\ncould be left in the dark without Plugins.\r\nBelow we can observe the execution of the script, and the discovery of the APIs that are being resolved by this function.\r\nAs you can see in the image above, this function is resolving APIs related to communication capabilities, possibly with\r\nadversaries’ C\u0026C.\r\nHaving this information in hand, we can now rename variables, objects and the function name, with the aim of making the\r\ncode more readable.\r\nAfter resolving the APIs related to communication capacity, the function code performs an XOR operation to decrypt two\r\nsets of bytes in hexadecimal, using the key 0xc5.\r\nhttps://0x0d4y.blog/zero2automated-custom-sample/\r\nPage 17 of 28\n\nI implemented this (and all the others that will be seen in this section) algorithm observed in the IDA pseudo-code in Python,\r\nwith the aim of decrypting the data and identifying the deobfuscated information. The script can be found below.\r\ndef rol1_url(byte, shift):\r\n return ((byte \u003c\u003c shift) | (byte \u003e\u003e (8 - shift))) \u0026 0xFF\r\ndef decrypt_url(v5):\r\n for i in range(len(v5)):\r\n v5[i] = rol1_url(v5[i], 4) ^ 0xC5\r\n decrypted_url = ''.join([chr(byte) for byte in v5 if byte != 0])\r\n return decrypted_url\r\nxored_url = [\r\n 0xDA, 0x1B, 0x1B, 0x5B, 0x6B, 0xFF, 0xAE, 0xAE, 0x5B, 0x4A, 0x6B, 0x1B, 0x0A, 0x7A, 0xCA, 0xBA, 0xBE, 0x6A, 0xAA, 0x8A\r\n]\r\ndecrypted_url = decrypt_url(xored_url)\r\nprint(f\"\\033[32mString Decrypted \\033[m[\\033[33mdownload_inject\\033[m]: \\033[31m{decrypted_url}\\033\\n\")\r\nBelow in the script execution, we are able to identify that the XOR operation decrypts a URL.\r\nIf we access the decrypted URL, it takes us to another URL that stores a PNG file.\r\nIf we access this other URL, we will have access to a PNG file with practically no content.\r\nIf we download this PNG file, and open it in a Hexadecimal reader/editor (I used xxd), we will be able to identify the string\r\nredaolurc, which is basically cruloader backwards, followed by several possibly encrypted bytes.\r\nAnalysis of the content of this PNG file will be explored in the next section. Now let’s continue with the code flow of the\r\nfunction we are analyzing.\r\nAfter decrypting the URL string, two functions will be executed, sub_401290 and sub_4013A0\r\nhttps://0x0d4y.blog/zero2automated-custom-sample/\r\nPage 18 of 28\n\nFirst let’s analyze the sub_401290 function, which takes the decrypted URL string as an argument.\r\nAfter de-hashing the APIs in the previous function, it is clear that this function is responsible for downloading the PNG file,\r\nthrough the decrypted URL.\r\nNow that we understand the purpose of the previous function (now called download_file_pastebin), let’s analyze the\r\nsub_4013A0 function.\r\nThis function is a bit long, so let’s break it down into parts. At the beginning of the section, the execution of an XOR\r\noperation and the dynamic resolution of some APIs that will be used below are identified.\r\nhttps://0x0d4y.blog/zero2automated-custom-sample/\r\nPage 19 of 28\n\nUsing the hashdb_automated script, we are able to identify that the hash algorithm used again was crc32, and that the APIs\r\nbeing resolved have the ability to write files to disk.\r\nIf we follow the flow we are in, the malware has downloaded the PNG file and wants to save it to disk.\r\nFurther down in the sub_4013A0 function, we can observe the use of these APIs, first identifying the current user’s\r\ntemporary directory, followed by the creation of a directory with the name of the file (possibly a directory with the name of\r\ncruloader), followed by the creation of the file within of this directory.\r\nAt this stage of the sub_4013A0 function, we identify the dropper capacity of this sample.\r\nhttps://0x0d4y.blog/zero2automated-custom-sample/\r\nPage 20 of 28\n\nNext there is another XOR operation for string decryption, which when implemented through Python, revealed that it was\r\nthe string c’ruloader‘, possibly a reference to the name of the directory/file created previously.\r\nNext, we have a decryption algorithm that takes the PNG file handle as an argument. Possibly, this algorithm is for the\r\nextraction and decryption of the third stage, using the key 0x61, which is inside the PNG file.\r\nExtraction and decryption of the third stage will be discussed in the next section. In the meantime, let’s continue with the\r\nanalysis of the second stage, to understand what will be done with the third stage payload.\r\nAnd then we reach the end of the function, where three last functions will be executed. The sub_401D50, sub_401CA0 and\r\nsub_401750.\r\nFirst, let’s look at the sub_401D50 function. This function is basically responsible for resolving more APIs through de-hashing.\r\nOnce again, through hasdb we are able to identify the hashing algorithm (crc32, once again) and the APIs corresponding to\r\neach Hash.\r\nhttps://0x0d4y.blog/zero2automated-custom-sample/\r\nPage 21 of 28\n\nAnd after analyzing the resolution of the APIs that will be called, we can observe that the code is preparing to perform some\r\ntype of Remote Process Injection.\r\nBasically the first function had the purpose of resolving the APIs, next, we will analyze the next function sub_401CA0.\r\nIn this function we are exposed once again to an XOR operation for decryption using the key 0xa2.\r\nOnce again, I implemented this algorithm in Python and when I ran it, the absolute path of the svchost binary was returned.\r\ndef rol1(byte, shift):\r\n return ((byte \u003c\u003c shift) | (byte \u003e\u003e (8 - shift))) \u0026 0xFF\r\ndef decrypt_svchost(svchost_encrypted):\r\n for i in range(len(svchost_encrypted)):\r\n svchost_encrypted[i] = rol1(svchost_encrypted[i], 4) ^ 0xA2\r\n decrypted_text = ''.join([chr(byte) for byte in reversed(svchost_encrypted)])\r\n return decrypted_text\r\nsvchost_encrypted = [0x7C, 0xAD, 0x7C, 0xC8, 0x6D, 0x1D, 0xDC, 0xAC, 0x1C, 0x4D, 0x1D, 0xEF, 0x09, 0x19, 0xFC, 0x7C,0x6D,0\r\nhttps://0x0d4y.blog/zero2automated-custom-sample/\r\nPage 22 of 28\n\ndecrypted_text = decrypt_svchost(svchost_encrypted)\r\nprint(f\"\\n\\033[32mDecrypted String \\033[m[\\033[33msvchost_process_create\\033[m]: \\033[31m{decrypted_text}\")\r\nWith this information, we are able to improve pseudo-code reading by renaming variables, functions and objects.\r\nWith this we are able to observe that after decrypting the string referring to the absolute path of svchost, this string will be\r\nused as an argument in the process creation call (the process will be created in suspended mode).\r\nNow that we know the purpose of this function, let’s move on to the analysis of the sub_401750 function, which we can\r\nalready see that receives as parameters the handles of the PNG file downloaded from pastebin, and the handle of the\r\nprocess created in suspended mode from svchost.\r\nAs we analyzed the function, we again observed a large number of executions of the dynamic API resolution function,\r\nthrough API Hashing.\r\nhttps://0x0d4y.blog/zero2automated-custom-sample/\r\nPage 23 of 28\n\nAgain, through hashdb, we identified that the hashes (crc32) refer to the set of APIs used to execute the Process Hollowing\r\ntechnique.\r\nAnd when we improve the visibility of our pseudo-code, it becomes clear that this function is in fact responsible for\r\nexecuting the Process Hollowing technique in the created svchost process in suspended mode.\r\nTherefore, in this section we analyze the second stage of the sample, where we identify that its purpose is to:\r\nDownload the PNG file that contains the third stage;\r\nExtract the third stage from the PNG file;\r\nCreate a process in svchost suspended mode, and execute the Process Hollowing technique to inject and execute the\r\nthird stage in a benign process, with the purpose of evading defenses.\r\nIn the next section, we will extract the third stage and analyze its final payload.\r\nExtract and Reversing the Third Stage\r\nhttps://0x0d4y.blog/zero2automated-custom-sample/\r\nPage 24 of 28\n\nAs we observed during the analysis of the second stage, it extracts the third stage from within the PNG file and decrypts the\r\nthird stage through an XOR operation using the key 0x61.\r\nHaving this information, it is very easy to proceed with the extraction and decryption using CyberChef. Using the XOR\r\noperation module and setting the key 0x61, we are quickly able to observe a PE header in the output.\r\nBy adding the file extraction module, we are able to download the PE file.\r\nHaving the PE file (our third stage) in hand, we simply analyze it in IDA and we are now able to see the final payload of our\r\nsample.\r\nTo validate that this is indeed the final payload, we simply need to execute the binary given to us by the ‘IR team’.\r\nhttps://0x0d4y.blog/zero2automated-custom-sample/\r\nPage 25 of 28\n\nThus, our sample analysis comes to an end!\r\nNow let’s venture into the process of identifying TTPs, tracking them through logs in the Elastic Stack, and developing\r\nYara rules.\r\nMalware Behavior Tracking\r\nIn this section we will delve deeper into tracking the sample run in our laboratory, using Elastic as a SIEM, with the purpose\r\nof trying to identify the infection steps that we identified during our analysis.\r\nBelow we are able to identify the second phase being executed, using Sysmon’s Event ID 1 (Process Creation). In this log,\r\nwe are observing the second phase by creating an svchost process by executing the Process Hollowing technique, and\r\nexecuting the malicious payload within the svchost process. At this point it is important to record the Process ID (1688) of\r\nthis new process, as we will use it to track the next phases.\r\n0:00 / 0:22\r\nhttps://0x0d4y.blog/zero2automated-custom-sample/\r\nPage 26 of 28\n\nAs we well know, the process is created in suspended mode until the second stage injects the malicious payload and\r\nexecutes it through a Thread. And that is exactly what we can see in the log record below, through Event ID 8\r\n(CreateRemoteThread). The fact that a binary is creating a remote Thread in a svchost process is suspicious enough.\r\nAnd after executing the second stage’s malicious payload within the svchost process (PID 1688), we are able to identify the\r\nnetwork connection with pastebin, in order to download the third stage, through Event ID 22 (DnsQuery) and Event ID 3\r\n(NetworkConnection) , respectively shown in the following two images.\r\nWe are also able to identify the disk writing of the PNG file, which contains the third stage performed by the svchost\r\nprocess (PID 1688). As we can see in the following two images, we are first able to identify Event ID 11 (FileCreate) by\r\nhttps://0x0d4y.blog/zero2automated-custom-sample/\r\nPage 27 of 28\n\nregistering the PNG file download cache, followed by the actual creation of the file output.jpg in the cruloader directory,\r\nwithin the temporary directory.\r\nAnd finally, we are able to identify the execution of the third stage, which consists of the svchost process containing the\r\nsecond stage (PID 1688) executing another svchost process containing the third stage (PID 19372).\r\nTherefore, in this section we were able to identify the behavior pattern of executing the binary that was sent to us by the ‘IR\r\nteam’.\r\nThis will help the IR, SOC and Threat Hunting teams understand the behavior of this sample, and identify such behavior\r\non other devices, allowing visibility into the scope of the incident.\r\nConclusion\r\nIt was absurdly fun to work on this sample, it actually demands everything you should learn in this first part of the\r\nZero2Automated: The Advanced Malware Analysis course. Excellent exercise, and very realistic! I hope this article has\r\ncontributed to your analysis, if you are stuck somewhere, and that you have learned something new here.\r\nSee you later!\r\nSource: https://0x0d4y.blog/zero2automated-custom-sample/\r\nhttps://0x0d4y.blog/zero2automated-custom-sample/\r\nPage 28 of 28\n\ndecrypted_text return decrypted_text = ''.join([chr(byte) for byte in reversed(svchost_encrypted)])   \nsvchost_encrypted = [0x7C, 0xAD, 0x7C, 0xC8, 0x6D, 0x1D, 0xDC, 0xAC, 0x1C, 0x4D, 0x1D, 0xEF, 0x09, 0x19, 0xFC, 0x7C,0x6D,0\n  Page 22 of 28",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://0x0d4y.blog/zero2automated-custom-sample/"
	],
	"report_names": [
		"zero2automated-custom-sample"
	],
	"threat_actors": [],
	"ts_created_at": 1775434452,
	"ts_updated_at": 1775791311,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/1154d254301a3eb5f0e49db783a89ff07351bf23.pdf",
		"text": "https://archive.orkl.eu/1154d254301a3eb5f0e49db783a89ff07351bf23.txt",
		"img": "https://archive.orkl.eu/1154d254301a3eb5f0e49db783a89ff07351bf23.jpg"
	}
}