先贴出这个练习的代码。主要考察的是 scas
和stos
指令的用法。首先根据[ebp+8]和[ebp+0ch]可以判断出这应该是一个被调用函数的实现代码,但这对于我们分析这段代码没关系。下面对每行代码进行分析。
Line 1 mov edi, [ebp+8]
取地址为 ebp+8 的 double word 存入 edi 中。若此代码段为被调用函数,则此条语句为取第一个参数到 edi。现在看不出来这个 double word 到底是什么。
Line 2 mov edx, edi
把 edi 的值复制到 edx 中。
Line 3 xor eax, eax
将 eax 置零。
Line 4 or ecx, 0FFFFFFFFh
设置 ecx = -1,做什么用处现在还看不出来。
Line 5 repne scasb
这是最关键的一步。首先看 scas
指令,它进行如下操作:
由于以上特性,所以此指令经常与 REP
指令一起出现,例如此条指令就是将 edi 指向的 double word 与 eax 比较,如果不等,则 edi = edi + 4, 直到相等。
Line 6 add ecx, 2
Line 7 neg ecx
之所以把这俩放到一起,是因为单看第六行指令很难理解,所以就继续往下看,发现对 ecx 取相反数了。首先由第五行的 scasd
指令可知 ecx 的值从 -1 又减小了从开始字符到遇到第一个 \0 时的长度。所以可以猜测这段代码用来计算字符串长度。
所以,如果 edi 指向的字符串为 \0
,则 ecx 完成第五行指令后的值为 -2。则完成第六行和第七行指令后的值分别为 0, 0。同理,如果 edi 指向的字符串为 hello\0
,则上述值分别为 -7, -5, 5。
故,此时 ecx 内存放的是此字符串的长度。
Line 8 mov al, [ebp+0Ch]
将地址为 ebp+0Ch 的 byte 存入 al 中。若此代码段为被调用函数,则此条语句为取第二个参数到 al。
Line 9 mov edi, edx
这里将第二行存入 edx 的值取出来,即将 edi 恢复成字符串头地址。
Line 10 rep stosb
继续先看 stos
指令,它进行如下操作:
所以这条指令就是把从字符串头开始位置,长度为 ecx(从第七行可知 ecx 为字符串长度)的内存块写入寄存器 al 的值。相当于 memset()。
Line 11 mov eax, edx
将字符串首地址作为返回值返回。
这段代码的 C 语言表示为:
01
:
8B
7D
08
mov edi, [ebp
+
8
]
02
:
8B
D7 mov edx, edi
03
:
33
C0 xor eax, eax
04
:
83
C9 FF
or
ecx,
0FFFFFFFFh
05
: F2 AE repne scasb
06
:
83
C1
02
add ecx,
2
07
: F7 D9 neg ecx
08
:
8A
45
0C
mov al, [ebp
+
0Ch
]
09
:
8B
FA mov edi, edx
10
: F3 AA rep stosb
11
:
8B
C2 mov eax, edx
01
:
8B
7D
08
mov edi, [ebp
+
8
]
02
:
8B
D7 mov edx, edi
03
:
33
C0 xor eax, eax
04
:
83
C9 FF
or
ecx,
0FFFFFFFFh
05
: F2 AE repne scasb
06
:
83
C1
02
add ecx,
2
07
: F7 D9 neg ecx
08
:
8A
45
0C
mov al, [ebp
+
0Ch
]
09
:
8B
FA mov edi, edx
10
: F3 AA rep stosb
11
:
8B
C2 mov eax, edx
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)