📄 汇编版正则表达式.txt
字号:
.DATA
lpszString db 'link.exe /SUBSYSTEM:WINDOWS /nologo /OUT:"Main.exe" "Main.obj" "Main.RES"'
lpEnd db 0
.DATA?
hInstance dd ?
lpRet POINT 20 dup() ;最多20个
iCount dd ?
buffer db MAX_PATH*2 dup(?)
.CODE
GetRetString proc uses edx,lpPOINT,lpRetString,iSize
mov edx,lpPOINT
mov eax,[edx].POINT.y
sub eax,[edx].POINT.x
.if eax>iSize
mov eax,iSize
.endif
push eax
invoke RtlMoveMemory,lpRetString,[edx].POINT.x,eax
pop eax
mov edx,lpRetString
mov BYTE ptr [edx+eax],0
ret
GetRetString endp
START:
invoke GetModuleHandle,NULL
mov hInstance,eax
.data
lp2 db '/{OUT}:{(\")+>}',0 ;将返回"Main.exe"包含引号
lp3 db '/{OUT}:(\")+<{?+[\"]}\">',0 ;将返回 main.exe 无引号
lp4 db '/{OUT}(:(\")+<{?+[\"]}\">)*',0
;与lp3相同,但是如果/OUT之后没有值,也返回成功
;接着,我们进行不定个数的查找测试,查找所有单独使用引号包含的字符串.
;目标必须是类似组合的字串,并且相连续, "Main.obj" "Main.RES ,分开后就是:
; "Main.obj"
; "Main.RES"
;分析得到表达式如下:
lp5 db '( +{\"?+<\">})+',0
.code
;在每次使用ExpressSearch前都要赋值.因为ExpressSearch会修改它
mov iCount,20
invoke ExpressSearch,0, ;使用默认的字符表
offset lpszString, ;目标地址
offset lpEnd, ;结束地址
offset lp5, ;查找/OUT:"Main.exe",并分离出参数与值
offset lpRet, ;返回结果地址
offset iCount, ;个数
EF_USEEXPRESS ;使用表达式,区分大小写
.if SDWORD ptr eax>0
;lpRet.x与lpRet.y,分别是整个匹配字符串的开始地址与结束地址.
;这个是不会变的。
;如果表达式中没有符号{}引用,则iCount永远为1
;这里有两个{},分别引出参数与值,一共是3个。
.if iCount==3
invoke GetRetString,addr lpRet[sizeof POINT],
addr buffer,sizeof buffer-1
invoke MessageBox,0,addr buffer,CTXT("参数"),0 ;显示 OUT
invoke GetRetString,addr lpRet[sizeof POINT*2],
addr buffer,sizeof buffer-1
invoke MessageBox,0,addr buffer,CTXT("值"),0
;显示 "Main.exe" 或 Main.exe
.elseif iCount==2 ;在使用lp4时才会有这个判断分支.
invoke GetRetString,addr lpRet,addr buffer,sizeof buffer-1
invoke MessageBox,0,addr buffer,CTXT("无值"),0
;显示整个匹配
;/OUT之后无参数
.endif
.else
; ;错误处理
; .if eax==-1
;
; .elseif eax==-2
; ... ...
; .endif
.endif
invoke ExitProcess,0
END START
代码中都有说明,使用其实是很简单的,这个表达式库最强的地方,在于可以选择性地获得结果,并一次性得到别的表达式需要多次查找才能得到的效果。是专门为程序员使用而定制的,使用这个表达式库,最重要的在于了解它的运作原理,使用起来才会得心应手。
我们就表达式来进行分析:
源字符串:
link.exe /SUBSYSTEM:WINDOWS /nologo /OUT:"Main.exe" "Main.obj" "Main.RES"
使用lp2 db '/{OUT}:{(\")+>}',0 时,拆分来分析:
/
{
OUT
}
:
{
(\")+<
?+<
\"
>
>
}
找到字符/,然后匹配OUT,如果有,返回位置(使用了符号{}),接着,后面必须是:号,然后返回两个”号之间的位置,?+<\”>,表示,任意字符直到碰到”号,合起来,就是/OUT:”*”,引号之间的可以是任意字符。
lp3 db '/{OUT}:(\")+<{?+[\"]}\">',0
这个与lp2的区别在于,返回的值不包含引号, {?+[\"]}\",?+[\”]表示任意字符直到碰到”号,但不把”号放入这次查找范围之内,也就是指针移动到了”号之前,这样后面需要再次用\”来匹配。如果已经是表达式的最后,可以不填。
lp4 db '/{OUT}(:(\")+<{?+[\"]}\">)*',0
这个表达式后面的部分用()*来包含,也就是表示,包含的这整个表达式都可以不要。这样,当只有前面的/OUT匹配时,仍然会返回成功,但返回的位置只有前面的。
lp5 db '( +{\"?+<\">})+',0
这个表达式查找并返回所有引号包含的字符串,但必须是空格开头,这样/OUT:”Main.exe”这一项就不会查找到。\"?+<\">就是返回引号之间的所有字符,()+表示,循 环地用这个表达式匹配成功之后的字符串,直到失败。这种时候,返回的位置{}个数是不确定的。这里使用了()+,也就是表示,至少要有1个,如果是使用()*,则一个都没有,都会返回成功。这就看使用者如果取舍了。
上述的例子一次性得到/SUBSYSTEM:WINDOWS与/OUT:”Main.exe”,看看吧:
(?+>)}>)+
要注意,这个表达式查找后,iCount是大于3的喔。修改显示的代码为:
.if iCount>1
Xor ebx,ebx
@@:
invoke GetRetString,addr lpRet[ebx*sizeof POINT],addr buffer,sizeof buffer-1
invoke MessageBox,0,addr buffer,CTXT("显示"),0
inc ebx
cmp ebx,iCount
jl @B
.endif
这样可以依次显示所有抓到的字串。看很简单吧。
如果要确定一个字串中是否包含某个字串,如在 Welcome中查找com,直接查找com即可,表达式搜索函数,是先从最开始进行搜索,一个一个向后来匹配,直到完成或失败,才结束的。
如果是确定不包含com呢?使用!(com)吧,如果包含这个,则表达式失败。
详细的,请大家多做一下测试吧,总之,这个表达式库,是专门为程序员使用而写的,强调查找与处理的方便性,而不在于功能如何复杂,所以,能够用在程序开发中的地方是非常之多的,别的表达式库,使用者总会认为太复杂,如果用得少还不如自己开发专用的函数来完成,事实上,我的这个库已经够复杂的了T_T,多分析与组合表达式,是可以实现极为快速的查找的,尤其是需要处理某些特殊的查找时,很多时候,使用这个函数和好的表达式,一次性就可以得到需要的所有字符与结果。当然必须以目标查找字串的格式而定制表达式。同一个表达式,在不同的字串查找中是不同的。
因为表达式的复杂性,是没办法详细举例的,大家可以利用上述的例子,详细地进行测试,在下载的表达式库中,还包含一个测试程序,是专门用来测试表达式是否正确的,根据返回的错误,可以慢慢地熟悉,有任何的问题,你可以在我们的论坛提出。
--------------------------------------------------------------------------------
欢迎访问AoGo汇编小站:http://www.aogosoft.com/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -