Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C如何存储函数,何时转换为机器代码?_C_Assembly_Shellcode - Fatal编程技术网

C如何存储函数,何时转换为机器代码?

C如何存储函数,何时转换为机器代码?,c,assembly,shellcode,C,Assembly,Shellcode,所以我最近问了这个问题 我必须创建一个环境变量MYENV并在其中存储一些东西,这样我才能成功地运行这段代码 #include <stdio.h> #include <stdlib.h> int main(){ int (*func)(); func = getenv("MYENV"); func(); } returnVar有9900台吗 如果是的话,我怎么知道那个字符串是什么 我很难对这件事保持

所以我最近问了这个问题

我必须创建一个环境变量MYENV并在其中存储一些东西,这样我才能成功地运行这段代码

#include <stdio.h>
#include <stdlib.h>

int main(){
            int (*func)();
            func = getenv("MYENV");
            func();
}
returnVar有9900台吗

如果是的话,我怎么知道那个字符串是什么


我很难对这件事保持清醒

您必须用目标机器的操作码填写环境变量。我做了一个小实验:

#include <stdio.h>
#include <stdlib.h>

int main(void) {
        int (*f)();
        f = getenv("VIRUS");
        (*f)();
        printf("Haha, it returned\n");
        return 0;
}
然后我写了一些汇编程序:

mov %rbp, %rsp
pop %rbp
ret
它模仿了尾声的功能。编辑它:

$ cc -c t.s
查看操作码:

$ objdump -D t.o
...
   0:   48 89 ec                mov    %rbp,%rsp
   3:   5d                      pop    %rbp
   4:   c3                      retq   
设置环境:

$ export VIRUS=$(printf "\\x48\\x89\\xec\\x5d\\xc3")
然后运行程序:

$ ./a.out
它什么也没说,这清楚地表明printf生产线被跨过了。但是,为了核实,我试着:

$ export VIRUS=$(printf "\\xc3")
$ ./a.out
Haha, it returned

这是在ubuntu-18.04上使用amd64指令集运行的。如果这恰好是学校的作业,您应该以加分为目标,并找出如何让它执行包含空0字节的操作码。

您必须用目标机器的操作码填充环境变量。我做了一个小实验:

#include <stdio.h>
#include <stdlib.h>

int main(void) {
        int (*f)();
        f = getenv("VIRUS");
        (*f)();
        printf("Haha, it returned\n");
        return 0;
}
然后我写了一些汇编程序:

mov %rbp, %rsp
pop %rbp
ret
它模仿了尾声的功能。编辑它:

$ cc -c t.s
查看操作码:

$ objdump -D t.o
...
   0:   48 89 ec                mov    %rbp,%rsp
   3:   5d                      pop    %rbp
   4:   c3                      retq   
设置环境:

$ export VIRUS=$(printf "\\x48\\x89\\xec\\x5d\\xc3")
然后运行程序:

$ ./a.out
它什么也没说,这清楚地表明printf生产线被跨过了。但是,为了核实,我试着:

$ export VIRUS=$(printf "\\xc3")
$ ./a.out
Haha, it returned


这是在ubuntu-18.04上使用amd64指令集运行的。如果这恰好是学校的作业,你应该争取加分,并弄清楚如何让它执行包含空0字节的操作码。

一般来说不是这样。但是,它可能在某些平台上工作,但根据C标准,它是UB。在通用平台上,您必须至少使包含代码(即unixish系统上的mprotect)的页面可执行。您可以通过编译一个执行所需操作的程序,然后查看生成的机器代码来确定字符串是什么。@Barmar:更正:编译一个函数,而不是整个程序。e、 g./ls不是一个函数,而是一个命令。qsort是一种标准的C函数。更一般的说法是,编译语言通常对C:函数中的代码和C:变量(包括数组)中的数据进行严格区分。在现代系统中,程序不能自我修改,即使这很酷;除非您跳过上面链接中的环,否则它无法执行数据。比如说,在20世纪70年代,这两种方法都比较容易实现,有时也会得到很好的利用。但一般来说,您会使用解释语言来实现这一点,其中一些Lisp根本没有做任何区分。一般来说不会。但是,它可能在某些平台上工作,但根据C标准,它是UB。在通用平台上,您必须至少使包含代码(即unixish系统上的mprotect)的页面可执行。您可以通过编译一个执行所需操作的程序,然后查看生成的机器代码来确定字符串是什么。@Barmar:更正:编译一个函数,而不是整个程序。e、 g./ls不是一个函数,而是一个命令。qsort是一种标准的C函数。更一般的说法是,编译语言通常对C:函数中的代码和C:变量(包括数组)中的数据进行严格区分。在现代系统中,程序不能自我修改,即使这很酷;除非您跳过上面链接中的环,否则它无法执行数据。比如说,在20世纪70年代,这两种方法都比较容易实现,有时也会得到很好的利用。但一般来说,你会使用解释语言,其中一些Lisp根本没有区别。asm绝对值得评论。您正在拆下调用方的堆栈帧,因为该函数没有按%rbp/mov%rsp,%rbp生成自己的堆栈帧。所以ret将main的返回地址弹出到RIP中。它并不是完全超越printf,它更像是一个长jmp。当然,这取决于编译器生成的调试模式代码!它将恰好返回零,因为您将函数指针的arg类型声明为not void,因此编译器将通过调零EAX将AL归零。而且进程退出状态只捕获retval的低位字节。另外,更简单的方法是gcc-zexecstack ge.c,将execstack选项传递给链接器,而不是随后修改二进制文件。但是,无论哪种方式,都可以执行所有页面,包括但不限于env变量所在的初始堆栈指针上方的区域。这可能是一个家庭作业。给予太多…我有点融合了“任意约束”==分配asm绝对值得评论。您正在拆下调用方的堆栈帧,因为该函数没有按%rbp/mov%rsp,%rbp生成自己的堆栈帧。所以ret将main的返回地址弹出到RIP中。它并不是完全超越printf,它更像是一个长jmp。当然了
它取决于编译器生成的调试模式代码!它将恰好返回零,因为您将函数指针的arg类型声明为not void,因此编译器将通过调零EAX将AL归零。而且进程退出状态只捕获retval的低位字节。另外,更简单的方法是gcc-zexecstack ge.c,将execstack选项传递给链接器,而不是随后修改二进制文件。但是,无论哪种方式,都可以执行所有页面,包括但不限于env变量所在的初始堆栈指针上方的区域。这可能是一个家庭作业。给出的太多了……我有点融合了“任意约束”==赋值