打印
[51单片机]

小i解惑之一:使用死循环陷阱

[复制链接]
3951|29
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
icecut|  楼主 | 2014-9-28 14:10 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 icecut 于 2014-9-29 09:47 编辑

好久没来单片机板块了。最近在深入研究单片机。所以给大家解惑之一就有了。
c语言pc版本程序是可以正常退出的。为什么单片机就需要加一个死循环在程序结束呢?
如果不加又是什么表现呢?

如果加死循环,程序结束就停住了。不加,常规认为会跑飞。但事实上用keil的人都会发现是复位,为什么是复位后续解答。

测试程序如下:
#include <reg51.h>

int main()
{
        int x = 5;
        int y = 6;
        while(x+y != 11);
        return 0;
}
这事一个测试单片机是否能正常执行加法的程序。使用keil来编译。debug的时候输出汇编


图片是汇编和c的混合输出。
这里我没有添加startup.s但是还是有一部分代码生成。在程序的下方。然后启动后首先跳转过去执行内存初始化。
这样粉色框显示内存已经全部初始化。并且sp=7,预留了7个0.
此时,执行绿线跳转到main函数开始执行用户代码。最后ret,这时候ret会将sp最初预留的0弹入pc中。于是重新从0开始执行代码
复位就这么产生了。所以很多人遇到没有死循环陷阱的程序会无限复位。
无限复位是编译器加进来的。不同编译器可能不一样。
你可以考虑在用户程序中改写这7个预留的字节,然后debug一下,就能发现crack的魅力。
上面说的有错误,不再改动,大家知道就好。省得大家说我犯错就销毁证据!!!!
经过后面指点,这个ret的确不需要我说的crack这么麻烦。
我写程序喜欢return 0,所以占便宜了。没遇到跑飞。
原因继续解释。
单片机的寄存器 r0-r7是ram统一编址。这里我没有在中断中使用第二组寄存器,所以sp预留了8个地址。原因是sp++,然后存放内容,对应r0-r7.
所以错误ret的时候,正好弹出了返回值的2个寄存器。我返回0就幸运的复位了。如果你返回值随机的话,恭喜你,中招了。如果你返回了一个函数地址,却不需要参数的,恭喜你,给动态**的人留下一个坑。
继续讨论补充:
sp预留的地址为 已使用的统一编址的寄存器+全局变量。

// 本文是看我的一个徒弟在用虚拟机技术去找程序漏洞后,才考虑放出来的。从简单开始搞。给那些没学汇编的人一个汇编不难的印象。
// 当然,对于return 0 :希望大家能多获得规范编程带来的潜意识的好效果。当然用全局变量后,就没有这种效果了。如果全局变量最后2个字节是0,也会有此效果。
最简单的解法还是while(1);












相关帖子

沙发
LIYLONG| | 2014-9-28 14:29 | 只看该作者
二楼

使用特权

评论回复
板凳
ayb_ice| | 2014-9-28 15:26 | 只看该作者
请问:
 main里调用了子程序呢,实际上堆栈指针一般也不是0x07

使用特权

评论回复
地板
电子无聊大神| | 2014-9-28 15:34 | 只看该作者
唉,虽然有1~2句汇编没直接看懂,还是理解到了意思。
I哥解惑系列要出了吗;P

使用特权

评论回复
5
ayb_ice| | 2014-9-28 15:37 | 只看该作者
用软件调试的时候,没有使用的代码全部是NOP指令,当PC跑飞时有极大可能是执行了这些NOP指令了,这样PC会不停的加,最终溢出,而且51对不能识别的指令也当NOP处理,这样就会更快的溢出,最终感觉像复位了

使用特权

评论回复
评分
参与人数 1威望 +5 收起 理由
laoxu + 5 很给力!
6
ayb_ice| | 2014-9-28 15:38 | 只看该作者
实际硬件上运行并非这个样子的

使用特权

评论回复
评论
icecut 2014-9-28 18:03 回复TA
硬件听软件的。反汇编是什么样子,就是什么样子。别吓唬人。 
评分
参与人数 1威望 +5 收起 理由
laoxu + 5 很给力!
7
laoxu| | 2014-9-28 16:23 | 只看该作者
小i乱谈琴~~~~~~~   :P





本例中,刚好SP=0x07,  RET返回时弹出RAM中 06H-07H之值到PC。

假如你写成 return  m;  则RET返回时弹出RAM中 m之值到PC。


使用特权

评论回复
8
laoxu| | 2014-9-28 16:25 | 只看该作者
上例实在是碰巧~~~~~~

实际情况并非如此,就像ayb_ice所言~~~~~~

使用特权

评论回复
9
icecut|  楼主 | 2014-9-28 17:59 | 只看该作者
laoxu 发表于 2014-9-28 16:25
上例实在是碰巧~~~~~~

实际情况并非如此,就像ayb_ice所言~~~~~~

继续解释添加了为什么预留8个地址和如何利用这个陷阱。

使用特权

评论回复
10
icecut|  楼主 | 2014-9-28 18:00 | 只看该作者
本帖最后由 icecut 于 2014-9-29 09:35 编辑
ayb_ice 发表于 2014-9-28 15:26
请问:
 main里调用了子程序呢,实际上堆栈指针一般也不是0x07

是不是07,看你需要预留几组寄存器。最多4组。

----------
据讨论,此句欠推敲,应该考虑全局分配的变量。更正之

使用特权

评论回复
11
icecut|  楼主 | 2014-9-28 18:01 | 只看该作者
电子无聊大神 发表于 2014-9-28 15:34
唉,虽然有1~2句汇编没直接看懂,还是理解到了意思。
I哥解惑系列要出了吗 ...

我也就是在玩的过程中记录一些截图。给大家解释一些原因。

使用特权

评论回复
12
laoxu| | 2014-9-28 18:13 | 只看该作者
icecut 发表于 2014-9-28 18:00
是不是07,看你需要预留几组寄存器。最多4组。

这个俺的一个产品程序的反汇编,由于用到大量的全局变量,堆栈指针往后移,由图中可看到,初始化的SP=0xa4;

在主程序中用 return  0;  返回,程序将飞到一个未知的地址~~~~  ;P




使用特权

评论回复
13
原野之浪| | 2014-9-28 18:28 | 只看该作者
类似的帖子我马甲好想以前发过。就是flash跑一圈转回来了。小i,最近对单片机有兴趣。不是只玩linux么

使用特权

评论回复
评论
icecut 2014-9-29 09:35 回复TA
我的目标是,如果想return,要人工处理返回地址。跑到你想要的位置。 
14
原野之狼| | 2014-9-28 22:37 | 只看该作者
玩什么不重要   挣到钱才重要

使用特权

评论回复
评论
icecut 2014-9-29 09:36 回复TA
我在研究一个极度保密的任务。 
通宵敲代码 2014-9-28 23:26 回复TA
你上面的孩子你认识吗 
评分
参与人数 1威望 +1 收起 理由
shuangjf + 1 很给力!
15
hgjinwei| | 2014-9-28 22:42 | 只看该作者
这个返回到哪,是可以预设的。

程序执行时,SP的生长是有规律的,不管main调用了多少子函数,调用深度有多大,只要堆栈没给冲破,那么他就不应该影响到进入main时SP所指向的RAM。
所以,在程序启动时,适量给SP预留点空间,不要给全局变量覆盖了,那么就可以预设main函数返回到哪了。

不过,这有神马意义吗?

使用特权

评论回复
评论
icecut 2014-9-29 09:37 回复TA
看样你没玩过破解。。。自己挖坑让动态破解的人去跳 
评分
参与人数 1威望 +5 收起 理由
laoxu + 5 这神马的毫无意义~~~~~~
16
tiden_wang| | 2014-9-28 22:48 | 只看该作者
单片机通常会继续执行下一条指令,即使下一条指令位于没有写入用户程序的存储区域,也将继续执行。为防止出现这种现象,用无限循环停止程序是一种简单的方法。

使用特权

评论回复
评论
icecut 2014-9-29 09:38 回复TA
是的。如果再深入一点。如何给动态破解代码的人挖坑? 
评分
参与人数 1威望 +5 收起 理由
laoxu + 5 很给力!
17
gaoyang9992006| | 2014-9-28 23:23 | 只看该作者
管他呢,能用就好。

使用特权

评论回复
18
通宵敲代码| | 2014-9-28 23:28 | 只看该作者
汇编学得不好,似懂非懂!

使用特权

评论回复
19
原野之狼| | 2014-9-28 23:34 | 只看该作者
玩Linux又能咋样,我最近真想去裸奔写单片机程序~

使用特权

评论回复
20
不亦心| | 2014-9-29 01:50 | 只看该作者
稍微玩一下汇编就不会得出这种解惑了,,,,

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:个人发展,技术咨询,点此  嵌入式arm爱好者←← +→→点击-->小 i 精品课全集,给你全方位的技能策划~~←←

1120

主题

15358

帖子

585

粉丝