码迷,mamicode.com
首页 > 其他好文 > 详细

Dll注入方法之二

时间:2016-04-27 15:39:21      阅读:157      评论:0      收藏:0      [点我收藏+]

标签:

有了第一种方法,我们不难举一反三,由于原理是只需要我们的执行函数被写入到目标进程,所有相关的变量也在目标函数里,那么我们的函数就能被正确执行(前提是没有互相调用我们注入的函数,否则需要做地址处理。这也是为什么整个可执行文件注入时,要做很多重定位)。这里,我们进一步尝试,将LoadLibrary放在一个函数里,在同一个函数里,我们再调用一个MessageBox(这里只是一个测试,以后你可以调用任何你的函数,但必须要对地址进行处理)。

步骤一和步骤二:请参考Dll注入方法之一。

步骤三:书写需要被注入到目标进程的函数,这里我们先从最简单的naked函数开始,以汇编的形式注入。

#define PARAM_START 0x80000000
#define pfn_LoadLibraryA PARAM_START+1
#define pfn_MessageBoxA PARAM_START+2
#define szLibrary PARAM_START+3
#define szMsg PARAM_START+4
//定义上面这些唯一标识符,就像资源ID一样具有独特性,方便之后再缓冲中对地址进行修改
void __declspec(naked) YourFunction()
{
    __asm
    {
        push szLibrary
        mov eax, pfn_LoadLibraryA
        call eax //LoadLibraryA(szLibrary)
        push MB_OK
        push NULL
        push szMsg
        push NULL
        mov eax, pfn_MessageBoxA
        call eax //MessageBoxA(NULL,szMsg,NULL,MB_OK)
        retn //由于远程线程是创建的函数,所以需要构造返回指令让堆栈平衡
    }
}

步骤四:写一个函数代码段计算函数,为了计算YourFunction()这个函数的大小

	DWORD CodeSize(DWORD pfn_jmp)
	{
		byte *lpStartAddr;
		if (*(byte *)pfn_jmp==0xe9)
			lpStartAddr=(byte *)(*(DWORD *)(pfn_jmp+0x1)+pfn_jmp+0x5);
		else
			lpStartAddr=(byte *)pfn_jmp;//判断是否近跳还是远跳,至于为什么这样,各位要用ollydbg去看看,编译器在生成这些汇编代码时,是什么样的
                              //由于篇幅有限,这里就不说反汇编基础了,自己去补充 byte *StartCode=lpStartAddr;//处理jmp这条指令后得到的函数地址 while (*lpStartAddr!=0xc3) //计算以retn指令结尾的函数 { if (*lpStartAddr==0xc2 && *(lpStartAddr+1)==0x4)//由于默认只传入一个参数,并判断是否以ret4指令结尾的函数 { lpStartAddr+=2; break; } lpStartAddr++; } return (DWORD)(lpStartAddr+1-StartCode);//返回函数字节大小 }

步骤五:写一个YourFunction函数的执行代码复制到缓存区的函数

	byte *BufferCode(DWORD pfn_jmp)
	{
		codeSize=CodeSize(pfn_jmp);//步骤四的函数
		bufferCode=(byte *)malloc(codeSize);//为缓存区分配大小
		assert(bufferCode!=NULL);
		byte *lpStartAddr;
		if (*(byte *)pfn_jmp==0xe9)
			lpStartAddr=(byte *)(*(DWORD *)(pfn_jmp+0x1)+pfn_jmp+0x5);
		else
			lpStartAddr=(byte *)pfn_jmp;
		RtlCopyMemory(bufferCode,lpStartAddr,codeSize);
		//由于是nacked函数,所以不用对堆栈平衡进行处理,但第三种dll注入方法必须处理!
		return bufferCode;
	}

步骤六:注入代码

	BOOL ReplaceParamAddr(byte *buffer,DWORD dwOld,DWORD dwNew)
	{//这个函数是通过在buffer这个缓冲区搜索特征码,然后替换成新的数据(为了对地址进行调整)
		for (DWORD i=0;i<codeSize;i++)
		{
			if (*(DWORD *)&buffer[i]==dwOld)
			{
				*(DWORD *)&buffer[i]=dwNew;
				return TRUE;
			}
		}
		return FALSE;
	}

开始我们的注入代码

	BOOL InjectDll()
	{
		BOOL iRet=-1;
		HANDLE hRemoteProcess=OpenProcess(PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_VM_WRITE,
			FALSE,GetProcessID(szInjectedExeFileName));//打开目标进程
		assert(hRemoteProcess!=INVALID_HANDLE_VALUE);
		BufferCode((DWORD)YourFunction);//步骤五的函数
		ReplaceParamAddr(bufferCode,pfn_LoadLibraryA,(DWORD)LoadLibraryA);//步骤六的函数,将唯一标识符替换为真实地址
		ReplaceParamAddr(bufferCode,pfn_MessageBoxA,(DWORD)MessageBoxA);
		//写入字符串到目标进程
		const char *szParameter="This is a Parameter!";
		PVOID lpString=VirtualAllocEx(hRemoteProcess,NULL,strlen(szDll)+strlen(szParameter)+2,
			MEM_COMMIT,	PAGE_READWRITE);
		assert(lpString!=NULL);
		WriteProcessMemory(hRemoteProcess,lpString,(LPVOID)szDll,strlen(szDll)+1,NULL);
		WriteProcessMemory(hRemoteProcess,(LPVOID)((DWORD)lpString+strlen(szDll)+1),
			(LPVOID)szParameter, strlen(szParameter)+1,NULL);
		ReplaceParamAddr(bufferCode,szLibrary,(DWORD)lpString);//同理,替换为字符串在目标进程中的地址
		ReplaceParamAddr(bufferCode,szMsg,(DWORD)lpString+strlen(szDll)+1);
		//写入执行代码到目标进程
		PVOID lpBaseAddr=VirtualAllocEx(hRemoteProcess,NULL,codeSize,MEM_COMMIT,
			PAGE_EXECUTE_READWRITE);
		assert(lpBaseAddr!=NULL);
		iRet=WriteProcessMemory(hRemoteProcess,lpBaseAddr,(LPVOID)bufferCode,codeSize,NULL);
		assert(iRet!=0);
		CreateRemoteThread(hRemoteProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)lpBaseAddr,
			0, NULL, NULL);
		return iRet;
	}

xp下测试效果图(win10同样测试通过,理由和”Dll注入方法之一“一样,注意字符串问题)  

技术分享

按下确定后,会继续再弹出一个窗口

技术分享

 

Dll注入方法之二

标签:

原文地址:http://www.cnblogs.com/dalgleish/p/5438982.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!