2021-09-13透过汇编学习C语言(还在学习中...)

透过汇编学习C语言

1.变量

全局变量和局部变量

全局变量:在声明并编译后,该变量的内存地址和宽度就被确定,如果不重新编译,则在整个程序运行时,该变量的地址就不会被修改,但是,全局变量中的值可以根据修改其对应地址的值而进行修改。(任何程序或函数都可修改他的值)
局部变量:在声明并编译后,程序并不会直接为其分配地址,只有在运行到该局部变量所在的函数被调用时才会被分配地址和宽度,同时当这个函数执行结束后,该局部变量也会被“清空”

实例学习

源码如下:

#include<stdio.h>
int x;
3:    void change(int i){
00401020   push        ebp
00401021   mov         ebp,esp
00401023   sub         esp,44h
00401026   push        ebx
00401027   push        esi
00401028   push        edi
00401029   lea         edi,[ebp-44h]这里是创建缓冲区
0040102C   mov         ecx,11h//程序提升栈指针而预留一部分内存空间
00401031   mov         eax,0CCCCCCCCh///同时将这部分空间以cc字符串进行填充
00401036   rep stos    dword ptr [edi]//
4:        int y=i;
00401038   mov         eax,dword ptr [ebp+8]
0040103B   mov         dword ptr [ebp-4],eax
5:        x=2;
0040103E   mov         dword ptr [x (00427c48)],2
6:    }
00401048   pop         edi
00401049   pop         esi
0040104A   pop         ebx
0040104B   mov         esp,ebp
0040104D   pop         ebp
0040104E   ret
    7:    int main(){
00401060   push        ebp
00401061   mov         ebp,esp
00401063   sub         esp,40h
00401066   push        ebx
00401067   push        esi
00401068   push        edi
00401069   lea         edi,[ebp-40h]
0040106C   mov         ecx,10h
00401071   mov         eax,0CCCCCCCCh
00401076   rep stos    dword ptr [edi]
8:        change(2);					//在此设置断点
00401078   push        2
0040107A   call        @ILT+0(change) (00401005)
0040107F   add         esp,4
9:        printf("%d\n",x);
00401082   mov         eax,[x (00427c48)]
00401087   push        eax
00401088   push        offset string "%d" (0042201c)
0040108D   call        printf (004010c0)
00401092   add         esp,8
10:       return 0;
00401095   xor         eax,eax
11:   }

开始分析程序(主要从局部变量开始分析)

///从change(2);跳到这里
/*
00401078   push        2							//这里有一个传参,将2压入到堆栈中
0040107A   call        @ILT+0(change) (00401005)
0040107F   add         esp,4
*/
void change(int i){
00401020   push        ebp
00401021   mov         ebp,esp
00401023   sub         esp,44h
00401026   push        ebx
00401027   push        esi
00401028   push        edi
00401029   lea         edi,[ebp-44h]	//这里是创建缓冲区
0040102C   mov         ecx,11h	//程序提升栈指针而预留一部分内存空间
00401031   mov         eax,0CCCCCCCCh	//同时将这部分空间以cc字符串进行填充
00401036   rep stos    dword ptr [edi]
4:        int y=i;
00401038   mov         eax,dword ptr [ebp+8]	/这里的ebp+8就是传入的参数‘2’
0040103B   mov         dword ptr [ebp-4],eax	ebp-4所在的内存,是缓冲区,同时也是局部变量的地址,也就是说缓冲区是用来存放局部变量的
5:        x=2;
0040103E   mov         dword ptr [x (00427c48)],2 这里00427c48是一个常见的地址,就是全局变量x的地址,在整个程序中不会改变,但存储的值可修改
6:    }
00401048   pop         edi
00401049   pop         esi
0040104A   pop         ebx
0040104B   mov         esp,ebp
0040104D   pop         ebp
0040104E   ret

该程序的堆栈分析图如下:
在这里插入图片描述

整段程序分析:(根据工作室的哥哥建议分析写的,对上面的分析有修改)

#include<stdio.h>
int x;
3:    void change(int i){
00401020   push        ebp			//保存main函数的ebp地址,将ebp压入到change函数的堆栈底部
00401021   mov         ebp,esp		//准备开辟本函数的堆栈,将当前ebp指向当前的esp
00401023   sub         esp,44h		//开辟44H的堆栈空间,通过提升esp=esp-44H
    
00401026   push        ebx
00401027   push        esi
00401028   push        edi
    保存将使用的寄存器,保存现场,通过将个寄存器的值压入堆栈的形式
    
00401029   lea         edi,[ebp-44h]lea命令就是将传地址到寄存器(其他内存单元也行),和mov指令类似
0040102C   mov         ecx,11h//预存rep命令的执行次数(由ecx的值指定)
00401031   mov         eax,0CCCCCCCCh///预先设定stos命令复制的内容(由eax中储存的内容决定)
    								 ///其中0xcc是int 3;的机械码(断点)防止该区域内的内容被执行。
00401036   rep stos    dword ptr [edi]//
    /*
    rep指令的目的是重复其上面的指令.ECX的值是重复的次数.ecx=11h
	STOS指令的作用是将eax中的值拷贝到ES:EDI指向的地址.拷贝过后,会对edi中的值做减法操作,减去的值看eax中存储的大小
	eax=0CCCCCCCCh;4字节大小,所以每次执行后edi-4
	edi=ebp-44h 就是指向缓冲区(也是局部变量的内存空间)
    */
4:        int y=i;
00401038   mov         eax,dword ptr [ebp+8]	//这里eax用来存储变量的值,该变量是change()函数外传入的参数,在change函数的堆栈外
    											//但也挨着ebp,ebp+8就是传参的变量的内存地址假如还有一个参,那么就是ebp+c
0040103B   mov         dword ptr [ebp-4],eax	//这ebp-4就是y这个局部变量的地址,在缓冲区之内
5:        x=2;
0040103E   mov         dword ptr [x (00427c48)],2
6:    }
00401048   pop         edi
00401049   pop         esi
0040104A   pop         ebx
0040104B   mov         esp,ebp
0040104D   pop         ebp
0040104E   ret
    //恢复main()函数现场将edi,esi,ebx,esp以及ebp这几个寄存器的值恢复成change()函数执行前的样子
    7:    int main(){
00401060   push        ebp
00401061   mov         ebp,esp
00401063   sub         esp,40h
00401066   push        ebx
00401067   push        esi
00401068   push        edi
00401069   lea         edi,[ebp-40h]
0040106C   mov         ecx,10h
00401071   mov         eax,0CCCCCCCCh
00401076   rep stos    dword ptr [edi]
    //这部分同样是创建main()函数的堆栈区域
8:        change(2);					//在此设置断点
00401078   push        2
0040107A   call        @ILT+0(change) (00401005)
0040107F   add         esp,4	//栈外平栈
9:        printf("%d\n",x);
00401082   mov         eax,[x (00427c48)]
00401087   push        eax
00401088   push        offset string "%d" (0042201c)
0040108D   call        printf (004010c0)
00401092   add         esp,8
10:       return 0;
00401095   xor         eax,eax
11:   }

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值