QQ登录

只需一步,快速开始

 找回密码
 注册

QQ登录

只需一步,快速开始

楼主: lluct

菜鸟求助:段错误问题!!!!

[复制链接]
发表于 2004-3-7 22:32:41 | 显示全部楼层
[code:1]
int *strcmp(const char *s1, const char *s2);  /*字符串比较函数 */
[/code:1]
这个是什么???
如果是库里面的函数,那么:
1 不用声明啦~
2 即使声明,你的声明也是错的……strcmp的返回值类型是int

[code:1]
#include <stdio.h>     /*文件操作及输入输出*/
#include <string.h>    /*字符串比较strcmp*/
[/code:1]
这些注释没用的~学过C语言的都应该知道这些头文件干什么,加上注释反而会显得画蛇添足

[code:1]
  fwrite(pSetPassword, sizeof(char), MAX, SetFile); /*写入文件 */
  fclose (SetFile);  /*关闭文件 */
[/code:1]
这些注释也没什么用

[code:1]
if ((FileCheck = fopen ("password.dat", "rb")) == NULL)
    {
      printf("发现程序密码为空,本程序要输入密码才可以运行!\n");
      setpassword();   /*如果找不到密码文件,就调用设置密码函数 */
    }
[/code:1]
错误信息应该输出到stderr上,可以这样:
[code:1]
fprintf(stderr,"can not find password file\n");
[/code:1]
[code:1]
FILE *SetFile;                   /*建立密码文件  */
[/code:1]
没必要写注释,而且,此时还没有建立文件

[code:1]
*pSetPassword = SetPassword;
[/code:1]
[code:1]
*pCheckPassword = CheckPassword;
[/code:1]
冗余变量,pCheckPassword和pSetPassword可以省略(一下子就省下8字节的空间阿!)

[code:1]
  if ((SetFile = fopen ("password.dat", "wb")) == NULL) /*建立文件 */
  {
    printf("系统错误!\n @_@");
    exit (0);
  }
[/code:1]
错误信息向stderr输出
异常退出应该是exit(-1);

汗……不查了,好累阿……

1 错误输出应该向stderr 异常退出应该是exit(-1);
2 继续注意冗余变量问题
3 库函数使用只要#include那个库就可以了,没必要声明
4 注释要合理,不要画蛇添足
5 由于你这个是一个密码设置的程序,一定一定注意安全问题。你现在这个程序我可以轻易突破,原理就是利用缓冲区溢出。注意:scanf函数是不检查缓冲区是否越界的。你想想,如果我输入的密码大于缓冲区的长度会如何?注意:在80X86的机器上,堆栈增长方向和字符串增长方向相反,这就意味着,你的程序中,一旦我输入的字符长度大于你的缓冲区长度,那么我就会压到前面的东西,这样,可以轻易修改函数的返回地址,让执行完一个函数后,执行我的特定代码(比如Shell Code)最可怕的是,我的那段代码拥有和你的程序一样的权限
回复

使用道具 举报

 楼主| 发表于 2004-3-7 22:48:12 | 显示全部楼层
[quote:964dbb179b="默难"][code:1]
int *strcmp(const char *s1, const char *s2);  /*字符串比较函数 */
[/code:1]
这个是什么???
如果是库里面的函数,那么:
1 不用声明啦~
2 即使声明,你的声明也是错的……strcmp的返回值类型是int

[code:1]
#include <stdio.h>     /*文件操作及输入输出*/
#include <string.h>    /*字符串比较strcmp*/
[/code:1]
这些注释没用的~学过C语言的都应该知道这些头文件干什么,加上注释反而会显得画蛇添足

[code:1]
  fwrite(pSetPassword, sizeof(char), MAX, SetFile); /*写入文件 */
  fclose (SetFile);  /*关闭文件 */
[/code:1]
这些注释也没什么用

[code:1]
if ((FileCheck = fopen ("password.dat", "rb")) == NULL)
    {
      printf("发现程序密码为空,本程序要输入密码才可以运行!\n");
      setpassword();   /*如果找不到密码文件,就调用设置密码函数 */
    }
[/code:1]
错误信息应该输出到stderr上,可以这样:
[code:1]
fprintf(stderr,"can not find password file\n");
[/code:1]
[code:1]
FILE *SetFile;                   /*建立密码文件  */
[/code:1]
没必要写注释,而且,此时还没有建立文件

[code:1]
*pSetPassword = SetPassword;
[/code:1]
[code:1]
*pCheckPassword = CheckPassword;
[/code:1]
冗余变量,pCheckPassword和pSetPassword可以省略(一下子就省下8字节的空间阿!)

[code:1]
  if ((SetFile = fopen ("password.dat", "wb")) == NULL) /*建立文件 */
  {
    printf("系统错误!\n @_@");
    exit (0);
  }
[/code:1]
错误信息向stderr输出
异常退出应该是exit(-1);

汗……不查了,好累阿……

1 错误输出应该向stderr 异常退出应该是exit(-1);
2 继续注意冗余变量问题
3 库函数使用只要#include那个库就可以了,没必要声明
4 注释要合理,不要画蛇添足
5 由于你这个是一个密码设置的程序,一定一定注意安全问题。你现在这个程序我可以轻易突破,原理就是利用缓冲区溢出。注意:scanf函数是不检查缓冲区是否越界的。你想想,如果我输入的密码大于缓冲区的长度会如何?注意:在80X86的机器上,堆栈增长方向和字符串增长方向相反,这就意味着,你的程序中,一旦我输入的字符长度大于你的缓冲区长度,那么我就会压到前面的东西,这样,可以轻易修改函数的返回地址,让执行完一个函数后,执行我的特定代码(比如Shell Code)最可怕的是,我的那段代码拥有和你的程序一样的权限
[/quote]

谢谢老大了。学到了很多的东西。
   其实我今天才刚学文件   
回复

使用道具 举报

发表于 2004-3-7 22:54:20 | 显示全部楼层
最后,解释一下我前面说的那个缓冲区溢出:
这个……鄙人的表达能力不是很强,还是喜欢用代码说明问题,你看看这个代码:
[code:1]
#include <stdio.h>

int main()
{
        int i;
        char a;

        i=0;

        scanf("%d",&a);/*Attention!!! Here : type is %d*/
        printf("%d\n",i);
        return 0;
}
[/code:1]
那么,我们看看运行结果:
[code:1]
[monnand@monnand test]$ gcc test.c
[monnand@monnand test]$ ./a.out
-1
16777215
[monnand@monnand test]$
[/code:1]
明白了?
也就是说,a明明应该只占用1个字节的空间,然而,我们调用的scanf中用了%d,所以scanf则按照int类型处理,即,每个单元4字节。
80X86系统中:栈的增长方向是低地址向高地址,而指针的增长方向却是高地址向低地址。存储一个变量,本着“高高低低”的原则。也就是说,变量的高端存储在内存的高端,低端存储在内存的低端。
那么,这样,scanf由于一下子占了自&a(变量a的起始地址)开始向高地址方向的4个字节(包括&a),那么也就是侵占了i的高端的三个字节。
下面的程序可以看出来(下面的程序你可能看不懂,而且里面采用了一些非常规手段,你可以不必理解)
[code:1]
#include <stdio.h>

int main()
{
        int i;
        char a;
        char *s;

        i=0;

        scanf("%d",&a);
        printf("%d\n",i);
        s=(char *)&i;

        for(a=0;a<4;a++,s++)
                printf("%2x\n",(int)*s);
        return 0;
}
[/code:1]
输出结果:
[code:1]
[monnand@monnand test]$ gcc test.c
[monnand@monnand test]$ ./a.out
-1
16777215
ffffffff
ffffffff
ffffffff
0
[monnand@monnand test]$
[/code:1]
明白?
回复

使用道具 举报

 楼主| 发表于 2004-3-7 23:11:53 | 显示全部楼层
[quote:1d6a6950c8="默难"]最后,解释一下我前面说的那个缓冲区溢出:
这个……鄙人的表达能力不是很强,还是喜欢用代码说明问题,你看看这个代码:
[code:1]
#include <stdio.h>

int main()
{
        int i;
        char a;

        i=0;

        scanf("%d",&a);/*Attention!!! Here : type is %d*/
        printf("%d\n",i);
        return 0;
}
[/code:1]
那么,我们看看运行结果:
[code:1]
[monnand@monnand test]$ gcc test.c
[monnand@monnand test]$ ./a.out
-1
16777215
[monnand@monnand test]$
[/code:1]
明白了?
也就是说,a明明应该只占用1个字节的空间,然而,我们调用的scanf中用了%d,所以scanf则按照int类型处理,即,每个单元4字节。
80X86的栈中,栈的增长方向是低地址向高地址,而指针的增长方向却是高地址向低地址。存储一个变量,本着“高高低低”的原则。也就是说,变量的高端存储在内存的高端,低端存储在内存的低端。
那么,这样,scanf由于一下子占了自&a(变量a的起始地址)开始向高地址方向的4个字节(包括&a),那么也就是侵占了i的高端的三个字节。
下面的程序可以看出来(下面的程序你可能看不懂,而且里面采用了一些非常规手段,你可以不必理解)
[code:1]
#include <stdio.h>

int main()
{
        int i;
        char a;
        char *s;

        i=0;

        scanf("%d",&a);
        printf("%d\n",i);
        s=(char *)&i;

        for(a=0;a<4;a++,s++)
                printf("%2x\n",(int)*s);
        return 0;
}
[/code:1]
输出结果:
[code:1]
[monnand@monnand test]$ gcc test.c
[monnand@monnand test]$ ./a.out
-1
16777215
ffffffff
ffffffff
ffffffff
0
[monnand@monnand test]$
[/code:1]
明白?[/quote]


    
我唯一明白的就是要努力去学。
回复

使用道具 举报

 楼主| 发表于 2004-3-8 03:09:06 | 显示全部楼层
已经解决了。谢谢默难老大了。现更正如下:
(不会又挑刺吧)   
[code:1]
#include <stdio.h>      
#include <string.h>      
#define MAX 10           /*设置密码长度*/

void setpassword(void);   /*设置密码函数*/
void password(void);      /*检验密码函数*/
void function(void);

int main (int argc, char *argv[])      /*主函数*/
{
  FILE *CheckFile;  

  if ((CheckFile = fopen("password.dat", "rb")) == NULL)
    {
      printf("\n发现程序密码为空,本程序需要输入密码才能运行!\n");
      setpassword();
    }
  else
    password();


}

void setpassword(void)
{
  FILE *SetPasswordFile;
  char SetPassword[MAX];
  char ConfirmPassword[MAX];
  char AddPass[MAX],*pAddPass = AddPass;
  char Input;
  int Count = 0;                   /*同下*/
  memset (SetPassword, 0, MAX);    /*数组设置初值,不设置会产生段错误*/
  memset (SetPassword, 0, MAX);
  memset (AddPass, 0, MAX);

  system ("stty -echo");  /*屏蔽屏幕输出*/

  printf("\n请输入密码:");
  while ((Input = getchar ()) != '\n')
    {
      SetPassword[Count] = Input;
      Count++;
    }
  SetPassword[Count] = '\0';
  
  if (Count > MAX)
    {
      printf("\n密码过长!!\n");
      system("stty -cbreak echo");  /*恢复屏幕输出*/
      exit (-1);  
    }

  Count = 0;
  printf("\n请确认密码:");
  while ((Input = getchar ()) != '\n')
    {
      ConfirmPassword[Count] = Input;
      Count++;
    }
  ConfirmPassword[Count] = '\0';

  if ((strcmp (SetPassword, ConfirmPassword)) == 0)
    printf("\n密码符合! :)\n");
  else
   {
     printf("\n密码不符合! :(\n");
     system("stty -cbreak echo");
     exit (0);
   }

  if ((SetPasswordFile = fopen ("password.dat", "wb")) == NULL)
    {
      fprintf(stderr,"\n系统错误! @_@\n"); /*stderr是标准错误输出设备*/
      system("stty -cbreak echo");
      exit(-1);     /*程序异常退出是-1,正常为0*/
    }
  else
    printf("\n密码设置成功! ^_^\n");

  Count =0;
  while ((SetPassword[Count]) != '\0')   /*简单加密*/
    {
      AddPass[Count] = SetPassword[Count] +3;
      Count++;
    }

  system ("stty -cbreak echo");
  fwrite (pAddPass, sizeof(char), MAX, SetPasswordFile);
  fclose (SetPasswordFile);
  
}

void password(void)
{
  FILE *GetPasswordFile;
  char GetPassword[MAX], *pGetPassword[MAX];
  char ComparePassword[MAX];
  char SubPass[MAX], *pSubPass = SubPass;  
  char Input;
  int Count = 0;
  int Times = 0;
  memset(GetPassword, 0, MAX);
  memset(ComparePassword, 0, MAX);
  memset(SubPass, 0, MAX);

  if ((GetPasswordFile = fopen ("password.dat", "rb")) == NULL)
  {
    fprintf(stderr, "\n密码没有设置! 6_6\n");
    exit (-1);
  }

  fread (pSubPass, sizeof(char), MAX, GetPasswordFile);

  
  while ((SubPass[Count]) !='\0')    /*简单解密*/
    {
      GetPassword[Count] = SubPass[Count] -3;
      Count++;
    }

  
  while (Times < 3) /*设置密码出错次数*/
    {
      memset(ComparePassword, 0, MAX);
      Count = 0;
      system("stty -echo");
      printf("\n请输入您的密码:");
      while ((Input = getchar ()) != '\n')
        {
          ComparePassword[Count] = Input;
          Count++;
        }
      ComparePassword[Count] ='\0';

      if ((strcmp (GetPassword, ComparePassword)) == 0)
        {
          printf("\n密码正确!\n");
          system("stty -cbreak echo");
          printf("\n谢谢您的使用!. by lluct @^_^@\n");
          function();
          exit (0);
        }
      else
        printf("\n密码错误!!!  *_*\n");
      Times++;
    }
  system ("stty -cbreak echo");
  fclose (GetPasswordFile);
}

void function(void)
{
  int choose;
  printf("%s\n%s",
         "\n1:删除密码  2:打开光驱  3:关闭光驱  4:退出\n",
         "请选择:");
  scanf("%d", &choose);
  switch (choose)
    {
    case 1:
      {
        system("rm password.dat");
        printf("密码已删除,请重新运行程序设置密码!\n");
        break;
      }
    case 2:
      system ("eject -r&");
      break;
    case 3:
      system ("eject -t&");
      break;
    case 4:
      exit (0);
    default:
      printf("选择错误!!\n");
    }
}
[/code:1]
回复

使用道具 举报

发表于 2004-3-8 14:21:04 | 显示全部楼层

这个……我就不说什么了,有空你QQ上找我,我跟你慢慢说说,这程序还有不少问题~
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

GMT+8, 2024-11-8 20:37 , Processed in 0.043234 second(s), 13 queries .

© 2021 Powered by Discuz! X3.5.

快速回复 返回顶部 返回列表