推理 arm-linux-gcc/g++ v3.4.1 版本的一个漏洞
2013-05-23 17:54
267 查看
如下是自己在开发项目的时候遇到的一个问题,并简单地记录下来。讲解的思路不是很连贯,但是,其中有给出一个例子,该例子推理出了问题的所在。
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);
}
}
问题的引出
在开发项目的时候,下位机把一包事件发送给上位机,那么,自己调试,在发送数据包的时候,把事件给显示出来,有如下的逻辑: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);
}
}
相关文章推荐
- 关于redhat9.0与arm-linux-gcc 编译链版本问题
- 稳定版本的arm-linux-gcc 3.3.2下载
- 64bit ubuntu 移植 arm-linux-gcc 4.3.2 版本出错
- arm-linux-gcc不同版本交叉编译器的切换使用
- 自己的内核支持低版本arm-linux-gcc静态编译的程序
- 高版本ubuntu安装低版本arm-linux-gcc
- 关于 arm-linux-gcc 使用 static关键字的一个 bug
- arm-linux-gcc环境安装与编译测试(版本4.4.4)
- Ubuntu 12.04版本下安装交叉编译器arm-linux-gcc4.3.2
- linux下安装两个不同版本的交叉编译环境arm-linux-gcc4.4.3、arm-linux-gcc3.4.1,切换调用的解决
- qt4.8.6版本使用arm-linux-gcc-3.4.5编译问题
- linux上怎么切换不同版本的arm-linux-gcc?只需改一行函数
- linux上怎么切换不同版本的arm-linux-gcc?只需改一行函数
- 如何查看arm-linux-gcc某个版本支持的-mcpu,-march可选值
- Ubuntu11.04中搭建交叉编译环境(arm-linux-gcc-4.6.1版本)
- Ubuntu11.04中搭建交叉编译环境(arm-linux-gcc-4.6.1版本)
- arm-linux-androideabi-gcc 预定义宏(编译器版本4.8)
- ubuntu下 arm-linux-gcc-4.5.1安装v1.0(未经整理版本)
- arm-linux-gcc & 一个相当低级的错误
- 安装新旧版本的arm-linux-gcc交叉工具链(基于JZ2440)