1.恶意代码或者恶意程序常用的行为或者方式有哪些?

恶意代码/恶意程序常见的行为方式主要包括以下几类:

  1. 持久化
    • 注册表自启动 (Run, Services)
    • 创建计划任务、服务或驱动
    • 篡改系统文件或劫持 DLL/进程
  2. 自我保护与隐蔽
    • 加壳、混淆、反调试、反虚拟机
    • Rootkit 技术隐藏进程、文件、注册表
  3. 信息收集
    • 窃取账号、密码、浏览器缓存
    • 键盘记录、屏幕截图、网络嗅探
  4. 传播与控制
    • 利用漏洞、钓鱼邮件、自传播(蠕虫)
    • 与 C2 服务器通信、接收远控指令
  5. 破坏与牟利
    • 删除或加密文件(勒索)
    • 注入挖矿、广告、木马下载器
    • 干扰系统运行(破坏数据或拒绝服务)

深入细节:

  • 启动持久化机制
    除了注册表,还可以通过 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 文件打开后创建子进程马上崩溃,我会:

  1. 监控进程创建:用 Process Monitor / Process Explorer 确认子进程路径、参数。
  2. 挂调试器:对父进程和子进程都附加(WinDbg/ x64dbg),或设置 Image File Execution Options 自动附加。
  3. 使用调试技巧:设置断点在 CreateProcess* 相关 API,或者用 gflags +e childdbg 让调试器自动附加到子进程。
  4. 捕获崩溃点:分析异常类型(访问冲突、堆栈溢出、异常指令等)并 dump 内存。

详细调试思路

  1. 确认子进程信息
    • Process Monitorprocmon 过滤 “Process Create”,获取子进程路径、命令行。
    • 看是否是临时文件(POC 常释放临时 exe)。
  2. 调试子进程启动
    • 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”。
  3. 捕获崩溃点
    • 设置断点: bp kernel32!CreateProcessW bp ntdll!NtCreateUserProcess
    • 跟踪子进程初始化,查看入口点代码是否有异常指令。
  4. 分析原因
    • 看是否因为 POC 恶意 Payload 触发漏洞导致 crash(比如堆溢出)
    • 检查是否需要特定环境(DLL、依赖文件),缺失也会导致崩溃。
  5. 额外技巧
    • dump 保存崩溃前状态: .dump /ma crash.dmp
    • 如需让程序暂停方便附加,可打补丁(NOP 出现崩溃前的指令)或用 Sleep() Hook 暂停执行。

3.像Messagebox这样的函数,vs或者系统是如何找到最后的执行函数的,像什么MessageboxA,MessageboxW

MessageBox 这样的 API,系统通过 函数名映射和导入表解析 找到最终执行的函数:

  1. 在源码中写 MessageBox,编译器通过头文件/宏定义将其映射为 MessageBoxW(Unicode)或 MessageBoxA(ANSI)。
  2. 链接器把调用指向 User32.dll 的导出函数(通过导入表 IAT)。
  3. 程序加载时,Windows Loader 解析 IAT,把导入的符号指向 User32.dll 中真实函数地址。
  4. 运行时,调用的是 user32!MessageBoxWuser32!MessageBoxA,最终底层还会转到 user32.dll 内部的系统调用(最终下层是 ntdllwin32k.sys 内核模块)。

详细深入

  1. 头文件/宏替换阶段
    • windows.h 中: #ifdef UNICODE #define MessageBox MessageBoxW #else #define MessageBox MessageBoxA #endif
    • 所以 MessageBox() 会自动替换成 MessageBoxWMessageBoxA,具体取决于项目是否定义 UNICODE 宏。
  2. 链接阶段(静态到动态)
    • 编译器生成对 __imp__MessageBoxW@16(导入符号)的引用。
    • 链接器将符号放入程序的 Import Address Table (IAT),声明依赖 User32.dll
  3. 加载阶段(运行时绑定)
    • 程序启动时,Windows Loader 加载 user32.dll,在其导出表找到 MessageBoxW 的地址。
    • 把这个地址写入程序的 IAT,对应的函数指针就能直接跳到实际实现。
  4. 运行时执行
    • 当程序执行 MessageBox() 时,其实跳转到 IAT 指针指向的地址 → user32!MessageBoxW → 内部再调用 NtUserMessageBox 这样的系统调用 → 最终在 win32k.sys 内核模块中渲染对话框。
  5. 动态查找的另一种方式
    • 如果没有在 IAT 中声明,也可以用 LoadLibrary + GetProcAddress("MessageBoxW") 手动获取地址,然后调用。

4.假如给你50个样本,你会如何快去排查恶意的样本

拿到 50 个样本时,我会先用 自动化+静态筛选,再做 重点动态分析

  1. 快速特征扫描:用杀软引擎、YARA、VT API 批量查杀过滤已知恶意文件。
  2. 静态分析:批量解析 PE(检查导入表、签名、可疑字符串、混淆、壳),找出异常样本。
  3. 沙箱/虚拟机批跑:用自动化工具(Cuckoo、Any.Run)跑一遍,筛出有明显恶意行为(网络连接、注册表修改、进程注入)的样本。
  4. 重点手动分析:只对高风险样本手动调试/反编译,确认行为。

详细

  1. 自动化初筛
    • hash + VirusTotal 批量查询(脚本自动化 API),直接剔除无害/已知文件。
    • YARA 扫描(检测恶意代码段、C2 域名、壳特征)。
    • 统计学方法:查看 PE 的入口点熵值(高混淆或壳的优先分析)。
  2. 静态特征分析
    • 提取 导入函数(如 CreateRemoteThread, VirtualAllocEx, WinExec)。
    • 检查数字签名、编译时间、节区异常(额外的 CODE, .UPX, 超大资源节)。
    • 抽取可疑字符串(域名、注册表键、命令行参数)。
  3. 动态沙箱分析
    • 在隔离环境下用 自动化沙箱 跑全部样本,收集:
      • 文件/注册表修改
      • 新进程/注入
      • 网络流量(C2 连接、加密流量)
    • 根据行为分级:明显恶意(加密文件/下载器)直接标记,高可疑(注入、持久化)进入手动分析。
  4. 重点手动分析
    • 对优先级最高的样本:
      • IDA 静态反编译,确认主要逻辑
      • x64dbg/WinDbg 动态调试,观察 API 调用栈
      • 分析 Payload 是否有下载器/后门
  5. 出结论
    • 每个样本生成分析报告,重点样本详细说明恶意行为。

追问:如何提速?

  • 用 Python 写脚本批量提取 PE 信息(导入表、节区、哈希)
  • 自动化调用沙箱 API 批量提交
  • 用 YARA/ClamAV 扫描未知恶意家族特征
  • 先聚合样本哈希去重,避免重复分析

5.如何使用hook技术


基本回答

Hook 技术就是拦截程序或系统 API 的调用,插入自己的代码以改变行为。常用方法:

  1. API Hook(用户态)
    • IAT Hook:修改进程 Import Address Table,把函数指针改为自己的函数。
    • EAT Hook:修改 DLL Export Table,改变导出函数地址。
    • Inline Hook:在目标函数入口写跳转指令(JMP),重定向到自定义代码。
  2. 内核 Hook
    • 修改 SSDT、IRP 或 Inline Patch 来截获系统调用(需要驱动)。
  3. 使用场景
    • 安全软件(监控 API 调用)
    • 调试器(拦截特定函数)
    • 恶意软件(隐藏、绕过、注入)

详细

  1. IAT Hook(Import Address Table)
    • 每个 PE 文件都有 IAT,存储外部 API 的地址。
    • 修改对应的 IAT 表项,把原本指向 MessageBoxW 的指针改成我们自己的函数地址。
    • 调用时先进入我们的代码,再决定是否转到原始 API。
  2. EAT Hook(Export Address Table)
    • 在 DLL 的导出表里直接修改导出函数指针,比如修改 user32.dll 的导出表,让其他进程加载时调用我们函数。
  3. Inline Hook(代码补丁法)
    • 在目标函数入口写入 JMP(5 字节),跳到我们的代码: push eax mov eax, MyFunction jmp eax
    • 我们的函数执行后,再跳回原函数(Trampoline 技术)。
  4. 内核 Hook
    • 修改 SSDT(系统服务分发表)或驱动对象的回调,拦截系统调用(如 NtCreateFile)。
    • 需要驱动签名,Windows 10 之后对 SSDT Hook 有保护(PatchGuard)。
  5. 实际开发中常用库
    • 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 永远只存在于内存。

Categories:

Tags:

No responses yet

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注