• 利用scanf函数修改内存中任意位置内容


        Scanf函数是常用的函数,它的作用一般认为是让用户给变量赋值。使用方法一般是scanf(“%d”, &num) 第二个参数是变量的地址。如果第二个参数不是变量的地址,而是变量本身,那么程序就会报错了。实际上,如果第二个参数是变量本身,程序也不一定报错,报错与否取决于这个变量的大小。

        透过现象看本质,scanf函数的作用其实是:把用户输入的字符格式化到指定格式,并输出到指定内存。事实上第二个参数可以是任意一个地址,而且我们可以直接指定它。

        如果第二个参数是一个变量本身,那么程序的报错与否,取决于变量的值所代表的那段内存地址空间是否属于Ring3,换句话说,也就是取决于这块内存是否属于用户可以编辑的内存区域。

        先来看一个会报错的情况。

     1 #include <stdio.h>
     2 
     3 int main()
     4 {
     5     int num = 6;
     6 
     7     printf("input num.\r\n");
     8     scanf("%d", num);
     9 
    10     printf("input finished.\r\n");
    11     printf("num's value is %d.\r\n", num);
    12 
    13     system("pause");
    14 
    15     return 0;
    16 }

        程序第8行,scanf(“%d”, num)的第二个参数是整形变量num的自身,按常理来说是不对的,如果想把用户输入赋值给num,第二个参数应该是&num才对。编译运行后,果然报错。

        现在我们改变示例程序,尝试突破第二个参数不能为变量自身的这个认识。我们把num的初始值修改为了74565(十六进制的12345)。再次编译运行。

        这次竟然没有报错。用户成功输入了8。当然这个8并不是赋值给num了。可以看到num的值依然是74565。利用WinHex查看进程的内存,我们应该会在0x00012345开始的4字节内存空间内,发现以小尾方式存储的8,也就是08 00 00 00

        这证明了scanf函数的本质:把用户输入的字符格式化到指定格式,并输出到指定内存。第一个示例程序之所以报错,是因为num的初始值6,转化为十六进制地址0x00000006,是属于系统占用的内存区域,尝试修改这一区域的内存所以报错。0x000000000x0000FFFF这片区域是系统的领空,一旦num的值大于这个范围,程序便不会报错了(当然也不能太大,大于用户自身可操作的内存范围0x0001000-0x7FFF0000还是会报错)。虽然不会报错,但是程序运行的结果却并不是把用户的输入赋值给num,而是修改了内存中某个位置的内容,所以用起来要小心。

      当然也可以直接制定要修改的内存位置。示例程序如下所示,我们想要改变虚拟内存中起始地址为0x00012345,占4个字节空间(int型数值)的地址:

    #include <stdio.h>
    
    int main()
    {
        printf("Check target RAM (00012345) status.\r\n");
        scanf("%d", 0x00012345);
    printf(
    "Check again.\r\n"); system("pause"); return 0; }

        编译运行后,首先用WinHex查看当前0x00012345处的内存内容。

        此时0x00012345处全是00

      输入任意整形数据,尝试把数据写入0x00012345起始的这片4字节区域。

        输入的1234567890转换成十六进制是499602D2。小尾形式是D2 02 96 49。查看内存,这段地址果然发生了改变。

      这种对scanf函数的利用方法,可以修改虚拟内存中任意位置的数据。对内存结构熟悉的话,可以用scanf函数偷偷修改一些东西。

  • 相关阅读:
    向Oracle 数据表中插入一条带有日期类型的数据
    JDBC 连接Oracle 数据库,JDBC 连接Mysql 数据库
    球球大作战四亿人都在玩?玩家回归没有优越感,新玩家游戏被虐,游戏体验感极差!
    struts2中的错误--java.lang.NoClassDefFoundError: org/apache/commons/lang3/StringUtils
    如何在idea中设置 jsp 内容修改以后,立即生效而不用重新启动服务?
    idea中 在接口中如何直接跳转到该接口的是实现类中?
    使用IDEA 创建Servlet 的时候,找不到javax.servlet
    如何高效的遍历HashMap 以及对key 进行排序
    springboot 自动装配
    git 多账户添加ssh秘钥
  • 原文地址:https://www.cnblogs.com/zhugehq/p/5918554.html
Copyright © 2020-2023  润新知