zoukankan      html  css  js  c++  java
  • PC微信读取微信好友列表(联系人)

    开篇

    PC微信端读取联系人有三种常规方法:

    1. hook相关call来实现拦截联系人数据
    2. 读取内存中的包含联系人的二叉树结构
    3. 解密读取微信本地数据库

    其实前两种方法只是利用微信启动后已经读取联系人放到内存。第一种是拦截过程,第二种是直接获取内存的结果。

    第一种方法

    找CALL请看:https://blog.csdn.net/qq_38474570/article/details/95889507

    我就不复述了,我也是小白,也是一步一步按照博客来操作的。我就直接给当前最新版本(2.8.0.121)的需要hook的地址偏移:0x479F07,如果不想自己找CALL的话,可以直接用OD跳转到 WeChatWin.dll + 0x479F07 这个地址。已经知道需要hook的地址,只需要用c++写dll然后注入到微信进程就可以得到所有的联系人信息了(这个call会在登录时被调用多次,所以需要登录前就注入dll)

    成品软件和dll(软件是用aardio写的,dll是用c++写的):https://www.lanzous.com/iakfpch

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

    第二种方法

    相比于第一种方法,这个更简单,连写dll注入都不需要。只要读内存中的数据就行。

    首先我们需要找到二叉树的根节点地址,方法请看:https://www.jianshu.com/p/b5585f03d849 (环境声太吵,人说话声音有点小,不过讲的不错)

    最新版本(2.8.0.121)二叉树根节点的地址:[[WeChatwin.dll + 0x161CF54]+0x28+0x84] + 0x4,中括号表示取地址里面的值。这个地址的偏移也是通过第一个方法的call找出来的,而且第一个方法中的call进去的代码就是通过传入的wxid来循环遍历二叉树来获取该wxid对应的好友数据。

    我们看一下call里面的汇编代码段:
    在这里插入图片描述
    然后用aardio来实现就是:

    import process;
    import console;
    
    getBTree = function(prcs, esi){  //前面不加var表示全局变量
    	if (!prcs.readNumber(esi + 0xD, "byte")){  //cmp byte ptr ds:[esi+0xD],0x0
    		//wxid
    		wxidAddr = prcs.readNumber(esi + 0x10) //获取wxid地址
    		wxidLen = prcs.readNumber(esi + 0x14)  //获取wxid长度
    		wxid = prcs.readStringUtf16(wxidAddr, wxidLen) // 读取Unicode字符串
    		wxid = string.fromUnicode(wxid)   //将Unicode字符串转换为utf-8
    		//微信号
    		微信号地址 = prcs.readNumber(esi + 0x44)
    		微信号长度 = prcs.readNumber(esi + 0x48)
    		微信号 = prcs.readStringUtf16(微信号地址, 微信号长度)
    		微信号 = string.fromUnicode(微信号)
    		//昵称
    		昵称地址 = prcs.readNumber(esi + 0x8C)
    		昵称长度 = prcs.readNumber(esi + 0x8C + 0x4)
    		昵称 = prcs.readStringUtf16(昵称地址, 昵称长度)
    		昵称 = string.fromUnicode(昵称)
    		//备注
    		备注地址 = prcs.readNumber(esi + 0x78)
    		备注长度 = prcs.readNumber(esi + 0x78 + 0x4)
    		备注 = prcs.readStringUtf16(备注地址, 备注长度)
    		备注 = string.fromUnicode(备注)
    		//v1
    		v1Addr = prcs.readNumber(esi + 0x58)
    		v1Len = prcs.readNumber(esi + 0x5C)
    		v1 = prcs.readStringUtf16(v1Addr, v1Len)
    		v1 = string.fromUnicode(v1)
    		//未知a1
    		a1Addr = prcs.readNumber(esi + 0xCC)
    		a1Len = prcs.readNumber(esi + 0xD0)
    		a1 = prcs.readStringUtf16(a1Addr, a1Len)
    		//未知a2
    		a2Addr = prcs.readNumber(esi + 0xE0)
    		a2Len = prcs.readNumber(esi + 0xE4)
    		a2 = prcs.readStringUtf16(a2Addr, a2Len)
    		console.writeText(string.format("%s | %s | %s | %s", tostring(wxid), tostring(微信号), tostring(昵称), tostring(备注)) + '
    ')
    		
    		左节点地址 = prcs.readNumber(esi)
    		getBTree(prcs, 左节点地址)
    		右节点地址 = prcs.readNumber(esi + 0x8)
    		getBTree(prcs, 右节点地址)
    		
    	}
    }
    
    
    var readData = function(){
    	console.open()
    	prcs = process.find("WeChat.exe")
        if (null == prcs){
        	console.writeText('未找到微信进程,请先打开微信登录后操作!')
            return
        }
        wechatwinAddr = prcs.getModuleBaseAddress('WeChatWin.dll')
        ecx = prcs.readNumber(wechatwinAddr + 0x161CF54) + 0x28 + 0x84
    	ebx = prcs.readNumber(ecx)     //mov ebx,dword ptr ds:[ecx]
    	esi = prcs.readNumber(ebx + 0x4) //mov esi,dword ptr ds:[ebx+0x4] esi也就是二叉树的根节点
    	getBTree(prcs, esi)
    	console.pause('按任意键关闭!')
    }
    readData()
    
    

    汇编代码中做了很多比较,是因为它要对比传入的微信ID和内存中的数据,而我们全都要则不需要对比,直接递归读取二叉树的左右节点即可。效果就不放了,自己下载aardio运行一遍就行。

  • 相关阅读:
    Todo
    我的类
    Python socket编程之七:多窗口的应用
    iOS与PHP/Android AES128 ECB NoPadding加密
    JSONModel简便应用
    iOS开发系列--UITableView全面解析
    常用方法
    OC和C++混编
    数据层
    block
  • 原文地址:https://www.cnblogs.com/kanadeblisst/p/12913313.html
Copyright © 2011-2022 走看看