Gh0st启动流程

这篇笔记详细记录了Gh0st软件的启动流程,从CGh0stApp的InitInstance开始,经过CMainFrame的Activate方法,再到CIOCPServer的初始化和监听线程的创建。文中逐层深入,分析了CIOCPServer的构造、套接字的创建、绑定、监听以及客户端连接的处理。同时,提到了CIOCPServer的Stop和Shutdown方法,描述了如何终止服务器并清理资源。笔记指出,这仅是个人学习记录,可能存在错误,尚未完成,不适合阅读。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

仅是笔记,存在错误,并未写完,请勿阅读,谢谢

1、CGh0stApp–>Initlnstance()
1)配置界面信息及其他
2)从.ini文件中读取监听端口ListenPort和最大连接数MaxConnection,并做相应的调整
3)调用((CMainFrame*) m_pMainWnd)->Activate(nPort, nMaxConnection)去激活服务器,(跳到2)

2、CMainFrame–>Activate(UINT nPort, UINT nMaxConnections)
0)1来
1)检查是否存在m_iocpServer,如果有的话,shutdown一下
(程序刚启动,一般是没有,这里停一下,不跟进,跟进到13)
2)m_iocpServer新建对象,调用CIOCPServer的构造函数(跟进,到3)
3)开启服务器,调用函数
m_iocpServer->Initialize(NotifyProc, this, 100000, nPort)(跟进到4)
4)获得主机名,通过主机名获得ip,并设置状态栏显示数据
5)返回到1

3、CIOCPServer–>CIOCPServer()
0)2来
1)初始化套接字版本wsaData
2)初始化一个临界区变量m_cs
3)初始化15个iocpserver的变量,
4)定义包标志bPacketFlag
5)返回到2

4、CIOCPServer–>Initialize(NotifyProc, this, 100000, nPort)
0)2来
1)存下三个参数
2)创建套接口m_socListen = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
3)创建网络事件m_hEvent = WSACreateEvent()
4)将FD_ACCEPT事件关联到套接口上
nRet = WSAEventSelect(m_socListen,m_hEvent,FD_ACCEPT);
5)配置SOCKADDR_IN地址
6)绑定套接头nRet = bind(m_socListen,(LPSOCKADDR)&saServer,sizeof(struct sockaddr));
7)监听端口nRet = listen(m_socListen, SOMAXCONN);
8)开启监听线程
m_hThread =(HANDLE)_beginthreadex(NULL,0,ListenThreadProc,(void*) this,0,&dwThreadId);
9)跟进看一下这个监听线程都干了啥(跟进到5)
A)初始化完成端口InitializeIOCP();(MD,数字太多,把我弄混了,居然把这个给漏了)(跳到20)
B)返回2

5、CIOCPServer.–>ListenThreadProc(LPVOID lParam)
0)4来
1)无限while循环
2)等待m_hKillEvent受信就跳出循环
WaitForSingleObject(pThis->m_hKillEvent, 100) == WAIT_OBJECT_0
3)插一句,受信是在CIOCPServer::stop中SetEvent(m_hKillEvent),
就是在stop掉server的时候受信
4)等待事件的发生,没有发生就阻塞在这里
dwRet = WSAWaitForMultipleEvents(1,&pThis->m_hEvent,FALSE,100,FALSE);
5)如果超时,继续while循环
6)查看事件是什么事件
int nRet = WSAEnumNetworkEvents(pThis->m_socListen,pThis->m_hEvent,&events);
7)如果error的话就跳出while循环
8)如果事件是FD_ACCEPT的话,表示有连接到来调用CIOCPSserver::OnAccept()(跟进到6)
9)继续自循环。到5

6、CIOCPSserver–>OnAccept()
0)5来
1)检查m_bTimeToKill和m_bDisconnectAll,如果关闭标识为真,则直接返回
2)接受套接字,保存套接字的地址和地址长度
clientSocket = accept(m_socListen,(LPSOCKADDR)&SockAddr,&nLen);
3)分配一个Context来存储套接字信息,返回值是个ClientContext指针
ClientContext* pContext = AllocateContext();
(跟进转到7)
4)检查是否分配成功,否返回,
5)然后将客户端的套接字给pContext,pContext->m_Socket = clientSocket;
6)修复m_wsaInBuffer结构体的长度和指针
7)调用这个函数来创建完成端口CIOCPServer::AssociateSocketWithCompletionPort(跳到9)
8)如果不成功的话,就删掉Context,并且关掉clientSocket和m_socListen,并返回
9)setsockopt来启动保活机制
setsockopt(pContext->m_Socket, SOL_SOCKET, SO_KEEPALIVE, (char *)&chOpt, sizeof(chOpt))
A)设置超时信息
B)加锁CLock cs(m_cs, “OnAccept” )并将pContext加到m_listContexts的尾部
C)投递到I/O完成队列中,
D)如果没有成功。则调用CIOCPSserver::RemoveStaleClient(pContext,TRUE);(挑转到10)
TRUE 表示不需要暴力断开连接
E)m_pNotifyProc((LPVOID) m_pFrame, pContext, NC_CLIENT_CONNECT);通知窗口处理上线信息(先不跳,跳到16)
F)PostRecv(pContext);(跳到12)
G)(返回到5)

7、CIOCPServer::AllocateContext()
0)6来
1)用cs进行加锁操作
2)如果m_listFreePool为不空的话,就拿出第一个来,否则新建一个ClientContext(这里跳到8)
3)将pContext清0
4)如果存在pContext对象的话,就再次清零(这里是不是有些重复),
然后写明不是MainSocket,m_Dialog也清为0
5)(返回6继续)

8、struct ClientContext 认识下这个结构体,很重要
0)7来
1)SOCKET m_Socket; //套接字
2)CBuffer m_WriteBuffer; //要发送的数据
3)CBuffer m_CompressionBuffer; // 接收到的压缩的数据
4)CBuffer m_DeCompressionBuffer; // 解压后的数据
5)CBuffer m_ResendWriteBuffer; // 上次发送的数据包,接收失败时重发时用
6)int m_Dialog[2]; //放对话框列表用,第一个int是类型,
第二个是CDialog的地址
//这个参数非常重要,区分主套接字与各个功能间的套接字,
//如果这个值为非NULL 则认为是功能的套接字,交给冲口处理
//如果为NULL 则认为是主套接字,交给主套接字的上线函数处理
//到void CMainFrame::ProcessReceiveComplete(ClientContext *pContext)分析
7)int m_nTransferProgress;
// Input Elements for Winsock
8)WSABUF m_wsaInBuffer; //结构体,buffer长度和指针,
指针指向m_byInBuffer,长度为m_byInBuffer的长度
9)BYTE m_byInBuffer[8192];
// Output elements for Winsock
A)WSABUF m_wsaOutBuffer;
B)HANDLE m_hWriteComplete; //socket写满了,准备好要发送
// Message counts… purely for example purposes
C)LONG m_nMsgIn;
D)LONG m_nMsgOut; //要发送的数据+1
E)BOOL m_bIsMainSocket; // 是不是主socket
F)ClientContext* m_pWriteContext;
G)ClientContext* m_pReadContext;
H)(返回7继续)

9、BOOL CIOCPServer::AssociateSocketWithCompletionPort(SOCKET socket,
HANDLE hCompletionPort, DWORD dwCompletionKey)
0)6来
1)把socket添加到一个已有I/O完成端口的设备列表中,socket与完成端口关联
2)(返回到6继续)

10、CIOCPServer–>RemoveStaleClient(ClientContext* pContext, BOOL bGraceful)
0)6来
1)CLock cs(m_cs, “RemoveStaleClient”);加锁
2)lingerStruct和setsockopt来暴力使socket的TCP夭折(FALSE才执行)
3)找到m_listContexts中的pContext
4)取消掉pContext的套接口的Io CancelIo((HANDLE) pContext->m_Socket);
5)关闭套接口,
6)查看I/O是否完成HasOverlappedIoCompleted((LPOVERLAPPED)pContext)宏查看
7)给界面发送断开连接的消息m_pNotifyProc((LPVOID) m_pFrame, pContext, NC_CLIENT_DISCONNECT);(先不跳)
8)把pContext放到m_listFreePool中(跳到11)(返回6)

11、CIOCPServer–>MoveToFreePool(pContext);
0)10来
1)CLock cs(m_cs, “MoveToFreePool”);加锁
2)从m_listContexts中找到pContext后,清掉它的各种数据后,移到m_listFreePool的链尾上
3)m_listContexts链表中移除pContext(返回10继续)

12、CIOCPServer–>PostRecv(ClientContext* pContext)
0)6来
1)pOverlap(IORead)
2)WSARecv读数据到m_wsaInBuffer里
3)如果读取失败的话,调用RemoveStaleClient(pContext, FALSE);(跳到10,然后跳回6)

13、CIOCPServer->Shutdown();
0)2来
1)检查服务器是否在运行,如果否的话,直接返回m_bInit
2)修改两个标志,m_bInit为false,m_bTimeToKill为true
3)调用CIOCPServer::stop()(跳到14)
4)关掉m_socListen套接口和m_hEvent事件,
5)关掉完成端口,CIOCPServer::CloseCompletionPort()(跳转到15)
6)删掉临界区,循环删掉m_listFreePool
7)结束了

14、CIOCPServer->stop();
0)13来
1)SetEvent(m_hKillEvent),监听线程停止循环,并结束
2)无限等待监听线程结束WaitForSingleObject(m_hThread, INFINITE);
3)关掉监听线程的句柄,关掉m_hKillEvent的句柄
4)(返回13)

15、CIOCPServer–>CloseCompletionPort()
0)13来
1)当m_nWorkerCnt工作线程还存在,就发送
PostQueuedCompletionStatus(m_hCompletionPort, 0, (DWORD) NULL, NULL);关掉工作线程
2)关掉标识m_hCompletionPort
3)遍历m_listContexts链表,删掉每一个Client,跳到10
4)最后删掉所有
5)返回到13

16、CALLBACK CMainFrame::NotifyProc(LPVOID lpParam, ClientContext *pContext, UINT nCode)
0)6来,10来
1)g_pConnectView获得主窗体(全局)
2)把CMainFram的m_iocpServer给gh0stView的m_iocpServer
3)设置状态条的流量值
4)如果nCode是NC_CLIENT_DISCONNECT的话,向窗口发送WM_REMOVEFROMLIST消息
5)如果是NC_RECEIVE则调用ProcessReceive,ProcessReceive(pContext); 跳到17
6)如果是NC_RECEIVE_COMPLETE则调用ProcessReceiveComplete函数,跳到18

17、CMainFrame::ProcessReceive(ClientContext *pContext)
0)16来
1)CDialog dlg = (CDialog )pContext->m_Dialog[1],获得窗口指针
2)pContext->m_Dialog[0]调用相应窗体(摄像头、屏幕监控、语音)的OnReceive函数,处理数据
3)返回16

18、CMainFrame::ProcessReceiveComplete(ClientContext *pContext)
0)16来
1)获得相应的窗体CDialog dlg = (CDialog )pContext->m_Dialog[1];
2)pContext->m_Dialog[0]),((CFileManagerDlg *)dlg)->OnReceiveComplete();
根据不同的消息交给不同的窗体处理,所有的完成的信息
3)pContext->m_DeCompressionBuffer.GetBuffer(0)[0],
根据加密数据的第一位来判断包的类型
4)Send函数,m_iocpServer->Send(pContext, (LPBYTE)&bToken, sizeof(bToken));
5)

19、CIOCPServer–>Send(ClientContext* pContext, LPBYTE lpData, UINT nSize)
0)18来
1)compress来压缩要传送的数据
2)向m_WriteBuffer中写入包标志m_bPacketFlag、整个包的大小,数据包的大小,写入压缩后的数据
3)把要发送的数据(加密后的)写到lpResendWriteBuffer
4)将lpResendWriteBuffer写入m_ResendWriteBuffer
5)如果要发送的数据的大小不大于0的话,就发备份的数据
6)等待m_hWriteComplete准备好(等CIOCPServer::OnClientWriting)
7)异读写结构体,置为IO写
8)post到完成端口队列,并将pContext->m_nMsgOut++
9)回到18

20、CIOCPServer–>InitializeIOCP(void)
0)4来
1)创建一个原始套接口s= socket(AF_INET, SOCK_STREAM, IPPROTO_IP)
2)m_hCompletionPort = CreateIoCompletionPort( (HANDLE)s, NULL, 0, 0 );//创建io完成端口
3)获得系统信息GetSystemInfo( &systemInfo );
4)m_nThreadPoolMin=m_nThreadPoolMax=线程数*2
5)m_nCPULoThreshold和m_nCPUHiThreshold CPU的使用量
6)初始化查询CPU的使用量 CPU.init()(跳到21)
7)计算工作线程数nWorkerCnt = systemInfo.dwNumberOfProcessors * HUERISTIC_VALUE;
8)循环创建工作线程
hWorker = (HANDLE)_beginthreadex(NULL,0,ThreadPoolFunc,(void*) this,0,&nThreadID);
9)工作线程的回调函数ThreadPoolFunc(跳到22)

21、CCpuUsage–>Init()
0)20来
1)定义一个查询结构PdhOpenQuery(NULL, 1, &m_hQuery)
2)pdh_status = PdhAddCounter(m_hQuery, szCounterName, (DWORD) m_pCounterStruct,
&(m_pCounterStruct->hCounter))
将查询结构添加到查询句柄中
3)返回20

22、CIOCPServer–>ThreadPoolFunc (LPVOID thisContext)
0)20来
1)m_CurrentThreads自自加锁,m_nBusyThreads自加锁
2)大for循环
3)m_nBusyThreads解锁
4)取得一个完成端口请求
BOOL bIORet = GetQueuedCompletionStatus(hCompletionPort,&dwIoSize,
(LPDWORD) &lpClientContext,&lpOverlapped, INFINITE);
5)CONTAINING_RECORD(address, type, field) ((type *)( \
(PCHAR)(address) - \
(ULONG_PTR)(&((type *)0)->field)))
宏:指向整个的定义结构,这样就能指向带有附加数据的整个OVERLAPPEDPLUS类型,
并且根据附加的数据的m_ioType域的不同,进行不同的处理
6)m_nBusyThread自锁
7)get不成功的话以及超时就移除所有ClientContext
8)继续循环
9)没有error的话,当前线程是唤醒的工作线程,并且唤醒的线程数少于最大线程池数,并且cpu的使用量大于最大线程利用率的
再开一个线程,目测这个被注释掉了,并不需要申请额外的线程到线程池了,
A)get不成功,线程超时,没有取得Contenxt,CPU使用少于最少,当前线程数大于最小线程池数的画,退出循环
B)如果get成功,调用ProcessIOMessage(pOverlapPlus->m_ioType, lpClientContext, dwIoSize);(跳到23)
C)解锁m_nWorkerCnt、m_nCurrentThreads、m_nBusyThreads
D)线程结束

23、CIOMessageMap的虚函数
IO_MESSAGE_HANDLER(IORead, OnClientReading)(跳到24)
IO_MESSAGE_HANDLER(IOWrite, OnClientWriting)()
IO_MESSAGE_HANDLER(IOInitialize, OnClientInitializing)
0)22来
1)根据消息的类型,选择不同的函数

24、CIOCPServer::OnClientReading(ClientContext* pContext, DWORD dwIoSize)
0)23来
1)CLock cs(CIOCPServer::m_cs, “OnClientReading”);加锁
2)计算接受速度,(这里值得好好思考下)
3)没有数据,说明遇到不可预知的错误,直接删掉连接
4)如果包里只有Gh0st数据的话,主控端就重新发送数据
5)把m_byInBuffer中的数据写入m_CompressionBuffer
6)通知界面,收到数据了 goto 16
7)while m_CompressionBuffer中的数据大于13的时候
8)拷出包头,并对比下是不是Gh0st,

未完待续,并且分析中可能存在错误,仅仅是阅读笔记

控制端采用IOCP模型,数据传输采用zlib压缩方式稳定快速,上线数量无上限,可同时控制上万台主机控制端自动检测CPU使用率调整自己的工作线程, 稳定高效宿主为svchost以系统服务启动,有远程守护线程,上线间隔为两分钟。心跳包机制防止意外掉线..支持HTTP和DNS上线两种方式自动恢复SSDT(这功能干什么,大家都知道,免杀自己做吧),安装本程序需要管理员权限控制端279K,返朴归真的界面,生成的服务端无壳,106 K,EXE内的资源用UPX压缩, 可安装多个服务端其它细节方面的功能大家自己去发现吧功能:文件管理 完全仿Radmin所写, 文件、文件夹批量上传、删除、下载、创建、重命名屏幕监视 扫描算法速度最快可达到120帧/秒,差异算法适合网络极差的情况下传输,传输速度快,控制屏幕,发送Ctrl+Alt+Del,剪贴板操作,7种色彩显示方式,等......键盘记录 可记录中英文信息,离线记录(记录上限50M)功能远程终端 一个简单shell系统管理 进程管理,窗口管理,拨号上网密码获取视频查看 查看远程摄像头,快照,录像,压缩等功能...语音监听 监听远程语音,同时也可以把本地语音传送给远程,进行语音聊天,GSM610压缩方式,传输流畅会话管理 注销,重启,关机,卸载服务端其它功能 下载执行指定URL中的程序,隐藏或者显示访问指定网址,清除系统日志地址位置 将IP数据库文件QQWry.Dat放置程序同目录下即可显示地理位置集群控制 可同时控制多台主机,同时打开视频监控等管理功能备注功能 .........注: 软件不断更新中,有什么意见大家多多提,偶看可以的就采纳.....gh0st的成长,离不开大家的帮助.2008/1/27 11:16 : 优化了屏幕传输算法,CPU利用率更低2008/1/27 16:06 : 驱动以资源方式写入安装文件跟DLL文件中,优化屏幕传输2008/1/27 17:26 : 修正驱动安装时的一个Bug2008/1/28 05:28 : 服务端安装强化,加入服务检测,守护线程强化,加入禁用监视,顺便做了下免杀2008/1/29 12:47 : 改变服务端安装启动方式,隐藏服务,去掉驱动程序和守护线程,感谢Lzx无私的帮助...2008/1/29 16:12 : 修正键盘记录重复问题,优化服务端上线方式2008/1/30 04:11 : 修正服务端网络内核的一个导致异常的Bug,优化服务端大小到100K2008/1/31 01:28 : 重写服务端网络内核,加入数据包验证,及重发功能,更加稳定2008/1/31 11:36 : 修正服务端网络内核一个导致数据包混乱的问题,加入帧速限制,传输不稳定的情况从此消失...2008/2/01 10:54 : 主动防御功能加强,过卡巴全监控,瑞星,Kis6,Kis7,Norton,ZoneAlarm,江民2008等杀毒软件.下个版本准备过所有杀软的主动...期待吧.2008/2/01 14:18 : 加入服务端异常处理,更新稳定,请各位帮助测试..2008/2/01 15:39 : 修正服务端删除后不能安装的致命错误2008/2/01 23:35 : 改写了下服务端一些函数,增加稳定性,春季过后重写服务端吧,简洁下程序.2008/2/02 19:51 : 修正服务端视频监控功能的一些BUG2008/2/03 00:40 : 屏幕监控加入显示远程鼠标功能2008/2/05 16:46 : 重写屏幕传输算法,屏幕传输更快,控制更稳定..2008/2/05 23:45 : 还是网络内核跟屏幕传输方面,只求更快,不求最快,前版本屏幕传输有问题,旧版本不能上线,请用最新版本...2008/2/06 17:32 : 服务端做了些优化,加入跟踪远程光标的功能,旧版本不能上线,请用最新版本2008/2/07 00:57 : 改了些服务端,没事优化优化,准备过完年,大整一下,新年快乐...2008/2/07 16:02 : 没事加了个托盘功能,做了些代码优化,一个人过年,有点郁闷...2008/2/07 20:42 : 修正服务端一个句柄泄漏的问题..2008/2/08 22:08 : 全面优化了下服务端,新加了备注功能.2008/2/09 22:58 : 修正一些大家提到的问题,Gh0st RAT Beta 2.1 发布2008/2/11 00:18 : 修正服务端安装的一个BUG,静心研究ACE中,暂停更新...................2008/2/17 16:14 : 保存配置文件,服务端支持socks5代理上线,加入下载更新功能,屏幕控制加入,黑屏,锁定等功能2008/2/20 10:49 : 应大家要求,看了看江民2008的垃圾主动,连注册表都没,随便改了下服务端,过江民2008主动.其它有啥主动过不了的,抓图,我抽空解决2008/2/20 09:26 : 改了下服务端一些网络方面的东西,看对2003掉线情况是否有效,望大家测试,多谢了.2008/2/21 15:43 : 服务端掉线问题,重启后不上线问题,测试版本,请大家测试2008/2/22 19:47 : 解决重启后服务端不上线问题,加强对抗主动防御的功能2008/2/23 17:11 : 全面优化了下服务端,加强稳定性,请大家测试2008/2/23 19:03 : 修正视频监视的一个小BUG2008/2/24 01:55 : 文件管理中加入本地和远程运行功能,优他了部分代码,旧版本不会上线,请用新版本2008/2/24 12:56 : 修正文件管理中一个低级错误,下载更新的一个错误2008/2/26 00:00 : 完美解决重复安装,重复上线问题,发布gh0st2.5,2008/3/20 21:52 : 服务端全部优化一遍,加入语音监听,屏幕监视的算法优化...2.6发布2008/3/24 18:52 : 抽出时间来,视频采用选择性压缩,强大的H263压缩算法,100:1的压缩率,加入快照功能...2.7发布2008/3/25 02:42 : 修正网友提出的问题,如下载网址输入有限制等,一些人性化细节方面的修改...2008/3/26 05:01 : 修正视频的一个解码器处理的BUG,加入智能选择编码器,调整屏幕传输4位调色板....2.712008/3/28 11:01 : 修正视频对一些摄像头不兼容的bug,加入录像功能,修正服务端一个导致整体稳定性的bug,此版本历来最稳定的...不与前版本相兼容2008/4/16 01:28 : 屏幕算法加入热点跟踪,心跳包方式改用保活方式,优化网络内核,实际压缩测试2003服务器,超过4万台同时上线,服务端生成方式为文件尾追加配置信息,壳为upackDLL资源也用upack加了壳,脱壳后,可自由更改,导入,不影响使用,软件标题日期,不做改变,2.8是个好数字,改动了一些其它细节方面的问题2008/4/18 23:44 : 完美解决键盘记录重复记录等问题.2008/5/10 20:47 : 修正2003 R2下下载更新或者下载执行时造成服务器崩溃的BUG,以及更新后黑屏的BUG,发布3.02008/5/11 18:10 : 超时改为3分钟,采用双保活机制度,防止网络异常导致出现死连接, 致使务端无法上线的BUG,请不要再用旧版本,最近更新的都是一些致命问题2008/5/14 00:26 : 修正一些摄像头无法显示的BUG,发布3.2版本2008/5/16 02:48 : 更改服务端安装方式,以前的安装方式很不稳定,现在的更加稳定,在多种操作系统中测试通过,可以自定义服务显示名称,描述....3.42008/5/17 15:03 : 换心跳方式,对付任何情况下产生的死连接,安装删除更加稳定,发布3.52008/5/17 20:32 : 修正3.5恢复SSDT失败的BUG,一个小小的笔误,实在不好意思.请大家不要用旧版本了,些版本是历来最稳定的,旧版本BUG太多,看更新记录就知道了,下个版本出来会有很长时间,大家可以放心的用,更新周期会变长2008/5/22 17:11 : 偶再三思考下,开源,开源是最好的办法,我就开源.....我就不信了...3.6开源视频压缩支持的编码格式,按优先级排列:Microsoft H.263 Video CodecIntel Indeo(R) Video R3.2Microsoft MPEG-4 Video Codec V2Cinepak Codec by Radius声明下软件的安装方式:如果安装时发现有相同配置的服务端已经安装过,就不安装也不删除,跟鸽子一个原理,我是靠字串区别的2008/3/2 06:35 : 本着我们红狼写gh0st的初衷,一个共享,免费,的软件,到今天为止,算是对大家一个交代,新版本开发中,经小组内部讨论将此版本开源..装上VC6,打造属于你们自己的gh0st吧..我们不保留版权,任何信息,自由修改,多谢一直以来大家的支持,我们会继续努力的
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值