- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在试验 shellcode 并偶然发现了 nop-slide 技术。我写了一个小工具,它将缓冲区大小作为参数并构造一个像这样的缓冲区:[ NOP | SC | RET ],NOP 占据缓冲区的一半,然后是 shellcode,其余部分填充(猜测的)返回地址。它与他著名论文中描述的工具 aleph1 非常相似。
我的易受攻击的测试应用程序与他的论文中的相同:
int main(int argc, char **argv) {
char little_array[512];
if(argc>1)
strcpy(little_array,argv[1]);
return 0;
}
我测试了它,很好,它有效:
jth@insecure:~/no_nx_no_aslr$ ./victim $(./exploit 604 0)
$ exit
但老实说,我不知道为什么。好的,保存的 eip 按预期被覆盖,但我认为它没有跳入缓冲区的某个地方,而是跳入了 argv。
gdb 在 调用 strcpy() 之前显示了以下地址:
(gdb) i f
Stack level 0, frame at 0xbffff1f0:
eip = 0x80483ed in main (victim.c:7); saved eip 0x154b56
source language c.
Arglist at 0xbffff1e8, args: argc=2, argv=0xbffff294
Locals at 0xbffff1e8, Previous frame's sp is 0xbffff1f0
Saved registers:
ebp at 0xbffff1e8, eip at 0xbffff1ec
little_array 的地址:
(gdb) print &little_array[0]
$1 = 0xbfffefe8 "\020"
在 strcpy() 之后:
(gdb) i f
Stack level 0, frame at 0xbffff1f0:
eip = 0x804840d in main (victim.c:10); saved eip 0xbffff458
source language c.
Arglist at 0xbffff1e8, args: argc=-1073744808, argv=0xbffff458
Locals at 0xbffff1e8, Previous frame's sp is 0xbffff1f0
Saved registers:
ebp at 0xbffff1e8, eip at 0xbffff1ec
那么,这里发生了什么?我用了一个604字节的buffer来溢出little_array,所以他当然覆盖了saved ebp,saved eip和argc还有argv,猜测的地址是0xbffff458。
然后返回后,EIP指向0xbffff458。但是little_buffer位于0xbfffefe8处,相差1136字节,所以他肯定不是在执行little_array。我跟随 stepi 命令执行,好吧,在 0xbffff458 及以后,他执行 NOP 并到达 shellcode。
我不太清楚为什么会这样。首先,他在 argv 而不是 little_array 中执行我的 shellcode 是否正确?加载程序(?)在哪里将 argv 放到堆栈上?我以为它紧跟在argc之后,但是在argc和0xbffff458之间,有620字节的差距。他怎么可能成功地“降落”在地址 0xbffff458 的 NOP-Pad 中,这个地址远高于保存在 0xbffff1ec 的 eip?
有人可以澄清一下吗?我实际上不知道为什么会这样。我的测试机器是没有 ASLR 的 Ubuntu 9.10 32 位机器。受害者有一个可执行堆栈,用 execstack -s 设置。
提前致谢。
最佳答案
首先,绘制堆栈图。
0xBFFFF4F9 | | ---------- ... 0xBFFFF29E | NOP |0xBFFFF29D | NOP | argv[1] * guestimate ----------0xBFFFF29C | '\0' | ...0xBFFFF295 | '/' |0xBFFFF294 | '.' | argv[0] "./victim" ---------- ... ----------0xBFFFF1F8 | NULL |0xBFFFF1F8 | &argv[1] |0xBFFFF1F4 | &argv[0] | argv ---------- 0xBFFFF1F0 | 0x000002 | argc ---------- ...0xBFFFEFE9 | |0xBFFFEFE8 | | little_array ----------
(注意:在图中,一些框每行包含 1 个字节,其他框则为 4 或 8 个,具体取决于内部存储的类型)
And where does the loader(?) place argv onto the stack?
argc
和 argv
在调用 strcpy
后被覆盖表明它们可能在 little_array
之上。我将它们放在 0xBFFFF1F0,因为那是前一帧的堆栈结束的地方,而且 main
的帧似乎没有空间,即使 GDB 说 arglist 位于 0xBFFFF1E8。它在我的系统上撒谎——argc
和 argv
在 little_array 之下。尝试使用 p &argv
和 p &argc
来确定它们的放置位置。
由于 0xBFFFF458 在 argv[1] 中,argv[1] 中的 shellcode 确实将被执行,而不是 little_array
中的。由于 shell 代码有两份副本(一份在 little_array
中,另一份在 argv[1]
中),因此可以执行任何一个,具体取决于您猜测的返回地址。
I thought [argv] follows immediately after argc, but between argc and 0xbffff458, there is a gap of 620 bytes.
0xBFFFF458 是 存储在 argv
中的值(注意 argc
与 (signed)0xBFFFF458 相同) == -1073744808
)。之前,argv
包含 0xbffff294。在这两种情况下,argv
本身都存储在别处。
关于c - 跳进argv?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2750132/
目前我正在学习 C 并试图理解这些说明。它们真的不同吗? ++*argv *argv++ *(++argv) *(argv++) 谢谢! 最佳答案 后缀递增运算符的优先级高于指针取消引用运算符,而不是
我正在与在 Hostgator 共享主机上运行的 PHP CLI 的一个(也许)简单问题作斗争。一个简单的代码: 在我的本地机器上运行时以及其他几个 php 实例: php test.php arg
谁能解释一下原因 int main(int argc, const char * argv[]) { while (* argv) puts(* argv++); return 0 ;
从 K&R 的 C 书的第 5.10 章开始,argv 的概念被引入以允许命令行参数。 argv 是指向字符指针数组的指针。据此,以下代码如何检查提供的参数是否以连字符开头? (*++argv)[0]
我不明白 sys.argv 和 argv 之间的区别,网上没有任何东西给我我理解的概念。如果两者相同!我们什么时候使用 sys.argv 什么时候使用 argv ? 如果不是,sys.argv 是什么
我正在编写一个接受参数的 C 程序,char *argv[] 来决定运行哪个 exec()。我有 execlp(argv[1], argv[1], NULL) 可以正常工作。出于某种原因,execvp
char** argv 和 char* argv[] 有什么区别?在 int main(int argc, char** argv) 和 int main(int argc, char* argv[]
我目前有一个 python 脚本,可以在大型网络中完成一项非常有用的任务。我所做的是使用 lsof -iTCP -F 和其他一些选项来转储所有监听的 TCP 套接字。我能够得到 argv[0],这不是
为什么 argvs 的行为很奇怪?示例: 这将按预期工作,打印第一个参数的第一个字符。 printf("%c", *argv[1]); 但是,这将打印 ascii 表中的字符(又名“更大”,表示为数字
我做了一个小的重复异或加密器。您可以使用您选择的键对您选择的字符串进行异或运算,它可以选择将其输出到文件中。 无论何时使用单个单词(无空格)字符串和键运行程序,都没有问题。但是,只要字符串或键中有空格
我刚开始学习 C,想知道我应该在我的主要方法中使用其中的哪一个。有什么不同吗?哪个更常见? 最佳答案 由于您刚开始学习 C,我建议您首先真正尝试了解数组和指针之间的区别,而不是共同的东西。 在参数和数
所以我在编译器转换的函数中传递数组时在幕后阅读过 int myArray(int arr[]) 进入 int myArray(int *arr) 例如,大多数时候数组也会衰减为指针 arr[0] 与相
我正在编写一个小的 shell 程序,它接受一个命令并执行它。如果用户输入无效命令,则 if 语句返回 -1。如果命令正确,它就会执行命令,但是一旦它执行了命令,程序就会结束。我做错了什么是不执行它之
是否可以传入自定义参数列表? 与现实生活中的用例相比,更多是出于好奇,但例如,我可能希望在让 argparse 完成其工作之前将所有参数转换为小写。 最佳答案 Yes .只需传入要parse_args
我知道这个问题很基础,我也是新手,所以请帮我解决这个问题: 我有这个代码: int wmain(int argc, wchar_t *argv[]) { if (*argv[1] == L'-
这个问题在这里已经有了答案: Understanding slicing (38 个答案) 关闭 3 个月前。 我写了这段代码: #!/usr/bin/env python import sys i
我的程序获取主要参数,我的任务是检查用户是否在执行文件和参数之间输入了空格。 这是一个没有在 argv[0] 为 HW01 和 argv[1] 之间输入空格的人的例子/n: HW01/n 但是如果有人
我的 c 技能很生疏,所以如果这是一个愚蠢的问题,我深表歉意,但我什至没想过要寻找这个简单问题的答案。此代码编译时没有任何警告: #include int run_script( int argc,
这个问题在这里已经有了答案: Should I use char** argv or char* argv[]? (10 个答案) What does the 'array name' mean i
我有以下代码片段: int main(int argc, char *argv[]) { char line[MAXLINE]; long lineno = 0; i
我是一名优秀的程序员,十分优秀!