- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我在这里有一些示例代码,我用它来理解初学者 CTF 的一些 C 行为:
// example.c
#include <stdio.h>
void main() {
void (*print)();
print = getenv("EGG");
print();
}
编译:gcc -z execstack -g -m32 -o example example.c
用法:EGG=$(echo -ne '\x90\xc3) ./example
如果我使用 execstack
标志编译代码,程序将执行我在上面注入(inject)的操作码。没有这个标志,程序将由于段错误而崩溃。
为什么会这样?是因为 getenv
将实际的操作码存储在堆栈上,并且 execstack 标志允许跳转到堆栈吗?或者 getenv
是否将指针压入堆栈,以及关于内存的哪些部分可执行的一些其他规则?我阅读了联机帮助页,但无法确切地了解规则是什么以及它们是如何执行的。
另一个问题是我认为我也确实缺少一个在调试时可视化内存的好工具,所以很难弄清楚这一点。任何建议将不胜感激。
最佳答案
getenv
不存储环境变量的值在堆栈上。它在进程启动时已经在堆栈中,getenv
获得指向它的指针。
请参阅 i386 System V ABI 对进程启动时 argv[] 和 envp[] 所在位置的描述:以上 [esp]
.
_start
在调用 main
之前不复制它们, 只是计算指向它们的指针作为参数传递给 main
. (链接到 https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI 的最新版本,其中维护了官方当前版本。)
您的代码将指向堆栈内存(包含环境变量的值)的指针转换为函数指针并通过它进行调用。查看编译器生成的 asm(例如 https://godbolt.org/ ):它类似于 call getenv
/call eax
.
-zexecstack
在您的内核版本中1 使您的所有页面都可执行,而不仅仅是堆栈。它也适用于 .data
, .bss
, 和 .rodata
部分,以及分配给 malloc
的内存/new
.
GNU/Linux 上的确切机制是一个“read-implies-exec”进程级标志,它会影响所有 future 的分配,包括手动使用 mmap
. 参见 Unexpected exec permission from mmap when assembly files included in the project有关 GNU_STACK
的更多信息ELF header 内容。
脚注 1:5.4 左右之后的 Linux 仅使堆栈本身可执行,而不是 READ_IMPLIES_EXEC:Linux default behavior of executable .data section changed between 5.4 and 5.9?
有趣的事实:获取访问其父局部变量的嵌套函数的地址会使 gcc 启用 -zexecstack
.它将可执行“蹦床”的代码存储到堆栈上,该堆栈将“静态链”指针传递给实际的嵌套函数,从而允许它引用其父级的堆栈框架。
如果你想在没有 -zexecstack
的情况下将数据作为代码执行,你会使用 mprotect(PROT_EXEC|PROT_READ|PROT_WRITE)
在包含该环境变量的页面上。 (它是您的堆栈的一部分,因此您不应删除写权限;例如,它可能与 main 的堆栈框架位于同一页面中。)
相关:
使用 GNU/Linux ld
在 2018 年底左右之前从 binutils 中,.rodata
部分链接到与 .text
相同的 ELF 段部分,因此 const char code[] = {0xc3}
或字符串文字是可执行的。
当前 ld
给出 .rodata
它自己的段在没有执行的情况下被映射读取,因此不再可能在只读数据中找到 ROP/Spectre“小工具”,除非您使用 -zexecstack
.即使这样也不适用于当前的内核; char code[] = ...;
作为函数内部的局部变量,会将数据放在实际可执行的堆栈中。参见 How to get c code to execute hex machine code?了解详情。
关于c - gcc execstack 标志究竟允许什么情况以及它是如何强制执行的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53346274/
我正在创建一个 sql server 存储过程,它将输入作为逗号分隔的 productid 或选项“全部”。当用户传入逗号分隔的产品 ID 时,查询应输出所有产品 ID 的数据。我使用“IN”语句执行
我有一个自动生成的 Web 服务客户端。我有很多复杂的类,我必须对其进行模式匹配。现在我的结构如下所示: val response = client.getResponse response matc
关闭。这个问题是opinion-based .它目前不接受答案。 想改进这个问题?更新问题,以便 editing this post 可以用事实和引用来回答它. 7年前关闭。 Improve this
我需要正确的 tsql 语法来解决这个问题: Select * from table where var_A='10' select * from table where var_B='10' 何时使
我遇到了这个问题。每当我运行程序并在需要时键入字母 m 时,我的 if 语句都不会识别它。有人知道为什么吗?我已经这样做了一个小时,但没有结果。 #include #include #includ
我从数据库列名称“你有护照”创建了一个表,用户回答是或否我如何将 css 应用到这个动态工作的表。 table, th, td { border: 1px solid black;
我对 LocationListener 类的 onStatusChanged 有一些疑问。 它知道它可以呈现三种状态:AVAILABLE、TEMPORARILY_UNAVAILABLE 和 OUT_O
当引入新的异常类型时,我总是不确定如何正确地做到这一点。有共同约定吗?你怎么做呢? 我对您组织它们的范围感兴趣(将它们保留在它们所使用的单元中?在组件级别有一个单元?包级别?应用程序?) 这也会影响命
我使用以下内容创建了日期维度: https://www.codeproject.com/Articles/647950/Create-and-Populate-Date-Dimension-for-D
您好,我正在使用 Android 完全 Kiosk 浏览器,该浏览器使用 chrome Webview。但是 javascript 中的某些方法或函数无法正常工作,例如 window.print()。
我有以下代码: public void OpenFile(string FileName) { if (FileName == null)
获取索引越界异常 for (int recordData = 0; recordData < recordDataList.size(); recordData++) {
我使用它在发生错误时在登录中显示一条消息: × Invalid user or password
这是我的场景,我有一个异常列表,其中包含来自不同层次结构的任意异常,下面的代码快照将解释我需要做什么 private List connectionExceptions; try { // tryin
我尝试动态更新 Jtextpane 中的左缩进。但我不能!这是我尝试过的! DefaultStyledDocument document = (DefaultStyledDocument) textp
我不知道为什么这个异常不起作用...... import java.util.*; public class a { public static void main(String[] args
我目前在 case 中使用多个 when 时遇到问题。当我删除第二个当时,它就起作用了。这是什么问题? 报告的MYSQL错误为: #1064 - You have an error in your S
例如,我有一个表记录用户查看和下载文件的事件, file_id user activity 2 Tim view 1 Ron
这是一个非常愚蠢的问题,但我需要一点安慰/帮助。我有当前的“递归”情况: void add( int value ) { // do something ... // if ( conditi
我尝试使用以下代码在按钮数组上注册回调。但我似乎无法理解如何绑定(bind)回调中需要的字符串。任何建议将不胜感激! for (var i = 0; i < this.car_types.length
我是一名优秀的程序员,十分优秀!