前言
作者:
浪子花梦
,一个有趣的程序员 ~
此系列文章都是一些基础的文章,每篇文章都通过几个小例子快速的了解 Win32反汇编与OD的使用,在此作个笔记
如若对您有帮助,记得三连哟 ~
前文链接
Win32反汇编(一) 初步探索Win32反汇编 与 Ollydbg的简单使用
Win32反汇编(二)几种常见的指令反汇编详解:EAX、MOVSX与MOVZX、LEA、SUB、CMP与转移指令
Win32反汇编(三)深层次的了解各种转移指令:IF语句有符号与无符号跳转
Win32反汇编(四)栈的工作原理与堆栈平衡,函数方法参数的调用约定
Win32反汇编(五)C/C++中的 if-else 与 switch-case 的正向分析与反向分析
Win32反汇编(六)C/C++中的循环语句反汇编分析、置增置减反汇编分析与编译器的优化分析
Win32反汇编(七)浮点指令(FLD / FILD / FSTP)与位移指令的逆向分析
Win32反汇编(八)逻辑运算符非运算与运算或运算与异或运算的逆向分析
文章目录
SCASB与REPNE
1)SCASB指令
SCASB 编译后:SCAS BTYP PTR [EDI]
相当于:
cmp byte ptr[edi],al
对标志位的影响相当于 sub指令,同时还会修改寄存器 EDI的值:
如果标志位 DF为0,则 inc EDI
如果标志位 DF为1,则 dec EDI
可通过 STD、CLD指令设置DF的值 . . .
2)REPNE指令:当 ECX != 0 并且 ZF = 0时,重复执行 SCASB,每执行一次 ECX的值减1
.
下面我们使用汇编来计算字符串的长度,cpp代码如下所示:
#include <cstdio>
int main() {
printf("SCASB REPNE\n");
char* s1 = (char*)"s1234567890";
__asm {
mov al, 0 // 用于比较的值
mov edi, s1 // edi 指向 s1
mov ecx, -1
repnz scasb // 开始查找字符 '\0'
not ecx // 取反
dec ecx; // -1 才等于字符串的长度
}
return 0;
}
使用 OD查看并演示效果如下所示:
.
.
CMPSB与REPZ
1)CMPS
cmps byte ptr [edi],byte ptr [esi]
cmps word ptr [edi],byte ptr [esi]
cmps dword ptr [edi],byte ptr [esi]
对标志位的影响相当于 sub指令,同时还会修改寄存器 EDI和ESI的值:
如果标志位 DF为0,则 EDI ESI 按对应大小递增
如果标志位 DF为1,则 EDI ESI 按对应大小递减
2)REPE / REPZ
repe / repz cmpsb 当 ecx != 0 并且 ZF = 1时,重复执行后面的指令
每执行一次 ecx的值减 1
我们运用上面的两个指令,再加上现在的两个指令来简单使用字符串的比较,cpp代码如下所示:
#include <cstdio>
int main() {
printf("repz-repe-cmpsb\n");
char* s1 = (char*)"adcdel";
char* s2 = (char*)"adcdel";
__asm {
// 求 s1 的长度
xor al, al // al = '\0'
mov edi, s1 // 指向 s1
mov ecx, -1
repnz scasb
not ecx
dec ecx
mov edi, s1
mov esi, s2
repz cmpsb // 开始逐个字符的比较
xor al, al
sete al // 取 ZF的值放到 al中
cmp al, 1 // 判断是否和 1不相等
jnz result1
cmp ecx, 0
jz result2 // 字符串相等
}
result1:
printf("s1 != s2\n");
goto end;
result2:
printf("s1 == s2\n");
end:
return 0;
}
使用 OD来演示这个程序的执行流程,如下所示:
.
.
字符串比较函数编写
此函数支持窄字节和宽字符的版本,可以在C/C++代码中直接使用,函数如下所示:
__declspec(naked) int __asm_stringStrcmpA(const char* s1, const char* s2) {
__asm {
push ebp // 堆栈保护
mov ebp, esp
push ecx
push edi
push esi
push edx
xor al, al // 第一个参数的大小
mov edi, [ebp + 4 + 4]
mov ecx, -1
cld // 比较的方向
repnz scasb
not ecx
dec ecx
mov edi, [ebp + 4 + 4] // 两个参数比较
mov esi, [ebp + 4 + 8]
repz cmpsb
xor eax, eax
xor edx, edx
mov al, [edi - 1] // 两个参数比较的最后一个字符相减
mov dl, [esi - 1]
sub eax, edx
pop edx // 堆栈恢复
pop esi
pop edi
pop ecx
pop ebp
retn // 返回 eax中的值
}
}
__declspec(naked) int __asm_stringStrcmpW(const wchar_t* s1, const wchar_t* s2) {
__asm {
push ebp // 堆栈保护
mov ebp, esp
push ecx
push edi
push esi
push edx
xor ax, ax // 第一个参数的大小
mov edi, [ebp + 4 + 4]
mov ecx, -1
repnz scasw
not ecx
dec ecx
mov edi, [ebp + 4 + 4] // 两个参数比较
mov esi, [ebp + 4 + 8]
repz cmpsw
xor eax, eax
xor edx, edx
mov al, [edi - 2] // 两个参数比较的最后一个字符相减
mov dl, [esi - 2]
sub eax, edx
pop edx // 堆栈恢复
pop esi
pop edi
pop ecx
pop ebp
retn // 返回 eax中的值
}
}
函数前面的 __declspec(naked) 表示我们不希望编译器为我们做任何的事情,所有的代码都由我们自己来维护,包括一些堆栈平衡等 . . .
.
.