⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 macro.asm

📁 宏文件,CTEXT,M2M等,自己整理比较实用.
💻 ASM
📖 第 1 页 / 共 2 页
字号:
;自由调用宏 by AoGo
;-------------------------------------
;与invoke的区别是fcall不检查参数个数和类型是否和声明一致(自由嘛),常用在调用DLL函数上
;同时它会自动处理字符串并进行声明
;会自动检查在使用eax之前是否使用addr引用局部变量,如:
;@fcall MessageBox,hWnd,eax,addr buffer,0
;会提示错误:addr overwrite eax
;@fcall eax,hWnd,eax,addr buffer,0
;会提示错误:addr overwrite Function [eax]
;但这样无错 fcall MessageBox,hWnd,addr buffer,eax,0
;@fcall MessageBox,0,"自由调用","成功",0
;@fcall MessageBox,0,addr buffer,CTXT("Hello"),0
_VAR_NUMERIC_ = 0
@fcall MACRO FunArgs:VARARG
	LOCAL txt, arg,curr,buseeax,lpquot,local_text
	txt TEXTEQU <>
	buseeax = 0
	;反转参数
	%FOR arg, <FunArgs>
	  txt CATSTR <arg>, <!,>, txt
	ENDM
	txt SUBSTR  txt, 1, @SizeStr( %txt ) - 1
	;压入所有参数
	:PushNext
		curr INSTR 1,txt,<!,>
		IF curr NE 0
			lpquot SUBSTR txt,1,1
			arg  SUBSTR txt,1,curr-1
			txt  SUBSTR txt,curr+1,@SizeStr(% txt)-curr
			IF @SizeStr(% txt) GE 1
				curr INSTR 1,arg,<!addr>
				IF curr NE 0
					arg SUBSTR arg,6,@SizeStr(% arg)-5
					buseeax=1
					lea eax,arg								;使用了eax,做一个标记,如果在这之后直接使用push eax时,显示错误
					push eax
				ELSE
					ifidn lpquot,<!">
						local_text CATSTR <!??__HA__??>,%_VAR_NUMERIC_
						_VAR_NUMERIC_ = _VAR_NUMERIC_+1
						.data
							local_text db arg,0
						.code
						push offset local_text
					elseIF buseeax EQ 1
						ifidn arg,<!eax>
							.err <addr overwrite eax>	;显示错误在使用eax之前使用了addr,中止编译
						endif
						push arg
					else
						push arg
					ENDIF
				ENDIF
				goto PushNext
			ENDIF
		ENDIF
		IF buseeax EQ 1									;如果已经修改了eax,检查函数调用是否使用了eax
			ifidn txt,<!eax>
				.err <addr overwrite Function [eax]>	;显示错误在使用eax之前使用了addr,中止编译
			endif
		ENDIF
		call txt
ENDM
;函数嵌套调用宏 by AoGo.
;==================================
;可以像c一样方便地调用函数,能自动处理字符串并定义,同时可在嵌套的同时创建并返回全局变量
;mov i,@(MessageBox,0,"做为指令参数使用","Welcome",0)
;在函数名前使用#号,可以自动创建并将函数返回值放入变量中.使用&号,表示当前这个API返回的是&后的符号地址
;&buffer展开后为lea eax,buffer,如果#与&同时存在,宏会在lea eax,*之前mov #*,eax,也就是函数的返回值总是
;保存在创建的变量中,另外,#*不能与已有的变量重名,只能创建新的,如果已经存在一个变量,请直接使用,不要加#号
;invoke MessageBox,0,@(#iStrSize=wsprintf,&buffer,CTXT("%d"),eax),0,0
;上述语句执行后,iStrSize中的值是wsprintf的返回值也就是填充后的缓冲大小,&buffer表示将addr buffer交给MessageBox
;invoke ExitProcess,@(#a=MessageBox,0,@(#hModule=GetModuleFileName,0,&buffer,sizeof buffer),"嵌套使用",0)
;需要的话,可以单独使用,在API名字前加上*号即可:
;@(*MessageBox,0,"单独使用","Welcome",0)
;宏支持至少20层嵌套.不过建议嵌套保持在5层以下.以免代码混乱.
@ Macro args:VARARG
	local lpargs,lpends,RetSize,lpAddressPos,retvar,varstr,startpos
	LOCAL arg,lpquot,local_text,InvokeAPI,paramindex,notretvalue
	InvokeAPI	TEXTEQU <invoke >
	paramindex	=0
	retvar		=0
	startpos		=0
	varstr		SUBSTR <args>,1,1
	ifidn varstr,<!*>
		notretvalue=0
		lpargs	SUBSTR <args>,2,@SizeStr(<args>)-1
		startpos=1
	else
		notretvalue=1
		startpos=0
		lpargs	TEXTEQU <args>
	endif
	lpAddressPos INSTR 1,<args>,<!,>	;找到xx=xx(,)
		retvar INSTR 1,<args>,<!=>		;找到xx(=)xx,
		if retvar ne 0
			if (retvar lt lpAddressPos) or (lpAddressPos eq 0)
				varstr SUBSTR <args>,startpos+1,1
				ifidn varstr,<!#>			;如果找到的变量前有一个#,定义它.
					varstr SUBSTR <args>,startpos+2,retvar-startpos-2
					.data?
						varstr dd ?
					.code
				else
					varstr SUBSTR <args>,startpos+1,retvar-startpos-1
				endif
				lpargs SUBSTR <args>,retvar+1,@SizeStr(<args>)-retvar
			else
				retvar =0
			endif
		endif
	startpos=startpos+retvar
	lpAddressPos INSTR 1,<args>,<!&>
	if lpAddressPos ne 0					;如果找到&符,表示需要返回这个地址
		lpargs SUBSTR <args>,startpos+1,lpAddressPos-startpos-1
		lpargs CATSTR lpargs,<addr >	;加上addr
		lpends SUBSTR <args>,lpAddressPos+1,@SizeStr(<args>)-lpAddressPos
		lpargs CATSTR lpargs,lpends
		RetSize INSTR 1,lpends,<!,>	;取这个参数
		if RetSize ne 0
			lpends SUBSTR <args>,lpAddressPos+1,RetSize-1
		else
			lpends SUBSTR <args>,lpAddressPos+1,@SizeStr(<args>)-lpAddressPos
		endif
	endif
	;-----------------------------------------------------
	;创建invoke行.
	%FOR arg, <lpargs>
		if paramindex ne 0
			InvokeAPI CATSTR InvokeAPI,<!,>
		endif
		lpquot SUBSTR <arg>,1,1
		ifidn lpquot,<!">
			local_text CATSTR <!_??xx??>,%_VAR_NUMERIC_
			_VAR_NUMERIC_ = _VAR_NUMERIC_+1
			.data
				local_text db arg,0
			.code
			InvokeAPI CATSTR InvokeAPI,<offset local_text>
		else
			InvokeAPI CATSTR InvokeAPI,<arg>
		ENDIF
		paramindex=paramindex+1
	ENDM
	InvokeAPI
	;-----------------------------------------------------
	if retvar ne 0
		mov varstr,eax
	endif
	if lpAddressPos ne 0
		lea eax,lpends						;入栈
	endif
	if notretvalue ne 0
		EXITM <eax>
	endif
ENDM

;创建一个数组,并返回它的全部索引,并自动创建数组常数.
;例子:ARRAY szNAME,8,"李明|成吉思汗|中国|你好"
;然后用以下名字访问字符串指针(IndexOfszName是自动生成的常数,值为当前字符串中各个数组的的偏移
;	szNAME[IndexOfszNAME*0]
;  szNAME[IndexOfszNAME*1]
;  szNAME[IndexOfszNAME*2]
;  szNAME[IndexOfszNAME*3]
ARRAY macro _name,_size,_string:VARARG
local i1,i2,quot,_str,_arr,var
   quot SUBSTR <_string>,1,1;开头的是单引号还是双引号
   _str SUBSTR <_string>,2,@SizeStr(<_string>)-2;去掉引号
   .data
      _var db 0
   i1=1
:next
   if i1 LE @SizeStr(%_str)
      i2 INSTR i1,_str,<|>
      if i2
         _arr SUBSTR _str,i1,i2-i1
         len SIZESTR _arr
         _arr CATSTR quot,_arr,quot
         db _arr,(_size-len+1) dup(0)
         i1=i2+1
         goto next
      else;最后一个词
         _arr SUBSTR _str,i1
         len SIZESTR _arr
         _arr CATSTR quot,_arr,quot
         db _arr,(_size-len+1) dup(0)
         db 0         
      endif
   endif
   .code
   _name equ DWORD ptr offset _var+1
   Indexof&_name equ (_size+1);创建一个Index常量
   IndexOf&_name equ (_size+1);
   endm
;高级字符串定义宏,支持转义符,能处理\\ \n \t \0
;例子invoke MessageBox,hWnd,CTEXT("欢迎使用MASMPlus\n\n\t字符串定义由CTEXT宏\n\n作者:鬼龙之舞"),0,0
;感谢[鬼龙之舞]费心编写.有意见请联系鬼兄
;Mail:	k_badboy@sohu.com 
;主页:	http://kbadboy.yeah.net
CTEXT macro text:VARARG
   local result,var
	local quot,text_noquot,i,j
	local find,replace
	local _char,comma
	
	inplacing=0	;控制是在转换还是正常添加

   quot SUBSTR <text> ,1,1 ;第一个字符是单引号还是双引号

	text_noquot SUBSTR <text>,2,@SizeStr(<text>)-2;a为去掉左右的引号后的内容
	ife @InStr(1,<text>,<\>)
		.data
			var db text,0
		.code
			exitm<offset var>
	endif
	result textequ <>
	comma textequ <!,>
	i=1
:nextchar
	_char SUBSTR text_noquot,i,1
	ifidn _char,<\>
		find SUBSTR text_noquot,i+1,1
		ifidn find,<n>;\n转换为13,10
			replace textequ <13!,10>
			i=i+1
		elseifidn find,<t>;\t转换为9
			replace textequ <09>
			i=i+1
		elseifidn find,<0>;\0
			replace textequ <00>
			i=i+1
		elseifidn find,<\>;\\为不转换
			replace textequ quot
			if @SizeStr(%text_noquot)-2 ;\\在最后,直接添加\
				replace CATSTR replace,<\>,quot
				i=i+1
			else;\\不是在最后,添加\和它后面的那个字符
				find SUBSTR text_noquot,i+2,1
				replace CATSTR replace,<\>,find,quot
				i=i+2
			endif
		else
			replace textequ quot,_char,quot
		endif
		if inplacing
			result CATSTR result,comma
		endif
		result CATSTR result,replace
		inplacing=1
	else
		if inplacing
			result CATSTR result,comma
			inplacing=0
		endif
		result CATSTR result,quot,_char,quot,comma
	endif
	if i NE @SizeStr(%text_noquot)
		i=i+1
		goto nextchar
	endif
	comma SUBSTR result,@SizeStr(%result),1
	ifidn comma,<!,>
		result SUBSTR result,1,@SizeStr(%result)-1
	endif
	
   .data
			var db 0
			j=1
			:nextp
			if j+2 LT @SizeStr(%result)
				i INSTR j+2,result,<!,>
				if i
					find SUBSTR result,j,i-j					
					db find					
					j=i+1
					goto nextp
				endif
			endif
			find SUBSTR result,j
			db find
			db 0		
	.code
   exitm<offset var+1>
endm

;智能宏的所谓智能就是:如果我们定义一个变量的首字母是g(global),就把它定义为全局标签
;在MASM中,以一个冒号结束的标签是局部标签(如果这个标签位于过程内)
;以2个冒号结束的标签是全局标签
;这个宏除了方便外,还有2个好处
;(1)反反汇编
;在ctext宏中,字符串是被添加到data节中,而在szText中,字符串直接定义在当前位置
;在一定的程度上,给反汇编带来一定的影响(w32asm也无法正常反汇编)
;(2)使用更方便
;由于我们使用的是标签,所以要访问字符串除了用常规的offset,addr外,
;还可以直接用变量名
;例子:szText gtext,"全局变量"		任何地方都可以引用
;例子:szText sztext,"局部变量"   只能在当前过程中引用
szText macro name,text:VARARG 
	local l
	jmp l
	ifidn @SubStr(name,1,1),<g>
		name::		;两个冒号是全局标签
		db text,0
	else
		name:
		db text,0
	endif
	l:
	endm

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -