【转】手把手教你读取Android版微信和手Q的聊天记录(仅作技术研究学习)
1、引言
特别说明:本文内容仅用于即时通讯技术研究和学习之用,请勿用于非法用途。如本文内容有不妥之处,请联系JackJiang进行处理!

我司有关部门为了获取黑产群的动态,有同事潜伏在大量的黑产群(QQ群、微信群)中,干起了无间道的工作。随着黑产群数量的激增,同事希望能自动获取黑产群的聊天信息,并交付风控引擎进行风险评估。于是,这个工作就交给我了,是时候表现一波了……
针对同事的需求,分析了一通,总结一下:
1)能够自动获取微信和 QQ群的聊天记录;
2)只要文字记录,图片和表情包,语音之类的不要;
3)后台自动运行,非实时获取记录。
(注:本文读取聊天记录的方法只适用于监控自己拥有的微信或者QQ ,无法监控或者盗取其他人的聊天记录。本文只写了如何获取聊天记录,服务器落地程序并不复杂,不做赘述。写的仓促,有错别字还请见谅。)
学习交流:
- 即时通讯开发交流3群:185926912[推荐]
- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM》
(本文同步发布于:http://www.52im.net/thread-1992-1-1.html)
2、相关文章
即时通讯网之前整理过微信本地数据库的读取和样本,如有兴趣可请往阅读:
《微信本地数据库破解版(含iOS、Android),仅供学习研究 [附件下载]》
3、准备工作
参阅很多相关的文章之后,对这个需求有了大致的想法,开始着手准备:
1)需要一个有root权限的Android手机,我用的是红米5(强调必须已被ROOT);
2)android的开发环境(就是Android Studio那一套啦);
3)android相关的开发经验(我是个PHP,第一次写Android程序,踩了不少坑)。
4、获取微信聊天记录过程分享
4.1 着手准备
微信的聊天记录保存在Android系统的:"/data/data/com.tencent.mm/MicroMsg/c5fb89d4729f72c345711cb*/EnMicroMsg.db" 目录和文件下。
该文件是加密的数据库文件,需要用到sqlcipher来打开。密码为:MD5(手机的IMEI+微信UIN)的前七位。文件所在的那个乱码文件夹的名称也是一段加密MD5值:MD5('mm'+微信UIN)。微信的UIN存放在微信文件夹“/data/data/com.tencent.mmshared_prefs/system_config_prefs.xml”中。(这个减号一定要带着!)

另外:即时通讯网之前整理过微信本地数据库的样本,如有兴趣可请往下载:《微信本地数据库破解版(含iOS、Android),仅供学习研究 [附件下载]》。
注意:如果手机是双卡双待,那么会有两个IMEI号,默认选择 IMEI1,如果不行,可以尝试一下字符串‘1234567890ABCDEF’。早期的微信会去判定你的IMEI,如果为空 默认选择这个字符串。

拿到密码,就可以打开EnMicroMsg.db了。微信聊天记录,包括个人、群组的所有记录全部存在message这张表里(如下图所示),就像下面这两张截图里展示的一样。

(为了方便截图,此图截自《微信本地数据库破解版(含iOS、Android),仅供学习研究 [附件下载]》中的样本)

(为了方便截图,此图截自《微信本地数据库破解版(含iOS、Android),仅供学习研究 [附件下载]》中的样本)
4.2 代码实现
第一步,不可能直接去访问EnMicroMsg.db。因为没有权限,还要避免和微信本身产生冲突,所以选择把这个文件拷贝到自己的项目下:
oldPath ="/data/data/com.tencent.mm/MicroMsg/c5fb89d4729f72c345711cb**\***/EnMicroMsg.db";
newPath ="/data/data/com.你的项目/EnMicroMsg.db";
copyFile(oldPath,newPath);//代码见 部分源码
第二步,拿到文件的密码:
String password = (MD5Until.md5("IMEI+微信UIN").substring(0, 7).toLowerCase());
第三步,打开文件,执行SQL:
SQLiteDatabase.loadLibs(context);
SQLiteDatabaseHook hook = newSQLiteDatabaseHook() {
publicvoidpreKey(SQLiteDatabase database) {
}
publicvoidpostKey(SQLiteDatabase database) {
database.rawExecSQL("PRAGMA cipher_migrate;");//很重要
}
};
SQLiteDatabase db = openDatabase(newPath, password, null, NO_LOCALIZED_COLLATORS, hook);
longnow = System.currentTimeMillis();
Log.e("readWxDatabases", "读取微信数据库:"+ now);
intcount = 0;
if(msgId != "0") {
String sql = "select * from message";
Log.e("sql", sql);
Cursor c = db.rawQuery(sql, null);
while(c.moveToNext()) {
long_id = c.getLong(c.getColumnIndex("msgId"));
String content = c.getString(c.getColumnIndex("content"));
inttype = c.getInt(c.getColumnIndex("type"));
String talker = c.getString(c.getColumnIndex("talker"));
longtime = c.getLong(c.getColumnIndex("createTime"));
JSONObject tmpJson = handleJson(_id, content, type, talker, time);
returnJson.put("data"+ count, tmpJson);
count++;
}
c.close();
db.close();
Log.e("readWxDatanases", "读取结束:"+ System.currentTimeMillis() + ",count:"+ count);
}
到此,我们就可以通过自已写的代码拿到微信的聊天记录了,之后可以直接将整理好的JSON通过POST请求发到服务器就可以了。(忍不住吐槽:写服务器落地程序用了30分钟,写上面这一坨花了三四天,还不包括搭建开发环境、下载SDK、折腾ADB什么的)。
5、获取QQ聊天记录过程分享
5.1 说明
QQ的聊天记录有点麻烦,他的文件保存在:“/data/data/com.tencent.mobileqq/databases/你的QQ号码.db”。
这个文件是不加密的,可以直接打开。QQ中群组的聊天记录是单独建表存放的,所有的QQ群信息存放在TroopInfoV2表里,需要对字段troopuin求MD5,然后找到他的聊天记录表:mr_troop_" + troopuinMD5 +"_New。
但是!(看到“但是”就没好事。。。)
问题来了,它的内容是加密的,而且加密方法还很复杂:根据手机IMEI循环逐位异或。具体的我不举例子了,太麻烦,直接看文章最后的解密方法。
5.2 代码实现
第一步,还是拷贝数据库文件:
final String QQ_old_path = "/data/data/com.tencent.mobileqq/databases/QQ号.db";
final String QQ_new_path = "/data/data/com.android.saurfang/QQ号.db";
DataHelp.copyFile(QQ_old_path,QQ_new_path);
第二步,打开并读取内容:
SQLiteDatabase.loadLibs(context);
String password = "";
SQLiteDatabaseHook hook = newSQLiteDatabaseHook() {
publicvoidpreKey(SQLiteDatabase database) {}
publicvoidpostKey(SQLiteDatabase database) {
database.rawExecSQL("PRAGMA cipher_migrate;");
}
};
MessageDecode mDecode = newMessageDecode(imid);
HashMap<String, String> troopInfo = newHashMap<String, String>();
try{
SQLiteDatabase db = openDatabase(newPath,password,null, NO_LOCALIZED_COLLATORS,hook);
longnow = System.currentTimeMillis();
Log.e("readQQDatabases","读取QQ数据库:"+now);
//读取所有的群信息
String sql = "select troopuin,troopname from TroopInfoV2 where _id";
Log.e("sql",sql);
Cursor c = db.rawQuery(sql,null);
while(c.moveToNext()){
String troopuin = c.getString(c.getColumnIndex("troopuin"));
String troopname = c.getString(c.getColumnIndex("troopname"));
String name = mDecode.nameDecode(troopname);
String uin = mDecode.uinDecode(troopuin);
Log.e("readQQDatanases","读取结束:"+name);
troopInfo.put(uin, name);
}
c.close();
inttroopCount = troopInfo.size();
Iterator<String> it = troopInfo.keySet().iterator();
JSONObject json = newJSONObject();
//遍历所有的表
while(troopCount > 0) {
try{
while(it.hasNext()) {
String troopuin = (String)it.next();
String troopname = troopInfo.get(troopuin);
if(troopuin.length() < 8)
continue;
String troopuinMD5 = getMD5(troopuin);
String troopMsgSql = "select _id,msgData, senderuin, time from mr_troop_"+ troopuinMD5 +"_New";
Log.e("sql",troopMsgSql);
Cursor cc = db.rawQuery(troopMsgSql,null);
JSONObject tmp = newJSONObject();
while(cc.moveToNext()) {
long_id = cc.getLong(cc.getColumnIndex("_id"));
byte[] msgByte = cc.getBlob(cc.getColumnIndex("msgData"));
String ss = mDecode.msgDecode(msgByte);
//图片不保留
if(ss.indexOf("jpg") != -1|| ss.indexOf("gif") != -1
|| ss.indexOf("png") != -1)
continue;
String time = cc.getString(cc.getColumnIndex("time"));
String senderuin = cc.getString(cc.getColumnIndex("senderuin"));
senderuin = mDecode.uinDecode(senderuin);
JSONObject tmpJson = handleQQJson(_id,ss,senderuin,time);
tmp.put(String.valueOf(_id),tmpJson);
}
troopCount--;
cc.close();
}
} catch(Exception e) {
Log.e("e","readWxDatabases"+e.toString());
}
}
db.close();
}catch(Exception e){
Log.e("e","readWxDatabases"+e.toString());
}
然后你就可以把信息发到服务器落地了(同样跟微信的记录上传一样,通过你自已写的代码发送到你的服务端就可以了)。
6、题外话:一些注意点
这里还有几个需要注意的地方。
1)最新安卓系统很难写个死循环直接跑了,所以我们需要使用Intent,来开始Service,再通过Service调用AlarmManager,就像下面的代码这样:
publicclassMainActivity extendsAppCompatActivity {
privateIntent intent;
@Override
protectedvoidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity\_main);
intent = newIntent(this, LongRunningService.class);
startService(intent);
}
@Override
protectedvoidonDestroy() {
super.onDestroy();
stopService(intent);
}
}
然后再创建一个LongRunningService,在其中调用AlarmManager:
AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);
intMinutes = 60*1000; //此处规定执行的间隔时间
longtriggerAtTime = SystemClock.elapsedRealtime() + Minutes;
Intent intent1 = newIntent(this, AlarmReceiver.class);//注入要执行的类
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent1, 0);
manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pendingIntent);
returnsuper.onStartCommand(intent, flags, startId);
在AlarmReceiver中调用我们的方法:
//微信部分
postWXMsg.readWXDatabase();
//QQ部分
postQQMsg.readQQDatabase();
//再次开启LongRunningService这个服务,即可实现定时循环。
Intent intentNext = newIntent(context, LongRunningService.class);
context.startService(intentNext);
2)安卓不允许在主线程里进行网络连接,可以直接用 retrofit2 来发送数据(或者最简单的方法就是用AsyncTask了)。
3)项目需要授权网络连接(就是在AndroidManifast.xml里加上网络权限申请就是了);
4)项目需要引入的包:
implementation files('libs/sqlcipher.jar')
implementation files('libs/sqlcipher-javadoc.jar')
implementation 'com.squareup.retrofit2:retrofit:2.0.0'
implementation 'com.squareup.retrofit2:converter-gson:2.0.0'
5)如果复制文件时失败,校验文件路径不存在,多半是因为授权问题。需要对数据库文件授权 全用户rwx权限;
6)如果服务端使用MySql数据库的话,数据库编码请用utf8mb4编码,用来支持Emoji表情。。
7、我的部分源码
(因为种种原因,我不太好直接把源码贴上来,现把几个实用方法分享出来,可以直接使用。)
复制文件的方法:
/**
* 复制单个文件
*
* @param oldPath String 原文件路径 如:c:/fqf.txt
* @param newPath String 复制后路径 如:f:/fqf.txt
* @return boolean
*/
publicstaticbooleancopyFile(String oldPath, String newPath) {
deleteFolderFile(newPath, true);
Log.e("copyFile", "time_1:"+ System.currentTimeMillis());
InputStream inStream = null;
FileOutputStream fs = null;
try{
intbytesum = 0;
intbyteread = 0;
File oldfile = newFile(oldPath);
Boolean flag = oldfile.exists();
Log.e("copyFile", "flag:"+flag );
if(oldfile.exists()) { //文件存在时
inStream = newFileInputStream(oldPath); //读入原文件
fs = newFileOutputStream(newPath);
byte[] buffer = newbyte[2048];
while((byteread = inStream.read(buffer)) != -1) {
bytesum += byteread; //字节数 文件大小
fs.write(buffer, 0, byteread);
}
Log.e("copyFile", "time_2:"+ System.currentTimeMillis());
}
} catch(Exception e) {
System.out.println("复制单个文件操作出错");
e.printStackTrace();
} finally{
try{
if(inStream != null) {
inStream.close();
}
if(fs != null) {
fs.close();
}
} catch(IOException e) {
e.printStackTrace();
}
}
returntrue;
}
/**
* 删除单个文件
*
* @param filepath
* @param deleteThisPath
*/
publicstaticvoiddeleteFolderFile(String filepath, booleandeleteThisPath) {
if(!TextUtils.isEmpty(filepath)) {
try{
File file = newFile(filepath);
if(file.isDirectory()) {
//处理目录
File files[] = file.listFiles();
for(inti = 0; i < file.length(); i++) {
deleteFolderFile(files[i].getAbsolutePath(), true);
}
}
if(deleteThisPath) {
if(!file.isDirectory()) {
//删除文件
file.delete();
} else{
//删除目录
if(file.listFiles().length == 0) {
file.delete();
}
}
}
} catch(Exception e) {
e.printStackTrace();
}
}
}
MD5方法:
publicclassMD5Until {
publicstaticcharHEX_DIGITS[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F'};
//将字符串转化为位
publicstaticString toHexString(byte[] b){
StringBuilder stringBuilder = newStringBuilder(b.length * 2);
for(inti = 0; i < b.length; i++) {
stringBuilder.append(HEX_DIGITS[(b[i] & 0xf0) >>> 4]);
stringBuilder.append(HEX_DIGITS[b[i] & 0x0f]);
}
returnstringBuilder.toString();
}
publicstaticString md5(String string){
try{
MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
digest.update(string.getBytes());
bytemessageDigest[] = digest.digest();
returntoHexString(messageDigest);
}catch(NoSuchAlgorithmException e){
e.printStackTrace();
}
return"";
}
}
QQ信息解密方法:
public class MessageDecode {
public String imeiID;
public intimeiLen;
public MessageDecode(String imeiID)
{
this.imeiID = imeiID;
this.imeiLen = imeiID.length();
}
public boolean isChinese(bytech) {
intres = ch & 0x80;
if(res != 0)
returntrue;
returnfalse;
}
public String timeDecode(String time)
{
String datetime = "1970-01-01 08:00:00";
SimpleDateFormat sdFormat = newSimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try{
longsecond = Long.parseLong(time);
Date dt = newDate(second * 1000);
datetime = sdFormat.format(dt);
} catch(NumberFormatException e) {
e.printStackTrace();
}
returndatetime;
}
public String nameDecode(String name)
{
bytenbyte[] = name.getBytes();
byteibyte[] = imeiID.getBytes();
bytexorName[] = newbyte[nbyte.length];
intindex = 0;
for(inti = 0; i < nbyte.length; i++) {
if(isChinese(nbyte[i])){
xorName[i] = nbyte[i];
i++;
xorName[i] = nbyte[i];
i++;
xorName[i] = (byte)(nbyte[i] ^ ibyte[index % imeiLen]);
index++;
} else{
xorName[i] = (byte)(nbyte[i] ^ ibyte[index % imeiLen]);
index++;
}
}
return new String(xorName);
}
public String uinDecode(String uin)
{
byteubyte[] = uin.getBytes();
byteibyte[] = imeiID.getBytes();
bytexorMsg[] = newbyte[ubyte.length];
intindex = 0;
for(inti = 0; i < ubyte.length; i++) {
xorMsg[i] = (byte)(ubyte[i] ^ ibyte[index % imeiLen]);
index++;
}
returnnewString(xorMsg);
}
public String msgDecode(byte[] msg)
{
byteibyte[] = imeiID.getBytes();
bytexorMsg[] = newbyte[msg.length];
intindex = 0;
for(int i = 0; i < msg.length; i++) {
xorMsg[i] = (byte)(msg[i] ^ ibyte[index % imeiLen]);
index++;
}
return new String(xorMsg);
}
}
附录:有关微信、QQ的技术文章汇总
《腾讯技术分享:腾讯是如何大幅降低带宽和网络流量的(图片压缩篇)》
《腾讯技术分享:腾讯是如何大幅降低带宽和网络流量的(音视频技术篇)》
《腾讯技术分享:Android版手机QQ的缓存监控与优化实践》
《微信团队分享:iOS版微信的高性能通用key-value组件技术实践》
《微信团队分享:iOS版微信是如何防止特殊字符导致的炸群、APP崩溃的?》
《腾讯技术分享:Android手Q的线程死锁监控系统技术实践》
《QQ音乐团队分享:Android中的图片压缩技术详解(上篇)》
《QQ音乐团队分享:Android中的图片压缩技术详解(下篇)》
《腾讯团队分享 :一次手Q聊天界面中图片显示bug的追踪过程分享》
《微信团队分享:微信Android版小视频编码填过的那些坑》
《微信团队披露:微信界面卡死超级bug“15。。。。”的来龙去脉》
《月活8.89亿的超级IM微信是如何进行Android端兼容测试的》
《微信客户端团队负责人技术访谈:如何着手客户端性能监控和优化》
《微信团队原创分享:Android版微信的臃肿之困与模块化实践之路》
《微信团队原创分享:微信客户端SQLite数据库损坏修复实践》
《腾讯原创分享(一):如何大幅提升移动网络下手机QQ的图片传输速度和成功率》
《腾讯原创分享(二):如何大幅压缩移动网络下APP的流量消耗(下篇)》
《腾讯原创分享(三):如何大幅压缩移动网络下APP的流量消耗(上篇)》
《如约而至:微信自用的移动端IM网络层跨平台组件库Mars已正式开源》
《开源libco库:单机千万连接、支撑微信8亿用户的后台框架基石 [源码下载]》
《微信新一代通信安全解决方案:基于TLS1.3的MMTLS详解》
《微信团队原创分享:Android版微信后台保活实战分享(进程保活篇)》
《微信团队原创分享:Android版微信后台保活实战分享(网络保活篇)》
《Android版微信从300KB到30MB的技术演进(PPT讲稿) [附件下载]》
《微信团队原创分享:Android版微信从300KB到30MB的技术演进》
《微信技术总监谈架构:微信之道——大道至简(PPT讲稿) [附件下载]》
《微信海量用户背后的后台系统存储架构(视频+PPT) [附件下载]》
《微信异步化改造实践:8亿月活、单机千万连接背后的后台解决方案》
《架构之道:3个程序员成就微信朋友圈日均10亿发布量[有视频]》
《微信团队原创分享:Android内存泄漏监控和优化技巧总结》
《微信团队原创Android资源混淆工具:AndResGuard [有源码]》
《移动端IM实践:Android版微信如何大幅提升交互性能(一)》
《移动端IM实践:Android版微信如何大幅提升交互性能(二)》
《移动端IM实践:WhatsApp、Line、微信的心跳策略分析》
《移动端IM实践:谷歌消息推送服务(GCM)研究(来自微信)》
《信鸽团队原创:一起走过 iOS10 上消息推送(APNS)的坑》
《腾讯TEG团队原创:基于MySQL的分布式数据库TDSQL十年锻造经验分享》
《微信多媒体团队访谈:音视频开发的学习、微信的音视频技术和挑战等》
《了解iOS消息推送一文就够:史上最全iOS Push技术详解》
《腾讯资深架构师干货总结:一文读懂大型分布式系统设计的方方面面》
《腾讯音视频实验室:使用AI黑科技实现超低码率的高清实时视频聊天》
《腾讯技术分享:微信小程序音视频与WebRTC互通的技术思路和实践》
《手把手教你读取Android版微信和手Q的聊天记录(仅作技术研究学习)》
>> 更多同类文章 ……
(本文同步发布于:http://www.52im.net/thread-1992-1-1.html)
作者:Jack Jiang (点击作者姓名进入Github)
出处:http://www.52im.net/space-uid-1.html
交流:欢迎加入即时通讯开发交流群 215891622
讨论:http://www.52im.net/
Jack Jiang同时是【原创Java Swing外观工程BeautyEye】和【轻量级移动端即时通讯框架MobileIMSDK】的作者,可前往下载交流。
本博文 欢迎转载,转载请注明出处(也可前往 我的52im.net 找到我)。
【转】手把手教你读取Android版微信和手Q的聊天记录(仅作技术研究学习)的更多相关文章
- 手把手教你读取Android版微信和手Q的聊天记录(仅作技术研究学习)
1.引言 特别说明:本文内容仅用于即时通讯技术研究和学习之用,请勿用于非法用途.如本文内容有不妥之处,请联系JackJiang进行处理! 我司有关部门为了获取黑产群的动态,有同事潜伏在大量的黑产群 ...
- 微信团队分享:Kotlin渐被认可,Android版微信的技术尝鲜之旅
本文由微信开发团队工程是由“oneliang”原创发表于WeMobileDev公众号,内容稍有改动. 1.引言 Kotlin 是一个用于现代多平台应用的静态编程语言,由 JetBrains 开发( ...
- 手把手教你修改iOS版QQ的运动步数
手把手教你修改iOS版QQ的运动步数 现在很多软件都加上了运动模块,比如QQ和微信,而且还有排行榜,可以和好友比较谁的运动步数多,任何东西只要添加了比较功能,就变得不一样了.今天教大家用代码去修改QQ ...
- 用Kotlin破解Android版微信小游戏-跳一跳
前言 微信又更新了,从更新日志上来看,似乎只是一次不痛不痒的小更新.不过,很快就有人发现,原来微信这次搞了个大动作——在小程序里加入了小游戏.今天也是朋友圈被刷爆的缘故. 看到网上 有人弄了一个破解版 ...
- Android版-微信APP支付
首发地址: Android版-微信APP支付 欢迎留言.转发 微信极速开发系列文章(微信支付.授权获取用户信息等):点击这里 目录 1.注册账号.开发者认证 2.添加应用 3.申请微信支付 4.技术开 ...
- Android版微信小代码(转)
以下代码仅适用于Android版微信: //switchtabpos:让微信tab更贴合Android Design 如果你并不喜欢微信Android版和iOS端同用一套UI,现在有一个小方法可以实现 ...
- 手把手教你实现Android真机远程截屏
先看效果演示 接下来手把手教你实现这样的效果. minicap简介 minicap是一个可以远程获取android屏幕画面的开源库,它在低版本的Android系统上采用截屏的方式获取画面,在Andro ...
- 读取PC版微信数据库(电脑版微信数据库)内容
原始网址 https://www.cnblogs.com/Charltsing/p/WeChatPCdb.html 1.PC版微信的密钥是32位byte,不同于安卓版(7位字符串) 2.通过OD或 ...
- android版微信5.2.1更新 支持微信聊天记录备份到电脑上
昨天微信 5.2.1 for Android 全新发布了,和微信 5.2.1 for iPhone一样,支持拍照分享,可以把照片发送给多个朋友,最重要的一个更新是支持微信聊天记录备份到电脑(可以通过腾 ...
随机推荐
- Error:"MetaStoreClient lost connection. Attempting to reconnect (1 of 24) after 5s. getCurrentNotificationEventId" occurs as HiveServer2 fails to start as it cannot connect to Metastore in HDP 3.0
SupportKB Problem Description:After upgrading to HDP 3.0, the HiveServer2 fails to start and the fol ...
- SpringBoot2.0之六 多环境配置
开发过程中面对不同的环境,例如数据库.redis服务器等的不同,可能会面临一直需要修改配置的麻烦中,在以前的项目中,曾通过Tomcat的配置来实现,有的项目甚至需要手动修改相关配置,这种方式费时费力, ...
- 为 VUE 项目添加 PWA 解决发布后刷新报错问题
为什么要给 VUE 项目添加 PWA 为什么要添加?因为不管是部署在 IIS,还是 nginx,每次应用部署后,再次访问因为旧的 js 已经不存在,所以页面访问的时候会整个报错,报错的结果就是一个白屏 ...
- 实战经验|大神战队都在i春秋教你打CTF
全国大学生信息安全竞赛创新实践能力赛旨在培养.选拔.推荐优秀信息安全专业人才创造条件,促进高等学校信息安全专业课程体系.教学内容和方法的改革,培养学生的创新意识与团队合作精神,普及信息安全知识,增强学 ...
- webpack学习笔记一:安装webpack、webpack-dev-server、内存加载js和html文件、loader处理非js文件
一 .webpack学习环境准备: 1:window系统 2:安装node.js 官方网址 下载好后下一步下一步安装即可 安装步骤略过....... 3:nrm的安装 打开cmd命令控制台 输入:n ...
- 3.Git基础-查看当前文件状态、跟踪新文件、暂存文件、忽略文件、提交更新、移除文件、移动文件
1.检查当前文件状态 -- git status git diff git diff --staged git status :我们可以使用 git status 来查看文件所处的状态.当运 ...
- 使用nvm管理node不同版本,安装,环境配置,切换不同版本的node版本
文章包含以下内容: 一.下载地址 二.nvm-noinstall.zip安装 三.nvm-setup.zip安装 四.测试安装以及使用 一.下载地址 https://github.com/coreyb ...
- SQL自动生成java实体类POJO
前言 当我们设计完成数据库之后,通常需要创建对应的实体类,有的称为Entity,有的称为DO,都是一个意思,而自己一个个去写非常的麻烦,所以麻烦的时候就需要相应的自动工具类解决这样的麻烦.超级方便~ ...
- tcc分布式事务框架解析
前言碎语 楼主之前推荐过2pc的分布式事务框架LCN.今天来详细聊聊TCC事务协议. 2pc实现:https://github.com/codingapi/tx-lcn tcc实现:https://g ...
- Java基础系列-Stream
原创作品,可以转载,但是请标注出处地址:https://www.cnblogs.com/V1haoge/p/10748817.html 一.概述 Stream操作简称流操作,这里的流与IO流毫无关系, ...