📄 进程注入的三种方法 - benny5609的专栏 - csdnblog.htm
字号:
<SCRIPT src="进程注入的三种方法 - benny5609的专栏 - CSDNBlog.files/benny5609.aspx"></SCRIPT>
</DIV><SPAN id=RecentVisitors>
<H3 class=listtitle>最近访客</H3>
<TABLE border=0>
<TBODY>
<TR>
<TD align=middle><IMG
onmouseover="try{BlogShowme(event, 'hesinyhe')}catch(ex){}"
alt="hesinyhe 的头像" src="进程注入的三种方法 - benny5609的专栏 - CSDNBlog.files/2.jpg"
border=0><BR><A title="访问时间: 9/25/2007 1:50:07 PM"
href="http://blog.csdn.net/hesinyhe/">hesinyhe</A></TD>
<TD align=middle><IMG
onmouseover="try{BlogShowme(event, 'ilovepd4')}catch(ex){}"
alt="ilovepd4 的头像"
src="D:\work\tools\vc6.0\调试内存泄漏\进程注入的三种方法 - benny5609的专栏 - CSDNBlog.files\2(1).jpg"
border=0><BR><A title="访问时间: 9/20/2007 10:24:02 PM"
href="http://blog.csdn.net/ilovepd4/">ilovepd4</A></TD></TR>
<TR>
<TD align=middle><IMG
onmouseover="try{BlogShowme(event, 'eagleoflove')}catch(ex){}"
alt="eagleoflove 的头像"
src="D:\work\tools\vc6.0\调试内存泄漏\进程注入的三种方法 - benny5609的专栏 - CSDNBlog.files\2(2).jpg"
border=0><BR><A title="访问时间: 9/19/2007 12:52:59 AM"
href="http://blog.csdn.net/eagleoflove/">eagleoflove</A></TD>
<TD align=middle><IMG
onmouseover="try{BlogShowme(event, 'liluvu')}catch(ex){}" alt="liluvu 的头像"
src="D:\work\tools\vc6.0\调试内存泄漏\进程注入的三种方法 - benny5609的专栏 - CSDNBlog.files\2(3).jpg"
border=0><BR><A title="访问时间: 9/18/2007 4:54:35 PM"
href="http://blog.csdn.net/liluvu/">liluvu</A></TD></TR></TBODY></TABLE></SPAN>
<H3 class=listtitle>文章</H3>
<UL class=list>
<LI class=listitem><A
href="http://blog.csdn.net/benny5609/category/334908.aspx">Algorithm</A><A
href="http://blog.csdn.net/benny5609/category/334908.aspx/rss">(RSS)</A>
<LI class=listitem><A
href="http://blog.csdn.net/benny5609/category/333851.aspx">C/C++</A><A
href="http://blog.csdn.net/benny5609/category/333851.aspx/rss">(RSS)</A>
<LI class=listitem><A
href="http://blog.csdn.net/benny5609/category/334688.aspx">DLL</A><A
href="http://blog.csdn.net/benny5609/category/334688.aspx/rss">(RSS)</A>
<LI class=listitem><A
href="http://blog.csdn.net/benny5609/category/335554.aspx">ETC.</A><A
href="http://blog.csdn.net/benny5609/category/335554.aspx/rss">(RSS)</A>
<LI class=listitem><A
href="http://blog.csdn.net/benny5609/category/333964.aspx">Socket</A><A
href="http://blog.csdn.net/benny5609/category/333964.aspx/rss">(RSS)</A>
<LI class=listitem><A
href="http://blog.csdn.net/benny5609/category/335065.aspx">Thread</A><A
href="http://blog.csdn.net/benny5609/category/335065.aspx/rss">(RSS)</A>
<LI class=listitem><A
href="http://blog.csdn.net/benny5609/category/337489.aspx">WinCE</A><A
href="http://blog.csdn.net/benny5609/category/337489.aspx/rss">(RSS)</A>
<LI class=listitem><A
href="http://blog.csdn.net/benny5609/category/335556.aspx">Windows</A><A
href="http://blog.csdn.net/benny5609/category/335556.aspx/rss">(RSS)</A></LI></UL>
<H3 class=listtitle>收藏</H3>
<UL class=list>
<LI class=listitem><A
href="http://blog.csdn.net/benny5609/category/333849.aspx">C++</A></LI></UL>
<H3 class=listtitle>相册</H3><!--category title-->
<UL class=list></UL>
<H3 class=listtitle>杂谈</H3>
<UL class=list></UL>
<H3 class=listtitle>存档</H3>
<UL class=list>
<LI><A
href="http://blog.csdn.net/benny5609/archive/2007/09.aspx">2007年09月(114)</A></LI></UL><SPAN
id=Anthem_RecentComments_ltlComments__><SPAN id=RecentComments_ltlComments>
<H3 class=listtitle>最近评论</H3>
<UL class=list>
<LI class=listitem>pluminsnow:<A title="点击查看《回复:VC动态链接库DLL 》"
href="http://blog.csdn.net/benny5609/archive/2007/09/13/1784038.aspx#722430">谢谢</A></LI></UL></SPAN></SPAN><BR><BR></DIV>
<DIV id=main>
<DIV class=Tag>
<SCRIPT language=javascript
src="进程注入的三种方法 - benny5609的专栏 - CSDNBlog.files/urltag.aspx"></SCRIPT>
<DIV style="CLEAR: both"></DIV></DIV><SPAN class=PreAndNext
id=viewpost.ascx_PreviousAndNextEntriesUp>
<DIV align=center><A
href="http://blog.csdn.net/benny5609/archive/2007/09/13/1784434.aspx">上一篇: 浅谈HOOK技术在VC编程中的应用
</A> | <A
href="http://blog.csdn.net/benny5609/archive/2007/09/13/1784051.aspx">下一篇: VC++动态链接库编程之非MFC
DLL</A></DIV></SPAN><BR>
<SCRIPT>function StorePage(){d=document;t=d.selection?(d.selection.type!='None'?d.selection.createRange().text:''):(d.getSelection?d.getSelection():'');void(keyit=window.open('http://www.365key.com/storeit.aspx?t='+escape(d.title)+'&u='+escape(d.location.href)+'&c='+escape(t),'keyit','scrollbars=no,width=475,height=575,left=75,top=20,status=no,resizable=yes'));keyit.focus();}</SCRIPT>
<DIV class=post>
<DIV class=postTitle>
<SCRIPT src="进程注入的三种方法 - benny5609的专栏 - CSDNBlog.files/vote.js"></SCRIPT>
<A href="http://blog.csdn.net/benny5609/archive/2007/09/13/1784273.aspx"><IMG
height=13 src="进程注入的三种方法 - benny5609的专栏 - CSDNBlog.files/authorship.gif"
width=15 border=0> 进程注入的三种方法</A>
<SCRIPT src="进程注入的三种方法 - benny5609的专栏 - CSDNBlog.files/count.htm"></SCRIPT>
</DIV>
<DIV class=postText>一般来说,这个问题有三种可能的解决方案:<BR> 1. 把你的代码放到一个DLL中;然后用 windows
钩子把它映射到远程进程。<BR> 2. 把你的代码放到一个DLL中;然后用 CreateRemoteThread 和 LoadLibrary
把它映射到远程进程。<BR> 3.
不用DLL,直接复制你的代码到远程进程(使用WriteProcessMemory)并且用CreateRemoteThread执行之。在这里有详细的说明:<BR> <BR> Ⅰ.
Windows 钩子<BR> <BR> 示例程序:HookSpy 和
HookInjEx<BR> <BR> Windows钩子的主要作用就是监视某个线程的消息流动。一般可分为:<BR> 1.
局部钩子,只监视你自己进程中某个线程的消息流动。<BR> 2. 远程钩子,又可以分为:<BR> a.
特定线程的,监视别的进程中某个线程的消息;<BR> b. 系统级的,监视整个系统中正在运行的所有线程的消息。<BR> <BR>
如果被挂钩(监视)的线程属于别的进程(情况2a和2b),你的钩子过程(hook
procedure)必须放在一个动态连接库(DLL)中。系统把这包含了钩子过程的DLL映射到被挂钩的线程的地址空间。Windows会映射整个DLL而不仅仅是你的钩子过程。这就是为什么windows钩子可以用来向其他线程的地址空间注入代码的原因了。<BR> <BR>
在这里我不想深入讨论钩子的问题(请看MSDN中对SetWindowsHookEx的说明),让我再告诉你两个文档中找不到的诀窍,可能会有用:<BR> 1.
当SetWindowHookEx调用成功后,系统会自动映射这个DLL到被挂钩的线程,但并不是立即映射。因为所有的Windows钩子都是基于消息的,直到一个适当的事件发生后这个DLL才被映射。比如:<BR> 如果你安装了一个监视所有未排队的(nonqueued)的消息的钩子(WH_CALLWNDPROC),只有一个消息发送到被挂钩线程(的某个窗口)后这个DLL才被映射。也就是说,如果在消息发送到被挂钩线程之前调用了UnhookWindowsHookEx那么这个DLL就永远不会被映射到该线程(虽然SetWindowsHookEx调用成功了)。为了强制映射,可以在调用SetWindowsHookEx后立即发送一个适当的消息到那个线程。<BR> <BR>
同理,调用UnhookWindowsHookEx之后,只有特定的事件发生后DLL才真正地从被挂钩线程卸载。<BR> <BR> 2.
当你安装了钩子后,系统的性能会受到影响(特别是系统级的钩子)。然而如果你只是使用的特定线程的钩子来映射DLL而且不截获如何消息的话,这个缺陷也可以轻易地避免。看一下下面的代码片段:<BR> BOOL
APIENTRY DllMain( HANDLE hModule,<BR> DWORD ul_reason_for_call,<BR> LPVOID
lpReserved )<BR> {<BR> if( ul_reason_for_call == DLL_PROCESS_ATTACH )<BR>
{<BR> //用 LoadLibrary增加引用次数<BR> char lib_name[MAX_PATH]; <BR>
::GetModuleFileName( hModule, lib_name, MAX_PATH );<BR> ::LoadLibrary(
lib_name );<BR> <BR> // 安全卸载钩子<BR> ::UnhookWindowsHookEx( g_hHook );<BR>
} <BR> return TRUE;<BR> }<BR> <BR>
我们来看一下。首先,我们用钩子映射这个DLL到远程线程,然后,在DLL被真正映射进去后,我们立即卸载挂钩(unhook)。一般来说当第一个消息到达被挂钩线程后,这DLL会被卸载,然而我们通过LoadLibrary来增加这个DLL的引用次数,避免了DLL被卸载。<BR> <BR>
剩下的问题是:使用完毕后如何卸载这个DLL?UnhookWindowsHookEx不行了,因为我们已经对那个线程取消挂钩(unhook)了。你可以这么做:<BR>
○在你想要卸载这个DLL之前再安装一个钩子;<BR> ○发送一个“特殊”的消息到远程线程;<BR> ○在你的新钩子的钩子过程(hook
procedure)中截获该消息,调用FreeLibrary 和
(译者注:对新钩子调用)UnhookwindowsHookEx。<BR> 现在,钩子只在映射DLL到远程进程和从远程进程卸载DLL时使用,对被挂钩线程的性能没有影响。也就是说,我们找到了一种(相比第二部分讨论的LoadLibrary技术)WinNT和Win9x下都可以使用的,不影响目的进程性能的DLL映射机制。<BR> <BR>
但是,我们应该在何种情况下使用该技巧呢?通常是在DLL需要在远程进程中驻留较长时间(比如你要子类[subclass]另一个进程中的控件)并且你不想过于干涉目的进程时比较适合使用这种技巧。我在HookSpy中并没有使用它,因为那个DLL只是短暂地注入一段时间――只要能取得密码就足够了。我在另一个例子HookInjEx中演示了这种方法。HookInjEx把一个DLL映射进“explorer.exe”(当然,最后又从其中卸载),子类了其中的开始按钮,更确切地说我是把开始按钮的鼠标左右键点击事件颠倒了一下。<BR> <BR>
你可以在本文章的开头部分找到HookSpy和HookInjEx及其源代码的下载包链接。<BR> <BR> <BR> Ⅱ.
CreateRemoteThread 和 LoadLibrary 技术<BR> 示例程序:LibSpy<BR>
通常,任何进程都可以通过LoadLibrary动态地加载DLL,但是我们如何强制一个外部进程调用该函数呢?答案是CreateRemoteThread。<BR> 让我们先来看看LoadLibrary和FreeLibrary的函数声明:<BR> <BR> HINSTANCE
LoadLibrary(<BR> LPCTSTR lpLibFileName // address of filename of library
module<BR> );<BR> <BR> BOOL FreeLibrary(<BR> HMODULE hLibModule // handle
to loaded library module<BR> );<BR> <BR> 再和CreateRemoteThread的线程过程(thread
procedure)ThreadProc比较一下:<BR> DWORD WINAPI ThreadProc(<BR> LPVOID lpParameter
// thread data<BR> );<BR> <BR> 你会发现所有的函数都有同样的调用约定(calling
convention)、都接受一个32位的参数并且返回值类型的大小也一样。也就是说,我们可以把LoadLibrary/FreeLibrary的指针作为参数传递给CrateRemoteThread。<BR> <BR>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -