首页 > 其他分享 >c语言·其二

c语言·其二

时间:2024-07-29 15:55:41浏览次数:14  
标签:语言 其二 mov eax ebp push dword ptr

1.代码区:可读可执行

2.堆栈:(参数,局部变量,临时数据)

3.堆:(动态申请,大小可变)可读可写

5.常量区:只读

变量

变量的声明

全局变量

int a,b,c; //全局变量的声明   

void Fun()   

{   

 a = 10; //全局变量的赋值  

 b = 20;  

 c = a;  

}

局部变量

void Fun()   

{   

 int a,b,c; //局部变量的声明  

 a = 10; //局部变量的赋值  

 b = 20;  

 c = a;  

}      

全局变量

特点:           

1、在程序编译完以后就已经预留的空间,预留的大小由类型决定,且位置不会发生变化.           

2、全局变量如果没有给的初始值,默认为0.         

3、全局变量可以在任何其他的函数里面进行读写

如图:

       

等于:MOV 寄存器,byte/word/dword ptr ds:[0x12345678]

4、多个函数使用同一个全局变量,只要exe程序不结束,里面将一直存储最后一次修改的值.        

注:全局变量就是所谓的基址

局部变量

局部变量的特点:            

1、局部变量在程序编译完成后并没有分配固定的地址.               

2、在所属的方法没有被调用时,局部变量并不会分配内存地址,只有当所属的程序被调用了,才会在

 堆栈中分配内存.             

3、当局部变量所属的方法执行完毕后,局部变量所占用的内存将变成垃圾数据.局部变量消失.              

4、局部变量只能在方法内部使用,函数A无法使用函数B的局部变量.           

5、局部变量的反汇编识别:   [ebp-4].....

6.使用前要赋初值

参数

传进来给函数里用

确定参数

一般情况

步骤一:观察调用处的代码     

push 3   

push 2   

push 1   

call 0040100f       //3个参数

步骤二:找到平衡堆栈的代码继续论证    

call 0040100f   

add esp,0Ch     

或者函数内部    

ret 4/8/0xC/0x10         //1/2/3/4个参数

寄存器传参

举例


 

1.

push ebx   

push eax   

mov ecx,dword ptr ds:[esi]   

mov edx,dword ptr ds:[edi]   

push 45   

push 33   

call 函数地址   函数地址未知 

2、函数调用处的代码无法查看.   

00401050 push ebp   

00401051 mov ebp,esp   

00401053 sub esp,48h   

00401056 push ebx   

00401057 push esi   

00401058 push edi   

00401059 push ecx   

0040105A lea edi,[ebp-48h]   

0040105D mov ecx,12h            将12h赋给ecx(不属于参数

00401062 mov eax,0CCCCCCCCh   

00401067 rep stos dword ptr [edi]   

00401069 pop ecx   

0040106A mov dword ptr [ebp-8],edx     将edx里的值赋给[ebp-8]中(发现前面没有给edx赋值,所以edx存了一个参数

0040106D mov dword ptr [ebp-4],ecx   

00401070 mov eax,dword ptr [ebp-4]   

00401073 add eax,dword ptr [ebp-8]   

00401076 add eax,dword ptr [ebp+8]   

00401079 mov [g_x (00427958)],eax   

0040107E pop edi   

0040107F pop esi   

00401080 pop ebx   

00401081 mov esp,ebp   

00401083 pop ebp   

00401084 ret 4   有一个压栈的参数

 


2.if汇编

00401030 push ebp    

00401031 mov ebp,esp    

00401033 sub esp,40h    

00401036 push ebx    

00401037 push esi    

00401038 push edi    

00401039 lea edi,[ebp-40h]    

0040103C mov ecx,10h    

00401041 mov eax,0CCCCCCCCh    

00401046 rep stos dword ptr [edi]    

——————————————————————————————————————堆栈图准备部分

00401048 mov eax,dword ptr [ebp+8]    参数x

0040104B cmp eax,dword ptr [ebp+0Ch]       参数y

0040104E jle 00401059    ≤跳转不执行

00401050 mov ecx,dword ptr [ebp+8]    x的值赋值给ecx

00401053 mov dword ptr [004225c4],ecx    全局变量(宽度4个字节)ecx赋值给全局变量

——————————————————————————————————————————平衡堆栈

00401059 pop edi    

0040105A pop esi    

0040105B pop ebx    

0040105C mov esp,ebp    

0040105E pop ebp    

0040105F ret    

 

 


 

公式:

1、不考虑ebp、esp    

2、只找给别人赋值的寄存器    

eax/ecx/edx/ebx/esi/edi       

3、找到以后追查其来源,如果,该寄存器中的值    

不是在函数内存赋值的,那一定是传进来的参数.      

公式一:寄存器 + ret 4 = 参数个数    

公式二:寄存器 + [ebp+8] +[ebp+0x] = 参数个数    

循环

if与else

1.if....else

int x=1;

int y=2

void one()

{

      if(x>y)   //如果

       {

       printf("%d\n",x);

         }

       else     //否则

       {

       printf("%d\n",y);

         }

}

2.else if

3.嵌套

汇编(if

1.

 

cmp:eax里的值减去[ebp+0Ch],根据结果后只修改标志寄存器

jle:当eax里的值<或者=[ebp+0Ch]的时候跳转(不执行if里的代码

2.

jl:小于才跳转

jge:≥

( else

 

004010B0 push ebp    

004010B1 mov ebp,esp    

004010B3 sub esp,44h    

004010B6 push ebx    

004010B7 push esi    

004010B8 push edi    

004010B9 lea edi,[ebp-44h]    

004010BC mov ecx,11h    

004010C1 mov eax,0CCCCCCCCh    

004010C6 rep stos dword ptr [edi]    

———————————————————————————————————————————————————————

004010C8 mov eax,[004225c4]    全局变量

004010CD mov dword ptr [ebp-4],eax   局部变量(将全局变量赋值给局部变量)

004010D0 mov ecx,dword ptr [ebp+8]    参数x

004010D3 cmp ecx,dword ptr [ebp+0Ch]    参数y

004010D6 jle 004010e6   ≤跳转,不执行

—————————————————————————————————————————————

004010D8 mov edx,dword ptr [ebp+8]    

004010DB add edx,dword ptr [ebp-4]    x+全局变量

004010DE mov dword ptr [004225c4],edx    

004010E4 jmp 004010f1   

int a=r;

if(x>y)

{

r=x+a;

}—————————————————————————————————————————    

004010E6 mov eax,dword ptr [ebp+0Ch]    

004010E9 add eax,dword ptr [ebp-4]    

004010EC mov [004225c4],eax    

————————————————————————————————————————————————

004010F1 pop edi    

004010F2 pop esi    

004010F3 pop ebx    

004010F4 mov esp,ebp    

004010F6 pop ebp    

004010F7 ret    

do....while

格式

do..while语句的语法 

 

do 

 //执行代码

 

}while(表达式) 

例子

void Fun(int x,int y)   

{   

 do  

 {  

  printf("%d\n",x); 

  x++; 

 }while(x>y);  

}   

汇编

0040B7F8 mov eax,dword ptr [ebp+8]      

0040B7FB push eax      

0040B7FC push offset string "%d\n" (0042001c)      

0040B801 call printf (004010f0)      

0040B806 add esp,8      

0040B809 mov ecx,dword ptr [ebp+8]      //x++

0040B80C add ecx,1                                 //

0040B80F mov dword ptr [ebp+8],ecx      //while(x>y)

0040B812 mov edx,dword ptr [ebp+8]      //

0040B815 cmp edx,dword ptr [ebp+0Ch]      //

0040B818 jg 0040b7f8      

总结

1、根据条件跳转指令所跳转到的地址,可以得到循环语句块的起始地址。     

2、根据条件跳转指令所在的地址,可以得到循环语句块的结束地址。     

3、条件跳转的逻辑与源码相同。

while

语法  

while(表达式)  

{  

 //执行代码 

}  

例子

void Fun(int x,int y)   

{   

 while(x<y)  

 {  

  printf("%d\n",x); 

  x++; 

 }  

}   

汇编

0040B7F8 mov eax,dword ptr [ebp+8]    

0040B7FB cmp eax,dword ptr [ebp+0Ch]    

0040B7FE jge 0040b81c    //

0040B800 mov ecx,dword ptr [ebp+8]    //

0040B803 push ecx                                //

0040B804 push offset string "%d\n" (0042001c)   // 

0040B809 call printf (004010f0)    //

0040B80E add esp,8    //

0040B811 mov edx,dword ptr [ebp+8]    //

0040B814 add edx,1    //

0040B817 mov dword ptr [ebp+8],edx    //

0040B81A jmp 0040b7f8    //

0040B81C pop edi    //

0040B81D pop esi    //

0040B81E pop ebx    //

总结:           

1、根据条件跳转指令所跳转到的地址,可以得到循环语句块的结束地址;      

2、根据jmp 指令所跳转到的地址,可以得到循环语句块的起始地址;      

for(表达式1;表达式2;表达式3)

for循环的执行次序:  

表达式1  

表达式2  

执行的代码(大括号里面的内容)  

表达式3  

————————————————

表达式2 //如果表达式2成立  

执行的代码(大括号里面的内容)  

表达式3  

————————————————

表达式2 //如果表达式2成立  

执行的代码(大括号里面的内容)  

表达式3  

———————————————

表达式2 //如果不成立  

跳出循环  

汇编

0040B7F8 mov eax,dword ptr [ebp+8]    //i=x

0040B7FB mov dword ptr [ebp-4],eax    //

0040B7FE jmp 0040b809    //

0040B800 mov ecx,dword ptr [ebp-4]    //

0040B803 add ecx,1    //

0040B806 mov dword ptr [ebp-4],ecx    //

0040B809 mov edx,dword ptr [ebp-4]    //

0040B80C cmp edx,dword ptr [ebp+0Ch]    //

0040B80F jge 0040b824    //

0040B811 mov eax,dword ptr [ebp-4]    //

0040B814 push eax    //

0040B815 push offset string "%d\n" (0042001c)    //

0040B81A call 004010f0    //

0040B81F add esp,8    //

0040B822 jmp 0040b800    //

0040B824 pop edi    //

0040B825 pop esi    //

0040B826 pop ebx    //

总结:

1、第一个jmp 指令之前为赋初值部分.  

2、第一个jmp 指令所跳转的地址为循环条件判定部分起始.  

3、判断条件后面的跳转指令条件成立时跳转的循环体外面   

4、条件判断跳转指令所指向的地址上面有一个jmp jmp地址为表达式3的起始位置    

 

标签:语言,其二,mov,eax,ebp,push,dword,ptr
From: https://www.cnblogs.com/yuli10952/p/18315811

相关文章

  • 大语言模型系列:Transformer(上)
    大语言模型系列:Transformer一、引言在自然语言处理(NLP)领域,随着数据量的爆炸性增长和计算能力的提升,深度学习模型的应用日益广泛。其中,Transformer模型作为大语言模型系列中的杰出代表,自2017年由谷歌提出以来,便以其独特的自注意力机制和高效的并行计算能力,迅速成为NLP领域的核......
  • 大语言模型系列:Transformer(下)
    五、Transformer模型应用Transformer模型自提出以来,凭借其强大的表示能力和高效的并行计算能力,在自然语言处理领域取得了广泛的应用。以下列举了一些Transformer模型的主要应用场景:机器翻译:Transformer模型最初就是为了解决机器翻译问题而设计的。它通过编码器将源语言文本......
  • C语言基础算法
    C语言基础算法目录C语言基础算法1、阶乘递归实现循环实现2、排序冒泡排序选择排序3、斐波那契数列4、ASCII码的使用1、阶乘递归实现#include<stdio.h>//递归函数计算阶乘intfactorial(intn){if(n==0||n==1)return1;elsereturnn......
  • Cypher语言
    Cypher是Neo4j提出的图查询语言,是一种声明式的图数据库查询语言。它具有精简的语法和强大的表现力,能够精准且高效地对图数据进行查询和更新。以下是对Cypher语言的详细解析:一、Cypher语言的特点声明式:用户只需声明想要从图数据库中选择、插入、更新或删除什么,而不需要精确......
  • C语言中的函数(保姆级详细讲解)
    文章目录一.函数的概念1.1库函数1.2自定义函数二.函数的参数1.实参2.形参3.形参和实参的关系(传值调用)4.数组做函数参数(传址调用)三.函数的return语句四.函数的嵌套调用和链式访问1.嵌套调用2.链式访问五.static和extern1.作用域和生命周期2.static2.1s......
  • 从零开始学嵌入式技术之C语言04:进制与转换
    一:进制        计算机世界中只有二进制,所以计算机中存储和运算的所有数据都要转为二进制。包括数字、字符、图片、声音、视频等。(1)二进制:0、1,满2进1。(2)十进制:0-9,满10进1。(3)十六进制:0-9及A-F,满16进1。十六进制中,除了0到9十个数字外,还引入了字母,以便表示超过......
  • 从零开始学嵌入式技术之C语言01:环境的搭建
    一:计算机语言简史(1)机器语言        1946年2月14日,世界上第一台计算机ENIAC诞生,使用的是最原始的穿孔卡片。这种卡片上使用的是用二进制代码表示的语言,与人类语言差别极大,这种语言就称为机器语言。(2)汇编语言        使用英文缩写的助记符来表示基本的操作,这......
  • 《重生到现代之从零开始的C语言生活》—— 数组
    数组数组是个啥数组是一组相同类型元素的集合数组分为一维数组和多维数组,多维数组比较常见的是二维数组一维数组的创建和初始化一维数组的建立的基本语法typearr_name[常量]存放的数组的值被称为数组的元素,在创建时可以指定数组的大小和数组的元素类型比如想创建......
  • 谁是开源之王?Mistral Large 2重磅发布,支持80多种编程语言
     Llama3.1登顶开源大模型王座仅仅过了一天,就被拉下了神坛,这次的主角是一家法国的团队MistralAI,发布了其最新旗舰模型MistralLarge2,这是一个具有1230亿参数的大型人工智能模型。该模型旨在增强代码生成、数学和推理能力,并支持超过80种编程语言。  模型信息数规模:12......
  • Pulsar客户端消费模式揭秘:Go 语言实现 ZeroQueueConsumer
    前段时间在pulsar-client-go社区里看到这么一个issue:import"github.com/apache/pulsar-client-go/pulsar"client,err:=pulsar.NewClient(pulsar.ClientOptions{URL:"pulsar://localhost:6650",})iferr!=nil{log.Fatal(err)}consumer,er......