C如何存储函数以及它何时转换为机器代码?
How does C store functions and when does it convert to machine code?
所以我最近问了这个
我必须创建一个环境变量 MYENV 并在其中存储一些东西,这样我才能成功 运行 这段代码。
#include <stdio.h>
#include <stdlib.h>
int main(){
int (*func)();
func = getenv("MYENV");
func();
}
早些时候我在做类似 export MYENV=ls
的事情。
用户指出的是不正确的,因为当调用 func() 时,它基本上告诉 C 运行 存储在变量 func
中的指令,这将是字符串 ls
并且不是正确的机器代码。所以我应该传递一些 shellcode。
现在我想知道这是否适用于一般功能。当我声明一个函数时,让我们说 myFunction()
,让我们说乘以 100
和 99
和 returns 的值,然后变量 myFunction
将指向一组存储在某处的机器指令,它将 100
和 99
和 returns 的值相乘。
如果我要找出那些机器指令并将它们存储在一个字符串中并使 myFunction
指向它,然后如果我调用 myFunction()
我们将得到 9900
回来了?
这就是我的意思:
int (*myFunc)();
char *var = <machine_instructions_in_string_format>
int returnVar = myFunc();
returnVar 会有 9900 吗?
如果是,我如何找出该字符串是什么?
我很难理解这个问题。
您必须使用目标机器的操作码填充环境变量。我做了一个小实验:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int (*f)();
f = getenv("VIRUS");
(*f)();
printf("Haha, it returned\n");
return 0;
}
我编译了它,然后使用execstack:
$ cc ge.c
$ execstack -s ./a.out
然后我写了一点汇编:
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) 字节的操作码。
所以我最近问了这个
我必须创建一个环境变量 MYENV 并在其中存储一些东西,这样我才能成功 运行 这段代码。
#include <stdio.h>
#include <stdlib.h>
int main(){
int (*func)();
func = getenv("MYENV");
func();
}
早些时候我在做类似 export MYENV=ls
的事情。
用户指出的是不正确的,因为当调用 func() 时,它基本上告诉 C 运行 存储在变量 func
中的指令,这将是字符串 ls
并且不是正确的机器代码。所以我应该传递一些 shellcode。
现在我想知道这是否适用于一般功能。当我声明一个函数时,让我们说 myFunction()
,让我们说乘以 100
和 99
和 returns 的值,然后变量 myFunction
将指向一组存储在某处的机器指令,它将 100
和 99
和 returns 的值相乘。
如果我要找出那些机器指令并将它们存储在一个字符串中并使 myFunction
指向它,然后如果我调用 myFunction()
我们将得到 9900
回来了?
这就是我的意思:
int (*myFunc)();
char *var = <machine_instructions_in_string_format>
int returnVar = myFunc();
returnVar 会有 9900 吗?
如果是,我如何找出该字符串是什么?
我很难理解这个问题。
您必须使用目标机器的操作码填充环境变量。我做了一个小实验:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int (*f)();
f = getenv("VIRUS");
(*f)();
printf("Haha, it returned\n");
return 0;
}
我编译了它,然后使用execstack:
$ cc ge.c
$ execstack -s ./a.out
然后我写了一点汇编:
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) 字节的操作码。