如何在 运行 之前更改 main 函数的参数
how to change the arguments of main function before running it
在下面的代码中,我想在不修改主函数的情况下更改主函数的参数。
最近看了AFL fuzzing工具的代码,对于forkserver,不知道怎么给目标程序传递参数,所以写了这个简单的程序。
我尝试过使用管道重定向标准输入并将参数写入标准输入,但它不起作用。
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
__attribute__((constructor))
void __start() {
static unsigned char tmp[4];
int count = 0;
pid_t pid;
int status;
while(count < 3){
pid = fork();
if(pid < 0) _exit(1);
if(!pid){
//how to pass "hello" to main without modfiying main function.
return;
}
count++;
if(count == 3) _exit(1);
}
//_exit(0);
}
int main(int argc, char** argv){
for(int i = 0; i < argc; i++){
printf("%d %s\n", i, argv[i]);
}
return 0;
}
如果 argv 中 "hello",argc 应为 2,输出应为“1 hello”。
在调用 C int main(int argc, char **argv)
方法之前 修改 C 运行时环境的 int argc
参数计数器 。 . . - - - = = = (; 一个讨厌的 HACK ;) = = = - - - 。 . .
我正在使用:
- 当前可用于 OS X High Sierra,
的最新 C++ 编译器
- 安装当前标准方式,使用
brew
。
要重现下面 argc.cpp
代码清单 的结果,要么:
- 更新您的 Mac OS 设置以反映我的设置,
- Install GNU compilers on your Ubuntu 64
- 为您的特定设置安装 GNU 编译器
argc.cpp :
#include <stdio.h>
__attribute__((constructor)) void start(int argc, char **argv)
{
int * pc = (int *) argv - 2; // NASTY HACK TO GET C RUNTIME argc * ;)
printf("argc = %d \n", *pc); // the original argc, on most systems ;)
int NUMBER_OF_PARAMETERS_NEEDED_FOR_FUZZING = 1; // Replace this line
// with the simple/complex logic needed for fuzz testing (fuzzing)
if(!(argc > NUMBER_OF_PARAMETERS_NEEDED_FOR_FUZZING)){
argc = NUMBER_OF_PARAMETERS_NEEDED_FOR_FUZZING + 1;
*pc = argc; // NASTY HACK TO OVERWRITE C RUNTIME argc ;)
}
// *pc = 2; // uncomment this to see that you can also reduce argc
argv[1] = "hello"; // Example setting of a fuzzy argument
// Add more lines, a loop, etc... here to set more fuzzy arguments
for (int i = 0; i < argc; i++) {
printf("%s: argv[%d] = '%s'\n", __FUNCTION__, i, argv[i]);
}
printf("argc = %d \n", argc); // the possibly modified argc
}
int main(int argc, char **argv)
{
for (int i = 0; i < argc; i++) {
printf("%s: argv[%d] = '%s'\n", __FUNCTION__, i, argv[i]);
}
printf("argc = %d \n", argc); // the possibly modified argc
return 0;
}
Mac OS 终端机:
编译:
$ /usr/local/bin/c++-9 argc.cpp -o argc
运行 带有 0
个参数,原始 int argc = 1
:
$ ./argc
argc = 1
start: argv[0] = './argc'
start: argv[1] = 'hello'
argc = 2
main: argv[0] = './argc'
main: argv[1] = 'hello'
argc = 2
运行 带有 3
个参数,原始 int argc = 4
:
$ ./argc 1 2 3
argc = 4
start: argv[0] = './argc'
start: argv[1] = 'hello'
start: argv[2] = '2'
start: argv[3] = '3'
argc = 4
main: argv[0] = './argc'
main: argv[1] = 'hello'
main: argv[2] = '2'
main: argv[3] = '3'
argc = 4
运行 , 以展示 argc
还原能力,
- 取消注释第 13 行并重新编译后(硬编码
argc = 2
):
*pc = 2; // uncomment this to see that you can also reduce argc
具有相同的3
参数,如上,原始int argc = 4
:
$ ./argc 1 2 3
argc = 4
start: argv[0] = './argc'
start: argv[1] = 'hello'
start: argv[2] = '2'
start: argv[3] = '3'
argc = 4
main: argv[0] = './argc'
main: argv[1] = 'hello'
argc = 2
如果 C 运行时环境 未 在您的系统上初始化类似于清单:
您可能需要:
- 通过将本地 C 运行时环境 与上面的 GNU 示例进行比较,and/or
来研究差异
- 实验性地修改我的代码,直到它适合你。例如:遍历 int 指针 before 以及 !after!
argv
的位置,看看你在那里找到了什么...
如果您发现破解当前的 C 运行时环境 太难,请尝试:
- Install GNU compilers on your Ubuntu 64,
- 为您的特定设置安装 GNU 编译器。
这里是 how/why 这个 hack 有效:
- 适用于您的设置的
C Runtime Environment
函数(有多种可能性)将 int argc, char **argv, char **envp
参数保存在某些内存位置 - 幸运的是,在我的设置中这些是相邻的。
- 在我的
64 bit
系统上,由于内存对齐规则,int argc
地址将比 char **argv
指向的内存多出 1 个 sizeof(int)
,即这就是为什么 - 2
在 int * pc = (int *) argv - 2;
行不是 - 1
.
╦ ╦ ╔═╗ ╔═╗ ╔═╗ ╦ ╦ ╦ ╦ ╔═╗ ╔═╗ ╦╔═ ╦ ╔╗╔ ╔═╗ ╦ ╦ ╦
╠═╣ ╠═╣ ╠═╝ ╠═╝ ╚╦╝ ─── ╠═╣ ╠═╣ ║ ╠╩╗ ║ ║║║ ║ ╦ ║ ║ ║
╩ ╩ ╩ ╩ ╩ ╩ ╩ ╩ ╩ ╩ ╩ ╚═╝ ╩ ╩ ╩ ╝╚╝ ╚═╝ o o o
在下面的代码中,我想在不修改主函数的情况下更改主函数的参数。
最近看了AFL fuzzing工具的代码,对于forkserver,不知道怎么给目标程序传递参数,所以写了这个简单的程序。
我尝试过使用管道重定向标准输入并将参数写入标准输入,但它不起作用。
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
__attribute__((constructor))
void __start() {
static unsigned char tmp[4];
int count = 0;
pid_t pid;
int status;
while(count < 3){
pid = fork();
if(pid < 0) _exit(1);
if(!pid){
//how to pass "hello" to main without modfiying main function.
return;
}
count++;
if(count == 3) _exit(1);
}
//_exit(0);
}
int main(int argc, char** argv){
for(int i = 0; i < argc; i++){
printf("%d %s\n", i, argv[i]);
}
return 0;
}
如果 argv 中 "hello",argc 应为 2,输出应为“1 hello”。
在调用 C int main(int argc, char **argv)
方法之前 修改 C 运行时环境的 int argc
参数计数器 。 . . - - - = = = (; 一个讨厌的 HACK ;) = = = - - - 。 . .
我正在使用:
- 当前可用于 OS X High Sierra, 的最新 C++ 编译器
- 安装当前标准方式,使用
brew
。
要重现下面 argc.cpp
代码清单 的结果,要么:
- 更新您的 Mac OS 设置以反映我的设置,
- Install GNU compilers on your Ubuntu 64
- 为您的特定设置安装 GNU 编译器
argc.cpp :
#include <stdio.h>
__attribute__((constructor)) void start(int argc, char **argv)
{
int * pc = (int *) argv - 2; // NASTY HACK TO GET C RUNTIME argc * ;)
printf("argc = %d \n", *pc); // the original argc, on most systems ;)
int NUMBER_OF_PARAMETERS_NEEDED_FOR_FUZZING = 1; // Replace this line
// with the simple/complex logic needed for fuzz testing (fuzzing)
if(!(argc > NUMBER_OF_PARAMETERS_NEEDED_FOR_FUZZING)){
argc = NUMBER_OF_PARAMETERS_NEEDED_FOR_FUZZING + 1;
*pc = argc; // NASTY HACK TO OVERWRITE C RUNTIME argc ;)
}
// *pc = 2; // uncomment this to see that you can also reduce argc
argv[1] = "hello"; // Example setting of a fuzzy argument
// Add more lines, a loop, etc... here to set more fuzzy arguments
for (int i = 0; i < argc; i++) {
printf("%s: argv[%d] = '%s'\n", __FUNCTION__, i, argv[i]);
}
printf("argc = %d \n", argc); // the possibly modified argc
}
int main(int argc, char **argv)
{
for (int i = 0; i < argc; i++) {
printf("%s: argv[%d] = '%s'\n", __FUNCTION__, i, argv[i]);
}
printf("argc = %d \n", argc); // the possibly modified argc
return 0;
}
Mac OS 终端机:
编译:
$ /usr/local/bin/c++-9 argc.cpp -o argc
运行 带有 0
个参数,原始 int argc = 1
:
$ ./argc
argc = 1
start: argv[0] = './argc'
start: argv[1] = 'hello'
argc = 2
main: argv[0] = './argc'
main: argv[1] = 'hello'
argc = 2
运行 带有 3
个参数,原始 int argc = 4
:
$ ./argc 1 2 3
argc = 4
start: argv[0] = './argc'
start: argv[1] = 'hello'
start: argv[2] = '2'
start: argv[3] = '3'
argc = 4
main: argv[0] = './argc'
main: argv[1] = 'hello'
main: argv[2] = '2'
main: argv[3] = '3'
argc = 4
运行 , 以展示 argc
还原能力,
- 取消注释第 13 行并重新编译后(硬编码
argc = 2
):
*pc = 2; // uncomment this to see that you can also reduce argc
具有相同的3
参数,如上,原始int argc = 4
:
$ ./argc 1 2 3
argc = 4
start: argv[0] = './argc'
start: argv[1] = 'hello'
start: argv[2] = '2'
start: argv[3] = '3'
argc = 4
main: argv[0] = './argc'
main: argv[1] = 'hello'
argc = 2
如果 C 运行时环境 未 在您的系统上初始化类似于清单:
您可能需要:
- 通过将本地 C 运行时环境 与上面的 GNU 示例进行比较,and/or 来研究差异
- 实验性地修改我的代码,直到它适合你。例如:遍历 int 指针 before 以及 !after!
argv
的位置,看看你在那里找到了什么...
如果您发现破解当前的 C 运行时环境 太难,请尝试:
- Install GNU compilers on your Ubuntu 64,
- 为您的特定设置安装 GNU 编译器。
这里是 how/why 这个 hack 有效:
- 适用于您的设置的
C Runtime Environment
函数(有多种可能性)将int argc, char **argv, char **envp
参数保存在某些内存位置 - 幸运的是,在我的设置中这些是相邻的。 - 在我的
64 bit
系统上,由于内存对齐规则,int argc
地址将比char **argv
指向的内存多出 1 个sizeof(int)
,即这就是为什么- 2
在int * pc = (int *) argv - 2;
行不是- 1
.
╦ ╦ ╔═╗ ╔═╗ ╔═╗ ╦ ╦ ╦ ╦ ╔═╗ ╔═╗ ╦╔═ ╦ ╔╗╔ ╔═╗ ╦ ╦ ╦
╠═╣ ╠═╣ ╠═╝ ╠═╝ ╚╦╝ ─── ╠═╣ ╠═╣ ║ ╠╩╗ ║ ║║║ ║ ╦ ║ ║ ║
╩ ╩ ╩ ╩ ╩ ╩ ╩ ╩ ╩ ╩ ╩ ╚═╝ ╩ ╩ ╩ ╝╚╝ ╚═╝ o o o