首页
社区
课程
招聘
[旧帖] [原创]惰性DLL注入 0.00雪花
发表于: 2014-2-25 18:55 3926

[旧帖] [原创]惰性DLL注入 0.00雪花

2014-2-25 18:55
3926
首先声明一下,虽然写的原创,但源代码里面还是有一些是网上复制来的,如有雷同,纯属共享.

在看雪注册好多年了....还是个临时会员....多年的挂机后今年我算发现了,几年才涨了点Kx,估计再挂四五年也买不起注册码....

好吧,终于被我发现原来发个优秀的帖子就能成会员.看来只有发贴试试了.

最近在研究DLL注入,就发一篇相关的文档吧...

本帖子的特色就是,惰性注入.为什么叫惰性呢,就是咱们不主动去注.只对程序简单的内存读写(当初以为只读写,360就不会报毒了,结果很失望,一写内存就提示,唉).
与那些什么远程线程注入,修改注册表注入,消息Hook注入,输入法注入,进程启动注入.等我在网上找的注入方式,好像又多了那么一条思路,哈哈.

先说下注入的思路:
在程序必定会执行的某个代码段里面写入一个跳转指令.
跳到咱们用机器码写的加载DLL的代码里面.
然后加载完后跳回去,哈哈不就注入了吗.
惰性这个词就是因为这个来的,因为要等程序自己来执行那个被咱们写入跳转指令的代码段里面来时,咱们的DLL,才会被加载.

思路是这样的,接下来咱们就开始设计咱们的代码吧.

要读写非本身程序的内存我似乎只会简单的
取得窗口句柄-->取得进程句柄-->打开进程并取得操作ID-->然后就用这个操作ID读写内存了.
HWND hwnd = FindWindowA("XLong", "isgoodtime");
                                      \/
                                      \/
DWORD ProcessId;GetWindowThreadProcessId(hwnd,&ProcessId);
                                      \/
                                      \/
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, 0, ProcessId);
                                      \/
                                      \/
BYTE szBuff[5];ReadProcessMemory(hProcess, baseAddress, szBuff, 5, 0);WriteProcessMemory(hProcess,(LPVOID)((long)menoryAddess + 256), exePath, sizeof(exePath), 0);

以上就是读写内存的相关流程及WIN32API.
好,现在咱们能读写咱们要注入的程序里面的内容了.那咱们就先去要注入的程序里面找一个必定会执行的代码片段,再把咱们的跳转命令用写入内存的方式写入到某一行里面(我的例子里面是写在一个按钮事件里面,当咱们惰性注入后,一点这个按钮咱们的DLL就注入了).

好要跳了,但咱们跳到哪里去呢.这就得去目标进程里面去分配一段内存(或利用目标程序的空闲内存也行),分完段内存后,咱们就要往里面写入咱们的加载DLL的相关机器码了.会用到的相关WIN32API我都列出来.
LPVOID menoryAddess = VirtualAllocEx(hProcess,0,512,MEM_COMMIT ,PAGE_READWRITE);//分配一块内存放代码
                                      \/
                                      \/
WriteProcessMemory(hProcess, menoryAddess , szCodeBuff, sizeof(szCodeBuff), 0);//将传入的代码 写入分配的内存中

经过以上的分配内存,写入机器码后,那么当程序点按钮时咱们的DLL就会被回载了.

以上关于咱们的注入程序的流程是走完了.但费了我相当多的脑力的还是那段机器码要怎么写.由于 我对汇编不太熟悉,真是绞尽了脑汁才写好.
下面我也介绍一下机器的流程吧.随带列出一下要用到的WIN32API.

机器码流程:
当程序跳到咱们的代码时. 由于咱们的惰性,所以不知道程序到底什么时候会跳进来,所以咱们要在这段代码里来恢复之前咱们的"注入程序"里面修改成跳转的代码.(所以上面所写的程序流程里还缺了一步就是把要改的那个地方的代码先保存5字节.)

然后要能修改程序的内存,居然还要修改内存的保护属性....(我查了许多资料才解决掉这个错误,许多资料介绍了用WriteProcessMemory可以写,而自己简单的mov却会报错,原来是WriteProcessMemory这个函数会自动判断是否能写,不能的会改成可写,写完后又把不可写改回来)

好现在咱们把原来的五字节代码恢复了,剩下来就得加载咱们的DLL了.再不加载就完完了,因为跳转的代码刚刚被咱们恢复了,不会再来执行咱们这段代码了,哈哈.
加载DLL的流程比较简单(只是从简了,真要写没这么简单,呵呵.),首先把咱们的DLL路径压栈,再一调用系统的LoadLibraryA()函数,咱们的DLL就加载进来啦,哈哈.

加载完咱们就跳回程序原来的代码中去,让他去做自己的事咯(感觉咱们应该清理这段由咱们分配的内存,不过我不会...).

思路和流程都介绍完了.下面咱就根据这思路去看看我写的一段示例代码吧,哈哈.不过提前说下,咱们那卸载DLL的代码我没完成.抱歉抱歉,嘿嘿.

BOOL PostDataToProcess(HWND hwnd ,LPVOID baseAddress,char * DLLname,BOOL InOrFree)
{
	SeDebugPrivilege();
	DWORD ProcessId;
	GetWindowThreadProcessId(hwnd,&ProcessId);
	HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, 0, ProcessId);
	BYTE szBuff[5];
	ReadProcessMemory(hProcess, baseAddress, szBuff, 5, 0);//读取原地址的五个字节保存下来
	LPVOID menoryAddess = VirtualAllocEx(hProcess,0,512,MEM_COMMIT ,PAGE_READWRITE);//分配一块内存放代码

	if(InOrFree)//如果为注入
	{
		char exePath[256];
		GetModuleFileNameA(NULL, exePath, 256);//取得程序的绝对路径
		for(int i = sizeof(exePath);i>=0;i--)//拼接DLL路径
		{
			if(exePath[i] == '\\')
			{
				for(int j = i+1;j<getlen(DLLname)+i+1;j++)
				{
					exePath[j] = DLLname[j - i - 1];
				}
				exePath[getlen(DLLname)+i+1] = '\0';
				break;
			}
		}

		WriteProcessMemory(hProcess,(LPVOID)((long)menoryAddess + 256), exePath, sizeof(exePath), 0);//将DLL路径 写入分配的内存中

		LPCSTR lpFileName = "kernel32";
		HMODULE hModule = GetModuleHandleA(lpFileName);
		if(hModule == NULL)
		{
			hModule = LoadLibraryA(lpFileName);
		}
		if(hModule != NULL)
		{
			//FARPROC farproc = GetProcAddress(hModule,"GetModuleHandleA");
			//FARPROC farproc = GetProcAddress(hModule,"GetProcAddress");
			FARPROC LOADLIBRARYA = GetProcAddress(hModule,"LoadLibraryA");
			FARPROC VIRTUALPROTECT = GetProcAddress(hModule,"VirtualProtect");
			if(LOADLIBRARYA != 0 && VIRTUALPROTECT != 0)
			{
				BYTE szCodeBuff[256] = //存放注入DLL的汇机器码
				{
					0x68,0x00,0x00,0x00,0x00,//PUSH 0 要可以写入的内存,否则将失败❶
					0x6A,0x40,//PUSH 40
					0x68,0x80,0x00,0x00,0x00,//PUSH 80
					0x68,0x00,0x00,0x00,0x00,//PUSH 这里为要修改属性的内存地址❷
					//0xFF,0x15,0x00,0x00,0x00,0x00,//CALL VirtualProtect❸
					0xBB,0x00,0x00,0x00,0x00,//mov ebx,kernel32.VirtualProtect❸
					0xFF,0xD3,//call ebx

					0xC6,0x05,0x00,0x00,0x00,0x00,0x00,//mov byte ptr ds:[40102A],0BB❹31
					0xC7,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//mov dword ptr ds:[40102B],目标程序.004011C0❺

					0x68,0x00,0x00,0x00,0x00,//push 0046C878; /FileName = "user32.dll"❻
					//0xFF,0x15,0x00,0x00,0x00,0x00,//call dword ptr ds:[<&KERNEL32.LoadLibrar>; LoadLibraryA❼
					0xBB,0x00,0x00,0x00,0x00,//mov ebx,kernel32.VirtualProtect❼
					0xFF,0xD3,//call ebx
					0xE9,0x00,0x00,0x00,0x00 //jmp dword ptr ds:[46669C]; 目标程序.00417160❽
				};

				PushAddressToBYTE(szCodeBuff,(LPVOID)((long)menoryAddess + 256 + strlen(exePath) + 1),1);//❶
				PushAddressToBYTE(szCodeBuff,baseAddress,13);//❷
				PushAddressToBYTE(szCodeBuff,(LPVOID)VIRTUALPROTECT,18);//❸

				PushAddressToBYTE(szCodeBuff,baseAddress,26);//❹
				szCodeBuff[30] = szBuff[0];//❹
				PushAddressToBYTE(szCodeBuff,(LPVOID)((long)baseAddress+1),33);//❺
				PushAddressToBYTE(szCodeBuff,szBuff,37);//❺-----

				PushAddressToBYTE(szCodeBuff,(LPVOID)((long)menoryAddess + 256),42);//❻DLL 路径
				PushAddressToBYTE(szCodeBuff,(LPVOID)LOADLIBRARYA,47);//❼//LoadLibraryA 函数地址
				INT32 jmptoaddress = (long)baseAddress - (long)menoryAddess - 58;//计算回跳地址
				PushAddressToBYTE(szCodeBuff,(LPVOID)jmptoaddress,54);//❽些值为计算所得

				WriteProcessMemory(hProcess, menoryAddess , szCodeBuff, sizeof(szCodeBuff), 0);//将传入的代码 写入分配的内存中
			}
		}
		else
		{
			return false;
		}
	}
	else
	{
		LPCSTR lpFileName = "kernel32";
		HMODULE hModule = LoadLibraryA(lpFileName);
		FARPROC farproc  = GetProcAddress(hModule,"FreeLibrary");
		BYTE szCodeBuff[256];//存放卸载DLL的代码
		WriteProcessMemory(hProcess, menoryAddess , szCodeBuff, sizeof(szCodeBuff), 0);//将传入的代码 写入分配的内存中
	}
	BYTE JmpCod[] = {0xE9,0x00,0x00,0x00,0x00};
	INT32 jmptoaddress = (long)menoryAddess - 5 - (long)baseAddress;//计算跳转地址
	PushAddressToBYTE(JmpCod,(LPVOID)jmptoaddress,1);//填充跳转地址
	WriteProcessMemory(hProcess, baseAddress , JmpCod, 5, 0);//修改相关地址跳到传入的代码处开始执行
	return true;
}


整个示例打包上传了,详情看附件

[课程]Android-CTF解题方法汇总!

上传的附件:
收藏
免费 0
支持
分享
最新回复 (16)
雪    币: 110
活跃值: (189)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
这个属于代码注入不?另外请教一下,除了上面提到的注入方法,楼主有没有不用WriteProcessMemory而实现注入的方法啊 ,指点一下呀 ~~~
2014-2-26 09:31
0
雪    币: 98
活跃值: (59)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
输入法注入,lsp网络过滤器注入,文件劫持注入都不需要writeprocessmemory
2014-2-26 09:43
0
雪    币: 110
活跃值: (189)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
多谢多谢
2014-2-26 09:57
0
雪    币: 7068
活跃值: (3517)
能力值: ( LV12,RANK:340 )
在线值:
发帖
回帖
粉丝
5
这种注入,我觉得一般杀毒软件只要开着保护,就会拦截,因为你写进程内存包含call LoadLibrary了。不知道杀软检测不检测shellcode。

如果杀软只检测远线程的话,与其这样"惰性"注入。不如挂起主线程,保存线程上下文,修改EIP为shellcode地址。执行完毕在shellcode代码最后写个死jmp。
每隔一段时间检测EIP是否在死jmp处。如果是那就恢复原线程上下文。释放内存地址。
2014-2-26 10:05
0
雪    币: 1392
活跃值: (4867)
能力值: ( LV13,RANK:240 )
在线值:
发帖
回帖
粉丝
6
一个WriteProcessMemory你就挂了
2014-2-26 10:18
0
雪    币: 11
活跃值: (32)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
7
是啊,在这个地方就挂了,现在不知道怎么办了,求高人指点.
2014-2-26 13:03
0
雪    币: 11
活跃值: (32)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
8
[QUOTE=bxc;1263855]这种注入,我觉得一般杀毒软件只要开着保护,就会拦截,因为你写进程内存包含call LoadLibrary了。不知道杀软检测不检测shellcode。QUOTE]

随便写什么都拦截.不一定要包含Call LoadLibrary .这样感觉跟远程线程差不多了.
2014-2-26 13:07
0
雪    币: 31
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
WriteProcessMemory太老了,容易检测,而且大多数程序要求防护的话是没办法注入的
如果是被拦截的话可以考虑把调用改成其他形式,不过如果对方把kernel挂了的话,你怎么做都会被发现的
这种情况下最好是漏洞什么的,才方便,不会被检测
2014-2-26 14:22
0
雪    币: 102
活跃值: (97)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
这个主动防御会报毒吗?
2014-3-10 21:41
0
雪    币: 24
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
有防护的。。。这个和远线程是一个道理。
2014-3-11 02:44
0
雪    币: 203
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
学习了,谢谢!
2014-4-1 16:55
0
雪    币: 3496
活跃值: (749)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
好贴,学习3,谢谢了!
2014-4-24 07:48
0
雪    币: 9
活跃值: (24)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
mark 学习下
2014-4-24 08:01
0
雪    币: 144
活跃值: (335)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
不错的东西 mark
2014-8-5 16:49
0
雪    币: 7
活跃值: (49)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
不错的思路。。

另外。。注入进去的东西。除了那个Hook的部分。完全可以用C写。参考UAC Whitelist那个注入的函数..
2014-8-5 22:09
0
雪    币: 3
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
值得学习借鉴下
2014-8-7 17:04
0
游客
登录 | 注册 方可回帖
返回
//