推理 arm-linux-gcc/g++ v3.4.1 版本的一个漏洞
发布日期:2021-07-01 04:36:47 浏览次数:2 分类:技术文章

本文共 3487 字,大约阅读时间需要 11 分钟。

     如下是自己在开发项目的时候遇到的一个问题,并简单地记录下来。讲解的思路不是很连贯,但是,其中有给出一个例子,该例子推理出了问题的所在。

 

问题的引出

       在开发项目的时候,下位机把一包事件发送给上位机,那么,自己调试,在发送数据包的时候,把事件给显示出来,有如下的逻辑:

typedef unsigned char INT8U;

typedef unsigned long long INT64U;

 

struct _EVENT

{

    INT64U cardid;    //结构体中有这个数据

    .....

};

 

INT8U buf[1204];  //存放事件包的缓存

 

memcpy(buf, .....);  //把事件包存放到 buf[] 缓存中

 

void show_card_info(INT8U *buf, INT16U count) //显示缓存信息

{

    Event *e = (Event*)buf;  //把 buf 缓存强制转换为 Event* 类型

 

    printf("e->cardid = %llu \n", e->cardid);

    .....

}

最终,运行程序发现:

1 cardid 变量中 8 个字节存放的数据是正确的,但是,使用 printf(); 输出的时候,却是错误的。

2 假如 cardid 8 个字节的数据是 0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88,而在 cardid 前面的 2 个字节是 0x1A, 0x1B 的话,那么,printf(); 输出的 carid 值是:0x1A, 0x1B , 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 这样的数据组织成的值。

就是说,cardid 的数值是 buf[ ] 中给 Event*e 引用的时候,会引用其前面的2 个字节。

注意:这种情况是在如下的 arm-linux-gcc/g++ 编译器中出现:

[weikaifeng@weikaifeng test]$ arm-linux-gcc -v

……

gcc version 3.4.1

Fedora14 系统自带的 GCC 编译器中,没有出现这种情况。

如下是一个测试的例子:

typedef unsigned char INT8U;

typedef unsigned long long INT64U;

 

struct _TEST

{

    INT64U id;

};

 

typedef struct _TEST test;

 

void func(INT8U* buf)

{

    int i = 0;

    INT8U *p = NULL;

    INT64U id = 0;

    INT64U p_id = 0;

 

    test *t = (test*)buf;

 

    printf("t->id = %llu \n", t->id);

 

    printf("buf = "); //显示传递进来的 buf[]

    for(i = 0; i < 8; i++)

    {

       printf("%2x ", buf[i]);

    }

    printf("\n");

    //计算 buf[] 存放的 id 数据

    for(i = 7; i >= 0; i--)

    {

       id = id*256 + buf[i];

    }

    printf("id = %llu \n", id);

 

    //显示 t->id 的内存数据

    p = (INT8U*)&(t->id);

    printf("p = ");

    for(i = 0; i < 8; i++)

    {

       printf("%2x ", *p);

       p++;

    }

    printf("\n");

    printf("t->id = %llu \n", t->id);

 

    //把 t->id 赋给一个变量,再次显示这个变量中 内存数据,发现与 t->id 的实际内存不一样

    //而是 main(); 函数中定义的整个 buf[] 是一样的。

    //所以,可以推论 使用 printf(); 输出 t->id 的时候,引导到了 buf[2] 的前 2 个数据

    p_id = t->id;

    printf("p_id = %llu \n", p_id);

 

    p = (INT8U*)&p_id;

    printf("p = ");

    for(i = 0; i < 8; i++)

    {

       printf("%2x ", *p);

       p++;

    }

    printf("\n");

}

 

int main(void)

{

    int i = 0;

    INT64U id = 8868;

    INT8U buf[10];

 

    buf[0] = 0x01;

    buf[1] = 0x02;

 

    for(i = 0; i < 8; i++)

    {

       buf[i + 2] = id % 256;

       id = id / 256;

    }

 

    printf("buf = ");

    for(i = 0; i < 10; i++)

    {

       printf("%2x ", buf[i]);

    }

    printf("\n");

 

 

    func(&buf[2]);    //注意,传的只是从 buf[2] 开始,为了测试在 func(); 函数中是否引用到 buf[2] 前面的 2 个字节

 

    printf("\nhehe.....\n");

    return 0;

}

Fedora14 系统自带的 GCC 编译环境中编译运行的结果如下:

[weikaifeng@weikaifeng test]$ ./test

buf =  1  2 a4 22  0  0  0  0  0  0

t->id = 8868

buf = a4 22  0  0  0  0  0  0

id = 8868

p = a4 22  0  0  0  0  0  0

t->id = 8868

p_id = 8868

p = a4 22  0  0  0  0  0  0

hehe.....

结果是完全正确的,如果使用 arm-linux-gcc v3.4.1 版本的编译器编译,然后,下载到ARM板上运行,得到的结果如下:

dig ~# ./arm_test

buf =  1  2 a4 22  0  0  0  0  0  0

t->id = 581173761

buf = a4 22  0  0  0  0  0  0

id = 8868

p = a4 22  0  0  0  0  0  0

t->id = 581173761

p_id = 581173761

p =  1  2 a4 22  0  0  0  0

hehe.....

可以看到,相同的一份代码,使用不同的编译器编译,得到不同的结果。同时,也可以推理出 arm-linux-gcc v3.4.1 版本的编译应该有这样的一个漏洞。对于 ARM 板上的芯片和当前PC上的CPU芯片,处理内存都是小端法,不会有影响。就应该是 arm-linux-gcc v3.4.1 版本编译器的问题。

最后,为了解决在ARM板上的应用程序能够显示正确的数据,可以利用:把 buf[ ] 缓存中的数据复制到一个相应的结构体中,然后,再显示结构体中的数据。

void show_card_info(INT8U *buf, INT16U count)

{

    TGDR_Event event;

    bzero(&event, sizeof(TGDR_Event));

 

    for(int i = 0; i < count; i++)

    {

       buf = buf + i*sizeof(TGDR_Event);

       memcpy(&event, buf, sizeof(TGDR_Event));      //把 buf[] 缓存中的数据复制到一个结构体中再操作

       printf("*********** i = %d **********\n", i);

       printf("CardNo = %llu \n", event.CardNo);

       printf("EvtCode = %u \n", event.EvtCode);

       printf("eDate = %u \n", event.eDate);

       printf("eTime = %u \n", event.eTime);

       printf("EvtType = %u \n", event.EvtType);

       printf("EvtActType = %u \n", event.EvtActType);

       printf("DotAddr = %u \n", event.DotAddr);

    }

}

 

转载地址:https://mylinux.blog.csdn.net/article/details/8966525 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:XML--XSD--类的循环编程过程
下一篇:常类型变量

发表评论

最新留言

路过,博主的博客真漂亮。。
[***.116.15.85]2024年04月24日 17时10分25秒