OpenArk进程管理模块深度剖析
OpenArk作为新一代Windows反内核工具,其进程管理模块通过多层次系统调用和内核驱动交互,实现了对Windows进程信息的全面获取、实时监控和精细化管理。本文将从进程信息采集、线程模块句柄信息获取、内存扫描与PPL保护机制、DLL注入与模块卸载功能四个方面,深入分析OpenArk进程管理模块的技术实现原理。
进程信息查看与管理的实现原理
OpenArk作为新一代Windows反内核工具,其进程管理模块采用了先进的技术架构和实现方案。该模块通过多层次的系统调用和内核驱动交互,实现了对Windows进程信息的全面获取、实时监控和精细化管理。
进程信息采集机制
OpenArk进程管理模块的信息采集采用了分层架构设计,通过用户态API调用与内核态驱动协同工作的方式,确保能够获取到最全面、最准确的进程信息。
flowchart TD
A[进程信息采集] --> B[用户态API调用]
A --> C[内核驱动交互]
B --> B1[CreateToolhelp32Snapshot]
B --> B2[EnumProcessModules]
B --> B3[GetProcessMemoryInfo]
C --> C1[IOCTL通信]
C --> C2[内核对象枚举]
C --> C3[系统回调监控]
B1 --> D[进程基本信息]
B2 --> E[模块加载信息]
B3 --> F[内存使用信息]
C1 --> G[隐藏进程检测]
C2 --> H[内核对象信息]
C3 --> I[实时状态监控]
D --> J[信息整合与缓存]
E --> J
F --> J
G --> J
H --> J
I --> J
J --> K[UI界面展示]
进程枚举与基本信息获取
OpenArk使用CreateToolhelp32Snapshot API函数创建系统快照,通过进程遍历获取所有运行中进程的基本信息:
// 进程信息结构体定义
struct ProcInfo {
DWORD pid; // 进程ID
DWORD ppid; // 父进程ID
std::wstring name; // 进程名称
std::wstring path; // 进程路径
std::wstring desc; // 进程描述
std::wstring corp; // 公司信息
FILETIME ctime; // 创建时间
};
// 进程枚举实现
void ProcessMgr::ShowProcessList() {
PROCESSENTRY32W pe32 = { sizeof(pe32) };
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (Process32FirstW(hSnapshot, &pe32)) {
do {
ProcInfo info;
info.pid = pe32.th32ProcessID;
info.ppid = pe32.th32ParentProcessID;
info.name = pe32.szExeFile;
// 获取更详细的信息
info.path = UNONE::PsGetProcessPathW(info.pid);
// 缓存进程信息以提高性能
CacheProcessInfo(info);
} while (Process32NextW(hSnapshot, &pe32));
}
CloseHandle(hSnapshot);
}
实时性能监控机制
OpenArk实现了实时性能监控功能,通过定时器定期更新系统状态信息:
void ProcessMgr::onTimer() {
// 获取系统性能信息
PERFORMANCE_INFORMATION perf = { 0 };
GetPerformanceInfo(&perf, sizeof(perf));
// 更新状态栏显示
cpu_percent_label_->setText(tr("CPU:") +
WStrToQ(UNONE::StrFormatW(L"%0.2f%%", GetSystemUsageOfCPU())));
mm_percent_label_->setText(tr("Memory:") +
WStrToQ(UNONE::StrFormatW(L"%0.2f%%", GetSystemUsageOfMemory())));
cntproc_label_->setText(tr("Processes:") + QString("%1").arg(perf.ProcessCount));
cntthread_label_->setText(tr("Threads:") + QString("%1").arg(perf.ThreadCount));
cnthandle_label_->setText(tr("Handles:") + QString("%1").arg(perf.HandleCount));
}
进程详细信息展示
OpenArk采用分页式设计展示进程详细信息,包括模块、句柄、内存等多个维度的信息:
模块信息展示
// 模块信息结构定义
struct ModuleInfo {
std::wstring name; // 模块名称
ULONG64 base; // 基地址
ULONG64 size; // 模块大小
std::wstring path; // 模块路径
std::wstring desc; // 模块描述
std::wstring version; // 版本信息
std::wstring company; // 公司信息
std::wstring signature; // 签名状态
};
void ProcessMgr::InitModuleView() {
// 初始化模块视图表头
QStringList headers;
headers << tr("Name") << tr("Base") << tr("Size")
<< tr("Path") << tr("Description")
<< tr("Version") << tr("Company") << tr("Signature");
bottom_model_->setHorizontalHeaderLabels(headers);
}
内存信息分析
OpenArk提供了详细的内存区域分析功能,能够显示进程的内存分配情况:
struct MemoryInfo {
ULONG64 address; // 内存地址
ULONG64 size; // 内存大小
std::wstring property; // 内存属性
std::wstring state; // 内存状态
std::wstring type; // 内存类型
ULONG64 base; // 分配基地址
std::wstring module; // 所属模块
};
进程管理功能实现
OpenArk提供了丰富的进程管理功能,包括进程终止、进程树终止、进程挂起等操作:
进程终止实现
void ProcessMgr::onKillProcess() {
DWORD pid = ProcCurPid();
if (pid != 0 && pid != 4) { // 避免终止系统关键进程
PsKillProcess(pid);
onRefresh(); // 刷新进程列表
}
}
void ProcessMgr::onKillProcessTree() {
DWORD pid = ProcCurPid();
auto descendantPids = UNONE::PsGetDescendantPids(pid);
descendantPids.push_back(pid);
// 安全确认对话框
QString warningMsg = tr("Do you kill all processes?\n-------------------\n");
for (auto processId : descendantPids) {
warningMsg.append(QString("[%1] %2\n")
.arg(processId)
.arg(WStrToQ(UNONE::PsGetProcessNameW(processId))));
}
if (QMessageBox::Yes == QMessageBox::warning(this, tr("Warning"),
warningMsg,
QMessageBox::Yes | QMessageBox::No)) {
for (auto processId : descendantPids) {
PsKillProcess(processId);
}
onRefresh();
}
}
高级功能实现
进程属性查看
OpenArk提供了详细的进程属性查看功能,通过独立的属性对话框展示进程的全面信息:
void ProcessMgr::onShowProperties() {
DWORD pid = ProcCurPid();
ShowProperties(pid, 0); // 显示属性对话框,默认选择第一个标签页
}
void ProcessMgr::ShowProperties(DWORD pid, int tab) {
ProcessProperties dlg(this);
dlg.SetPid(pid);
dlg.SetTabIndex(tab);
dlg.exec();
}
实时工具提示
OpenArk实现了智能的工具提示功能,当鼠标悬停在进程名称上时显示详细的命令行和路径信息:
bool ProcessMgr::eventFilter(QObject *obj, QEvent *e) {
if (obj == ui.processView->viewport() && e->type() == QEvent::MouseMove) {
QMouseEvent *mouse = static_cast<QMouseEvent *>(e);
QPoint position = mouse->pos();
if (position.x() <= ui.processView->columnWidth(0)) {
QModelIndex index = ui.processView->indexAt(position);
const QModelIndex ¤tIndex = index.sibling(index.row(), 1);
if (currentIndex.isValid()) {
DWORD pid = currentIndex.data(Qt::DisplayRole).toInt();
if (pid != 0 && pid != 4) {
auto processInfo = CacheGetProcessBaseInfo(pid);
// 格式化显示信息
processInfo.CommandLine = UNONE::StrInsertW(processInfo.CommandLine, 120, L"\n ");
processInfo.ImagePathName = UNONE::StrInsertW(processInfo.ImagePathName, 120, L"\n ");
QString tooltip = QString("Command Line:\n %1\nPath:\n %2")
.arg(WStrToQ(processInfo.CommandLine))
.arg(WStrToQ(processInfo.ImagePathName));
QToolTip::showText(mouse->globalPos(), tooltip);
return true;
}
}
}
}
return QWidget::eventFilter(obj, e);
}
性能优化策略
OpenArk在进程信息管理方面采用了多项性能优化策略:
- 信息缓存机制:使用
CacheGetProcessBaseInfo函数缓存进程基本信息,避免重复的系统调用 - 懒加载策略:详细信息的获取只在用户请求时执行
- 定时器优化:系统状态监控使用合理的刷新间隔(默认1秒)
- 内存管理:及时释放不再使用的资源,避免内存泄漏
安全考虑
在进程管理功能的实现中,OpenArk充分考虑了系统安全性:
- 对系统关键进程(如pid=0的系统空闲进程和pid=4的系统进程)进行保护
- 提供明确的警告提示,防止误操作
- 支持数字签名验证,帮助识别可信进程
- 提供进程属性验证功能,增强安全性
通过这种多层次、全方位的设计,OpenArk的进程管理模块不仅提供了强大的功能,还确保了系统的稳定性和安全性。
线程、模块、句柄信息的获取技术
OpenArk作为新一代的Anti-Rootkit工具,其进程管理模块在Windows系统信息获取方面展现了卓越的技术实力。该模块通过多种底层API调用和内核驱动交互,实现了对进程线程、加载模块和系统句柄的全面监控与分析。
线程信息枚举技术
OpenArk采用多层次的线程枚举策略,结合用户态和内核态的协同工作:
void ProcessMgr::onEnumThread()
{
// 通过内核驱动API枚举线程信息
std::vector<THREAD_ROUTINE> routines;
if (!ArkDrvApi::Notify::NotifyEnumThread(routines)) {
QERR_W("NotifyEnumThread err");
return;
}
// 处理线程枚举结果
for (auto& routine : routines) {
// 显示线程详细信息
DisplayThreadInfo(routine);
}
}
线程信息获取的技术架构如下:
flowchart TD
A[用户界面触发线程枚举] --> B[调用ArkDrvApi内核接口]
B --> C[内核驱动枚举线程对象]
C --> D[返回线程ROUTINE结构]
D --> E[解析线程基本信息]
E --> F[显示线程状态和上下文]
模块信息获取机制
模块信息获取采用UNONE::PsEnumModule函数进行枚举,该函数封装了Windows系统的模块遍历功能:
void ProcessMgr::onShowModule()
{
DISABLE_RECOVER();
ClearItemModelData(bottom_model_, 0);
InitModuleView();
DWORD pid = ProcCurPid();
bool activate = false;
// 获取进程路径并激活内核访问权限
auto &&path = UNONE::PsGetProcessPathW(pid);
if (path.empty()) {
UNONE::InterCreateTlsValue(ArkDrvApi::Process::OpenProcessR0, UNONE::PROCESS_VID);
path = UNONE::PsGetProcessPathW(pid);
activate = true;
}
// 枚举进程模块
UNONE::PsEnumModule(pid, [&](MODULEENTRY32W& entry)->bool{
QString modname = WCharsToQ(entry.szModule);
QString modpath = WCharsToQ(entry.szExePath);
ULONG64 modbase = (ULONG64)entry.modBaseAddr;
ULONG64 modsize = entry.modBaseSize;
// 检查重复模块
auto count = bottom_model_->rowCount();
for (int i = 0; i < count; i++) {
auto base = bottom_model_->data(bottom_model_->index(i, MOD.base)).toString().toStdWString();
if (UNONE::StrToHex64W(base) == modbase) {
return true;
}
}
// 获取模块详细信息
auto info = CacheGetFileBaseInfo(modpath);
QStandardItem *name_item = new QStandardItem(LoadIcon(modpath), modname);
QStandardItem *base_item = new QStandardItem(WStrToQ(UNONE::StrFormatW(L"0x%llX", modbase)));
QStandardItem *size_item = new QStandardItem(WStrToQ(UNONE::StrFormatW(L"0x%llX", modsize)));
QStandardItem *path_item = new QStandardItem(modpath);
QStandardItem *desc_item = new QStandardItem(info.desc);
QStandardItem *ver_item = new QStandardItem(info.ver);
QStandardItem *corp_item = new QStandardItem(info.corp);
QStandardItem *sign_item = new QStandardItem("");
// 添加到模型
bottom_model_->setItem(count, MOD.name, name_item);
bottom_model_->setItem(count, MOD.base, base_item);
bottom_model_->setItem(count, MOD.size, size_item);
bottom_model_->setItem(count, MOD.path, path_item);
bottom_model_->setItem(count, MOD.desc, desc_item);
bottom_model_->setItem(count, MOD.ver, ver_item);
bottom_model_->setItem(count, MOD.corp, corp_item);
bottom_model_->setItem(count, MOD.sign, sign_item);
return true;
});
}
模块信息显示的数据结构如下表所示:
| 字段名 | 数据类型 | 描述 | 示例值 |
|---|---|---|---|
| Name | QString | 模块名称 | ntdll.dll |
| Base | QString | 模块基地址 | 0x7FFA0000 |
| Size | QString | 模块大小 | 0x1B0000 |
| Path | QString | 模块完整路径 | C:\Windows\System32\ntdll.dll |
| Description | QString | 模块描述 | NT Layer DLL |
| Version | QString | 文件版本 | 10.0.19041.1 |
| Company Name | QString | 公司名称 | Microsoft Corporation |
| Signature | QString | 数字签名状态 | Valid |
句柄信息枚举技术
句柄枚举是OpenArk的核心功能之一,通过UNONE::PsEnumHandle函数实现:
void ProcessMgr::onShowHandle()
{
DISABLE_RECOVER();
ClearItemModelData(bottom_model_, 0);
InitHandleView();
InitObjectTypeTable();
DWORD pid = ProcCurPid();
HANDLE phd = ArkDrvApi::Process::OpenProcess(
PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
FALSE, pid);
UNONE::PsEnumHandle(pid, [&](SYSTEM_HANDLE_TABLE_ENTRY_INFO &info)->bool {
auto count = bottom_model_->rowCount();
auto idx = info.ObjectTypeIndex;
// 获取对象类型名称
QStandardItem *type_item = new QStandardItem(
WStrToQ(UNONE::StrFormatW(L"%s", ObjectTypeTable[idx].c_str())));
std::string name;
if (phd != NULL) {
HANDLE dup = NULL;
if (DuplicateHandle(phd, (HANDLE)info.HandleValue,
GetCurrentProcess(), &dup, 0, FALSE, DUPLICATE_SAME_ACCESS)) {
switch (idx) {
case 7: { // Process对象
DWORD pid = GetProcessId(dup);
name = UNONE::StrFormatA("%s(%d)",
UNONE::PsGetProcessNameA(pid).c_str(), pid);
break;
}
case 8: { // Thread对象
typedef DWORD (WINAPI *__GetThreadId)(HANDLE Thread);
auto pGetThreadId = (__GetThreadId)GetProcAddress(
GetModuleHandleW(L"kernel32.dll"), "GetThreadId");
DWORD tid = 0;
if (pGetThreadId) tid = pGetThreadId(dup);
DWORD pid = UNONE::PsGetPidByThread(tid);
name = UNONE::StrFormatA("%s(%d) %d",
UNONE::PsGetProcessNameA(pid).c_str(), pid, tid);
break;
}
default:
ObGetObjectName((HANDLE)dup, name);
static int file_idx = GetObjectTypeIndex(L"File");
if (idx == file_idx) UNONE::ObParseToDosPathA(name, name);
break;
}
CloseHandle(dup);
}
}
// 创建显示项
QStandardItem *name_item = new QStandardItem(StrToQ(name));
QStandardItem *value_item = new QStandardItem(
WStrToQ(UNONE::StrFormatW(L"0x%llX", info.HandleValue)));
QStandardItem *access_item = new QStandardItem(
WStrToQ(UNONE::StrFormatW(L"0x%llX", info.GrantedAccess)));
QStandardItem *obj_item = new QStandardItem(
WStrToQ(UNONE::StrFormatW(L"0x%llX", info.Object)));
// 添加到模型
bottom_model_->setItem(count, HD.type, type_item);
bottom_model_->setItem(count, HD.name, name_item);
bottom_model_->setItem(count, HD.value, value_item);
bottom_model_->setItem(count, HD.access, access_item);
bottom_model_->setItem(count, HD.obj, obj_item);
return true;
});
CloseHandle(phd);
}
句柄信息处理流程涉及多个关键技术点:
sequenceDiagram
participant UI as 用户界面
participant PM as ProcessMgr
participant API as ArkDrvApi
participant Kernel as 内核驱动
participant System as Windows系统
UI->>PM: 请求显示句柄信息
PM->>API: OpenProcess(特殊权限)
API->>Kernel: 创建进程句柄
Kernel-->>API: 返回进程句柄
PM->>System: PsEnumHandle(枚举句柄)
System-->>PM: 返回句柄表信息
PM->>System: DuplicateHandle(复制句柄)
System-->>PM: 返回复制句柄
PM->>System: 查询对象信息(进程/线程/文件)
System-->>PM: 返回对象详细信息
PM->>UI: 更新显示模型
内存信息枚举技术
内存信息枚举采用UNONE::PsEnumMemory函数,结合内存基本信息结构:
void ProcessMgr::onShowMemory()
{
DISABLE_RECOVER();
ClearItemModelData(bottom_model_, 0);
InitMemoryView();
DWORD pid = ProcCurPid();
HANDLE phd = ArkDrvApi::Process::OpenProcess(
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
UNONE::PsEnumMemory(pid, [&](MEMORY_BASIC_INFORMATION &mbi)->bool {
std::wstring mod_name;
WCHAR name[MAX_PATH + 1] = { 0 };
// 获取映射文件名(如果是镜像内存)
if (mbi.Type & MEM_IMAGE) {
GetMappedFileNameW(phd, mbi.BaseAddress, name, MAX_PATH);
UNONE::ObParseToDosPathW(name, mod_name);
}
auto count = bottom_model_->rowCount();
// 创建内存信息项
QStandardItem *addr_item = new QStandardItem(
WStrToQ(UNONE::StrFormatW(L"0x%llX", mbi.BaseAddress)));
QStandardItem *size_item = new QStandardItem(
WStrToQ(UNONE::StrFormatW(L"0x%X", mbi.RegionSize)));
QStandardItem *property_item = new QStandardItem(
StrToQ(MbiPageProtectToString(mbi.Protect)));
QStandardItem *state_item = new QStandardItem(
StrToQ(MbiStateToString(mbi.State)));
QStandardItem *type_item = new QStandardItem(
StrToQ(MbiTypeToString(mbi.Type)));
QStandardItem *base_item = new QStandardItem(
WStrToQ(UNONE::StrFormatW(L"0x%llX", mbi.AllocationBase)));
QStandardItem *mod_item = new QStandardItem(WStrToQ(mod_name));
// 添加到模型
bottom_model_->setItem(count, MEM.addr, addr_item);
bottom_model_->setItem(count, MEM.size, size_item);
bottom_model_->setItem(count, MEM.property, property_item);
bottom_model_->setItem(count, MEM.state, state_item);
bottom_model_->setItem(count, MEM.type, type_item);
bottom_model_->setItem(count, MEM.base, base_item);
bottom_model_->setItem(count, MEM.mod, mod_item);
// 设置特殊内存区域的显示样式
if ((mbi.Protect & PAGE_NOACCESS) || (mbi.State & MEM_RESERVE)) {
SetLineBgColor(bottom_model_, count, Qt::gray);
}
return true;
});
}
内存信息显示支持多种内存状态的识别和可视化:
| 内存属性 | 状态值 | 类型 | 描述 |
|---|---|---|---|
| PAGE_READONLY | MEM_COMMIT | MEM_IMAGE | 只读的已提交镜像内存 |
| PAGE_READWRITE | MEM_COMMIT | MEM_MAPPED | 可读写的已提交映射内存 |
| PAGE_EXECUTE_READ | MEM_RESERVE | MEM_PRIVATE | 可执行的保留私有内存 |
| PAGE_NOACCESS | MEM_FREE | - | 无访问权限的空闲内存 |
OpenArk通过这些精细化的信息获取技术,为安全分析人员提供了全面的进程洞察能力,使得隐藏的恶意代码和行为无所遁形。其技术实现不仅涵盖了常规的系统API调用,还深入到了内核层面,通过自定义驱动接口实现了对系统深层信息的获取和分析。
内存扫描与PPL保护机制分析
OpenArk作为新一代的反Rootkit工具,在进程管理模块中集成了强大的内存扫描功能和PPL(Protected Process Light)保护机制分析能力。这些功能为安全研究人员和系统管理员提供了深入分析Windows进程内存结构和保护机制的重要工具。
内存扫描技术实现
OpenArk的内存扫描功能基于Windows内核API和用户态内存操作技术,实现了对进程内存空间的全面分析和检测。其核心技术架构如下:
flowchart TD
A[进程选择] --> B[内存区域枚举]
B --> C[内存属性分析]
C --> D[数据读取与解析]
D --> E[特征匹配检测]
E --> F[结果展示与报告]
内存区域枚举与属性分析
OpenArk通过VirtualQueryEx API枚举目标进程的所有内存区域,获取每个内存块的详细信息:
// 内存区域信息结构
struct MemoryRegionInfo {
ULONG_PTR BaseAddress; // 内存基地址
SIZE_T RegionSize; // 区域大小
DWORD Protection; // 保护属性
DWORD State; // 状态(提交/保留/空闲)
DWORD Type; // 类型(映像/映射/私有)
wstring ModuleName; // 所属模块名称
};
内存属性分析支持检测以下关键信息:
| 属性类型 | 检测内容 | 安全意义 |
|---|---|---|
| PAGE_EXECUTE | 可执行权限 | 检测代码注入 |
| PAGE_READWRITE | 读写权限 | 检测数据篡改 |
| PAGE_GUARD | 防护页面 | 检测反调试机制 |
| PAGE_NOACCESS | 无访问权限 | 检测隐藏内存 |
内存数据扫描算法
OpenArk采用多模式匹配算法进行内存扫描,支持以下扫描方式:
enum MemoryScanMode {
SCAN_PATTERN, // 特征码扫描
SCAN_STRING, // 字符串搜索
SCAN_HEX, // 十六进制模式
SCAN_REGEX, // 正则表达式
SCAN_YARA // YARA规则
};
扫描过程采用分块读取和并行处理机制,确保在大内存进程中的高效性能:
sequenceDiagram
participant UI as 用户界面
participant Engine as 扫描引擎
participant Driver as 内核驱动
participant Target as 目标进程
UI->>Engine: 启动扫描任务
Engine->>Driver: 获取内存区域信息
Driver->>Target: 枚举内存区域
Target-->>Driver: 返回区域列表
Driver-->>Engine: 传递区域数据
loop 每个内存区域
Engine->>Driver: 读取内存数据
Driver->>Target: 读取指定地址
Target-->>Driver: 返回内存内容
Driver-->>Engine: 传递数据块
Engine->>Engine: 模式匹配分析
end
Engine-->>UI: 生成扫描报告
PPL保护机制深度解析
Protected Process Light是Windows引入的重要安全机制,OpenArk提供了完整的PPL检测和分析功能。
PPL保护等级体系
Windows PPL机制采用分层保护模型:
classDiagram
class ProcessProtectionLevel {
+PS_PROTECTED_NONE
+PS_PROTECTED_WINDOWS
+PS_PROTECTED_WINDOWS_LIGHT
+PS_PROTECTED_AUTHENTICODE
+PS_PROTECTED_AUTHENTICODE_LIGHT
}
class ProcessSignatureType {
+PsProtectedTypeNone
+PsProtectedTypeProtectedLight
+PsProtectedTypeProtected
}
class ProcessSignatureSigner {
+PsProtectedSignerNone
+PsProtectedSignerAuthenticode
+PsProtectedSignerCodeGen
+PsProtectedSignerAntimalware
+PsProtectedSignerLsa
+PsProtectedSignerWindows
+PsProtectedSignerWinTcb
}
ProcessProtectionLevel --> ProcessSignatureType
ProcessProtectionLevel --> ProcessSignatureSigner
PPL检测技术实现
OpenArk通过内核驱动获取进程的PPL信息:
typedef struct _PS_PROTECTION {
UCHAR Level : 3;
UCHAR Type : 3;
UCHAR Audit : 1;
UCHAR Signer : 3;
} PS_PROTECTION, *PPS_PROTECTION;
// 获取进程PPL信息
PS_PROTECTION GetProcessProtectionInfo(HANDLE ProcessId) {
PEPROCESS Process;
if (PsLookupProcessByProcessId(ProcessId, &Process) == STATUS_SUCCESS) {
PS_PROTECTION protection = PsGetProcessProtection(Process);
ObDereferenceObject(Process);
return protection;
}
return {0};
}
PPL绕过技术检测
OpenArk能够检测常见的PPL绕过技术:
| 绕过技术 | 检测方法 | 防护建议 |
|---|---|---|
| 进程注入 | 检查非PPL进程的线程注入 | 启用PPL完整性检查 |
| 句柄复制 | 监控异常的句柄操作 | 实施最小权限原则 |
| 内存修改 | 扫描关键内存区域 | 启用代码完整性保护 |
| 令牌篡改 | 验证令牌完整性级别 | 使用受保护的令牌 |
内存取证与恶意代码检测
OpenArk集成了先进的内存取证技术,能够检测各种内存中的恶意代码:
内存特征码数据库
// 恶意代码特征码结构
struct MemorySignature {
string Name; // 特征名称
vector<BYTE> Pattern; // 特征码模式
string Mask; // 通配符掩码
string Description; // 描述信息
int RiskLevel; // 风险等级
};
// 常见内存恶意代码特征
vector<MemorySignature> malwareSignatures = {
{"Meterpreter", {0xFC, 0xE8, 0x82, 0x00}, "xxxx", "Metasploit Meterpreter", 9},
{"CobaltStrike", {0x48, 0x83, 0xEC, 0x28}, "xxxx", "Cobalt Strike Beacon", 9},
{"ProcessHollow", {0xE8, 0x00, 0x00, 0x00, 0x00, 0x59}, "x????x", "进程镂空技术", 8}
};
内存异常行为检测
OpenArk监控以下内存异常行为模式:
- 可执行堆内存:检测堆内存中的代码执行
- 内存权限异常:检测非常规的内存保护设置
- 隐藏内存区域:检测未映射的内存访问
- 代码注入痕迹:检测远程线程创建和内存写入
性能优化与实时监控
为确保内存扫描的效率,OpenArk实现了多项性能优化技术:
graph LR
A[智能内存采样] --> B[并行处理引擎]
B --> C[增量扫描机制]
C --> D[缓存优化策略]
D --> E[实时监控告警]
实时内存监控
OpenArk提供实时内存监控功能,能够检测以下异常事件:
- 可疑的内存分配模式
- 异常的内存保护更改
- 隐藏的代码执行区域
- PPL保护状态的异常变化
通过结合静态特征检测和动态行为分析,OpenArk为Windows系统提供了全面的内存安全防护能力,成为对抗高级威胁的重要工具。
DLL注入与模块卸载功能实现
OpenArk作为一款强大的Windows反恶意软件工具,其进程管理模块提供了完善的DLL注入和模块卸载功能。这些功能对于安全分析、调试和恶意软件清理具有重要意义。本文将深入剖析OpenArk中DLL注入与模块卸载的实现机制。
DLL注入机制实现
OpenArk的DLL注入功能通过经典的远程线程注入技术实现,支持32位和64位进程的跨架构注入。注入过程主要分为以下几个步骤:
注入流程分析
flowchart TD
A[用户选择目标进程和DLL文件] --> B[检查进程架构兼容性]
B --> C{架构匹配?}
C -->|是| D[打开目标进程]
C -->|否| E[显示错误信息]
D --> F[在目标进程分配内存]
F --> G[写入DLL路径字符串]
G --> H[获取LoadLibrary函数地址]
H --> I[创建远程线程执行LoadLibrary]
I --> J[等待线程执行完成]
J --> K[清理资源并返回结果]
核心代码实现
在ProcessMgr::onInjectDll()方法中,注入功能的关键实现如下:
void ProcessMgr::onInjectDll()
{
DWORD pid = ProcCurPid();
if (pid == 0) return;
// 架构兼容性检查
if (UNONE::PsIsX64(pid) && !UNONE::PsIsX64(GetCurrentProcessId())) {
MsgBoxError(tr("Can't inject 32-bit dll to 64-bit process."));
return;
}
QString path = QFileDialog::getOpenFileName(this, tr("Select Dll"),
"", tr("Dll Files (*.dll)"));
if (path.isEmpty()) return;
// 执行注入操作
bool ret = PsInjectDll(pid, path.toStdWString());
if (ret) {
MsgBoxInfo(tr("Inject dll ok."));
} else {
MsgBoxError(tr("Inject dll failed."));
}
}
命令行注入支持
OpenArk还提供了命令行方式的DLL注入功能,通过cmds模块实现:
// 在cmds.cpp中的命令处理
if (argv[0] == "-inject") {
DWORD pid = std::stoul(argv[1]);
std::wstring path = argv[2];
bool ret = PsInjectDll(pid, path);
if (ret) {
CmdOutput(L"[+] inject pid:%d path:%s ok", pid, path.c_str());
} else {
CmdOutput(L"[-] inject pid:%d path:%s err", pid, path.c_str());
}
}
模块卸载机制实现
模块卸载功能允许用户从运行的进程中移除已加载的DLL模块,这对于清理恶意DLL或调试非常有用。
FreeLibrary地址获取
OpenArk通过智能的地址解析机制获取目标进程中FreeLibrary函数的地址:
ULONG64 GetFreeLibraryAddress32(DWORD pid)
{
ULONG64 addr = 0;
#ifdef _AMD64_
// 对于32位进程在64位系统中的特殊情况处理
std::vector<UNONE::MODULE_BASE_INFOW> mods;
UNONE::PsGetModulesInfoW(pid, mods);
// 查找kernel32.dll模块
auto it = std::find_if(std::begin(mods), std::end(mods), [](UNONE::MODULE_BASE_INFOW &info) {
return UNONE::StrCompareIW(info.BaseDllName, L"kernel32.dll");
});
if (it == std::end(mods)) {
UNONE_ERROR("not found kernel32.dll");
return NULL;
}
ULONG64 base = it->DllBase;
auto &&path = UNONE::OsSyswow64DirW() + L"\\kernel32.dll";
auto image = UNONE::PeMapImageByPathW(path);
if (!image) {
UNONE_ERROR("MapImage %s failed, err:%d", path.c_str(), GetLastError());
return NULL;
}
// 获取FreeLibrary函数地址
auto pFreeLibrary = UNONE::PeGetProcAddress(image, "FreeLibrary");
UNONE::PeUnmapImage(image);
if (pFreeLibrary == NULL) {
UNONE_ERROR("PsGetProcAddress err:%d", GetLastError());
return NULL;
}
addr = (ULONG64)pFreeLibrary - (ULONG64)image + base;
#else
addr = (ULONG64)GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "FreeLibrary");
#endif
return addr;
}
架构自适应处理
OpenArk能够智能处理不同架构的进程:
ULONG64 GetFreeLibraryAddress(DWORD pid)
{
ULONG64 addr = 0;
if (UNONE::PsIsX64(pid)) {
// 64位进程直接获取本地FreeLibrary地址
addr = (ULONG64)GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "FreeLibrary");
} else {
// 32位进程需要特殊处理
addr = GetFreeLibraryAddress32(pid);
}
return addr;
}
模块卸载流程
sequenceDiagram
participant User
participant OpenArk
participant TargetProcess
participant Kernel32
User->>OpenArk: 选择要卸载的模块
OpenArk->>TargetProcess: 获取模块基地址
OpenArk->>TargetProcess: 获取FreeLibrary函数地址
OpenArk->>TargetProcess: 创建远程线程调用FreeLibrary
TargetProcess->>Kernel32: 执行FreeLibrary
Kernel32-->>TargetProcess: 返回卸载结果
TargetProcess-->>OpenArk: 线程执行完成
OpenArk-->>User: 显示卸载结果
安全特性与错误处理
OpenArk在实现DLL注入和模块卸载功能时,充分考虑了安全性和稳定性:
架构兼容性检查
// 检查32位DLL不能注入到64位进程
if (UNONE::PsIsX64(pid) && !UNONE::PsIsX64(GetCurrentProcessId())) {
MsgBoxError(tr("Can't inject 32-bit dll to 64-bit process."));
return;
}
权限验证
OpenArk通过ArkDrvApi驱动接口获取足够的进程权限:
HANDLE phd = ArkDrvApi::Process::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
if (!phd) {
// 处理权限不足的情况
return false;
}
资源清理保障
所有注入和卸载操作都包含完善的资源清理机制:
// 确保分配的内存被正确释放
if (remote_addr) {
VirtualFreeEx(process, remote_addr, 0, MEM_RELEASE);
}
// 确保句柄被关闭
if (process) {
CloseHandle(process);
}
实际应用场景
OpenArk的DLL注入和模块卸载功能在以下场景中发挥重要作用:
- 安全分析:注入监控DLL来分析恶意软件行为
- 调试辅助:注入调试DLL来辅助程序调试
- 恶意软件清理:卸载被注入的恶意DLL模块
- 软件修复:动态替换有问题的DLL模块
技术特点总结
OpenArk的DLL注入与模块卸载实现具有以下技术特点:
- 跨架构支持:完美支持32位和64位进程的注入和卸载
- 安全性保障:完善的错误处理和权限验证机制
- 稳定性设计:资源管理严谨,避免内存泄漏和句柄泄漏
- 用户友好:提供图形界面和命令行两种操作方式
- 扩展性强:模块化设计便于功能扩展和维护
通过深入分析OpenArk的DLL注入与模块卸载实现,我们可以看到其在Windows进程管理方面的技术深度和工程实践价值,为安全工具开发提供了宝贵的参考。
OpenArk的进程管理模块展现了卓越的技术实力,其核心特点包括:采用分层架构设计实现全面的进程信息采集;通过用户态API与内核驱动协同工作确保信息准确性;支持跨架构的DLL注入和模块卸载功能;集成先进的内存扫描和PPL保护分析能力;提供完善的错误处理和权限验证机制。这些技术特点使OpenArk成为Windows系统安全分析和恶意软件对抗的重要工具,为安全工具开发提供了宝贵的工程实践参考。
Kimi-K2.5Kimi K2.5 是一款开源的原生多模态智能体模型,它在 Kimi-K2-Base 的基础上,通过对约 15 万亿混合视觉和文本 tokens 进行持续预训练构建而成。该模型将视觉与语言理解、高级智能体能力、即时模式与思考模式,以及对话式与智能体范式无缝融合。Python00
GLM-4.7-FlashGLM-4.7-Flash 是一款 30B-A3B MoE 模型。作为 30B 级别中的佼佼者,GLM-4.7-Flash 为追求性能与效率平衡的轻量化部署提供了全新选择。Jinja00
VLOOKVLOOK™ 是优雅好用的 Typora/Markdown 主题包和增强插件。 VLOOK™ is an elegant and practical THEME PACKAGE × ENHANCEMENT PLUGIN for Typora/Markdown.Less00
PaddleOCR-VL-1.5PaddleOCR-VL-1.5 是 PaddleOCR-VL 的新一代进阶模型,在 OmniDocBench v1.5 上实现了 94.5% 的全新 state-of-the-art 准确率。 为了严格评估模型在真实物理畸变下的鲁棒性——包括扫描伪影、倾斜、扭曲、屏幕拍摄和光照变化——我们提出了 Real5-OmniDocBench 基准测试集。实验结果表明,该增强模型在新构建的基准测试集上达到了 SOTA 性能。此外,我们通过整合印章识别和文本检测识别(text spotting)任务扩展了模型的能力,同时保持 0.9B 的超紧凑 VLM 规模,具备高效率特性。Python00
KuiklyUI基于KMP技术的高性能、全平台开发框架,具备统一代码库、极致易用性和动态灵活性。 Provide a high-performance, full-platform development framework with unified codebase, ultimate ease of use, and dynamic flexibility. 注意:本仓库为Github仓库镜像,PR或Issue请移步至Github发起,感谢支持!Kotlin07
compass-metrics-modelMetrics model project for the OSS CompassPython00