strcmp库函数原理

0x00 寄语

万变不离宗,寻求本质,才能运筹帷幄。

0x01 VC++6.0&Release

#include <string.h>

int main(int argc, char **argv, char **envp)
{
    char szBuf[] = "Hello World!";
    char szDst[20] = "thank you";
    if (strcmp(szDst, szBuf))
    {
        printf("Well.\r\n");
    }
    return 0;
}

上图为测试的源代码,将其编译为release版本,使用ida打开,定位至main函数的关键代码部分。

上图第一行的eax表示szBuf字符串首地址的指针,esi表示szDst字符串首地址的指针;从上至下开始对其解析,首先从两个首地址中分别取出一个字符,保留前一个地址的字符后,将两字符进行比较,由于cmp指令是将两个字符做减法保留原值,所以其影响CF、ZF等标志位,此时分为三种情况:

  1. dl大于bl,此时CF标志位不产生借位,所以为0;两数之差不为0,ZF置0。此时完成两字符串比较,跳转至后续处理部分:
    1. 第一次sbb指令(eax-eax-CF位)得到eax为0,CF标志位依然为0;
    2. 第二个sbb指令(eax-(-1)-CF)得到eax为1作为返回值。
  2. dl小于bl,CF标志位产生借位,CF位置1;两数之差不为0,ZF置0。完成字符串比较,后续处理eax:
    1. 第一个sbb指令(eax-eax-CF位)得到eax为-1,出现借位,CF置1;
    2. 第二个sbb指令(eax-(-1)-CF),eax依然为-1作为返回值。
  3. dl等于bl,CF标志位无借位,CF置0;两数之差为0,ZF置1,表示两字符相同,不跳转继续执行代码;将保留的第一个字符串的字符使用test测试其是否为0:
    1. 为0,ZF位置1,表示字符串已经比较完成,jz指令直接跳走,将eax置0作为返回值跳出循环代码;
    2. 不为0,ZF位置0,jz指令不跳,则将两个寄存器各加1使用相对寻址方式重复一轮上述比较步骤,如果依然相同递归至此,则将两个寄存器各加2,循环执行上述所有步骤。
    3. 这里隐含的巧妙之处在于,当比较的两字符相同时,则只有两种情况:
      1. 非零字符相同继续比较
      2. 两字符均为‘\00’,
      3. 所以仅测试一次字符是否为‘\00’,便可得知比较是否结束。

strcmp在当前环境下,会将“每次循环比较两次”的代码内联,当前面的字符较大时,两次sbb计算会将eax置1;后面字符较大时,两次sbb计算会将eax置为-1;若比较相同后,前者为‘\00’,则两字符串相同,比较结束后,跳转将eax置零后跳出。

综上所述,第一次sbb指令会产生0或-1两个值,第二次sbb指令产生1或-1两个值作为返回值,分别表示“前者字符串较大”和“后者字符串较大”。若两字符串相同,则会将0作为返回值输出。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇