Server 开发指南¶
本指南介绍如何为IoM的Server组件进行开发和贡献。Server是IoM的核心数据处理和交互服务。
回到总览
返回开发者贡献指南 | 查看Client开发指南 | 查看Implant开发指南
环境配置¶
环境配置client与server完全一致, 按需取用
Go开发环境
版本要求: Go >= 1.20
推荐golang 1.20
golang 1.20是兼容Win7的最后一个版本
go version
protobuf环境
protobuf Go插件 (指定版本)
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.3.0
go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.34.1
参考官方文档
更多安装选项请参考 protobuf.dev/installation
项目设置
-
Fork并克隆仓库
git clone --recurse-submodules https://github.com/your-username/malice-network.git cd malice-network git remote add upstream https://github.com/chainreactors/malice-network.git
-
安装依赖
go mod tidy
-
生成protobuf文件 (如果修改了proto定义)
go generate ./client
-
编译server
go build ./server/
开发实践¶
扩展Proto协议¶
为了适用大部分场景中, 我们添加两个较为通用的proto。适配绝大部分场景, 如果可以满足你的需求, 请优先使用这两个proto
message Request {
string name = 1;
string input = 2;
repeated string args = 3;
map<string, string> params = 4;
bytes bin = 5;
}
message Response {
string output = 1;
string error = 2;
map<string, string> kv = 3;
repeated string array =4;
}
如果这两个通用的proto无法满足, 才需要考虑修改proto
- 修改proto文件
在proto/implant/implantpb/implant.proto
中添加新的message:
message NewCommand {
string param = 1;
}
将message添加到Spite的body oneof中:
message Spite {
// ... 其他字段
oneof body {
// ... 其他消息类型
NewCommand new_command = 999;
}
}
- 修改server常量
在helper/types/message.go
中添加:
MsgNewCommand MsgName = "new_command"
在buildSpite
中添加对应的message处理:
case *implantpb.NewCommand:
spite.Name = MsgNewCommand.String()
spite.Body = &implantpb.Spite_NewCommand{NewCommand: msg.(*implantpb.NewCommand)}
- 添加protobuf rpc
在proto/services/clientrpc/service.proto
中添加:
service MaliceRPC {
// ... 其他RPC
rpc NewCommandRpc(implantpb.NewCommand) returns (clientpb.Task);
}
添加新的RPC接口¶
Server端提供两种类型的RPC实现:普通RPC和流式RPC。
1. 普通RPC¶
适用于简单的请求-响应模式:
func (rpc *Server) NewCommand(ctx context.Context, req *implantpb.Request) (*clientpb.Task, error) {
greq, err := newGenericRequest(ctx, req)
if err != nil {
return nil, err
}
ch, err := rpc.asyncGenericHandler(ctx, greq)
if err != nil {
return nil, err
}
go greq.HandlerAsyncResponse(ch, types.MsgResponse)
return greq.Task.ToProtobuf(), nil
}
2. 流式RPC¶
适用于需要分块传输或实时数据流的场景:
Execute示例 (实时输出流):
func (rpc *Server) Execute(ctx context.Context, req *implantpb.ExecRequest) (*clientpb.Task, error) {
greq, err := newGenericRequest(ctx, req)
if err != nil {
return nil, err
}
if !req.Realtime {
// 非实时模式:普通RPC
ch, err := rpc.GenericHandler(ctx, greq)
if err != nil {
return nil, err
}
go greq.HandlerResponse(ch, types.MsgExec)
} else {
// 实时模式:流式RPC
greq.Count = -1 // 无限流
_, out, err := rpc.StreamGenericHandler(ctx, greq)
if err != nil {
return nil, err
}
go func() {
for {
resp := <-out
exec := resp.GetExecResponse()
// 验证响应
err := handler.AssertSpite(resp, types.MsgExec)
if err != nil {
greq.Task.Panic(buildErrorEvent(greq.Task, err))
return
}
// 处理响应
err = greq.HandlerSpite(resp)
if err != nil {
return
}
// 检查是否结束
if exec.End {
greq.Task.Finish(resp, "")
break
}
}
}()
}
return greq.Task.ToProtobuf(), nil
}
Listener开发¶
Listener与Server是解耦的,可以独立部署。开发新的Listener类型:
- 实现Pipeline接口
- 实现Parser接口
- 实现Cryptor接口
参考现有的TCP/HTTP实现进行开发。
todo¶
相关资源¶
- IoM设计文档 - 了解整体架构
- Proto仓库 - 协议定义
- Client开发指南 - 客户端开发
- Implant开发指南 - 植入物开发