在shellcode NASM的JMP CALL POP技术中避免使用JMP?
即使这两个程序都遵守shellcode执行所需的相对寻址指令,并且在执行时都会打印所需的消息,但在用作shellcode时, 第二个采样会失败。 任何人都可以解释行为吗? 奇怪的是,与第一个相同的第三个样本也失败了。
输出: 示例1 Hello World
其他样本(2&3)打印垃圾值
样品1
global _start section .text _start: jmp widen pHworld: pop rsi xor rax,rax mov al,1 mov rdi,rax mov rdx,rdi add rdx,11 syscall ;Exit xor rax,rax mov rax,60 xor rdi,rdi syscall widen: call pHworld Hworld db "Hello World",0xa
样品2
global _start section .text _start: call pHworld Hworld db "Hello World",0xa pHworld: pop rsi xor rax,rax mov al,1 mov rdi,rax mov rdx,rdi add rdx,11 syscall ;Exit xor rax,rax mov rax,60 xor rdi,rdi syscall
样品3
global _start section .text _start: jmp label1 label1: call pHworld Hworld db "Hello World",0xa pHworld: pop rsi xor rax,rax mov al,1 mov rdi,rax mov rdx,rdi add rdx,11 syscall ;Exit xor rax,rax mov rax,60 xor rdi,rdi syscall
无法休息我的好奇心,我尝试了另一个变种,并且这失败(打印垃圾值),即使我objdump没有任何0x00。 样品4
global _start section .text pHworld: pop rsi xor rax,rax mov al,1 mov rdi,rax mov rdx,rdi add rdx,11 syscall xor rax,rax xor rdi,rdi mov al,60 syscall l1: call pHworld Hworld db "Hello World", 0xa _start: jmp l1 enter code here
样本4的Objdump
./hworld2.s: file format elf64-x86-64 Disassembly of section .text: 0000000000400080 : 400080: 5e pop rsi 400081: 48 31 c0 xor rax,rax 400084: b0 01 mov al,0x1 400086: 48 89 c7 mov rdi,rax 400089: 48 89 fa mov rdx,rdi 40008c: 48 83 c2 0b add rdx,0xb 400090: 0f 05 syscall 400092: 48 31 c0 xor rax,rax 400095: 48 31 ff xor rdi,rdi 400098: b0 3c mov al,0x3c 40009a: 0f 05 syscall 000000000040009c : 40009c: e8 df ff ff ff call 400080 00000000004000a1 : 4000a1: 48 rex.W 4000a2: 65 gs 4000a3: 6c ins BYTE PTR es:[rdi],dx 4000a4: 6c ins BYTE PTR es:[rdi],dx 4000a5: 6f outs dx,DWORD PTR ds:[rsi] 4000a6: 20 57 6f and BYTE PTR [rdi+0x6f],dl 4000a9: 72 6c jb 400117 4000ab: 64 fs 4000ac: 0a eb or ch,bl 00000000004000ad : 4000ad: eb ed jmp 40009c
TL; DR :使用shellcode时,您希望避免编码0x00字节,否则当代码被用作漏洞的字符串时,它们将在第一个0x00处截断。 这有效地缩短了您的代码。
额外的0x00字节在漏洞之外运行时不会导致问题,因为它们没有被转换为字符串。 这些指令就像任何普通的可执行文件一样执行。
JMP / CALL / POP方法中JMP指令的原因是消除了在生成的代码中插入不需要的0x00字节。 64位代码中的JMP具有rel8
和rel32
编码。 在64位代码中,CALL只有一个rel32
编码。 这意味着如果您使用64位代码中的CALL在存储器中向前传输小数据,它将被编码为32位零扩展目标。 零扩展会导致不需要的0x00值被放置在shell代码中。 在这个CALL指令的64位代码中:
call next
nop
next:
将被编码为:
e8 01 00 00 00
由于JMP指令支持rel8
(相对字节位移),如果目标不超过127个字节(有符号字节为-128至+127),则NASM可以在内存中向前生成JMP指令。 此JMP指令:
jmp next
nop
next:
将被编码为:
eb 01
所以没有额外的零。 您可能会问为什么JMP / CALL / POP方法中的CALL指令有效。 原因是负值的符号在高位字节中扩展。 用1填充高位不会产生额外的0x00字节,因此它可以工作。 本CALL指令:
prev:
call prev
将被编码为:
e8 fb ff ff ff
注意额外的字节不是0.这就是为什么在内存中调用一个点以避免产生零。
样品2
如果我们将上述内容牢记在心,我们只需要检查Sample 2的生成代码即可查看出现问题的位置。 objdump -D ./sample2 -Mintel
生成:
0000000000000000 <_start>:
0: e8 0c 00 00 00 call 11 <pHworld> <---------- Extra zeros
0000000000000005 <Hworld>:
5: 48 rex.W
6: 65 6c gs ins BYTE PTR es:[rdi],dx
8: 6c ins BYTE PTR es:[rdi],dx
9: 6f outs dx,DWORD PTR ds:[rsi]
a: 20 57 6f and BYTE PTR [rdi+0x6f],dl
d: 72 6c jb 7b <pHworld+0x6a>
f: 64 0a 5e 48 or bl,BYTE PTR fs:[rsi+0x48]
0000000000000011 <pHworld>:
11: 5e pop rsi
12: 48 31 c0 xor rax,rax
15: b0 01 mov al,0x1
17: 48 89 c7 mov rdi,rax
1a: 48 89 fa mov rdx,rdi
1d: 48 83 c2 0b add rdx,0xb
21: 0f 05 syscall
23: 48 31 c0 xor rax,rax
26: b8 3c 00 00 00 mov eax,0x3c <---------- Extra zeros
2b: 48 31 ff xor rdi,rdi
2e: 0f 05 syscall
所以我们看到CALL被编码为额外零的问题,这就是为什么您需要传统的JMP / CALL / POP。 mov eax, 60
有第二个问题mov eax, 60
因为它编码了额外的字节。 我想你的意思是使用mov al, 60
样品3
objdump -D ./sample3 -Mintel
生成:
0000000000000000 <_start>:
0: eb 00 jmp 2 <label1> <---------- Extra zeros
0000000000000002 <label1>:
2: e8 0c 00 00 00 call 13 <pHworld> <---------- Extra zeros
0000000000000007 <Hworld>:
7: 48 rex.W
8: 65 6c gs ins BYTE PTR es:[rdi],dx
a: 6c ins BYTE PTR es:[rdi],dx
b: 6f outs dx,DWORD PTR ds:[rsi]
c: 20 57 6f and BYTE PTR [rdi+0x6f],dl
f: 72 6c jb 7d <pHworld+0x6a>
11: 64 0a 5e 48 or bl,BYTE PTR fs:[rsi+0x48]
0000000000000013 <pHworld>:
13: 5e pop rsi
14: 48 31 c0 xor rax,rax
17: b0 01 mov al,0x1
19: 48 89 c7 mov rdi,rax
1c: 48 89 fa mov rdx,rdi
1f: 48 83 c2 0b add rdx,0xb
23: 0f 05 syscall
25: 48 31 c0 xor rax,rax
28: b8 3c 00 00 00 mov eax,0x3c <---------- Extra zeros
2d: 48 31 ff xor rdi,rdi
30: 0f 05 syscall
与样本2相同的问题类型。
样品1
objdump -D ./sample1 -Mintel
生成:
0000000000000000 <_start>:
0: eb 1f jmp 21 <widen>
0000000000000002 <pHworld>:
2: 5e pop rsi
3: 48 31 c0 xor rax,rax
6: b0 01 mov al,0x1
8: 48 89 c7 mov rdi,rax
b: 48 89 fa mov rdx,rdi
e: 48 83 c2 0b add rdx,0xb
12: 0f 05 syscall
14: 48 31 c0 xor rax,rax
17: b8 3c 00 00 00 mov eax,0x3c <---------- Extra zeros
1c: 48 31 ff xor rdi,rdi
1f: 0f 05 syscall
0000000000000021 <widen>:
21: e8 dc ff ff ff call 2 <pHworld>
0000000000000026 <Hworld>:
26: 48 rex.W
27: 65 6c gs ins BYTE PTR es:[rdi],dx
29: 6c ins BYTE PTR es:[rdi],dx
2a: 6f outs dx,DWORD PTR ds:[rsi]
2b: 20 57 6f and BYTE PTR [rdi+0x6f],dl
2e: 72 6c jb 9c <Hworld+0x76>
30: 64 fs
31: 0a .byte 0xa
虽然你说sample 1
有效,但它仍然存在需要纠正的问题。 mov rax, 60
需要mov al, 60
。
上一篇: Avoiding the JMP in the JMP CALL POP technique for shellcode NASM?