由远程线程注入代码引出来的一些问题

来源:互联网 发布:3个数最小公倍数算法 编辑:程序博客网 时间:2024/04/30 00:40

        昨天小平同学在写一个远程线程注入代码的程序,他注入成功了,能弹出对话框,但是点击确定之后被注入的程序会崩溃掉,我记得自己以前写过是没有问题,但是我是拿VC6写的,调试了一下他的程序,发现原因是向目标进程地址空间中writeprocessmemory的时候,把call checkesp也写进去了,这玩意就是用来检验ESP在函数体中是否被改变,但是这些检验函数的地址在不同PE文件中有可能是不一样的。我在VC6中写的时候直接关掉/gz编译选项就OK了,我发现在VS08中没有这一选项,但有一个缓冲区安全检查的选项,我以为这个就是类似GZ,关掉之后发现还是不行,照样会生成checkesp的代码,在naked函数中也是同样,后来在微软的在线MSDN上查到原来是在05之后将GZ换为了/rtc,将这个关掉之后就OK了。


远程加载与卸载DLL看我这篇文章

http://blog.csdn.net/evi10r/article/details/6724874



总结下远程注入代码需要注意的一些东西:
(1) 远程线程函数体不得使用kernel32.dll,user32.dll以外的函数。因为这个两个模块在各个进程的相对地址是一样的,如果一定要使用其它函数,则必须将函数体写入目标进程空间,其实就是两个进程地址空间中必须加载了同一个DLL并且基址相同。
(2) 不能使用任何字符串常量,因为字符串常量是存放在PE文件里.data这个段里面的,函数里保存的只是相对地址。(片面的)
(3) 去掉编译器的/GZ编译选项,这个选项是用来Enable Stack Frame Run-Time Error Checking。当这个选项打开时,编译器会在每个函数中加入一些代码,用来检验ESP在函数体中是否被改变,但是这些检验函数的地址在不同PE文件中有可能是不一样的。这个编译选项是在VC6里面的,/GZ 在 Visual C++ 2005 中已不推荐使用,微软推荐使用 /RTC(运行时错误检查)。
(4) 不得使用增量链接(incremental linking)。增量链接是编译器为了减少链接时间做的处理,把函数体用一个JMP指令代替,这样就可以随意改变函数的内容,而不用修改CALL指令。
(5) 不要在函数体内使用超过4kb的局部变量。当局部变量的大小超过4kb时,栈指针并不直接改版,而是调用另一个函数来分配内存,这个函数有可能在不同进程中的地址不一样。
(6) 函数体内switch语句中的case不要超过3个,否则编译器会在PE文件中使用跳转表,而这个跳转表有可能在目标进程中并不存在。



vs2008
debug编译:默认启用增量链接  基本运行时检查是两者都选(栈帧,未初始化变量)
release编译:不启用增量链接  基本运行时检查是默认(应该是都不选)


关于增量链接:
可以看我以前的一篇文章
http://blog.csdn.net/evi10r/article/details/6978016
这里再补充点,静态的全局函数是不会有增量链接的,call了之后直接就到函数代码处,不会有JMP过渡。并且在release模式下,会直接把静态全局函数内联。(我调试的是这样的,不知道会不会出现其他情况)。所以在计算函数大小的时候可以声明两个静态全局函数,直接相减,在release模式下得到的就是确定的函数大小。但是debug模式下并没有,还是call的形式,并且两个函数之间有很多cc。


还有跟.textbss段的关系
    Incremental Linking作用不仅仅是在于减少我们重新连接程序所需要的时间,他还是我们调试时能够动态改动代码的前提。调试代码时直接修改了代码,然后VS直接在调试的时候将你的改动反映到程序里去了。这就是VS在Debug模式时动态编译代码的功能。
    实际上这个功能是基于Incremental Linking机制的,而且是使用的Incremental Linking的第二套方案——直接找个大的地儿把修改的函数挪过去。
    .textbss有关键字bss,这就说明实际上这个节没有占据实际的硬盘空间。然后text关键字告诉我们这里段是包含代码的,另外用工具查知这个段有可执行属性更是印证了这个观点。没有代码,那要这个节有啥用呢?
  你想到了么?是的,在VS动态编译的时候,他直接将被修改的函数放到了.textbss节里,然后修改了对应的ILT表项(这应该是保存各个函数JMP中转的表吧),使他指向这个位置。
    说是简单,但实际上这个过程还个细节需要注意——你把我的函数挪地儿了,要是我正在执行这个函数怎么办?实际上,在改了ILT之后立刻会做的,就是检查当前程序所有线程的TIB,如果他们的EIP指向老的函数(它们正在执行老版本函数),我们就修改EIP使其指向新版本函数的对应位置。当然,这实际上暗示了,这个工作非要在调试程序的帮助下不可了。注意动态编译的功能只在Debug版本程序下有效,Release版本是不行的,因为Release版本默认禁用Incremental Linking。
原创粉丝点击