{
	"id": "d4cffc8c-8a6c-4df4-b76b-f0cce96fcb6f",
	"created_at": "2026-04-06T00:22:18.280879Z",
	"updated_at": "2026-04-10T03:19:59.382203Z",
	"deleted_at": null,
	"sha1_hash": "419a4bd890aa3edad0195be8a1e7510063dda8e3",
	"title": "The Infostealer Pie: Python Malware Analysis",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 1544016,
	"plain_text": "The Infostealer Pie: Python Malware Analysis\r\nPublished: 2023-02-19 · Archived: 2026-04-05 20:49:30 UTC\r\nHey Everyone, Happy New Year! I know, almost 2 months late but with all that is going on in this world and my life right\r\nnow, writing a blog post was not at the top of my list. Hope you are all doing well.\r\nSo recently I came across a tweet from “0xToxin” regarding a malware called “Venus Stealer”, now usually everyday I\r\ncome across tweets of malware, incidents and what not, but this one caught my attention because it said it was a python\r\nbased malware. I had never analyzed a python based malware before so I said “hey, time to not sleep at night!” That is how\r\nall this started, I hope you learn something from this and enjoy the read. Also as you can see the post image is from DALL-E.\r\nThis article primarily just touches on the python aspect of the stealer and therefore should not be considered as a\r\ncomplete analysis, I have intentionally stayed away from analyzing the PE file too much as the intent was to\r\nunderstand the python side of things. In any case your feedback is most welcome along with anything else you want to\r\nshare in the comments! Lets jump in! (Head to summary if you are in a hurry!)\r\n[UPDATE 1] : (SPOILER ALERT) For details regarding how google app script can be used to receive data over web and\r\nuse google sheets as a data store please scroll to bottom.\r\nBasic Information \u0026 Sample source\r\nSample Source: MalwareBazaar\r\nSample Link: https://bazaar.abuse.ch/sample/2e7371ac46e29730ed2739b041c619ea86d41a7b5032259a02f9fc8ac397988a/\r\nSample Hash (MD5): d58ce3bc7ea80069fbaa79b4db1e77db\r\nSample Hash (SHA256): 2e7371ac46e29730ed2739b041c619ea86d41a7b5032259a02f9fc8ac397988a\r\nSample Tag: Venus Stealer\r\nFile Type: “exe” PE File\r\nYes, a python malware packaged as an executable. It shouldn’t be a surprise since the ability to package python code into a\r\nexecutable has been with us since long. But one disadvantage of this approach from a malware author point of view would\r\nbe relatively huge size. Now a days though, keeping malware lean does not seem to be a priority for most malware authors\r\nas exhibited by 100MB+ sized malware binaries. Some of these use size to their advantage as a lot of online sandbox and\r\nautomated analysis tools along with EDR/AV tools do not scan files above a particular size. We will talk about such samples\r\nin upcoming blog posts, for now lets get back into the present topic.\r\nBasic Triage\r\nAfter downloading the sample, my first tool of choice was PEStudio, to find out the composition of the PE binary but for\r\nsome reason it did not work in this case. PEStudio just kept on crunching it asking me to wait.\r\nI decided to go with Detect it Easy since anyway I would have used it for its amazing packer detection capabilities. Below\r\nare some things I usually look into:\r\nTimestamp \u0026 Tooling\r\nhttps://geekypandatales.wordpress.com/2023/02/19/the-infostealer-pie-python-malware-analysis/\r\nPage 1 of 15\n\nAs can be seen here, we have a compile timestamp of 3rd Feb 2023 15:13:03 UTC so its a relatively recent sample unless\r\nthe timestamp was meddled with. Looking into the tooling detection graciously provided to us by Nauz File Detector, we\r\ncan infer that it is was indeed written in python and PyInstaller was used to convert the python script to an executable.\r\nBased on what I have read so far the reference to overlay here is important as most of the python bytecode and required\r\nlibraries are present in this. If we check the overlay heading on this screen it says it uses zlib compression.\r\nImports\r\nOld habits die hard, while in this case checking imports of the PE file was not strictly necessary since all the actual work\r\nwas to be done by python bytecode and corresponding libraries, I checked it anyway.\r\nWhile the imports seem common for a malware, it still seems to miss a few that I would have expected, including libraries\r\nfor network communication. But seeing “LoadLibraryEx” function being imported(not shown here) from\r\n“KERNEL32.DLL” I was sure it will load more libraries during runtime. An interesting observation was missing imports of\r\nregistry related functions from “ADVAPI32.DLL”.\r\nEntropy\r\nhttps://geekypandatales.wordpress.com/2023/02/19/the-infostealer-pie-python-malware-analysis/\r\nPage 2 of 15\n\nWhile we already know the sample uses PyInstaller for conversion, the entropy graph at first seemed odd to me. It didn’t\r\nseem to match the table above it until I realized that “Overlay” which was zlib compressed and therefore would definitely\r\nhave high entropy comprised of a significantly large chunk of data compared to other parts of the PE and therefore the graph\r\nseemed odd.\r\nSections\r\nOut of habit, I checked the sections listing and one oddity I noticed was the “.data” section having relatively huge virtual\r\nsize(space it is expected to occupy in ram) than its raw size(space it occupies on disk). This kind of behavior is usually\r\nobserved in cases where a packed malware unpacks itself into a section which has its virtual size listed as much larger than\r\nits raw size. The section will also need to be marked as readable, writable and executable(if unpacked content is code to be\r\nexecuted). Here however the characteristic value “0xc0000040” implies that the section contains initialized data\r\n(0x00000040) and can be read (0x40000000) and can be written to (0x80000000) but not to be executed.\r\nStrings\r\nThis is the most important component of analysis in the case of this malware. We know we have a python malware at hand\r\nand we know it uses PyInstaller to package it into an executable. But the path from downloading a python program\r\npackaged as executable to getting human readable python script is not a straight forward one.\r\nAlthough python version upgrades usually do not seem to break the python scripts written in older versions, when it comes\r\nto the underlying python byte code these version upgrades have been changing a lot of things underneath. This does not\r\nimpact you if you have the actual source code in form of python script file (.py) but if you have to deal with compiled\r\npython files (.pyc) parsing them and decompiling them into a valid .py file is a task many amazing people are putting their\r\ntime and brain power into and even after all this there is still no single python decompiler out there (at the time of writing\r\nthis post) that handles all bytecodes generated by all python versions and gives out a proper python script. There are multiple\r\ntools and they are limited by versions of python they support.\r\nGiven all this, it becomes important to know which version of python was used to write and compile the malware at hand\r\nand that is where strings come in, How? Let us see.\r\nhttps://geekypandatales.wordpress.com/2023/02/19/the-infostealer-pie-python-malware-analysis/\r\nPage 3 of 15\n\nIn the strings tab of Detect it Easy, if you filter for python you get above results and what do the indicate? They indicate that\r\nversion 3.9 of python was used to compile this package. Now we know what version we have to look a decompiler for.\r\nEasier said than done.\r\nExtraction and Decompilation\r\nBefore we think of decompiling python bytecode, we need to extract it from the executable and that is where an amazing\r\nopensource tool called pyinstxtractor comes into play. It supports wide range of python versions, is easy to use and gives\r\nyou helpful insights like the entrypoint of the entire program in form of a \u003cname\u003e.pyc file. Telling you which file to\r\ndecompile. One thing you need to make sure is that you run it with a python version same as the version used to package the\r\ntarget sample which in our case would be python version 3.9.\r\nExtraction\r\nAt this point I got a bit lazy and instead of installing python version 3.9 (my windows VM had version 3.10) I jumped into\r\nmy debian VM which had the required version. Below is the command used and its output. Notice that it says “tv6.pyc”\r\nappears to be the entry point, it makes same predictions about other files as well but the last one is usually it.\r\nroot@[REDACTED]:~/Desktop/pystealer# python3 /root/Desktop/pyinstxtractor-master/pyinstxtractor.py 2e7371ac46e29730ed2739\r\n[+] Processing 2e7371ac46e29730ed2739b041c619ea86d41a7b5032259a02f9fc8ac397988a.exe.bin\r\n[+] Pyinstaller version: 2.1+\r\n[+] Python version: 3.9\r\n[+] Length of package: 28193037 bytes\r\n[+] Found 1093 files in CArchive\r\n[+] Beginning extraction...please standby\r\n[+] Possible entry point: pyiboot01_bootstrap.pyc\r\n[+] Possible entry point: pyi_rth_subprocess.pyc\r\n[+] Possible entry point: pyi_rth_pkgutil.pyc\r\n[+] Possible entry point: pyi_rth_multiprocessing.pyc\r\n[+] Possible entry point: pyi_rth_inspect.pyc\r\n[+] Possible entry point: pyi_rth__tkinter.pyc\r\n[+] Possible entry point: tv6.pyc\r\n[+] Found 576 files in PYZ archive\r\n[+] Successfully extracted pyinstaller archive: 2e7371ac46e29730ed2739b041c619ea86d41a7b5032259a02f9fc8ac397988a.exe.bin\r\nYou can now use a python decompiler on the pyc files within the extracted directory\r\nhttps://geekypandatales.wordpress.com/2023/02/19/the-infostealer-pie-python-malware-analysis/\r\nPage 4 of 15\n\nFiles extracted by pyinstxtractor from our sample\r\nDecompilation\r\nWhen I looked up for decompilers for python version 3.9 bytecode I found a few that could have helped but after going\r\nthrough some like uncompyle6, decompyle3 \u0026 pycdc I realized that as of now, I won’t be able to get a free and open source\r\npython version 3.9 decompiler that is capable of handling all the python 3.9 bytecodes without a hitch. While the public\r\nversions of decompyle3 \u0026 uncompyle6 straight up say they can not handle 3.9 bytecode, pycdc does the job but with a\r\npartially decompiled result so I went for pycdc.\r\nDon’t get me wrong, all of these are amazing projects and I am grateful they exist, the problem is the sheer amount of under\r\nthe hood changes introduced in newer python versions and a relative lack of interest in a python decompilers.\r\nUsing pycdc requires building it on your machine and then using its decompiler or disassembler as the need be. Let us look\r\nat its build process which is fairly simple.\r\nPrerequisites: Git \u0026 Cmake\r\nsudo apt install git cmake\r\nBuild Process:\r\ngit clone https://github.com/zrax/pycdc.git\r\ncd pycdc \u0026\u0026 mkdir build\r\ncd build\r\ncmake ..\r\nmake\r\nOnce this is done your build directory will contain pycdc and pcdas. The executable pycdc is the decompiler and pycdas is\r\nthe disassembler. Below is a screenshot outlining the commands used for decompiling and disassembling the extracted\r\ntv6.pyc.\r\nSince pycdc was unable to completely decompile the sample I decided to disassemble it as well. Disassembly in case of\r\npython bytecode does not give x86/x64 like assembly outputs and is usually a bit more descriptive and different from those\r\nso I thought it’ll be fun trying to make sense of it.\r\nhttps://geekypandatales.wordpress.com/2023/02/19/the-infostealer-pie-python-malware-analysis/\r\nPage 5 of 15\n\nThe Reveal\r\nNow that we have the actual script and the disassembled version we can begin analysis. Obviously I started with the easy\r\nthing first and opened the partially decompiled script tv6.py in a Code OSS along with the disassembled one along side just\r\nin case I need more context. Even with partial decompilation it is a long script. Let us go through the findings.\r\nImports\r\nYes, imports again but this time its python imports.\r\nJudging from the imports the malware seems capable of (Non-Exhaustive List):\r\nMaking web requests and handling responses.\r\nHandle json data.\r\nPerform OS operations.\r\nHandle compression and decompression.\r\nInterface with Sqlite3 DB, probably to save obtained victim data in a structured way.\r\nHandle Base64 strings.\r\nTake screenshots using pyautogui.\r\nDecrypt data that was encrypted using win32crypt::CryptProtectData, which encrypts data using the session key.\r\nSearch using regex.\r\nEncrypt and decrypt data using AES.\r\nMulti-threaded operations.\r\nBased on this, the stealer can probably harvest a lot of information from the victim’s windows machine. Let us dive deeper\r\nand see what all it intends to take.\r\nCode Analysis\r\nWe don’t have the full python code but we do have full python bytecode to augment our analysis albeit with some pain. First\r\nlet us look at some collection functions or methods as the entire thing is in form of a class.\r\nData Collection\r\nhttps://geekypandatales.wordpress.com/2023/02/19/the-infostealer-pie-python-malware-analysis/\r\nPage 6 of 15\n\nFirst one to look into is “get_data_browser” fairly self explanatory. We can see a list of browsers it is going to target but\r\nsadly beyond this point decompiled code is not available and we will have to resort to the disassembled code.\r\nUp until instruction 42 it seems to store the browser values in a dictionary called “browsers” and then loads it. Instructions\r\n44 onward deal with iteration so probably something like “for browser in browsers” along with invoking method\r\n“get_all_profile” for each browser.\r\nhttps://geekypandatales.wordpress.com/2023/02/19/the-infostealer-pie-python-malware-analysis/\r\nPage 7 of 15\n\nHere we see it opening “Local State” file which is a json file containing all profiles under the key “profile.info_chache”. Let\r\nus look at the disassembled code.\r\nhttps://geekypandatales.wordpress.com/2023/02/19/the-infostealer-pie-python-malware-analysis/\r\nPage 8 of 15\n\nIn the constants listing we see reference to profile and info_cache. Also based on the disassembled code we can infer it is\r\niterating over all available profiles and extracting passwords, credit card information and cookies saved in browser. If\r\nsuccessful, it would allow the attacker to gain unauthorized access to victim’s online accounts as well as credit card balance.\r\nhttps://geekypandatales.wordpress.com/2023/02/19/the-infostealer-pie-python-malware-analysis/\r\nPage 9 of 15\n\nNext up is a function “get_master_key”. On analysis of the disassembled bytecode I feel it is better to present this function\r\nalong with the functions “decrypt_payload” \u0026 “generate_cipher”. Together these are used in other data collection functions\r\nsuch as “grabCreditCards”, “grabPassword” \u0026 “grabCookies”. It has multiple uses in multiple functions as described below.\r\nCredit Card Collection\r\nThe function “get_master_key” obtains the protected master key from “os_crypt.encrypted_key” and decrypts it using\r\n“CryptUnprotectData”. This master key is then used to decrypt stored credit card numbers as can be seen below. Luckily this\r\nfunction was decompiled completely.\r\nPassword Collection\r\nWe can see “get_master_key” returns a key here but for what purpose, we will have to find out in the disassembled code.\r\nFor password collection, the malware uses “decrypt_password” which in turn uses functions called “decrypt_payload” and\r\n“generate_cipher”. Also as can be seen above, it stores facebook passwords separate from others.\r\nhttps://geekypandatales.wordpress.com/2023/02/19/the-infostealer-pie-python-malware-analysis/\r\nPage 10 of 15\n\nThe above code takes IV and encrypted content (password it is attempting to steal) and a reference to an AES cipher using\nGCM Mode (from “generate_cipher”) then passes it onto “decrypt_payload” to decrypt the password, returning a decrypted\npassword to “grabPassword”.\nThis function segregates passwords into those of facebook accounts and those belonging to other accounts then stores them\nat “C:\\Users\\\\AppData\\Local\\Temp\\Venus_Stealer\\Venus++\\Facebook_Password.txt” \u0026 “C:\\Users\\\n\\AppData\\Local\\Temp\\Venus_Stealer\\Venus++\\NeedCheck_Password.txt” respectively.\nCookie Collection\nNext we focus on cookie collection because that aspect leads to a lot of functions and information gathering functions most\nof which are targeted at the victim’s facebook account. Since the code for this is too large to put screenshot of here, I will try\nto give just an overview of it.\nGets master key from get_master_key.\nCopies login db to “Loginvault.db” then connects to it.\nFor each cookie entry, it decryots the encrypted value using “decrypt_password”.\nPushes the decrypted cookie along with other values to “wire_cookie”.\n“wire_cookie” segregates these into general, facebook \u0026 non-facebook ones and writes to “C:\\Users\\\n\\AppData\\Local\\Temp\\Venus_Stealer\\Venus++\\_Cookies.txt”, “C:\\Users\\\nhttps://geekypandatales.wordpress.com/2023/02/19/the-infostealer-pie-python-malware-analysis/\nPage 11 of 15\n\n\u003cusername\u003e\\AppData\\Local\\Temp\\Venus_Stealer\\Venus++\\Facebook_Cookies.txt” \u0026 “C:\\Users\\\r\n\u003cusername\u003e\\AppData\\Local\\Temp\\Venus_Stealer\\Venus++\\NeedCheck_Cookie.txt” respectively.\r\nI will briefly go over a few more functions that make use of these cookies.\r\n“checkAds” : Extracts c_user and hands it to “checkAd” for further inspection.\r\n“checkAd” : Obtains Facebook account’s access token \u0026 anti-CSRF token. Using below mentioned functions it\r\nobtains more information about the victim’s account including payment information etc.\r\n“getListAccInfo” : Uses facebook’s graph api to get a lot of information about victim’s account. An interesting one is\r\nthat it uses “getCard” function to obtain payment card information stored with facebook for victim’s account.\r\n“getListFanPage” : Tries to get a list of all fan pages run by the account along with information on active ad\r\ncampaigns, number of fans etc.\r\n“getListBM” : Gathers information regarding business being managed (on facebook) by victim account, their\r\nextended credit etc.\r\n“getListGroup” : Obtains a list of all groups the victim is an administrator on along with number of members.\r\nScreenshot\r\nYes it takes a screenshot, just one, and saves it to “C:\\Users\\\r\n\u003cusername\u003e\\AppData\\Local\\Temp\\Venus_Stealer\\Screenshot.png”.\r\nSending Data\r\nNow that we have looked at what all data it gathers, let us look at some functions involved in sending the data to the\r\nmothership. The place to start here is “SendInfo” but it is hardly decompiled, so we’ll head into its disassembly.\r\nAs the bytecode is too long, I took a sideways screenshot. Hope this is readable.\r\nhttps://geekypandatales.wordpress.com/2023/02/19/the-infostealer-pie-python-malware-analysis/\r\nPage 12 of 15\n\nLooking at the code, It obtains location information of the victim based on their ip address using\r\nhttps://codewithnodejs.com/api/ip-and-location/ runs “checkAds” method discussed earlier. After clubbing the data (or a\r\nsegment of it) together it sends a post request to “https://script.google.com/macros/s/AKfycbyK_TfquP0SswaY2iA25T-C4ASRt5hFQvu4414VpmoCeXu82WwnpxptTU0puZ63GEvC/exec” using function “CheckInfo”.\r\nIt then seems to prepare a url for an api request to send above mentioned data in a zipped format to a telegram bot at URL\r\n“https://api.telegram.org/bot6161058135:AAFtQgRfFX7WgLcyG-35LjuF8LjZVZLJXZA/sendDocument” . Here it\r\nalso makes a reference to a telegram chat id “-840681657“, It seems to be a group chat ID but I did not go down that rabbit\r\nhole due to time constraints.\r\nFollowing this it uses “sendAccountFolow” to send some information shown below to a google script\r\n“https://script.google.com/macros/s/AKfycbxnNWjH1seal8lc5iWP5ocqq1jXO9jp_F6Vbik8fvc6bJ_CHHBBOUEDyhgCBmqRjo-n/exec\u0026#8221;\r\nFollowing this it uses “sendCreditCard” method to send information shown below to google script\r\n“https://script.google.com/macros/s/AKfycbydBG0i5mU39PJqbsIzKaRFqf1NWxG6pvgb0h_2U0S_T2UKQcKBYW3JvnEgd9BPQ7\r\nhttps://geekypandatales.wordpress.com/2023/02/19/the-infostealer-pie-python-malware-analysis/\r\nPage 13 of 15\n\nWith this ends the analysis of Venus Stealer’s python side of things.\r\nSummary\r\nThis section summarizes the findings of the analysis above, as I have not dug into the PE File itself and the corresponding\r\nassembly this might not contain all the indicators. It also may not enlist all capabilities. All that was seen in the extracted\r\npython code/bytecode is here nothing else.\r\nCapabilities:\r\nExtract user information (stored passwords, stored cookies \u0026 stored credit cards) from a subset of browsers.\r\nGather information from the victim’s facebook account using facebook’s graph api and other endpoints.\r\nFrom victim’s facebook account it tries to identify if it is a business account, if it has ad campaigns sunning, payment\r\nmethods, fan pages administered etc.\r\nExfiltrate the collected information via telegram and google scripts.\r\nTelegram related Information:\r\nTelegram id: https://t.me/kaiwi9z\r\nTelegram Bot Identifier: https://api.telegram.org/bot6161058135:AAFtQgRfFX7WgLcyG-35LjuF8LjZVZLJXZA\r\nTelegram Bot exfil URL: https://api.telegram.org/bot6161058135:AAFtQgRfFX7WgLcyG-35LjuF8LjZVZLJXZA/sendDocument\r\nGoogle Scripts:\r\nhttps://script.google.com/macros/s/AKfycbyK_TfquP0SswaY2iA25T-C4ASRt5hFQvu4414VpmoCeXu82WwnpxptTU0puZ63GEvC/exec\r\nAccount Information sent to:\r\nhttps://script.google.com/macros/s/AKfycbxnNWjH1seal8lc5iWP5ocqq1jXO9jp_F6Vbik8fvc6bJ_CHHBBOUEDyhgCBmqRjo-n/exec\r\nCredit Card Information sent to:\r\nhttps://script.google.com/macros/s/AKfycbydBG0i5mU39PJqbsIzKaRFqf1NWxG6pvgb0h_2U0S_T2UKQcKBYW3JvnEgd9BPQ7\r\nUPDATES\r\nUpdate 1 : Data storage and automated data handling using Google App Script \u0026 google sheet.\r\nDISCLAIMER : I don’t actually know how google app scripts used in this malware actually work so this isn’t an exact\r\ndescription or analysis of the same, i was just curious on how it could be done. That lead to this, the information presented in\r\nthis article is purely for educational purposes and any use of the same in any form of activities is your own responsibility. I\r\nwill not be responsible for the same.\r\nTo use google app scripts and google sheets for processing and storing data received from the web (any device capable of\r\nsending a post request over internet) is actually pretty simple. Below is the process:\r\nhttps://geekypandatales.wordpress.com/2023/02/19/the-infostealer-pie-python-malware-analysis/\r\nPage 14 of 15\n\n1. Create a google sheet, named for e.g. test_sheet.\r\n2. Go to Extensions \u003e App Scripts\r\n3. Modify the empty function to receive json input and after desired processing add to the sheet.\r\n4. Now deploy it as a web app and save the web app url which should be something like:\r\nhttps://script.google.com/macros/s/\u003cYOUR DEPLOYMENT ID\u003e/exec\r\nTo test the same, you can send a post request with a body type set as json and data in the body just like the case in this\r\nmalware. I have tested this and it works even on a free google account.\r\nFrom the malware perspective all they will need to do is send a post request to their relevant URL which should not be\r\ninspected too much (unless the blue teams have considered this possibility) since it is going to google.\r\nSource: https://geekypandatales.wordpress.com/2023/02/19/the-infostealer-pie-python-malware-analysis/\r\nhttps://geekypandatales.wordpress.com/2023/02/19/the-infostealer-pie-python-malware-analysis/\r\nPage 15 of 15",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://geekypandatales.wordpress.com/2023/02/19/the-infostealer-pie-python-malware-analysis/"
	],
	"report_names": [
		"the-infostealer-pie-python-malware-analysis"
	],
	"threat_actors": [],
	"ts_created_at": 1775434938,
	"ts_updated_at": 1775791199,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/419a4bd890aa3edad0195be8a1e7510063dda8e3.pdf",
		"text": "https://archive.orkl.eu/419a4bd890aa3edad0195be8a1e7510063dda8e3.txt",
		"img": "https://archive.orkl.eu/419a4bd890aa3edad0195be8a1e7510063dda8e3.jpg"
	}
}