x86汇编语言实现简单的C函数功能

x86汇编语言实现简单的C函数功能

  • 问题介绍
  • 函数程序设计逻辑分析
    • 1.strlen函数
    • 2.strchr函数
    • 3.strcmp函数
    • 4.strset函数
  • 程序源代码
    • 1.strlen过程
    • 2.strchr过程
    • 3.strcmp过程
    • 4.strset过程
  • 程序运行结果截图
    • 【截图】-strlen
    • 【截图】-strchr
    • 【截图】-strcmp
    • 【截图】-strset

问题介绍

x86汇编语言实现简单的C函数功能_第1张图片

函数程序设计逻辑分析

1.strlen函数

程序要求
计算给定字符串的长度。

程序变量及寄存器注解:
sztext <----> 给定的字符串基址
EDI <----> 存放字符串基址
EAX <----> 用于长度计数

程序实现逻辑:
字符串结束时(即遇到终止符’\0’)停止计数。
每一次从字符串中取出一个字符并利用CMP指令与’\0’比较,将标志寄存器(包含ZF位)状态入栈。
给计数器EAX和索引地址EDI加一。
ZF出栈,LOOPNZ指令根据ZF位判断是否继续循环。
最后跳出循环时,给计数器EAX减一(以上逻辑将’\0’也计数的缘故)。
打印计数值。

关键语句含义讲解:

MOV EAX,0 ;计数
 count:            ;此过程体用于计量字符数目
    CMP BYTE PTR [EDI],0 ;将每一个字符与字符串结束符'\0'比较
	PUSHFD               ;将状态标志位入栈
	ADD EDI,1            ;增加字符串索引
	INC EAX              ;不管三七二十一,先给计数值+1
	POPFD                ;将状态标志位出栈
 LOOPNZ count            ;若此字符不等于'\0',则跳转回count继续计数
    DEC EAX              ;由于最后将字符='\0'的情况也计数了,所以需要给计数值-1
	INVOKE crt_printf,addr format,EAX  ;这里调用过程把计数值打印出来,perfecct!

2.strchr函数

程序要求
返回给定字符串中特定字符的第一个索引下标值(从一计数)。

程序变量及寄存器注解:
sztext <----> 给定的字符串基址
chr <---->特定字符
EDI <----> 存放字符串基址
AH <----> 存储数组下标,从一开始
AL <---->存放字符串中字符副本的容器。

程序实现逻辑:
在字符串中逐一进行字符匹配,第一次匹配到特定字符,立即跳出循环返回索引下标值。若是直至最后匹配到终止符,则跳转到“未发现”模块,将AH置为零以表示未找到。

关键语句含义讲解:

;1.题目要求返回位置指针,但是打印指针对于判断准确性并不直观。我选用数组下标代替
;2.由于要求在未找到时返回零,故而这里数组下标的初始值是一
	MOV AH,1 ;AH用于存储数组下标,从一开始
stringLocate:  ;字符串定位过程
    MOV AL,[EDI]  ;将字符串的字符值送入AL寄存器
	CMP AL,chr    ;把AL与待查找字符比较
	JE print      ;如果相等,找到了,跳转到打印过程
	CMP AL,0      ;AL与待查找字符不想等,则与终止符比较,是否到了字符串末尾?
	JE NotFound   ;到达字符串末尾,未找到待查找字符,跳转到“未发现”
	ADD EDI,1     ;字符串索引值+1
	INC AH        ;数组下标计数+1
	JMP stringLocate   ;继续查找
 NotFound:
    MOV AH,0    ;将数组下标值置零,表示未找到
 print:
INVOKE crt_printf,addr format,AH  ;打印

3.strcmp函数

程序要求
按照字符串比较规则,比较两个字符串大小。(大于返回1,小于返回-1,等于返回0)。

程序变量及寄存器注解:
Sztext* <----> 给定的字符串*基址
ESI <----> 存放第一个字符串基址
EDI <----> 存放第二个字符串基址
AL <---->存放第一个字符串中字符副本的容器。
AH<---->存放第二个字符串中字符副本的容器。

程序实现逻辑:
两字符串依次比较相同位置的字符大小(按ASCII值比较),如果相等则循环比较下一位。如果不等则跳出比较逻辑得出结果。
特别说明字符串终止符,由于终止符的ASCII值为0,低于任何字符,所以是适用于比较逻辑的。

关键语句含义讲解:

compare:              ;比较过程
    MOV AL,[ESI]       ;取第一个字符串对应位置的字符,送入AL
	MOV AH,[EDI]       ;取第二个字符串对应位置的字符,送入AH
    CMP AL,AH          ;比较两个字符的大小
	JL less            ;第一个字符串小于第二个字符串,跳转
	JG greater         ;第一个字符串大于第二个字符串,跳转
	CMP AL,0           ;字符串一对应位置字符等于字符串二对应位置字符,比较是否为终止符'\0'
	JE equal           ;等于终止符则两字符串相等,跳转
	ADD ESI,1          ;不等于终止符则继续比较,索引值+1
	ADD EDI,1          ;同上
	JMP compare        ;那我再比较下一个位置的字符值
 ;以下根据字符串比较规则对EAX(存放结果)的赋值
 less:
    MOV EAX,-1
	JMP print
 greater:
    MOV EAX,1
    JMP print
 equal:
    MOV EAX,0 
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 print:
	INVOKE crt_printf, addr format, EAX

4.strset函数

程序要求
用特定字符置换给定字符串的所有字符值。

程序变量及寄存器注解:
Sztext* <----> 给定的字符串*基址
chr <----> 特定字符
EDI <----> 存放字符串基址
AL <----> 存放chr
AH<---->存放字符串中字符副本的容器。

程序实现逻辑:
遍历给定字符串,使用AL中存放的chr替换该处字符并写入内存。
以终止符作为循环结束标志。

关键语句含义讲解:

   MOV AL,chr ;将特定字符值送入AL寄存器
    stringSet:     ;字符串设特定值过程
        MOV AH,[EDI] ;将字符串的一个字符送入AH寄存器
        CMP AH,0     ;将此字符与终止符'\0'比较
    	JE print     ;假如相等,则抵达字符串末尾,跳转打印
    	MOV [EDI],AL ;字符串未结束,赋值
    	ADD EDI,1    ;索引值+1
    	JMP stringSet ;继续循环此过程直至字符串结束
    	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
     print:
    	INVOKE crt_printf, addr szText

程序源代码

1.strlen过程

.386
.model flat, stdcall

include kernel32.inc
includelib kernel32.lib

include msvcrt.inc
includelib msvcrt.lib

.data
szText	db	"Reverse Engineering", 0
chr		db	'i'
format	db	"%d", 0AH, 0

.code

main PROC
	LEA EDI, szText
	MOV ECX,0FFFFFFFFH
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	;strlen逻辑
	MOV EAX,0 ;计数
 count:            ;此过程体用于计量字符数目
    CMP BYTE PTR [EDI],0 ;将每一个字符与字符串结束符'\0'比较
	PUSHFD               ;将状态标志位入栈
	ADD EDI,1            ;增加字符串索引
	INC EAX              ;不管三七二十一,先给计数值+1
	POPFD                ;将状态标志位出栈
 LOOPNZ count            ;若此字符不等于'\0',则跳转回count继续计数
    DEC EAX              ;由于最后将字符='\0'的情况也计数了,所以需要给计数值-1
	INVOKE crt_printf,addr format,EAX  ;这里调用过程把计数值打印出来,perfecct!
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	INVOKE crt_getchar
	INVOKE ExitProcess, 0
main ENDP

END main

2.strchr过程

.386
.model flat, stdcall

include kernel32.inc
includelib kernel32.lib

include msvcrt.inc
includelib msvcrt.lib

.data
szText	db	"Reverse Engineering", 0
chr		db	'i'
format	db	"%d", 0AH, 0

.code

main PROC
	LEA EDI, szText
	MOV ECX,0FFFFFFFFH
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	;strchr逻辑
	;1.题目要求返回位置指针,但是打印指针对于判断准确性并不直观。我选用数组下标代替
	;2.由于要求在未找到时返回零,故而这里数组下标的初始值是一
	MOV AH,1 ;AH用于存储数组下标,从一开始
stringLocate:  ;字符串定位过程
    MOV AL,[EDI]  ;将字符串的字符值送入AL寄存器
	CMP AL,chr    ;把AL与待查找字符比较
	JE print      ;如果相等,找到了,跳转到打印过程
	CMP AL,0      ;AL与待查找字符不想等,则与终止符比较,是否到了字符串末尾?
	JE NotFound   ;到达字符串末尾,未找到待查找字符,跳转到“未发现”
	ADD EDI,1     ;字符串索引值+1
	INC AH        ;数组下标计数+1
	JMP stringLocate   ;继续查找
 NotFound:
    MOV AH,0    ;将数组下标值置零,表示未找到
 print:
    INVOKE crt_printf,addr format,AH  ;打印
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	INVOKE crt_getchar
	INVOKE ExitProcess, 0
main ENDP

END main

3.strcmp过程

.386
.model flat, stdcall

include kernel32.inc
includelib kernel32.lib

include msvcrt.inc
includelib msvcrt.lib

.data
format		db	"%d", 0AH, 0
szText		db	"Reverse Engineering", 0
szText2		db	"Reverse Engineering", 0	;szText==szText2
szText3		db	"Reverse Eng", 0			;szText>szText3
szText4		db	"Reverse Engj", 0			;szTextszText5

.code

main PROC
	LEA ESI, szText
	LEA EDI, szText2	;result=0
	;LEA EDI, szText3	;result=1
	;LEA EDI, szText4	;result=-1
	;LEA EDI, szText5	;result=1
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	;strcmp逻辑
 compare:              ;比较过程
    MOV AL,[ESI]       ;取第一个字符串对应位置的字符,送入AL
	MOV AH,[EDI]       ;取第二个字符串对应位置的字符,送入AH
    CMP AL,AH          ;比较两个字符的大小
	JL less            ;第一个字符串小于第二个字符串,跳转
	JG greater         ;第一个字符串大于第二个字符串,跳转
	CMP AL,0           ;字符串一对应位置字符等于字符串二对应位置字符,比较是否为终止符'\0'
	JE equal           ;等于终止符则两字符串相等,跳转
	ADD ESI,1          ;不等于终止符则继续比较,索引值+1
	ADD EDI,1          ;同上
	JMP compare        ;那我再比较下一个位置的字符值
 ;以下根据字符串比较规则对EAX(存放结果)的赋值
 less:
    MOV EAX,-1
	JMP print
 greater:
    MOV EAX,1
    JMP print
 equal:
    MOV EAX,0 
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 print:
	INVOKE crt_printf, addr format, EAX

	INVOKE crt_getchar
	INVOKE ExitProcess, 0
main ENDP

END main

4.strset过程

.386
.model flat, stdcall

include kernel32.inc
includelib kernel32.lib

include msvcrt.inc
includelib msvcrt.lib

.data
szText	db	"Reverse Engineering", 0
chr		db	'j'

.code

main PROC
	LEA EDI, szText
	MOV ECX,0FFFFFFFFH
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	;strset逻辑
	MOV AL,chr ;将特定字符值送入AL寄存器
stringSet:     ;字符串设特定值过程
    MOV AH,[EDI] ;将字符串的一个字符送入AH寄存器
    CMP AH,0     ;将此字符与终止符'\0'比较
	JE print     ;假如相等,则抵达字符串末尾,跳转打印
	MOV [EDI],AL ;字符串未结束,赋值
	ADD EDI,1    ;索引值+1
	JMP stringSet ;继续循环此过程直至字符串结束
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 print:
	INVOKE crt_printf, addr szText

	INVOKE crt_getchar
	INVOKE ExitProcess, 0
main ENDP

END main

程序运行结果截图

【截图】-strlen

x86汇编语言实现简单的C函数功能_第2张图片

【截图】-strchr

x86汇编语言实现简单的C函数功能_第3张图片

【截图】-strcmp

x86汇编语言实现简单的C函数功能_第4张图片

【截图】-strset

x86汇编语言实现简单的C函数功能_第5张图片

你可能感兴趣的:(软件逆向工程,逆向工程,X86汇编,字符串函数)