某位牛人在某本很牛的汇编书中,介绍了一种隐蔽执行代码的方法,结尾的时候,作者写下了“希望读者负责任地使用这些代码”。 我曾经寄希望于木马作者不至于将某些技术用于木马,但很显然,我估计错了。 一般我们认为,木马应当开启一个进程,以便执行自身代码,但很快就有人想到了“线程”这个好东西——不需要额外开启一个进程,意味着任务管理器中不会多出一个陌生进程,隐蔽性无疑大大提高了。不过这种方法有个弱点,一般需要将希望执行的代码放置在一个dll文件中,再加载到某个熟知进程中去。这种方法在水平越来越高的计算机用户面前,已经不那么保险了——各种进程察看软件可以轻而易举地看到,这个进程加载了哪些文件,陌生的dll文件很可能被有一定经验的用户识破,进而被铲除掉。 那么,有办法不使用dll文件而在进程中开启一个线程并执行代码么? 显然,有。 以下内容,一般人员可以忽略 Windows的API中有数个函数能够向目标进程的内存空间中写入数据,同时还有数个函数能够修改内存页的属性——通俗一点地说,就是任何人都能够把任何东西写到任何一个进程中去,并作为代码来执行。 但是写入的数据并不一定能(事实上,几乎是一定不能)顺利运行,因为写入的代码必须是已编译好的机器码,而在已编译好的机器码中,内存地址是固定的。换言之,这些代码必须被写到一个固定的内存地址,才可以正常运行。然而,那个期望的地址,一般早就被其他代码占据了,强行向那个地址写入数据只会导致目标进程的崩溃。而如果不写到那个地址呢?那么木马代码中所有跳转指令都指向错误地址——结局仍然是崩溃。 那么,dll文件为什么可以加载并执行呢?事实上dll文件被加载后,Windows加载器将根据dll被加载到的位置,自动修改代码内的地址,使得代码能适应当前内存地址,进而可以被正常执行。具体信息,可以自行查阅 RVA(虚拟相对地址)的相关信息。 这就可以解释为什么一般的木马要使用dll来注入进程。 但是,如果使用汇编语言,就会知道,汇编语言中有一种“代码自定位”技术。代码可以知道自己目前被加载到什么地址,因此,精心编写的汇编代码翻译而成的机器码,可以被放置到任意内存地址,都可以正常运行——不需要Windows加载器修改RVA值。 结论 即使没有可疑进程,也没有可疑dll,仍然可以执行代码——只需要一小段看似无害的代码,向某个进程中写入一些东西。 能够用自定位代码的人,当然能够让所有的杀毒软件都不报警,这毫无疑问。 因此,这是一个可怕的事实,更可怕的是我们必须面对…… 或许,拦截所有的危险函数调用能够在一定程度上防止这一切的发生吧…… |