{
	"id": "fc8d24eb-19aa-4dc9-860a-71687203e461",
	"created_at": "2026-04-06T01:31:52.199511Z",
	"updated_at": "2026-04-10T13:11:45.568719Z",
	"deleted_at": null,
	"sha1_hash": "0705b2049572913046d0183a53c13008463c6612",
	"title": "Dynamic Binary Instrumentation for Malware Analysis",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 506820,
	"plain_text": "Dynamic Binary Instrumentation for Malware Analysis\r\nBy map[name:Alessandro Strino]\r\nPublished: 2023-03-14 · Archived: 2026-04-06 00:08:46 UTC\r\nIntroduction\r\nBecause of the massive Ursnif campaigns that hit Italy during the last weeks, I was looking for a lightweight\r\nmethod to quickly extract the last infection stage of all collected samples, in order to start further analysis\r\neffectively. Due to this, I wrote a little frida script that performs basic Dynamic Binary Instrumentation (DBI) to\r\nmonitor useful function calls and extracts the Ursnif payload. In this article I am going to briefly discuss this script\r\nand the steps needed to start analyzing the resulting binary.\r\nSince I would like to skip redundant topics that are already written all over the internet by people that are Jedi in\r\nthis field, I’m going to limit this post linking references that would be nice to have to understand everything\r\neasily.\r\nFrida\r\nWindows API\r\nUrsnif/Gozi\r\nIntercepting function calls\r\nMost of the time, malware, in order to write memory and run code from the newly allocated space, make use of\r\ntwo functions, such as: VirtualAlloc (ref.) and VirtualProtect (ref.). For the purpose of our task, I have chosen\r\nthe VirtualProtect function, because at the time of its calling, the data (payload) should be already there and it\r\nwould be easier to analyze.\r\nSo let’s start to write out the code that retrieves the reference of this function and the interceptor that is going to\r\nbe used to monitor function calls entry and return. Thanks to Frida, it is possible to directly retrieve function\r\narguments through the variable args and check their values. The most important parameter and the one that will be\r\nused for our purpose is the lpAddress that represents the address space that is involved in this function call.\r\nFigure 1 - References to VirtualProtect and call Interceptor\r\nhttps://viuleeenz.github.io/posts/2023/03/dynamic-binary-instrumentation-for-malware-analysis/\r\nPage 1 of 4\n\nBecause of the purpose of the article we are not interested in all VirtualProtect calls but we would like to limit\r\nour scope to ones that contain a PE header.  To do this, it’s possible to verify if lpAddress starts with “MZ” or\r\n“5d4a”. If so, we could print out some values in order to check them against the running executable using tools\r\nsuch as ProcessMonitor or ProcessHacker.\r\nFigure 2 - Printing VirtualProtect arguments\r\nRetrieving the payload\r\nNow comes the tricky part. If we simply apply this technique to dump the memory that contains the MZ, it would\r\nbe possible for us to also dump the binary that we originally started the infection with. However, analyzing Ursnif\r\ncode, it’s possible to see that it creates a dedicated memory space to write its final stage that is commonly\r\nreferenced as a DLL. In order to avoid that, it’s possible to use a function findModuleByAddress that belongs to\r\nthe Process object.\r\nAs reported by Frida documentation:\r\nProcess.findModuleByAddress(address) returns a Module whose address or name matches the one\r\nspecified. In the event that no such module could be found, the find-prefixed functions return null whilst\r\nthe get-prefixed functions throw an exception.\r\nIn order to avoid exception handling stuff I have preferred to go with find prefix function and then checking if the\r\nModule returned is equal to null. Otherwise, we would have an existing module object and  module.base = image\r\nbase.\r\nNow, as a final step before moving on and dumping the actual payload, it’s necessary to retrieve the page size to\r\nwhich  lpAddress belongs. That information could be retrieved using the findRangeByAddress that  return an\r\nobject with details about the range (memory page) containing address.\r\nFigure 3 - Checking for payload address\r\nDumping config file\r\nhttps://viuleeenz.github.io/posts/2023/03/dynamic-binary-instrumentation-for-malware-analysis/\r\nPage 2 of 4\n\nNow that we have all the information required, it’s time to dump the actual Ursnif payload. In order to do this, it’s\r\npossible to read the page related to lpAddress using the readByteArray using the module.size. Once the\r\ninformation has been stored, it’s possible to write it in a file that could be used later on for further manipulation\r\nand analysis.\r\nFigure 4 - Dumping Ursnif payload\r\nIt’s worth noting that before proceeding with the configuration extraction phase, it’s necessary to modify Raw\r\naddresses and Virtual Addresses of each section  header accordingly. This step is necessary because the\r\npayload was extracted directly from memory.\r\nScript Testing\r\nNow that we have completed our script it’s time for testing with a real case! Let’s take one of the recent samples\r\ndelivered by the TA and see if it works. For this example I have chosen a publicly available sample on\r\nMalwareBazar.\r\nRunning the script against this sample with Frida as follow:\r\nfrida.exe \u003cmal_executable\u003e -l \u003cyour_script.js\u003e\r\nIt will produce a file called 0x2cf0000_mz.bin (it may vary from the memory address allocation on your\r\nmachine).\r\nhttps://viuleeenz.github.io/posts/2023/03/dynamic-binary-instrumentation-for-malware-analysis/\r\nPage 3 of 4\n\nFigure 5 - Ursnif payload extraction with Frida\r\nIf we open this file with PE-Bear, what should alert us, is the import table that contains unresolved information.\r\nThis happens, because our code has been extracted directly from memory and before proceeding with our analysis\r\nit is necessary to map the raw sections addresses with their virtual counterparts (for brevity I have prepared a\r\nscript that is going to perform these steps automatically). After having settled the addresses properly, it’s possible\r\nto proceed with configuration extraction through a custom script (that is out of the scope for this post).\r\nReference\r\nDBI script: mon.py\r\nSource: https://viuleeenz.github.io/posts/2023/03/dynamic-binary-instrumentation-for-malware-analysis/\r\nhttps://viuleeenz.github.io/posts/2023/03/dynamic-binary-instrumentation-for-malware-analysis/\r\nPage 4 of 4",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"origins": [
		"web"
	],
	"references": [
		"https://viuleeenz.github.io/posts/2023/03/dynamic-binary-instrumentation-for-malware-analysis/"
	],
	"report_names": [
		"dynamic-binary-instrumentation-for-malware-analysis"
	],
	"threat_actors": [],
	"ts_created_at": 1775439112,
	"ts_updated_at": 1775826705,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/0705b2049572913046d0183a53c13008463c6612.pdf",
		"text": "https://archive.orkl.eu/0705b2049572913046d0183a53c13008463c6612.txt",
		"img": "https://archive.orkl.eu/0705b2049572913046d0183a53c13008463c6612.jpg"
	}
}