一段多字节strlen汇编代码的分析

以下是代码与注释

注意

这里两个注意的点:

  1. 需要关注每一个字节的最低位, 以及最高字节的最高位, 以及为什么取FF FE 7E 作为EAX的加操作数
  2. ADD加-1对于没个字节的最低位来说可以看做是取反, 最低位是加1还是加0很重要, 对于最高位来说也是一样, 加的7E刚好是抽象把最高位当成下一个字节的最低位了…有点抽象…

代码及注释

;装载目的字符串
00259590:
MOV EAX,DWORD PTR DS:[ECX]

;加载ff,fe,7e使得eax的各个字节的最低位取反!!!,若对应的eax字节刚好为0,那么0的下一个高位的最低位就相当于复制过去了,没有取反
MOV EDX,0x7EFEFEFF
ADD EDX,EAX

;eax取反,各个字节的最低位取反
XOR EAX,0xFFFFFFFF
;异或,如果之前最低位,的前一字节不是0那么就相当于两个最低位都取过反,那么异或结果就是0,若前一个字节是0,异或结果就为1
XOR EAX,EDX

;自增4个字节,记录比较过的数
ADD ECX,0x4

;测试最终结果, 这里的81(若00出现在最高位那么就把判断位移到最高位,所以前面为7e,后面进位后变为7f,如果最高位字节非零那么就相当于前面取反了) 01(这个就是取最低位的异或结果) 01(这个就是取最低位的异或结果) 00(这个因为是最低字节所以默认进位…取ff)
TEST EAX,0x81010100

;结果非0就退出,说明DWORD中有00字节出现, 否则跳到00259590 继续执行
JE SHORT Reverse0.00259590

;以下是进行最后的字符串长度计算, 找出哪个\0在哪个字节并从总长度减去相应的长度, 之前是4个字节一加的, 所以退出的时候可能会多加长度, 这里就判断下\0在哪
MOV EAX,DWORD PTR DS:[ECX-0x4]
TEST AL,AL
JE SHORT Reverse0.002595E1
TEST AH,AH
JE SHORT Reverse0.002595D7
TEST EAX,0xFF0000
JE SHORT Reverse0.002595CD
TEST EAX,0xFF000000
JE SHORT Reverse0.002595C3
JMP SHORT Reverse0.00259590
002595C3:
LEA EAX,DWORD PTR DS:[ECX-0x1]
MOV ECX,DWORD PTR SS:[ESP+0x4]
SUB EAX,ECX
RETN
002595CD:
LEA EAX,DWORD PTR DS:[ECX-0x2]
MOV ECX,DWORD PTR SS:[ESP+0x4]
SUB EAX,ECX
RETN
002595D7:
LEA EAX,DWORD PTR DS:[ECX-0x3]
MOV ECX,DWORD PTR SS:[ESP+0x4]
SUB EAX,ECX
RETN
002595E1:
LEA EAX,DWORD PTR DS:[ECX-0x4]
MOV ECX,DWORD PTR SS:[ESP+0x4]
SUB EAX,ECX
RETN

代码运行实例

第一次:
//=============================
;EAX放着’4321’,输入的是"123456"
EDX 7e fe fe ff
EAX 34 33 32 31
//=============================
ADD EDX,EAX
最高字节不知道, 其他三字节都减一…感觉是配合00,变成负数!
EDX B3 32 31 30
EAX 34 33 32 31
//=============================
XOR EAX,-1
相当于取反, eax取反…后三位是减一后取反,现在的eax取反加一!..那就是
EDX B3 32 31 30
EAX CB CC CD CE
//=============================
XOR EAX,EDX
异或,不带进位的加…
EDX B3 32 31 30
EAX 78 FE FC FE
//=============================
这里的34 33什么的对应的是字符在内存的顺序,不是寄存器里的
==>是按字节看的最后TEST结果的
34 33 32 31 ===> 0000
TEST EAX,0x 81 01 01 00
EDX B3 32 31 30
EAX 78 FE FC FE
0111 1000 1111 1110 1111 1100 1111 1110
81 01 01 00
1000 0001 0000 0001 0000 0001 0000 0000
都取不上…最后是零了

第二次:
eax放着 fe 0 ‘6’ ‘5’
//=============================
EDX 7e fe fe ff
EAX fe 00 36 35
//=============================
ADD EDX,EAX
EDX 7c ff 35 34
EAX fe 00 36 35
//=============================
XOR EAX,-1
相当于取反
EDX 7c ff 35 34
EAX 01 ff c9 ca
//=============================
XOR EAX,EDX
EDX 7c ff 35 34
EAX 7d 00 fc fe
//=============================
35 36 00 fe ===> 0001
TEST EAX,0x81 01 01 00
EDX 7c ff 35 34
EAX 7d 00 fc fe
0111 1101 0000 0000 1111 1100 1111 1110
81 01 01 00
1000 0001 0000 0001 0000 0001 0000 0000

\0出现的情况汇总

这里是分析的起点, 我是从这里意识到, 每次\0影响的都是字符的后一位, 也即 按DWORD读入的前一个字节处
内存中地址: 00 fe fe fe
EAX读入的: fe fe fe 00
意识到这点,之后发现这里主要运用的是最低位的判断, 这也是为什么利用01 对一个字节进行TEST的原因
知道这一点其他就顺其自然了
//=============================
00 fe fe fe ===> 0100
eax 7c fc fd 00
0111 1100 1111 1100 1111 1101 0000 0000
81 01 01 00
1000 0001 0000 0001 0000 0001 0000 0000

//=============================
35 00 fe fe ===> 0010
eax 7c fd 00 fe
0111 1100 1111 1101 0000 0000 1111 1110
81 01 01 00
1000 0001 0000 0001 0000 0001 0000 0000

//=============================
35 36 00 fe ===> 0001
eax 7d 00 fc fe
0111 1101 0000 0000 1111 1100 1111 1110
81 01 01 00
1000 0001 0000 0001 0000 0001 0000 0000

//=============================
35 36 37 00 ===> 0001
eax 80 fe fc fe
1000 0000 1111 1110 1111 1100 1111 1110
81 01 01 00
1000 0001 0000 0001 0000 0001 0000 0000

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值