|
网站菜单
|
日记 - 奇奇怪怪的C
我只是在做C Primer Plus第三章的第二道练习题。 题目要求,输入一个数字给出对应ascii字符。 #include <stdio.h> int main (void) { char cAa = 0; printf("GIVE ME AN Ascii number, MY MASTER!"); scanf("%d", &cAa); //问题在这,%d是四字节int,gcc给出了警告 printf("A IKUikuiku!!!!! %cn", cAa); return 0; } 然后我发现,不管输入什么,程序都会在最后的printf结束后: *** stack smashing detected ***: terminated 中止 (核心已傾印) 奇怪。 然后注意到: 通过gdb,我可以观察到canary值被修改、导致程序在返回时触发栈粉碎。 原因:scanf("%d", &cAa),cAa是一字节char变量,%d会写入四字节int。 而char变量只有一字节,剩余三字节理论上会溢出覆盖canary值,整个程序只有这一个变量。 分析: 1. 方便观察,我向一个char变量输入了2147483648(0x80000000), 平台为aarch64,小端序,所以会由低到高写入。程序会依次写入 00 00 00 80,其中 后三个应该会溢出,把高位内存覆盖三字节为800000。 在ARM64下,使用x/gx $sp + 8来查看运行时金丝雀值(的末尾) 0x17e7147510a42300(前) 0x17e7147510800000(后) 可以注意到后三个字节,a42300确实被替换成了800000。 因为前后不符,运行至return 0;后,程序金丝雀值比对不通过,触发栈粉碎*** stack smashing detected ***: terminated。 2. 更换数字,如果我输入1(0x00 00 00 01) 按照由低到高写入,程序会依次写入 10 00 00 00,其中 后三个应该会溢出,把高位内存覆盖三字节为000000。 0x09dee24c8c700100(前) 0x09dee24c8c000000(后) 后三个字节同样被替换成了000000,符合分析。运行结果同样触发栈粉碎。 3. 对照测试。 同一个程序,提前获取canary值,并且写入对应值,理应能正常退出。 x/gx $sp + 7能看到canary值末尾和char变量 0x0a0775aabf7d00(00),括号内为char变量cAa的值,我们初始化为0。 注意最后四个字节,scanf将会写入这四个字节,即bf7d0000。按照猜测,把这个值写入进去,金丝雀值将不会有变化,程序会正常退出。 我们把bf7d0000转换为十进制得到3212640256,作为scanf的输入值。 写入后,继续访问同一个地址 0x0a0775aa [bf 7d 00(00)] 没有变化。 gdb可以看到,__libc_start_call_main将x/gx $sp + 0x08地址的金丝雀值与$tpidr + 0x28地址存储的金丝雀值进行比对。因为前后没有变化,所以没有触发栈粉碎。 [Inferior 1 (process 46207) exited normally],程序正常退出,符合预测。 评论: (7) |