逆向分析练习三(最长公共前缀)

本文通过一道逆向分析练习题介绍了如何找出字符串数组的最长公共前缀,涉及汇编语言中的for和while嵌套循环。通过debug版本的汇编代码,解析了程序的执行逻辑,包括字符串长度的计算、循环条件判断以及字符比较,最终实现找到公共前缀的功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

逆向分析练习三(最长公共前缀)

这次选择的这个代码中存在for和while的嵌套,适合提升逆向中对循环的感知。

题目描述

编写一个函数来查找字符串数组中的最长公共前缀。

如果不存在公共前缀,返回空字符串 ""

示例 1:

输入:strs = ["flower","flow","flight"]
输出:"fl"

debug版本汇编代码

009F3580  push        ebp  
009F3581  mov         ebp,esp 
009F3583  sub         esp,0F0h 
009F3589  push        ebx  
009F358A  push        esi  
009F358B  push        edi  
009F358C  lea         edi,[ebp-0F0h] 
009F3592  mov         ecx,3Ch 
009F3597  mov         eax,0CCCCCCCCh 						
009F359C  rep stos    dword ptr es:[edi] 				//rep 和 stos 在下面分析节点的[1]中有描述
009F359E  mov         eax,dword ptr [strs] 			////这下面开始是业务逻辑的代码了
009F35A1  mov         ecx,dword ptr [eax] 
009F35A3  push        ecx  										//上面应该是从一个指针的指针对象中取出地址
009F35A4  call        @ILT+495(_strlen) (9F11F4h) //调用strlen
009F35A9  add         esp,4 
009F35AC  mov         dword ptr [a],eax 			//a = strlen的返回值
009F35AF  mov         eax,dword ptr [strs] 	//
009F35B2  mov         ecx,dword ptr [eax] 
009F35B4  mov         dword ptr [ss],ecx 	//ss = strs[0]
009F35B7  mov         dword ptr [j],1 				//这下面这一块应该是个for(;j<strSize;j++)
009F35BE  jmp         longestCommonPrefix+49h (9F35C9h) 
009F35C0  mov         eax,dword ptr [j]    //进入for循环
009F35C3  add         eax,1 
009F35C6  mov         dword ptr [j],eax 
009F35C9  mov         eax,dword ptr [j] 	//上面这一块是j++,下面开始是for的代码块
009F35CC  cmp         eax,dword ptr [strsSize] 
009F35CF  jge         longestCommonPrefix+90h (9F3610h) //这里直接跳出 j>=strSize
009F35D1  mov         dword ptr [i],0 				//i=0
009F35D8  mov         eax,dword ptr [i] 			//进入循环判断
009F35DB  cmp         eax,dword ptr [a] 
009F35DE  jge         longestCommonPrefix+88h (9F3608h) //if(a<strlen)进入下面代码块
009F35E0  mov         eax,dword ptr [j] 
009F35E3  mov         ecx,dword ptr [strs] 
009F35E6  mov         edx,dword ptr [ecx+eax*4] //edx = strs[j]
009F35E9  mov         eax,dword ptr [i] 
009F35EC  movsx       ecx,byte ptr [edx+eax] //movsx是有符号的mov,ecx=strs[j][i]
009F35F0  mov         edx,dword ptr [ss] //上面只移动一个byte作为偏移所以说strs应该是个char**
009F35F3  add         edx,dword ptr [i] 
009F35F6  movsx       eax,byte ptr [edx] 
009F35F9  cmp         ecx,eax 				//ss[i]和 strs[j][i]做比较看是否相等	
009F35FB  jne         longestCommonPrefix+88h (9F3608h) //这里是if(strs[j][i]==ss[i])
009F35FD  mov         eax,dword ptr [i] 		//相等就i++
009F3600  add         eax,1 
009F3603  mov         dword ptr [i],eax 
009F3606  jmp         longestCommonPrefix+58h (9F35D8h) //跳回第二层循环判断
009F3608  mov         eax,dword ptr [i] 
009F360B  mov         dword ptr [a],eax  		//a = i
009F360E  jmp         longestCommonPrefix+40h (9F35C0h) //进入第一层循环
009F3610  mov         eax,dword ptr [ss] 
009F3613  add         eax,dword ptr [a] 
009F3616  mov         byte ptr [eax],0 
009F3619  mov         eax,dword ptr [ss]    //返回的还是eax是个指针
009F361C  pop         edi  
009F361D  pop         esi  
009F361E  pop         ebx  
009F361F  add         esp,0F0h 
009F3625  cmp         ebp,esp 
009F3627  call        @ILT+335(__RTC_CheckEsp) (9F1154h) 
009F362C  mov         esp,ebp 
009F362E  pop         ebp  
009F362F  ret         

分析

  1. stos:作用是把eax里面的数据,赋值给后面的地址,然后edi + 4,或者是-4,加或减主要看方向标志位DF,DF=0 就是+地址 DF=1就是减地址

    1. 例如:stos dword ptr es:[edi]这条stos指令可以分解后变成下面汇编代码

      mov dword ptr es:[edi],eax
      add edi , 4
      
  2. rep指令作用是:重复后面的指令,是个前缀,例如这里 rep stos,就是重复执行stos指令
    rep指令每次执行的时候都从ecx寄存器里面读取值,当ecx大于0,就执行后面语句,执行完以后,会让ecx - 1,然后再执行rep后面的指令。

DOWRD func(char** strs,int strSize){
	int  a = strlen(strs[0]);
	char* ss = strs[0]
	for(int j=0;j<strSize;j++){
	int i = 0;
		while(i<a){
			if(ss[i] == strs[j][i]){
				i++;
			}else{
				a = i;
				break;
			}
		}
	}
	ss[a] = 0;
	return ss;
}

源代码


char * longestCommonPrefix(char ** strs, int strsSize){
int a=strlen(strs[0]);
char*ss=strs[0];
for(int j=1;j<strsSize;j++)
{
int i=0;
while(i<a&&strs[j][i]==ss[i])
{
    i++;
}
a=i;
}
ss[a]='\0';
return ss;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值