首页
论坛
专栏
课程

[原创]ShellCode编写之hash式函数调用及相关

2008-1-16 11:31 6968

[原创]ShellCode编写之hash式函数调用及相关

HSQ
8
2008-1-16 11:31
6968
前段时间的Exploit Me挑战赛,使我深刻的感到ShellCode编写完全不同与病毒,对于栈空间得按字节来省着用,ShellCode中hash式函数调用势在必行。另外,在unicode环境下的shell处理,也得过关才行。参照《The Shellcoder's Handbook》 中关于“百叶窗”法,及相关网文资料,自己也写了拆分ShellCode字符串模块,在此一并放出
   CreateWinAPINameHash功能是获取指定模块中函数名称串的HASH值,并返回Hash的Key值,要计算实际中函数名称串的HASH值只需要调用次过程就可以;ShellCodeToStdByteChar功能是对于已经写好的ShellCode,将其中的非纯数字和字母字节进行拆分,使之转换为字母字节。另外,GetBaseAddressOfKernel32ByTEB与GetKernel32BaseAddressBySearch是两种不同方法获取Kernel32.dll 的基址的子过程,以及GetStringSize用于获取字符串大小的子程序,是顺便送给大家公用子程序,省的自己写
.586
.model  flat, stdcall
option  casemap:none

include windows.inc
include kernel32.inc
include user32.inc                                                  
includelib kernel32.lib
includelib user32.lib

		.const
szLoadLibraryA		db	'LoadLibraryA',0
szGetProcAddressA	db	'GetProcAddressA',0
szGetProcAddresAs	db	'GetProcAddresAs',0
szFileName		db	".\ShellCode.log",0
szkernel32Dll		db	"kernel32.Dll",0

		.data
ppKernel32Win32ApiName	dd	szLoadLibraryA,szGetProcAddressA,szGetProcAddresAs	

		.data?
pKernel32Win32ApiHash	dd	lengthof ppKernel32Win32ApiName dup  (?)

		.code
start:
	call	GetBaseAddressOfKernel32ByTEB

	push	-1
	push	-1
	push	lengthof ppKernel32Win32ApiName
	push	offset pKernel32Win32ApiHash
	push	offset ppKernel32Win32ApiName
	push	eax
	call	CreateWinAPINameHash
	xor	eax, eax
	ret
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
;如何编写Unicode形式的ShellCode及过WideCharToMultiByte
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;--------------------------------------CreateWinAPINameHash---------------------------------------------
;函数功能:  获取指定模块中函数名称串的HASH值,并返回Hash的Key值
;入口参数:  hModule		:  被Hash函数所在模块的句柄或基址
;	     lppWinApiName	:  函数名称串地址表首地址
;	     lpHashCode		:  接收函数名称串被Hash后的缓冲区地址
;	     dwNumberString	:  函数名称串的个数
;            dwHashKey          :  可以预设Hash的Key值的范围的上限(-1则为系统寻找合适KEY值)[0--31]
;            dwFilterFlags      :  设置Hash值过滤标志:
;                                  0--不含零字节;1--不含连续的零字节;-1--不过滤
;出口参数:  成功则EAX返回正确Hash的Key值,否则为返回值小于零.           
;-------------------------------------------------------------------------------------------------------
CreateWinAPINameHash	proc	hModule:dword,lppWinApiName:dword,lpHashCode:dword,\
                                dwNumberString:dword,dwHashKey:dword,dwFilterFlags:dword
local	ret_value:dword	
	pushad
	mov	ebx, hModule
	mov	eax, ebx
;********************************************************************
; 从 PE 文件头的数据目录获取导出表地址
;********************************************************************	
	add	eax, dword ptr [ebx + IMAGE_DOS_HEADER.e_lfanew]
	assume	eax : ptr IMAGE_NT_HEADERS
	mov	eax, [eax].OptionalHeader.DataDirectory.VirtualAddress
	add	eax, ebx
	assume	eax : ptr IMAGE_EXPORT_DIRECTORY
;********************************************************************
; 计算函数名的hash值
;********************************************************************
	mov	ecx, dword ptr [eax].NumberOfNames	;检查是否搜索完毕
	mov	eax, dword ptr [eax].AddressOfNames	;取出函数名字符串地址表指针(RVA)
	add	eax, ebx				;eax真实指向函数名字符串地址表首地址
	push	ecx
	push	eax
	shl	ecx, 2
	push	ecx
	push	LMEM_ZEROINIT
	call	LocalAlloc				;申请临时内存
	pop	esi
	pop	ecx
	test	eax, eax
	je	exit_CreateWinAPINameHash
	mov	edx, eax				;检测执行结果
	
	mov	eax, dwHashKey
	mov	edi, -1
	cmp	eax, edi
	jne	@f
	mov	al, 32
@@:
	push	eax
	jmp	@f
next_CreateWinAPINameHash:
	push	edi
@@:
	push	ecx
	push	edx
	push	esi
	push	ebx
@@:
	call	HashWinAPIString
	cmp	eax, 0
	jl	@f
	cmp	eax, edi
	je	@f
	xchg	eax, edi
	cmp	edi, eax
	jl	next_CreateWinAPINameHash
	push	edi
	push	dwNumberString
	push	lpHashCode
	push	lppWinApiName
	push	dwFilterFlags
	jmp	@b
@@:
	push	eax
	push	edx
	call	LocalFree			;释放临时内存
	pop	eax
exit_CreateWinAPINameHash:
	mov	ret_value, eax
	popad
	mov	eax, ret_value
	ret
CreateWinAPINameHash	endp
;--------------------------------------HashWinAPIString-------------------------------------------------
;函数功能:  将函数名称串进行HASH计算
;入口参数:  lpBaseIED		:  被Hash函数所在模块的IMAGE_EXPORT_DIRECTORY指针
;	     lpStringTable	:  函数名称串地址表首地址
;	     lpHashCode		:  接收函数名称串被Hash后的缓冲区地址
;	     dwNumberString	:  函数名称串的个数
;            dwHashKey          :  可以预设Hash的Key值(-1则为系统寻找合适KEY值)[0--31]
;出口参数:  成功则EAX返回正确Hash的Key值,否则为-1.             
;-------------------------------------------------------------------------------------------------------
HashWinAPIString	proc	lpBaseIED:dword,lpStringTable:DWORD,lpHashCode:dword,\
                                dwNumberString:dword,dwHashKey:dword
local	hash_key:byte,string_table_base:dword
	pushad
	mov	eax, dwHashKey
	inc	eax
	test	eax, eax
	jne	@f
	mov	al, 32
@@:
	dec	eax
	mov	hash_key, al
	mov	ebx, lpBaseIED
hash_key_HashWinAPIString:
	mov	edi, lpHashCode
	mov	ecx, dwNumberString
	push	ebx
	push	ecx
	push	edi					; call CheckSameDwordByte
	dec	ebx
	je	@f
	inc	ebx
	jge	@f
	inc	ebx
@@:
	push	lpStringTable
	pop	string_table_base 
hash_next_HashWinAPIString:
	push	ecx
	xor	eax, eax
	cdq
	mov	esi, string_table_base
	mov	esi, dword ptr [esi]			;取出函数名字符串地址表第一个单元内容(函数名字符串RVA)
	add	esi, ebx				;esi真实指向函数名字符串
;----------------------hash--------------------------
@@:
	lodsb
	mov	cl, hash_key
	ror	edx, cl
	add	edx, eax
	test	al, al
	jne	@b
;----------------------------------------------------
	mov	eax, edx
	stosd
	add	string_table_base, 4
	pop	ecx
	loop	hash_next_HashWinAPIString

	call	CheckSameDwordByte
	test	eax, eax
	je	@f
	dec	hash_key
	jge	hash_key_HashWinAPIString
@@:
	popad
	movzx	eax, hash_key
	ret
HashWinAPIString	endp
;--------------------------------------CheckSameDwordByte-----------------------------------------------
;函数功能:  检验HASH值的合法性
;入口参数:  lpBuffer		:  需要检验的数据缓冲区首地址
;	     dwLengthOfType	:  被检数据的长度(以字位单位计算DWORD)
;	     dwFlags		:  设定检验标志: 0,则检验是否非法ASCII码0;
;                                                1,则检验是否非法Unicode码0;
;                                                -1,则不检验是否非法;
;                                                否则检验是否含重复字.
;出口参数:  成功则EAX返回0, 否则为EAX≠0              
;-------------------------------------------------------------------------------------------------------
CheckSameDwordByte	proc	lpBuffer:dword, dwLengthOfType:dword, dwFlags:dword
	push	ecx
	push	edi
	push	esi
	mov	esi, lpBuffer
	mov	ecx, dwLengthOfType
	cld
	xor	eax, eax
	push	eax
	dec	eax
	cmp	dwFlags, eax
	pop	eax
	je	ret_CheckSameDwordByte
	mov	edi, esi
	cmp	dwFlags, eax
	je	ASCII_CheckSameDwordByte
	cmp	dwFlags, 1
	je	Unicode_CheckSameDwordByte
	dec	ecx
@@:
	push	ecx
	lodsd
	mov	edi, esi
	repne	scasd
	test	ecx, ecx
	jne	@f
	pop	ecx
	loop	@b
	push	ecx
@@:
	pop	ecx
	jmp	exit_CheckSameDwordByte
ASCII_CheckSameDwordByte:
	shl	ecx, 2
	repne	scasb
	jmp	exit_CheckSameDwordByte
Unicode_CheckSameDwordByte:
	lodsd
	ror	eax, 8
	test	ax, ax
	je	exit_CheckSameDwordByte
	loop	Unicode_CheckSameDwordByte
exit_CheckSameDwordByte:
	mov	eax, ecx
ret_CheckSameDwordByte:
	pop	esi
	pop	edi
	pop	ecx
	ret
CheckSameDwordByte	endp
;----------------------------------ShellCodeToStdByteChar------------------------------
;函数功能:  拆分ShellCode字符串,使之转换为纯数字和字母字符
;入口参数:  lpStdByteCharStr	:  需要处理的ShellCode字符串地址
;	     lpShellCodeCharStr :  转换后的接收缓冲区
;出口参数:  EAX返回转换后的字符串长度(BYTE)                  
;--------------------------------------------------------------------------------------
ShellCodeToStdByteChar	proc	lpStdByteCharStr:dword,lpShellCodeCharStr:dword
	push	ebx
	push	ecx
	push	esi
	push	edi

	mov	esi, lpStdByteCharStr
	mov	edi, lpShellCodeCharStr
	push	edi
	xor	eax, eax
	mov	ecx, eax
	dec	ecx
	cld
	repnz	scasb
	not	ecx
	dec	ecx				; 获取待处理串长度

	mov	ebx, esp
	cld
next_ShellCodeToStdByteChar:
	lodsb
	cmp	al, 30h
	jl	must_ShellCodeToStdByteChar
	cmp	al, 7ah
	jg	must_ShellCodeToStdByteChar
	cmp	al, 61h
	jge	@f
	cmp	al, 5ah
	jg	must_ShellCodeToStdByteChar
	cmp	al, 41h
	jge	@f
	cmp	al, 3ah
	jge	must_ShellCodeToStdByteChar
@@:
	stosb					; 对数字,字母不需要拆分
	jmp	continue_ShellCodeToStdByteChar
must_ShellCodeToStdByteChar:
	push	eax
@@:
	and	al, 1111b			; 拆分: 将一个字节的高低四位分别扩展到
	add	al, 41h				; 两个字节中,加41h后存储
	stosb
	pop	eax
	shr	al, 4
	cmp	ebx, esp
	je	@b
	push	eax
continue_ShellCodeToStdByteChar:
	loop	next_ShellCodeToStdByteChar
	xor	eax, eax
	lodsb					; 添加串结束符
	pop	eax
	xchg	eax, edi
	sub	eax, edi			; 统计转换后串长度

	pop	edi
	pop	esi
	pop	ecx
	pop	ebx
	ret
ShellCodeToStdByteChar	endp
;--------------------------------GetBaseAddressOfKernel32ByTEB-----------------------------------
;函数功能:  根据TEB结构定位Kernel32.dll 的基址
;入口参数:  无
;出口参数:  成功则返回Kernel32.dll 的基址在EAX中             
;------------------------------------------------------------------------------------------------
GetBaseAddressOfKernel32ByTEB	proc
	assume	fs:nothing
	xor	eax, eax
	mov	eax, dword ptr fs:[eax+30h]
	mov	eax, dword ptr [eax+0ch]
	mov	eax, dword ptr [eax+1ch]
	mov	eax, dword ptr [eax]
	mov	eax, dword ptr [eax+8]
	ret
GetBaseAddressOfKernel32ByTEB	endp
;-----------------------------------GetKernel32BaseAddressBySearch--------------------------------------
;函数功能:  在内存中扫描 Kernel32.dll 的基址
;入口参数:  lpKernel32SpaceOfAny	:  Kernel32.dll领空内的任一地址
;出口参数:  成功则返回Kernel32.dll 的基址在EAX中,否则为EAX=0                  
;-------------------------------------------------------------------------------------------------------
GetKernel32BaseAddressBySearch	  proc	lpKernel32SpaceOfAny : DWORD		
	mov	eax,lpKernel32SpaceOfAny			
	xor	edx,edx
@@:
	dec	eax					     ;暴力查找 Kernel32.dll 的基地址
	mov	dx,word ptr [eax+IMAGE_DOS_HEADER.e_lfanew]
	test	dx,0f000h
	jnz	@b
	cmp	eax,[eax+edx+IMAGE_NT_HEADERS.OptionalHeader.ImageBase]
	jnz	@b
	ret	4	
GetKernel32BaseAddressBySearch	 endp
;--------------------------------------------GetStringSize---------------------------------------------
;函数功能:  用于获取字符串大小的子程序
;入口参数:  lpOutTexts		:  需要检测字符串的地址	
;出口参数:  eax字符串大小
;------------------------------------------------------------------------------------------------------
GetStringSize	proc	lpStringBuffer:dword
	push	ecx
	push	edi
	mov	edi, lpStringBuffer
	xor	eax, eax
	mov	ecx, eax
	dec	ecx
	cld
	repnz	scasb
	not	ecx
	mov	eax, ecx
	dec	eax
	pop	edi
	pop	ecx
	ret
GetStringSize	endp
end	start


        以上个功能模块的使用注释中写的很明白,如同MSDN,在此就不重复说明了。

[公告]安全测试和项目外包请将项目需求发到看雪企服平台:https://qifu.kanxue.com

上传的附件:
最新回复 (19)
kanxue 8 2008-1-16 11:55
2
0
很年青,如果真喜欢计算机,转行来得及的。
论坛上也有碰到2位是学医的,后来改行搞这块了。
笨笨雄 14 2008-1-16 13:00
3
0
当我走出迷宫才发现,外面是更大的迷宫
cxhcxh 3 2008-1-16 13:09
4
0
楼主和我一样的专业啊
现在才大四
不过没楼主的功力深厚
combojiang 26 2008-1-16 13:22
5
0
哈哈,不错,我曾经遇到一位搞编程的,是医学毕业的,还遇到一位是养蚕专业的,他们都是抛弃了自己专业来搞软件的,都是不错的程序员。
安摧 2 2008-1-16 13:38
6
0
支持楼主!!!
it虫子 2008-1-16 14:17
7
0
和楼主一样,我也是和你一般年纪的人,看到你的经历让我对IT更有信心
sudami 25 2008-1-16 15:45
8
0
学习~

shellcode 啊~
zhtjia 2008-1-16 16:12
9
0
向楼主学习,弃电从IT
呵呵,我是学电的,无聊的要死
sbright 2 2008-1-16 16:23
10
0
可以考虑刘涛涛的脱产班,兼顾兴趣与工作
bithaha 5 2008-1-16 17:48
11
0
学医的适合学习计算机 比较有耐心和细心
爱爆就是,好像在安全焦点也有位大侠是学医的
我都想去先学医再改学计算机了.
netwind 13 2008-1-16 17:57
12
0
其实人一辈子都在学各种东西 ,都在想办法搞到更多money
bithaha 5 2008-1-16 18:55
13
0
你的话总是充满哲理
火影 11 2008-1-16 23:35
14
0
跟我和我的同学的遭遇一样 ,我那位同学在实习时彻底改行,不过考试都是抄我的,基本没挂科,而我至今还在犹豫是不是应该把爱好当作工作来做 ,其实医学也是很有趣的东西,尤其是在临床实际中,可现在医患关系实在让我感到头疼,每天都快说破嘴皮子了,腿都走直了,感觉我对我亲爹亲妈都没那样亲过 ,都改行吧
atylon 2008-1-17 08:43
15
0
谢谢分享! 佩服楼主的毅力
founder 2008-3-4 12:55
16
0
你是学医的想证明什么?
我啥都不是,高中毕业文化,还是一个二流子,数学0分.至今不懂矩阵和啥微积分.大脑不好使,8086的指令到现在仍需要查字典,英文的MSDN看得很烦.不知道国外的知名技术nb网站.
但是我一样凭三脚猫的asm和c++混在了高手林立的北京.不是白领也绝对面子上看起来比海龙卖光盘或者拉货车的好一些.
付出的肯定得比别人多,但是你要靠这个吃饭,就没必要说自己多么多么苦,那是必然的.

如果我作黑社会混混应该比现在的职业有前途.我说真的.过了这个夏天,我想我应该离开这个事4功半的行业,从2001年跟别人笨手笨脚的学汇编的时候就有人打击我的自信心,一个简单的FAT32的分区程式,别人手把手的陪我SoftICE调试到深夜,自己还是一头雾水,最后扔下一句"你不适合作编程的...",想想也是.凭着3寸不烂之舌终于在电科院骗了一个月薪8000的工作,那可是2002年啊,可惜自己当时连他妈的c++的::符号都不知道是啥,狗屁简单的一个事情大下雪的冬夜打车从清河到麦子店去求人解释.....如今::倒是懂了,但是发觉自己下半辈子的时间用来学习无穷至的计算机技术,实在不值得.今天你弄一个0Day,明天他干掉一个猛壳,后天她写了个赚钱的外挂(嗯,外挂病毒木马也算是软件的黑社会吧),可是自己呢?你永远跟不上别人的彪悍.....

挣钱有无数的办法,搞计算机这块实在不怎么风光,连个销售都不如,在KTV耍妞的时候人家鄙视你.看看有钱的老板,不是爹是官就是自己没文化但是面子好,比我还大老粗,但是人家走财运,狗屎运,就是有钱,就是活的滋润,活的有思想.

有时候 想起来真恨那个5寸软盘上的酒井法子.

所以,下辈子还是作个帅哥或者美女,有个当官的老爹,然后再有一点点悲天悯人的贵族气质,我就满足了.

BTW:前面有个哥们说的好,走出了现在的迷宫,才发现了外面有更大的迷宫.....有些东西玩玩还是可以的.千万不要给自己上套,说什么为之奋斗终身啊等等的豪言壮语.人在死亡和饥饿面前都是微不足道的.
刘烨的电视剧里面有句话很好,"我只想要体面的生活."
华罗庚和陈景润如果在法国,一定比现在的成就更大.

生活无忧,进入小康的朋友可以漂过,你非要把时间奉献给二进制,我除了对你的羡慕之外没别的敬仰.
简单爱 2008-3-5 14:12
17
0
“生活无忧,进入小康的朋友可以漂过,你非要把时间奉献给二进制,我除了对你的羡慕之外没别的敬仰.”
完了,我计算机专业的,还指望二进制过度到小康呢......
cntom 2008-3-11 22:08
18
0
记忆力也可以学习而得来,书店里讲解增强记忆力这方面的东西多着呢,学学吧,虽然熟能生巧,但很多东西也可以轻松记下来嘛!也可起到相辅相成的作用!
NWMonster 1 2008-3-12 20:40
19
0
同时利用多种方法,不过没有新意。
richardhc 2008-3-12 23:29
20
0
我还大二啊!!!
信息安全的,shellcode...不懂!
正在努力学习专业技术中...
游客
登录 | 注册 方可回帖
返回