滴水三期:day10.2-条件语句

这篇博客详细介绍了C语言中的IF语句及其在汇编层面上的体现,包括IF、IF...ELSE、IF...ELSEIF...ELSE的结构与反汇编指令。同时,讲解了数组的定义、使用和查找最大值的操作。通过实例展示了如何从反汇编代码还原C语言的IF逻辑,并提供了几个涉及数组操作的C语言代码示例,如找最大值、数组元素求和。最后,讨论了字符串处理,特别是针对包含中英文的字符串截取方法。

一、IF语句

  • 三种格式:

    if
    if...else...
    if..else if..else if....else
    
  • 可以嵌套使用

二、IF反汇编指令

  • 满足的格式:一般查看反汇编指令时,发现有一块指令修改了标志寄存器,后面紧跟了一个JCC指令,多半就是IF语句

    image-20211205101411668
    image-20211205112803768
  • 而且注意:if后面的判断条件翻译成汇编指令逻辑是反的!!

    • 比如我们写正向代码时使用的是if(x>y)表示如果x大于y则进入到{}中执行当中的代码,如果不成立则不执行

    • 但是当翻译成汇编指令后,x>y翻译的JCC指令为JLE即有符号数小于等于则跳转到后面的地址,但是结合跳转的地址可以发现,汇编指令的意思为:如果x<=y,则跳转到后面的地址处,不执行if{}当中的指令。所以虽然是一个意思,但是逻辑上是反的

      屏幕截图 2021-12-05 102236
  • 我们逆向这种if语句时,只要知道它的执行条件即可,只要知道功能自己用C语言描述出来即可,不一定非要按照JCC一模一样翻译,要灵活。比如如果现在反汇编出现jle,那么jle虽然是小于等于则跳转到地址,但是我们写C语言是为了使用条件判断去执行当中的语句,所以应该翻译成如果大于则执行if当中的语句,如果小于等于则不执行,跳过执行此if{}中部分往下继续执行

三、IF…ELSE反汇编指令

  • 满足的格式:同样先有一段影响标志寄存器的指令,下面跟着一个JCC跳转指令,跳转后顺序执行就可以到END结束位置;IF…ELSE反汇编只是后面还可以找到一句JMP指令且在JCC跳转的地址上面一行,JMP也会跳到END结束位置

    		  修改标志寄存器指令
      ------- JCC 地址1
      |
      |		  ...  //执行相关操作
      ↓		  jmp 结束地址   --------
    地址1:	...  //执行相关操作    |
      ↓                            ↓
    结束地址:  ...    ←-------------
    
    1B66BF0C68F91026204D7CC98AD7BC3A
    image-20211205112929418

四、IF…ELSE IF…ELSE反汇编指令

  • 格式:发现有修改标志寄存器的指令下面跟着一个JCC跳转指令,跳转的地址又是一个修改寄存器然后紧跟JCC指令且上面是一个jmp指令;第二个JCC指令跳转的地址又是修改寄存器后紧跟JCC指令且上面是一个jmp指令。。。直到最后一个操作数据的指令执行完后就是结束地址。且发现上述所有的jmp指令跳转的地址都是结束地址

    BF094BC28EB858CDDE27143A8E90B405
    image-20211205112731395

五、数组的初识

这里先提一下数组是如何定义和简单的使用的,因为我们做题需要用到

  • 数组也是一种数据类型:它当中可以存储多个同类型的值。如果给数组定义了大小n,那么从前往后下标依次从0到n-1
int arr[10] = {1,2,3,4,5,6,7,8,9,10};		
		
void Function()		
{		
	int x = arr[0];	  //读取数组中的某一个位值
	int y = arr[1];	
	int z = arr[2];	
		
	arr[3] = 20;  //修改数组	
}		

六、作业

1.正向IF语句练习

  • 定义4个int类型的全局变量,分别是g_x、g_y、g_z、g_r,使用if…else…分支语句,将最大的值存储到g_r中

    #include "stdafx.h"
    //定义全局变量
    int g_x;  //全局变量不赋初始值默认为0
    int g_y;
    int g_z;
    int g_r;  //储存结果
    
    //定义函数来返回三个数的最大值
    int maxMethod(int a,int b,int c){
        g_x = a;
        g_y = b;
        g_z = c;
        if(g_x >= g_y){
            if(g_x >= g_z){
                g_r = g_x;
            }else{
                g_r = g_z;
            }
        }else{
            if(g_y >= g_z){
                g_r = g_y;
            }else{
                g_r = g_z;
            }
        }
        return g_r;
    }
    
    int main(int argc, char* argv[]){
        printf("%d\n",maxMethod(5,2,7));   //7
        printf("%d",maxMethod(6,6,3));     //6
        return 0;
    }
    
  • 找出数组里面最大的值,并存储到全局变量中(if…esle)

    #include "stdafx.h"
    //定义全局变量
    int arr[4] = {2,5,7,9};	 //4表示大小
    int g_r;
    
    int ArrMax(int arr[]){   //定义一个整型数组型参数,名字可以任意	
        if(arr[0] >= arr[1]){
            if(arr[0] >= arr[2]){
                if(arr[0] >= arr[3]){
                    g_r = arr[0];
                }else{
                    g_r = arr[3];
                }
            }else{
                if(arr[2] >= arr[3]){
                    g_r = arr[2];
                }else{
                    g_r = arr[3];
                }
            }
        }else{
            if(arr[1] >= arr[2]){
                if(arr[1] >= arr[3]){
                    g_r = arr[1];
                }else{
                    g_r = arr[3];
                }
            }else{
                if(arr[2] >= arr[3]){
                    g_r = arr[2];
                }else{
                    g_r = arr[3];
                }
            }
        }
    	return g_r;
    }
    
    int main(int argc, char* argv[]){
        printf("%d",ArrMax(arr));   //把全局变量传给ArrMax方法的参数
        return 0;
    }
    
  • 将数组所有的元素相加,将结果存储到g_r中

    #include "stdafx.h"
    
    int arr[10] = {2,5,7,9,22,4,8,22,3,18};			
    int g_r;   //默认值为0			
    	
    //使用while
    int ArrSum(int arr[]){
        int i = 0;
        while(i <= 9){
            g_r += arr[i];
            i++;
        }
    	return g_r;
    }
    
    //使用for
    int ArrSum2(int arr[]){
        for(int i = 0;i <= 9;i++){
            g_r += arr[i];
        }
    	return g_r;
    }
    
    int main(int argc, char* argv[]){
        printf("%d\n",ArrSum(arr));
        g_r = 0;   //方法一得出结果后要把g_r清零再调用方法二
        printf("%d",ArrSum2(arr));
        return 0;
    }
    
  • 有一个字符串是这样的:china中国verygood天朝nice,里面既含有中文又含义英文,请编写一个函数,能截取任意长度的字符串n(n<=总长度)

    比如:subString(5) = china;subString(6) = china中;subString(8) = china中国v

    因为我们知道一个英文字母存储在内存中占一个字节(ASCII编码),一个汉字存储在内存中占两个字节(GB)

    #include "stdafx.h"
    
    //全局变量
    char str[] = "china中国verygood天朝nice";
    
    void subString(char str[],int length){
        int count = 0; //因为length表示我们想要得到的字符个数,所以使用count计数,到达个数就停止
        for(int i = 0;count < length && str[i] != '\0';i++,count++){
            int unsigned temp = str[i];  //得出它的对应的编码数,一定要注意是无符号数!我们在意的是大小
            if(temp <= 127){  //因为标准ASCII码没有超过127的,即7bit。所以<127表示数组当前位置存的字母
                printf("%c",str[i]);
            }else{  //如果编号大于127,那么说明这是一个汉字的一半(GB编码两字节表示一个汉字)
                char tempStr[] = "周"; //如果不知道定义多大的宽度数组,就干脆初始化定义一个随机汉字即可
                tempStr[0] = str[i++];
                tempStr[1] = str[i];
                printf("%s",tempStr);  //采用这种字符串拼接的方法,来达到两个字节输出一个汉字
            }
        }
    }
    
    int main(int argc, char* argv[]){
        //验证
        subString(str,5);
    	printf("\n");
    	subString(str,6);
    	printf("\n");
    	subString(str,8);
        return 0;
    }
    

2.逆向IF语句

1)IF逆向
  • 反汇编如下:

    调用处代码:			
    push        5		
    push        4		
    call        0040100f		
    add         esp,8		
    -------------------------------------------------------------------------------
    函数内部:					                            
    00401030   push        ebp							函数内部功能分析:	
    00401031   mov         ebp,esp						1、分析参数:	
    00401033   sub         esp,44h							
    00401036   push        ebx							
    00401037   push        esi							
    00401038   push        edi							2、分析局部变量	
    00401039   lea         edi,[ebp-44h]							
    0040103C   mov         ecx,11h							
    00401041   mov         eax,0CCCCCCCCh							
    00401046   rep stos    dword ptr [edi]							
    00401048   mov         eax,[004225c4]				3、分析全局变量	
    0040104D   mov         dword ptr [ebp-4],eax							
    00401050   mov         ecx,dword ptr [ebp+8]							
    00401053   cmp         ecx,dword ptr [ebp+0Ch]							
    00401056   jg          00401064							
    00401058   mov         edx,dword ptr [ebp+0Ch]		4、功能分析	
    0040105B   add         edx,dword ptr [ebp-4]							
    0040105E   mov         dword ptr [004225c4],edx							
    00401064   pop         edi							
    00401065   pop         esi							5、返回值分析	
    00401066   pop         ebx							
    00401067   mov         esp,ebp							
    00401069   pop         ebp							
    0040106A   ret										6、还原成C函数	
    
  • 按照上述步骤开始分析:

    image-20211205130323491
    #include "stdafx.h"
    
    int m;   //全局变量
    
    void Func1(int x,int y){  //参数
    	int a;		//局部变量
    	a = m;
    	if(x<=y){
            m = y + a;
    	}
    }
    
    int main(int argc,char* argv[]){
    	Func1(4,5);   //看参数入栈的指令,注意是倒着入栈的
    }
    
  • 验证一下:

    image-20211205130950351 image-20211205130859752

2)IF…ELSE逆向
  • 反汇编如下:

    004010B0   push        ebp							函数内部功能分析:	
    004010B1   mov         ebp,esp								
    004010B3   sub         esp,48h							1、分析参数:	
    004010B6   push        ebx								
    004010B7   push        esi								
    004010B8   push        edi								
    004010B9   lea         edi,[ebp-48h]					2、分析局部变量	
    004010BC   mov         ecx,12h								
    004010C1   mov         eax,0CCCCCCCCh								
    004010C6   rep stos    dword ptr [edi]								
    004010C8   mov         eax,[004225c4]								
    004010CD   mov         dword ptr [ebp-4],eax			3、分析全局变量	
    004010D0   mov         dword ptr [ebp-8],2								
    004010D7   mov         ecx,dword ptr [ebp+8]								
    004010DA   cmp         ecx,dword ptr [ebp+0Ch]								
    004010DD   jl          004010e8								
    004010DF   mov         edx,dword ptr [ebp-8]			4、功能分析	
    004010E2   add         edx,1								
    004010E5   mov         dword ptr [ebp-8],edx								
    004010E8   mov         eax,dword ptr [ebp+8]								
    004010EB   cmp         eax,dword ptr [ebp+0Ch]			5、返回值分析	
    004010EE   jge         004010fb								
    004010F0   mov         ecx,dword ptr [ebp-8]								
    004010F3   mov         dword ptr [004225c4],ecx								
    004010F9   jmp         00401107							6、还原成C函数	
    004010FB   mov         edx,dword ptr [ebp-4]								
    004010FE   add         edx,dword ptr [ebp-8]								
    00401101   mov         dword ptr [004225c4],edx								
    00401107   pop         edi								
    00401108   pop         esi								
    00401109   pop         ebx								
    0040110A   mov         esp,ebp								
    0040110C   pop         ebp								
    0040110D   ret								
    
  • 按照上述步骤开始逆向分析:

    image-20211205143324453
    #include "stdafx.h"
    
    int m;
    void Func(int x,int y){
    	int a = m;
    	int b = 2;
    	if(x >= y){
    		b++;	
    	}
    	
    	if(x < y)
    	{
    		m = b;
    	}else{
    		m = a + b;
    	}
    }
    
    int main(int argc,char* argv[]){
    	Func(1,2);
        return 0;
    }
    
  • 验证一下:

    image-20211205143404190 image-20211205143458836

3)IF…ELSE IF…ELSE逆向
  • 反汇编如下:

    004010B0   push        ebp							函数内部功能分析:	
    004010B1   mov         ebp,esp							
    004010B3   sub         esp,4Ch						1、分析参数:	
    004010B6   push        ebx							
    004010B7   push        esi							
    004010B8   push        edi							
    004010B9   lea         edi,[ebp-4Ch]				2、分析局部变量	
    004010BC   mov         ecx,13h							
    004010C1   mov         eax,0CCCCCCCCh							
    004010C6   rep stos    dword ptr [edi]							
    004010C8   mov         dword ptr [ebp-4],0							
    004010CF   mov         dword ptr [ebp-8],1			3、分析全局变量	
    004010D6   mov         dword ptr [ebp-0Ch],2							
    004010DD   mov         eax,dword ptr [ebp+8]							
    004010E0   cmp         eax,dword ptr [ebp+0Ch]							
    004010E3   jg         004010f0							
    004010E5   mov         ecx,dword ptr [ebp-8]		4、功能分析	
    004010E8   sub         ecx,1							
    004010EB   mov         dword ptr [ebp-4],ecx							
    004010EE   jmp         00401123							
    004010F0   mov         edx,dword ptr [ebp+0Ch]		5、返回值分析	
    004010F3   cmp         edx,dword ptr [ebp+10h]							
    004010F6   jl          00401103							
    004010F8   mov         eax,dword ptr [ebp-0Ch]							
    004010FB   add         eax,1						6、还原成C函数	
    004010FE   mov         dword ptr [ebp-4],eax							
    00401101   jmp         00401123							
    00401103   mov         ecx,dword ptr [ebp+8]							
    00401106   cmp         ecx,dword ptr [ebp+10h]							
    00401109   jle         00401116							
    0040110B   mov         edx,dword ptr [ebp-8]							
    0040110E   add         edx,dword ptr [ebp-0Ch]							
    00401111   mov         dword ptr [ebp-4],edx							
    00401114   jmp         00401123							
    00401116   mov         eax,dword ptr [ebp-0Ch]							
    00401119   mov         ecx,dword ptr [ebp-8]							
    0040111C   lea         edx,[ecx+eax-1]							
    00401120   mov         dword ptr [ebp-4],edx							
    00401123   mov         eax,dword ptr [ebp-4]							
    00401126   add         eax,1							
    00401129   pop         edi							
    0040112A   pop         esi							
    0040112B   pop         ebx							
    0040112C   mov         esp,ebp							
    0040112E   pop         ebp							
    0040112F   ret							
    
  • 按照上述步骤开始分析:

    2
    #include "stdafx.h"
    
    int Func(int x,int y,int z){
    	int a = 0;
    	int b = 1;
    	int c = 2;
    	if(x<=y){
    		a = b - 1;
    	}else if(y >= z){
    		a = c + 1;
    	}else if(x > z){
    		a = b + c;
    	}else{
    		a = b + c - 1;
    	}
    	return a + 1;
    }
    int main(int argc,char* argv[]){
        Func(1,2,3);
        return 0;
    }
    
  • 验证一下:

    image-20211205152553107 image-20211205152532001

3.总结

  • IF语句反汇编格式:就只有单纯的这种格式

    影响标志寄存器的指令
    JCC指令
    
  • if…else语句反汇编格式:

    影响标志寄存器的指令
    JCC指令
    1.如果不跳转一直走到jmp,jmp后面的地址为if分支语句结束的地方
    2.如果跳转,跳转到的地方没有影响寄存器指令,而是一些操作指令,执行完后就结束了if分支语句
    
  • if…else if…else语句反汇编格式:

    影响标志寄存器的指令
    JCC指令
    1.如果不跳转,一直走到jmp,jmp后面的地址为分支结束地址
    2.如果跳转
    	2.1如果发现还有影响标志寄存器的指令,且上面一行是jmp指令,下面又分为跳与不跳...则此处时else if语句
    	2.2如果发现没有影响标志寄存器指令了,而是一些操作指令,执行完后就结束了if分支语句,则是else语句
    
    满足的共性:
    1.当每个条件跳转指令要跳转的地址前面都有jmp指令
    2.这些jmp指令跳转的地址都是一样的
    3.如果某个分支没有条件判断,则为else部分
    
  • 逆向分析的时候不要一头扎进去一步一步的分析,而是先要按照这些分支语句的特征分析出哪些部分是if,哪些部分是else if,哪些部分是else,即先做整体分析,分析出结构后再去具体分析!

第1讲:2015-01-12(进制01) 第2讲:2015-01-13(进制02) 第3讲:2015-01-14(数据宽度-逻辑运算03) 第4讲:2015-01-15(通用寄存器-内存读写04) 第5讲:2015-01-16(内存寻址-堆栈05) 第6讲:2015-01-19(EFLAGS寄存器06) 第7讲:2015-01-20(JCC) 第8讲:2015-01-21(堆栈图) 第8讲:2015-01-21(宝马问题) 第9讲:2015-01-22(堆栈2) 第10讲:2015-01-23(C语言01_后半段) 第10讲:2015-01-23(C语言完整版) 第11讲:2015-01-26(C语言02_数据类型) 第12讲:2015-01-27(C语言03_数据类型_IF语句) 第13讲:2015-01-28(C语言04_IF语句逆向分析上) 第14讲:2015-01-28(C语言04_IF语句逆向分析下) 第15讲:2015-01-29(C语言04_正向基础) 第16讲:2015-01-30(C语言05_循环语句) 第17讲:2015-02-02(C语言06_参数_返回值_局部变量_数组反汇编) 第18讲:2015-02-02(2015-01-30课后练习) 第19讲:2015-02-03(C语言07_多维数组) 第20讲:2015-02-03(2015-02-02课后练习) 第21讲:2015-02-04(C语言08_结构体) 第22讲:2015-02-05(C语言09_字节对齐_结构体数组) 第23讲:2015-02-06(C语言10_Switch语句反汇编) 第24讲:2015-02-26(C语言11_指针1) 第25讲:2015-02-27(C语言11_指针2) 第26讲:2015-02-28(C语言11_指针3) 第27讲:2015-02-28(C语言11_指针4) 第28讲:2015-03-02(C语言11_指针5) 第29讲:2015-03-03(C语言11_指针6) 第30讲:2015-03-04(C语言11_指针7) 第31讲:2015-03-06(C语言11_指针8) 第32讲:2015-03-09(位运算) 第33讲:2015-03-10(内存分配_文件读写) 第34讲:2015-03-11(PE头解析_手动) 第35讲:2015-03-12(PE头字段说明) 第36讲:2015-03-13(PE节表) 第37讲:2015-03-16(FileBuffer转ImageBuffer) 第38讲:2015-03-17(代码节空白区添加代码) 第39讲:2015-03-18(任意节空白区添加代码) 第40讲:2015-03-19(新增节添加代码) 第41讲:2015-03-20(扩大节-合并节-数据目录) 第42讲:2015-03-23(静态连接库-动态链接库) 第43讲:2015-03-24(导出表) 第44讲:2015-03-25(重定位表) 第45讲:2015-03-26(移动导出表-重定位表) 第46讲:2015-03-27(IAT表) 第47讲:2015-03-27(导入表) 第48讲:2015-03-30(绑定导入表) 第49讲:2015-03-31(导入表注入) 第50讲:2015-04-01(C++ this指针 类 上) 第51讲:2015-04-01(C++ this指针 类 下) 第52讲:2015-04-02(C++ 构造-析构函数 继承) 第53讲:2015-04-03(C++ 权限控制) 第54讲:2015-04-07(C++ 虚函数表) 第55讲:2015-04-08(C++ 动态绑定-多态-上) 第56讲:2015-04-08(C++ 动态绑定-多态-下) 第57讲:2015-04-09(C++ 模版) 第58讲:2015-04-10(C++ 引用-友元-运算符重载) 第59讲:2015-04-13(C++ new-delete-Vector) 第60讲:2015-04-14(C++Vector实现) 第61讲:2015-04-15(C++链表) 第62讲:2015-04-16(C++链表实现) 第63讲:2015-04-16(C++二叉树) 第64讲:2015-04-17(C++二叉树实现) 第65讲:2015-04-20(Win32 宽字符) 第66讲:2015-04-21(Win32 事件-消息-消息处理函数) 第67讲:2015-04-22(Win32 ESP寻址-定位回调函数-条件断点) 第68讲:2015-04-23(Win32 子窗口-消息处理函数定位) 第69讲:2015-04-24(Win32 资源文件-消息断点) 第70讲:2015-04-27(Win32 提取图标-修改标题) 第71讲:2015-04-28(Win32 通用控件-VM_NOTIFY) 第72讲:2015-04-29(Win32 PE查看器-项目要求) 项目一:PE查看器 开发周期(5天) 需求文档 第73讲:2015-05-07(Win32 创建线程) 第74讲:2015-05-08(Win32 线程控制_CONTEXT) 第75讲:2015-05-11(Win32 临界区) 第76讲:2015-05-12(Win32 互斥体) 第77讲:2015-05-13(Win32 事件) 第78讲:2015-05-14(Win32 信号量) 第79讲:2015-05-15(Win32 线程同步与线程互斥) 第80讲:2015-05-18(Win32 进程创建_句柄表) 第81讲:2015-05-20(Win32 以挂起形式创建进程) 第82讲:2015-05-21(Win32 加密壳_项目说明) 项目二:加密壳 开发周期(5天) 需求文档 第83讲:2015-05-28(Win32 枚举窗口_鼠标键盘事件) 第84讲:2015-05-29(Win32 CE练习) 第85讲:2015-06-01(Win32 OD练习) 第86讲:2015-06-03(Win32 ShellCode_远程线程注入) 第87讲:2015-06-04(Win32 加载EXE_模块隐藏) 第88讲:2015-06-09(Win32 IAT_HOOK) 第89讲:2015-06-10(Win32 InlineHook) 第90讲:2015-06-11(Win32 进程通信) 第91讲:2015-06-11(Win32 进程监控_项目说明) 项目三:进程监控 开发周期(5天) 需求文档 第92讲:2015-06-15(硬编码_01) 第93讲:2015-06-16(硬编码_02) 第94讲:2015-06-17(硬编码_03) 第95讲:2015-06-18(硬编码_04) 第96讲:2015-06-19(硬编码_05)
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值