fix: add try-catch to upload hooks to prevent WeChat crash on manual image send

The `attachUploadMedia`, `attachGetCallbackFromWrapper`, and
`uploadOnCompleteAddr` hooks call `readPointer().readUtf8String()` which
can access invalid memory when triggered by normal WeChat image sends
(not API-initiated), causing WeChat to crash immediately.

Wrapping each hook's onEnter body in try-catch prevents the crash while
preserving all functionality. In the catch path, `uploadGlobalX0` is
still captured to ensure subsequent API uploads work correctly.

Tested on WeChat 4.1.7 build 34888 (macOS arm64) with v0.0.8 binary.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
madandan888-star
2026-03-20 19:29:51 +08:00
co-authored by Claude Opus 4.6
parent 53a0a8c0a8
commit 9db2ca38f5
+41 -28
View File
@@ -1553,14 +1553,19 @@ function triggerUploadVideo(receiver, md5, videoPath) {
function attachUploadMedia() {
Interceptor.attach(uploadImageAddr.add(0x10), {
onEnter: function (args) {
uploadGlobalX0 = this.context.x0;
const selfId = this.context.x1.add(0x68).readUtf8String();
const filePath = this.context.x1.add(0xe0).readPointer().readUtf8String();
send({
type: "upload",
self_id: selfId,
})
console.log("UploadMedia x0: " + uploadGlobalX0 + " filePath: " + filePath + " selfId: " + selfId);
try {
uploadGlobalX0 = this.context.x0;
const selfId = this.context.x1.add(0x68).readUtf8String();
const filePath = this.context.x1.add(0xe0).readPointer().readUtf8String();
send({
type: "upload",
self_id: selfId,
})
console.log("UploadMedia x0: " + uploadGlobalX0 + " filePath: " + filePath + " selfId: " + selfId);
} catch (e) {
console.log("[-] attachUploadMedia error: " + e);
uploadGlobalX0 = this.context.x0;
}
}
})
}
@@ -1647,33 +1652,41 @@ setImmediate(patchCdnOnComplete)
function attachGetCallbackFromWrapper() {
Interceptor.attach(uploadGetCallbackWrapperAddr, {
onEnter: function (args) {
const tmpFileId = this.context.x1.readPointer().readUtf8String();
const imageFileId = imageIdAddr.readUtf8String();
const videoFileId = videoIdAddr.readUtf8String()
if (tmpFileId !== imageFileId && tmpFileId !== videoFileId) {
console.log("[+] GetCallbackFromWrapper tmpFileId: " + tmpFileId + " imageFileId: " + imageFileId + " videoFileId:" + videoFileId);
return
}
try {
const tmpFileId = this.context.x1.readPointer().readUtf8String();
const imageFileId = imageIdAddr.readUtf8String();
const videoFileId = videoIdAddr.readUtf8String()
if (tmpFileId !== imageFileId && tmpFileId !== videoFileId) {
console.log("[+] GetCallbackFromWrapper tmpFileId: " + tmpFileId + " imageFileId: " + imageFileId + " videoFileId:" + videoFileId);
return
}
uploadCallback.add(0x10).writePointer(uploadGetCallbackWrapperFuncAddr);
this.context.x8 = uploadCallback;
console.log("[+] GetCallbackFromWrapper x8: " + this.context.x8);
uploadCallback.add(0x10).writePointer(uploadGetCallbackWrapperFuncAddr);
this.context.x8 = uploadCallback;
console.log("[+] GetCallbackFromWrapper x8: " + this.context.x8);
} catch (e) {
console.log("[-] GetCallbackFromWrapper error: " + e);
}
}
})
Interceptor.attach(uploadOnCompleteAddr, {
onEnter: function (args) {
const tmpFileId = this.context.x1.readPointer().readUtf8String();
const imageFileId = imageIdAddr.readUtf8String();
const videoFileId = videoIdAddr.readUtf8String()
if (tmpFileId !== imageFileId && tmpFileId !== videoFileId) {
console.log("[+] OnComplete tmpFileId: " + tmpFileId + " imageFileId: " + imageFileId + " videoFileId:" + videoFileId);
return
}
try {
const tmpFileId = this.context.x1.readPointer().readUtf8String();
const imageFileId = imageIdAddr.readUtf8String();
const videoFileId = videoIdAddr.readUtf8String()
if (tmpFileId !== imageFileId && tmpFileId !== videoFileId) {
console.log("[+] OnComplete tmpFileId: " + tmpFileId + " imageFileId: " + imageFileId + " videoFileId:" + videoFileId);
return
}
uploadCallback.add(0x30).writePointer(uploadOnCompleteFuncAddr);
this.context.x8 = uploadCallback;
console.log("[+] OnComplete x8: " + this.context.x8);
uploadCallback.add(0x30).writePointer(uploadOnCompleteFuncAddr);
this.context.x8 = uploadCallback;
console.log("[+] OnComplete x8: " + this.context.x8);
} catch (e) {
console.log("[-] OnComplete error: " + e);
}
}
})
}