前言
这里所说的代码注入和上篇的DLL注入有类似之处。DLL文件的注入与卸载在上篇中都完成了,整个注入与卸载的过程其实就是让远程线程执行一次LoadLibrary函数或者FreeLibrary函数。远程线程装载或者卸载一个DLL文件,通过dllMain()调用DLL中具体功能代码,这样注入DLL以后就可以让DLL做很多事情了。
是否可以不依赖DLL文件直接向目标进程写入要执行的代码,完成特定的功能呢?当然是可以的。这节我们就来实现代码注入到指定的进程中。
代码注入思路
要在目标进程中完成一定的特定功能,就需要使用相关的API函数,不同的API函数实现在不同的DLL中。Kernel32.dll文件在每个进程中的地址是相同的,但是并不代表其他的DLL文件在每个进程中的地址都是一样的。这样,在目标进程中调用每一个API函数时,必须使用LoadLibrary(或GetModuleHandle)函数和GetProcAddress函数动态导出用到的每个API函数(必需的)。把想要使用的API函数及API函数所在的DLL文件都封装进一个结构体 (作为写的函数代码的参数),直接写入目标进程的空间中。直接把要在远程执行的代码也写入到目标进程的内存空间中,最后调用CreateRemoteThread函数即可将其运行。
界面效果
有图有真相!我们往QQ.exe进程中 注入代码。
核心代码
选择注入的进程,这里主要是用到了进程遍历,可以参考 Qt:Windows编程—Qt实现进程管理 这篇博文。
封装的结构体
这个数据类型就是要传递 线程回调函数的参数,也就是我们注入的函数代码的参数。
#define STRLEN 20
typedef struct _mydata{
// 4个不变函数的函数地址
DWORD dwLoadLibrary;
DWORD dwGetProcAddress;
DWORD dwGetModuleFileName;
DWORD dwGetModuleHandle;
char user32dll[STRLEN]; // user32.dll 含有MessageBoxA函数
char MessageBoxFun[STRLEN]; // "MessageBoxA" 字符串
char msvcrtdll[STRLEN]; // MSVCRT.DLL 微软运行库 含有strcat函数
char strcatFun[STRLEN]; // "strcat" 字符串
char caption[STRLEN]; // 消息框标题 "Inject Code!"
char content[MAX_PATH]; // 消息框内容
}MyData;
注入的代码
// 注入的可执行代码,执行弹框功能
DWORD WINAPI CodeFunc(LPVOID param)
{
MyData* data = (MyData*)param;
// 定义函数指针类型 方便下面的类型转换
typedef HMODULE (__stdcall *MyLoadLibrary)(LPCSTR);
typedef FARPROC (__stdcall *MyGetProcAddress)(HMODULE,LPCSTR);
typedef DWORD (__stdcall *MyGetModuleFileName)(HMODULE,LPSTR,DWORD);
typedef HMODULE (*MyGetModuleHandle)(LPCSTR);
typedef int (__stdcall *MyMessageBox)(HWND,LPCSTR,LPCSTR,UINT);
typedef char*(*Mystrcat)(char *dest, const char *src);
// 获取函数地址
MyLoadLibrary myLoadLibrary = (MyLoadLibrary)data->dwLoadLibrary;
MyGetProcAddress myGetProcAddress = (MyGetProcAddress)data->dwGetProcAddress;
MyGetModuleFileName myGetModuleFileName = (MyGetModuleFileName)data->dwGetModuleFileName;
MyGetModuleHandle myGetModuleHandle = (MyGetModuleHandle)data->dwGetModuleHandle;
// 所有用的函数,都需像下面一样 导出函数地址然后再使用,包括标准库函数也一样
// 笔者刚开始就犯了一个错,直接使用sprintf、strcat 等函数,这样是不行!因为我们自己注入的代码,函数地址需要我们自己确定!
HMODULE user32dll = myLoadLibrary(data->user32dll);
HMODULE msvcrtdll = myGetModuleHandle(data->msvcrtdll);// msvcrt.dll 微软运行库,可直接获取
MyMessageBox myMessageBox = (MyMessageBox)myGetProcAddress(user32dll,data->MessageBoxFun);
Mystrcat mystrcat = (Mystrcat)myGetProcAddress(msvcrtdll,data->strcatFun);
// 调用获取到的函数
char curFile[MAX_PATH] = {0};
myGetModuleFileName(NULL,curFile,MAX_PATH);
mystrcat(data->content,curFile);
myMessageBox(NULL, data->content ,data->caption, MB_OK);
return 0;
}
注入代码操作
// 注入Code操作
void WorkerThread::injectCode()
{
HANDLE targetProc = OpenProcess(PROCESS_ALL_ACCESS,FALSE,m_pId);
if( targetProc == NULL )
{
qDebug() << "OpenProcess error";
return;
}
MyData data = {0};
strcpy(data.user32dll,"user32.dll");
strcpy(data.msvcrtdll,"msvcrt.dll");
strcpy(data.MessageBoxFun,"MessageBoxA");
strcpy(data.strcatFun,"strcat");
strcpy(data.caption,"Inject Code!");
strcpy(data.content,"current process:");// 这里使用中文会乱码
HMODULE module = GetModuleHandleA("kernel32.dll");
data.dwLoadLibrary = (DWORD)GetProcAddress(module,"LoadLibraryA");
data.dwGetProcAddress = (DWORD)GetProcAddress(module,"GetProcAddress");
data.dwGetModuleFileName = (DWORD)GetProcAddress(module,"GetModuleFileNameA");
data.dwGetModuleHandle = (DWORD)GetProcAddress(module,"GetModuleHandleA");
int dataLen = sizeof(MyData);
// 1.目标进程申请空间 存放data数据,也就是注入的 可执行代码函数 的参数
LPVOID pData = VirtualAllocEx(targetProc,NULL,dataLen,MEM_COMMIT | MEM_RESERVE,PAGE_READWRITE );
if( pData == NULL )
{
qDebug() << "VirtualAllocEx error 1";
return;
}
int ret = WriteProcessMemory(targetProc,pData,&data,dataLen,NULL);
if( ret == 0 )
{
qDebug() << "WriteProcessMemory error 1";
return;
}
// 2.目标进程申请空间 存放CodeFunc可执行代码函数
int codeLen = 0x4000; // 4 * 16^3 = 16KB足够了
// 第5个参数,数据具有可执行权限
LPVOID pCode = VirtualAllocEx(targetProc,NULL,codeLen,MEM_COMMIT,PAGE_EXECUTE_READWRITE );
if( pCode == NULL )
{
qDebug() << "VirtualAllocEx error 2";
return;
}
ret = WriteProcessMemory(targetProc,pCode,(LPCVOID)&CodeFunc,codeLen,NULL);
if( ret == 0 )
{
qDebug() << "WriteProcessMemory error 2";
return;
}
// 3.创建远程线程 执行可执行代码
HANDLE tHandle = CreateRemoteThread(targetProc,NULL,NULL,
(LPTHREAD_START_ROUTINE)pCode,pData,NULL,NULL);
if(tHandle == NULL)
{
qDebug() << "CreateRemoteThread error";
return ;
}
qDebug() << "注入,wait ..." ;
WaitForSingleObject(tHandle,INFINITY);
CloseHandle(tHandle);
CloseHandle(targetProc);
qDebug() << "注入,finish ...";
emit doInjectFinish();
}
完整代码
完整代码工程请在这里下载。