首先声名,在写这篇文章时项目并不成功,只是对研究的过程和思路进行总结。
一 基于hook和解密
这是我在没有查阅任何资料前自己拍脑袋想出来的思路,如果要审核聊天内容则必须先要获取到聊天内容,那么可以对这些即时通信软件的消息的发送与接受进行截取,获取其聊天内容,但这些大厂的安全人员肯定也不是白给的,截取到的信息肯定会被加密,下面就是密码学之间的较量了。
简单查阅后就发现此路不同,在七八年前qq就已经应用了反hook的技术,且就算真hook到了,想凭自己破解他们安全团队设立的密码保护也不太现实。
二 本地数据库的破解
这方面网上倒是有一些资料,
微信逆向
qq逆向
钉钉研究
可以说基本囊括目前所以的主流通信软件,大抵思路逃不开通过ollydbg动态调试,下断点,在包含db文件为参数的函数进入,排查相关字符串是否为数据库密码,然后根据该密码编写代码对数据库进行解密,但该密码是动态生成的,如果变化还需要下次再查找,密码变化但存储密码的基地址不会变化,故可以使用CE定位当前查找到密码的地址进行动态获取,以此保证密码的长期可用。
测试了一些,确实是可以借鉴的,还是比较靠谱,但不完全靠谱,可能因为时间稍远或其他问题,暂时还未找到完全直接可行的方案。
不过这种方案如果成功,会是最完整获取到聊天内容的方法。
三 屏幕截图OCR
就是对屏幕截图,再对截取的图片进行文字提取,这种方法暂时可以说是最笨,最低效,最麻烦,但却是最可行的。前面两种都有很大的技术难题,如果是自行研究的话好像是以一己之力对抗整个腾讯/阿里安全团队,气势上先怕了。
可以通过不间断的屏幕截图捕获信息,再通过现有的ocr软件进行文字提取,后续完善的话可以对提取出的文字进行处理,比如去重等。
但再笨也不能笨到不管用户正在干嘛都对屏幕一顿截图,这一会电脑硬盘空间就不够了谁看不出来啊,最好当且仅当用户使用通信软件的时候再截图。该操作可以通过一些windows API实现,检测用户当前使用的进程,如果是qq、微信或钉钉的话,捕获窗口大小,截图并保存。示例代码如下:
#需要安装pypiwin32库和pillow枕头库 pip install pypiwin32/pillow即可安装
import win32gui as w
import win32process,logging
import wmi,uuid,os,filecmp
import time
from PIL import ImageGrab
import ctypes
from ctypes.wintypes import *
#import mypyutils
g_allNeedCaptureSoft = ';QQ.EXE;DINGTALK.EXE;WECHAT.EXE;'
c = wmi.WMI()
def get_window_rect(hwnd):#获取窗口大小
try:
f = ctypes.windll.dwmapi.DwmGetWindowAttribute
except WindowsError:
f = None
if f:
rect = ctypes.wintypes.RECT()
DWMWA_EXTENDED_FRAME_BOUNDS = 9
f(ctypes.wintypes.HWND(hwnd),
ctypes.wintypes.DWORD(DWMWA_EXTENDED_FRAME_BOUNDS),
ctypes.byref(rect),
ctypes.sizeof(rect)
)
return rect.left, rect.top, rect.right, rect.bottom
def get_app_path(hwnd):
try:
_, pid = win32process.GetWindowThreadProcessId(hwnd)
for p in c.query('SELECT ExecutablePath FROM Win32_Process WHERE ProcessId = %s' % str(pid)):
exe = p.ExecutablePath
break
except:
return None
else:
return exe
def get_app_name(hwnd):
exe = None;
try:
_, pid = win32process.GetWindowThreadProcessId(hwnd)
for p in c.query('SELECT Name FROM Win32_Process WHERE ProcessId = %s' % str(pid)):
exe = p.Name
break
except:
return None
else:
return exe
if __name__ == "__main__":
#mypyutils.initLog('capturewindows.log')
lastJpgName = None;
lastTitle = None;
while True:
try:
activeWnd = w.GetForegroundWindow();
appName = get_app_name(activeWnd)
if appName is None:
print('无法获取活动窗口进程名...');
time.sleep(0.1);
continue;
else:
print('窗口进程名为%s'%appName);
appName = str.upper(appName)
if g_allNeedCaptureSoft.__contains__(appName) is False:#若窗口应用不为通信软件则继续
time.sleep(1);
continue;
title = w.GetWindowText (activeWnd)
wndRect = get_window_rect(activeWnd);#获取当前窗口大小
title ='----window title = %s,rect=%d,%d,%d,%d -----'%(title,wndRect[0],wndRect[1],wndRect[2],wndRect[3]);
print("title:",title)
if lastTitle is not None and str(title).__eq__(lastTitle) is False:#这是判断啥的?
print(title)
lastTitle = title
#newWndRect = ( wndRect[0]+10, wndRect[1]+10, wndRect[2]-10,wndRect[3]-10);
fileName = appName + '-'+ time.strftime("%H-%M-%S", time.localtime()) + str(uuid.uuid4().__str__())[5:10] +'.png'
img=ImageGrab.grab(wndRect)
img.save(fileName, "PNG")
print("保存成功")
if lastJpgName is None:
lastJpgName = fileName
continue
except Exception as e:
lastJpgName = None;
logging.error('循环处理过程发生异常了,但仍然继续处理.....');
logging.exception(e);
time.sleep(1)
PS: 有关窗体大小,其实可以通过win32gui.GetWindowRect() API 直接获取窗口位置及大小,但实际操作下发现获取效果并不理想,大小偏小且位置偏左,有文章说是因为vista以后的系统自带毛玻璃特效而api中没计算,但现在Win10了哪还有毛玻璃特效,不咋明白,不过get_window_rec这个函数确实能用,就不纠结这些细节了。
文字提取图像识别因为人工智能目前比较火,百度搜索天若批量识别即可找到资源下载。使用该软件可以生成一个或多个包含图像文本的word文档。
到此,即可获得通信软件的全部聊天内容了,聊天内容的准确依赖于第三方图像识别软件,而具体的审计则更是依赖于人工,及目前只能计,还不能审,且生成的图片应该上传到专门的服务器并删除清理痕迹,也没有做到。不过作为简单实现通信内容获取的demo来说,还是达到了最低要求。
改进版,由客户端和服务器端组成,
客户端实现 当用户进程为qq、微信、钉钉时自动截图并上传到服务器端,上传后删除本地文件。
服务器端接收图片并保存。
git地址如下:
通信内容审计
四 工具
目前已有针对通信内容审计的成熟商用产品–ping 32,该软件功能其实蛮强,可以即时获取qq、微信、钉钉的聊天记录,包括时间、表情等,并根据敏感词报警,还能分析使用者电脑的使用情况,甚至包括文件操作和粘贴板内容,同时可以实现对计算机的关机,重启,锁定鼠标键盘等操作,可以说装了该客户端的电脑已经没有丝毫秘密可言,完全将自己的一举一动暴露在服务器端。一些功能和界面展示如下:
需要注意的是,试用版的客户端不提供卸载接口,目前已在应用、后台进程及服务等各个方向查找均未找到,本意是防止恶意卸载,但试用版这个是不是有点流氓了。且该软件监听的项目实在是过于多了,真正的让人感觉在裸奔,反正我是不会去给我装这个系统的公司工作。