c语言·其二

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的起始位置    

 

posted @ 2024-07-29 15:56  雨里青山隐  阅读(12)  评论(0编辑  收藏  举报