一篇看雪的病毒重定位的帖子
时间:2010-09-16 来源:wsnhyjj
以下是原帖的内容,作者是xfish,谢谢xfish的付出!

1.2 1.病毒的重定位技术
病毒的重定位技术应该也算是最基本和最有用的技术之一了,其实重定位技术只要是对外壳开发比较熟悉的朋友都应该很熟悉了。重定位顾名思义重新定位地址。上篇文章中我们已经讲解到了由于我们被感染对象的不同,我们部分定义的变量被插入的地址也不同。所以这就需要我们重新定位,也就是今天的主题——重定位技术。
首先我们来看
假如我们定义一段变量
szText db 'Virus Dels Demo', 0
假设我们这个变量在我们病毒体的地址是00403201h, 那么我们插入到被感染对象后这个变量的地址是00408602h。那么我们如何能让我们的病毒体代码在运行时期来计算到被插入被感染对象后变量的地址呢?
我们思索下是否能找到一些固定的地方。有时候换位思考是很不错的,我们病毒体既然被插入的地址是不固定的,那么病毒体的一些绝对偏移它相对病毒体的偏移肯定是固定的吧。
假设一个病毒的起始位置是00400021h,那么它插入到被感染对象后的位置是00500021h, 那么我们是不是只要知道一个变量相对于我们病毒起始位置的偏移就可以求得这个变量插入后的位置了?
比如我们的szText变量相对于病毒起始位置的偏移是9h, 那么只要通过求得病毒插入到被感染对象后的病毒起始位置 + 这个变量相对病毒起始位置的偏移 = 变量在被感染对象中的位置。
是不是很好理解?
继续思索:
我们如何求病毒被插入感染对象后的起始位置,它是可变的。
我们来看一下call指令, call指令是将下一句指令的偏移压入堆栈,然后设置eip寄存器指向要跳转的地址。
看以下代码:
00401010 >/$ E8 00000000 ;call 00401015
00401015 |$ 5B ;pop ebx
就如这段代码call指令首先将下一句指令的地址00401015h压入堆栈,然后将eip寄存器指向00401015h。
病毒技术中call指令详解:
我们都知道call 调用一个内存地址的话,编译器编译的是相对于调用地址的偏移(注意:这里不是绝对偏移,相对偏移),求调用地址的公式是调用地址 - (call指令所处偏移 +5) = 相对偏移
如上面这段代码, 假设我们的代码是call 00401016的话, 那么编译器会将机器码编译为 E8 00000001 。 E8为call对应的机器码。 00000001为偏移差,不懂自己根据上面的公式算算。
我想大家看到这点应该明白我讲解call 指令的作用了吧。。 因为call是将下句指令偏移压入堆栈,然后设置eip寄存器为调用地址。所以我们只要在调用地址中取得堆栈中4字节数据则为下句指令的偏移。
这句代码执行的到00401015处通过pop ebx取得堆栈中4字节的数据(这4字节数据则为call 地址所处位置下句指令偏移地址, 也就是pop ebx指令的地址)。通过这个地址我们就可以把它参照(就相当于上面所说的把它相当于病毒的起始地址),这样我们后面任何绝对地址均采用 这个地址 + 绝对地址相对这个地址的偏移 来取得真正的地址。说起来有些绕口,不过的确是这么个意思。初学者可以多读读理解下。
这里很多不了解基础的人,写代码总是开始E8 00000000
其实你可以调用其他的地址,然后在其后写一些垃圾代码防止杀软的查杀。然后只要把下句指令偏移作为参照就行了。
看代码。
szText db 'Virus Dels Demo', 0
__Entry:
call Dels2
Dels:
int 3
int 3
Dels2:
pop ebx
lea edx, [ebx + szText - Dels] ; edx = szText
ret
代码很简单很好理解,通过调用call dels, 然后通过pop ebx获得dels的偏移,然后通过szText - Dels获得szText变量基于Dels的相对偏移,然后在+dels(ebx) = 重定位后的偏移。
如果您能看到这里,我想您已经是基本理解了。其实就是这么简单,找一个能在运行时计算出来的地址,然后+上相对它的偏移则为重定位后的地址。主要思路就是这样,至于如何发挥就是大家的事情了,您可以发挥你的创造力来变形你的重定位代码,任何技术都是基础。。
好了今天这篇文章就到这里吧。下篇文章我们再见面。
文章无疑是好文章,但是我觉得还是有问题的,即文章里的“call指令是将下一句指令的偏移压入堆栈”,从如果压入的是指令的偏移,那就谈不上重定位了,因为这个偏移值无论是在病毒体中还是在中毒的程序中都是不会变的。关于这点我也用OD打开一个简单的程序看了一下,事实上call指令压入堆栈的内容应该是下条指令的绝对地址,而在以上给出的程序中,标号szText Dels Dels2都是病毒编译时就已经编译好了的绝对地址,这个地址是永远不会变的。
那么,重定位的过程可以这样来过一边:
1、病毒编译的时候将各标号的绝对地址先编译好,无论病毒是否感染,这个地址都是不变的
2、当病毒感染到目标程序以后,标号所对应的代码的地址发生了改变
3、通过调用call指令,压入标号对应的代码的实际地址,然后在子函数中通过pop指令获得这个实际地址(此处应该注意,如果是使用高级程序语言编译的程序应该再将pop出的值再压回堆栈去,因为编译器会在程序中自动加入pop call压入的值的指令)
4、然后通过如下公式就能够得到病毒体中任意变量在被感染程序中的实际地址了:标号A实际地址-标号A原地址=目标实际地址-目标原地址,公式变换一下可以得到:目标实际地址=标号A实际地址-标号A原地址+目标原地址,也就是xfish给出的那个公式了。
相关阅读 更多 +