{
	"id": "0c370909-c348-4402-9864-76093911370a",
	"created_at": "2026-04-06T00:18:04.387389Z",
	"updated_at": "2026-04-10T03:20:06.916066Z",
	"deleted_at": null,
	"sha1_hash": "f6af1bb0d0b7d47aabd662c06d1454118d33d169",
	"title": "Agent Tesla - Building an effective decryptor",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 1747668,
	"plain_text": "Agent Tesla - Building an effective decryptor\r\nBy map[name:Alessandro Strino]\r\nPublished: 2023-08-29 · Archived: 2026-04-05 17:58:53 UTC\r\nGeneral Information and preface\r\nAgent Tesla, according to the data provided by CERT-EU, is one the most prominent threats that are hitting\r\nEuropean cyberspace. Because of that, I found that it could be quite interesting understanding its behavior.\r\nHowever, as I usually prefer, instead of focusing on the infection chain or information about TA methodologies,\r\nsharing knowledge that were already provided by more authoritative sources, I preferred to focus mostly on\r\nmalware analysis and in this specific case to the latest encryption algorithm adopted. Then, upon the knowledge\r\nacquired, I would like to write a decryptor script that extracts payload configuration.\r\nEncryption variants\r\nAgent Tesla first appeared in 2014, however, its evolution over time could be tracked by multiple TTPs. For the\r\npurpose of this article, I’m versioning it through the encryption algorithm adopted. At the time of writing there\r\nhave been 4 different versions with unique characteristics:\r\nEncryption v1: Through this encryption implementation, strings are stored (encrypted) in base64. The decryption\r\nfunction uses a password and a salt ( both hardcoded) as input for the SHA1 algorithm, in order to generate the\r\ndecryption key. Then, ciphertext and key are eventually used with AES in CBC mode.\r\nEncryption v2: The main difference from the previous method, is that each encrypted string is paired with a\r\ndedicated key and an IV. The algorithm used is still AES in CBC mode.\r\nEncryption v3: In this version, TA completely changed their approach, shifting to a pure xor decryption. The\r\ndecryption function is defined within the .cctor() constructor. The structure of encrypted strings is quite simple.\r\nEach string is contained in a byte array paired with a key. The size of the ciphertext allows the decryption routine\r\nto iterate over the byte array distinguishing all parameters.\r\nEncryption v4: The latest version of Agent Tesla is based on a xor string algorithm that stores information within\r\na macro-structure that contains raw data organized as follow:\r\nhttps://viuleeenz.github.io/posts/2023/08/agent-tesla-building-an-effective-decryptor/\r\nPage 1 of 6\n\nFigure 1 - Encrypted data structure\r\nIn this version we have a macro-struct that contains the encrypted data. It’s actually possible to visualize it as an\r\narray where each element follows a specific structure where the first 4 bytes are dedicated to define the encryption\r\ndata length, then other 4 bytes are used to describe the encryption key and the remaining bytes are reserved for the\r\nactual data.\r\nAs always, the decryption routine iterates over the encrypted data, using key bytes.\r\nAnalysis of encryption v4 and obfuscation routine\r\nAs I wrote in the first paragraph Agent Tesla analysis will be carried out on the latest encryption mechanism.\r\nBecause of that, let’s start analyzing the main components of this algorithm:\r\nThe key is generated randomly through RandomNumberGenerator.GetInt32(int.MaxValue) function. The\r\nint.MaxValue constraint is related to the key size limitation of 4 bytes within the encrypted data structure. The\r\nalgorithm it’s pretty straightforward, performing xor between plaintext and key bytes. However, what really\r\nmatters here is the obfuscator that happens at runtime.\r\nThe obfuscation routine is part of an open source project. Basically, this obfuscation works creating multiple\r\nplaceholders that are going to be replaced at runtime. Analyzing the sample statically, this technique messes up\r\nwith code decompilers such as DnSpy. However, the author wrote a detailed blogpost explaining obfuscator\r\nfeatures and its modus operandi:\r\n“After processing all methods we need to do some patches in the injected runtime. First, we need to set\r\nup the placeholder struct with the correct attribute values. The struct needs a ClassLayout with\r\npacking size 1 and the length of the encrypted data as its size.”\r\n“We also need to create a new field which will be an initialized version of our struct. By adding a\r\nDataSegment in its FieldRva, we can use the field to store any raw data we want, in this case, our\r\nencrypted string data.”\r\nhttps://viuleeenz.github.io/posts/2023/08/agent-tesla-building-an-effective-decryptor/\r\nPage 2 of 6\n\nFollowing the indication provided by the author, we should have a more clear idea of what these components are\r\nand how to hunt for them in the code. Now it’s possible to start looking at the code gathering as much information\r\nas possible (e.g., locating these placeholders) and finding out a pattern to write an effective configuration\r\ndecryptor.\r\nBinary inspection\r\nIf we open up DnSpy, we could be overwhelmed by the mess that is going to be presented in front of us. However,\r\ntrying to follow the code flow, we could start exploring.\r\nFigure 2 - Entry point\r\nStarting from the Entry Point, it’s possible to locate something promising. Exploring variable and function calls\r\nand following references to the object GWZl2RFJ6nA, it’s possible to bump into quite interesting piece of code.\r\nFigure 3 - Obfuscated decryption routine\r\nFirst of all, we see the function cpblk that it’s necessary to perform the injection at runtime, moreover, scrolling\r\nthe code it’s possible to get insight about pointer operations paired with xor. In fact, observing the line 104 in\r\nFigure 3, it is very similar to the encryption routine that we saw in the previous paragraph.  Nevertheless, on the\r\ntop of that, as a final proof that we are looking in the right place, scrolling at the end of the code we see a class\r\nthat fulfills all requirements requested by the obfuscator.\r\nhttps://viuleeenz.github.io/posts/2023/08/agent-tesla-building-an-effective-decryptor/\r\nPage 3 of 6\n\nClassLayout\r\nPack size = 1\r\nSize = encrypted data length\r\nFigure 4 - Class placeholder for runtime decryption\r\nMoreover, following the instruction provided by the author, we should be able to locate the encrypted string in raw\r\nbytes within the binary. If we have a closer look to struct zqRrwrwgu examining the raw value, we are redirected\r\nto a very suspicious sequence of bytes.\r\nFigure 5 - Encrypted string\r\nAnalyzing those bytes, it’s immediate to find out that we are dealing with an encrypted payload that is ready to be\r\ndecrypted.\r\nDecrypting Strings\r\nThe idea behind this script is simple:\r\nFind out a class that is big enough to contain the encrypted data ( usually the biggest class in the code).\r\nThen we could retrieve raw bytes related to its size from the binary file and forward them towards our\r\ndecryption routine\r\nBefore proceeding, it’s worth mentioning that I’m quite a newbie in .NET interaction with python and generally,\r\nI’m still learning .NET layout. Because of that, if someone else is going to produce more efficient code. Please do\r\nit! But for now, let’s do a quick look to this this script:\r\nhttps://viuleeenz.github.io/posts/2023/08/agent-tesla-building-an-effective-decryptor/\r\nPage 4 of 6\n\nFigure 6 - Agent Tesla decryptor\r\nLine 40 - 44: Gathered references to ClassLayout and FieldRVA Tables.\r\nLine 46 - 47: Following the initial idea that encrypted data should be stored in a quite large class, I started\r\nto enumerate class, selecting the biggest (likely the one that contains the encrypted strings)\r\nLine 51: retrieve the last element of the FieldRVA table that contains our data (I don’t know if it is an\r\nunexpected behavior caused by the obfuscation process applied, but the raw data containing the encryption\r\nstring resulted to be always the last element of the FieldRVA table).\r\nRunning our script on one of the latest Agent Tesla sample, we got the following result:\r\nFigure 7 - Decryptor result\r\nReferences\r\nAgent Tesla Decryptor:\r\nagent_tesla_decryptor_v4.py\r\nDotNet references:\r\nGeneral .NET implementation info\r\nPython parser for .NET\r\nSamples:\r\nhttps://viuleeenz.github.io/posts/2023/08/agent-tesla-building-an-effective-decryptor/\r\nPage 5 of 6\n\nae26382f191225447550e9a691453fc3ea2e02127222787c662efc8db63c59e3 (SHA256) MalwareBazaar\r\nacedd97c8350bacc485e87ae56c851d08b497c202deb46df28c3e7218cb4469a (SHA256) MalwareBazaar\r\nf5751d89bc6f15c3ade6513d3cf44f92a25e8cd25d2f5ad239b8c44f8f732cb8 (SHA256)MalwareBazaar\r\nSource: https://viuleeenz.github.io/posts/2023/08/agent-tesla-building-an-effective-decryptor/\r\nhttps://viuleeenz.github.io/posts/2023/08/agent-tesla-building-an-effective-decryptor/\r\nPage 6 of 6",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://viuleeenz.github.io/posts/2023/08/agent-tesla-building-an-effective-decryptor/"
	],
	"report_names": [
		"agent-tesla-building-an-effective-decryptor"
	],
	"threat_actors": [],
	"ts_created_at": 1775434684,
	"ts_updated_at": 1775791206,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/f6af1bb0d0b7d47aabd662c06d1454118d33d169.pdf",
		"text": "https://archive.orkl.eu/f6af1bb0d0b7d47aabd662c06d1454118d33d169.txt",
		"img": "https://archive.orkl.eu/f6af1bb0d0b7d47aabd662c06d1454118d33d169.jpg"
	}
}