@leptune
2018-09-12T02:16:48.000000Z
字数 9194
阅读 303
chrome插件
可以定时、批量、自动发送信息给好友、群,可以获取微信聊天消息的应用程序,即成为微信机器人。
现在网上流传的微信机器人都是利用web微信的接口来实现的,利用模拟登录web微信,来获取微信接口调用凭证和cookie信息,以实现微信机器人。但这个方式有个弊端,就是很容易被微信查封。因为微信可以通过检测web微信端的cookie和一些接口请求、数据特征、cookie特征等,来辨别该接口是否是web微信调用的,还是微信机器人调用的。
所以,最安全的方式,是利用chrome插件可以注入js的方法,往web微信端注入js,在js中调用微信的各种接口,进行最大限度伪装自己是web微信调用的接口,从而避免被封!
若不用开发者工具栏,而直接用js来模拟微信登录的话,会变得异常艰难。
首先,需要获取各种必须的参数,有些必须研究web微信js源码,才能知道是怎么获取的参数。
其次,即使各种参数都获取到了,也模拟登录成功了,但依然有可能被微信察觉,毕竟不是web微信发起的登录。
最后,用js模拟登录,实现会过于复杂,一旦微信更改登录机制,那也意味着插件要改动非常多!
而如果是利用开发者工具栏的chrome插件,不用去费劲脑筋去模拟登录微信,不用去研究怎么获取微信调用凭证,不用去思考怎么获取微信登录cookie。利用开发者工具栏的chrome插件,有个非常有用的api,就是可以监听网页的所有请求。利用这点,当web微信登录成功后,监听web微信发起的获取联系人接口、群列表接口、发送信息接口、获取最新信息接口等,然后模拟这些接口,发起微信请求,即可伪装成web微信,来发起这些请求,避免被微信查封!!!
{
"manifest_version": 2,
"name": "微信机器人",
"description": "chrome微信机器人",
"version": "1.0",
"browser_action": {
"default_icon": "img/icon.png"
},
"devtools_page": "devtools.html",
"background": {
"scripts": ["js/jquery-2.0.3.js", "js/background.js"]
},
"content_scripts": [{
"matches": ["https://wx2.qq.com/*","https://wx.qq.com/*"],
"js": ["js/jquery-2.0.3.js", "js/content.js"]
}
],
"permissions": [
"activeTab",
"tabs",
"https://login.weixin.qq.com/*",
"https://wx2.qq.com/*",
"http://www.wx-robot.com/*",
"https://wx.qq.com/*"
]
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="js/devtools.js" charset="utf-8" type="text/javascript"></script>
</head>
<body>
</body>
</html>
chrome.extension.sendRequest({tabId: chrome.devtools.inspectedWindow.tabId, action: 'dev_start', msg: 'devtools js start'});
// dev域用于toolbar的网络监听
chrome.devtools.network.onRequestFinished.addListener(function (request) {
// 转发所有微信请求到background页面
if (request.request.url.indexOf('wx2.qq.com') != -1 || request.request.url.indexOf('wx.qq.com') != -1) {
request.getContent(function (body) {
chrome.extension.sendRequest({
tabId: chrome.devtools.inspectedWindow.tabId,
action: 'request',
request: request,
body: body,
});
});
}
return true;
});
console.log('backgroud js start');
// 监听来自content-script的消息
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
// console.log('收到content-js消息');
switch (request.action) {
case 'request':
// console.log(request);
if (request.data.type == 'post') {
$.post(request.data.url, request.data.data, function (data) {
// console.log('post res:', data);
sendResponse(data);
});
} else {
$.get(request.data.url, function (data) {
// console.log('get res:', data);
sendResponse(data);
});
}
break;
}
return true;
});
// 接收来自dev页面的消息
chrome.extension.onRequest.addListener(function (request) {
// 直接转发给content页面
// console.log(request)
chrome.tabs.sendRequest(request.tabId, request);
});
console.log('content js start');
var initGlobals = {
friendsInfo: {},
friends: {},
groupsInfo: {},
groups: {},
myInfo: {},
my: {},
sendBase: {},
notFirst: true,
};
var otherGlobals = {
adminUser: {},
};
String.prototype.trimChars = function (c) {
var re = new RegExp("^[" + c + "]+|[" + c + "]+$", "g");
return this.replace(re, "");
}
function init_globals() {
initGlobals = {
friendsInfo: {},
friends: {},
groupsInfo: {},
groups: {},
myInfo: {},
my: {},
sendBase: {},
notFirst: true,
};
}
function typeOf(obj) {
return {}.toString.call(obj).split(' ')[1].slice(0, -1).toLowerCase();
}
function isEmpty(value) {
if (!value) {
return true;
}
if ('array' == typeOf(value) || 'string' == typeOf(value)) {
return !value.length;
}
if('object' == typeOf(value)){
for(var key in value) {
if(Object.prototype.hasOwnProperty.call(value, key)) {
return false;
}
}
return true;
}
return false;
}
function getNullKeys() {
var nullKeys = [];
for (var key in initGlobals) {
if (isEmpty(initGlobals[key])) {
nullKeys.push(key);
}
}
return nullKeys;
}
function login() {
$('body').append('\
<div class="wx-robot-top">\
<style>\
.wx-robot-zzc {position: fixed; top: 0; right: 0; bottom: 0; left: 0; background-color: rgba(0,0,0,.8); z-index:9998}\
.wx-robot-wrap {width: 100%;text-align: center;position: absolute;top: 20%;background: none;z-index: 9999;}\
.wx-robot-div {width: 60%; text-align: center; background: #f1f1f1; padding: 31px; margin: 0 auto;}\
.wx-robot-btn-user {width: 30%; padding: 6px 12px; font-size: 14px; line-height: 1.42857143; color: #555; background-color: #fff; border: 1px solid #ccc; border-radius: 4px;}\
.wx-robot-btn-pwd {width: 30%; padding: 6px 12px; font-size: 14px; line-height: 1.42857143; color: #555; background-color: #fff; border: 1px solid #ccc; border-radius: 4px;}\
.wx-robot-btn-login {width: 19%; padding: 6px 12px; font-size: 14px; line-height: 1.42857143; color: #555; background-color: #fff; border: 1px solid #ccc; border-radius: 4px;}\
.wx-robot-btn-login:hover {color: #333; background-color: #e6e6e6; border-color: #adadad; }\
</style>\
<div class="wx-robot-wrap">\
<div class="wx-robot-div">\
<h1>微信机器人后台管理系统</h1>\
<br/>\
<div class="my-wx-robot">\
<input class="wx-robot-btn-user" name="robot_user" type="text" placeholder="用户名">\
<input class="wx-robot-btn-pwd" name="robot_pwd" type="password" placeholder="密码">\
<input class="wx-robot-btn-login" type="button" value="登录">\
</div>\
</div>\
</div>\
<div class="wx-robot-zzc"></div>\
</div>\
');
}
function setInitGlobas(key, value) {
// console.log('get initGlobals.'+key);
initGlobals[key] = value;
//发送消息content层
var nullKeys = getNullKeys();
if (!nullKeys.length) {
console.log('all finished!');
initGlobals.notFirst = false; // 确保初始化程序只运行一次
myRequest({
url: 'http://www.wx-robot.com/index/chrome/isLogin',
callback: function(data) { //检测是否已经登录后台
// console.log(data);
if (data.errcode) {
login();
} else {
otherGlobals.adminUser = data.data;
console.log('开始监听任务...');
listenTask();
}
},
});
} else {
if (nullKeys.length > 1) console.log('nullKeys: ', nullKeys);
}
}
function do_request(request) {
var reqData = request.request.request;
if (-1 != reqData.url.indexOf('&me=me')) { // 避开循环监听
return;
}
// 获取群联系人(不能直接用监听返回的数据,因为中文会乱码)
if (-1 != reqData.url.indexOf('wx2.qq.com/cgi-bin/mmwebwx-bin/webwxbatchgetcontact')) {
var tmpData = JSON.parse(reqData.postData.text);
if (!isEmpty(tmpData) && !isEmpty(tmpData.BaseRequest)) {
setInitGlobas('sendBase', tmpData.BaseRequest);
}
$.post(reqData.url+'&me=me', JSON.stringify(JSON.parse(reqData.postData.text)), function (data) {
setInitGlobas('groupsInfo', JSON.parse(data));
var tmpData = {};
initGlobals.groupsInfo.ContactList.forEach(function(e){
tmpData[e.NickName] = e.UserName;
});
setInitGlobas('groups', tmpData);
});
}
if (-1 != reqData.url.indexOf('wx2.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact')) {
// 获取联系人(不能直接用监听返回的数据,因为中文会乱码)
$.get(reqData.url+'&me=me', function (data) {
setInitGlobas('friendsInfo', JSON.parse(data));
var tmpData = {};
initGlobals.friendsInfo.MemberList.forEach(function(e){
tmpData[e.NickName] = e.UserName;
});
setInitGlobas('friends', tmpData);
});
}
if (-1 != reqData.url.indexOf('wx2.qq.com/cgi-bin/mmwebwx-bin/webwxinit')) {
var tmpData = JSON.parse(request.body);
if (!isEmpty(tmpData) && !isEmpty(tmpData.User)) {
setInitGlobas('myInfo', tmpData);
setInitGlobas('my', tmpData.User);
}
}
if (-1 != reqData.url.indexOf('wx2.qq.com/cgi-bin/mmwebwx-bin/webwxlogout')) {
// 重新初始化
init_globals();
}
}
function myRequest(param) {
chrome.runtime.sendMessage({
action: 'request',
data: param,
}, function(response) {
if (param.callback) {
param.callback(response);
}
});
}
function sendmsg(data, task_id) {
if (!data.nickname && !data.username) {
return;
}
var Msg = {
Type: 1,
Content: "0",
FromUserName: "0",
ToUserName: "0",
LocalID: "0",
ClientMsgId: "0"
};
var username = data.username;
if (!username) {
if (!data.isGroup && initGlobals.friends[data.nickname]) {
username = initGlobals.friends[data.nickname];
} else if (data.isGroup && initGlobals.groups[data.nickname]) {
username = initGlobals.groups[data.nickname];
}
}
if (!username) {
console.log('没有该用户: ', data.nickname);
return;
}
Msg.Content = data.msg;
Msg.ToUserName = username;
Msg.FromUserName = initGlobals.my.UserName;
var clientMsgId = new Date().getTime() + (Math.random() + "").substring(2, 6);
Msg.LocalID = clientMsgId;
Msg.ClientMsgId = clientMsgId;
$.post("https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?lang=zh_CN&me=me", JSON.stringify({BaseRequest: initGlobals.sendBase, Msg: Msg, Scene: 0}), function (data) {
data = JSON.parse(data);
// console.log(data);
if (data.BaseResponse.Ret) {
console.log('发送消息失败: ', data.BaseResponse.ErrMsg);
return;
}
console.log('发送消息成功!');
if (task_id) {
myRequest({url: 'http://www.wx-robot.com/index/chrome/execReport?is_success=1&task_id='+task_id, callback: function (data) {
console.log(data);
}});
}
});
}
var clickFlag = 0;
function loginSuccess() {
alert('成功,可以关掉开发者工具栏了!');
$('.wx-robot-top').remove();
// 保持在线
(function heartBit() {
//模拟点击
if(clickFlag == 0) {
clickFlag = 1;
$('.web_wechat_tab_chat').click();
}else {
clickFlag = 0;
$('.web_wechat_tab_friends').click();
}
sendmsg({
username: 'filehelper',
msg: "保持在线:" + new Date(),
});
setTimeout(heartBit, 20*1000);
})();
}
// 循环等待服务器的任务
function listenTask() {
myRequest({
url: 'http://www.wx-robot.com/index/chrome/listen',
callback: function(data) {
// console.log(data);
if (!data.errcode) {
console.log('get task: ', data);
data = data.data;
switch (data.action) {
case 'sendmsg':
sendmsg(data.data, data.id);
break;
}
}
setTimeout(listenTask, 1000);
},
});
}
$(document).on('click', '.wx-robot-btn-login', function(event) {
myRequest({
url: 'http://www.wx-robot.com/index/chrome/login',
type: 'post',
data: {
user: $('.wx-robot-btn-user').val(),
pwd: $('.wx-robot-btn-pwd').val(),
},
callback: function(data) {
// console.log('login data:', data);
if (!data.errcode) {
otherGlobals.adminUser = data.data;
loginSuccess();
listenTask();
} else {
alert('用户名或密码错误!');
}
},
});
});
// 接收来自background页面的消息
chrome.extension.onRequest.addListener(function(request) {
// console.log('收到background消息');
switch (request.action) {
case 'dev_start':
console.log('devtools js start');
break;
case 'request':
do_request(request);
break;
}
return true;
});