飘云阁

 找回密码
 加入我们

QQ登录

只需一步,快速开始

查看: 3156|回复: 6

[C/C++] kmp代码编译分析

[复制链接]
  • TA的每日心情
    擦汗
    2019-3-1 23:51
  • 签到天数: 559 天

    [LV.9]以坛为家II

    发表于 2015-6-3 20:01:24 | 显示全部楼层 |阅读模式



    1.         //下面是kmp算法
    2. //*********************************************************//
    3.     void get_next(char* s,int* next) //s表示模式串,next表示next数组的头指针
    4. {
    5.     int length=strlen(s);
    6.     int i=1,j=0;
    7.                                //i表示模式串的每一个元素的指针,每次加1递增,j表示前缀串中,每一个元素的位置。
    8.     next[0]=-1;
    9.     for(;i<length;i++){        //开始递归模式串中每一个元素
    10.         if(s[i]==s[j]){        //如果当前元素和前缀的第一个元素相等,表示开始匹配前缀和后缀串,j++表示前缀的下一个位置的元素。
    11.             next[i]=j;         //同时把当前next[i]设置成为前缀中的位置。
    12.             j++;
    13.         }else{                 //当前位置和前缀串中的不一致,
    14.             if(s[i]==s[0]){    //如果当前位置和前缀串中的第一个元素相同,那么表示又重新开始匹配新一轮后缀
    15.                 next[i]=0;     //重新开始匹配后缀,所以next的值是0,表示前缀的第一个元素的位置
    16.                 j=1;           //前缀的指针变成下一个位置
    17.             }
    18.             else{              //如果当前位置和第一个位置的元素也不相同,表示没有这样的以这个元素为前缀的字符串,把这个next值变成-1.
    19.                 next[i]=-1;
    20.                 j=0;
    21.             }
    22.         }
    23.     }
    24. }

    25.    //target是目标串,s是模式串,data是next数组
    26. void find(char *target,char *s,int* data){
    27.   int i=0;              //i是目标串的指针
    28.   int j=0;              //j是模式串的指针
    29.   for(;i<strlen(s);){
    30.      if(s[i]==target[j]){ //如果模式串和目标串匹配
    31.         if(j==strlen(target)-1){//如果完全匹配,就说明在目标串中找到了模式串
    32.            printf("start:%d\n",i-j+1);
    33.            break;
    34.         }else{
    35.            j++;//否则继续比较下一个字符
    36.            i++;
    37.         }
    38.      }else{    //如果这两个字符不匹配
    39.        if(j==0||data[j-1]==-1){    //如果是和模式串的第一个字符做匹配失败,或者next数组的前一个值是-1,表示前一个位置的后缀,在当前模式串中找不到前缀,所以这时,i指针需要向前移动,
    40.                 j=0;
    41.                 i++;
    42.             }else{               //表示匹配前缀的后一个位置的元素。
    43.                 j=data[j-1]+1;
    44.             }
    45.      }
    46.   }
    47. }
    复制代码

    这个代码表面看起来没有什么问题,但编译的时候就出问题了。
    我们看看编译后的void find(char *target,char *s,int* data) 函数

    00401430  /$  53                 push    ebx
    00401431  |.  8B5C24 0C          mov     ebx, dword ptr [esp+0xC]
    00401435  |.  55                 push    ebp
    00401436  |.  56                 push    esi
    00401437  |.  57                 push    edi
    00401438  |.  8BFB               mov     edi, ebx
    0040143A  |.  83C9 FF            or      ecx, 0xFFFFFFFF
    0040143D  |.  33C0               xor     eax, eax
    0040143F  |.  33F6               xor     esi, esi
    00401441  |.  33D2               xor     edx, edx
    00401443  |.  F2:AE              repne   scas byte ptr es:[edi]              ;  垃圾代码
    00401445  |.  F7D1               not     ecx                                 ;  垃圾代码
    00401447  |.  49                 dec     ecx                                 ;  垃圾代码
    00401448  |.  74 60              je      short 004014AA                      ;  垃圾代码
    0040144A  |.  8B6C24 14          mov     ebp, dword ptr [esp+0x14]
    0040144E  |>  8A041E             /mov     al, byte ptr [esi+ebx]
    00401451  |.  8A0C2A             |mov     cl, byte ptr [edx+ebp]
    00401454  |.  3AC1               |cmp     al, cl
    00401456  |.  75 15              |jnz     short 0040146D
    00401458  |.  8BFD               |mov     edi, ebp
    0040145A  |.  83C9 FF            |or      ecx, 0xFFFFFFFF
    0040145D  |.  33C0               |xor     eax, eax
    0040145F  |.  F2:AE              |repne   scas byte ptr es:[edi]
    00401461  |.  F7D1               |not     ecx
    00401463  |.  83C1 FE            |add     ecx, -0x2
    00401466  |.  3BD1               |cmp     edx, ecx
    00401468  |.  74 2F              |je      short 00401499
    0040146A  |.  42                 |inc     edx
    0040146B  |.  EB 16              |jmp     short 00401483
    0040146D  |>  85D2               |test    edx, edx
    0040146F  |.  74 10              |je      short 00401481
    00401471  |.  8B4C24 1C          |mov     ecx, dword ptr [esp+0x1C]
    00401475  |.  8B5491 FC          |mov     edx, dword ptr [ecx+edx*4-0x4]
    00401479  |.  83FA FF            |cmp     edx, -0x1
    0040147C  |.  74 03              |je      short 00401481
    0040147E  |.  42                 |inc     edx
    0040147F  |.  EB 03              |jmp     short 00401484
    00401481  |>  33D2               |xor     edx, edx
    00401483  |>  46                 |inc     esi
    00401484  |>  8BFB               |mov     edi, ebx                           ;  垃圾代码
    00401486  |.  83C9 FF            |or      ecx, 0xFFFFFFFF                    ;  垃圾代码
    00401489  |.  33C0               |xor     eax, eax                           ;  垃圾代码
    0040148B  |.  F2:AE              |repne   scas byte ptr es:[edi]             ;  垃圾代码
    0040148D  |.  F7D1               |not     ecx                                ;  垃圾代码
    0040148F  |.  49                 |dec     ecx                                ;  垃圾代码
    00401490  |.  3BF1               |cmp     esi, ecx                           ;  垃圾代码
    00401492  |.^ 72 BA              \jb      short 0040144E
    00401494  |.  5F                 pop     edi
    00401495  |.  5E                 pop     esi
    00401496  |.  5D                 pop     ebp
    00401497  |.  5B                 pop     ebx
    00401498  |.  C3                 retn

    这样的后果就是程序遇到0x00就会退出比较。

    将那些垃圾代码删除即可,修改如下:
    00401430  /$  53                 push    ebx
    00401431  |.  8B5C24 0C          mov     ebx, dword ptr [esp+0xC]
    00401435  |.  55                 push    ebp
    00401436  |.  56                 push    esi
    00401437  |.  57                 push    edi
    00401438  |.  8BFB               mov     edi, ebx
    0040143A  |.  83C9 FF            or      ecx, 0xFFFFFFFF
    0040143D  |.  33C0               xor     eax, eax
    0040143F  |.  33F6               xor     esi, esi
    00401441  |.  33D2               xor     edx, edx
    00401443      90                 nop                                         ;  垃圾代码
    00401444      90                 nop
    00401445      90                 nop                                         ;  垃圾代码
    00401446      90                 nop
    00401447      90                 nop                                         ;  垃圾代码
    00401448      90                 nop                                         ;  垃圾代码
    00401449      90                 nop
    0040144A  |.  8B6C24 14          mov     ebp, dword ptr [esp+0x14]
    0040144E  |>  8A041E             /mov     al, byte ptr [esi+ebx]
    00401451  |.  8A0C2A             |mov     cl, byte ptr [edx+ebp]
    00401454  |.  3AC1               |cmp     al, cl
    00401456  |.  75 15              |jnz     short 0040146D
    00401458  |.  8BFD               |mov     edi, ebp
    0040145A  |.  83C9 FF            |or      ecx, 0xFFFFFFFF
    0040145D  |.  33C0               |xor     eax, eax
    0040145F  |.  F2:AE              |repne   scas byte ptr es:[edi]
    00401461  |.  F7D1               |not     ecx
    00401463  |.  83C1 FE            |add     ecx, -0x2
    00401466  |.  3BD1               |cmp     edx, ecx
    00401468  |.  74 2F              |je      short 00401499
    0040146A  |.  42                 |inc     edx
    0040146B  |.  EB 16              |jmp     short 00401483
    0040146D  |>  85D2               |test    edx, edx
    0040146F  |.  74 10              |je      short 00401481
    00401471  |.  8B4C24 1C          |mov     ecx, dword ptr [esp+0x1C]
    00401475  |.  8B5491 FC          |mov     edx, dword ptr [ecx+edx*4-0x4]
    00401479  |.  83FA FF            |cmp     edx, -0x1
    0040147C  |.  74 03              |je      short 00401481
    0040147E  |.  42                 |inc     edx
    0040147F  |.  EB 03              |jmp     short 00401484
    00401481  |>  33D2               |xor     edx, edx
    00401483  |>  46                 |inc     esi
    00401484  |>  8BFB               |mov     edi, ebx                           ;  垃圾代码
    00401486    ^ EB C6              jmp     short 0040144E                      ;  垃圾代码
    00401488      90                 nop
    00401489      90                 |nop                                        ;  垃圾代码
    0040148A      90                 nop
    0040148B      90                 |nop                                        ;  垃圾代码
    0040148C      90                 nop
    0040148D      90                 |nop                                        ;  垃圾代码
    0040148E      90                 nop
    0040148F      90                 |nop                                        ;  垃圾代码
    00401490      90                 |nop                                        ;  垃圾代码
    00401491      90                 nop
    00401492      90                 \nop
    00401493      90                 nop
    00401494  |.  5F                 pop     edi
    00401495  |.  5E                 pop     esi
    00401496  |.  5D                 pop     ebp
    00401497  |.  5B                 pop     ebx
    00401498  |.  C3                 retn
    00401499  |>  2BF2               sub     esi, edx
    0040149B  |.  46                 inc     esi
    0040149C  |.  56                 push    esi
    0040149D  |.  68 B0704200        push    004270B0                            ;  start:%d\n
    004014A2  |.  E8 18210100        call    004135BF
    004014A7  |.  83C4 08            add     esp, 0x8
    004014AA  |>  5F                 pop     edi
    004014AB  |.  5E                 pop     esi
    004014AC  |.  5D                 pop     ebp
    004014AD  |.  5B                 pop     ebx
    004014AE  \.  C3                 retn

    至于速度是确实一般!

    未命名.PNG




    PYG19周年生日快乐!
  • TA的每日心情
    擦汗
    2019-3-1 23:51
  • 签到天数: 559 天

    [LV.9]以坛为家II

     楼主| 发表于 2015-6-4 08:59:05 | 显示全部楼层
    看来那些垃圾代码确实是strlen,那个代码之前是字符串查找的,而strlen遇到0x00会停止。
    我将其改成hex查找,所以出错。

    现在修正一下就可以用了:
    PYG19周年生日快乐!
  • TA的每日心情
    难过
    7 天前
  • 签到天数: 11 天

    [LV.3]偶尔看看II

    发表于 2015-6-4 09:46:12 | 显示全部楼层
    {:soso_e100:}/...你把char 换成 unsigned char
    len 传进来不就好了?

    点评

    主要是strlen遇到0x00就会截止,所以我将len传进来就可以了,char倒是无所谓。  详情 回复 发表于 2015-6-4 09:52
    我试试,我直接将len放外面了,也可以。  发表于 2015-6-4 09:49
    PYG19周年生日快乐!
  • TA的每日心情
    擦汗
    2019-3-1 23:51
  • 签到天数: 559 天

    [LV.9]以坛为家II

     楼主| 发表于 2015-6-4 09:48:32 | 显示全部楼层
    本帖最后由 menglv 于 2015-6-4 09:53 编辑



            //下面是kmp算法,可以查找hex
    //*********************************************************//
            void get_next(char* s,int* next,int length) //s表示模式串,next表示next数组的头指针
    {
        //int length=strlen(s);
        int i=1,j=0;
                                   //i表示模式串的每一个元素的指针,每次加1递增,j表示前缀串中,每一个元素的位置。
        next[0]=-1;
        for(;i<length;i++){        //开始递归模式串中每一个元素
            if(s==s[j]){        //如果当前元素和前缀的第一个元素相等,表示开始匹配前缀和后缀串,j++表示前缀的下一个位置的元素。
                next=j;         //同时把当前next设置成为前缀中的位置。
                j++;
            }else{                 //当前位置和前缀串中的不一致,
                if(s==s[0]){    //如果当前位置和前缀串中的第一个元素相同,那么表示又重新开始匹配新一轮后缀
                    next=0;     //重新开始匹配后缀,所以next的值是0,表示前缀的第一个元素的位置
                    j=1;           //前缀的指针变成下一个位置
                }
                else{              //如果当前位置和第一个位置的元素也不相同,表示没有这样的以这个元素为前缀的字符串,把这个next值变成-1.
                    next=-1;
                    j=0;
                }
            }
        }
    }

       //target是目标串,s是模式串,data是next数组
    void find(char *target,char *s,int* data,int l,int l2){
      //l 为文件长度,l2 为特征码长度
      int i=0;              //i是目标串的指针
      int j=0;              //j是模式串的指针
      for(;i<l;){
         if(s==target[j]){ //如果模式串和目标串匹配
            if(j==l2-1){//如果完全匹配,就说明在目标串中找到了模式串
               printf("start:%d\n",i-j+1);
               break;
            }else{
               j++;//否则继续比较下一个字符
               i++;
            }
         }else{    //如果这两个字符不匹配
           if(j==0||data[j-1]==-1){    //如果是和模式串的第一个字符做匹配失败,或者next数组的前一个值是-1,表示前一个位置的后缀,在当前模式串中找不到前缀,所以这时,i指针需要向前移动,
                    j=0;
                    i++;
                }else{               //表示匹配前缀的后一个位置的元素。
                    j=data[j-1]+1;
                }
         }
      }
    }

    PYG19周年生日快乐!
  • TA的每日心情
    擦汗
    2019-3-1 23:51
  • 签到天数: 559 天

    [LV.9]以坛为家II

     楼主| 发表于 2015-6-4 09:52:41 | 显示全部楼层
    飘云 发表于 2015-6-4 09:46
    /...你把char 换成 unsigned char
    len 传进来不就好了?

    主要是strlen遇到0x00就会截止,所以我将len传进来就可以了,char倒是无所谓。

    点评

    .。不用strlen啊,,len外部算好~~ 随便改改源代码就OK了  详情 回复 发表于 2015-6-4 10:27
    PYG19周年生日快乐!
  • TA的每日心情
    难过
    7 天前
  • 签到天数: 11 天

    [LV.3]偶尔看看II

    发表于 2015-6-4 10:27:09 | 显示全部楼层
    menglv 发表于 2015-6-4 09:52
    主要是strlen遇到0x00就会截止,所以我将len传进来就可以了,char倒是无所谓。

    .。不用strlen啊,,len外部算好~~ 随便改改源代码就OK了

    PYG19周年生日快乐!
    您需要登录后才可以回帖 登录 | 加入我们

    本版积分规则

    快速回复 返回顶部 返回列表