最强黑客库Blackbone使用教程

环境搭建

项目地址

https://github.com/DarthTon/Blackbone

项目介绍

作为Windows开发人员,经常遇到枚举进程、枚举模块、读写进程内存的操作;Windows安全开发人员更是会涉及注入、hook、操作PE文件、编写驱动。每次都要翻各种资料制造轮子,那么有没有好的开源库解决这个问题呢,目前知道的就Blackbone了,而且它的代码写的很好,完全可以作为教科书来用。

网上对于各种类型的封装库百分之99都是copy的这个项目,并且看雪很多大佬的项目都引用了其中的代码。由此可见,这个项目的重要性和牛逼程度就不言而喻了。

库内容包含

Process interaction(进程交互)
    操作PEB32/PEB64
    通过WOW64 barrier管理进程
Process Memory(进程内存)
    分配和释放虚拟内存
    改变内存保护属性
    读写虚拟内存
Process modules(进程模块)
    枚举所有进程加载的模块 (32/64 bit)
    获得导出函数地址
    获得主模块
    从模块列表中去除模块信息
    注入、卸载模块(支持 pure IL images)
    在WOW64进程中注入64位模块
    操作PE
Threads(线程)
    枚举线程
    创建和关闭线程
    获得线程退出码
    获得主线程
    管理 TEB32/TEB64
    join线程(等待线程退出)
    暂停、恢复线程
    设置、清除硬件断点
Pattern search
    特征码匹配(支持本进程和其他进程)
Remote code execution
    在远程进程中执行函数
    组装自己的代码并远程执行(shellcode注入)
    支持各种调用方式: cdecl/stdcall/thiscall/fastcall
    支持各种参数类型
    支持FPU
    支持在新线程或已经存在的线程中执行shellcode
Remote hooking
    通过软硬断点,在远程进程中hook函数
    Hook functions upon return(通过return挂钩函数)
Manual map features
    隐藏注入,支持x86和x64,注入任意未保护的进程,支持导入表和延迟导入等等特性,不一一列举了。
Driver features
    分配、释放、保护内存
    读写用户层、驱动层内存
    对于WOW64进程,禁用DEP
    修改进程保护标记
    修改句柄访问权限
    操作进程内存(如:将目标进程map到本进程等)
    隐藏已分配用户模式内存
    用户模式dll注入;手动mapping(手动加载模块)
    手动加载驱动

项目编译

需要安装下面几个组件

  1. sdk、wdk版本要相同10.0.17763.0
  2. cor.h文件及相关的mscoree.lib库找不到编译错误,需要安装.NET桌面开发
  3. VC++ 2017 Libs for Spectre (x86 and x64)
  4. Visual C++ ATL (x86/x64) with Spectre Mitigations

在这里插入图片描述

在这里插入图片描述

我用VS2017编译会报一个引用已删除函数的错误,找不到解决方案,就直接找人帮我编译了一份。

据说是最新版本只支持VS2019,如果要使用VS2017,需要选择其他分支代码。

项目集成

在这里插入图片描述

新建一个空项目
在这里插入图片描述

然后在项目目录下新建一个include文件夹

在这里插入图片描述

把src目录下的三个文件夹复制到include文件夹

在这里插入图片描述

上面三个文件夹的在引用头文件的时候需要用到,build里面存放的是已经编译好的lib库

在这里插入图片描述

接着包含lib库和头文件

#include <iostream>
#include "../include/BlackBone/Config.h"
#include "../include/BlackBone/Process/Process.h"
#include "../include/BlackBone/Process/MultPtr.hpp"
#include "../include/BlackBone/Process/RPC/RemoteFunction.hpp"
#include "../include/BlackBone/PE/PEImage.h"
#include "../include/BlackBone/Misc/Utils.h"
#include "../include/BlackBone/Misc/DynImport.h"
#include "../include/BlackBone/Syscalls/Syscall.h"
#include "../include/BlackBone/Patterns/PatternSearch.h"
#include "../include/BlackBone/Asm/LDasm.h"
#include "../include/BlackBone/localHook/VTableHook.hpp"
#include "../include/BlackBone/DriverControl/DriverControl.h"


#ifdef _DEBUG
#pragma comment(lib, "..\\include\\build\\Win32\\Debug\\BlackBone.lib")
#else
#pragma comment(lib, "..\\include\\build\\Win32\\Release\\BlackBone.lib")
#endif

使用命名空间

using namespace blackbone;

在这里插入图片描述

随意调用一个函数,即可编译通过。编译通过说明集成成功。

在这里插入图片描述

接着需要把build生成的三个文件拷贝到项目目录下,否则会报下面的错误

在这里插入图片描述

项目使用

下面讲解每一个模块的代码功能使用。

进程交互

根据进程名枚举所有进程ID
auto pids = Process::EnumByName(L"explorer.exe");
根据进程ID或进程名枚举进程信息
	auto procInfo = Process::EnumByNameOrPID(4596, L"");
	for (auto info : procInfo.result())
	{
		wcout << info.imageName << info.pid << info.threads.size();
	}
枚举所有进程
	auto all = Process::EnumByNameOrPID(0, L"");
	for (auto info : all.result())
	{
		wcout << info.imageName << "\t" << info.pid << info.threads.size() << endl;
	}
附加一个进程(打开进程),并获取相关信息
	Process process;
	vector<DWORD> vecPid = Process::EnumByName(L"QQ.exe");

	//附加一个进程
	if (!vecPid.empty()&&NT_SUCCESS(process.Attach(vecPid.front())))
	{
		//ProcessCore类
		ProcessCore& processCore = process.core();

		//进程WOW64信息
		Wow64Barrier barrier = process.barrier();

		//获取进程ID和进程句柄
		DWORD dwPid = processCore.pid();
		HANDLE hProcess = processCore.handle();

		//获取进程PEB
		PEB_T peb = {};
		ptr_t ptrPEB = processCore.peb(&peb);

		//获取进程的所有句柄
		for (HandleInfo handleInfo:process.EnumHandles().result())
		{
			wcout << handleInfo.name << handleInfo.handle << handleInfo.typeName << endl;
		}
启动并附加进程
	//启动并附加进程
	Process process;
	process.CreateAndAttach(L"D:\\InjectTool.exe", true);
	{
		//恢复进程
		process.Resume();

		//延迟100毫秒
		std::this_thread::sleep_for(std::chrono::milliseconds(100));
	}

进程模块管理

	//进程模块管理
	Process process;
	if (NT_SUCCESS(process.Attach(L"WeChat.exe")))
	{
		//模块管理
		ProcessModules& proModules = process.modules();

		//获取所有模块 包括x86跟x64模块
		auto mapModule = proModules.GetAllModules();

		//获取主模块
		ModuleDataPtr mainModule = proModules.GetMainModule();

		//主模块基地址
		module_t baseAddress = mainModule->baseAddress;

		//获取导出函数地址
		call_result_t<exportData> exportFunAddr = proModules.GetExport(L"kernel32.dll", "LoadLibraryW");
		if (exportFunAddr.success())
		{
			cout << "LoadLibraryW" << exportFunAddr->procAddress << endl;
		}

		//模块断链
		proModules.Unlink(mainModule);


		auto mapModule2 = proModules.GetAllModules();
        
        //注入模块
		call_result_t<ModuleDataPtr> ptr= proModules.Inject(L"E:\\Dll1.dll");

		//卸载模块
		proModules.Unload(ptr);
	}

里面有一个很牛逼的功能,模块断链,实测可行~

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oc7z6bW0-1642037164410)(Blackbone黑客库的使用.assets/image-20220112125146182.png)]

进程内存管理

	Process process;
	if (NT_SUCCESS(process.Attach(L"QQ.exe")))
	{
		//操作内存类
		ProcessMemory& memory = process.memory();

		//主模块
		ModuleDataPtr  mainModoulePtr = process.modules().GetMainModule();

		//PE头信息
		IMAGE_DOS_HEADER dosHeader = {};

		//读取内存 模块的开始信息是PE头信息
		//第一种方法
		memory.Read(mainModoulePtr->baseAddress, dosHeader);

		//第二种方法
		memory.Read(mainModoulePtr->baseAddress, sizeof(dosHeader),&dosHeader);

		//第三种方法
		call_result_t<IMAGE_DOS_HEADER> dosHeaderResult = memory.Read<IMAGE_DOS_HEADER>(mainModoulePtr->baseAddress);

		//改变内存读写属性
		if (NT_SUCCESS(memory.Protect(mainModoulePtr->baseAddress,sizeof(dosHeader), PAGE_READWRITE)))
		{
			//写内存第一种方法
			memory.Write(mainModoulePtr->baseAddress, dosHeader);

			//写内存第二种方法
			memory.Write(mainModoulePtr->baseAddress, sizeof(dosHeader),&dosHeader);
		}

		//分配内存
		call_result_t<MemBlock> memBlockResult = memory.Allocate(0x1000, PAGE_READWRITE);
		if (memBlockResult.success())
		{
			//写内存
			memBlockResult->Write(0x10, 12.0);
			//读内存
			memBlockResult->Read<double>(0x10, 0.0);
		}

		//枚举所有有效内存区域
		vector<MEMORY_BASIC_INFORMATION64> region = memory.EnumRegions();
	}

进程线程管理

	Process process;
	if (NT_SUCCESS(process.Attach(L"QQ.exe")))
	{
		//枚举所有线程
		vector<ThreadPtr> vecTheadPtr = process.threads().getAll();

		//获取主线程
		ThreadPtr mainThread = process.threads().getMain();

		//根据线程ID获取线程信息
		ThreadPtr threadPtr = process.threads().get(mainThread->id());

		//获取线程上下文
		CONTEXT_T ctx = {};
		if (threadPtr->GetContext(ctx, CONTEXT_FLOATING_POINT))
		{
            //这里设置Dr寄存器就可以清除硬件断点
            //......
			//设置线程上下文
			threadPtr->SetContext(ctx);
		}

		//等待线程退出
		threadPtr->Join(100);
	}

JIT汇编

AsmHelper32 asmPtr = AsmFactory::GetAssembler();
	IAsmHelper& a = *asmPtr;
	//生成函数代码
	a->GenPrologue();
	a->add(a->zcx, a->zdx);
	a->mov(a->zax, a->zdx);
	a.GenEpilogue();
	auto func = reinterpret_cast<uintptr_t(__fastcall*)(uintptr_t, uintptr_t)>(a->make());
	uintptr_t r = func(10, 5);

远程代码执行

	Process process;
	if (NT_SUCCESS(process.Attach(L"QQ.exe")))
	{
		//远程执行类
		RemoteExec& remoteExe = process.remote();

		//创建远程执行环境
		remoteExe.CreateRPCEnvironment(Worker_None, true);
		
		//获取导出函数地址
		call_result_t<exportData> GetModuleHandleWPtr = process.modules().GetExport(L"kernel32.dll", "GetModuleHandleW");
		if (GetModuleHandleWPtr.success())
		{
			//使用指定的入口点和参数创建新线程
			DWORD mod = remoteExe.ExecDirect(GetModuleHandleWPtr->procAddress, 0);

			AsmHelperPtr asmPtr = AsmFactory::GetAssembler();

			if (asmPtr)
			{
				blackbone::IAsmHelper& asmHelper = *asmPtr;
				asmHelper.GenPrologue();
				asmHelper.GenCall(static_cast<uintptr_t>(GetModuleHandleWPtr->procAddress), { nullptr }, blackbone::cc_stdcall);
				asmHelper.GenEpilogue();
				uint64_t result = 0;
				//创建新线程并在其中执行代码。 等待执行结束
				remoteExe.ExecInNewThread(asmHelper->make(), asmHelper->getCodeSize(), result);
			}

			//在主线程执行
			blackbone::ThreadPtr mainThreadPtr = process.threads().getMain();
			blackbone::AsmHelperPtr asmHelperPtr = blackbone::AsmFactory::GetAssembler();
			if (asmHelperPtr)
			{
				blackbone::IAsmHelper& asmHelper = *asmHelperPtr;
				asmHelper.GenPrologue();
				asmHelper.GenCall(static_cast<uintptr_t>(GetModuleHandleWPtr->procAddress), { nullptr }, blackbone::cc_stdcall);
				asmHelper.GenEpilogue();

				uint64_t result = 0;
				remoteExe.ExecInAnyThread(asmHelper->make(), asmHelper->getCodeSize(), result, mainThreadPtr);
			}

		}

	}

内存搜索匹配

	Process process;
	if (NT_SUCCESS(process.Attach(L"QQ.exe")))
	{
		//匹配模版
		PatternSearch ps{ 1,2,3,4,5,6,7,8,9 };
		//搜索结果
		vector<ptr_t> results;
		//内存搜索
		ps.SearchRemote(process, false, 0, results);
		
	}

上面的SearchRemote函数是远程搜索

BLACKBONE_API size_t Search( 
        uint8_t wildcard, 
        void* scanStart, 
        size_t scanSize, 
        std::vector<ptr_t>& out, 
        ptr_t value_offset = 0,
		size_t maxMatches = SIZE_MAX
        ) const;

另外还提供了一个Search函数支持本进程搜索吗,而且还支持通配符

远程函数调用

	Process process;
	if (NT_SUCCESS(process.Attach(L"QQ.exe")))
	{
		//1.简单直接调用
		//获取远程函数对象
		RemoteFunction<decltype(&MessageBoxW)> pMessageBoxW = MakeRemoteFunction<decltype(&MessageBoxW)>(process, L"user32.dll", "MessageBoxW");
		if (pMessageBoxW.valid())
		{
			//远程调用
			auto result = pMessageBoxW(HWND_DESKTOP, L"HelloWorld", L"Title", MB_OK);
		}

		//2.使用特定线程调用
		auto mainThread = process.threads().getMain();
		if (auto pIsGuiThread= MakeRemoteFunction<decltype(&IsGUIThread)>(process, L"user32.dll", "IsGUIThread"); pIsGuiThread && mainThread)
		{
			auto result = pIsGuiThread.Call({ FALSE }, mainThread);
			if (*result)
			{
			}

		}

		//3.给定参数调用
		if (auto pMultiByteToWideChar = blackbone::MakeRemoteFunction<decltype(&MultiByteToWideChar)>(process, L"kernel32.dll", "MultiByteToWideChar"))
		{
			auto args = pMultiByteToWideChar.MakeArguments({ CP_ACP, 0, "Sample text", -1, nullptr, 0 });
			std::wstring converted(32, L'\0');

			// Set buffer pointer and size manually
			args.set(4, blackbone::AsmVariant(converted.data(), converted.size() * sizeof(wchar_t)));
			args.set(5, converted.size());

			auto length = pMultiByteToWideChar.Call(args);
			if (length)
				converted.resize(*length - 1);
		}

	}

系统调用 只适用于x64

{
        uint8_t buf[32] = { };
        uintptr_t bytes = 0;

        NTSTATUS status = syscall::nt_syscall(
            syscall::get_index( "NtReadVirtualMemory" ),
            GetCurrentProcess(),
            GetModuleHandle( nullptr ),
            buf,
            sizeof(buf),
            &bytes
        );

        if (NT_SUCCESS( status ))
        {
        }
    }

dll隐藏注入

//隐藏注入dll 进程名 dll路径 适配32位和64位
void HideInject(const std::wstring& processName, const std::wstring& dllPath)
{
	vector<DWORD> vecPid = Process::EnumByName(processName);

	if (vecPid.empty())
	{
		MessageBoxA(0, "不存在目标进程", "提示", 0);
		return;
	}


	//首先要拿到目标进程的信息
	Process proc;
	proc.Attach(vecPid.front());

	//确保LdrInitializeProcess被调用
	proc.EnsureInit();

	//将PE文件映射到目标进程 1.PE文件路径 flags(手动映射导入函数) 回调函数
	auto image = proc.mmap().MapImage(dllPath, ManualImports, &MapCallback2);

	//获取导出函数地址
	auto g_loadDataPtr = proc.modules().GetExport(image.result(), "g_LoadData");

	//调用导出函数
	auto g_loadData = proc.memory().Read<DllLoadData>(g_loadDataPtr->procAddress);	
}

ManualMap模块的代码利用反射型dll注入的原理,将PE文件不借助LoadLibrary在目标进程中展开,从而实现隐藏注入。

https://github.com/DarthTon/Xenos

另外这个作者还有一个非常强大的注入工具,支持三种零环的注入方式和两种三环的注入。不过这个工具基本都已经被国外的各大游戏检测的死死的。

总结

这个项目功能看似很强大,包含有各个模块的封装。但实际使用的时候往往只会用到其中一两个模块的功能。我只需要里面的特征码搜索和dll隐藏注入这两个功能,然后顺便学习了一下其他模块。

没想到最后集成的时候,头文件之间互相包含依赖,而且数据类型都是作者自定义的。如果想拿出其中的一个模块,最后会因为头文件包含的问题,从而把整个工程代码都包含进来。

为了一个功能而把剩下几个不需要的模块代码也加进来实在是有点鸡肋。总的来说,学习价值拉满,实用性就不得而知了。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鬼手56

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值