目前windows下注入dll的技术大体上就是两种
1:钩子 SetWindowsHook
2:创建远程线程 CreateRemoteThread
尽管都能实现远程注入dll,但都难逃杀毒软件的法眼,特别是 CreateRemoteThread
一般都被杀毒软件监控的很牢,这里提供一个巧妙的方法能够利用目标进程(确切地说是线程)
自己主动调用LoadLibrary装载dll.我们想一想,windows下vc调试器可以调试正在运行的进程,功能很是强大,那可不可以
借鉴调试器的机理呢?完全可以,调试器的机理大致分为以下几步:
1:OpenProcess() 获取目标进程句炳,拥有调试权限(我们这里不需要用这个权限)
2:SuspendThread() 挂起目标进程的主线程
3:GetThreadContext(), SetThreadContext() 读写目标线程的当前CPU上下文信息。
4:ReadProcessMemory(), WriteProcessMemory() 读写目标进程内存数据。好了,这里面就给我们提供了很好的方法,是什么?对了就是 GetThreadContext(), SetThreadContext()
这两个API函数,它俩不但是哥们,也是我们最好的朋友(亲一下)。
下面给出代码:
1:我们自己的dll
BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved
{
//很简单,我们不搞破坏,紧紧弹个信息框。
::MessageBox(0,"嘿嘿嘿!!!",0,0);
return TRUE;
}
2:我们的主程序
typedef HMODULE (__stdcall *pLoadLibrary)(LPCSTR lpLibFileName);
void test()
{
//不能直接使用常量字符串,否则会引起目标进程读取数据异常。
char dllname[] = {'c',':','\\','d','l','l','t','e','s','t','.','d','l','l','\0'};
//必须用2088770939这个 LoadLibrary 函数的绝对地址(在我的xp下是这个地址,使用时应该在自己的windows下获取)
pLoadLibrary pFunc = pLoadLibrary(2088770939);
//调用LoadLibrary,因为LoadLibrary函数在windows下每个进程中绝对地址都是一样的。
pFunc(dllname);
return;
}
//以下是控制注入的函数
#include <windows.h>
void Inject()
{
CONTEXT context;
memset(&context,0,sizeof(context));
context.ContextFlags = CONTEXT_CONTROL;
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
ZeroMemory( &siStartInfo, sizeof(STARTUPINFO));
siStartInfo.cb = sizeof(STARTUPINFO);
BOOL bOk = CreateProcess(NULL,
"C:\\WINDOWS\\system32\\notepad.exe", // command line
NULL, // process security attributes
NULL, // primary thread security attributes
FALSE, // handles are inherited
0, // creation flags
NULL, // use parent's environment
"C:\\WINDOWS\\system32\\",// use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo); // receives PROCESS_INFORMATION
::WaitForInputIdle(piProcInfo.hProcess,-1);
//为目标进程分配空间
LPVOID pRemote = ::VirtualAllocEx(piProcInfo.hProcess,0,4096,MEM_RESERVE|MEM_COMMIT,PAGE_EXECUTE_READWRITE);
DWORD dWriten = 0,id = 0;
//将test函数写入目标进程
::WriteProcessMemory(piProcInfo.hProcess,pRemote,(LPVOID)test,1024,&dWriten);
//挂起目标进程的主线程
::SuspendThread(piProcInfo.hThread);
//获取目标线程的CPU上下文信息
i = ::GetThreadContext(piProcInfo.hThread,&context);
//更改Eip指令为我们拷贝好的test函数
context.Eip = (long)pRemote;
//设置目标线程的CPU上下文信息
i = ::SetThreadContext(piProcInfo.hThread,&context);
//唤醒目标线程,
::ResumeThread(piProcInfo.hThread);
//目标线程此时就会执行我们的test函数了,执行完后还会继续沿着
//自己原先的代码序列执行下去。
return 0;
}以上代码都经过测试,的确比较“不动声色”的完成了dll的注入,杀毒软件
也不会有所觉察(除非定时扫描进程dll模块。那系统会比较慢)。
1:钩子 SetWindowsHook
2:创建远程线程 CreateRemoteThread
尽管都能实现远程注入dll,但都难逃杀毒软件的法眼,特别是 CreateRemoteThread
一般都被杀毒软件监控的很牢,这里提供一个巧妙的方法能够利用目标进程(确切地说是线程)
自己主动调用LoadLibrary装载dll.我们想一想,windows下vc调试器可以调试正在运行的进程,功能很是强大,那可不可以
借鉴调试器的机理呢?完全可以,调试器的机理大致分为以下几步:
1:OpenProcess() 获取目标进程句炳,拥有调试权限(我们这里不需要用这个权限)
2:SuspendThread() 挂起目标进程的主线程
3:GetThreadContext(), SetThreadContext() 读写目标线程的当前CPU上下文信息。
4:ReadProcessMemory(), WriteProcessMemory() 读写目标进程内存数据。好了,这里面就给我们提供了很好的方法,是什么?对了就是 GetThreadContext(), SetThreadContext()
这两个API函数,它俩不但是哥们,也是我们最好的朋友(亲一下)。
下面给出代码:
1:我们自己的dll
BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved
{
//很简单,我们不搞破坏,紧紧弹个信息框。
::MessageBox(0,"嘿嘿嘿!!!",0,0);
return TRUE;
}
2:我们的主程序
typedef HMODULE (__stdcall *pLoadLibrary)(LPCSTR lpLibFileName);
void test()
{
//不能直接使用常量字符串,否则会引起目标进程读取数据异常。
char dllname[] = {'c',':','\\','d','l','l','t','e','s','t','.','d','l','l','\0'};
//必须用2088770939这个 LoadLibrary 函数的绝对地址(在我的xp下是这个地址,使用时应该在自己的windows下获取)
pLoadLibrary pFunc = pLoadLibrary(2088770939);
//调用LoadLibrary,因为LoadLibrary函数在windows下每个进程中绝对地址都是一样的。
pFunc(dllname);
return;
}
//以下是控制注入的函数
#include <windows.h>
void Inject()
{
CONTEXT context;
memset(&context,0,sizeof(context));
context.ContextFlags = CONTEXT_CONTROL;
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
ZeroMemory( &siStartInfo, sizeof(STARTUPINFO));
siStartInfo.cb = sizeof(STARTUPINFO);
BOOL bOk = CreateProcess(NULL,
"C:\\WINDOWS\\system32\\notepad.exe", // command line
NULL, // process security attributes
NULL, // primary thread security attributes
FALSE, // handles are inherited
0, // creation flags
NULL, // use parent's environment
"C:\\WINDOWS\\system32\\",// use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo); // receives PROCESS_INFORMATION
::WaitForInputIdle(piProcInfo.hProcess,-1);
//为目标进程分配空间
LPVOID pRemote = ::VirtualAllocEx(piProcInfo.hProcess,0,4096,MEM_RESERVE|MEM_COMMIT,PAGE_EXECUTE_READWRITE);
DWORD dWriten = 0,id = 0;
//将test函数写入目标进程
::WriteProcessMemory(piProcInfo.hProcess,pRemote,(LPVOID)test,1024,&dWriten);
//挂起目标进程的主线程
::SuspendThread(piProcInfo.hThread);
//获取目标线程的CPU上下文信息
i = ::GetThreadContext(piProcInfo.hThread,&context);
//更改Eip指令为我们拷贝好的test函数
context.Eip = (long)pRemote;
//设置目标线程的CPU上下文信息
i = ::SetThreadContext(piProcInfo.hThread,&context);
//唤醒目标线程,
::ResumeThread(piProcInfo.hThread);
//目标线程此时就会执行我们的test函数了,执行完后还会继续沿着
//自己原先的代码序列执行下去。
return 0;
}以上代码都经过测试,的确比较“不动声色”的完成了dll的注入,杀毒软件
也不会有所觉察(除非定时扫描进程dll模块。那系统会比较慢)。
不过这种方法对于有驱动保护的某些游戏来说就不行,
注入还得从ring0层,才有可能成功.不过游戏多半都有非法模块检测.
非法模块检测比较肤浅的方法是可以通过更改注入的dll文件名来绕过去。
如果非法模块检测中定期调用合法模块的函数的话就不行了,
更好的办法是在合法dll里注入代码,这样的方式目前应该还没有办法
实现。但是任何非法模块检测都是有漏洞可利用的,简单的说就是利用
检测周期的间隔来注入dll,dllmain函数吧进程的所有线程都suspend
掉,然后搜索内存数据,读写等,完成外挂的行为后再把进程内所有的
线程都唤醒,最后不论非法模块检测程序如何动作,都无所谓了。这只是我的一点想法,有时间我验证一下,看看。其实只要不是安全软件,
注入的代码没必要长期存在目标进程内,只要在短时间内完成了想要的功能
就可以了。
的确,可以构造shellcode,通过我的方法让目标进程执行这个shellcode
因为VirtualAllocEx这个函数操作系统经常会调用,很多进程都有内存,
请求,操作系统必须通过该函数给这些进程分配虚拟内存,这个函数的调用率
如此之高,杀毒软件不会hook的,否则影响了虚拟内存的分配速度,会严重
影响系统性能,你说呢?
hook NtSetContextThread 当然可以,但如果调试程序的话难免不受影响
而且如果把注入程序更名成调试程序的话,和容易骗过杀毒软件
1:SuspendThread() 挂起目标进程的一个线程
2:GetThreadContext(),保存CPU上下文信息。
3:ReadProcessMemory(),保存一段不常使用地址的内存,比如一般pe开始位置0x4000000是可以用的。
4:构造一段极短的初始化代码,WriteProcessMemory()到目标进程中,用来分配内存,创建一个在分配内存上的并处于挂起状态的Thread_2,当前进程通告自己状态并等待。。
5:利用SetThreadContext() ,运行上述代码,等待其结束。
6:写目标代码到新分配的内存中,设置Thread_2到目标代码并运行。
7:恢复原来的内存和ThreadContext。最新的注入方式应该是acl办法,不过没有看到详细的资料公开,希望楼主可以研究研究并公开给大家,呵呵
不过这种方法很常见,杀软应该是会报的
其他方法还有detours,CreateRemoteThread,更底层的修改SSDT等等方法
现在n多人都不知道mbr了,要不去年也不会搞得那么热闹。10年前n多人敢手动修复,现在呢.................
char dllname[] = {'c',':','\\','d','l','l','t','e','s','t','.','d','l','l','\0'};没遇到过,这是为什么呢?
"adadasdasdasd"会被放到pe文件的.data节,然后复制到cllname,但是复制到目标进程的只有那个函数的代码,因此字符串的赋值必须完全由指令完成。
<input type="button" onclick="alert('*** 终于把难看的 (code=HTML)( /code) 去掉了,呵呵 ***')" value="点我呀!">][/code]