远程线程DLL注入

老手请飘过,写给新手看的低级东西

一、步骤

1、CreateThread
    要搞懂远程线程注入技术,首先应该用过CreateThread创建多线程。
    如果对这个函数怎么使用没搞懂下面的内容就不用看了,如果对这个函数理解了那么继续走

2、如何加载一个DLL
    要在目标进程注入一个DLL,也就是要将DLL加载到目标进程,我们平时在使用DLL时,是怎么加载的?
    通过LoadLibrary加载。那么我们要将一个DLL注入目标进程,可以理解为我们要在目标进程执行LoadLibrary("xxxdll")
    
3、如何在目标进程执行LoadLibrary
    如果是在自己的进程,我们直接调用LoadLibrary就可以加载一个DLL,现在的问题是我们要在其它进程
    执行LoadLibrary,这就要借助创建远程线程
    
4、如何创建远程线程
    调用下面这个函数,就可以创建远程线程,我们看下msdn对这个函数的描述:
    The CreateRemoteThread function creates a thread that runs in the virtual address space of another process. 

    HANDLE CreateRemoteThread(
        HANDLE hProcess,                          // handle to process
        LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD
        SIZE_T dwStackSize,                       // initial stack size
        LPTHREAD_START_ROUTINE lpStartAddress,    // thread function
        LPVOID lpParameter,                       // thread argument
        DWORD dwCreationFlags,                    // creation option
        LPDWORD lpThreadId                        // thread identifier
    );
    其它参数不多说了,如果不懂可以百度这个函数用法,说说第四个参数
    LPTHREAD_START_ROUTINE lpStartAddress,其实这个参数和CreateThread的第三个参数一样,LPTHREAD_START_ROUTINE原型如下:
    DWORD WINAPI ThreadProc(
        LPVOID lpParameter   // thread data
    );

    说白了第四个参数就是要指定,线程跑起来时,要执行的代码在哪里,这就给我们注入dll带来了机会啊,我们可以把目标进程中LoadLibrary
    函数在内存中的地址作为CreateRemoteThread的第四个参数,那么线程运行时,就去执行LoadLibrary这个函数了。
    
    补充下为什么可以把LoadLibrary这个函数的地址,作为第四个参数,我们来看下LoadLibrary的原型:
    HMODULE LoadLibrary(
        LPCTSTR lpFileName   // file name of module
    );
    
    发现没,LoadLibrary在MSDN中给出的原型只少了个WINAPI,但是Windows所有的API默认都是WINAPI啊,(WINAPI表示调用约定)
    返回值:DWORD 和 HMODULE 本质就是个整数
    参数:LPVOID 和 LPCTSTR 都是个指针
    这就是为什么可以把LoadLibrary作为CreateRemoteThread函数的第三个参数,这样我们就完美利用CreateRemoteThread创建一个
    远程线程,并执行LoadLibrary,去加载我们要注入的DLL了。
    
    那要如何获取目标进程中的LoadLibrary函数地址了,很简单我们获取自己进程中的LoadLibrary的地址即可,LoadLibrary属于kernel32模块
    这个模块在每个进程中加载的基地址都一样,所以LoadLibrary在自己进程中的地址和在目标进程中的地址是一致的。
    
5 解决LoadLibrary的参数问题
    在第四步中我们解决了如何跨进程调用LoadLibrary这个问题,现在的问题是,执行LoadLibrary,我们要给它一个参数,
    这个参数用来指明DLL的路径。我们可以利用CreateRemoteThread的第五个参数LPVOID lpParameter,来解决。
    lpParameter这个参数在远程线程执行时,会传递给LoadLibrary (LoadLibrary就是远程线程),作为LoadLibrary的第一参数。
    
    但是这里有一个问题,我们调用CreateRemoteThread时,是在自己的进程调用,那么传递lpParameter这个参数时,不能使用自己进程
    虚拟地址空间的地址,那要怎么解决这个问题
    
6 VirtualAllocEx
    在Step5中,碰到了新的问题,如何传递LoadLibrary的参数,因为这个参数必须是目标进程中的一个虚拟地址。
    我们需要用到VirtualAllocEx这个函数,这个函数可以在目标进程申请内存,我们通过调用这个函数,在目标
    进程中申请一段内存,然后把DLL的路径,写到这段内存中,比如d:\xxx\xxoo.dll
    这个函数的返回值,就是申请到的内存的起始地址。所以我们可以把返回值作为CreateRemoteThread的第5个参数,这样解决了给
    LoadLibrary传递参数的问题。
    
7 其它一些细节问题看代码注释
    

二、注意事项
    如果你要注入的目标进程是64位程序,那么你的注入进程必须是64位的,而且要注入的DLL也必须是64位的,否则           CreateRemoteThread会 失败,GetLastError返回错误代码:5。写一个完善的注入代码要考虑的问题很多

三、部分关键代码如下,代码有参考这个博客:

https://www.cnblogs.com/BoyXiao/archive/2011/08/11/2134367.html

代码网上一大把,关键是搞清楚思路,如果需要完整代码可以联系QQ 844255657, 这里没有把所有代码贴上来了,

因为网上太多了。

int _tmain(int argc, _TCHAR* argv[])
{
	

	if (!AdjustProcessTokenPrivilege()){
		MyOutputDebugString("提权失败\n");
	}

	DWORD dwPid = GetPidByName("explorer.exe");
	if (dwPid == 0){
		MyOutputDebugString("GetPidByName failed\n");
		return -1;
	}

	MyOutputDebugString("explorer.exe pid=%d\n", dwPid);

	HANDLE hProcess;
	hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);

	if (hProcess == NULL)
	{
		MyOutputDebugString("打开进程失败!!!!");
		return -1;
	}


	//1.在远程进程中分配内存
	LPVOID pszRemoteBuffer = (char *)VirtualAllocEx(hProcess, NULL, MAX_PATH, MEM_COMMIT, PAGE_READWRITE);

	if (pszRemoteBuffer == NULL)
	{
		MyOutputDebugString("申请远程空间失败");
		return -1;
	}
	//2.在远程申请的内存空间中写入DLL的路径,后面这块数据当做远程线程的参数
	SIZE_T dwWriten = 0;
	const char * dllPath = "D:\\VS\\DllToInject\\x64\\Debug\\UtilDll.dll";
	if (!WriteProcessMemory(hProcess, pszRemoteBuffer, (LPVOID)dllPath, strlen(dllPath) + 1, &dwWriten))
	{
		MyOutputDebugString("写入内存失败");
		return -1;
	}

	//3.获取远程进程中LoadLibry的地址, 这里使用当前进程Kernel32模块的基地址当做远程进程中的kernel32的基地址,这不是巧合
	//kernel32在每个进程中的基地址都一样,可能是操作系统为进程加载kernel32时,直接将已经加载了的kernel32映射到需要这个模块的进程中
	//pfnLoadLibrary 就是远程线程, 所以远程线程执行就是在对方进程调用LoadLibrary, 
	//如果是Unicode程序,GetProcAddress需要使用LoadLibraryW
	HMODULE hMouDle = GetModuleHandle("Kernel32");
	PTHREAD_START_ROUTINE pfnLoadLibrary = (PTHREAD_START_ROUTINE)GetProcAddress(hMouDle, "LoadLibraryA");

	if (pfnLoadLibrary == NULL)
	{
		MyOutputDebugString("获取LoadLibrary地址失败!!!");
		return -1;
	}

	//4.创建远程线程
	DWORD dwThreadId = 0;
	HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, pfnLoadLibrary, pszRemoteBuffer, 0, &dwThreadId);

	if (hThread == NULL)
	{
		MyOutputDebugString("创建远程线程失败 %d\n", GetLastError());
		return -1;
	}

	//5 等待远程线程退出
	DWORD exitCode = 0;
	DWORD dwRet = 0;
	WaitForSingleObject(hThread, INFINITE);
	dwRet = GetExitCodeThread(hThread, &exitCode);

	//6 检查退出码,如果退出码等于0,说明LoadLibrary失败了
	if (dwRet == 0){
		MyOutputDebugString("GetExitCodeThread failed\n");
		return -1;
	}

	if (exitCode == 0){
		MyOutputDebugString("LoadLibrary %s failed\n", dllPath);
	}

	VirtualFreeEx(hProcess, pszRemoteBuffer, MAX_PATH, MEM_DECOMMIT);
	::CloseHandle(hThread);
	::CloseHandle(hProcess);

	getchar();

	//6 释放注入的DLL, 需要再次创建远程线程执行FreeLibrary
	
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值