[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fFgpYb3Weor_YJdnPK8vyv8fe_JzHzf6bY1deLuyNQkk":3},{"id":4,"question":5,"answer":6,"answerHtml":7,"slug":8,"keywords":9,"article":10,"status":34,"aiModel":39,"aiConfidence":39,"updatedAt":51,"createdAt":51,"_status":50},923,"What technique does the execute-assembly approach use to avoid static detection of the Seatbelt binary?","The execute-assembly method XORs every byte of Seatbelt.exe with a key (e.g., 0x01) before storing it in a C++ array. At runtime, the loader reverses the XOR operation to restore the original binary in memory before loading the .NET assembly via `Load_3(...)`. This obfuscation hides the Seatbelt signature from static analysis. The full implementation, including XOR handling and parameter passing, is detailed in the [Implementation of In-Memory Loading for Seatbelt](\u002Fnews\u002Fimplementation-of-in-memory-loading-for-seatbelt) article.","\u003Cp>The execute-assembly method XORs every byte of Seatbelt.exe with a key (e.g., 0x01) before storing it in a C++ array. At runtime, the loader reverses the XOR operation to restore the original binary in memory before loading the .NET assembly via `Load_3(...)`. This obfuscation hides the Seatbelt signature from static analysis. The full implementation, including XOR handling and parameter passing, is detailed in the [Implementation of In-Memory Loading for Seatbelt](\u002Fnews\u002Fimplementation-of-in-memory-loading-for-seatbelt) article.\u003C\u002Fp>\u003Cp>\u003Ca href=\"\u002Fnews\u002Fimplementation-of-in-memory-loading-for-seatbelt\">Read the related One Day Sec article\u003C\u002Fa>\u003C\u002Fp>","what-technique-does-the-execute-assembly-approach-use-to-avoid-static-detection--1777481344396","XOR obfuscation, execute-assembly, static evasion, HostingCLR, .NET assembly loading",{"id":11,"title":12,"slug":13,"description":14,"content":15,"contentHtml":30,"cover":31,"author":32,"views":19,"readingTime":33,"status":34,"publishedAt":35,"seo":36,"tags":41,"qaPairs":42,"meta":47,"updatedAt":48,"createdAt":49,"_status":50},224,"Implementation of In-Memory Loading for Seatbelt","implementation-of-in-memory-loading-for-seatbelt","Learn to load Seatbelt in memory using Assembly.Load and execute-assembly methods for security checks without modifying code. Includes parameter passing and compilation steps.",{"root":16},{"type":17,"format":18,"indent":19,"version":20,"children":21,"direction":29},"root","",0,1,[22],{"type":23,"format":18,"indent":19,"version":20,"children":24,"direction":29},"paragraph",[25],{"mode":26,"text":27,"type":28,"style":18,"detail":19,"format":19,"version":20},"normal","\u003Chtml>\u003Chead>\u003C\u002Fhead>\u003Cbody>\u003Ch2>0x00 Preface\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>Seatbelt is a C# project that can be used for security checks on hosts, serving both offensive and defensive purposes.\u003C\u002Fp>\u003Cp>With a single command, it can retrieve multiple configuration details of the current host, making it convenient and practical.\u003C\u002Fp>\u003Cp>To expand the usage scenarios of Seatbelt without modifying any of its code, this article will introduce two methods for loading Seatbelt in memory (Assembly.Load and execute-assembly), completing the implementation code for passing parameters to the Main function of .NET assemblies.\u003C\u002Fp>\u003Cp>Previous articles \"Exploitation Analysis of Loading .NET Assemblies from Memory (Assembly.Load)\" and \"Exploitation Analysis of Loading .NET Assemblies from Memory (execute-assembly)\"\u003C\u002Fp>\u003Cp>only covered the implementation code for passing parameters to methods of specified classes.\u003C\u002Fp>\u003Ch2>0x01 Introduction\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>This article will cover the following topics:\u003C\u002Fp>\u003Cul>\u003Cli>Compilation and usage of Seatbelt\u003C\u002Fli>\u003Cli>Method for loading Seatbelt using Assembly.Load and passing parameters\u003C\u002Fli>\u003Cli>Method for loading Seatbelt using execute-assembly and passing parameters\u003C\u002Fli>\u003Cli>Method for using assembly code in Visual Studio 2015 on 64-bit platforms\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>0x02 Compilation and Usage of Seatbelt\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Ch3>1. Compilation\u003C\u002Fh3>\u003Cp>Project Repository:\u003C\u002Fp>\u003Cp>https:\u002F\u002Fgithub.com\u002FGhostPack\u002FSeatbelt\u003C\u002Fp>\u003Cp>Supports .NET 3.5 and 4.0\u003C\u002Fp>\u003Cp>Requires Visual Studio 2017 or higher for compilation\u003C\u002Fp>\u003Ch3>2. Usage\u003C\u002Fh3>\u003Cp>Requires passing parameters to specify specific commands, for example, to run all checks and return all output:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>Seatbelt.exe -group=all -full\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Detailed commands can be referenced in the project documentation:\u003C\u002Fp>\u003Cp>https:\u002F\u002Fgithub.com\u002FGhostPack\u002FSeatbelt#command-line-usage\u003C\u002Fp>\u003Ch2>0x03 Method for Loading Seatbelt and Passing Parameters Using Assembly.Load\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>Implementation Language: C#\u003C\u002Fp>\u003Cp>Implementation approach:\u003C\u002Fp>\u003Cp>Encode Seatbelt.exe as base64 and store it in an array, then use Assembly.Load() for base64 decoding and loading, finally pass parameters to the Main function\u003C\u002Fp>\u003Cp>Implementation code:\u003C\u002Fp>\u003Ch4>1. Encode Seatbelt.exe as base64 and return the result\u003C\u002Fh4>\u003Cp>C# implementation code:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>using System;\u003Cbr>using System.Reflection;\u003Cbr>namespace TestApplication\u003Cbr>{\u003Cbr>    public class Program\u003Cbr>    {\u003Cbr>        public static void Main()\u003Cbr>        {\u003Cbr>\u003Cbr>            byte[] buffer = System.IO.File.ReadAllBytes(\"Seatbelt.exe\");\u003Cbr>            string base64str = Convert.ToBase64String(buffer);\u003Cbr>            Console.WriteLine(base64str);\u003Cbr>        }\u003Cbr>    }\u003Cbr>}\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>You can compile using Visual Studio or directly using csc.exe\u003C\u002Fp>\u003Cp>Command to compile with csc.exe under .Net 3.5:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>C:\\Windows\\Microsoft.NET\\Framework64\\v3.5\\csc.exe base64.cs\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Command to compile with csc.exe under .Net 4.0:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>C:\\Windows\\Microsoft.NET\\Framework64\\v4.0.30319\\csc.exe base64.cs\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>After successful compilation, base64.exe is generated. Executing it produces the base64-encoded string of Seatbelt.exe\u003C\u002Fp>\u003Ch4>2. Use Assembly.Load() for base64 decoding and loading, then pass parameters to the Main function\u003C\u002Fh4>\u003Cp>C# implementation code:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>using System;\u003Cbr>using System.Reflection;\u003Cbr>namespace TestApplication\u003Cbr>{\u003Cbr>    public class Program\u003Cbr>    {\u003Cbr>        public static void Main(string[] args)\u003Cbr>        {\u003Cbr>\u003Cbr>            string base64str = \"\u003Cbase64 string=\"\">\";\u003Cbr>\u003Cbr>            byte[] buffer = Convert.FromBase64String(base64str);\u003Cbr>            object[] commands = args;\u003Cbr>            Assembly assembly = Assembly.Load(buffer);\u003Cbr>            try\u003Cbr>            {\u003Cbr>                assembly.EntryPoint.Invoke(null, new object[] { commands });\u003Cbr>            }\u003Cbr>            catch\u003Cbr>    {\u003Cbr>                MethodInfo method = assembly.EntryPoint;\u003Cbr>                if (method != null)\u003Cbr>                {\u003Cbr>                    object o = assembly.CreateInstance(method.Name);                    \u003Cbr>                    method.Invoke(o, null);\u003Cbr>                }\u003Cbr>            }\u003Cbr>        }\u003Cbr>    }\u003Cbr>}\u003C\u002Fbase64>\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Replace \u003Cbase64 string=\"\"> in the above code with the base64-encoded string of Seatbelt.exe\u003C\u002Fbase64>\u003C\u002Fp>\u003Cp>Similarly, the above code can be compiled using Visual Studio or directly with csc.exe\u003C\u002Fp>\u003Ch2>0x04 Method for loading Seatbelt and passing parameters using execute-assembly\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>Implementation language: C++\u003C\u002Fp>\u003Cp>Implementation approach:\u003C\u002Fp>\u003Cp>Save the content of Seatbelt.exe in an array, then use Load_3(...) to load the .NET assembly after reading, and finally pass parameters to the Main function\u003C\u002Fp>\u003Cp>To remove the signature of Seatbelt.exe, each character in Seatbelt.exe can be XORed and then saved to the array\u003C\u002Fp>\u003Cp>Here, HostingCLR is used as the code development template\u003C\u002Fp>\u003Cp>The code of HostingCLR does not solve the parameter passing issue and cannot pass parameters to the Main function of the .NET assembly. Code location:\u003C\u002Fp>\u003Cp>https:\u002F\u002Fgithub.com\u002Fetormadiv\u002FHostingCLR\u002Fblob\u002Fmaster\u002FHostingCLR\u002FHostingCLR.cpp#L218\u003C\u002Fp>\u003Cp>My code solves the parameter passing issue and removes the signature of Seatbelt.exe by XORing each character in Seatbelt.exe and then saving it to the array\u003C\u002Fp>\u003Cp>Implementation code:\u003C\u002Fp>\u003Ch4>1. XOR each character in the exe file and save it as a new file\u003C\u002Fh4>\u003Cp>C++ implementation code:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>int main(int argc, char* argv[])\u003Cbr>{\u003Cbr>\tif (argc != 3)\u003Cbr>\t{\u003Cbr>\t\tprintf(\"File_XOR_generator\\n\");\u003Cbr>\t\tprintf(\"Usage:\\n\");\u003Cbr>\t\tprintf(\"%s \u003Cfile path=\"\"> \u003Cxor inputs=\"\">\\n\", argv[0]);\u003Cbr>\t\tprintf(\"Eg:\\n\");\u003Cbr>\t\tprintf(\"%s test.exe 0x01\\n\", argv[0]);\u003Cbr>\u003Cbr>\t\treturn 0;\u003Cbr>\t}\u003Cbr>\u003Cbr>\tint x;\u003Cbr>\tsscanf_s(argv[2], \"%x\", &amp;x);\u003Cbr>\u003Cbr>\tFILE* fp;\u003Cbr>\tint err = fopen_s(&amp;fp, argv[1], \"ab+\");\u003Cbr>\tif (err != 0)\u003Cbr>\t{\u003Cbr>\t\tprintf(\"\\n[!]Open file error\");\u003Cbr>\t\treturn 0;\u003Cbr>\t}\u003Cbr>\tfseek(fp, 0, SEEK_END);\u003Cbr>\tint len = ftell(fp);\u003Cbr>\tunsigned char *buf = new unsigned char[len];\u003Cbr>\tfseek(fp, 0, SEEK_SET);\u003Cbr>\tfread(buf, len, 1, fp);\u003Cbr>\tfclose(fp);\u003Cbr>\tprintf(\"[*] file name:%s\\n\", argv[1]);\u003Cbr>\tprintf(\"[*] file size:%d\\n\", len);\u003Cbr>\u003Cbr>\tfor (int i = 0; i &lt; len; i++)\u003Cbr>\t{\u003Cbr>\t\tbuf[i] = buf[i] ^ x;\u003Cbr>\t}\u003Cbr>\tchar strNew[256] = {0};\u003Cbr>\tsnprintf(strNew, 256, \"xor_%s\", argv[1]);\u003Cbr>\u003Cbr>\tFILE* fp2;\u003Cbr>\terr = fopen_s(&amp;fp2, strNew, \"wb+\");\u003Cbr>\tif (err != 0)\u003Cbr>\t{\u003Cbr>\t\tprintf(\"\\n[!]createfile error!\");\u003Cbr>\t\treturn 0;\u003Cbr>\t}\u003Cbr>\tfwrite(buf, len, 1, fp2);\u003Cbr>\tfclose(fp2);\t\u003Cbr>\tprintf(\"[*] XOR file name:%s\\n\", strNew);\u003Cbr>\tprintf(\"[*] XOR file size:%d\\n\", len);\u003Cbr>}\u003C\u002Fxor>\u003C\u002Ffile>\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Here, each character in Seatbelt.exe is XORed with 0x01. The command line parameters are as follows:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>File_XOR_generator.exe Seatbelt.exe 0x01\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Generate the file xor_Seatbelt.exe\u003C\u002Fp>\u003Cp>Open xor_Seatbelt.exe using HxD\u003C\u002Fp>\u003Cp>Copy the file content into C code format, as shown in the figure below\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fuploads\u002Fdocx_image_1770017279789_0_4559a5f5bc.jpeg\">\u003C\u002Fp>\u003Ch4>2. Use Load_3(...) to load the .NET assembly, and finally pass parameters to the Main function\u003C\u002Fh4>\u003Cp>The complete code has been uploaded to GitHub, address as follows:\u003C\u002Fp>\u003Cp>An open-source project\u003C\u002Fp>\u003Cp>When using, modify the following locations in the code:\u003C\u002Fp>\u003Cul>\u003Cli>Replace the content in the array rawData\u003C\u002Fli>\u003Cli>Define the path for mscorlibPath\u003C\u002Fli>\u003Cli>Define the version for runtimeVersion\u003C\u002Fli>\u003C\u002Ful>\u003Cp>The code will perform XOR operation character by character on the content in the array rawData with 0x01, restore the file content of Seatbelt.exe, then load it and pass parameters to the Main function\u003C\u002Fp>\u003Cp>After compilation, generate the file HostingCLR_with_arguments_XOR.exe, test command example:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>HostingCLR_with_arguments_XOR.exe -group=all\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Use Process Explorer to view the .NET Assemblies item of the process HostingCLR_with_arguments_XOR.exe, as shown in the figure below\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fuploads\u002Fdocx_image_1770017308918_1_1d4c157455.jpeg\">\u003C\u002Fp>\u003Cp>Can obtain the name of the .NET assembly\u003C\u002Fp>\u003Cp>If you want to hide the name of a .NET assembly, you need to bypass ETW detection.\u003C\u002Fp>\u003Ch4>3. Bypassing ETW detection\u003C\u002Fh4>\u003Cp>Refer to the code at https:\u002F\u002Fgithub.com\u002Foutflanknl\u002FTamperETW\u002F\u003C\u002Fp>\u003Cp>Introduce the code for bypassing ETW from there; the code has been uploaded to GitHub at the following address:\u003C\u002Fp>\u003Cp>An open-source project\u003C\u002Fp>\u003Cp>Here, you also need to add the asm file Syscalls.asm to implement calls to the assembly file.\u003C\u002Fp>\u003Cp>Create a new item, select a C++ file, enter the file name Syscalls.asm, with the specific content as follows:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>.code\u003Cbr>\u003Cbr>; Reference: https:\u002F\u002Fj00ru.vexillium.org\u002Fsyscalls\u002Fnt\u002F64\u002F\u003Cbr>\u003Cbr>; Windows 7 SP1 \u002F Server 2008 R2 specific syscalls\u003Cbr>\u003Cbr>ZwProtectVirtualMemory7SP1 proc\u003Cbr>\t\tmov r10, rcx\u003Cbr>\t\tmov eax, 4Dh\u003Cbr>\t\tsyscall\u003Cbr>\t\tret\u003Cbr>ZwProtectVirtualMemory7SP1 endp\u003Cbr>\u003Cbr>ZwWriteVirtualMemory7SP1 proc\u003Cbr>\t\tmov r10, rcx\u003Cbr>\t\tmov eax, 37h\u003Cbr>\t\tsyscall\u003Cbr>\t\tret\u003Cbr>ZwWriteVirtualMemory7SP1 endp\u003Cbr>\u003Cbr>ZwReadVirtualMemory7SP1 proc\u003Cbr>\t\tmov r10, rcx\u003Cbr>\t\tmov eax, 3Ch\u003Cbr>\t\tsyscall\u003Cbr>\t\tret\u003Cbr>ZwReadVirtualMemory7SP1 endp\u003Cbr>\u003Cbr>; Windows 8 \u002F Server 2012 specific syscalls\u003Cbr>\u003Cbr>ZwProtectVirtualMemory80 proc\u003Cbr>\t\tmov r10, rcx\u003Cbr>\t\tmov eax, 4Eh\u003Cbr>\t\tsyscall\u003Cbr>\t\tret\u003Cbr>ZwProtectVirtualMemory80 endp\u003Cbr>\u003Cbr>ZwWriteVirtualMemory80 proc\u003Cbr>\t\tmov r10, rcx\u003Cbr>\t\tmov eax, 38h\u003Cbr>\t\tsyscall\u003Cbr>\t\tret\u003Cbr>ZwWriteVirtualMemory80 endp\u003Cbr>\u003Cbr>ZwReadVirtualMemory80 proc\u003Cbr>\t\tmov r10, rcx\u003Cbr>\t\tmov eax, 3Dh\u003Cbr>\t\tsyscall\u003Cbr>\t\tret\u003Cbr>ZwReadVirtualMemory80 endp\u003Cbr>\u003Cbr>; Windows 8.1 \u002F Server 2012 R2 specific syscalls\u003Cbr>\u003Cbr>ZwProtectVirtualMemory81 proc\u003Cbr>\t\tmov r10, rcx\u003Cbr>\t\tmov eax, 4Fh\u003Cbr>\t\tsyscall\u003Cbr>\t\tret\u003Cbr>ZwProtectVirtualMemory81 endp\u003Cbr>\u003Cbr>ZwWriteVirtualMemory81 proc\u003Cbr>\t\tmov r10, rcx\u003Cbr>\t\tmov eax, 39h\u003Cbr>\t\tsyscall\u003Cbr>\t\tret\u003Cbr>ZwWriteVirtualMemory81 endp\u003Cbr>\u003Cbr>ZwReadVirtualMemory81 proc\u003Cbr>\t\tmov r10, rcx\u003Cbr>\t\tmov eax, 3Eh\u003Cbr>\t\tsyscall\u003Cbr>\t\tret\u003Cbr>ZwReadVirtualMemory81 endp\u003Cbr>\u003Cbr>; Windows 10 \u002F Server 2016 specific syscalls\u003Cbr> \u003Cbr>ZwProtectVirtualMemory10 proc\u003Cbr>\t\tmov r10, rcx\u003Cbr>\t\tmov eax, 50h\u003Cbr>\t\tsyscall\u003Cbr>\t\tret\u003Cbr>ZwProtectVirtualMemory10 endp\u003Cbr>\u003Cbr>ZwWriteVirtualMemory10 proc\u003Cbr>\t\tmov r10, rcx\u003Cbr>\t\tmov eax, 3Ah\u003Cbr>\t\tsyscall\u003Cbr>\t\tret\u003Cbr>ZwWriteVirtualMemory10 endp\u003Cbr>\u003Cbr>ZwReadVirtualMemory10 proc\u003Cbr>\t\tmov r10, rcx\u003Cbr>\t\tmov eax, 3Fh\u003Cbr>\t\tsyscall\u003Cbr>\t\tret\u003Cbr>ZwReadVirtualMemory10 endp\u003Cbr>\u003Cbr>end\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>\u003Cstrong>Note:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>The code for Syscalls.asm is from https:\u002F\u002Fgithub.com\u002Foutflanknl\u002FTamperETW\u002Fblob\u002Fmaster\u002FTamperETW\u002FUnmanagedCLR\u002FSyscalls.asm\u003C\u002Fp>\u003Cp>To use assembly code in Visual Studio 2015 on a 64-bit platform, the following settings are required:\u003C\u002Fp>\u003Cp>(1) Right-click on the project -&gt; Build Dependencies -&gt; Build Customizations, check masm\u003C\u002Fp>\u003Cp>As shown in the figure below\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fuploads\u002Fdocx_image_1770017338060_2_b67ddfab9e.jpeg\">\u003C\u002Fp>\u003Cp>(2) Right-click the file Syscalls.asm -&gt; Properties, set the Item Type to Microsoft Macro Assembler\u003C\u002Fp>\u003Cp>As shown in the figure below\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fuploads\u002Fdocx_image_1770017384417_3_e428fd5101.jpeg\">\u003C\u002Fp>\u003Cp>After compilation, the file HostingCLR_with_arguments_XOR_TamperETW.exe is generated\u003C\u002Fp>\u003Cp>Test command example:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>HostingCLR_with_arguments_XOR_TamperETW.exe -group=all\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Use Process Explorer to view the .NET Assemblies entry of the process HostingCLR_with_arguments_XOR_TamperETW.exe, as shown in the figure below\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fuploads\u002Fdocx_image_1770017407639_4_1975b7d286.jpeg\">\u003C\u002Fp>\u003Cp>Successfully hides the names of .NET assemblies\u003C\u002Fp>\u003Ch2>0x05 Summary\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>This article introduces two methods for loading Seatbelt in memory (Assembly.Load and execute-assembly), respectively completing the implementation code for passing parameters to the Main function of a .NET assembly. It addresses the parameter passing issue in HostingCLR, introduces code for TamperETW to bypass ETW, and explains the method of using assembly code in Visual Studio 2015 on a 64-bit platform.\u003C\u002Fp>\u003C\u002Fbody>\u003C\u002Fhtml>","text","ltr","\u003Chtml>\u003Chead>\u003C\u002Fhead>\u003Cbody>\u003Ch2>0x00 Preface\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>Seatbelt is a C# project that can be used for security checks on hosts, serving both offensive and defensive purposes.\u003C\u002Fp>\u003Cp>With a single command, it can retrieve multiple configuration details of the current host, making it convenient and practical.\u003C\u002Fp>\u003Cp>To expand the usage scenarios of Seatbelt without modifying any of its code, this article will introduce two methods for loading Seatbelt in memory (Assembly.Load and execute-assembly), completing the implementation code for passing parameters to the Main function of .NET assemblies.\u003C\u002Fp>\u003Cp>Previous articles \"Exploitation Analysis of Loading .NET Assemblies from Memory (Assembly.Load)\" and \"Exploitation Analysis of Loading .NET Assemblies from Memory (execute-assembly)\"\u003C\u002Fp>\u003Cp>only covered the implementation code for passing parameters to methods of specified classes.\u003C\u002Fp>\u003Ch2>0x01 Introduction\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>This article will cover the following topics:\u003C\u002Fp>\u003Cul>\u003Cli>Compilation and usage of Seatbelt\u003C\u002Fli>\u003Cli>Method for loading Seatbelt using Assembly.Load and passing parameters\u003C\u002Fli>\u003Cli>Method for loading Seatbelt using execute-assembly and passing parameters\u003C\u002Fli>\u003Cli>Method for using assembly code in Visual Studio 2015 on 64-bit platforms\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>0x02 Compilation and Usage of Seatbelt\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Ch3>1. Compilation\u003C\u002Fh3>\u003Cp>Project Repository:\u003C\u002Fp>\u003Cp>https:\u002F\u002Fgithub.com\u002FGhostPack\u002FSeatbelt\u003C\u002Fp>\u003Cp>Supports .NET 3.5 and 4.0\u003C\u002Fp>\u003Cp>Requires Visual Studio 2017 or higher for compilation\u003C\u002Fp>\u003Ch3>2. Usage\u003C\u002Fh3>\u003Cp>Requires passing parameters to specify specific commands, for example, to run all checks and return all output:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>Seatbelt.exe -group=all -full\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Detailed commands can be referenced in the project documentation:\u003C\u002Fp>\u003Cp>https:\u002F\u002Fgithub.com\u002FGhostPack\u002FSeatbelt#command-line-usage\u003C\u002Fp>\u003Ch2>0x03 Method for Loading Seatbelt and Passing Parameters Using Assembly.Load\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>Implementation Language: C#\u003C\u002Fp>\u003Cp>Implementation approach:\u003C\u002Fp>\u003Cp>Encode Seatbelt.exe as base64 and store it in an array, then use Assembly.Load() for base64 decoding and loading, finally pass parameters to the Main function\u003C\u002Fp>\u003Cp>Implementation code:\u003C\u002Fp>\u003Ch4>1. Encode Seatbelt.exe as base64 and return the result\u003C\u002Fh4>\u003Cp>C# implementation code:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>using System;\u003Cbr>using System.Reflection;\u003Cbr>namespace TestApplication\u003Cbr>{\u003Cbr>    public class Program\u003Cbr>    {\u003Cbr>        public static void Main()\u003Cbr>        {\u003Cbr>\u003Cbr>            byte[] buffer = System.IO.File.ReadAllBytes(\"Seatbelt.exe\");\u003Cbr>            string base64str = Convert.ToBase64String(buffer);\u003Cbr>            Console.WriteLine(base64str);\u003Cbr>        }\u003Cbr>    }\u003Cbr>}\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>You can compile using Visual Studio or directly using csc.exe\u003C\u002Fp>\u003Cp>Command to compile with csc.exe under .Net 3.5:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>C:\\Windows\\Microsoft.NET\\Framework64\\v3.5\\csc.exe base64.cs\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Command to compile with csc.exe under .Net 4.0:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>C:\\Windows\\Microsoft.NET\\Framework64\\v4.0.30319\\csc.exe base64.cs\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>After successful compilation, base64.exe is generated. Executing it produces the base64-encoded string of Seatbelt.exe\u003C\u002Fp>\u003Ch4>2. Use Assembly.Load() for base64 decoding and loading, then pass parameters to the Main function\u003C\u002Fh4>\u003Cp>C# implementation code:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>using System;\u003Cbr>using System.Reflection;\u003Cbr>namespace TestApplication\u003Cbr>{\u003Cbr>    public class Program\u003Cbr>    {\u003Cbr>        public static void Main(string[] args)\u003Cbr>        {\u003Cbr>\u003Cbr>            string base64str = \"\u003Cbase64 string=\"\">\";\u003Cbr>\u003Cbr>            byte[] buffer = Convert.FromBase64String(base64str);\u003Cbr>            object[] commands = args;\u003Cbr>            Assembly assembly = Assembly.Load(buffer);\u003Cbr>            try\u003Cbr>            {\u003Cbr>                assembly.EntryPoint.Invoke(null, new object[] { commands });\u003Cbr>            }\u003Cbr>            catch\u003Cbr>    {\u003Cbr>                MethodInfo method = assembly.EntryPoint;\u003Cbr>                if (method != null)\u003Cbr>                {\u003Cbr>                    object o = assembly.CreateInstance(method.Name);                    \u003Cbr>                    method.Invoke(o, null);\u003Cbr>                }\u003Cbr>            }\u003Cbr>        }\u003Cbr>    }\u003Cbr>}\u003C\u002Fbase64>\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Replace \u003Cbase64 string=\"\"> in the above code with the base64-encoded string of Seatbelt.exe\u003C\u002Fbase64>\u003C\u002Fp>\u003Cp>Similarly, the above code can be compiled using Visual Studio or directly with csc.exe\u003C\u002Fp>\u003Ch2>0x04 Method for loading Seatbelt and passing parameters using execute-assembly\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>Implementation language: C++\u003C\u002Fp>\u003Cp>Implementation approach:\u003C\u002Fp>\u003Cp>Save the content of Seatbelt.exe in an array, then use Load_3(...) to load the .NET assembly after reading, and finally pass parameters to the Main function\u003C\u002Fp>\u003Cp>To remove the signature of Seatbelt.exe, each character in Seatbelt.exe can be XORed and then saved to the array\u003C\u002Fp>\u003Cp>Here, HostingCLR is used as the code development template\u003C\u002Fp>\u003Cp>The code of HostingCLR does not solve the parameter passing issue and cannot pass parameters to the Main function of the .NET assembly. Code location:\u003C\u002Fp>\u003Cp>https:\u002F\u002Fgithub.com\u002Fetormadiv\u002FHostingCLR\u002Fblob\u002Fmaster\u002FHostingCLR\u002FHostingCLR.cpp#L218\u003C\u002Fp>\u003Cp>My code solves the parameter passing issue and removes the signature of Seatbelt.exe by XORing each character in Seatbelt.exe and then saving it to the array\u003C\u002Fp>\u003Cp>Implementation code:\u003C\u002Fp>\u003Ch4>1. XOR each character in the exe file and save it as a new file\u003C\u002Fh4>\u003Cp>C++ implementation code:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>int main(int argc, char* argv[])\u003Cbr>{\u003Cbr>\tif (argc != 3)\u003Cbr>\t{\u003Cbr>\t\tprintf(\"File_XOR_generator\\n\");\u003Cbr>\t\tprintf(\"Usage:\\n\");\u003Cbr>\t\tprintf(\"%s \u003Cfile path=\"\"> \u003Cxor inputs=\"\">\\n\", argv[0]);\u003Cbr>\t\tprintf(\"Eg:\\n\");\u003Cbr>\t\tprintf(\"%s test.exe 0x01\\n\", argv[0]);\u003Cbr>\u003Cbr>\t\treturn 0;\u003Cbr>\t}\u003Cbr>\u003Cbr>\tint x;\u003Cbr>\tsscanf_s(argv[2], \"%x\", &amp;x);\u003Cbr>\u003Cbr>\tFILE* fp;\u003Cbr>\tint err = fopen_s(&amp;fp, argv[1], \"ab+\");\u003Cbr>\tif (err != 0)\u003Cbr>\t{\u003Cbr>\t\tprintf(\"\\n[!]Open file error\");\u003Cbr>\t\treturn 0;\u003Cbr>\t}\u003Cbr>\tfseek(fp, 0, SEEK_END);\u003Cbr>\tint len = ftell(fp);\u003Cbr>\tunsigned char *buf = new unsigned char[len];\u003Cbr>\tfseek(fp, 0, SEEK_SET);\u003Cbr>\tfread(buf, len, 1, fp);\u003Cbr>\tfclose(fp);\u003Cbr>\tprintf(\"[*] file name:%s\\n\", argv[1]);\u003Cbr>\tprintf(\"[*] file size:%d\\n\", len);\u003Cbr>\u003Cbr>\tfor (int i = 0; i &lt; len; i++)\u003Cbr>\t{\u003Cbr>\t\tbuf[i] = buf[i] ^ x;\u003Cbr>\t}\u003Cbr>\tchar strNew[256] = {0};\u003Cbr>\tsnprintf(strNew, 256, \"xor_%s\", argv[1]);\u003Cbr>\u003Cbr>\tFILE* fp2;\u003Cbr>\terr = fopen_s(&amp;fp2, strNew, \"wb+\");\u003Cbr>\tif (err != 0)\u003Cbr>\t{\u003Cbr>\t\tprintf(\"\\n[!]createfile error!\");\u003Cbr>\t\treturn 0;\u003Cbr>\t}\u003Cbr>\tfwrite(buf, len, 1, fp2);\u003Cbr>\tfclose(fp2);\t\u003Cbr>\tprintf(\"[*] XOR file name:%s\\n\", strNew);\u003Cbr>\tprintf(\"[*] XOR file size:%d\\n\", len);\u003Cbr>}\u003C\u002Fxor>\u003C\u002Ffile>\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Here, each character in Seatbelt.exe is XORed with 0x01. The command line parameters are as follows:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>File_XOR_generator.exe Seatbelt.exe 0x01\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Generate the file xor_Seatbelt.exe\u003C\u002Fp>\u003Cp>Open xor_Seatbelt.exe using HxD\u003C\u002Fp>\u003Cp>Copy the file content into C code format, as shown in the figure below\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fapi\u002Fmedia\u002Ffile\u002Fdocx_image_1770017279789_0_4559a5f5bc-1.jpeg\">\u003C\u002Fp>\u003Ch4>2. Use Load_3(...) to load the .NET assembly, and finally pass parameters to the Main function\u003C\u002Fh4>\u003Cp>The complete code has been uploaded to GitHub, address as follows:\u003C\u002Fp>\u003Cp>An open-source project\u003C\u002Fp>\u003Cp>When using, modify the following locations in the code:\u003C\u002Fp>\u003Cul>\u003Cli>Replace the content in the array rawData\u003C\u002Fli>\u003Cli>Define the path for mscorlibPath\u003C\u002Fli>\u003Cli>Define the version for runtimeVersion\u003C\u002Fli>\u003C\u002Ful>\u003Cp>The code will perform XOR operation character by character on the content in the array rawData with 0x01, restore the file content of Seatbelt.exe, then load it and pass parameters to the Main function\u003C\u002Fp>\u003Cp>After compilation, generate the file HostingCLR_with_arguments_XOR.exe, test command example:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>HostingCLR_with_arguments_XOR.exe -group=all\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Use Process Explorer to view the .NET Assemblies item of the process HostingCLR_with_arguments_XOR.exe, as shown in the figure below\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fapi\u002Fmedia\u002Ffile\u002Fdocx_image_1770017308918_1_1d4c157455-1.jpeg\">\u003C\u002Fp>\u003Cp>Can obtain the name of the .NET assembly\u003C\u002Fp>\u003Cp>If you want to hide the name of a .NET assembly, you need to bypass ETW detection.\u003C\u002Fp>\u003Ch4>3. Bypassing ETW detection\u003C\u002Fh4>\u003Cp>Refer to the code at https:\u002F\u002Fgithub.com\u002Foutflanknl\u002FTamperETW\u002F\u003C\u002Fp>\u003Cp>Introduce the code for bypassing ETW from there; the code has been uploaded to GitHub at the following address:\u003C\u002Fp>\u003Cp>An open-source project\u003C\u002Fp>\u003Cp>Here, you also need to add the asm file Syscalls.asm to implement calls to the assembly file.\u003C\u002Fp>\u003Cp>Create a new item, select a C++ file, enter the file name Syscalls.asm, with the specific content as follows:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>.code\u003Cbr>\u003Cbr>; Reference: https:\u002F\u002Fj00ru.vexillium.org\u002Fsyscalls\u002Fnt\u002F64\u002F\u003Cbr>\u003Cbr>; Windows 7 SP1 \u002F Server 2008 R2 specific syscalls\u003Cbr>\u003Cbr>ZwProtectVirtualMemory7SP1 proc\u003Cbr>\t\tmov r10, rcx\u003Cbr>\t\tmov eax, 4Dh\u003Cbr>\t\tsyscall\u003Cbr>\t\tret\u003Cbr>ZwProtectVirtualMemory7SP1 endp\u003Cbr>\u003Cbr>ZwWriteVirtualMemory7SP1 proc\u003Cbr>\t\tmov r10, rcx\u003Cbr>\t\tmov eax, 37h\u003Cbr>\t\tsyscall\u003Cbr>\t\tret\u003Cbr>ZwWriteVirtualMemory7SP1 endp\u003Cbr>\u003Cbr>ZwReadVirtualMemory7SP1 proc\u003Cbr>\t\tmov r10, rcx\u003Cbr>\t\tmov eax, 3Ch\u003Cbr>\t\tsyscall\u003Cbr>\t\tret\u003Cbr>ZwReadVirtualMemory7SP1 endp\u003Cbr>\u003Cbr>; Windows 8 \u002F Server 2012 specific syscalls\u003Cbr>\u003Cbr>ZwProtectVirtualMemory80 proc\u003Cbr>\t\tmov r10, rcx\u003Cbr>\t\tmov eax, 4Eh\u003Cbr>\t\tsyscall\u003Cbr>\t\tret\u003Cbr>ZwProtectVirtualMemory80 endp\u003Cbr>\u003Cbr>ZwWriteVirtualMemory80 proc\u003Cbr>\t\tmov r10, rcx\u003Cbr>\t\tmov eax, 38h\u003Cbr>\t\tsyscall\u003Cbr>\t\tret\u003Cbr>ZwWriteVirtualMemory80 endp\u003Cbr>\u003Cbr>ZwReadVirtualMemory80 proc\u003Cbr>\t\tmov r10, rcx\u003Cbr>\t\tmov eax, 3Dh\u003Cbr>\t\tsyscall\u003Cbr>\t\tret\u003Cbr>ZwReadVirtualMemory80 endp\u003Cbr>\u003Cbr>; Windows 8.1 \u002F Server 2012 R2 specific syscalls\u003Cbr>\u003Cbr>ZwProtectVirtualMemory81 proc\u003Cbr>\t\tmov r10, rcx\u003Cbr>\t\tmov eax, 4Fh\u003Cbr>\t\tsyscall\u003Cbr>\t\tret\u003Cbr>ZwProtectVirtualMemory81 endp\u003Cbr>\u003Cbr>ZwWriteVirtualMemory81 proc\u003Cbr>\t\tmov r10, rcx\u003Cbr>\t\tmov eax, 39h\u003Cbr>\t\tsyscall\u003Cbr>\t\tret\u003Cbr>ZwWriteVirtualMemory81 endp\u003Cbr>\u003Cbr>ZwReadVirtualMemory81 proc\u003Cbr>\t\tmov r10, rcx\u003Cbr>\t\tmov eax, 3Eh\u003Cbr>\t\tsyscall\u003Cbr>\t\tret\u003Cbr>ZwReadVirtualMemory81 endp\u003Cbr>\u003Cbr>; Windows 10 \u002F Server 2016 specific syscalls\u003Cbr> \u003Cbr>ZwProtectVirtualMemory10 proc\u003Cbr>\t\tmov r10, rcx\u003Cbr>\t\tmov eax, 50h\u003Cbr>\t\tsyscall\u003Cbr>\t\tret\u003Cbr>ZwProtectVirtualMemory10 endp\u003Cbr>\u003Cbr>ZwWriteVirtualMemory10 proc\u003Cbr>\t\tmov r10, rcx\u003Cbr>\t\tmov eax, 3Ah\u003Cbr>\t\tsyscall\u003Cbr>\t\tret\u003Cbr>ZwWriteVirtualMemory10 endp\u003Cbr>\u003Cbr>ZwReadVirtualMemory10 proc\u003Cbr>\t\tmov r10, rcx\u003Cbr>\t\tmov eax, 3Fh\u003Cbr>\t\tsyscall\u003Cbr>\t\tret\u003Cbr>ZwReadVirtualMemory10 endp\u003Cbr>\u003Cbr>end\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>\u003Cstrong>Note:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>The code for Syscalls.asm is from https:\u002F\u002Fgithub.com\u002Foutflanknl\u002FTamperETW\u002Fblob\u002Fmaster\u002FTamperETW\u002FUnmanagedCLR\u002FSyscalls.asm\u003C\u002Fp>\u003Cp>To use assembly code in Visual Studio 2015 on a 64-bit platform, the following settings are required:\u003C\u002Fp>\u003Cp>(1) Right-click on the project -&gt; Build Dependencies -&gt; Build Customizations, check masm\u003C\u002Fp>\u003Cp>As shown in the figure below\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fapi\u002Fmedia\u002Ffile\u002Fdocx_image_1770017338060_2_b67ddfab9e-1.jpeg\">\u003C\u002Fp>\u003Cp>(2) Right-click the file Syscalls.asm -&gt; Properties, set the Item Type to Microsoft Macro Assembler\u003C\u002Fp>\u003Cp>As shown in the figure below\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fapi\u002Fmedia\u002Ffile\u002Fdocx_image_1770017384417_3_e428fd5101-1.jpeg\">\u003C\u002Fp>\u003Cp>After compilation, the file HostingCLR_with_arguments_XOR_TamperETW.exe is generated\u003C\u002Fp>\u003Cp>Test command example:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>HostingCLR_with_arguments_XOR_TamperETW.exe -group=all\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Use Process Explorer to view the .NET Assemblies entry of the process HostingCLR_with_arguments_XOR_TamperETW.exe, as shown in the figure below\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fapi\u002Fmedia\u002Ffile\u002Fdocx_image_1770017407639_4_1975b7d286-1.jpeg\">\u003C\u002Fp>\u003Cp>Successfully hides the names of .NET assemblies\u003C\u002Fp>\u003Ch2>0x05 Summary\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>This article introduces two methods for loading Seatbelt in memory (Assembly.Load and execute-assembly), respectively completing the implementation code for passing parameters to the Main function of a .NET assembly. It addresses the parameter passing issue in HostingCLR, introduces code for TamperETW to bypass ETW, and explains the method of using assembly code in Visual Studio 2015 on a 64-bit platform.\u003C\u002Fp>\u003C\u002Fbody>\u003C\u002Fhtml>",632,"Onedaysec",6,"published","2026-02-02T07:38:21.176Z",{"title":37,"description":14,"keywords":38,"ogImage":39,"canonicalUrl":39,"noIndex":40},"In-Memory Loading for Seatbelt: Assembly.Load & execute-assembly","Seatbelt, in-memory loading, Assembly.Load, execute-assembly, .NET security, C# exploitation, memory loading techniques",null,false,[],{"docs":43,"hasNextPage":40},[44,4,45,46],924,922,921,{"title":39,"description":39,"image":39},"2026-07-24T15:37:10.782Z","2026-07-23T16:02:17.421Z","draft","2026-07-23T16:15:34.402Z"]