我正在用这个把我的头撞到墙上。
在我的项目中,使用mmap映射(/proc/self/maps)分配内存时,尽管我只请求了可读内存,但它仍是一个可读且可执行的区域。
在研究了strace(看起来不错)和其他调试之后,我能够确定似乎唯一可以避免这个奇怪问题的东西:从项目中删除程序集文件,只保留纯C。(什么?!)
所以这是我一个奇怪的例子,我正在使用Ubunbtu 19.04和默认的gcc。
如果使用ASM文件(为空)编译目标可执行文件,则将mmap返回一个可读和可执行区域,如果构建时没有该区域,则它将正常运行。请参阅/proc/self/maps示例中已嵌入的输出。
example.c
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
int main()
{
void* p;
p = mmap(NULL, 8192,PROT_READ,MAP_ANONYMOUS|MAP_PRIVATE,-1,0);
{
FILE *f;
char line[512], s_search[17];
snprintf(s_search,16,"%lx",(long)p);
f = fopen("/proc/self/maps","r");
while (fgets(line,512,f))
{
if (strstr(line,s_search)) fputs(line,stderr);
}
fclose(f);
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
example.s:是一个空文件!
产出
附带ASM版本
VirtualBox:~/mechanics/build$ gcc example.c example.s -o example && ./example
7f78d6e08000-7f78d6e0a000 r-xp 00000000 00:00 0
Run Code Online (Sandbox Code Playgroud)
没有ASM随附的版本
VirtualBox:~/mechanics/build$ gcc example.c -o example && ./example
7f1569296000-7f1569298000 …Run Code Online (Sandbox Code Playgroud) 我刚刚注意到我的简单程序的数据和堆栈段是可执行的.我在/ proc/[pid]/maps中看到了它,简单的代码证实了它.
例如:
; prog.asm
section .data
code: db 0xCC ;int3
section .text
global _start
_start:
jmp code
mov rax, 60 ; sys_exit
mov rdi, 0
syscall
Run Code Online (Sandbox Code Playgroud)
然后
nasm -f elf64 prog.asm
ld -o prog prog.o
./prog
Run Code Online (Sandbox Code Playgroud)
导致prog执行int3指令.
用C语言编写并用gcc构建的程序使其数据,堆栈和堆不可执行,那么为什么那些用汇编编写的程序会以不同的方式运行?
我想要一个简单的C方法,以便能够在Linux 64位机器上运行十六进制字节码.这是我的C程序:
char code[] = "\x48\x31\xc0";
#include <stdio.h>
int main(int argc, char **argv)
{
int (*func) ();
func = (int (*)()) code;
(int)(*func)();
printf("%s\n","DONE");
}
Run Code Online (Sandbox Code Playgroud)
我试图运行的代码("\x48\x31\xc0")我通过编写这个简单的汇编程序获得(它不应该真的做任何事情)
.text
.globl _start
_start:
xorq %rax, %rax
Run Code Online (Sandbox Code Playgroud)
然后编译并objdump它以获取字节码.
但是,当我运行我的C程序时,我得到了一个分段错误.有任何想法吗?
我编写了下面的代码来测试/tmp/passwd安全类中的赋值的shellcode(用于取消链接).
当我编译时gcc -o test -g test.c,我得到了跳转到shellcode的段错误.
当我使用后处理二进制文件时execstack -s test,我不再获得段错误并且shellcode正确执行,删除/tmp/passwd.
我运行gcc 4.7.2.为了使堆可执行,似乎要求堆栈是可执行的似乎是个坏主意,因为后者比前者有更多合法的用例.
这是预期的行为吗?如果是这样,理由是什么?
#include <stdio.h>
#include <stdlib.h>
char* shellcode;
int main(){
shellcode = malloc(67);
FILE* code = fopen("shellcode.bin", "rb");
fread(shellcode, 1, 67, code);
int (*fp)(void) = (int (*) (void)) shellcode;
fp();
}
Run Code Online (Sandbox Code Playgroud)
这是输出xxd shellcode.bin:
0000000: eb28 5e89 760c 31c0 8846 0bfe c0fe c0fe .(^.v.1..F......
0000010: c0fe c0fe c0fe c0fe c0fe c0fe c0fe c089 ................
0000020: f3cd 8031 db89 d840 …Run Code Online (Sandbox Code Playgroud) 需要创建一个脚本来检查内核是否处于PAE模式.当然,仅检查/ proc/cpuinfo标志是否具有此"pae"设置是不够的.
我们必须知道PAE机制是否实际上不仅实现了,而且还被激活.
因为PAE内核现在是新的默认值,如果你需要一个非PAE内核,那么现在必须创建另一个内核.
换句话说,我们如何判断内核在具有PAE的CPU上是否是非PAE(是测试的两个可能条件之一).
另一个是,如何在没有PAE支持的CPU上判断内核是否为PAE.
并且没有办法判断在典型的安全内核中是否使用了CONFIG_HIGHMEM或CONFIG_PAE内核配置选项.
memory kernel memory-management cpu-architecture linux-kernel
在控制段上的可执行位的过程中,我发现了PT_GNU_STACK加载程序如何使用的一个巨大的怪癖。
根据elf(5)联机帮助页,PT_GNU_STACK用作:
GNU 扩展,Linux 内核使用它通过 p_flags 成员中设置的标志来控制堆栈的状态。
该execstack手册页,也支持这一点:
... ELF 二进制文件和共享库现在可以标记为需要或不需要可执行堆栈。此标记是通过 PT_GNU_STACK 程序头条目中的 p_flags 字段完成的。
但是,除了设置堆栈可执行文件之外,当我设置该位时,几乎所有段都变为可执行文件。
例如,当我运行时sleep,我得到了这个内存映射
sleep 100 & cat /proc/$!/maps
[1] 1260
561460d8d000-561460d94000 r-xp 00000000 08:01 524383 /bin/sleep
561460f94000-561460f95000 r--p 00007000 08:01 524383 /bin/sleep
561460f95000-561460f96000 rw-p 00008000 08:01 524383 /bin/sleep
561462eca000-561462eeb000 rw-p 00000000 00:00 0 [heap]
7f02b08b9000-7f02b0b97000 r--p 00000000 08:01 1966102 /usr/lib/locale/locale-archive
7f02b0b97000-7f02b0d7e000 r-xp 00000000 08:01 655384 /lib/x86_64-linux-gnu/libc-2.27.so
7f02b0d7e000-7f02b0f7e000 ---p 001e7000 08:01 655384 /lib/x86_64-linux-gnu/libc-2.27.so
7f02b0f7e000-7f02b0f82000 r--p …Run Code Online (Sandbox Code Playgroud) 我有以下汇编函数(已用 objdump 显示)
0000000000000000 <add>:
0: b8 06 00 00 00 mov $0x6,%eax
5: c3 retq
Run Code Online (Sandbox Code Playgroud)
现在在 CI 中做了以下代码:
#include <stdio.h>
typedef int (*funcp) (int x);
unsigned char foo[] = {0xb8,0x06,0x00,0x00,0x00,0xc3};
int main(void)
{
int i;
funcp f = (funcp)foo;
i = (*f);
printf("exit = %d\n", i);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在全局变量 foo 中,我在汇编中输入了我的函数的内存地址并尝试执行它,但它没有按预期返回 6。如何为它们的内存地址执行函数?此外,我可以在哪里研究更多关于该主题的信息?
obs:有时我会遇到 Segmentation fault (core dumped) 错误
我正在学习汇编和低级编程,并阅读有关它的书.据说我们可以将任何数据放在elf文件的.text部分中,但当然我们不能因为页面/段的不同权限而改变它.但是没有告诉那里,因为在.text部分内部有数据的原因是什么.许多C++程序员也告诉我g ++编译器
static const char DATA[] = "SOME DATA";
Run Code Online (Sandbox Code Playgroud)
也在.text部分内.我想知道,为什么不将这些数据放在.rodata部分,目的是什么?如果使用.text,那么.rodata中应该存储什么?
主要问题是在长模式下的这种行为.
我这里有一些示例代码,用于理解初学者CTF的某些C行为:
// example.c
#include <stdio.h>
void main() {
void (*print)();
print = getenv("EGG");
print();
}
Run Code Online (Sandbox Code Playgroud)
编译: gcc -z execstack -g -m32 -o example example.c
用法: EGG=$(echo -ne '\x90\xc3) ./example
如果我用execstack标志编译代码,则程序将执行我在上面注入的操作码。没有该标志,该程序将由于分段错误而崩溃。
为什么会这样呢?是因为getenv将实际的操作码存储在堆栈上,而execstack标志允许跳转到堆栈吗?还是getenv将指针推入堆栈,关于内存的哪些部分可执行的还有其他一些规则?我阅读了联机帮助页,但是我无法确切了解规则是什么以及如何执行它们。
另一个问题是,我认为我确实也缺少在调试时可视化内存的好工具,因此很难弄清楚这一点。任何建议将不胜感激。
我有一个非常简单的ELF可执行文件:
$ readelf -l ./plt.out
Elf file type is EXEC (Executable file)
Entry point 0x400338
There are 7 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x00000000003ff040 0x00000000003ff040
0x0000000000000188 0x0000000000000188 R E 8
LOAD 0x0000000000000000 0x00000000003ff000 0x00000000003ff000
0x0000000000001000 0x0000000000001000 RW 1000
INTERP 0x00000000000001c8 0x00000000003ff1c8 0x00000000003ff1c8
0x0000000000000032 0x0000000000000032 R 1
[Requesting program interpreter: /data/keno/new_glibc/usr/lib/ld-linux-x86-64.so.2]
LOAD 0x0000000000001000 0x0000000000400000 0x0000000000400000
0x00000000000003b0 0x00000000000003b0 R E 1000
LOAD 0x0000000000001ea0 0x0000000000600ea0 0x0000000000600ea0
0x0000000000000180 0x0000000000000180 RW 1000 …Run Code Online (Sandbox Code Playgroud) 为什么会出现分段错误?
我用的nasm -f elf64 t.asm -o t.o ld t.o -o t是linux下的编译。
我已经做了我能想到的一切。
section .data:
variable_int db 1
variable_string db "yaaaa", 10
section .text:
global _start
_start:
mov rax, 1
mov rdi, 1
mov rsi, variable_string
mov rdx, 14
syscall
mov rax, 60
mov rdi, 0
syscall
Run Code Online (Sandbox Code Playgroud) 我是汇编新手,从我了解到的情况.code与 相同.text,但下面的代码将使用.code.
segment .data
msg db "hello, world", 0xa
len equ $ - msg
section .text
global _start
_start:
mov edx, len
mov ecx, msg
mov ebx, 1
mov eax, 4
int 0x80
mov ebx, 0
mov eax, 1
int 0x80
Run Code Online (Sandbox Code Playgroud)
nasm -f elf64 -o hello.o hello.s
ld -s -o hello hello.o
hello, world
sed -i s/.text/.code/ ./hello.s
nasm -f elf64 -o hello.o hello.s
ld -s -o hello hello.o
./stack.sh: line 8: 4621 Segmentation …Run Code Online (Sandbox Code Playgroud)