首页
论坛
课程
招聘
[Anti Virus专题]1.2 - 1.病毒的重定位技术
2009-4-9 21:22 31458

[Anti Virus专题]1.2 - 1.病毒的重定位技术

2009-4-9 21:22
31458
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) = 重定位后的偏移。

        如果您能看到这里,我想您已经是基本理解了。其实就是这么简单,找一个能在运行时计算出来的地址,然后+上相对它的偏移则为重定位后的地址。主要思路就是这样,至于如何发挥就是大家的事情了,您可以发挥你的创造力来变形你的重定位代码,任何技术都是基础。。

        好了今天这篇文章就到这里吧。下篇文章我们再见面。

《0day安全 软件漏洞分析技术(第二版)》第三次再版印刷预售开始!

收藏
点赞0
打赏
分享
最新回复 (54)
雪    币: 265
活跃值: 活跃值 (29)
能力值: ( LV13,RANK:350 )
在线值:
发帖
回帖
粉丝
moonife 活跃值 8 2009-4-9 22:12
2
0
学习了,谢谢了,期待下篇
雪    币: 367
活跃值: 活跃值 (10)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
flowons 活跃值 2 2009-4-9 22:37
3
0
期待,期待,支持楼主
雪    币: 218
活跃值: 活跃值 (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
tianci 活跃值 2009-4-9 23:32
4
0
[QUOTE=;]...[/QUOTE]
淋漓尽致的感觉!学习…
雪    币: 102
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
御剑圣者 活跃值 2009-4-9 23:47
5
0
学习中,期待后面更精彩
雪    币: 205
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
mydooom 活跃值 2009-4-10 00:33
6
0
“代码很简单很好理解,通过调用call dels, 然后通过pop ebx获得dels的偏移"

这里是不是写错了?你明明是call dels2啊
雪    币: 111
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
JwLee 活跃值 2009-4-10 10:39
7
0
顶楼主,不过有一疑问,麻烦解答一下:

求调用地址的公式是

调用地址 - (call指令所处偏移 +5) = 相对偏移

我不太明白这个公式,尤其是后面的 +5,调用地址 - call指令所处偏移不就是相对偏移么?为什么还要加5?
雪    币: 11
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
woosheep 活跃值 2009-4-10 10:55
8
0
call + 地址

长度为5
雪    币: 115
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
hust白客 活跃值 2009-4-10 11:01
9
0
我帮楼主解答下,call指令占5个字节,CPU在执行指令时是这样计算的
(1) 下一条指令地址 EIP = 当前EIP + 当前指令长度
(2) PUSH EIP
(3) JMP EIP + 相对偏移

所以,当跳转时,EIP已经指向call下一条指令的地址了

不晓得说的对不,我是这样理解的
雪    币: 111
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
JwLee 活跃值 2009-4-10 11:36
10
0
明白了,谢谢!
雪    币: 130
活跃值: 活跃值 (10)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
jesterjy 活跃值 1 2009-4-10 12:32
11
0
很详细.帮顶.
雪    币: 2362
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zapline 活跃值 2009-4-10 15:12
12
0
   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  Dels2 ,下一句就是    Dels: int  3     ,这里call把    Dels:的地址压入堆栈了
所以  pop  ebx  ,ebp的值是dels的偏移

不过  “通过调用call dels” 这里好像是要加个 2
雪    币: 266
活跃值: 活跃值 (11)
能力值: ( LV9,RANK:220 )
在线值:
发帖
回帖
粉丝
xfish 活跃值 5 2009-4-10 15:15
13
0
你应该就是我所说的不了解基础的人哈哈。。
注意下:
__Entry:
     call  Dels2
    Dels:
    int  3
    int  3
Dels2:

call是将所处偏移的下句指令偏移压入堆栈,当调用call  Dels2的时候, 是将dels偏移压入堆栈,然后设置eip寄存器为Dels2。。
此时在Dels2偏移处通过pop ebx取得的就是dels的偏移,明白了吗?
雪    币: 266
活跃值: 活跃值 (11)
能力值: ( LV9,RANK:220 )
在线值:
发帖
回帖
粉丝
xfish 活跃值 5 2009-4-10 15:24
14
0
因为这个相对偏移要减去call 地址所占的字节数。

举个例子

00401000   |$  E8 00000000     call    00401005 ;5字节
;0字节
00401005   |$  5B                      pop     ebx            

call    00401005,因为call 地址所占字节是5字节,所以这个例子的相对偏移是0。               

不知道这样表达明白了不?
雪    币: 266
活跃值: 活跃值 (11)
能力值: ( LV9,RANK:220 )
在线值:
发帖
回帖
粉丝
xfish 活跃值 5 2009-4-10 15:30
15
0
恩对。。
不过表达的有点问题。
下一条指令地址 EIP ,这个叫做下一条指令地址 就可以了,不要加上eip。

(1) 下一条指令地址 = 当前EIP + 当前指令长度
(2) push 下一条指令地址
(3) JMP eip + 5 +  相对偏移
雪    币: 204
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
udknight 活跃值 2009-4-10 15:35
16
0
在LZ的帮助下,终于完全弄明白了。支持你下。不是那种发完贴就闪人的高手。
雪    币: 45
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:140 )
在线值:
发帖
回帖
粉丝
nkspark 活跃值 3 2009-4-11 00:20
17
0
先顶后看~~~~~
雪    币: 193
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
cham 活跃值 2009-4-11 08:17
18
0
3中的eip是1中的当前eip.host白客3中的eip是1中的下一条指令eip,其实都是一样的啊!
雪    币: 193
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
cham 活跃值 2009-4-11 08:41
19
0
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
szText是个全局变量,地址是在编译的时候定的,但是插入被感染对象后地址就变了,所以我们要重定位。而局部变量是运行时分配的,所以无需考虑。也就是说lea  edx, [ebx + szText - Dels],这里的szText是在病毒体内编译时确定的地址,Dels应该也是在病毒体内编译是就确定的,ebx的值是被感染对象中Dels的地址。ebx-Dels也就是这段代码在被感染对象的地址和在病毒体中地址的差值,再加上szText在病毒体中的地址,就是szText在被感染对象中的地址。所以我们写重地位代码是无需考虑szText,只要看ebx-Dels的值是不是那个差值就好了,随便变化都可以吧!晕,不知道我这样理解对不对!
雪    币: 206
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Pat 活跃值 2009-4-13 10:18
20
0
这里写写本人的理解,不知对不对。

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指令所处偏移 +5) = 相对偏移
则有:调用地址 = (call指令所处偏移 +5) + 相对偏移

      其中:ebx即为 (call指令所处偏移 +5) [执行call指令,call指令会将下一句指令的偏移压入堆栈,call指令本身长度为5,压入堆栈的其实就是call指令所处偏移 +5了;pop ebx取得的也就是call指令所处偏移 +5了];szText - Dels 即szText变量基于Dels的相对偏移
      ebx= (call指令所处偏移 +5),szText - Dels=相对偏移
      lea  edx, [ebx + szText - Dels] ; edx = szText的调用地址

      [edx]=[ebx + szText - Dels]
         szText的调用地址=[Dels的偏移(=call指令所处偏移 +5)+ szText - Dels]
         szText在运行进程中的地址=Dels在运行进程中的地址+szText变量基于Dels的相对偏移
雪    币: 266
活跃值: 活跃值 (11)
能力值: ( LV9,RANK:220 )
在线值:
发帖
回帖
粉丝
xfish 活跃值 5 2009-4-14 10:36
21
0
to cham:

1: 前面已经说了,host白客3表达上面的问题。

2: 理解是正确的。不过大部分为了更加优化,所以通过+ 一个偏移的相对偏移更加要好些。

to pat:

  恩,正确。
雪    币: 338
活跃值: 活跃值 (37)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
guijian 活跃值 2009-4-16 11:09
22
0
不错,简单明了!支持楼主!
雪    币: 247
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
evilcode 活跃值 2009-4-16 11:39
23
0
这只是一段程序编译好再感染进去的吧?

直接反汇编感染的话怎么弄啊?
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
recnad 活跃值 2009-4-16 13:09
24
0
写得不错, 继续啊!
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
recnad 活跃值 2009-4-16 13:57
25
0
这段:
    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
   
改成:
   szText  db  'Virus Dels Demo', 0
   
   __Entry:
     call  Dels2
    Dels:
    int  3
    int  3
    Dels2:
    pop  ebx
    lea  ebx, [ebx - Dels]
    lea  edx, [ebx + szText] ; edx = szText
    ret

是不是更好些? 这样以后变量直接加上ebx就可以算出位移了。
游客
登录 | 注册 方可回帖
返回