{
	"id": "58ba9a1e-4e94-44bd-a189-c5ddcee2bc32",
	"created_at": "2026-04-29T02:21:14.823074Z",
	"updated_at": "2026-04-29T08:22:55.623487Z",
	"deleted_at": null,
	"sha1_hash": "fd03457059e72612eec6b3b63bdc38e3e2bc88ed",
	"title": "HInvoke and avoiding PInvoke",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 47518,
	"plain_text": "HInvoke and avoiding PInvoke\r\nPublished: 2022-08-10 · Archived: 2026-04-29 02:08:25 UTC\r\nA very minimalistic approach of calling .net runtime functions or accessing properties using only hashes as identifiers. It\r\ndoes not leave any strings or import references since we dynamically resolve the required member from the mscorlib\r\nassembly on runtime.\r\nHow does HInvoke work?\r\nIts fairly simple, iterate trough all Types of mscorlib and hash their names using some hashing function. Upon finding the\r\nmatching type continue by iterating trough all its methods or properties and do the same hashing routine as before. Finish by\r\neither invoking the resolved method and if applicable return its returnvalue or return the value of the resolved property. This\r\nwhole process has one fairly big limitation it can only find methods that have a unique name, as the current implementation\r\nis fairly lazy and does not take parameter count or types into account.\r\n1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\n9\r\n10\r\n11\r\n12\r\n13\r\n14\r\n15\r\n16\r\n17\r\n18\r\n public static T InvokeMethod\u003cT\u003e(uint classID, uint methodID, object[]? args = null)\r\n {\r\n // Get the System assembly and go trough all its types hash their name\r\n // and find the hash that matches the supplied one\r\n var typeDef = typeof(void).Assembly.GetTypes()\r\n .FirstOrDefault(type =\u003e GetHash(type.FullName!) == classID);\r\n // Use the type and go trough its methods hash their name\r\n // and find the hash that matches the supplied one\r\n var methodInfo = typeDef.GetRuntimeMethods()\r\n .FirstOrDefault(method =\u003e GetHash(method.Name) == methodID);\r\n // Invoke the resolved method with the supplied args\r\n if (methodInfo != null)\r\n return (T) methodInfo.Invoke(null, args);\r\n return default!;\r\n }\r\nCalls using HInvoke look like this\r\n1\r\n2\r\n if (HInvoke.GetPropertyValue\u003cbool\u003e(1577037771, 179842977)) // System.Diagnostics.Debugger.IsAttac\r\n HInvoke.InvokeMethod(1174404872, 2029614223, new object[] {0}); // System.Environment.Exit(0)\r\nThe HInvoke call requires the two before mentioned hashes, and additionally parameters for the method being called. The\r\nexample is a common anti debug measure in .net obfuscators, only that this version does not expose the actual call on first\r\nglance. It checks the value of Debugger.IsAttached in case its true it calls Environment.Exit with parameter 0, closing\r\nthe program.\r\nhttps://dr4k0nia.github.io/posts/HInvoke-and-avoiding-PInvoke/\r\nPage 1 of 2\n\nSo in short: We can call every uniquely named method from the .net runtime using only 2 hashes.\r\nAvoiding Pinvoke\r\nAnother idea I got while browsing trough the internal parts of the managed .net runtime. There is a class called\r\nMicrosoft.Win32.Win32Native which contains you guessed it managed wrappers for native functions. Since Microsoft\r\nalready so kindly provides these wrappers it would be a waste to not use them.\r\nThere were 2 functions that I found especially interesting: GetModuleHandle and GetProcAddress . By invoking them we\r\ncan without any usage of PInvoke in our binary get the address of any unmanaged function. Also by using the delegate\r\npointer type ( delegate* ) we can easily invoke the resolved unmanaged functions.\r\n1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\n9\r\n var module =\r\n HInvoke.InvokeMethod\u003cIntPtr\u003e(13239936, 811580934,\r\n new object[] {\"kernel32.dll\"}); // Microsoft.Win32.Win32Native.GetModuleHandle\r\n var address =\r\n HInvoke.InvokeMethod\u003cIntPtr\u003e(13239936, 1721745356,\r\n new object[] {module, \"IsDebuggerPresent\"}); // Microsoft.Win32.Win32Native.GetProcAddres\r\n if (((delegate* unmanaged[Stdcall]\u003cbool\u003e) address)())\r\n Console.WriteLine(\"Hey meanie I said no debugging :c\");\r\nThe example shows a combination of using the Win32Native class and HInvoke to resolve the address of\r\nkernel32!IsDebuggerPresent . After it casts a delegate pointer with the unmanaged attribute, the calling convention and the\r\nreturntype on the resolved address. Then calls it.\r\nYou can find the full example code here\r\nThis is a rather short post but hopefully interesting to some. For feedback or questions contact me on Twitter or Discord.\r\nThis post is licensed under CC BY 4.0 by the author.\r\nSource: https://dr4k0nia.github.io/posts/HInvoke-and-avoiding-PInvoke/\r\nhttps://dr4k0nia.github.io/posts/HInvoke-and-avoiding-PInvoke/\r\nPage 2 of 2",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"MITRE"
	],
	"origins": [
		"web"
	],
	"references": [
		"https://dr4k0nia.github.io/posts/HInvoke-and-avoiding-PInvoke/"
	],
	"report_names": [
		"HInvoke-and-avoiding-PInvoke"
	],
	"threat_actors": [],
	"ts_created_at": 1777429274,
	"ts_updated_at": 1777450975,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/fd03457059e72612eec6b3b63bdc38e3e2bc88ed.pdf",
		"text": "https://archive.orkl.eu/fd03457059e72612eec6b3b63bdc38e3e2bc88ed.txt",
		"img": "https://archive.orkl.eu/fd03457059e72612eec6b3b63bdc38e3e2bc88ed.jpg"
	}
}