1.恶意代码或者恶意程序常用的行为或者方式有哪些?
恶意代码/恶意程序常见的行为方式主要包括以下几类:
- 持久化:
- 注册表自启动 (
Run,Services) - 创建计划任务、服务或驱动
- 篡改系统文件或劫持 DLL/进程
- 注册表自启动 (
- 自我保护与隐蔽:
- 加壳、混淆、反调试、反虚拟机
- Rootkit 技术隐藏进程、文件、注册表
- 信息收集:
- 窃取账号、密码、浏览器缓存
- 键盘记录、屏幕截图、网络嗅探
- 传播与控制:
- 利用漏洞、钓鱼邮件、自传播(蠕虫)
- 与 C2 服务器通信、接收远控指令
- 破坏与牟利:
- 删除或加密文件(勒索)
- 注入挖矿、广告、木马下载器
- 干扰系统运行(破坏数据或拒绝服务)
深入细节:
- 启动持久化机制:
除了注册表,还可以通过 DLL 劫持(AppInit_DLLs、KnownDlls)、WMI 事件订阅、Office 宏感染、计划任务、服务安装等方式长期驻留。 - 进程注入与权限提升:
常见手法包括CreateRemoteProcess + WriteProcessMemory + CreateRemoteThread,以及利用 Token 窃取、UAC 绕过提权。 - 混淆与规避检测:
包括代码混淆、API 动态解析、反沙箱检测(检测文件名、硬件特征)、利用签名白加黑(合法签名+恶意 DLL)。 - 常见恶意功能:
- 窃密(Cookie、证书、密码、浏览器数据)
- 挖矿(利用 GPU/CPU)
- DDoS 攻击或 Botnet 控制
- 下载器行为(Dropper/Loader)
- 对抗手段:
使用 hook/inline patching 绕过安全产品,禁用杀软服务(net stop,sc delete),以及利用漏洞逃逸沙箱。
2.假如有一个POC文件,但是会出现这样的问题,就是你打开这个文件,它会创建子进程后马上就崩溃掉,如果让你去调试你会怎么去调试
如果一个 POC 文件打开后创建子进程马上崩溃,我会:
- 监控进程创建:用 Process Monitor / Process Explorer 确认子进程路径、参数。
- 挂调试器:对父进程和子进程都附加(WinDbg/ x64dbg),或设置
Image File Execution Options自动附加。 - 使用调试技巧:设置断点在
CreateProcess*相关 API,或者用gflags +e childdbg让调试器自动附加到子进程。 - 捕获崩溃点:分析异常类型(访问冲突、堆栈溢出、异常指令等)并 dump 内存。
详细调试思路
- 确认子进程信息
- 用
Process Monitor或procmon过滤 “Process Create”,获取子进程路径、命令行。 - 看是否是临时文件(POC 常释放临时 exe)。
- 用
- 调试子进程启动
- 用
WinDbg设置 调试子进程:gflags /p /enable target.exe /full gflags /p /enable target.exe +ksl gflags /i target.exe +inheritdbg - 或者在 WinDbg 中:
.childdbg 1 ; 自动调试子进程 - 如果用 x64dbg,可在 “Options → Preferences → Events” 里启用 “Break on new process”。
- 用
- 捕获崩溃点
- 设置断点:
bp kernel32!CreateProcessW bp ntdll!NtCreateUserProcess - 跟踪子进程初始化,查看入口点代码是否有异常指令。
- 设置断点:
- 分析原因
- 看是否因为 POC 恶意 Payload 触发漏洞导致 crash(比如堆溢出)
- 检查是否需要特定环境(DLL、依赖文件),缺失也会导致崩溃。
- 额外技巧
- 用
dump保存崩溃前状态:.dump /ma crash.dmp - 如需让程序暂停方便附加,可打补丁(NOP 出现崩溃前的指令)或用
Sleep()Hook 暂停执行。
- 用
3.像Messagebox这样的函数,vs或者系统是如何找到最后的执行函数的,像什么MessageboxA,MessageboxW
像 MessageBox 这样的 API,系统通过 函数名映射和导入表解析 找到最终执行的函数:
- 在源码中写
MessageBox,编译器通过头文件/宏定义将其映射为MessageBoxW(Unicode)或MessageBoxA(ANSI)。 - 链接器把调用指向
User32.dll的导出函数(通过导入表 IAT)。 - 程序加载时,Windows Loader 解析 IAT,把导入的符号指向
User32.dll中真实函数地址。 - 运行时,调用的是
user32!MessageBoxW或user32!MessageBoxA,最终底层还会转到user32.dll内部的系统调用(最终下层是ntdll和win32k.sys内核模块)。
详细深入
- 头文件/宏替换阶段
windows.h中:#ifdef UNICODE #define MessageBox MessageBoxW #else #define MessageBox MessageBoxA #endif- 所以
MessageBox()会自动替换成MessageBoxW或MessageBoxA,具体取决于项目是否定义UNICODE宏。
- 链接阶段(静态到动态)
- 编译器生成对
__imp__MessageBoxW@16(导入符号)的引用。 - 链接器将符号放入程序的 Import Address Table (IAT),声明依赖
User32.dll。
- 编译器生成对
- 加载阶段(运行时绑定)
- 程序启动时,Windows Loader 加载
user32.dll,在其导出表找到MessageBoxW的地址。 - 把这个地址写入程序的 IAT,对应的函数指针就能直接跳到实际实现。
- 程序启动时,Windows Loader 加载
- 运行时执行
- 当程序执行
MessageBox()时,其实跳转到 IAT 指针指向的地址 →user32!MessageBoxW→ 内部再调用NtUserMessageBox这样的系统调用 → 最终在win32k.sys内核模块中渲染对话框。
- 当程序执行
- 动态查找的另一种方式
- 如果没有在 IAT 中声明,也可以用
LoadLibrary+GetProcAddress("MessageBoxW")手动获取地址,然后调用。
- 如果没有在 IAT 中声明,也可以用
4.假如给你50个样本,你会如何快去排查恶意的样本
拿到 50 个样本时,我会先用 自动化+静态筛选,再做 重点动态分析:
- 快速特征扫描:用杀软引擎、YARA、VT API 批量查杀过滤已知恶意文件。
- 静态分析:批量解析 PE(检查导入表、签名、可疑字符串、混淆、壳),找出异常样本。
- 沙箱/虚拟机批跑:用自动化工具(Cuckoo、Any.Run)跑一遍,筛出有明显恶意行为(网络连接、注册表修改、进程注入)的样本。
- 重点手动分析:只对高风险样本手动调试/反编译,确认行为。
详细
- 自动化初筛
- 用
hash + VirusTotal批量查询(脚本自动化 API),直接剔除无害/已知文件。 - YARA 扫描(检测恶意代码段、C2 域名、壳特征)。
- 统计学方法:查看 PE 的入口点熵值(高混淆或壳的优先分析)。
- 用
- 静态特征分析
- 提取 导入函数(如
CreateRemoteThread,VirtualAllocEx,WinExec)。 - 检查数字签名、编译时间、节区异常(额外的
CODE,.UPX, 超大资源节)。 - 抽取可疑字符串(域名、注册表键、命令行参数)。
- 提取 导入函数(如
- 动态沙箱分析
- 在隔离环境下用 自动化沙箱 跑全部样本,收集:
- 文件/注册表修改
- 新进程/注入
- 网络流量(C2 连接、加密流量)
- 根据行为分级:明显恶意(加密文件/下载器)直接标记,高可疑(注入、持久化)进入手动分析。
- 在隔离环境下用 自动化沙箱 跑全部样本,收集:
- 重点手动分析
- 对优先级最高的样本:
- IDA 静态反编译,确认主要逻辑
- x64dbg/WinDbg 动态调试,观察 API 调用栈
- 分析 Payload 是否有下载器/后门
- 对优先级最高的样本:
- 出结论
- 每个样本生成分析报告,重点样本详细说明恶意行为。
追问:如何提速?
- 用 Python 写脚本批量提取 PE 信息(导入表、节区、哈希)
- 自动化调用沙箱 API 批量提交
- 用 YARA/ClamAV 扫描未知恶意家族特征
- 先聚合样本哈希去重,避免重复分析
5.如何使用hook技术
基本回答
Hook 技术就是拦截程序或系统 API 的调用,插入自己的代码以改变行为。常用方法:
- API Hook(用户态):
- IAT Hook:修改进程 Import Address Table,把函数指针改为自己的函数。
- EAT Hook:修改 DLL Export Table,改变导出函数地址。
- Inline Hook:在目标函数入口写跳转指令(
JMP),重定向到自定义代码。
- 内核 Hook:
- 修改 SSDT、IRP 或 Inline Patch 来截获系统调用(需要驱动)。
- 使用场景:
- 安全软件(监控 API 调用)
- 调试器(拦截特定函数)
- 恶意软件(隐藏、绕过、注入)
详细
- IAT Hook(Import Address Table)
- 每个 PE 文件都有 IAT,存储外部 API 的地址。
- 修改对应的 IAT 表项,把原本指向
MessageBoxW的指针改成我们自己的函数地址。 - 调用时先进入我们的代码,再决定是否转到原始 API。
- EAT Hook(Export Address Table)
- 在 DLL 的导出表里直接修改导出函数指针,比如修改
user32.dll的导出表,让其他进程加载时调用我们函数。
- 在 DLL 的导出表里直接修改导出函数指针,比如修改
- Inline Hook(代码补丁法)
- 在目标函数入口写入
JMP(5 字节),跳到我们的代码:push eax mov eax, MyFunction jmp eax - 我们的函数执行后,再跳回原函数(Trampoline 技术)。
- 在目标函数入口写入
- 内核 Hook
- 修改 SSDT(系统服务分发表)或驱动对象的回调,拦截系统调用(如
NtCreateFile)。 - 需要驱动签名,Windows 10 之后对 SSDT Hook 有保护(PatchGuard)。
- 修改 SSDT(系统服务分发表)或驱动对象的回调,拦截系统调用(如
- 实际开发中常用库
- Microsoft Detours
- MinHook
- EasyHook
追问:安全角度?
- Hook 技术既能做安全监控(杀毒、调试),也能被恶意软件用来隐藏进程、劫持 API。
- 内核 Hook 高版本 Windows 会触发 PatchGuard,需要用官方回调机制(ObRegisterCallbacks、Filter Manager)。
恶意的PEdll文件肯定是加密的,解密后他是如何写入进内存然后执行的呢?
解密后的 DLL 手工加载流程
一般可以分成 五大步骤:
1. 分配内存用于承载解密后的 PE 映像
c复制编辑LPVOID base = VirtualAlloc(NULL, size_of_image, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE);
- 分配一块足够大的连续内存。
- 大小通常等于
OptionalHeader.SizeOfImage。 - 权限设为
PAGE_EXECUTE_READWRITE,方便后续写入和执行。
2. 将各个 PE Section 复制到对应的内存位置
c复制编辑// 解析 PE 头(IMAGE_DOS_HEADER, IMAGE_NT_HEADERS)
for each section in SectionHeaders:
memcpy(base + section.VirtualAddress, encrypted_image + section.PointerToRawData, section.SizeOfRawData);
- 从解密得到的 DLL 数据中,按照节(
.text,.rdata,.data等)逐段拷贝。 - 这相当于手动完成
LoadLibrary做的事情。
3. 处理导入表和重定位(非常关键)
c复制编辑// 1) 修复重定位(如果加载地址 != PreferredBase)
apply_base_relocations(base, delta);
// 2) 解析导入表,加载依赖模块并填充 IAT
for each import_dll in ImportTable:
HMODULE h = LoadLibraryA(import_dll);
for each function in import_dll:
proc = GetProcAddress(h, function_name);
write_to_IAT(base, proc);
- 修复因为加载基址不同带来的地址偏移。
- 动态解析所有依赖函数地址填入 IAT。
- 这是标准 PE 装载流程,但在恶意 Loader 里手工完成,避开 API 监控。
4. 设置节区权限并准备执行
c复制编辑// 将 .text 设为 RX, .data 设为 RW
VirtualProtect(base + section.VirtualAddress, section.SizeOfRawData, section.Characteristics, &oldProtect);
- 防止以后写入,避免被检测为可写可执行内存。
5. 调用 DLL 的入口点执行
c复制编辑// 入口点通常是 DllMain
DllEntry entry = (DllEntry)(base + OptionalHeader.AddressOfEntryPoint);
entry(base, DLL_PROCESS_ATTACH, NULL);
- 直接跳转到入口点,执行 DLL 初始化逻辑。
- 这一步通常是通过函数指针间接调用(避免静态分析,CFG 防护)。
恶意 Loader 的一些技巧
- 解密内存即加载:很多样本只解密当前需要的 Section,执行后立即擦除或再次加密,防止内存取证。
- 使用
_guard_dispatch_icall_fptr(你看到的函数):- 通过 Control Flow Guard 的间接调用执行入口,绕过一些 EDR Hook。
- 全程不写磁盘,DLL 永远只存在于内存。
No responses yet