REPNE SCAS BYTE PTR ES:[EDI] 指令详解

在OD中看到一段汇编中有如下指令:
REPNE SCAS BYTE PTR ES:[EDI]
查了下.说是 扫描 ES:[EDI]字符串中的 AL值.值到找到AL值后停止.
听得一知半解.自已用VC写段类似的汇编跟了一下.才算是明白了.

LPSTR pstr="12345678";
DWORD strCount=0;
__asm{
xor eax,eax ;清0 eax.因为这个指令经常是用来得到字符串长度的.C中的字符串又是根据 /0来判断结束的.
or ecx,0xFFFFFFFF;//不明白.... 我是理解为 ecx=-1
mov edi,pstr;// EDI中现在是字符串的首地址了
repne scas BYTE PTR ES:[EDI];//在字符串中查找 AL值(AL=0) 这个指令会让ECX增加,也会让EDI增加.
mov strCount,ecx;//这时的ECX不是长度.是 0xFFFFFFF6 (这应该是表示一个负数)
not ecx ;//这才是正确的数了.这才是正数.(ECX=0x9) 为什么是9 ?因为把最后一个空字符也算进去了.
                //所以一般下面都会跟一句 dec ecx. 来减一.这样才是字符的长度.
sub edi,ecx ;//把EDI 指回字符串的首地址.
mov strCount,ecx
}


今天在分析一个crackme的时候遇到一条指令感觉不是很熟悉,查询了一些资料进行了学习,顺便做下笔记,方便以后查看,也方便给需要的人。
   具体的代码如下: 
004015E9   .  8D7C24 20     lea edi,dword ptr ss:[esp+0x20]
004015ED   .  83C9 FF       or ecx,-0x1                                  ;  将ecx 赋值为FFFFFFFF
004015F0   .  33C0          xor eax,eax                                  ;  EAX 清零
004015F2   .  895424 28     mov dword ptr ss:[esp+0x28],edx
004015F6   .  33F6          xor esi,esi                                  ;  ESI清零
004015F8   .  F2:AE         repne scas byte ptr es:[edi]
004015FA   .  F7D1          not ecx
004015FC   .  49            dec ecx
    看到上面有一条指令repne scas byte ptr es:[edi],原来一直很少见到,于是查询了一番,在看雪找到了相关的解答,原地址:
原文
    有下面的一些解答,总结如下:
1、即:repnz scasb(32位地址操作)。扫描es:edi指向的一系列字节数据,扫描长度由ecx指定,当遇到与al中的数据相等时停止扫描。
2、最经典的求字符串长度的代码,strlen()在VC优化编译模式是这段代码。
3、得到的字符串最后存放在ecx中。
详细分析步骤如下(修改了论坛中的一点错误):
重复前缀指令
任何一个串操作指令,都可以在前面加一个重复前缀,以实现串操作的重复执行,重复次数隐含在CX寄存器中
REP;REP前缀用在MOVS、STOS、LODS指令前,每次执行一次指令,CX减1;直到CX=0,重复执行结束
REPZ ;也可以表把为REPE,用在CMPS、SCAS指令前,每执行一次串指令CX减1,并判断ZF标志是否为0
;只要CX=0或ZF=0,则重复执行结束
REPNZ ;也可以表达为REPNE,用在CMPS、SCAS指令前,每执行一次串操作指令CX减1,并判断ZF标志是否为1,只要CX=0 或ZF=1,则重复执行结束。

串扫描指令SCAS
SCASB         ;字节串扫描:AL-ES:[DI],DI←DI+/-1
SCASW         ;字串扫描:AX-ES:[DI],DI←DI+/-2
串扫描指令SCAS将附加段中的字节或字内容与AL/AX寄存器内容进行比较,根据比较的结果设置标志,每次比较后修改DI寄存器的值,使之指向下一个元素。

解释:
假设esp+10指向字符串如:"xqiang",长度为6,以0结尾
ecx=FFFFFFFF
eax=0,则al=0
执行repne scas时候:
第一次:
al-'x',di=di-1,即byte ptr es:[edi]指向'q',并置相应的标志位
然后cx-1,则ecx=FFFFFFFE,判断是否cx=0或ZF=1,显然该处条件不成立,继续重复执行
第二次:
al-'q',di=di-1,即byte ptr es:[edi]指向'i',并置相应的标志位
然后cx-1,则ecx=FFFFFFFD,判断是否cx=0或ZF=1,显然该处条件不成立,继续重复执行
第三次:
al-'i',di=di-1,即byte ptr es:[edi]指向'a',并置相应的标志位
然后cx-1,则ecx=FFFFFFFC,判断是否cx=0或ZF=1,显然该处条件不成立,继续重复执行
第四次:
al-'a',di=di-1,即byte ptr es:[edi]指向'n',并置相应的标志位
然后cx-1,则ecx=FFFFFFFB,判断是否cx=0或ZF=1,显然该处条件不成立,继续重复执行
第五次:
al-'n',di=di-1,即byte ptr es:[edi]指向'g',并置相应的标志位
然后cx-1,则ecx=FFFFFFFA,判断是否cx=0或ZF=1,显然该处条件不成立,继续重复执行
第六次:
al-'g',di=di-1,即byte ptr es:[edi]指向'0',并置相应的标志位
然后cx-1,则ecx=FFFFFFF9,判断是否cx=0或ZF=1,显然该处条件不成立,继续重复执行
第七次:
al-0,di=di-1,即byte ptr es:[edi]指向'未知字符',并置相应的标志位
然后cx-1,则ecx=FFFFFFF8,判断是否cx=0或ZF=1,此时ZF=1,停止串搜索
现在ecx从FFFFFFFF到FFFFFFF8记录了字符串'xqiang'和0的长度
然后not ecx得到ecx=00000007
    dec ecx得到ecx=00000006 该长度就是字符串'xqiang'的实际长度

你可能感兴趣的:(REPNE SCAS BYTE PTR ES:[EDI] 指令详解)