钉钉消息防撤回功能研究与实现-可查看历史消息[文件/图文/管理员/链接 撤回拦截]

news2024/11/17 7:22:34

研究背景

由于在某个大学进行上课的时候,遇到的某个老师,总是习惯发过的消息,到第二天的时候撤回,我们用聊天工具的其中一个原因,不就是因为可以随时去查看发过的消息吗,,而这位老师的操作,也让包括我在内的很多人感到痛不欲生。

想一想,当自己想要去看下聊天记录的时候,发现消息都被撤回,每天那么多的消息,难道我们还需要每一条都复制下来到本地吗?

以上是本次技术研究的初衷,并未涉及到任何敏感信息的获取,逆向,文中所有逆向操作,均未实际进行。

在这里插入图片描述

前置知识

废话不多说了,简单介绍下在本次实验中需要的基础知识,javascript , 逆向 逻辑思考能力

实际都是废话,因为有很多过程都已经被很多大佬总结出来了。这里就不去做太多的赘述。

实操过程

打开安装目录

首先我们打开钉钉的安装目录。右键钉钉图标,打开文件所在位置。 依次进入main - current 文件夹下面

复制关键文件

另外如果有人的钉钉安装目录下存在current_new 文件,是 因为钉钉更新的原因. 需要确定钉钉究竟使用的哪个对应的文件。

找到web_content.pak 或者web_content.dat 我这里是web_content.dat文件。

在这里插入图片描述

该文件是可以解压的,我们可以通过解压工具解压,然后通过搜索关键字 撤回了一条消息 来快速定位到关键的JS 代码。

这里我将这个文件复制出来到桌面, 千万不要直接修改该文件,即使非要如此,也一定要有备份。

你解压的时候发现存在密码,**密码长度是9位,由数字和小写字母组成。**不要尝试去暴力破解… 下图是暴力破解的时间。。

在这里插入图片描述

这里有两种获取密码的方式

第一种破解密码方式

由于这个文件钉钉需要不断的去读取这个文件,所以钉钉的程序中肯定有该密码或者说文件的加密方式。

那么我们可以通过逆向工具调试钉钉的主程序即DingtalkLauncher.exe

常用的工具Ollydbg IDA 这里就不做赘述了,这种方式,会的人不用我这里写,不会的人,写了照着做也整不出来。直接跳到第二种方式即可。

在这里插入图片描述

第二种方式

上面在说第一种方式的时候,说了可以通过逆向去破解钉钉的加密方式,同时也可以获取密码的格式.这里借助其他大佬的一段话。。

————————————————————————————————————————————————

ollydbg拉起DingTalk.exe后,
**方法一、**在CreateFileW下断点,F9运行多次后,当出现web_content.dat时,向上回溯搜索字符串 web_content.dat 的引用,可以找到相关代码
**方法二、**待模块MainFrame.dll加载后,在内存窗口模块MainFrame.dll中Ctrl+B查找 web_content.dat,找到后记录下字符串地址,然后到CPU窗口查找地址常量即可快速定位到相关代码。

6371973C    6A 09           push 0x9
6371973E    6A 03           push 0x3
63719740    8D4424 4C       lea eax,dword ptr ss:[esp+0x4C]
63719744    50              push eax
63719745    8D8C24 98000000 lea ecx,dword ptr ss:[esp+0x98]
6371974C    E8 EFE88AFE     call MainFram.61FC8040                   ; get_key

这里密码key长度是9,具体算法是 md5(version)[2:12],其中version可以从DingTask.exe的属性中拼接而来

以上内容 来源于 原文链接

————————————————————————————————————————————————

查看钉钉版本号

我这里的版本是7.0.11-Release.3139102

在这里插入图片描述

md5加密

可以到在线的md5加密网站 md5加密

我的版本号是 7.0.11-Release.3139102

在这里插入图片描述

将版本号进行md5加密,并截取[2,12] 共9

tip: 索引从0开始

这里我截取的就是 77b8d48f8

在这里插入图片描述

解压文件,静态分析

在这里插入图片描述

我这里是借助VSCODE 进行搜索,结果如下,

可以看到变量的命名,这里我们继续搜索命名函数。

钉钉的 群主或管理员撤回消息, XX 撤回消息. 撤回的图文消息, 单独文字消息都是调用不同的方法,所以如果想要防撤回所有消息格式,需要多次修改.

这里我就演示一种。

在这里插入图片描述

复制 pc_im_recalled_a_message ,继续搜索。

我们锁定文件名最像的那个,

在这里插入图片描述

打开之后,代码非常乱,应该是通过vite build 直接构建的,

我们美化一下,

在这里插入图片描述

分析-修改-保存

可以通过JSON.stringify 进行打印,然后进行分析.

# 文本消息
{
    "atCustomRoleIds": { }, 
    "atOpenIds": { }, 
    "contentType": 1, 
    "textContent": {
        "templateData": [ ], 
        "templateId": "", 
        "text": "具体内容"
    }
}

在这里插入图片描述

所以撤回的文本消息就是 i.baseMessage.content.textContent.text

{
    "atCustomRoleIds": { }, 
    "atOpenIds": { }, 
    "attachments": [
        {
            "extension": {
                "imageUrl": "https://cdn2.jianshu.io/assets/web/recommend-author-03cc8798d5cc3f986e49cbcb2eb63079.png", 
                "picUrl": "@lQDPNDgdkcl3OmDMyMzIsME6THfi_fNeBBZJkRtAdQA", 
                "rule": "spiderbot", 
                "source_from": "1", 
                "source_url": "https://www.jianshu.com/recommendations/users", 
                "text": "在简书,仍有数百万创作者在坚持产出优质创作,有数千万读者在用心交流创作;众多精彩创作,只在简书看得到", 
                "title": "推荐作者 - 简书", 
                "url": "https://www.jianshu.com/recommendations/users"
            }, 
            "isPreload": false, 
            "size": "0", 
            "type": 16, 
            "url": "https://www.jianshu.com/recommendations/users"
        }
    ], 
    "contentType": 102
}

所以撤回链接的变量 应该是: i.baseMessage.content.attachments[0].url
简单分析之后,我们在关键的位置,添加拦截代码。

如果想要实现每种消息的防撤回,那么应该添加判断该消息的种类. 如下:

## 文件必须下载过,本地才会存在
try {
	if(i.baseMessage.content.contentType == 1){
		s = " 撤回的消息为:" + i.baseMessage.content.textContent.text;
	}else if(i.baseMessage.content.contentType == 102){
		s = " 撤回的链接为:" + i.baseMessage.content.attachments[0].url;
	}else if(i.baseMessage.content.contentType == 2){
		s = " 撤回消息类型: 图片,暂时无法锁定所在路径";
		// s = " 撤回消息类型: 图片 :" + JSON.stringify(i.baseMessage);
	}else if(i.baseMessage.content.contentType == 3100){
		s = " 撤回图文消息为:" + i.baseMessage.content.attachments[0].extension.desc;
	}else if(i.baseMessage.content.contentType == 501){
		s = " 撤回文件名为:" + i.baseMessage.content.attachments[0].extension.f_name + "请在本地搜索[需要保存过]";
	}else{
		s = " 未识别出撤回的信息类型";
		//s =  JSON.stringify(i.baseMessage);
	}
} catch (e) {
	s = " 读取撤回消息失败。"
};

效果如下:
在这里插入图片描述

关于图片,经过我不断测试,发现只要消息阅读过,即使没有特意保存到本地,钉钉也会将其下载到你的电脑本地,
保存地址是 C:\Users\用户名\AppData\Roaming\DingTalk\584039362_v2\resource_cache\XX\*.png
可以根据修改时间手动查看图片。

C:\Users\用户名\AppData\Roaming\DingTalk\584039362_v2\resource_cache\\584039362_v2\ImageFiles\ 中是缩略图

最终修改文件为 chatbox-index.05b147d5.js

修改前关键代码

if(i.baseMessage.shieldStatus===X.s6.YES){let e;e=a?"dt_message_shield_tip_message_file":"dt_message_shield_tip_message",t=g.i18next.t(e)}else if(s){let e;e=a?"dt_message_recall_yourecallmessage_file":"pc_conv_list_you_recall_last_message",t=g.i18next.t(e)}else{let e;e=a?"dt_message_recall_message_file_format":"pc_im_recalled_a_message";let s=g.i18next.t(e);t=u.createElement("span",null,n," ",s)}return u.createElement("div",{className:"msg-recall-hint","data-msg-id":i.baseMessage.messageId},t,this.renderReEdit())}

修改后内容: 又增加了管理员防撤回

if(i.baseMessage.shieldStatus===X.s6.YES){let e;e=a?"dt_message_shield_tip_message_file":"dt_message_shield_tip_message",t=g.i18next.t(e);try{if(i.baseMessage.content.contentType==1){t=" 管理员撤回的消息为:"+i.baseMessage.content.textContent.text}else if(i.baseMessage.content.contentType==102){t=" 管理员撤回的链接为:"+i.baseMessage.content.attachments[0].url}else if(i.baseMessage.content.contentType==2){t=" 管理员撤回消息类型: 图片,暂时无法锁定所在路径"}else if(i.baseMessage.content.contentType==3100){t=" 管理员撤回图文消息为:"+i.baseMessage.content.attachments[0].extension.desc}else if(i.baseMessage.content.contentType==501){t=" 管理员撤回文件名为:"+i.baseMessage.content.attachments[0].extension.f_name+"请在本地搜索[需要保存过]"}else{t=" 未识别出管理员撤回的信息类型"}}catch(e){t=" 读取管理员撤回消息失败。"}}else if(s){let e;e=a?"dt_message_recall_yourecallmessage_file":"pc_conv_list_you_recall_last_message",t=g.i18next.t(e)}else{let e;e=a?"dt_message_recall_message_file_format":"pc_im_recalled_a_message";let s=g.i18next.t(e);try{if(i.baseMessage.content.contentType==1){s=" 撤回的消息为:"+i.baseMessage.content.textContent.text}else if(i.baseMessage.content.contentType==102){s=" 撤回的链接为:"+i.baseMessage.content.attachments[0].url}else if(i.baseMessage.content.contentType==2){s=" 撤回消息类型: 图片,暂时无法锁定所在路径"}else if(i.baseMessage.content.contentType==3100){s=" 撤回图文消息为:"+i.baseMessage.content.attachments[0].extension.desc}else if(i.baseMessage.content.contentType==501){s=" 撤回文件名为:"+i.baseMessage.content.attachments[0].extension.f_name+"请在本地搜索[需要保存过]"}else{s=" 未识别出撤回的信息类型"}}catch(e){s=" 读取撤回消息失败。"};t=u.createElement("span",null,n," [作者:SwBack] ",s)}

下面的贴图是旧版, 后进行了改进
在这里插入图片描述

这里有一点需要注意,不要原样照抄,注意撤回的消息后面跟着的i 在你本地是不是这个,还有 将撤回消息赋值给 s 是因为后面 createElement 调用的是s.

在这里插入图片描述

然后保存内容. 进行压缩,然后将内容替换web_content.dat。

重启钉钉,如果没有意外的话.你应该会遇到这样子的情况。
在这里插入图片描述

这里我怀疑是因为JS美化的问题,所以我记住修改的位置之后,如下操作,未发现问题.不去美化代码.直接修改原生的JS。

在这里插入图片描述

然后去替换文件

在这里插入图片描述

效果

修改之后,重启钉钉,就会发现以前撤回的消息,大多数都可以看到了,

只要你的电脑上不是第一次安装钉钉,那么即使是很久以前的消息,也会显示出来。

在这里插入图片描述

实验总结

这整个过程,在不断的遇到问题,解决问题的过程就是一个学习的过程.同时也会让自己感觉很有成就感, 这里面需要的技术含量不高,因为主要借助了其他大佬的思路。

另外网上也有很多别人开发的类似工具,插件之类的Q,原理基本上都是这样.并且,如果仔细研究的话,还可以去做到很多事情,比如,让撤回的消息,以卡片的形式展现出来。

拦截已读 状态的发送. 等等。

最主要的还是安全性.可自定义性。 嗯~ 有些有想法的朋友 给我讲可以在撤回消息前给添加前缀. 比如 [**] XXX 撤回了一条消息

,不得不说,这一届的网友,是知道怎么加前缀的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/410291.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Error in mounted hook: TypeError: Cannot read properties of undefined (reading isHiddenDay ) found

Error in mounted hook: TypeError: Cannot read properties of undefined (reading isHiddenDay ) found 无法读取未定义的属性‘isHiddenDay’. 在vue中使用fullcalendar在mounted钩子中渲染报错 背景 我在一个小demo中实现还是好好的,并且用的依赖都是6.x版本的…

初入了解——什么是VUE

个人简介:云计算网络运维专业人员,了解运维知识,掌握TCP/IP协议,每天分享网络运维知识与技能。座右铭:海不辞水,故能成其大;山不辞石,故能成其高。个人主页:小李会科技的…

vue3+ts项目里如何使用状态管理pinia以及数据持久化

我们都知道在vue2项目里搭配状态管理vuex3XX使用,效果极好的。 虽然在vue3项目里,vuex4XX仍能发挥余热,但由于缺乏对于ts的支持,使得类型推断陷入僵局。 所以在vue3ts的项目里,vuex渐被舍弃,pinia取而代之…

微信小程序入门教程 --(保姆级)

一、小程序注册 1、首先,到小程序官网注册自己的小程序账号,以下附有地址和教程: 小程序官网 进入这个地址之后,会看到这样的页面,点击立即注册按钮 2、在接下来的页面,选择小程序 3、然后根据提示完成三…

Web基础 HTML标签 六种超链接标签的使用方式

超链接标签&#xff08;重点&#xff09; 1、链接的语法格式&#xff1a; <a href"跳转目标链接" target"目标窗口的弹出方式"> 文本或图像 </a><a>标签里的a是单词anchor的的缩写&#xff0c;意为:锚。 两个属性的作用如下&#xff…

【前端灵魂脚本语言JavaScript⑤】——JS中数组的使用

&#x1f41a; 作者: 阿伟 &#x1f482; 个人主页: Flyme awei &#x1f40b; 希望大家多多支持&#x1f618;一起进步呀&#xff01; &#x1f4ac; 文章对你有帮助&#x1f449;关注✨点赞&#x1f44d;收藏&#x1f4c2; JavaScript数组的使用 文章目录JavaScript数组的使用…

【Vue2从入门到精通】详解Vue数据双向绑定原理及手动实现双向绑定

文章目录✨什么是数据双向绑定✨数据双向绑定的原理✨Vue数据双向绑定原理✨实现数据双向绑定的步骤✨手动实现自定义组件的双向绑定的步骤✨写在最后✨什么是数据双向绑定 我们先从单向绑定切入单向绑定非常简单&#xff0c;就是把Model绑定到View。 什么是双向绑定呢&#…

基于pytorch+Resnet101加GPT搭建AI玩王者荣耀

本源码模型主要用了SamLynnEvans Transformer 的源码的解码部分。以及pytorch自带的预训练模型"resnet101-5d3b4d8f.pth"本资源整理自网络&#xff0c;源地址&#xff1a;https://github.com/FengQuanLi/ResnetGPT注意运行本代码需要注意以下几点 注意&#xff01;&a…

【Unity】Button基础-按钮更换图片样式

话说&#xff0c;今天修改了一下项目中的内容&#xff0c;发现按钮不怎么好看&#xff0c;想用图片的方式改一改&#xff0c;然后点开Button&#xff0c;忽然发现好多内容都忘记了。。。 Transition&#xff08;过渡方式&#xff09;&#xff1a;按钮在状态改变时自身的过渡方式…

P2E游戏《西游降魔》站在元宇宙风口 打造高效、完整且可持续的GameFi2.0体系

引言&#xff1a;当人类大步迈入元宇宙时代&#xff0c;链上P2E游戏《西游降魔》正与元宇宙生态相伴相生&#xff0c;带领人们开启Play to Earn的变革之旅。 区块链结合游戏组成新的 GameFi 赛道&#xff0c;在 2021 年迎来爆炸式增长。各大公链如&#xff1a;ETH、BSC、OKCha…

【蓝桥杯】X进制减法、贪心思想、小白专用

问题描述&#xff1a; 解题分析&#xff1a; 首先要搞明白 X 进制与 十 进制是如何转换的&#xff0c;以 X 进制321为例 题中说明&#xff0c;3 的进制为8&#xff0c;2的进制为10&#xff0c;1的进制为2 那么开始计算&#xff1a; 1就代表一个1 2的话是十进制&#xff0c…

【论文精读】COLING 2020 -带有对偶关系图注意力网络的事件检测模型

【论文精读】COLING 2020 -带有对偶关系图注意力网络的事件检测模型 【论文原文】&#xff1a;Event Detection with Dual Relational Graph Attention Networks 【作者信息】&#xff1a;Jiaxin Mi and Po Hu and Peng Li 论文&#xff1a;https://aclanthology.org/2022.c…

Spring系列(六) --- SpringBoot 与 Servlet 的比较及 Spring 读取配置文件的方式

SpringSpringBoot VS ServletSpring 读取配置文件的方式yml 和 properties 的区别SpringBoot VS Servlet Spring 读取配置文件的方式 1 Value 注解获取单个配置项 如在 yml 中定义一个 qq 音乐的 token; 然后输出, 如下: 2 针对对象的读取: ConfigurationProperties 在 yml 中…

笔记本电脑连接不上WiFi怎么办?4个实用解决方法!

案例&#xff1a;笔记本电脑连接不上WiFi怎么办 “朋友们&#xff0c;想问问大家知道为什么我的笔记本电脑连接不上WiFi呢&#xff1f;试了好几遍还是无法连接&#xff0c;遇到这种情况我应该怎么解决呢&#xff1f;感谢大家&#xff01;” 在现代生活中&#xff0c;笔记本电…

HTTP协议详解(二)

目录 1.HTTP 响应详解 1.1认识状态码(status code) 1.2 认识响应报头(header) 1.3 认识响应正文(body) 2.构造 HTTP 请求 2.1 通过form表单构造请求 2.2 通过ajax构造请求 2.3 使用第三方工具构造请求 开始之前我们先复习一下http协议格式 1.HTTP 响应详解 我们先抓包…

【JavaScript】四个常用功能/案例:表格排序 | 替换链接 | 倒计时 | 双色球机选一注

CSDN话题挑战赛第2期 参赛话题&#xff1a;学习笔记 &#x1f5a5;️ NodeJS专栏&#xff1a;Node.js从入门到精通 &#x1f5a5;️ 博主的前端之路&#xff08;源创征文一等奖作品&#xff09;&#xff1a;前端之行&#xff0c;任重道远&#xff08;来自大三学长的万字自述&am…

《文章复现》考虑用户舒适度的冷热电多能互补综合能源系统优化调度

说明书 免费&#xff1a;https://download.csdn.net/download/qq_50594161/87625438 MATLAB代码&#xff1a;考虑用户舒适度的冷热电多能互补综合能源系统优化调度 关键词&#xff1a;用户舒适度 综合能源 PMV 优化调度 参考文档&#xff1a;《冷热电气多能互补的微能源网鲁…

点击开关按钮,js实现电灯开关效果

初识js&#xff0c;跟大家分享js实现电灯开关灯效果的具体代码&#xff0c;利用简单的htmljs模拟电灯开关的小案例。 首先进行案例分析&#xff1a; 1.获取图片属性 2.判断变量的值 3.点击时切换图片 通过点击按钮实现电灯开关 以下是两张需要的图片&#xff0c;接下来添加…

vue3路由配置及路由跳转传参

1、安装路由 npm i vue-router 2、编写需要展示的路由 在src目录下创建pages文件夹&#xff0c;里面创建两个vue文件命名为student.vue,person.vue 分别编写两个vue文件 student.vue和person.vue <template>学生 </template><script setup></script…

后端架构token授权认证机制:spring security JSON Web Token(JWT)简例

后端架构token授权认证机制&#xff1a;spring security JSON Web Token&#xff08;JWT&#xff09;简例 在基于token的客户端-服务器端认证授权以前&#xff0c;前端到服务器端的认证-授权通常是基于session&#xff0c;自从token机制出现并流行起来后&#xff0c;基于token…