馭龍HIDS是一款由 YSRC 開源的入侵檢測系統,由
Agent
,Daemon
,Server
和Web
四個部分組成,集異常檢測、監控管理爲一體,擁有異常行爲發現、快速阻斷、高級分析等功能,可從多個維度行爲信息中發現入侵行爲。
分析源碼首先了解代碼結構即目錄結構,瞭解各個目錄文件下的具體功能
GitHub 上已經給出相關文件的具體功能了。
首先分析agent功能,爲什麼要先分析agent呢,因爲最近自己在寫一個agent 的功能,先從它下手。
從入口文件agnet/anget.go 文件看
if len(os.Args) <= 1 {
fmt.Println("Usage: agent[.exe] ServerIP [debug]")
fmt.Println("Example: agent 8.8.8.8 debug")
return
}
開頭這段代碼主要功能是判斷 在運行agent文件中 是否輸入參數,未輸入參數時提示輸入信息並退出程序。
正常啓動命令是:./agent.ext 192.168.3.2 debug
os.Args 功能:
繼續往下看
if runtime.GOOS == "linux" {
out, _ := common.CmdExec(fmt.Sprintf("lsmod|grep syshook_execve"))
if out == "" {
common.CmdExec(fmt.Sprintf("insmod %s/syshook_execve.ko", common.InstallPath))
}
}
runtime.GOOS 功能
該方法的功能主要是返回當前程序執行環境所在的操作系統。
這段代碼主要功能:
如果agent在linux系統上運行時:
執行一段linux命令
lsmod|grep syshook_execve
主要用來查看syshook_execve這個模塊是否被載入了這個系統。syshook_execve 模塊後期再繼續深入研究。
如果查不到linux系統中如果沒有載入這個模塊,就使用命令載入。
var agent client.Agent
agent.ServerNetLoc = os.Args[1]
if len(os.Args) == 3 && os.Args[2] == "debug" {
log.Println("DEBUG MODE")
agent.IsDebug = true
}
agent.Run()
分析上面這段代碼
首先定義變量 類型爲 client.Agent,查看agent/client/agent.go 文件中Agent 結構
繼續分析 主文件代碼
agent.ServerNetLoc = os.Args[1]
os.Args[1] 存儲的是獲取的啓動命令:./agent.exe 192.168.192.13 debug 的ip地址。
後面if代碼判斷第三個參數 是否是debug,猜測應該是做是否開啓Debug模式標誌使用。
agent.Run() 執行Run方法,在agent/client/agent.go文件
// Run 啓動agent
func (a *Agent) Run() {
// agent 初始化
// 請求Web API,獲取Server地址,初始化RPC客戶端,獲取客戶端IP等
a.init()
// 每隔一段時間更新初始化配置
a.configRefresh()
// 開啓各個監控流程 文件監控,網絡監控,進程監控
a.monitor()
// 每隔一段時間獲取系統信息
// 監聽端口,服務信息,用戶信息,開機啓動項,計劃任務,登錄信息,進程列表等
a.getInfo()
}
Run方法中依次執行了4個方法
首先看init() 主要功能是初始化
Run是Agent 結構的方法。
init() 源碼
func (a *Agent) init() {
a.ServerList, err = a.getServerList()
if err != nil {
a.log("GetServerList error:", err)
panic(1)
}
a.ctx = context.WithValue(context.Background(), share.ReqMetaDataKey, make(map[string]string))
a.log("Available server node:", a.ServerList)
if len(a.ServerList) == 0 {
time.Sleep(time.Second * 30)
a.log("No server node available")
panic(1)
}
a.newClient()
if common.LocalIP == "" {
a.log("Can not get local address")
panic(1)
}
a.Mutex = new(sync.Mutex)
err := a.Client.Call(a.ctx, "GetInfo", &common.ServerInfo, &common.Config)
if err != nil {
a.log("RPC Client Call Error:", err.Error())
panic(1)
}
a.log("Common Client Config:", common.Config)
}
a.ServerList, err = a.getServerList()
調用a.getServerList() 方法,將返回值結果賦值給a.ServerList 。a是Agent結構。
a.ServerList表示存活服務端集羣列表。(馭龍應該是支持分佈式部署的,同時擁有多個服務接受端。防止大量agent併發的性能問題)
分析 a.getServerList() 方法
func (a Agent) getServerList() ([]string, error) {
var serlist []string
var url string
if TESTMODE {
url = "http://" + a.ServerNetLoc + SERVER_API
} else {
url = "https://" + a.ServerNetLoc + SERVER_API
}
a.log("Web API:", url)
request, _ := http.NewRequest("GET", url, nil)
request.Close = true
resp, err := httpClient.Do(request)
if err != nil {
return nil, err
}
defer resp.Body.Close()
result, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
err = json.Unmarshal([]byte(result), &serlist)
if err != nil {
return nil, err
}
return serlist, nil
}
該方法 不需要傳入參數,返回的是字符串型的切片。
首先聲明瞭一個 名爲 serlist的字符串型切片,其次定義了一個名爲url 的字符串。
判斷TESTMODE ,TESTMODE 爲常量。在agent/client/config.go中
bool類型,當前爲false。
如果爲false
url變量等於https+a.ServerNetloc+SERVER_API
a.ServerNetloc 上面已經分析過了,爲啓動命令的第一個參數,屬於IP地址。當我們輸入./agent.exe 127.0.01 debug 命令時
a.ServerNetloc = 127.0.0.1。SERVER_API 爲常量存儲在config.go 文件中,這段代碼執行下來結果爲:
url 變量 等於 https://127.0.0.1/json/serverlist
該判斷代碼塊主要作用是如果TESTMODE 爲true 服務端地址爲http,false爲https。
a.log("Web API:", url)
查看a.log代碼
如果啓動命令輸入了DEBUG 則。調用log.Println()函數並寫入數據
該功能屬於日誌記錄功能。運行後在控制檯輸出:
Web API: https://127.0.0.1/json/serverlist
主要功能顯示當前接口地址。
繼續分析剩下代碼邏輯,主要是請求https://127.0.0.1/json/serverlist 接口地址。
json/serverlist 接口在web目錄下,暫不做分析。
大致內容就是請求該接口返回一段json 字符串。
繼續回到a.init()方法
未完待續。。。。。