概述
相关视频教程下载链接:http://pan.baidu.com/s/1eR6xKiQ 密码:alrl
(3)分配内存地址空间
要将指定的动态库路径写入到进程的地址空间中,需要为该动态库路径分配地址空间。要分配地址空间,就需要知道要分配地址空间的大小。假设动态库文件与注入程序文件在同一文件夹下,即如果注入文件的绝对路径为“C:12inject.exe”,则动态库的绝对路径为“C:12myDll.dll”。分配地址空间的大小即为动态库绝对路径的长度,首先获取注入文件的绝对路径,之后将绝对路径中的“inject.exe”换成“myDll.dll”即可。
TCHAR szLibFile[MAX_PATH] = { 0 };
GetModuleFileName(NULL, szLibFile, _countof(szLibFile));
PTSTR pFileName = _tcsrchr(szLibFile, _T('\')) + 1;
_tcscpy_s(pFileName, _countof(szLibFile) - (pFileName - szLibFile), inject_dll_name);
int cch = lstrlen(szLibFile) + 1;
SIZE_T cb = cch*sizeof(TCHAR);
其中,GetModuleFileName()函数的作用是获取注入程序的绝对路径,并将其保存在szLibFile中;之后通过_tcsrchr()函数获取szLibFile中最后一个“\”的位置;接下来通过_tcscpy_s()函数将szLibFile中注入程序的名称换成动态库的名称inject_dll_name;最后得到动态库的绝对路径的长度cb。
在获取了要分配内存地址空间的长度之后,通过VirtualAllocEx()函数在远程进程的内存空间中进行分配。该函数的格式为
LPVOID WINAPI VirtualAllocEx(
_In_ HANDLE hProcess,
_In_opt_ LPVOID lpAddress,
_In_ SIZE_T dwSize,
_In_ DWORD flAllocationType,
_In_ DWORD flProtect
);
其中,参数hProcess表示进程的句柄;lpAddress指定了分配的内存地址空间的起始地址,如果该参数为NULL,则表示由函数本身来决定分配空间的起始地址;dwSize表示分配的内存地址空间的大小;flAllocationType表示分配内存的类型;flProtect表示对分配的内存地址空间的权限。该函数的返回值即为分配的内存地址空间的起始地址。
LPVOID dll_name_address = VirtualAllocEx(hProcess, NULL, cb, MEM_COMMIT, PAGE_READWRITE);
if (NULL == dll_name_address)
{
MessageBox(_T("分配内存失败!"));
return;
}
在VirtualAllocEx()函数的参数中,hProcess是在“(2)获取远程进程句柄”中获取到的远程进程的句柄;第二个参数NULL表示由函数指定内存空间的起始地址;cb是动态库文件绝对路径的大小;MEM_COMMIT表示内存的类型是“提交”;PAGE_READWRITE表示对分配的内存地址空间有读写权限。返回值dll_name_address是分配的内存地址空间的起始地址。
(4)写入动态库的绝对路径
在内存中分配了地址空间之后,接下来通过WriteProcessMemory()函数将动态库的绝对路径写入到内存空间中。该函数的格式为
BOOL WINAPI WriteProcessMemory(
_In_ HANDLE hProcess,
_In_ LPVOID lpBaseAddress,
_In_ LPCVOID lpBuffer,
_In_ SIZE_T nSize,
_Out_ SIZE_T *lpNumberOfBytesWritten
);
其中,参数hProcess是进程的句柄;lpBaseAddress表示写入内存的起始地址;lpBuffer表示写入内存地址的内容;nSize表示写入内存地址内容的大小;lpNumberOfBytesWritten表示写入到内存地址内容的实际大小。如果将指定内容成功写入到内存地址中,则返回值是TRUE,否则为FALSE。
SIZE_T number_bytes_written = 0;
if (!WriteProcessMemory(hProcess, dll_name_address, (LPCVOID)szLibFile, cb, &number_bytes_written))
{
MessageBox(_T("写入内存失败"));
return;
}
其中,SIZE_T类型在basetsd.h中定义为
typedef ULONG_PTR SIZE_T, *PSIZE_T;
可将该类型看作是一个64位无符号的long类型。WriteProcessMemory()函数的参数hProcess是在“获取远程进程句柄”中获取到的指定的远程线程的句柄;dll_name_address是在“(3)分配内存地址空间”中分配的内存地址空间的起始地址;szLibFile是在“(3)分配内存地址空间”中得到的动态库文件的绝对路径;cb是动态库文件的绝对路径的大小。
3.3.3 创建远程线程注入动态库
在将动态库文件的绝对路径写入到远程进程的地址空间之后,接下来在远程进程中创建远程线程。该线程的函数为LoadLibrary(),线程函数的参数即为在“3.3.2 写入动态库名称”中写入的动态库绝对路径。
(1)获取LoadLibrary()函数的地址
LoadLibrary()函数在Windows系统的动态库文件Kernel32.dll中定义。对于在Windows系统中运行的程序,在运行时都会导入该动态库文件。对于导入程序和要注入的远程程序,在运行时都会导入Kernel32.dll文件。也就是说,LoadLibrary()函数在导入程序中的地址与远程程序中的地址是相同的。因此,在导入程序中获取的LoadLibrary()函数地址即为其在要注入的远程程序中的地址。
LPVOID remote_thread_pointer = LoadLibraryW;
其中,remote_thread_pointer即为LoadLibrary()函数在远程进程中的地址。
(2)创建LoadLibrary()函数的进程
通过CreateRemoteThread()函数创建远程线程。该函数的格式为
HANDLE WINAPI CreateRemoteThread(
_In_ HANDLE hProcess,
_In_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_ SIZE_T dwStackSize,
_In_ LPTHREAD_START_ROUTINE lpStartAddress,
_In_ LPVOID lpParameter,
_In_ DWORD dwCreationFlags,
_Out_ LPDWORD lpThreadId
);
其中,参数hProcess表示远程进程句柄;lpThreadAttributes表示创建的线程的安全描述符(security descriptor),该参数是NULL表示线程使用默认的安全描述符;dwStackSize表示新创建的线程堆的初始大小,该参数是0表示新线程使用默认的堆大小;lpStartAddress表示线程对应的函数的地址;lpParameter表示线程函数的参数;dwCreateFlags表示创建线程时的标志;lpThreadId表示创建线程的ID。该函数的返回值为新创建线程的句柄。
DWORD remote_thread_id = 0;
HANDLE remote_thread_handle = CreateRemoteThread(
hProcess
, NULL
, 0
, (LPTHREAD_START_ROUTINE)remote_thread_pointer
, dll_name_address
, 0
, &remote_thread_id);
if (NULL == remote_thread_handle)
{
MessageBox(_T("创建线程失败"));
return;
}
对于CreateRemoteThread()函数的参数,hProcess是“获取远程进程句柄”中获取到的指定的远程线程的句柄;remote_thread_pointer是“(1)获取LoadLibrary()函数的地址”中LoadLibrary()函数的地址;dll_name_address是动态库的绝对路径。
(3)等待新创建的线程结束
在创建了新线程之后,需要等待其结束再进行后续释放资源的处理。否则,会导致导入动态库失败。可通过WaitForSingleObject()函数等待线程结束,该函数的格式为
DWORD WINAPI WaitForSingleObject(
_In_ HANDLE hHandle,
_In_ DWORD dwMilliseconds
);
其中,参数hHandle表示要等待的线程句柄;dwMilliseconds表示要等待的时间。该函数的返回值表示函数返回的原因。
WaitForSingleObject(remote_thread_handle, INFINITE);
其中,remote_thread_handle是在“(2)创建LoadLibrary()函数的进程”中新创建线程的句柄,INFINITE表示无限等待下去,直到指定的线程结束。
最后
以上就是认真黑夜为你收集整理的VC++远程注入动态库的实现(6-4)的全部内容,希望文章能够帮你解决VC++远程注入动态库的实现(6-4)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复