1. 程式人生 > >【算法】Gh0st配置加密算法(異或、Base64)

【算法】Gh0st配置加密算法(異或、Base64)

異或 urn byte break down unsigned ltib else lower

1、前言

分析木馬程序常常遇到很多配置信息被加密的情況,雖然現在都不直接分析而是通過Wireshark之類的直接讀記錄。

2017年Gh0st樣本大量新增,通過對木馬源碼的分析還發現有利用Gh0st加密方式來傳播的源碼中的後門。

2、加密思路

  • 控制端:對字符串異或、移位、Base64編碼

  • 服務端:對字符串Base64解碼、移位、異或

3、實踐代碼

  • 加密編碼
// Base64編碼
static char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

int C模仿Gh0st加密上線地址Dlg::base64_encode(const void *data, int size, char **str)
{
    char *s, *p;
    int i;
    int c;
    const unsigned char *q;

    p = s = (char*)malloc(size * 4 / 3 + 4);
    if (p == NULL)
        return -1;
    q = (const unsigned char*)data;
    i = 0;
    for (i = 0; i < size;) {
        c = q[i++];
        c *= 256;
        if (i < size)
            c += q[i];
        i++;
        c *= 256;
        if (i < size)
            c += q[i];
        i++;
        p[0] = base64[(c & 0x00fc0000) >> 18];  //base64
        p[1] = base64[(c & 0x0003f000) >> 12];
        p[2] = base64[(c & 0x00000fc0) >> 6];
        p[3] = base64[(c & 0x0000003f) >> 0];
        if (i > size)
            p[3] = ‘=‘;
        if (i > size + 1)
            p[2] = ‘=‘;
        p += 4;
    }
    *p = 0;
    *str = s;
    return strlen(s);
}

// 加密函數
char * C模仿Gh0st加密上線地址Dlg::MyEncode(char *str)
{
    int     i, len;
    char    *s, *data;
    // 字符串長度
    len = strlen(str) + 1;
    // 開辟字符串相對應的內存空間
    s = (char *)malloc(len);
    // 將字符串拷貝到開辟出來的指針中
    memcpy(s, str, len);
    // 異或操作
    for (i = 0; i < len; i++)
    {
        s[i] ^= 0x19;
        s[i] += 0x86;
    }
    // Base64編碼
    base64_encode(s, len, &data);
    free(s);

    return data;
}
  • 解密編碼
// Base64密鑰
static char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

// 解碼密鑰
int C模仿Gh0st加密上線地址Dlg::pos(char c)
{
    char *p;
    for (p = base64; *p; p++)
        if (*p == c)
            return p - base64;
    return -1;
}

// Base64解碼
int C模仿Gh0st加密上線地址Dlg::base64_decode(const char *str, char **data)
{
    const char *s, *p;
    unsigned char *q;
    int c;
    int x;
    int done = 0;
    int len;
    s = (const char *)malloc(strlen(str));
    q = (unsigned char *)s;
    for (p = str; *p && !done; p += 4) {
        x = pos(p[0]);
        if (x >= 0)
            c = x;
        else {
            done = 3;
            break;
        }
        c *= 64;

        x = pos(p[1]);
        if (x >= 0)
            c += x;
        else
            return -1;
        c *= 64;

        if (p[2] == ‘=‘)
            done++;
        else {
            x = pos(p[2]);
            if (x >= 0)
                c += x;
            else
                return -1;
        }
        c *= 64;

        if (p[3] == ‘=‘)
            done++;
        else {
            if (done)
                return -1;
            x = pos(p[3]);
            if (x >= 0)
                c += x;
            else
                return -1;
        }
        if (done < 3)
            *q++ = (c & 0x00ff0000) >> 16;

        if (done < 2)
            *q++ = (c & 0x0000ff00) >> 8;
        if (done < 1)
            *q++ = (c & 0x000000ff) >> 0;
    }

    len = q - (unsigned char*)(s);

    *data = (char*)realloc((void *)s, len);

    return len;
}

// 解密函數
char* C模仿Gh0st加密上線地址Dlg::MyDecode(char *str)
{
    int     i, len;
    char    *data = NULL;
    len = base64_decode(str, &data);

    for (i = 0; i < len; i++)
    {
        data[i] -= 0x86;
        data[i] ^= 0x19;
    }
    return data;
}

然後就是加密解密界面的內容。

技術分享圖片

函數代碼:

  • 生成配置信息按鈕
void C模仿Gh0st加密上線地址Dlg::OnBnBuild()
{
    // TODO: 在此添加控件通知處理程序代碼
    UpdateData(TRUE);
    m_remote_host.Replace(L" ", L"");
    m_remote_port.Replace(L" ", L"");

    CString str = m_remote_host + ":" + m_remote_port;
    str.MakeLower();
    TCHAR * pWStrKey;         // 合並後的內容

    // 開辟數組
    pWStrKey = new TCHAR[str.GetLength() + 1];
    pWStrKey = str.GetBuffer(0);

    // 第一次 調用確認轉換後單字節字符串的長度,用於開辟空間
    int pSize = WideCharToMultiByte(CP_OEMCP, 0, pWStrKey, wcslen(pWStrKey), NULL, 0, NULL, NULL);
    // 單字符
    char* pCStrKey = new char[pSize + 1];
    // 第二次 調用將雙字節字符串轉換成單字節字符串
    WideCharToMultiByte(CP_OEMCP, 0, pWStrKey, wcslen(pWStrKey), pCStrKey, pSize, NULL, NULL);
    pCStrKey[pSize] = ‘\0‘;

    // 接收char*
    m_encode = MyEncode(pCStrKey);

    m_encode.Insert(0, L"AAAA");
    m_encode += "AAAA";

    UpdateData(FALSE);
}
  • 解密配置信息按鈕

void C模仿Gh0st加密上線地址Dlg::OnBnGetLoginInfo()
{
    // TODO: 在此添加控件通知處理程序代碼
    UpdateData(TRUE);


    // 1 獲取加密編輯控件裏的字符串
    int pSize = m_encode.GetLength() + 1;
    wchar_t * pStart, *pEnd;
    wchar_t strKey[] = L"AAAA";
    wchar_t strEncode[1024];

    // 拿到最開始的字符串,如果前面是AAAA就賦值到pStart
    pStart = wcsstr(m_encode.GetBuffer(0), strKey);
    // 前移動4個字節,也就是跳過AAAA
    pStart += 4;
    // 如果AAAA匹配不到把strKey,也就是AAAA賦值給pEnd
    pEnd = wcsstr(pStart, strKey);
    // 清空原先AAAA字符串
    wmemset(strEncode, 0, wcslen(pStart) + 1);
    // 取key值之間的內容,配置字符串 - 字符串長度,取前面的真實加密字符串
    wmemcpy(strEncode, pStart, pEnd - pStart);
    // 單字符
    char* pCStrKey = new char[wcslen(strEncode) + 1];
    // 調用將雙字節字符串轉換成單字節字符串
    WideCharToMultiByte(CP_OEMCP, 0, strEncode, wcslen(strEncode) + 1, pCStrKey, wcslen(strEncode) + 1, NULL, NULL);
    pCStrKey[pSize] = ‘\0‘;

    // 解密代碼
    m_decode = MyDecode(pCStrKey);


    UpdateData(FALSE);
}

4、實際效果

技術分享圖片

5、參考

gh0st3.6源碼分析(1)——木馬的生成

http://blog.csdn.net/hjxyshell/article/details/19094609

【算法】Gh0st配置加密算法(異或、Base64)