PC端:
微信的主要功能都是在WeChat\[3.9.10.27]\WeChatWin.dll
动态链接库中实现的
直接进IDA分析
都没有符号表
我们需要找一下实现撤回功能的函数,尝试在字符串里搜索revokeMsg
也是有非常多的字符串
我们需要用frida来hook这些字符串来找出撤回实际调用的函数
先初步写一个脚本找到WeChatWin.dll的基地址
python
#wecaht_hook
import frida
import sys
def main(target_process):
session = frida.attach(target_process)
jsCode = """
//找WeChatWin.dll映射到内存的根地址
const baseAddr = Module.findBaseAddress('WeChatWin.dll');
console.log("WeChatWin.dll baseAddr: " + baseAddr);
"""
#js脚本控制注入逻辑
script = session.create_script(jsCode)
script.load() #加载脚本
print("Process attatched successfully!")
sys.stdin.read() #持续执行
if __name__=='__main__':
target_process = 15964 #pid
main(target_process)
'''
WeChatWin.dll baseAddr: 0x7ffb6d8e0000
Process attatched successfully!
'''
任务管理器可以查看pid
成功回显
但是这里输出的地址是个装载之后的虚拟地址,要与ida中函数的地址对应,还需要进行一个转化
这是IDA中的基地址0x180000000
python
#wecaht_hook
import frida
import sys
def main(target_process):
session = frida.attach(target_process)
jsCode = """
//找WeChatWin.dll映射到内存的根地址
const baseAddr = Module.findBaseAddress('WeChatWin.dll');
console.log("WeChatWin.dll baseAddr: " + baseAddr);
const revokeMsgFunAddr = resolveAddress('0x1823CC870'); //测试的目标函数地址
console.log('revokeMsgFunAddr: ' + revokeMsgFunAddr);
Interceptor.attach(revokeMsgFunAddr, {
//一旦进入地址的回调函数
onEnter(args) {
console.log('test!');
}
})
//虚拟地址转化为实际内存地址
function resolveAddress(addr) {
const idaBase = ptr(0x180000000);
const offset = ptr(addr).sub(idaBase); //偏移地址
const result = baseAddr.add(offset);
return result;
}
"""
#js脚本控制注入逻辑
script = session.create_script(jsCode)
script.load() #加载脚本
print("Process attatched successfully!")
sys.stdin.read() #持续执行
if __name__=='__main__':
target_process = 15964
main(target_process)
然后把这个脚本跑起来,用另一个号发消息并进行撤回操作,逐个函数进行尝试
调试到SyncMgr::ProcessRevokeMsg
对应的函数时,有了回显
我们进相应的函数sub_1823CC870进行静态分析
发现多个分支都调用了sub_1826DA2D0函数,且之前的字符串也在其参数当中,这时候再去hook该函数0x1826DA2D0也是有回显的
那么只要跳过这个函数应该就不会撤回了
但是这个位置的if判断过于复杂(或),不容易跳过
那我们就看一下上一级的sub_1823CC870函数在哪里被调用
可以看到是sub_1823E4AD0函数
这里也可以hook一下,确认回显
转成伪代码会发现这里是一个switch语句,当v9==4时就会触发撤回的函数
很显然那是通过cmp edi, 4
来比较
那就在这里注入0x1823E4CBA
我们把edi(64位对应的rdi)的值强行修改成不是4的值(这里改成0)
python
#wecaht_hook
import frida
import sys
def main(target_process):
session = frida.attach(target_process)
jsCode = """
//找WeChatWin.dll映射到内存的根地址
const baseAddr = Module.findBaseAddress('WeChatWin.dll');
console.log("WeChatWin.dll baseAddr: " + baseAddr);
const revokeMsgFunAddr = resolveAddress('0x1823E4CBA');
console.log('revokeMsgFunAddr: ' + revokeMsgFunAddr);
Interceptor.attach(revokeMsgFunAddr, {
//一旦进入地址的回调函数
onEnter(args) {
console.log('called!');
console.log("original rdi: " + this.context.rdi);
this.context.rdi = 0;
console.log("changed rdi: " + this.context.rdi);
}
})
//虚拟地址转化为实际内存地址
function resolveAddress(addr) {
const idaBase = ptr(0x180000000);
const offset = ptr(addr).sub(idaBase); //偏移地址
const result = baseAddr.add(offset);
return result;
}
"""
#js脚本控制注入逻辑
script = session.create_script(jsCode)
script.load() #加载脚本
print("Process attatched successfully!")
sys.stdin.read() #持续执行
if __name__=='__main__':
target_process = 15964
main(target_process)
撤回的消息就被固定了!
当然要在本地持续化利用,直接把dll里面的
这部分指令NOP掉也行
参考: