一、DLL注入概述
1.简介
DLL注入指的是向运行中的其他进程强制插入特定的DLL文件。从技术细节上来讲,DLL注入命令区别于其他进程自行调用LoadLibary()API加载用户指定的DLL文件。DLL注入与一般DLL加载的区别在于,加载的目标进程在自身还是在其他进程,正经的程序谁会去操作其他的进程空间呢?
2. 原理
DLL注入的工作原理是强制目标程序调用LoadLibary()函数加载dll文件,因此会强制执行DLLMain函数,同时,被注入的DLL拥有目标进程的内存访问权限从而实现一些有用的功能。
例如:
- 改善功能与修复BUg
- 消息钩取
- API钩取
- 恶意代码
- …
二、DLL注入实现
各个方式都分为注入程序和DLL程序两部分,其中DLL都是一样的,我们的目标是把我们自己的DLL注入程序中,不同的方式使用不同的注入程序,从而实现DLL注入。
1.远程线程注入
所用主要API
- LoadLibrary():用来加载DLL文件,
- CreateRemoteThread() :在其他程序中启动远程线程,使程序自动启用LoadLibrary()函数,从而加载DLL文件
- WriteProcessMemory():在其他进程中写入数据
程序代码
BOOL InjectProgram(DWORD dwPID, LPCTSTR path)
{
HANDLE hProcess = NULL, hThread = NULL;
HMODULE hMod = NULL;
LPVOID pRemoteBuf = NULL;
DWORD dwBufSize = (DWORD)(_tcslen(path) + 1) * sizeof(TCHAR);
LPTHREAD_START_ROUTINE pThreadProc;
//用获取的PID找到注入进程的句柄
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID);
if (!hProcess)
{
MessageBox(NULL, L"句柄失败", L"Error",MB_OK);
_tprintf(L"Inject fail PID=%d,error is %d", dwPID, GetLastError);
return 0;
}
//在目标进程的内存中分配空间
pRemoteBuf = (LPVOID)VirtualAllocEx(hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_READWRITE);
//在分配好的空间中写入dll文件名
WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID)path, dwBufSize, NULL);
//获取LoadLibrary API的地址
hMod = GetModuleHandle(L"kernel32.dll");
pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hMod, "LoadLibraryW");
hThread = CreateRemoteThread(
hProcess,
NULL,
0,
pThreadProc,
pRemoteBuf,
0,
NULL
);
if (!hThread)
{
return 0;
}
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
CloseHandle(hProcess);
return TRUE;
}
int _tmain(int argc,TCHAR* argv[]) //主函数名为_tmain(),否则无法接受参数
{
if (argc != 3)
{
MessageBox(NULL, L"Error", L"参数错误", MB_OK);
OutputDebugString(L"参数数量不对");
}
else
{
BOOL flag;
_tprintf(L"%d,Inject PID=%d", argc,(DWORD)_tstol(argv[1]));
flag=InjectProgram((DWORD)_tstol(argv[1]), argv[2]);
if (flag)
{
MessageBox(NULL, L"YES", L"成功", MB_OK);
}
else
{
MessageBox(NULL, (LPCWSTR)&argv[1], L"错误", MB_OK);
}
}
}
2.修改注册表注入
手动改注册表
运行regedit.exe,可以打开注册表编辑器,
找到HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\windows NT\windows,我们需要该其中的两项
需要改AppInit_DLLs,以及LoadAppInt_DLLs。
AppInit_DLLs的值会让程序在加载user32.dll时同时加载,就像你在食堂打一碗饭,食堂大妈顺手给了你一碗汤。
LoadAppInt_DLLs的值改为1,让程序加载上一项中修改的DLL地址。
重启之后生效。
注入程序:
#define DSTKEY L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows"
BOOL RegInject(WCHAR* path);
int main()
{
WCHAR Dllpath[MAX_PATH] = L"C:\\Users\\Y\\Desktop\\myhack.dll";
BOOL flag = RegInject(Dllpath);
if (flag)
{
_tprintf(L"SUCCESS");
}
else
{
printf("erro\n");
}
}
BOOL RegInject(WCHAR* path)
{
HKEY key = NULL;
BYTE Dllpath[MAX_PATH] = { 0 };
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, DSTKEY, 0, KEY_ALL_ACCESS, &key) != ERROR_SUCCESS)
{
printf("Inject faile\n");
return false;
}
memcpy((void*)Dllpath, path,_tcslen(path)*2+1);
if (RegSetValueEx(key, L"AppInit_DLLs", 0, REG_SZ, Dllpath, (_tcslen(path) + 1)*sizeof(TCHAR))!=ERROR_SUCCESS)
{
printf("set error\n");
return false;
}
DWORD dwValue = 1;
if (RegSetValueEx(key, L"LoadAppInit_DLLs", 0, REG_DWORD,(BYTE*)&dwValue, sizeof(dwValue)) != ERROR_SUCCESS)
{
printf("set2 error\n");
return false;
}
return true;
}
3.消息钩取
利用windows提供的setWindowsHook()API,我们可以实现DLL注入,该函数会注册一个钩子,当程序触发相应事件时,会将DLL注入到相应的进程,从而实现一系列的目标。
键盘钩子见另一篇博客
参考资料:《逆向工程核心原理》