開篇
PC微信端讀取聯系人有三種常規方法:
- hook相關call來實現攔截聯系人數據
- 讀取內存中的包含聯系人的二叉樹結構
- 解密讀取微信本地數據庫
其實前兩種方法只是利用微信啟動后已經讀取聯系人放到內存。第一種是攔截過程,第二種是直接獲取內存的結果。
第一種方法
找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(備注)) + '\n')
左節點地址 = 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運行一遍就行。