Quick Start

在这一章, 我们将制作一个Local类型的Plugin, 并理解PumpBin的工作原理.

Local类型的Plugin, shellcode在最终植入物内部存放. 这种方式有一定的稳定性优势, 但是shellcode容易被提取分析.

PumpBin将读取shellcode文件, 并根据加密设置将加密后的shellcode动态patch到二进制植入物模板内, 加密所使用的随机密码也会一同patch.

所以PumpBin本质上是一个二进制数据搜索替换工具, 这种实现方式要求预先在二进制植入物内放置占位数据, 一旦编译完成, 占位数据长度将不可更改.

一般情况下, 我们会让shellcode占位数据长度比所需要的稍大一些(如果你知道将要使用的shellcode长度), 这有两个原因:

  1. 为了更大的兼容性(如果Plugin shellcode占位数据长度小于加密后的shellcode长度, Plugin将无法用于此shellcode)
  2. 多出的占位数据并非无用, PumpBin将用随机数据填充, 保证每次生成的植入物都是唯一的

制作二进制植入物模板

我将使用rust-shellcode中的create_thread作为加载代码.

克隆rust-shellcode

git clone --depth 1 https://github.com/b1nhack/rust-shellcode.git

进入create_thread目录

cd rust-shellcode
cd create_thread

编译运行, 测试是否成功加载演示shellcode
默认会运行w64-exec-calc-shellcode-func.bin, 你应该看到calc程序被启动.

cargo r

我们需要使用shellcode占位数据替换w64-exec-calc-shellcode-func
create_thread目录下创建build.rs, 并粘贴以下代码

use std::{fs, iter};

fn main() {
    let mut shellcode = "$$SHELLCODE$$".as_bytes().to_vec();
    shellcode.extend(iter::repeat(b'0').take(1024 * 1024));
    fs::write("shellcode", shellcode.as_slice()).unwrap();
}

这样我们会生成一个大约1MiB的占位数据, 并且由$$SHELLCODE$$开头(我们称其为Prefix, PumpBin使用它来定位占位数据, 所以Prefix需要保持唯一, PumpBin会使用第一个匹配结果).

将main.rs第11行替换为下面的代码, 使其包含占位数据

let shellcode = include_bytes!("../shellcode");

由于shellcode后会填充随机数据, 我们需要知道shellcode的长度, 以正确取出shellcode.

在main.rs 11行代码后添加以下代码

const SIZE_HOLDER: &str = "$$99999$$";
let shellcode_len = usize::from_str_radix(SIZE_HOLDER, 10).unwrap();
let shellcode = &shellcode[0..shellcode_len];

我们添加了一个常量字符串引用, $$99999$$也是一个Prefix, 不过我们更喜欢称其为Place Holder, 因为它将被完全替换. (Prefix会以有效数据+随机数据的形式完全替换, 而Place Holder会以有效数据完全替换)

有了shellcode的长度信息, 我们可以获取到正确的shellcode, 编译修改后的create_thread项目, 我们将得到一个简单的二进制植入物模板

cargo b -r

制作Plugin

现在我们有了一个简单的二进制植入物模板, 我们可以使用PumpBin Maker制作一个只包含Windows Exe的Plugin

Plugin Name填写first_plugin. (这个字段是Plugin的唯一标识, 这意味着用户无法同时安装两个同名的Plugin)

Prefix填写$$SHELLCODE$$. (这是我们上面shellcode占位数据的Prefix, 你可以使用任何你喜欢的Prefix, 只要确保它是唯一的, 或者是第一个被匹配的)

Max Len填写shellcode占位数据的总大小, 在这个例子中应该是 1024*1024 + Prefix的大小 = 1048589. (单位是Bytes)

Type选择Local, Size Holder填写$$99999$$. (这是我们上面用来确定shellcode长度的常量字符串引用, 你可以使用任何你喜欢的Size Holder, 规则同上)

Windows Exe选择我们上面编译好的二进制植入物模板. (也可以直接填写文件路径)

点击Generate, 保存生成的b1n文件

测试Plugin

用PumpBin安装制作的Plugin, 并使用w64-exec-calc-shellcode-func生成一个最终植入物, 运行应该看到calc程序被启动.

至此, 我们制作了一个Local类型的Plugin, 并理解了PumpBin的工作原理.

下一章将介绍PumpBin中的加密系统, 加密过程对用户透明, 由Plugin开发者决定, 由PumpBin处理.

本例中的完整项目文件在PumpBin代码仓库的examples/create_thread.