zoukankan      html  css  js  c++  java
  • 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中的字符串又是根据 来判断结束的.
    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'的实际长度


  • 相关阅读:
    Python学习日记(三) 学习使用dict
    Python学习日记(二) list操作
    Python学习日记(一) String函数使用
    Linux 下查找并删除文件命令
    spring mvc处理静态文件
    集合工具类CollectionUtils、ListUtils、SetUtils、MapUtils探究(转)
    如何选择IO流
    java并发框架Executor介绍
    mybatis如何传入一个list参数
    大规模SOA系统中的分布事务思考
  • 原文地址:https://www.cnblogs.com/arhatlohan/p/4217029.html
Copyright © 2011-2022 走看看