Can you break it without knowing the password?
你能在不知道密码的情况下破解它吗?
#include<stdio.h>
int main(int argc, char *argv[])
{
int flag = 0;
char passwd[10];
memset(passwd,0,sizeof(passwd));
strcpy(passwd, argv[1]);
if(0 == strcmp("LinuxGeek", passwd))
{
flag = 1;
}
if(flag)
{
printf("\n 密码破解 \n");
}
else
{
printf("\n 不正确的密码 \n");
}
return 0;
}
很容易看到密码就是"LinuxGeek",但是它也没给你输入密码的功能。它用的是一个很特殊的方法,要知道这个方法首先要知道mian函数里面的两个参数的标识符argc和argv。
argc和argv
我们通常叫这两个参数为——命令行参数(command line parameters),一提到命令行你大概会想到Linux。很多人喜欢用命令行的感觉,因为那让他感觉自己像电脑里的黑客。事实上在Windows里面也有命令行,那就是cmd.exe。而在Linux和Mac OSX上则是bash shell。
操作系统会给专业的用户即程序员提供许多API,程序员通过API编程来获得操作系统的各种服务。但是随着计算机的普及,对于那些不会编程的普通用户,还有那些只是想和计算机进行简单交互的用户来说,他们又该怎么办呢?
操作系统提供一个shell来与用户交互,可以看到上述每个操作系统都提供了这种shell。shell虽然直译过来是壳,但是我们通常叫它命令解释器。用户在shell中输入一个命令和相应的参数,然后shell调用操作系统来执行它。
argv是一个元素类型为char*的数组,即每个元素都是一个指向char的指针。每个元素都对应一个字符串,即一个命令行参数。而char *argv[ ]很显然是一个不完整类型,我们并不知道它的元素数量。所以参数argc就是元素的数量,或者说程序名加上参数的个数。通常参数这样写才使得函数具有灵活性。
比如你在命令行上要执行一个程序,你输入a.exe。不加上参数则argc值为1,argv[0]所指向的字符串就是a.exe。所以在这个程序中首先利用strcpy函数将argv[1]的内容复制给passwd,而argv[1]的内容是没有的,取决于你的输入。事实上strcmp在这里已毫无作用...
执行程序并加上参数aaaaaaaaaaaaa共13个a,这些a即argv[1]的内容,由于Linux的栈是向下增长的,所以flag内容直接被覆盖掉。再也不可能为0,程序直接输出为“密码破解”。现在你应该知道就算不输入aaa...程序也是可以成功break的。
父进程和子进程
程序保存在硬盘里,载入内存后才会运行。载入内存后它被称为进程(process),事实上IBM最早把它称为工作(job)。顾名思义就是一个程序正在工作,只不过后来的Multics系统研发人员不愿意使用它,将其改为进程,而其催生的Unix继承了这一术语。
在Linux里,shell执行用户命令的步骤分为两步。分别是用fork创建一个子进程,然后用exec在这个创建的子进程里执行用户输入的命令,关于fork和exec可以在Linux上查阅手册。而shell就是父进程,而它传递命令行参数给子进程来执行它...
网友评论