现在的位置: 首页 > 综合 > 正文

利用FS寄存器得到任意函数地址

2013年10月31日 ⁄ 综合 ⁄ 共 2441字 ⁄ 字号 评论关闭
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;		程序函数说明:利用fs寄存器,得到任意的函数地址
;               by:瀚 海    2011年11月19日
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;很早之前就知道利用fs可以导出kernel32!LoadLibrary、Kernel32!GetProcAddress函数
;也就可以得到任意dll的任意函数,一直不清楚到底哪个数据偏移多少位置。最近开始弄安全
;所以顺便弄下shellcode
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
		.386
		.model	flat,stdcall
		option casemap:none
include		windows.inc

		.data
DllName		db		'ExitProcess',0

		.data?
Count		dd			?

assume	fs:nothing		;打开FS寄存器,否则用到FS寄存器的编译都不会通过
		.code

;得到字符串长度
;相同返回0,不同返回1,便于后面可以使用C语言库的strcmp函数
strcmp		proc uses edi esi ebx ecx  source:dword,dst:dword
		xor		eax,eax
		;判断来源是不是有NLL地址,如果有,直接当成不等字符串
		mov		esi,source
		test	esi,esi
		je		NotEQual
		mov		edi,dst
		test	edi,edi
		je		NotEQual
		;判断两字符是否有为'\0'结尾的字符串,有一个不为'\0'则将继续比较
		;直到遇到不等字符或两个都为'\0'字符
	cmpNext:
		mov		bl,byte ptr[esi]
		test	bl,bl
		jnz		TestNextZ
		cmp		byte ptr[edi],0
		je		szEqual ;两字符串都以'\0'结尾,那么他们是相同字符串
	TestNextZ:
		mov		cl,byte ptr[edi]
		inc		edi
		inc		esi
		cmp		bl,cl
		jnz		NotEQual
		jmp		cmpNext
	NotEQual:
		inc		eax
	szEqual:
		ret
strcmp		endp

;得到字符串长度函数
;这个函数在其他地方copy的
strlen	proc	uses ecx edi szString:dword
		mov		edi,szString
		xor		ecx,ecx
		dec		ecx
		xor		al,al
		repne	scasb
		not		ecx
		dec		ecx
		xchg	eax,ecx
		ret
strlen	endp

;得到任意函数地址
;如果函数不在Kernel32.dll中可以利用LoadLibrary、GetProcAddress加载其他函数
GetProcessAddress	proc	uses edx esi ecx ebx dllName:DWORD
		mov		eax,dword ptr fs:[30H] ;得到TEB结构
		mov		eax,dword ptr [eax+0CH] ;得到PEB_LDR_DATA结构
		mov		esi,dword ptr [eax+1CH] ;InInitializationOrderModuleList
		;得到Kernel32.dll所在LDR_MODEL结构的InInitializationOrderModuleList地址
		lodsd	
		mov		edx,dword ptr[eax+8H]	;得到BaseAddress,即kernel32基址
		push	edx
		mov		ecx,dword ptr[edx+3CH] ;edx指向kernel32的内存映像基址,得到PE头指针
		lea		ecx,dword ptr[edx+ecx] ;ecx,指向PE头
		mov		ecx,dword ptr[ecx+78H] ;指向导出表
		lea		ecx,dword ptr[edx+ecx] ;ecx指向导出表
		mov		ebx,dword ptr[ecx+1CH]
		lea		ebx,dword ptr[edx+ebx] ;ebx指向函数地址列表
		push	ebx	;先保存函数地址列表首地址
		mov		ebx,dword ptr[ecx+0CH]		;网上有说这个地址是偏移0x20的,不清楚是不是系统版本问题
		lea		ebx,dword ptr[edx+ebx] ;ebx指向函数名称列表,第一个是kernel32.dll
;		push	ebx		;有必要的话,可以保存下
	@@:
		inc		Count		;函数序号+1
		mov		eax,Count
		cmp		eax,3BBH	;XP中只有954个函数,超过的就错误了
		jge		@F
		invoke	strlen,ebx
		;ebx指向下一个字符串首地址,第一次指向"kernel32.dll"字符串
		lea		ebx,dword ptr[eax+ebx+1]
		invoke	strcmp,dllName,ebx	;比较字符串,相同返回0
		cmp		eax,0
		jnz		@B
		dec		Count			;得到函数的序号,也可以当成是函数表中的第几个函数
		mov		eax,Count
		shl		eax,2			;每个地址32位,所以要乘以4
		pop		ebx				;弹出函数地址列表首地址
		mov		ebx,dword ptr[ebx+eax]		;得到函数的偏移地址
		pop		edx				;弹出kernel32首地址
		lea		eax,dword ptr[edx+ebx]		;得到函数地址
	@@:
		ret
GetProcessAddress	endp

start:
		xor		eax,eax
		mov		Count,eax
		;调用查找函数地址函数,返回eax中是函数地址,如果函数不存在返回小于0xFFFFF的值
		invoke	GetProcessAddress,offset DllName
		.if	 eax > 0FFFFFH
			push	NULL
			call	eax	;调用ExitProcess函数
		.endif
		;如果没有这个函数,那么手动处理错误
end	start

抱歉!评论已关闭.