首页
社区
课程
招聘
[原创]HSQARKH 完整源码
发表于: 2008-5-14 22:23 12154

[原创]HSQARKH 完整源码

HSQ 活跃值
8
2008-5-14 22:23
12154
HSQARKH 完整源码
这只是一个初步代码,用来实现ARK,做隐藏方面研究的.
本来打算等自己把所有自己知道的都尽量用上,再找时机发布,无奈最近平凡被各位大牛打击,实在在信心几近丧失殆尽. 暂时不想再搞这了,贻笑大方也罢,索性也把整个小工程源码给发出来, 也好让各位牛人说说我是否有再继续搞内核ROOTKIT研究的必要,是否够入门资格,代码风格是否规范(在现实世界里我从未接触过真正写程序的,我的身边都是搞医学的,真正的IT世界我丝毫不知,请勿见笑).

关于这个HSQInLineAPI.h里面的几个函数我时花了不少时间调试写出来的,如果有人不幸引用了鄙人的简陋代码,还望注明出处.
PVOID CheckFixHookedBaseAddress(PVOID);
PVOID GetNativeFunctionBaseAddress(PCWSTR);
DWORD GetFixOpcodeByLength(PVOID,LPVOID,LPVOID,DWORD);
DWORD SetHookAPIHead(LPVOID,PVOID,LPVOID,LPVOID,BYTE);
DWORD FixOpcodeForBackup(LPVOID,LPVOID,DWORD);
///////////////////////////////////////////////////////////////////////////////////// 
//*********************************************************************************** 
//模块名字:PVOID CheckFixHookedBaseAddress(PVOID lpBaseAddress)
//模块功能:对指定的基址试图寻找更合适的HOOK入口
//返回数值:返回合适的HOOK入口
//***********************************************************************************
//参数说明:参数名         |   输入/输出  |        参数说明
//          lpBaseAddress  |    IN        |  正常的需要优化的HOOK基址
//***********************************************************************************
PVOID CheckFixHookedBaseAddress(PVOID lpBaseAddress)
{
	__asm
	{	
		mov		esi, lpBaseAddress
		mov		edi, esi
		mov		ecx, 2					; 检测前2条指令是否含直接跳转, 是则跟进之
	CheckFixHookedBaseAddress_next:		; 支持更深层次的Inline HOOK
		push	ecx
		push	eax
		push	esp
		push	esi
		call	LDE32					; LDE32 会修改EDX, ECX, EAX,需自己手动保护其值 	
		pop		edx
		pop		ecx
		cmp		edx, 6
		je		CheckFixHookedBaseAddress_jmp_mem
		cmp		edx, 5
		je		CheckFixHookedBaseAddress_jmp_imm
	CheckFixHookedBaseAddress_jmp_continue:
		add		esi, edx
		loop	CheckFixHookedBaseAddress_next
		jmp		CheckFixHookedBaseAddress_quit
	CheckFixHookedBaseAddress_jmp_imm:
		lodsb
		dec		edx
		cmp		al, 0xe9
		jne		CheckFixHookedBaseAddress_jmp_continue
		lodsd
		add		eax, esi				; 需修正跳转地址
		jmp		CheckFixHookedBaseAddress_new_addr
	CheckFixHookedBaseAddress_jmp_mem:
		lodsw
		cmp		ax, 0x25ff
		jne		CheckFixHookedBaseAddress_quit
		lodsd
		mov		eax, dword ptr [eax]
	CheckFixHookedBaseAddress_new_addr:
		push	eax
		pop		lpBaseAddress
	CheckFixHookedBaseAddress_quit:
	}
	return lpBaseAddress;
}

PVOID GetNativeFunctionBaseAddress(IN PCWSTR pusNativeKeJmpFunctionName)
{
	UNICODE_STRING usFunctionName;
	RtlInitUnicodeString(&usFunctionName, pusNativeKeJmpFunctionName);
	return CheckFixHookedBaseAddress(MmGetSystemRoutineAddress(&usFunctionName));
}
///////////////////////////////////////////////////////////////////////////////////// 
//*********************************************************************************** 
//模块名字:DWORD SetHookAPIHead(LPVOID lpOpcode,PVOID lpBuffer,LPVOID lpParam,
//													LPVOID lpHookAPI,BYTE bAPICount)
//模块功能:设置被Inline HOOK的API头
//返回数值:返回实际设置Inline HOOK的API头指令串长度
//***********************************************************************************
//参数说明:参数名         |   输入/输出  |        参数说明
//          lpOpcode	   |    IN        |  需要处理的操作码基址(即原API的EPO)
//          lpBuffer	   |    OUT       |  接受Inline HOOK的API头指令串的本地缓冲区地址
//          lpParam		   |    IN        |  远程参数缓冲区地址,(没有可以为NULL)
//          lpHookAPI	   |    IN        |  HOOK API代码所存放的远程参数缓冲区地址
//          bAPICount	   |    IN        |  被Inline HOOK的原API需要传入的实际参数数目
//***********************************************************************************
//更新:
//2008-05-13: 自动生成最优化HOOK头, 增加对EAX的保存,使之支持更深层次的Inline HOOK
///////////////////////////////////////////////////////////////////////////////////////
DWORD SetHookAPIHead(LPVOID lpOpcode,PVOID lpBuffer,LPVOID lpParam,LPVOID lpHookAPI,BYTE bAPICount)
{	LARGE_INTEGER dwSeed;
	#if WIN32_VERSION
	QueryPerformanceCounter(&dwSeed);
	#else
	KeQueryPerformanceCounter(&dwSeed);
	#endif
__asm
	{	
		mov		ecx, dwSeed.HighPart
		mov		eax, dwSeed.LowPart
		add		ecx, eax
		ror		ecx, cl				; 产生随机数
		mov		eax, ecx
	;===============================================================================	
		push	lpHookAPI			; 开始填写可变参数
		push	lpParam
		lea		edx, SHQ_HookParam
		pop		dword ptr [edx]	
		xor		dword ptr [edx], eax
		lea		edx, SHQ_HookProc
		pop		dword ptr [edx]	
		xor		dword ptr [edx], eax ; 用随机密钥加密两个地址参数,加强检测难度
		cld
		lea		edi, SHQ_AddressKey
		stosd	
		lea		edi, SHQ_ClsESP
		mov		al, bAPICount
		shl		al, 2
		stosb					
		lea		edi, SHQ_FuckESP
		stosb						; 填写可变参数完毕
		call	SHQ_SaveData
	;===============================================================================
	;###############################################################################
		mov     edi, edi		; 8B FF	
		push    ebp				; 55	
		mov     ebp, esp		; 8B EC 伪扮入口标志,加强检测难度 ★★★ 	
		pop		ebp				; 保存EBP (伪装时必需)
		
		xchg	eax, dword ptr [esp] ; 保存返回地址(这个很重要), 同时入栈保存EAX
								; 在深层HOOK时,有时EAX也可能是跳转表的索引,故需保存之
								; 2008-05-12 增加对EAX的保存
		push    ecx
		push    edx				; 保护EBX, ECX,可以兼容fastcall api	★★★★
	SHQ_HookParam_Fix:	
		_emit	0x68
	SHQ_HookParam:	
		DD_ADRESS				; push    lpParam	; 传入HOOK参数
								; ◆注:重定位和跳转也成为RKU检测Line hook的标志◆
		_emit	0x68			; 不使用这些, 其实这样更省空间
	SHQ_AddressKey:				; 栈中解析地址,加强检测难度 ★★★★★
		DD_ADRESS				; push	dword ptr [SHQ_AddressKey]			
		pop		ecx				; 取得解码Key
	SHQ_HookParam_Fix_Sec:	
		_emit	0x31			; 地址解码
		_emit	0x0c
		_emit	0x24			; xor   dword ptr [esp], ecx ★★★★★	
		push	eax				; 修正返回地址
	SHQ_BackAddress:
		_emit	0x83
		_emit	0xEC			; 平衡堆栈  ●●●●●●●●
	SHQ_FuckESP:				; 制造假象申请局部栈空间的同时,能保留压入的参数共HOOK使用
		_emit	0x00			; sub     esp, x
	SHQ_FuckESP_Fix:
		_emit	0x68
	SHQ_HookProc:
		DD_ADRESS				; push	eax, lpHookAPI	; 设置真正的跳转地址
		_emit	0x31			; 地址解码
		_emit	0x0c
		_emit	0x24			; xor   dword ptr [esp], ecx ★★★★★
	SHQ_HookProc_Fix:

		push	ebp				; 模拟原API返回前恢复原EBP (不仅实现了跳转,还恢复了EBP)
		mov		ebp, esp		; 将HOOK代码做成正常调用退出格式,加强检测难度
		
		_emit	0x0c9			; leave 由于无法编译通过,只好采用机器码(WIN32时却可以)
		;leave					; mov   esp, ebp	; 主要目的是设置ESP指针
								; pop   ebp			; 在ESP指定的位置恢复EBP
		_emit	0x0c2			; ret	x  =>	pop	eip
								;				add	esp, x	●●●●●●●●●	
	SHQ_ClsESP:
		DW_DATA					; x
	;###############################################################################
	SHQ_SaveData:				; 保存HOOK 头数据
		pop		ecx
    ;--------------------------------------------------------------------------------
		mov		edi, lpOpcode					; 生产最优化HOOK头,指令实时修正保存
		test	edi, edi
		je		SHQ_SaveData_Exit
		mov		esi, edi
		cld
		xor		edx, edx						; EDX 作为属否含有PROC的标志(默认为0,表无)
		lodsw
												; 检测是否需要添加不必要的API入口伪装头
												; 尽量减小HOOK头尺寸
		cmp		ax, 0FF8Bh						; 8BFF	    mov     edi, edi
		jne		SHQ_SaveData_Nt					; 据说NT以上MS才添加了这个,方便大家HOOK
		or		dl, 01b							; 设置标志: -> XP
	SHQ_SaveData_Nt:
		lodsb									; 55		push    ebp				
		cmp		al, 55h
		je		SHQ_SaveData_Proc
		lodsw 
		jmp		SHQ_SaveData_Proc_Head
	SHQ_SaveData_Proc:
		lodsw	
		cmp		ax,	0EC8Bh						; 8BEC		mov     ebp, esp
		jne		SHQ_SaveData_Proc_Head
		sub		esi, 3+1						; 有PROC时,需要 POP EBP -> (+1)
		or		dl, 10b							; 设置标志: ->标准的PROC
		and		dl, 01b							; 检测是否为旧的OS的PROC
		je		SHQ_SaveData_Proc_Head
		sub		esi, 2
	SHQ_SaveData_Proc_Head:
		lodsb									; 默认不需要 POP EBP
		sub		esi, edi
		add		esi, ecx						; 得到最优HOOK头基址
		mov		edi, lpBuffer

		lea		ecx, SHQ_HookParam_Fix
		sub		ecx, esi
		rep		movsb
		mov		eax, lpParam
		test	eax, eax						; 如果HookParam=NULL,可以精简指令为
		jne		SHQ_SaveData_ParamExist	
		mov		ax, 6Ah							; 6A 00         push    0
		stosw
		add		esi, 5
		lea		ecx, SHQ_HookParam_Fix_Sec
		sub		ecx, esi
		rep		movsb
		add		esi, 3							; 0 时无需地址解码
		mov		al, 50h							; 50            push    eax
		stosb									; 采用手工完成 push    eax
		jmp		SHQ_SaveData_BackMe
	SHQ_SaveData_ParamExist:
		lea		ecx, SHQ_BackAddress
		sub		ecx, esi
		rep		movsb
	SHQ_SaveData_BackMe:						; 处理返回HOOK调用部分
		test	edx, edx
		jne		SHQ_SaveData_Proc_Back
		add		esi, 4
		lea		ecx, SHQ_HookProc_Fix
		sub		ecx, esi
		rep		movsb
		mov		al, 0c3h
		stosb									; 无需伪装,直接RET跳转调用HOOK
		jmp		SHQ_SaveData_Exit
	SHQ_SaveData_Proc_Back:	
		lea		ecx, SHQ_SaveData				; 余下的指令都需要
		cmp		bAPICount, 0
		jne		SHQ_SaveData_Proc_Normal
		mov		esi, SHQ_FuckESP_Fix			; 不用移动ESP
		sub		ecx, 2							; 参数个数为0,又可省 2 BYTE
		mov		byte ptr [ECX-1], 0c3h
	SHQ_SaveData_Proc_Normal:
		sub		ecx, esi
		rep		movsb
	SHQ_SaveData_Exit:
		sub		edi, lpBuffer
		mov		dwSeed.LowPart, edi
	;--------------------------------------------------------------------------------
	}
	return  dwSeed.LowPart;
}
////////////////////////////////////////////////////////////////////////////////////////
//**************************************************************************************
//模块名字:GetFixOpcodeByLength(LPVOID,LPVOID,LPVOID,DWORD)
//模块功能:备份被Inline HOOK的API头
//返回数值:返回实际备份指令串长度, 零表示失败
//**************************************************************************************
//参数说明:参数名			|   输入/输出  |        参数说明
//          lpBuffer		|    OUT       |     备份API的本地缓冲区地址
//          lpOpcode		|    IN        |     需要处理的操作码基址(即原API的EPO)
//          lpRemoteBuffer	|    IN        |     备份API的远程缓冲区地址
//          dwNumberOfBytes	|    IN        |     需要备份指令串长度
//**************************************************************************************
//更新:
//2008-05-11:
//    在内核环境下当检测到ret指令,就应该是为该指令串结束标志,不宜继续处理
//2008-05-08:
//    增加对长CALL,JMP跳转的检测功能
//2008-05-03:
//    增加对CALL跳转的修正功能
//2008-04-28:
//    如果空间不够则,不被HOOK
//2008-04-27:
//    由HSQ花12h用OD和VC9调试通过, 增加了对简单跳转指令的修正功能,及优化代码结构
////////////////////////////////////////////////////////////////////////////////////////
DWORD	GetFixOpcodeByLength(PVOID lpBuffer,LPVOID lpOpcode,LPVOID lpRemoteBuffer,DWORD dwNumberOfBytes)
{	
	__asm
	{	
		push	ebx
		xor		ebx, ebx
		mov		esi, lpOpcode
		test	esi, esi
		je		GetFixOpcodeByLength_exit		
		mov		edi, lpBuffer
		mov		ecx, ebx
		cld
	GetFixOpcodeByLength_next:
		push	ecx
		push	esp
		push	esi
		call	LDE32 	
		pop		ecx
		add		ebx, ecx						; 累计目前已扫描的指令长度
		cmp		ecx, 2							; 检测本条指令是否需函数结束指令
		ja		GetFixOpcodeByLength_check
		lodsb
		dec		esi
		cmp		al, 0c2h						; 若后面只存在少于5个BYTE不能继续覆盖
		je		GetFixOpcodeByLength_hook_false
		cmp		al, 0c3h						
		je		GetFixOpcodeByLength_hook_false
		jmp		GetFixOpcodeByLength_normal
	GetFixOpcodeByLength_hook_false:
		xor		ebx, ebx
		jmp		GetFixOpcodeByLength_exit		; 无法Inline HOOK, 退出
	GetFixOpcodeByLength_check:
		cmp		ecx, 5							; 检测本条指令是否需要修正
		jne		GetFixOpcodeByLength_check_jmp
		lodsb
		stosb
		cmp		al, 0XE8
		je		GetFixOpcodeByLength_fix_dword
		jmp		GetFixOpcodeByLength_no_call
	GetFixOpcodeByLength_check_jmp:
		cmp		ecx, 6	
		jne		GetFixOpcodeByLength_normal
		lodsw
		stosw
		xchg	ah, al
		cmp		ax, 0FF25h						; jmp     dword ptr [80554484]
		je		GetFixOpcodeByLength_hook_false	
		cmp		ax, 0FF15h						; call    dword ptr [80554484]
		je		GetFixOpcodeByLength_hook_false	; 跳转地址属于系统变量, 本可以不加修正
												; 的直接备份,段很有可能直接跳转到已被
												; 修改的原入口,而非HOOK内部,如果是运行时
												; 全局常量,则可以修正该地址后PUSH RET之.
												; 暂时为简化处理,显示无法处理,返回失败	
		cmp		ax, 0F8Fh						; 检测是否含有JXX指令
		ja		GetFixOpcodeByLength_no_jmp
		cmp		ax, 0F80h						; 检测是否含有CALL指令
		jb		GetFixOpcodeByLength_no_jmp
	GetFixOpcodeByLength_fix_dword:	
		lodsd
		add		eax, lpOpcode 
		sub		eax, lpRemoteBuffer				; 需修正跳转
		stosd
		jmp		GetFixOpcodeByLength_continue
	GetFixOpcodeByLength_no_jmp:
		dec		ecx
	GetFixOpcodeByLength_no_call:
		dec		ecx
	GetFixOpcodeByLength_normal:
		rep		movsb							; 备份当前指令 								
	GetFixOpcodeByLength_continue:	
		cmp		ebx, dwNumberOfBytes
		jb		GetFixOpcodeByLength_next
		mov		al, 0e9h						; 填加回跳指令
		stosb
		mov		eax, esi
		sub		eax, lpRemoteBuffer
		sub		eax, ebx
		sub		eax, 5
		stosd	
	GetFixOpcodeByLength_exit:
		mov		eax, ebx
		pop		ebx
		mov		dwNumberOfBytes, eax
	}
	return dwNumberOfBytes;
}
////////////////////////////////////////////////////////////////////////////////////////
//**************************************************************************************
//模块名字:FixOpcodeForBackup(LPVOID,LPVOID,DWORD)
//模块功能:修正备份Inline HOOK的API头
//返回数值:返回实际修正指令串长度, 零表示失败
//**************************************************************************************
//参数说明:参数名			|   输入/输出  |        参数说明
//          lpOpcode		|    IN        |     需要处理的操作码基址
//          lpFixBase	    |    IN        |     需修正目标空间的基址
//          dwNumberOfBytes	|    IN        |     需修正的指令串长度
//**************************************************************************************
///////////////////////////////////////////////////////////////////////////////
DWORD	FixOpcodeForBackup(LPVOID lpOpcode,LPVOID lpFixBase,DWORD dwNumberOfBytes)
{	
	__asm
	{
		push	ebx
		xor		ebx, ebx
		mov		esi, lpOpcode
		test	esi, esi
		je		FixOpcodeForBackup_exit	
		mov		ecx, ebx
		cld
	FixOpcodeForBackup_next:
		push	ecx
		push	esp
		push	esi
		call	LDE32 	
		pop		ecx
		add		ebx, ecx						; 累计目前已扫描的指令长度
		cmp		ecx, 5							; 检测本条指令是否需要修正
		jne		FixOpcodeForBackup_check_jmp
		lodsb
		cmp		al, 0XE8
		jne		FixOpcodeForBackup_no_call	
		jmp		FixOpcodeForBackup_fix_dword
	FixOpcodeForBackup_check_jmp:
		cmp		ecx, 6	
		jne		FixOpcodeForBackup_normal
		lodsw
		xchg	ah, al
		cmp		ax, 0F8Fh						; 检测是否含有JXX指令
		ja		FixOpcodeForBackup_no_jmp
		cmp		ax, 0F80h						; 检测是否含有CALL指令
		jb		FixOpcodeForBackup_no_jmp
	FixOpcodeForBackup_fix_dword:	
		mov		edi, esi
		lodsd
		add		eax, lpFixBase
		sub		eax, lpOpcode 					; 需修正跳转
		stosd
		jmp		FixOpcodeForBackup_continue
	FixOpcodeForBackup_no_jmp:
		dec		ecx
	FixOpcodeForBackup_no_call:
		dec		ecx
	FixOpcodeForBackup_normal:
		add		esi, ecx
	FixOpcodeForBackup_continue:
		cmp		ebx, dwNumberOfBytes
		jb		FixOpcodeForBackup_next
	FixOpcodeForBackup_exit:
		mov		eax, ebx
		pop		ebx
		mov		dwNumberOfBytes, eax
	}
	return dwNumberOfBytes;
}

                        by HSQ 22:03 2008-5-14
                                                于湖北宜昌XXX网吧

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 7
支持
分享
最新回复 (14)
雪    币: 1946
活跃值: (243)
能力值: (RANK:330 )
在线值:
发帖
回帖
粉丝
2
LZ很强大,我也来学习一下
2008-5-14 23:24
0
雪    币: 415
活跃值: (34)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
3
老兄是一打击就会出好东西,哈。哈。正需要这部分资料,
2008-5-15 01:34
0
雪    币: 846
活跃值: (221)
能力值: (RANK:570 )
在线值:
发帖
回帖
粉丝
4
即使不规范..这么多注释..比那些只有规范没有注释的代码好了...

我是进来学习的..
2008-5-15 01:47
0
雪    币: 381
活跃值: (140)
能力值: ( LV13,RANK:330 )
在线值:
发帖
回帖
粉丝
5
江湖险恶,卧虎藏龙,初出茅庐,处处挨刀,卧薪尝胆,终究辉煌。
2008-5-15 10:28
0
雪    币: 201
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
学医好啊, 找个学医的mm就不愁身体出问题了
2008-5-15 10:54
0
雪    币: 381
活跃值: (140)
能力值: ( LV13,RANK:330 )
在线值:
发帖
回帖
粉丝
7
看来我得考虑坚持自己的医学,把IT的当作爱好,不去找IT工作,就在医院混得了
2008-5-15 11:32
0
雪    币: 242
活跃值: (14)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
8
不错

不过跳转/调用指令处理部分有点瑕疵,在不少情况下可能会处理不了
另外,隐约记得LDE已经被不少杀毒软件列入黑名单了,如果实际用的话,还是换个好点

额,汇编代码还是在IDA里看着方便。
2008-5-15 12:02
0
雪    币: 381
活跃值: (140)
能力值: ( LV13,RANK:330 )
在线值:
发帖
回帖
粉丝
9
1.对于“不过跳转/调用指令处理部分有点瑕疵”,这是存在的,因为CheckFixHookedBaseAddress()是我临时加的,本来打算他是在其他函数内面。考虑到代码的重用性及模块化,我就将他抽出来单独编写。一边针对在实际应用过程中的错误,或具体情况进行增加和修补。
2.对于“隐约记得LDE已经被不少杀毒软件列入黑名单了”,这个我没太在意。主要是我机子太乱,装个查毒软件没法干事,所以机子里没有任何杀毒软件,于是我没注意到这事。其实,对于这种事情,我个人认为,完全没有必要迁就杀软。由于LDE是在运行时调用,通过变形或加密处理后在使用,估计应该能够躲过检查。
3.“汇编代码还是在IDA里看着方便”,对于这里两个核心函数,没有源码你用IDA试试看。我自己
那IDA看了一下,F5是没用的,只是标号,应该看得很难受的。因为它们会在多个时空里执行,要不是我自己写的,看的都有些晕。。。
2008-5-15 18:08
0
雪    币: 116
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
很好,很强大
2008-5-15 18:10
0
雪    币: 215
活跃值: (34)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
佩服, 我等汗颜.....
2008-5-15 20:41
0
雪    币: 242
活跃值: (14)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
12
不晓得哦,一直都是用IDA分析东西,蛮习惯,标号可以自己起。F5这种东西,基本不用。
2008-5-15 21:50
0
雪    币: 279
活跃值: (160)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
13
回贴收藏。。。谢谢。。
2008-5-15 23:50
0
雪    币: 204
活跃值: (14)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
楼主牛人。。。我等确实汗颜啊。。。。
2008-5-16 01:47
0
雪    币: 209
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
看到牛人了我等太菜基本不懂啊
2009-1-7 17:02
0
游客
登录 | 注册 方可回帖
返回
//