SIGSEGV 在 ARMv6 上从数组执行机器代码
SIGSEGV at executing machine code from array on ARMv6
我试图在 ArchLinux 下首先 Raspberry Pi 执行存储在数组中的机器代码。我已经在 x86 下完成了,但我无法理解我在 ARMv6 下做错了什么。问题是无论数组中的代码是什么,它总是会在执行第一条指令后崩溃。代码是在 gcc 5.2.0 下禁用 Thumb 互通的情况下编译的。
这是我用来测试的代码:
#include <stdio.h>
char shellcode[] = {
0x04, 0xb0, 0x2d, 0xe5, // push {r11}
0x00, 0xb0, 0x8d, 0xe2, // add r11, sp, #0
0x00, 0x00, 0xa0, 0xe1, // nop
0x00, 0x00, 0xa0, 0xe1, // nop
0x00, 0x00, 0xa0, 0xe1, // nop
0x00, 0xd0, 0x4b, 0xe2, // sub sp, r11, #0
0x04, 0xb0, 0x9d, 0xe4, // pop {r11}
0x1e, 0xff, 0x2f, 0xe1 // bx lr
};
void shellcode2() {
asm("mov r0, r0");
asm("mov r0, r0");
}
typedef void (*entry_t)();
int main() {
entry_t entry = (entry_t)(shellcode);
entry();
return 0;
}
机器代码取自 shellcode2
函数反汇编,我不知道这样做是否正确,但问题是即使 shellcode 中的第一条指令是 nop - 它会崩溃。
Program received signal SIGSEGV, Segmentation fault.
0x00020704 in shellcode ()
(gdb) disas /r
Dump of assembler code for function shellcode:
=> 0x00020704 <+0>: 04 b0 2d e5 push {r11} ; (str r11, [sp, #-4]!)
0x00020708 <+4>: 00 b0 8d e2 add r11, sp, #0
0x0002070c <+8>: 00 00 a0 e1 nop ; (mov r0, r0)
0x00020710 <+12>: 00 00 a0 e1 nop ; (mov r0, r0)
0x00020714 <+16>: 00 00 a0 e1 nop ; (mov r0, r0)
0x00020718 <+20>: 00 d0 4b e2 sub sp, r11, #0
0x0002071c <+24>: 04 b0 9d e4 pop {r11} ; (ldr r11, [sp], #4)
0x00020720 <+28>: 1e ff 2f e1 bx lr
End of assembler dump.
我是不是遗漏了什么或者只是在 ARMv6 上做错了?如果有人能指出正确的方向,我将不胜感激。
提前致谢。
将评论放在答案中以便将来的用户可以找到它。
ARMv6 支持 'Execute Never' 个区域,可用于防止包含数据的页面作为代码执行。
这是一项安全措施,因为它可以防止各种黑客攻击。但这对于尝试执行自修改代码的程序来说可能是个问题(这实际上是 OP 正在尝试做的)。
查看 ARMv6 文档了解详细信息。
您需要在链接描述文件中指定一段内存供代码执行。例如:
.umem : {
. = ALIGN(4);
_umem = .;
. = . + 48k;
} > RAM
其中 ram 是至少标记为 rx 的部分
_umem 应该是这个 48k 缓冲区开始地址处的一个符号,可以使用 extern 语句将其添加到头文件中。
我试图在 ArchLinux 下首先 Raspberry Pi 执行存储在数组中的机器代码。我已经在 x86 下完成了,但我无法理解我在 ARMv6 下做错了什么。问题是无论数组中的代码是什么,它总是会在执行第一条指令后崩溃。代码是在 gcc 5.2.0 下禁用 Thumb 互通的情况下编译的。
这是我用来测试的代码:
#include <stdio.h>
char shellcode[] = {
0x04, 0xb0, 0x2d, 0xe5, // push {r11}
0x00, 0xb0, 0x8d, 0xe2, // add r11, sp, #0
0x00, 0x00, 0xa0, 0xe1, // nop
0x00, 0x00, 0xa0, 0xe1, // nop
0x00, 0x00, 0xa0, 0xe1, // nop
0x00, 0xd0, 0x4b, 0xe2, // sub sp, r11, #0
0x04, 0xb0, 0x9d, 0xe4, // pop {r11}
0x1e, 0xff, 0x2f, 0xe1 // bx lr
};
void shellcode2() {
asm("mov r0, r0");
asm("mov r0, r0");
}
typedef void (*entry_t)();
int main() {
entry_t entry = (entry_t)(shellcode);
entry();
return 0;
}
机器代码取自 shellcode2
函数反汇编,我不知道这样做是否正确,但问题是即使 shellcode 中的第一条指令是 nop - 它会崩溃。
Program received signal SIGSEGV, Segmentation fault.
0x00020704 in shellcode ()
(gdb) disas /r
Dump of assembler code for function shellcode:
=> 0x00020704 <+0>: 04 b0 2d e5 push {r11} ; (str r11, [sp, #-4]!)
0x00020708 <+4>: 00 b0 8d e2 add r11, sp, #0
0x0002070c <+8>: 00 00 a0 e1 nop ; (mov r0, r0)
0x00020710 <+12>: 00 00 a0 e1 nop ; (mov r0, r0)
0x00020714 <+16>: 00 00 a0 e1 nop ; (mov r0, r0)
0x00020718 <+20>: 00 d0 4b e2 sub sp, r11, #0
0x0002071c <+24>: 04 b0 9d e4 pop {r11} ; (ldr r11, [sp], #4)
0x00020720 <+28>: 1e ff 2f e1 bx lr
End of assembler dump.
我是不是遗漏了什么或者只是在 ARMv6 上做错了?如果有人能指出正确的方向,我将不胜感激。
提前致谢。
将评论放在答案中以便将来的用户可以找到它。
ARMv6 支持 'Execute Never' 个区域,可用于防止包含数据的页面作为代码执行。
这是一项安全措施,因为它可以防止各种黑客攻击。但这对于尝试执行自修改代码的程序来说可能是个问题(这实际上是 OP 正在尝试做的)。
查看 ARMv6 文档了解详细信息。
您需要在链接描述文件中指定一段内存供代码执行。例如:
.umem : {
. = ALIGN(4);
_umem = .;
. = . + 48k;
} > RAM
其中 ram 是至少标记为 rx 的部分 _umem 应该是这个 48k 缓冲区开始地址处的一个符号,可以使用 extern 语句将其添加到头文件中。