DLL远程注入代码详解
DLL远程注入代码详解
首先,四个你要知道的东西:
1.“远程线程‘’是指跨进程,而不是跨计算机。
2.计算机每个进程的地址空间都是独立隔离的。
3.简单说,进程A在进程B创建一个线程就叫远程线程。
4.多用在木马外Gua等注入,dll文件的运行不会单独创建一个进程,它的运行被加载到进程的地址空间中,因此其隐蔽性相对较好。
主要的函数如下:
- 一. CreatRemoteThread()//创建远程线程
在这个函数调用中主要有三个参数以及伴随的三个问题:
1.第四个参数lpStartAddress,指定进程中的线程函数的地址,稍微解释一下就是,你要在目标进程中注入的功能函数的地址。我们用到的函数是LoadLibrary(加载DLL用的)。
2.第五个参数lpParameter,他是dll的具体地址,是loadlibrary的参数,也要传入目标进程中进行存储,(问题:)就需要在目标进程中开辟合适大小的空间来保存。
首先解释解决第一个问题,因为是注入DLL,所以我们需要在目标进程中调用loadlibrary(dll)这个函数来加载dll。那么如何将loadlibrary放到目标进程呢??Loadlibrary是系统中的Kernel32.dll的导出函数,因此他存在于目标进程中,同时kernel32.dll在任何进程中的加载位置都是相同的,也就是说LoadLibraryA()在任何进程中的位置都是相同的。问题变简单了,只需要找到kernel32.dll,找到之后再找library就完成。
然后解决第二个问题,如何将LoadLibrary函数的参数,即dll文件的完整路径传入目标进程内存。问题变简单了,调用我们的第二个函数,如下详细:
- 二. WriteProcessMemory()
/*
注意:该函数功能十分强大,比如在**方面,用该函数可以实现一个内存补丁;在开发方面,用该函数可以修改制定进程中指定的值(比如在游戏中修改属性);
*/
使用该函数可以将DLL文件的完整路径加载到目标进程中,这样就可以使用LoadLibrary()函数来加载指定的DLL文件了。
如上两个问题已经解决,那么有没有人考虑过,DLL文件路径价值再到目标进程中的哪个位置?第三个问题来了,关于dll文件路径存放在哪里。就是接下来的函数发挥作用:
- 三. VirtualAllocEx()//在目标进程中申请内存
该函数申请内存成功之后,会返回一个新内存区域的首地址。
到此为止,主要的函数和思路已经讲完了,接下来设计界面和写代码。
其中GetProcessId()和InjectDll是自写函数,便于后期调试,也可以不写这两个,直接把所有代码写在按钮之下。
void CMFCApplication13Dlg::OnBnClickedButton1()
{
CString szDLLName;
CString szProcessName;
DWORD dwpid = 0;
GetDlgItemText(IDC_EDIT1,szDLLName);
GetDlgItemText(IDC_EDIT2, szProcessName);
//通过进程名获得pid,自定义函数GetProcId
dwpid = GetProcId(szProcessName);
//HANDLE Fhandle=FindWindow(NULL,szProcessName);
//dwpid = GetProcessId(Fhandle);
//注入szDLLName到dwpid
InjectDll(dwpid,szDLLName);
}
GetProcessId()的具体内容如下:
[mw_shl_code=cpp,true]DWORD CMFCApplication13Dlg::GetProcId(CString szProcessName)
{
BOOL bRet;
PROCESSENTRY32 pe32;
HANDLE hSnap;
char* str = (LPSTR)(LPCTSTR)szProcessName;
//获取当前进程快照
hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,NULL);
pe32.dwSize = sizeof(pe32);
bRet = Process32First(hSnap,&pe32);//从第一个进程开始判断
while (bRet)
{
//strupr转换为大写,便于字符串对比,strcmp对比两个进程名称
if (strcmp(strupr(pe32.szExeFile),
strupr(str)) == 0)
{
return pe32.th32ProcessID;//找到
}
bRet = Process32Next(hSnap,&pe32);//下一个进程
}
return 0;
}
InjectDll()代码如下:
void CMFCApplication13Dlg::InjectDll(DWORD dwPid, CString szDllName)
{
if (dwPid == 0 || strlen(szDllName) == 0)
{
return;
}
char* pFunName = "LoadLibraryA";//要在进程中寻找的函数名
//打开目标进程,返回目标进程的句柄
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
if (hProcess == NULL)
{
return;
}
//欲注入的DLL文件路径的长度
int nDllLen = strlen(szDllName) + sizeof(char);
//在目标进程申请一块长度为nDllLen的内存空间,存储dll路径,作为LoadLibraryA()的参数
PVOID pDllAddr = VirtualAllocEx(hProcess,NULL,nDllLen,MEM_COMMIT,PAGE_READWRITE);
if (pDllAddr == NULL)
{
CloseHandle(hProcess);
return;
}
DWORD dwWriteNum = 0;
//将欲注入DLL的路径写入在目标进程申请的空间中
WriteProcessMemory(hProcess,pDllAddr,szDllName,nDllLen,&dwWriteNum);
//其中的一个问题已经完成,就是dll在目标进程中的存储问题。下面是解决在目标进程中获取LoadLibraryA的地址问题
/*获取LoadLibraryA()的地址。这个函数位于kernel32.dll中,kernel在任何进程中的加载位置都是相同的,也就是说LoadLibraryA()
在任何进程中的位置都是相同的。*/
FARPROC pFunAddr = GetProcAddress(GetModuleHandle("kernel32.dll"),pFunName);
//创建远程线程
HANDLE hThread = CreateRemoteThread(hProcess,NULL,0,(LPTHREAD_START_ROUTINE)pFunAddr,pDllAddr,0,NULL);
WaitForSingleObject(hThread,INFINITE);
CloseHandle(hThread);
CloseHandle(hProcess);
}
功能和软件已经完成(我用的MFC添加了几个按钮,请自行设计界面,本篇文章只介绍代码)。
接下来找一个记事本程序进行注入测试,会发现弹出窗口表示注入成功