Win32反汇编(九)使用SCASB与REPNE、CMPSB与REPZ指令实现对字符串的比较功能

前言

作者:浪子花梦,一个有趣的程序员 ~
此系列文章都是一些基础的文章,每篇文章都通过几个小例子快速的了解 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) 表示我们不希望编译器为我们做任何的事情,所有的代码都由我们自己来维护,包括一些堆栈平衡等 . . .

.
.


  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值