实验内容:修改二进制可重定位目标文件“phase1.o”的代码(.text)节内容(不允许修改其他节),使其与main.o模块如下链接后运行时输出目标字符串“123456789”。
gcc -no-pie -o linkbomb main.o phase1.o
./linkbomb
目标字符串
实验步骤:
1. 使用objdump工具获得目标文件的汇编代码,使用readelf工具获得其重定位记录。
2.结合汇编代码和重定位信息,推断目标文件的汇编代码中各函数的功能作用,定位出其中负责输出的函数。
3.构造调用输出函数的指令代码。
4.使用构造的调用输出函数的指令代码,替换目标文件中的do_phase过程中的nop指令,实现目标字符串的输出。
实验验证:
1.查看反汇编代码
objdump -d phase1.o > phase1.s
cat phase1.s
00000000 :
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 ec 38 sub $0x38,%esp
6: c7 45 cc 39 6b 44 70 movl $0x70446b39,-0x34(%ebp)
d: c7 45 d0 6b 76 68 4c movl $0x4c68766b,-0x30(%ebp)
14: c7 45 d4 59 68 35 49 movl $0x49356859,-0x2c(%ebp)
1b: c7 45 d8 66 52 6c 66 movl $0x666c5266,-0x28(%ebp)
22: c7 45 dc 77 57 67 69 movl $0x69675777,-0x24(%ebp)
29: c7 45 e0 6a 73 67 7a movl $0x7a67736a,-0x20(%ebp)
30: c7 45 e4 66 36 58 71 movl $0x71583666,-0x1c(%ebp)
37: c7 45 e8 36 65 32 6d movl $0x6d326536,-0x18(%ebp)
3e: c7 45 ec 36 77 6e 33 movl $0x336e7736,-0x14(%ebp)
45: c7 45 f0 68 6f 4b 00 movl $0x4b6f68,-0x10(%ebp)
4c: 83 ec 0c sub $0xc,%esp
4f: 8d 45 cc lea -0x34(%ebp),%eax
52: 50 push %eax
53: e8 fc ff ff ff call 54
58: 83 c4 10 add $0x10,%esp
5b: 89 45 f4 mov %eax,-0xc(%ebp)
5e: 83 7d 08 00 cmpl $0x0,0x8(%ebp)
62: 78 15 js 79
64: 8b 45 08 mov 0x8(%ebp),%eax
67: 3b 45 f4 cmp -0xc(%ebp),%eax
6a: 7d 0d jge 79
6c: 8d 55 cc lea -0x34(%ebp),%edx
6f: 8b 45 08 mov 0x8(%ebp),%eax
72: 01 d0 add %edx,%eax
74: 0f b6 00 movzbl (%eax),%eax
77: eb 05 jmp 7e
79: b8 00 00 00 00 mov $0x0,%eax
7e: c9 leave
7f: c3 ret
00000080 :
80: 55 push %ebp
81: 89 e5 mov %esp,%ebp
83: 83 ec 08 sub $0x8,%esp
86: 83 ec 08 sub $0x8,%esp
89: 68 02 00 00 00 push $0x2
8e: ff 75 08 pushl 0x8(%ebp)
91: e8 fc ff ff ff call 92
96: 83 c4 10 add $0x10,%esp
99: 85 c0 test %eax,%eax
9b: 75 10 jne ad
9d: 83 ec 0c sub $0xc,%esp
a0: ff 75 0c pushl 0xc(%ebp)
a3: e8 fc ff ff ff call a4
a8: 83 c4 10 add $0x10,%esp
ab: eb 01 jmp ae
ad: 90 nop
ae: c9 leave
af: c3 ret
000000b0 :
b0: 55 push %ebp
b1: 89 e5 mov %esp,%ebp
b3: 90 nop
b4: 90 nop
b5: 90 nop
b6: 90 nop
b7: 90 nop
b8: 90 nop
b9: 90 nop
ba: 90 nop
bb: 90 nop
bc: 90 nop
bd: 90 nop
be: 90 nop
bf: 90 nop
c0: 90 nop
c1: 90 nop
c2: 90 nop
c3: 90 nop
c4: 90 nop
c5: 90 nop
c6: 90 nop
c7: 90 nop
c8: 90 nop
c9: 90 nop
ca: 90 nop
cb: 90 nop
cc: 90 nop
cd: 90 nop
ce: 90 nop
cf: 90 nop
d0: 90 nop
d1: 90 nop
d2: 90 nop
d3: 90 nop
d4: 90 nop
d5: 90 nop
d6: 90 nop
d7: 90 nop
d8: 90 nop
d9: 90 nop
da: 90 nop
db: 90 nop
dc: 90 nop
dd: 90 nop
de: 90 nop
df: 90 nop
e0: 90 nop
e1: 90 nop
e2: 90 nop
e3: 90 nop
e4: 90 nop
e5: 90 nop
e6: 90 nop
e7: 90 nop
e8: 90 nop
e9: 90 nop
ea: 90 nop
eb: 90 nop
ec: 90 nop
ed: 90 nop
ee: 90 nop
ef: 90 nop
f0: 90 nop
f1: 90 nop
f2: 90 nop
f3: 90 nop
f4: 5d pop %ebp
f5: c3 ret
root@educoder:/data/workspace/myshixun/step1# readelf -r phase1.o
2.查看重定位信息
readelf -r phase1.o
在这里可以看到在.text节中偏移量为a4 的为输出函数。
3.获取目标函数 在.text节中的偏移量
readelf -s phase1.o
目标函数在.text节中的偏移量为80 (LOCAL说明:链接绑定属性,调用函数可通过相对于PC值的偏移量来进行跳转)
4.分析目标函数逻辑
为了确保正确调用,首先确保传递给目标函数的两个参数字符串完全相同。
1.内置字符串地址 = .rodata起始地址 + 引用处的初始值0*2
使用指令,发现的第1个参数为内容为“lDdEIUE”字符串地址
readelf -x.rodata phase1.o
2.在栈中构造与内置字符串和学号字符串内容相同的局部字符串变量,并将其地址作为实参压入栈中 。构造在do phase函数中,调用kfSvKnbh函数的机器指令代码指令内容:在栈中构造和初始化两个字符串局部变量,使其内容相同于程序内置的比较字符串"MSLuleX"和待输出的学号字符串“123456789" 。
可以利用sub指令先分配两个字符串的存储空间,然后使用一组move指令对两个字符串的内容按照前面分析的结果进行设置。然后用push指令将两个字符串的地址作为参数压入栈中。并进一步使用call指令调用目标函数。
调用函数的二进制编码为下列(从第一行的83开始 到最后一行的C3结束)
获得.text节的偏移量为34,机器码的插入位置为b3,所以插入机器码在文件中的偏移量为34 + b3 等于e7
最后!使用上步构造的调用输出函数的指令代码,替换do_ _phase()函数体中的nop指令,以实现期望输出。