逆向工程实战:用IDA与OllyDbg深度剖析熊猫烧香病毒
1. 项目概述一次对经典恶意代码的深度“解剖”十几年前一个名为“熊猫烧香”的病毒席卷了国内互联网其破坏力之强、传播之广让它成为了中国网络安全史上一个标志性的事件。时至今日它依然是安全研究、逆向工程入门绕不开的经典案例。很多人可能觉得分析一个“过时”的病毒有什么意义恰恰相反它的价值正在于其“经典性”。它集成了文件感染、网络传播、自我保护、破坏性载荷等多种恶意软件常见技术且代码结构相对清晰是理解恶意软件运作原理、掌握逆向分析基本功的绝佳“标本”。这次我们不满足于只看分析报告而是要亲手拿起“手术刀”——IDA Pro和OllyDbgOD像法医解剖一样从静态到动态完整地拆解这只“熊猫”。我们的目标不是复现病毒而是通过逆向工程彻底理解它的核心功能模块是如何实现的包括它如何感染文件、如何隐藏自身、如何通过网络扩散以及最终如何实施破坏。整个过程我会结合IDA的静态反汇编分析与OD的动态调试跟踪并附上完整的调试过程记录和内存快照。无论你是刚接触逆向的新手还是想巩固基础的安全从业者这篇实战记录都能为你提供一条清晰的路径和一堆可以避开的“坑”。2. 分析环境与样本准备构建安全的“无菌实验室”在开始任何恶意软件分析之前搭建一个绝对隔离、可控的分析环境是重中之重。这不仅是保护你主力机的第一道防线也是确保分析过程可复现、结果可信的关键。2.1 虚拟化环境搭建与网络隔离我强烈建议使用虚拟机VM进行分析。我选择的是VMware Workstation因为它对硬件调试的支持相对较好。创建一个干净的Windows XP SP3虚拟机作为分析机。选择XP系统是因为“熊猫烧香”主要针对该时代系统且系统相对简单干扰少。注意切勿在分析机上安装任何杀毒软件或安全工具它们会干扰病毒样本的执行和我们的调试行为导致分析失败。网络配置是核心安全环节。必须将虚拟机的网络适配器设置为“主机模式”或“NAT模式”并在虚拟机内部禁用所有网络适配器。更稳妥的做法是在VMware的虚拟网络编辑器中直接断开该虚拟机的虚拟网卡。我们的目标是让样本在“断网”状态下运行防止其意外连接外部服务器进行扩散或下载其他恶意组件。同时在主机防火墙中可以设置规则禁止虚拟机IP的任何出站连接构成双重保险。2.2 分析工具链配置与样本获取工欲善其事必先利其器。我们的核心工具是IDA Pro (Interactive Disassembler)用于静态分析。我将使用IDA 7.0版本它对旧版PE文件的支持稳定。需要配置好合适的处理器类型x86和加载选项。OllyDbg (OD)用于动态调试。我选用经典的OllyDbg 1.10其界面和插件生态对初学者友好。务必准备好强大的插件如StrongOD反反调试、PhantOm隐藏调试器等。“熊猫烧香”具备一定的反调试能力这些插件能帮助我们绕过检测。辅助工具Process Explorer查看进程、句柄、DLL、Procmon监控文件、注册表操作、Wireshark虽然断网但可监控回环流量分析其网络行为意图、PEiD查壳不过熊猫烧香通常未加壳。关于样本出于法律和安全考虑我不会提供任何下载链接。你可以从一些知名的恶意软件研究资源库或学术机构提供的样本集中寻找确保仅用于合法的研究目的。获取样本后先在其MD5/SHA1值与公开的病毒数据库如VirusTotal中的已知样本哈希进行比对确认你拿到的是正宗的“熊猫烧香”变种。2.3 分析机状态快照与调试策略在启动样本前为虚拟机创建一个“干净快照”。这样每次分析运行后都可以一键恢复到初始状态保证每次实验的起点一致。同时用Process Explorer和Procmon记录下系统初始的进程列表、关键系统目录如C:\Windows\,C:\Windows\System32\的文件状态以便后续对比。我的调试策略是“动静结合由外而内”。首先用IDA进行全局的静态浏览了解程序的大致结构、导入函数哪些API被调用暗示了其功能识别出可能的核心函数如文件操作、注册表操作、网络相关函数簇。然后在OD中动态运行通过设置断点、单步执行验证静态分析的猜想并观察其运行时行为创建了哪些文件、进程修改了哪些注册表项。3. 静态分析先行用IDA揭开病毒的“静态面纱”在运行病毒之前我们先在IDA中打开样本进行一轮“冷读”。这能让我们对病毒的整体架构有一个宏观认识避免在动态调试中像无头苍蝇一样乱撞。3.1 入口点识别与初步反汇编将样本拖入IDA它会自动识别为PE文件并定位到入口点Entry Point。对于“熊猫烧香”入口点代码通常不是直接的用户逻辑而是一段启动代码startup code负责一些初始化工作然后跳转到主要的WinMain或用户定义的主函数。在IDA的“函数窗口”中寻找像WinMain、main、start这样的函数或者通过查看导入函数表Imports寻找GetCommandLineA、GetStartupInfo等典型Win32 GUI/控制台程序入口函数附近的调用来定位主逻辑函数。我找到的主函数开头往往有典型的栈帧建立指令push ebp; mov ebp, esp。通过静态浏览主函数我发现了几个关键代码块自复制与持久化代码中调用了GetModuleFileNameA获取自身路径然后结合CopyFileA或CreateFile/WriteFile等API将自身复制到系统目录如%SystemRoot%\或%SystemRoot%\System32\下并可能重命名为一个看似正常的系统文件名如spoclsv.exe。同时发现了对RegSetValueExA的调用参数指向SOFTWARE\Microsoft\Windows\CurrentVersion\Run这证实了其通过注册表实现开机自启动。文件遍历与感染逻辑存在循环结构内部调用了FindFirstFileA/FindNextFileA搜索路径通常是C:\、D:\等根目录以及*.exe、*.scr等扩展名。在循环体内有文件打开CreateFile、读写ReadFile/WriteFile、关闭CloseHandle的操作这极有可能是感染例程。网络功能模块虽然导入表中可能有WS2_32.dllWinsock库的函数如socket,connect,send但在静态代码中这些网络调用可能被封装在某个子函数里或者条件触发。需要留意对特定IP地址或域名的字符串引用。反调试与自我保护可能会看到对IsDebuggerPresent、CheckRemoteDebuggerPresent等API的调用或者一些手动检查调试器标志如PEB.BeingDebugged的汇编指令。还可能发现创建互斥体CreateMutexA防止多实例运行以及提升权限AdjustTokenPrivileges的代码。3.2 关键字符串与函数交叉引用分析IDA的“字符串窗口”是宝藏。在这里我搜索到了大量中文和英文的错误信息、文件路径、注册表路径、URL等。例如”GameOver”或”WhBoy”这可能是病毒作者留下的签名或感染标记。”*.exe”,”*.htm”,”*.html”指示其感染的目标文件类型。”SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run”自启动项。”%SystemRoot%\\system32\\drivers\\etc\\hosts”可能意图修改hosts文件屏蔽安全网站。一些特定的URL或IP地址可能是病毒下载更多载荷或上报信息的地址。双击这些字符串IDA会跳转到引用它们的位置。通过交叉引用Xrefs我可以快速定位到进行文件感染、注册表修改、网络通信的具体函数。例如追踪到一个包含”*.exe”字符串的函数很可能就是文件感染例程的一部分。3.3 感染逻辑的静态推演通过静态分析我已经可以初步勾勒出感染逻辑。病毒可能采用“PE文件追加”或“缝隙插入”的方式。在代码中我寻找文件映射CreateFileMappingA/MapViewOfFile、PE头解析操作IMAGE_DOS_HEADER.e_lfanew、IMAGE_NT_HEADERS、节表IMAGE_SECTION_HEADER操作的代码。特别是寻找计算文件偏移、移动文件指针、在文件末尾或节间隙写入数据的代码段。通常病毒体会被加密或编码所以在感染例程中可能还会看到一个解密循环涉及XOR操作或简单的加减法运算。4. 动态调试实战用OD跟踪病毒的“一举一动”静态分析给了我们地图动态调试则是亲自踏上征途。现在我们打开OD附加到目标进程如果是EXE直接打开开始实时观察病毒的行为。4.1 绕过反调试与定位核心代码首先在OD中加载样本。如果病毒直接运行并退出或者OD意外关闭说明触发了反调试。这时需要启用StrongOD等插件的“隐藏调试器”功能并在OD的调试选项中设置相关标志。也可以在病毒调用IsDebuggerPresent的指令处下断点然后修改其返回值将EAX改为0。我采取的策略是先在IDA中找到疑似主逻辑函数比如感染循环的起点的地址然后在OD中对该地址下断点F2再运行程序F9。程序会在断点处暂停此时我们就进入了病毒的核心逻辑区域。4.2 逐步跟踪感染流程当程序在感染函数中断下后我开始单步F7/F8执行并密切关注寄存器窗口和堆栈窗口的变化。文件遍历当执行到FindFirstFileA时堆栈上会显示要搜索的路径如C:\*.exe。执行后返回值句柄保存在EAX中。随后进入循环FindNextFileA会被反复调用。每一步我都在数据窗口中跟随存储文件名的缓冲区看看它找到了哪些文件。文件打开与判断找到目标文件后病毒会调用CreateFileA打开它。这里可以下条件断点断在特定文件名上以便专注于分析对一个文件的感染过程。打开文件后病毒通常会读取文件头部ReadFile判断是否是有效的PE文件检查MZ和PE标志以及是否已被感染检查特定标记比如在PE头某个保留字段或节表中写入的魔术字。执行感染如果文件可感染病毒会开始计算感染位置。我观察到它可能会调用SetFilePointer将文件指针移动到文件末尾或者通过MapViewOfFile将文件映射到内存。在内存中它会修改PE头的AddressOfEntryPoint使其指向病毒代码通常附加在文件末尾或最后一个节的空隙中并调整SizeOfImage等字段。同时将原始的入口点地址保存到病毒体的某个位置以便执行完病毒代码后跳转回原程序。写入病毒体最关键的一步是写入病毒体本身。病毒体可能在内存中是加密的。我会在调用WriteFile或内存拷贝指令如rep movsd时检查写入的目标地址和内容。通过内存转储在数据窗口选中区域右键-Backup-Save to file可以将病毒体代码提取出来供后续单独分析。修复与关闭写入完成后病毒会修复被感染文件的校验和可选然后关闭文件句柄。整个过程在一个循环中对目录下的每个可执行文件重复。在调试过程中我同时用Procmon监控可以清晰地看到病毒对文件系统的所有操作序列与OD中的代码执行流相互印证。4.3 网络传播与破坏行为的捕捉由于我们断网了病毒的网络连接尝试会失败connect返回错误。但在OD中我们可以在socket、connect、send等函数上设置断点。当断点命中时观察堆栈参数可以知道它试图连接哪个IP和端口以及准备发送什么数据数据缓冲区内容。这有助于理解其网络传播机制可能是扫描局域网、尝试连接IRC服务器作为僵尸网络控制端或下载其他模块。对于破坏性行为如删除文件、格式化磁盘、覆盖MBR等通常会调用DeleteFileA、_wsystem执行命令行等函数。在OD中跟踪到这些调用时需要格外小心可以在调用前修改EIP跳过这些危险指令或者提前在虚拟机快照中做好备份。5. 核心功能模块深度解析通过动静结合的分析我们可以系统地总结“熊猫烧香”的几个核心功能模块。5.1 文件感染机制详解“熊猫烧香”主要感染本地和网络驱动器上的*.exe,*.scr,*.pif,*.com等可执行文件以及*.htm,*.html,*.asp,*.php等网页文件。对于可执行文件它采用经典的“PE文件追加”方式。感染步骤检查与标记打开目标文件检查PE签名。在IMAGE_NT_HEADERS.OptionalHeader的某个保留字段如CheckSum后的字段或某个节表的名称字段写入感染标记如”WhBoy”。如果已存在标记则跳过。计算植入位置将病毒体经过简单加密追加到文件的最后一个节.rsrc或新增一个节的末尾。计算新的入口点NewEntryPoint OriginalEntryPoint VirusSize不通常是病毒体在内存中的起始RVA。修改PE头将OptionalHeader.AddressOfEntryPoint修改为病毒体的入口点RVA。增加OptionalHeader.SizeOfImage使其包含病毒体的大小。如果病毒体放在新增的节中需要添加一个IMAGE_SECTION_HEADER并设置其VirtualAddress,SizeOfRawData,Characteristics通常为可读、可写、可执行。保存原始入口点将原始的AddressOfEntryPoint值保存在病毒体内部的某个固定偏移处。写入病毒体将加密后的病毒体代码写入到文件计算好的偏移位置。修复可选重新计算并更新OptionalHeader.CheckSum。对于网页文件它会在文件末尾插入一段利用IE漏洞的恶意脚本代码如iframe src”病毒网址” width0 height0/iframe当用户浏览该网页时可能自动下载并执行病毒。实操心得在OD中调试感染过程时最好针对一个简单的、自己编写的测试exe进行。这样文件结构清晰便于观察每一步修改。可以在感染前后分别用PE工具如LordPE查看PE头信息对比变化。5.2 持久化与自启动技术病毒为了在系统重启后依然存活采用了多种持久化手段注册表自启动这是最主要的方式。病毒将自身副本的路径写入HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Run或HKEY_LOCAL_MACHINE下的对应位置。在代码中表现为对RegCreateKeyA和RegSetValueExA的调用。系统目录隐藏将自身复制到%SystemRoot%\system32\或%SystemRoot%\目录下并命名为类似spoclsv.exe、winlogon.exe与系统进程名相似的名字利用用户的疏忽进行隐藏。文件属性隐藏感染后通过SetFileAttributesA为自身副本或生成物设置FILE_ATTRIBUTE_HIDDEN和FILE_ATTRIBUTE_SYSTEM属性使其在默认的文件夹选项中不可见。进程注入或守护进程某些变种会创建两个进程相互守护或者将代码注入到explorer.exe等系统进程中结束一个另一个会立即将其重启。在OD中可以在RegSetValueExA和CopyFileA函数上设置断点准确捕获其持久化行为的具体参数写入的注册表路径、复制的目标路径。5.3 网络传播与后门功能分析虽然我们的环境断网但通过静态分析和动态断点可以推断其网络行为局域网传播可能通过扫描局域网内其他主机的默认共享如IPC$,ADMIN$并尝试使用弱口令或空口令进行连接。一旦成功就将病毒副本复制到对方的共享目录下。这涉及WNetAddConnection2A建立网络连接和远程文件操作API。下载者功能病毒体内可能硬编码了几个URL。它会尝试从这些URL下载更新版本的病毒体或其他恶意软件如盗号木马。这通过URLDownloadToFileA或WinHttp系列API实现。信息上报可能会收集本机信息计算机名、用户名、IP地址等并通过HTTP POST或自定义协议发送到指定的服务器。这解释了为什么其导入表中会有wininet.dll或ws2_32.dll的函数。僵尸网络Botnet部分变种可能连接到一个IRC服务器加入特定频道接受攻击者发布的命令如发起DDoS攻击、更新配置等。这需要解析IRC协议。注意事项分析网络功能时即使断网也要在OD中让代码执行到网络调用部分然后分析其准备发送的数据缓冲区内存区域。这些数据往往包含了重要的配置信息或上报数据格式。可以使用OD的“数据窗口中跟随”功能查看缓冲区的原始字节和ASCII字符串。5.4 反分析反调试、反虚拟机技巧识别“熊猫烧香”采用了一些基础的反分析技术反调试直接调用IsDebuggerPresent。在OD中可以通过插件绕过或者手动在调用后修改EAX寄存器值为0。时间延迟在关键循环或函数开始处调用Sleep函数延缓分析人员的调试速度或干扰基于时间的分析。检测虚拟机通过执行一些特权指令如sidt,sgdt并检查结果或者查询特定的注册表键、进程列表、硬件信息如通过GetSystemInfo或CPUID指令来检测是否运行在VMware/VirtualBox等虚拟机中。检测到后可能改变行为或直接退出。多线程与代码混淆创建多个线程相互配合或进行干扰增加动态跟踪的难度。代码中可能夹杂大量无用的跳转、垃圾指令干扰反汇编器的分析。在OD中遇到程序无故退出或行为异常时就要考虑是否触发了反分析代码。可以在常见的反调试API和检测虚拟机的代码片段上下断点观察其执行路径。6. 调试过程全记录与问题排查这里分享一次完整的调试会话中遇到的关键节点和解决方法。6.1 调试会话记录启动与入口用OD加载panda.exe。入口点是一段编译器生成的启动代码。我按F8步过直到看到一个CALL指令后面跟着JMP跳转到一个函数这个函数内部调用了GetCommandLineA确认是WinMain。定位主逻辑在WinMain中我搜索字符串引用找到了”GameOver”。交叉引用到函数sub_401000。对这个函数开头下断点F9运行程序中断在此。跟踪自复制在sub_401000中单步执行发现调用了GetModuleFileNameA结果保存在一个缓冲区内容是当前病毒路径。紧接着调用了CopyFileA目标路径是C:\WINDOWS\system32\drivers\spoclsv.exe。至此自复制行为被捕获。分析感染循环继续执行进入一个大循环。循环内调用了FindFirstFileA(”C:\\*.exe”)。我在FindNextFileA上设断点每次命中时在堆栈窗口查看找到的文件名。当找到一个test.exe我预先放置的时我让程序执行后续的CreateFileA。单步感染打开test.exe后程序读取了文件头并计算了一些值。我观察到它检查了PE头中OptionalHeader的[Reserved1]字段偏移0x5C判断是否为0。如果是0则认为是未感染。然后它计算文件大小调用SetFilePointer移动到文件末尾准备写入。在写入前有一段循环对一段内存数据进行XOR 0xAA操作——这是解密病毒体我将解密后的内存区域约10KB转储保存。修改PE头写入病毒体后程序又定位回PE头修改了AddressOfEntryPoint改为文件末尾的RVA并增加了SizeOfImage。我使用LordPE在调试过程中实时查看test.exe的内存镜像确认了修改。绕过反调试在调试网络部分代码时程序突然退出。我回溯发现在调用connect之前有一个call ds:IsDebuggerPresent返回值被测试并跳转。我在这个call之后下断点将EAX寄存器手动改为0然后继续执行程序顺利执行到网络代码部分虽然connect会失败。6.2 常见问题与解决技巧问题现象可能原因排查与解决技巧OD加载程序后立即运行结束1. 程序是控制台程序执行完退出。2. 触发了反调试如IsDebuggerPresent。3. 程序需要命令行参数。1. 在入口点或WinMain直接下断点。2. 使用StrongOD插件隐藏调试器或在反调试API调用后修改返回值。3. 在OD的调试选项或命令行参数中提供参数。单步执行时程序跑飞或崩溃1. 跟踪进入了系统DLL领空如ntdll.dll。2. 遇到了异常或非法指令。3. 多线程干扰。1. 使用OD的“执行到用户代码”功能AltF9。2. 检查OD的异常设置忽略一些常见异常。仔细检查上一步执行的指令是否操作了非法内存。3. 暂停其他线程或使用OD的线程管理功能专注于主线程。无法在关键函数如感染函数下断点1. 函数地址是动态计算的如通过call [eaxxx]。2. 代码被加壳或混淆。1. 在函数被调用前的某个固定位置如FindFirstFileA调用处下断点然后步进到目标函数。2. “熊猫烧香”通常未加壳。如果遇到需要先寻找OEP并脱壳再进行静态分析。动态行为与静态分析不符1. 病毒采用多态或解密执行。2. 某些代码路径由条件触发如日期、特定文件存在。1. 在OD中关注内存中解密后的代码区域而不是文件中的原始字节。2. 在静态分析时注意条件跳转在动态调试时尝试满足或修改条件如修改标志寄存器以触发不同路径。Procmon捕获到大量无关操作系统后台进程活动干扰。在Procmon中设置过滤器Filter只显示目标进程panda.exe的操作或者只关注文件、注册表、进程特定类型的操作。独家避坑技巧双机调试对于更复杂的、会检测本地调试器的样本可以考虑使用双机调试两台虚拟机通过串口连接一台运行样本另一台用WinDbg调试。这能彻底隐藏调试器。脚本化分析对于重复性的操作如记录每个被感染的文件名可以编写OD的脚本插件如ODbgScript来自动化提高效率。内存断点是利器当病毒将解密后的代码或配置数据写入某个内存区域后想知道谁在读取它可以在该内存地址上设置“内存访问断点”。当有指令读取该地址时OD会中断帮你快速定位到关键的解析或使用代码。善用“执行到返回”当进入一个不关心的系统API或复杂子函数时不要一步步跟进去按CtrlF9执行到返回会快速执行到当前函数的RETN指令处。7. 总结与延伸思考完成对“熊猫烧香”的逆向分析就像完成了一次完整的解剖实验。你不仅看到了它的“器官”各个功能模块更理解了它们如何“协作”执行流程。这个过程巩固了PE文件结构、Windows API、反调试技巧等基础知识。我个人最大的体会是逆向分析没有捷径就是“大胆假设小心求证”。静态分析时做出的每一个猜想比如“这里可能是在感染文件”都要在动态调试中去验证。OD中的每一步执行都要问自己“现在寄存器里是什么堆栈里是什么这段代码想要达到什么目的”。积累的多了看到FindFirstFileA后面紧跟着CreateFile和WriteFile你就能立刻意识到这是一段文件感染或释放的代码。这个样本虽然古老但其中蕴含的技术思想持久化、传播、反分析在现代恶意软件中依然以更复杂的形式存在。分析完它之后你可以尝试挑战一些更现代的样本比如使用API哈希避免字符串、动态解析API地址、使用更复杂加密如AES、或利用新型漏洞的恶意软件。每一次分析都是对自身技能的一次锤炼。最后务必记住所有分析都必须在隔离环境中进行并将获得的知识用于防御和建设这才是安全研究的真正价值所在。