能力值:
(RANK:170 )
2 楼
两个基本知识:
1、操作是对栈数据置cc。
2、cc是软断点,
debug模式会作上面的操作,如果数据执行出错的话,比如堆栈乱了,cdecl, stdcall之类的返回错误,可以直接抛出一个断点异常,容易定位问题,不会把问题放大。
release模式则为了效率和优化考虑,把这部分代码去掉。
能力值:
( LV8,RANK:150 )
3 楼
那debug程序为什么能定位到源代码,而release版本的却不能呢??再说了,数据怎么会被执行呢??
能力值:
( LV2,RANK:10 )
4 楼
debug忠于源码且包含调试信息,release要优化。数据执行那个,你应该了解一点缓冲区溢出的基本知识。
能力值:
( LV2,RANK:10 )
5 楼
哦,这样啊...明白个大概,我还新的很啊..
能力值:
( LV2,RANK:10 )
6 楼
00000 55 push ebp
00001 8b ec mov ebp, esp
这俩句,我也挺迷糊的,我是把它理解成,使ebp和esp指向栈底,栈的大小为空。
00003 83 ec 40 sub esp, 64 ; 00000040H
//这里应该是分配堆栈空间,栈的结构从上到下是由低址到高址,所以sub esp,64是esp向上移动64,即分配空间大小为64
下面这段我的理解是,因为要调用main()函数,所以要保存下寄存器内容,以便函数返回时还原。
00006 53 push ebx
00007 56 push esi
00008 57 push edi
//这三条,把寄存器内容如栈保存。
00009 8d 7d c0 lea edi, DWORD PTR [ebp-64]
//这条使edi指向栈顶。
0000c b9 10 00 00 00 mov ecx, 16 ; 00000010H
00011 b8 cc cc cc cc mov eax, -858993460 ; ccccccccH
00016 f3 ab rep stosd
//这三条是把ccccccccH存储到edi指向的堆栈中。这我也不太明白。
这大概就是一楼说的那个东东吧?
1、操作是对栈数据置cc。
2、cc是软断点,
//这里的CC软断点应该就是上面的ccccccccH吧!
debug模式会作上面的操作,如果数据执行出错的话,比如堆栈乱了,cdecl, stdcall之类的返回错误,可以直接抛出一个断点异常,容易定位问题,不会把问题放大。
release模式则为了效率和优化考虑,把这部分代码去掉。
呵呵,我所理解的就这些了,希望对你有帮助!!
能力值:
( LV2,RANK:10 )
7 楼
路过学习 6个字啊
能力值:
( LV6,RANK:90 )
8 楼
数据是可以被执行的,忘记这是冯诺依曼体系的特点还是微软搞的,所谓的数据和指令都是二进制码,区别在于CPU怎么对待
能力值:
( LV6,RANK:90 )
9 楼
门前小雪解释的基本差不多。建议楼主搞本天书夜读,书的一开始对这些都做了详细的分析
能力值:
( LV3,RANK:20 )
10 楼
6楼的解释好像只是解释单条指令,没解释作用,我等下有时间写一下
①先说开头和结尾,这是个基本结构
00000 55 push ebp
00001 8b ec mov ebp, esp
00003 83 ec 40 sub esp, 64 ; 00000040H
跟后面的
0002a 83 c4 40 add esp, 64 ; 00000040H
0002d 3b ec cmp ebp, esp
0002f e8 00 00 00 00 call __chkesp
00034 8b e5 mov esp, ebp
00036 5d pop ebp
00037 c3 ret 0
是配对的,一般的主程序或者子程序都是这样的结构,
一般程序运行前都要保存重要寄存器的值,运行完返回时再恢复
sub esp, 64 是给主程序分配内存空间
00003这条指令会改变esp的值,esp是栈顶的地址,所以要用mov ebp, esp 先把esp保存在ebp里面,结束后用mov esp, ebp将esp恢复
00001这条指令会改变ebp的值,所以要push ebp将ebp存入堆栈,后面再用pop ebp恢复ebp
执行pop ebp后堆栈的下一条指令就是程序的返回地址,ret 0从栈顶取出返回地址返回
这个过程中ebp存着原来的栈顶地址,如果ebp被意外的改变了,程序就不能返回了,
所以
0002d 3b ec cmp ebp, esp
0002f e8 00 00 00 00 call __chkesp是做检查
② 00006 53 push ebx
00007 56 push esi
00008 57 push edi
是保存这3个寄存器的值
后面的
00027 5f pop edi
00028 5e pop esi
00029 5b pop ebx
是把这3个寄存器改回去,这6条指令也是对应的,一个push对一个pop,为了堆栈平衡而且可以恢复这3个寄存器的原始值
③然后再来说中间的,中间就是要输出Hello,World这个字符串,连回车符是12个字符,当然还要先做一些初始化工作
lea edi, DWORD PTR [ebp-64]
把ebp-64的地址存入edi中,刚才00003的指令是分配的64字节的空间,[ebp-64]就是那个空间的起始地址,用C语言的话说就是让edi指向空间的起始地址
0000c b9 10 00 00 00 mov ecx, 16 ; 00000010H
00011 b8 cc cc cc cc mov eax, -858993460 ; ccccccccH
00016 f3 ab rep stosd
这3条指令的效果就是用cc填充刚才的64字节的数据空间,至于为什么是cc二楼说得很清楚了,ecx用作循环的计数器,表示后面的rep stosd循环16次
00011的指令表示将eax用0xcccccccc填充,00016的指令表示将eax的值填入那个的空间,循环16次,一次填充4字节,16*4=64
④ 00018 68 00 00 00 00 push OFFSET FLAT:??_C@_0N@OJDJ@Hello?0World?6?$AA@ ; `string'
0001d e8 00 00 00 00 call _printf
00022 83 c4 04 add esp, 4
00025 33 c0 xor eax, eax
把Hello,World的字符串地址压入栈顶,然后调用printf,一般调用函数都是被参数依次放入堆栈中,然后call
push使堆栈增加了4,所以esp减少了4,add esp, 4是为了堆栈平衡,
printf的返回值在eax中,所有函数都是用eax保存返回值的,我们不用printf函数的返回值,所以用xor eax, eax清空
整个程序就分析完了,小弟初学汇编,如果有不对的地方请大家指正
能力值:
( LV2,RANK:10 )
11 楼
因为debug版本的文件中有调试的段,realease里的则没有。
能力值:
( LV15,RANK:670 )
12 楼
release也能调试的,加入调试信息就可以了。
能力值:
( LV3,RANK:20 )
13 楼
mov ebp,esp是将原栈底设成新顶....
一个函数调用过程大概如下:
push 参数2
push 参数1
call 函数
call操作隐含了push eip
进函数后:
push ebp
mov ebp,esp
........
sub esp,64
此时的栈结构大概就像下面:
.
.
.
函数内部的变量空间
64字节空间
.
.
.
ebp
eip
参数1
参数2
栈是从高到低增长的.函数之前的开辟空间\保存返回值\把EBP之类的压栈操作称为"函数序言"
能力值:
( LV2,RANK:10 )
14 楼
00000 55 push ebp ;保存基址
00001 8b ec mov ebp, esp ;打开堆栈 可以通过 ebp+- 来访问变量
00003 83 ec 40 sub esp, 64 ;为分配局部内存 一般都是64
00006 53 push ebx ;一般按照函数间调用的约定,函数中可以自由使用eax,ecx,edx
00007 56 push esi ;其它寄存器如果需要使用则需要保存,用完时恢复;
;也就是寄存器的使用约定; 这也使函数调用约定的一部分
00008 57 push edi ;在函数中调用了别的函数后,eax,ecx,edx很可能已经改变
;这三条 保存寄存器的值
00009 8d 7d c0 lea edi, DWORD PTR [ebp-64] ;装载局部内存地址
0000c b9 10 00 00 00 mov ecx, 16 ; 00000010H ;计数
00011 b8 cc cc cc cc mov eax, -858993460 ; ccccccccH
00016 f3 ab rep stosd ;把al/ ax/ eax的内容存储到edi指向的内存单元中,同时edi的值根据方向标志的值增加或者减少。
前面开辟的(16*4)byte局部空间全部填充0xCC
注意: 0xCC是调试中断(__asm int 3)的指令码,所以可以想象,当程序错误的跳转到这个区域进行执行时将产生调试中断
能力值:
( LV2,RANK:10 )
15 楼
VC编译出的程序 多少会有点冗余的吧~~
如果直接用汇编 会省去许多代码的~
能力值:
( LV2,RANK:10 )
16 楼
00000 55 push ebp
00001 8b ec mov ebp, esp
00003 83 ec 40 sub esp, 64 ; 00000040H
00006 53 push ebx
00007 56 push esi
00008 57 push edi
00009 8d 7d c0 lea edi, DWORD PTR [ebp-64]
0000c b9 10 00 00 00 mov ecx, 16 ; 00000010H
00011 b8 cc cc cc cc mov eax, -858993460 ; ccccccccH
00016 f3 ab rep stosd 均是编译器约定的,
能力值:
( LV2,RANK:10 )
17 楼
结合实际例子,浅显易懂,赞一个。