Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1.13.9 #220

Closed
wants to merge 62 commits into from
Closed

1.13.9 #220

wants to merge 62 commits into from

Conversation

atorber
Copy link
Collaborator

@atorber atorber commented Mar 14, 2024

  1. 增加修改好友备注名称接口
  2. 优化示例代码

Summary by CodeRabbit

  • New Features
    • Added functionality for sending link messages with specific offsets.
    • New features related to modifying contact remarks, getting head images, and removing chat room members.
    • Enhanced message processing logic and added asynchronous handling for certain operations.
  • Bug Fixes
    • Improved error handling across various components.
  • Documentation
    • Updated README with settings for contact remark and optimized sample code.
  • Refactor
    • Code refactoring for better readability, consistency, and enhanced error handling in examples.
    • Updated function parameter types and variable names for clarity.
  • Style
    • Adjusted code styling including eslint directives, formatting adjustments, and syntax improvements.
  • Chores
    • Modified bot initialization and startup process.

choogoo and others added 30 commits July 11, 2023 13:51
* 3.9.2.23 initt

* Update init-agent-script.js

* 3.9.2.23 adapter
* 3.9.2.23 initt

* Update init-agent-script.js

* 3.9.2.23 adapter

* 适配3.9.2.23

* Delete agent-script-3.9.2.23-new.js
* 3.9.2.23 initt

* Update init-agent-script.js

* 3.9.2.23 adapter

* 适配3.9.2.23

* Delete agent-script-3.9.2.23-new.js

* 适配3.9.2.23

---------

Co-authored-by: LuChao <atorber@163.com>
1. 修复获取群成员昵称乱码
1.13.2删除agent的ts文件
atorber and others added 19 commits January 19, 2024 17:27
* 3.9.2.23 init (wechaty#180)

* 3.9.2.23 initt

* Update init-agent-script.js

* 3.9.2.23 adapter

* 3.9.2.23 init (wechaty#182)

* 3.9.2.23 initt

* Update init-agent-script.js

* 3.9.2.23 adapter

* 适配3.9.2.23

* Delete agent-script-3.9.2.23-new.js

* 适配3.9.2.23 (wechaty#185)

* 3.9.2.23 initt

* Update init-agent-script.js

* 3.9.2.23 adapter

* 适配3.9.2.23

* Delete agent-script-3.9.2.23-new.js

* 适配3.9.2.23

---------

Co-authored-by: LuChao <atorber@163.com>

* add 1.3.0 illustrate

* Update README.md

* Update README.md

* add demo

* 1.13.1

* 1.13.1

* 1.13.2 dev

* 增加扫码登录、检测登录状态

* 增加登入登出事件

* 增加ts改造init

* 1.13.2

* 1.13.2

* 1.13.2

* 1.13.2

* 1.13.2

1. 修复获取群成员昵称乱码

* Update .npmignore

* Update .gitignore

* 1.13.2删除agent的ts文件

* 1.13.4

* 1.13.5

* Update init-agent-script.ts

* 1.13.5

* 1.13.6

* del png file

* Update init-agent-script.js

* 1.13.7 修复@好友出现两个昵称的bug

---------

Co-authored-by: choogoo <104893934+choogoo@users.noreply.github.com>
1. Add setting for contact remark
2. Optimize sample code
Add XP Discord Invite Link
Copy link

coderabbitai bot commented Mar 14, 2024

Walkthrough

The recent updates involve a comprehensive overhaul aimed at refining functionality and readability throughout the project. Key enhancements include new features for handling link messages, modifying contact remarks, and managing chat room members. The changes focus on improving code clarity, consistency, error handling, and overall user experience through asynchronous operations and updated logging and messaging functions.

Changes

Files Change Summary
README.md Added a setting for contact remarks and optimized sample code in versions v1.13.12 and v1.13.9.
src/init-agent-script.js/ts Added functionality for sending link messages with specific offsets, refactored contact remark functions, and introduced new chat room member management features.
examples/demo.ts Refactored code for better readability, updated parameter types, improved error handling and logging, enhanced message processing logic.
examples/quick-start.ts, examples/ripe-wechaty.ts Adjusted syntax and formatting, improved readability, and error handling.
examples/raw-sidecar.ts Added asynchronous handling and improved error handling in the login event scenario.
src/puppet-xp.ts, src/wechat-sidecar.ts Adjusted constructor defaults, added modifyContactRemark method, improved method handling.
.vscode/launch.json Introduced a configuration for debugging portfiles using CMake with specific communication settings.
tests/frida.js, tests/frida.ts Introduced functionality for interacting with WeChat using Frida, including various actions like sending messages, checking login status, and managing contacts.

🐇✨
In the realm of code, where changes abound,
A rabbit hopped, leaving magic unbound.
Through refactor and tweak, a clearer path found,
With every hop, improvement astound.
So here's to the journey, long and profound,
Where code grows stronger, by leaps and bounds.
🌟🐰
"""

Related issues

  • Issue #2642: The changes in this PR address the objectives of processing and responding to incoming messages, improving contact interaction handling, and enhancing message processing logic within the WeChat platform. This issue aligns with the enhancements made in various files related to message handling and contact management.

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share

Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit-tests for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit tests for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit tests.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • The JSON schema for the configuration file is available here.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/coderabbit-overrides.v2.json

CodeRabbit Discord Community

Join our Discord Community to get help, request features, and share feedback.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 9

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between eb9f9a6 and 9291df0.
Files ignored due to path filters (1)
  • package.json is excluded by: !**/*.json
Files selected for processing (9)
  • README.md (1 hunks)
  • examples/demo.ts (3 hunks)
  • examples/quick-start.ts (8 hunks)
  • examples/raw-sidecar.ts (7 hunks)
  • examples/ripe-wechaty.ts (6 hunks)
  • src/init-agent-script.js (10 hunks)
  • src/init-agent-script.ts (7 hunks)
  • src/puppet-xp.ts (2 hunks)
  • src/wechat-sidecar.ts (1 hunks)
Additional comments: 19
examples/ripe-wechaty.ts (3)
  • 1-1: The addition of the eslint-disable sort-keys directive at the top of the file disables sorting keys in objects. While this can make the code more readable in some cases by grouping related properties, it's important to ensure that this decision aligns with the project's coding standards.
  • 115-118: The error handling in the try-catch block for saving the file is well-implemented. It's good practice to catch and log errors during file operations to avoid crashing the application. Consider adding more specific error messages or handling based on the type of error for improved diagnostics.
  • 140-146: > 📝 NOTE

This review was outside the diff hunks and was mapped to the diff hunk with the greatest overlap. Original lines [143-178]

The initialization of the PuppetXp object with a specific wechatVersion and the subsequent setup of event handlers (onScan, onLogin, etc.) is correctly implemented. However, ensure that the wechatVersion used here is compatible with the rest of the application and that any potential version mismatches are handled appropriately.

examples/raw-sidecar.ts (3)
  • 45-45: Adding await to sidecar.isLoggedIn() before checking isLoggedIn ensures that the login status is accurately obtained before proceeding. This is a good practice for asynchronous operations.
  • 77-88: The asynchronous handling and error catching in the loginEvent case are well-implemented. It's important to handle potential errors in asynchronous operations to prevent unhandled promise rejections. Consider adding more specific error handling based on the error type for improved diagnostics.
  • 182-184: Replacing await detach(sidecar) with void detach(sidecar) in the clean function changes the execution from waiting for the detachment to complete to fire-and-forget. Ensure this change aligns with the desired behavior, especially regarding resource cleanup and potential side effects.
README.md (1)
  • 105-109: The documentation update clearly outlines the new features and optimizations introduced in version 1.13.9, including the addition of a setting for contact remark and sample code optimization. Ensure that these features are accurately described and that any necessary details for users to utilize them are provided.
src/wechat-sidecar.ts (1)
  • 143-147: The addition of the modifyContactRemark method to the WeChatSidecar class is a significant enhancement, allowing for the modification of contact remark names. Ensure that the method is correctly integrated with the rest of the application and that its usage is documented for developers.
examples/quick-start.ts (3)
  • 1-1: Adding the eslint-disable sort-keys directive at the top of the file disables the sorting keys rule for the entire file. Ensure this aligns with the project's coding standards and that disabling this rule won't lead to maintainability issues, especially in larger objects where sorted keys can improve readability.
  • 19-19: The function declaration onScan correctly uses a space before the opening parenthesis, aligning with common TypeScript formatting standards. This improves readability and consistency across the codebase.
  • 136-161: The conditional checks for message types are correctly implemented using array includes method, which is a clean and efficient way to check if the message type matches any of the specified types. This approach enhances readability and maintainability.
examples/demo.ts (2)
  • 2-2: Adding the eslint-disable sort-keys directive at the top of the file disables the sorting keys rule for the entire file. Ensure this aligns with the project's coding standards and that disabling this rule won't lead to maintainability issues, especially in larger objects where sorted keys can improve readability.
  • 196-293: > 📝 NOTE

This review was outside the diff hunks and was mapped to the diff hunk with the greatest overlap. Original lines [187-291]

The main function demonstrates various operations such as finding contacts by ID, name, or alias, and sending messages. It's well-structured and provides a comprehensive example of interacting with the Wechaty API. However, ensure that all error handling is consistent and provides sufficient context for debugging.

src/puppet-xp.ts (2)
  • 82-82: The change to initialize options with an empty object {} in the constructor is a good practice for ensuring that the options parameter is always an object. This prevents potential undefined or null errors when attempting to access properties of options.
  • 650-653: Adding a conditional block in the contactAlias method to handle setting contact aliases is a functional enhancement. However, it's important to ensure that the sidecar.modifyContactRemark method properly handles errors and rejects the promise if an error occurs. This will prevent silent failures and make error handling more robust in the calling code.
src/init-agent-script.ts (3)
  • 669-722: The function modifyContactRemarkFunction is designed to modify the remark of a contact. However, there are several points to consider for improvement and verification:
  • Ensure that the memory allocated for strings and structures is properly freed to avoid memory leaks.
  • Validate the offsets used in the function calls to ensure they are correct for the targeted version of the application.
  • Consider adding error handling to manage any failures in native function calls or memory allocations.
  • 726-785: The function getHeadImage aims to retrieve the head image of a contact. Similar considerations as the previous function apply here:
  • Memory management is crucial; ensure allocated memory is released appropriately.
  • Offsets and native function calls should be verified for correctness.
  • Adding error handling for native function calls and memory operations would improve robustness.
  • 1395-1448: The function sendLinkMsgNativeFunction is marked as unfinished. To improve this function:
  • Ensure that all parameters are used correctly within the function.
  • Verify the correctness of offsets and native function calls.
  • Implement error handling for native function calls and memory operations.
  • Consider the security implications of handling URLs and ensure they are sanitized.
src/init-agent-script.js (1)
  • 1256-1264: > 📝 NOTE

This review was outside the diff hunks and was mapped to the diff hunk with the greatest overlap. Original lines [1247-1261]

The recvMsgNativeCallback function sets up a callback for receiving messages. While the implementation is technically correct, it's essential to consider the following:

  • Error Handling: The function lacks comprehensive error handling, especially for the native function calls and memory operations.
  • Performance: Ensure that the callback does not adversely affect the performance of the host application, especially since it's invoked for every received message.
  • Security: Be cautious about the security implications of reading and modifying memory directly.

Implement robust error handling and review the function for potential performance and security issues.

Comment on lines +593 to +631
var modifyContactRemarkFunction = function (contactId, text) {
var txtAsm = Memory.alloc(Process.pageSize);
var wxidPtr = Memory.alloc(contactId.length * 2 + 2);
wxidPtr.writeUtf16String(contactId);
var picWxid = Memory.alloc(0x0c);
picWxid.writePointer(ptr(wxidPtr)).add(0x04)
.writeU32(contactId.length * 2).add(0x04)
.writeU32(contactId.length * 2).add(0x04);
var contentPtr = Memory.alloc(text.length * 2 + 2);
contentPtr.writeUtf16String(text);
var sizeOfStringStruct = Process.pointerSize * 5;
var contentStruct = Memory.alloc(sizeOfStringStruct);
contentStruct
.writePointer(contentPtr).add(0x4)
.writeU32(text.length).add(0x4)
.writeU32(text.length * 2);
// const ecxBuffer = Memory.alloc(0x2d8)
Memory.patchCode(txtAsm, Process.pageSize, function (code) {
var writer = new X86Writer(code, {
pc: txtAsm
});
writer.putPushfx();
// writer.putMovRegAddress('eax', content);
writer.putPushax();
writer.putMovRegAddress('eax', contentStruct);
writer.putPushReg('eax');
// writer.putMovRegAddress('eax', contact);
writer.putMovRegAddress('eax', picWxid);
// writer.putMovRegAddress('ecx', ecxBuffer)
writer.putPushReg('eax');
// console.log('begin call mod_addr:', mod_addr)
writer.putCallAddress(mod_addr);
writer.putCallAddress(moduleBaseAddress.add(wxOffsets.contact.WX_MOD_REMARK_OFFSET));
// writer.putAddRegImm('esp', 0x18);
writer.putPopax();
writer.putPopfx();
writer.putRet();
writer.flush();
});
// console.log('----------txtAsm', txtAsm)
var nativeativeFunction = new NativeFunction(ptr(txtAsm), 'void', []);
nativeativeFunction();
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The implementation of modifyContactRemarkFunction uses Frida's Memory.alloc and NativeFunction to modify contact remarks directly in memory. While this approach is powerful, it comes with several risks and considerations:

  • Memory Management: Ensure that allocated memory is managed properly to avoid leaks. In this case, it looks managed well, but always double-check.
  • Error Handling: There's no visible error handling in case the native calls fail. Consider adding try-catch blocks or checking return values where applicable.
  • Security and Stability: Direct memory manipulation can lead to stability issues or security vulnerabilities if not done carefully. Make sure to test extensively across different environments and WeChat versions.
  • Documentation: Adding comments explaining the purpose of specific memory addresses and the overall process can help maintainability and future updates.

Consider adding error handling and documentation for clarity and robustness.

Comment on lines +635 to +682
var getHeadImage = function (contactId, url) {
var txtAsm = Memory.alloc(Process.pageSize);
var wxidPtr = Memory.alloc(contactId.length * 2 + 2);
wxidPtr.writeUtf16String(contactId);
var contact = Memory.alloc(0x0c);
contact.writePointer(ptr(wxidPtr)).add(0x04)
.writeU32(contactId.length * 2).add(0x04)
.writeU32(contactId.length * 2).add(0x04);
var contentPtr = Memory.alloc(url.length * 2 + 2);
contentPtr.writeUtf16String(url);
var sizeOfStringStruct = Process.pointerSize * 5;
var img_url = Memory.alloc(sizeOfStringStruct);
img_url
.writePointer(contentPtr).add(0x4)
.writeU32(url.length).add(0x4)
.writeU32(url.length * 2);
// const ecxBuffer = Memory.alloc(0x2d8)
var head_image_mgr_addr = moduleBaseAddress.add(wxOffsets.contact.WX_HEAD_IMAGE_MGR_OFFSET);
var get_img_download_addr = moduleBaseAddress.add(wxOffsets.contact.QUERY_THEN_DOWNLOAD_OFFSET);
var temp = Memory.alloc(0x8);
Memory.patchCode(txtAsm, Process.pageSize, function (code) {
var writer = new X86Writer(code, {
pc: txtAsm
});
writer.putPushfx();
writer.putPushax();
writer.putCallAddress(head_image_mgr_addr);
writer.putMovRegAddress('ecx', img_url);
writer.putPushReg('ecx');
writer.putMovRegAddress('ecx', contact);
writer.putPushReg('ecx');
writer.putMovRegAddress('ecx', temp);
writer.putPushReg('ecx');
// 执行MOV ECX,EAX,将EAX(由head_image_mgr_addr函数返回的值)移动到ECX,用于下一个函数调用
writer.putMovRegReg('ecx', 'eax');
writer.putCallAddress(get_img_download_addr);
// writer.putAddRegImm('esp', 0x18);
writer.putPopax();
writer.putPopfx();
writer.putRet();
writer.flush();
// console.log('end call mod_addr:', mod_addr)
});
// console.log('txtAsm:', modifyContactRemarkAsm)
var nativeFunction = new NativeFunction(ptr(modifyContactRemarkAsm), 'void', []);
// console.log('nativeFunction:', nativeFunction)
// console.log('----------txtAsm', txtAsm)
var nativeativeFunction = new NativeFunction(ptr(txtAsm), 'void', []);
var head_img = nativeativeFunction();
console.log('head_img:', head_img);
return head_img;
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The getHeadImage function demonstrates an advanced use of Frida for interacting with WeChat's internal functions to retrieve contact head images. While the approach is technically sound, similar considerations as previously mentioned apply here:

  • Memory Management: Ensure that all allocated memory is properly managed.
  • Error Handling: There's a lack of error handling mechanisms. Implementing error checks and handling routines would improve the robustness.
  • Documentation: Detailed comments explaining the logic and purpose of each step would enhance the readability and maintainability of the code.

Adding error handling and documentation would significantly improve the code's quality and maintainability.

Comment on lines +1181 to +1225
function sendLinkMsgNativeFunction(wxid, title, url, thumburl, senderId, senderName, digest) {
console.log('Function called with wxid:', wxid, 'title:', title, 'url:', url, 'thumburl:', thumburl, 'senderId:', senderId, 'senderName:', senderName, 'digest:', digest);
var success = -1;
// 假设已经有了这些函数和基地址的相对偏移量
var initChatMsgAddr = moduleBaseAddress.add(wxOffsets.setChatMsgValue.WX_INIT_CHAT_MSG_OFFSET); // 这些偏移量需要替换为实际的偏移量
var appMsgMgrAddr = moduleBaseAddress.add(wxOffsets.appMsgMgr.WX_APP_MSG_MGR_OFFSET);
var newItemAddr = moduleBaseAddress.add(wxOffsets.sendLink.NEW_MM_READ_ITEM_OFFSET);
var freeItem2Addr = moduleBaseAddress.add(wxOffsets.sendLink.FREE_MM_READ_ITEM_2_OFFSET);
var forwardPublicMsgAddr = moduleBaseAddress.add(wxOffsets.sendLink.FORWARD_PUBLIC_MSG_OFFSET);
var buff = Memory.alloc(0x238);
// 调用 newItemAddr 函数初始化 buff
var newItem = new NativeFunction(newItemAddr, 'void', ['pointer']);
newItem(buff);
// 创建WeChatString对象
var toUser = Memory.allocUtf16String(wxid);
var wTitle = Memory.allocUtf16String(title);
var wUrl = Memory.allocUtf16String(url);
var wThumburl = Memory.allocUtf16String(thumburl);
var wSender = Memory.allocUtf16String(senderId);
var wName = Memory.allocUtf16String(senderName);
var wDigest = Memory.allocUtf16String(digest);
// 将WeChatString对象的地址复制到buff中的相应位置
// 注意:这里的偏移量需要根据实际的结构体布局调整
buff.add(0x4).writePointer(wTitle);
buff.add(0x2c).writePointer(wUrl);
buff.add(0x6c).writePointer(wThumburl);
buff.add(0x94).writePointer(wDigest);
buff.add(0x1A0).writePointer(wSender);
buff.add(0x1B4).writePointer(wName);
// 调用其他函数完成消息的转发
try {
var appMsgMgr = new NativeFunction(appMsgMgrAddr, 'pointer', [])();
var initChatMsg = new NativeFunction(initChatMsgAddr, 'void', ['pointer', 'pointer']);
initChatMsg(buff, toUser);
var forwardPublicMsg = new NativeFunction(forwardPublicMsgAddr, 'int', ['pointer']);
success = forwardPublicMsg(appMsgMgr);
var freeItem2 = new NativeFunction(freeItem2Addr, 'void', ['pointer', 'int']);
freeItem2(buff, 0);
}
catch (e) {
console.error('Error during sendLinkMsgNativeFunction function execution:', e);
return false;
}
return success;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sendLinkMsgNativeFunction attempts to send a link message using native function calls. This function is marked as unfinished, and it's crucial to address the following points before considering it complete:

  • Error Handling: The function has a basic try-catch block, but it's essential to handle specific errors more gracefully and provide feedback for debugging.
  • Hardcoded Offsets: The function uses hardcoded memory offsets, which might change between WeChat versions. Consider a more dynamic approach to finding these offsets.
  • Complexity: The function's complexity is high, making it hard to maintain. Breaking it down into smaller, more manageable pieces could help.

Refactor the function to improve error handling, reduce reliance on hardcoded offsets, and decrease complexity for better maintainability.

@@ -187,7 +186,7 @@ async function onMessage(message: Message) {
if (/^luyuchao$/i.test(message.text())) {
const contactCard = await bot.Contact.find({ name: 'luyuchao' })
if (!contactCard) {
console.log('not found')
log.info('contactCard snot found')
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a typographical error in the log message: "contactCard snot found". This should be corrected to "contactCard not found" to ensure clarity and professionalism in log messages.

- log.info('contactCard snot found')
+ log.info('contactCard not found')

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
log.info('contactCard snot found')
log.info('contactCard not found')

}

if (message.type() === types.Message.Image&&false) {
if (message.type() === types.Message.Image) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The handling of image messages to generate and save thumbnail and HD files demonstrates good use of asynchronous operations and file handling. However, consider adding error handling around the file operations (toFile) to gracefully handle any issues that might arise during file saving.

try {
  await thumbFile.toFile(`${process.cwd()}/cache/${thumbFile.name}`, true)
} catch (error) {
  log.error('Error saving thumbnail file:', error)
}

try {
  await hdFile.toFile(`${process.cwd()}/cache/${hdFile.name}`, true)
} catch (error) {
  log.error('Error saving HD file:', error)
}

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
if (message.type() === types.Message.Image) {
if (message.type() === types.Message.Image) {
try {
await thumbFile.toFile(`${process.cwd()}/cache/${thumbFile.name}`, true)
} catch (error) {
log.error('Error saving thumbnail file:', error)
}
try {
await hdFile.toFile(`${process.cwd()}/cache/${hdFile.name}`, true)
} catch (error) {
log.error('Error saving HD file:', error)
}

Comment on lines 787 to 881
const txtAsm: any = Memory.alloc(Process.pageSize)

const wxidPtr: any = Memory.alloc(contactId.length * 2 + 2)
wxidPtr.writeUtf16String(contactId)

const user_id = Memory.alloc(0x0c)
user_id.writePointer(ptr(wxidPtr)).add(0x04)
.writeU32(contactId.length * 2).add(0x04)
.writeU32(contactId.length * 2).add(0x04)

const contentPtr = Memory.alloc(text.length * 2 + 2)
contentPtr.writeUtf16String(text)

const sizeOfStringStruct = Process.pointerSize * 5
const w_msg = Memory.alloc(sizeOfStringStruct)

w_msg
.writePointer(contentPtr).add(0x4)
.writeU32(text.length).add(0x4)
.writeU32(text.length * 2)

// const ecxBuffer = Memory.alloc(0x2d8)

let success = -1;
const contact_mgr_addr = moduleBaseAddress.add(wxOffsets.contactMgr.WX_CONTACT_MGR_OFFSET) ;
const verify_msg_addr = moduleBaseAddress.add(wxOffsets.contact.WX_VERIFY_MSG_OFFSET);
const set_value_addr = moduleBaseAddress.add(wxOffsets.setChatMsgValue.WX_INIT_CHAT_MSG_OFFSET);
const do_verify_user_addr = moduleBaseAddress.add(wxOffsets.contact.WX_DO_VERIFY_USER_OFFSET) ;
const fn1_addr = moduleBaseAddress.add(0x7591b0);

// 创建未知结构体null_obj,并初始化
const nullObjSize = 24; // 根据C++代码中Unkown结构体的大小进行调整
const nullObj = Memory.alloc(nullObjSize);
nullObj.writeByteArray([0, 0, 0, 0, 0, 0, 0xF]); // 根据C++代码中的初始化逻辑进行调整

Memory.patchCode(txtAsm, Process.pageSize, code => {
const writer = new X86Writer(code, {
pc: txtAsm,
})

// PUSHAD
// PUSHFD
writer.putPushfx();
writer.putPushax();

// 调用contact_mgr_addr函数获取实例
writer.putCallAddress(contact_mgr_addr);

// 根据C++代码逻辑设置EDI, ESI和其他参数
// 注意:这部分逻辑可能需要根据实际情况调整
writer.putSubRegImm('edi', 0xE);
writer.putSubRegImm('esi', 0x8);

// 这里使用临时栈空间的逻辑需要特别注意,因为在Frida中直接操作ESP可能不是最佳实践
// 如果fn1_addr函数对ESP的操作是必需的,那么需要确保在Frida脚本中正确模拟
// 可能需要创建一个足够大的buffer来模拟这部分内存操作,而不是直接操作ESP

// 调用fn1_addr函数
writer.putCallAddress(fn1_addr);

// 准备verify_msg_addr函数的参数
writer.putMovRegAddress('eax', w_msg);
writer.putPushReg('eax');
writer.putCallAddress(verify_msg_addr);

// 准备set_value_addr函数的参数
writer.putMovRegPtrReg('eax', wxidPtr);
writer.putPushReg('eax');
writer.putCallAddress(set_value_addr);

// 调用do_verify_user_addr函数
writer.putCallAddress(do_verify_user_addr);

// POPFD
// POPAD
writer.putPopax();
writer.putPopfx();
writer.putRet()
writer.flush();

})

// console.log('----------txtAsm', txtAsm)
const nativeativeFunction = new NativeFunction(ptr(txtAsm), 'int', [])
try {
const success = nativeFunction();
// console.log('设置备注好友备注结果:', success)
return success;
success = nativeativeFunction()
} catch (e) {
// console.error('[设置好友备注]Error during modifyContactRemark nativeFunction function execution:', e);
return false;
console.error('Error during function execution:', e);
return '';
}

};
// 示例调用
// modifyContactRemark("ledongmao", "超哥2");
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function addFriendByWxid is not fully implemented and may cause errors. It's important to:

  • Complete the implementation or remove it if it's not needed.
  • Ensure memory safety by properly managing allocated memory.
  • Verify the correctness of offsets and native function calls.
  • Add comprehensive error handling for robustness.
- // addFriendByWxid('tyutluyc', 'hello')
+ // TODO: Complete the implementation of addFriendByWxid or remove if not needed.

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
// 添加好友——未实现,2024-03-13,会报错
const addFriendByWxid = (contactId: string, text: string) => {
const txtAsm: any = Memory.alloc(Process.pageSize)
const wxidPtr: any = Memory.alloc(contactId.length * 2 + 2)
wxidPtr.writeUtf16String(contactId)
const user_id = Memory.alloc(0x0c)
user_id.writePointer(ptr(wxidPtr)).add(0x04)
.writeU32(contactId.length * 2).add(0x04)
.writeU32(contactId.length * 2).add(0x04)
const contentPtr = Memory.alloc(text.length * 2 + 2)
contentPtr.writeUtf16String(text)
const sizeOfStringStruct = Process.pointerSize * 5
const w_msg = Memory.alloc(sizeOfStringStruct)
w_msg
.writePointer(contentPtr).add(0x4)
.writeU32(text.length).add(0x4)
.writeU32(text.length * 2)
// const ecxBuffer = Memory.alloc(0x2d8)
let success = -1;
const contact_mgr_addr = moduleBaseAddress.add(wxOffsets.contactMgr.WX_CONTACT_MGR_OFFSET) ;
const verify_msg_addr = moduleBaseAddress.add(wxOffsets.contact.WX_VERIFY_MSG_OFFSET);
const set_value_addr = moduleBaseAddress.add(wxOffsets.setChatMsgValue.WX_INIT_CHAT_MSG_OFFSET);
const do_verify_user_addr = moduleBaseAddress.add(wxOffsets.contact.WX_DO_VERIFY_USER_OFFSET) ;
const fn1_addr = moduleBaseAddress.add(0x7591b0);
// 创建未知结构体null_obj,并初始化
const nullObjSize = 24; // 根据C++代码中Unkown结构体的大小进行调整
const nullObj = Memory.alloc(nullObjSize);
nullObj.writeByteArray([0, 0, 0, 0, 0, 0, 0xF]); // 根据C++代码中的初始化逻辑进行调整
Memory.patchCode(txtAsm, Process.pageSize, code => {
const writer = new X86Writer(code, {
pc: txtAsm,
})
// PUSHAD
// PUSHFD
writer.putPushfx();
writer.putPushax();
// 调用contact_mgr_addr函数获取实例
writer.putCallAddress(contact_mgr_addr);
// 根据C++代码逻辑设置EDI, ESI和其他参数
// 注意:这部分逻辑可能需要根据实际情况调整
writer.putSubRegImm('edi', 0xE);
writer.putSubRegImm('esi', 0x8);
// 这里使用临时栈空间的逻辑需要特别注意,因为在Frida中直接操作ESP可能不是最佳实践
// 如果fn1_addr函数对ESP的操作是必需的,那么需要确保在Frida脚本中正确模拟
// 可能需要创建一个足够大的buffer来模拟这部分内存操作,而不是直接操作ESP
// 调用fn1_addr函数
writer.putCallAddress(fn1_addr);
// 准备verify_msg_addr函数的参数
writer.putMovRegAddress('eax', w_msg);
writer.putPushReg('eax');
writer.putCallAddress(verify_msg_addr);
// 准备set_value_addr函数的参数
writer.putMovRegPtrReg('eax', wxidPtr);
writer.putPushReg('eax');
writer.putCallAddress(set_value_addr);
// 调用do_verify_user_addr函数
writer.putCallAddress(do_verify_user_addr);
// POPFD
// POPAD
writer.putPopax();
writer.putPopfx();
writer.putRet()
writer.flush();
})
// console.log('----------txtAsm', txtAsm)
const nativeativeFunction = new NativeFunction(ptr(txtAsm), 'int', [])
try {
const success = nativeFunction();
// console.log('设置备注好友备注结果:', success)
return success;
success = nativeativeFunction()
} catch (e) {
// console.error('[设置好友备注]Error during modifyContactRemark nativeFunction function execution:', e);
return false;
console.error('Error during function execution:', e);
return '';
}
};
// 示例调用
// modifyContactRemark("ledongmao", "超哥2");
}
// TODO: Complete the implementation of addFriendByWxid or remove if not needed.

Comment on lines 999 to 1062
// 移除群成员——未完成,2024-03-13,会导致微信崩溃
const delMemberFromChatRoom = (chat_room_id: string, wxids: string[]) => {
let success: any = 0
const txtAsm: any = Memory.alloc(Process.pageSize)
const get_chat_room_mgr_addr = moduleBaseAddress.add(wxOffsets.chatRoomMgr.WX_CHAT_ROOM_MGR_OFFSET);
const del_member_addr = moduleBaseAddress.add(wxOffsets.chatRoom.WX_DEL_CHAT_ROOM_MEMBER_OFFSET);
const init_chat_msg_addr = moduleBaseAddress.add(wxOffsets.setChatMsgValue.WX_INIT_CHAT_MSG_OFFSET);
const chatRoomPtr = Memory.allocUtf16String(chat_room_id);
const membersBuffer = Memory.alloc(Process.pointerSize * (wxids.length + 1));
for (let i = 0; i < wxids.length; i++) {
const wxidPtr = Memory.allocUtf16String(wxids[i]);
membersBuffer.add(Process.pointerSize * i).writePointer(wxidPtr);
}
membersBuffer.add(Process.pointerSize * wxids.length).writePointer(NULL); // 确保数组以NULL结尾

const get_chat_room_mgr_addr = base_addr.add(wxOffsets.chatRoomMgr.WX_CHAT_ROOM_MGR_OFFSET);
const del_member_addr = base_addr.add(wxOffsets.chatRoom.WX_DEL_CHAT_ROOM_MEMBER_OFFSET);
const init_chat_msg_addr = base_addr.add(wxOffsets.setChatMsgValue.WX_INIT_CHAT_MSG_OFFSET);
const delMemberFromChatRoomAsm: any = Memory.alloc(Process.pageSize);

Memory.patchCode(delMemberFromChatRoomAsm, Process.pageSize, code => {
const writer = new X86Writer(code, { pc: delMemberFromChatRoomAsm });
writer.putPushax();
Memory.patchCode(txtAsm, Process.pageSize, code => {
const writer = new X86Writer(code, {
pc: txtAsm,
})
writer.putPushfx();
writer.putPushax();

console.log('get_chat_room_mgr_addr:', get_chat_room_mgr_addr)
writer.putCallAddress(get_chat_room_mgr_addr);
writer.putSubRegImm('esp', 0x14);
writer.putMovRegReg('esi', 'eax');
writer.putMovRegAddress('ecx', chat_room);
writer.putPushReg('edi');
// writer.putMovRegReg('ecx', 'esp');
console.log('chat_room:', chatRoomPtr)
writer.putMovRegAddress('ecx', chatRoomPtr);
writer.putPushReg('ecx');

console.log('init_chat_msg_addr:', init_chat_msg_addr)
writer.putCallAddress(init_chat_msg_addr);
writer.putMovRegReg('ecx', 'esi');
writer.putMovRegAddress('eax', membersBuffer.add(Process.pointerSize));

console.log('membersBuffer:', membersBuffer)
writer.putMovRegAddress('eax', membersBuffer);
writer.putPushReg('eax');
console.log('del_member_addr:', del_member_addr)
writer.putCallAddress(del_member_addr);
writer.putMovRegReg('eax', 'esi');
writer.putPopfx();

console.log('putPopax:', 'putPopax')
writer.putPopax();
writer.putPopfx();

writer.putRet()
writer.flush();
});
console.log('writer.flush();')
})

console.log('----------txtAsm', txtAsm)
// 调用刚才写入的汇编代码
const nativeFunction = new NativeFunction(ptr(delMemberFromChatRoomAsm), 'void', []);
const nativeFunction = new NativeFunction(ptr(txtAsm), 'int', []);
try {
const success = nativeFunction();
// console.log('success:', success);
success = nativeFunction();
console.log('[踢出群聊]delMemberFromChatRoom success:', success);
return success;
} catch (e) {
// console.error('[踢出群聊]Error during delMemberFromChatRoom nativeFunction function execution:', e);
console.error('[踢出群聊]Error during delMemberFromChatRoom nativeFunction function execution:', e);
return false;

}
};
// delMemberFromChatRoom('21341182572@chatroom', ['ledongmao'])

}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function delMemberFromChatRoom is marked as unfinished and may cause the application to crash. Recommendations include:

  • Finalizing the implementation or removing the function if it's not required.
  • Ensuring memory is managed correctly to prevent leaks.
  • Verifying offsets and native function calls for accuracy.
  • Implementing error handling to catch and manage failures.
- // delMemberFromChatRoom('21341182572@chatroom', ['tyutluyc'])
+ // TODO: Finalize or remove delMemberFromChatRoom to prevent potential crashes.

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
// 移除群成员——未完成,2024-03-13,会导致微信崩溃
const delMemberFromChatRoom = (chat_room_id: string, wxids: string[]) => {
let success: any = 0
const txtAsm: any = Memory.alloc(Process.pageSize)
const get_chat_room_mgr_addr = moduleBaseAddress.add(wxOffsets.chatRoomMgr.WX_CHAT_ROOM_MGR_OFFSET);
const del_member_addr = moduleBaseAddress.add(wxOffsets.chatRoom.WX_DEL_CHAT_ROOM_MEMBER_OFFSET);
const init_chat_msg_addr = moduleBaseAddress.add(wxOffsets.setChatMsgValue.WX_INIT_CHAT_MSG_OFFSET);
const chatRoomPtr = Memory.allocUtf16String(chat_room_id);
const membersBuffer = Memory.alloc(Process.pointerSize * (wxids.length + 1));
for (let i = 0; i < wxids.length; i++) {
const wxidPtr = Memory.allocUtf16String(wxids[i]);
membersBuffer.add(Process.pointerSize * i).writePointer(wxidPtr);
}
membersBuffer.add(Process.pointerSize * wxids.length).writePointer(NULL); // 确保数组以NULL结尾
const get_chat_room_mgr_addr = base_addr.add(wxOffsets.chatRoomMgr.WX_CHAT_ROOM_MGR_OFFSET);
const del_member_addr = base_addr.add(wxOffsets.chatRoom.WX_DEL_CHAT_ROOM_MEMBER_OFFSET);
const init_chat_msg_addr = base_addr.add(wxOffsets.setChatMsgValue.WX_INIT_CHAT_MSG_OFFSET);
const delMemberFromChatRoomAsm: any = Memory.alloc(Process.pageSize);
Memory.patchCode(delMemberFromChatRoomAsm, Process.pageSize, code => {
const writer = new X86Writer(code, { pc: delMemberFromChatRoomAsm });
writer.putPushax();
Memory.patchCode(txtAsm, Process.pageSize, code => {
const writer = new X86Writer(code, {
pc: txtAsm,
})
writer.putPushfx();
writer.putPushax();
console.log('get_chat_room_mgr_addr:', get_chat_room_mgr_addr)
writer.putCallAddress(get_chat_room_mgr_addr);
writer.putSubRegImm('esp', 0x14);
writer.putMovRegReg('esi', 'eax');
writer.putMovRegAddress('ecx', chat_room);
writer.putPushReg('edi');
// writer.putMovRegReg('ecx', 'esp');
console.log('chat_room:', chatRoomPtr)
writer.putMovRegAddress('ecx', chatRoomPtr);
writer.putPushReg('ecx');
console.log('init_chat_msg_addr:', init_chat_msg_addr)
writer.putCallAddress(init_chat_msg_addr);
writer.putMovRegReg('ecx', 'esi');
writer.putMovRegAddress('eax', membersBuffer.add(Process.pointerSize));
console.log('membersBuffer:', membersBuffer)
writer.putMovRegAddress('eax', membersBuffer);
writer.putPushReg('eax');
console.log('del_member_addr:', del_member_addr)
writer.putCallAddress(del_member_addr);
writer.putMovRegReg('eax', 'esi');
writer.putPopfx();
console.log('putPopax:', 'putPopax')
writer.putPopax();
writer.putPopfx();
writer.putRet()
writer.flush();
});
console.log('writer.flush();')
})
console.log('----------txtAsm', txtAsm)
// 调用刚才写入的汇编代码
const nativeFunction = new NativeFunction(ptr(delMemberFromChatRoomAsm), 'void', []);
const nativeFunction = new NativeFunction(ptr(txtAsm), 'int', []);
try {
const success = nativeFunction();
// console.log('success:', success);
success = nativeFunction();
console.log('[踢出群聊]delMemberFromChatRoom success:', success);
return success;
} catch (e) {
// console.error('[踢出群聊]Error during delMemberFromChatRoom nativeFunction function execution:', e);
console.error('[踢出群聊]Error during delMemberFromChatRoom nativeFunction function execution:', e);
return false;
}
};
// delMemberFromChatRoom('21341182572@chatroom', ['ledongmao'])
}
// TODO: Finalize or remove delMemberFromChatRoom to prevent potential crashes.
const delMemberFromChatRoom = (chat_room_id: string, wxids: string[]) => {
let success: any = 0
const txtAsm: any = Memory.alloc(Process.pageSize)
const get_chat_room_mgr_addr = moduleBaseAddress.add(wxOffsets.chatRoomMgr.WX_CHAT_ROOM_MGR_OFFSET);
const del_member_addr = moduleBaseAddress.add(wxOffsets.chatRoom.WX_DEL_CHAT_ROOM_MEMBER_OFFSET);
const init_chat_msg_addr = moduleBaseAddress.add(wxOffsets.setChatMsgValue.WX_INIT_CHAT_MSG_OFFSET);
const chatRoomPtr = Memory.allocUtf16String(chat_room_id);
const membersBuffer = Memory.alloc(Process.pointerSize * (wxids.length + 1));
for (let i = 0; i < wxids.length; i++) {
const wxidPtr = Memory.allocUtf16String(wxids[i]);
membersBuffer.add(Process.pointerSize * i).writePointer(wxidPtr);
}
membersBuffer.add(Process.pointerSize * wxids.length).writePointer(NULL); // 确保数组以NULL结尾
Memory.patchCode(txtAsm, Process.pageSize, code => {
const writer = new X86Writer(code, {
pc: txtAsm,
})
writer.putPushfx();
writer.putPushax();
console.log('get_chat_room_mgr_addr:', get_chat_room_mgr_addr)
writer.putCallAddress(get_chat_room_mgr_addr);
writer.putSubRegImm('esp', 0x14);
writer.putMovRegReg('esi', 'eax');
// writer.putMovRegReg('ecx', 'esp');
console.log('chat_room:', chatRoomPtr)
writer.putMovRegAddress('ecx', chatRoomPtr);
writer.putPushReg('ecx');
console.log('init_chat_msg_addr:', init_chat_msg_addr)
writer.putCallAddress(init_chat_msg_addr);
writer.putMovRegReg('ecx', 'esi');
console.log('membersBuffer:', membersBuffer)
writer.putMovRegAddress('eax', membersBuffer);
writer.putPushReg('eax');
console.log('del_member_addr:', del_member_addr)
writer.putCallAddress(del_member_addr);
console.log('putPopax:', 'putPopax')
writer.putPopax();
writer.putPopfx();
writer.putRet()
writer.flush();
console.log('writer.flush();')
})
console.log('----------txtAsm', txtAsm)
// 调用刚才写入的汇编代码
const nativeFunction = new NativeFunction(ptr(txtAsm), 'int', []);
try {
success = nativeFunction();
console.log('[踢出群聊]delMemberFromChatRoom success:', success);
return success;
} catch (e) {
console.error('[踢出群聊]Error during delMemberFromChatRoom nativeFunction function execution:', e);
return false;
}
}

Comment on lines +45 to +49
const room = await bot.Room.find({ topic:'大师是群主' })
const contact = await bot.Contact.find({ name:'luyuchao' })
log.info('room:', room)
if(room && contact){
const contacts:Contact[]= [contact]
if (room && contact) {
const contacts:Contact[] = [ contact ]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic for sending a message to a room with a specific topic and a contact with a specific name is clear and concise. However, consider adding error handling for the cases where the room or contact is not found to improve robustness.

if (room && contact) {
  const contacts: Contact[] = [contact];
  await room.say(new Date().toLocaleString() + ':瓦力上线了!', ...contacts);
} else {
  log.error('Room or contact not found');
}

@@ -60,7 +61,7 @@
const contact = msg.talker()
log.info('当前联系人信息:', JSON.stringify(contact))
const room = msg.room()
if(room){
if (room) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The use of await inside the if condition to fetch the room topic and owner information is a good practice as it ensures that the information is retrieved before logging. However, ensure that there's proper error handling around these asynchronous calls to handle any potential failures gracefully.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 2

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 9291df0 and bf72246.
Files selected for processing (1)
  • README.md (1 hunks)
Additional comments: 1
README.md (1)
  • 105-109: The addition of the version 1.13.9 section with details on new features and optimizations is clear and concise. However, it would be beneficial to include more specific examples or links to documentation that illustrate how to use the new setting for contact remark modification. This would help users understand and implement the new feature more easily.

README.md Outdated
Comment on lines 102 to 113

## HISTORY

### next v1.13.0 (September 21, 2023)
### next v1.13.9

1. Add setting for contact remark
2. Optimize sample code

### v1.13.0 (September 21, 2023)

1. This version start to support WeChat v3.9.2.23,need to update WeChat on your pc to 3.9.2.23
2. [WeChatSetup-v3.9.2.23.exe](https://github.com/tom-snow/wechat-windows-versions/releases/download/v3.9.2.23/WeChatSetup-3.9.2.23.exe)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 NOTE
This review was outside the diff hunks, and no overlapping diff hunk was found. Original lines [25-25]

There's a missing space after the comma in "Windows,You". It should be corrected to "Windows, You" for proper grammar.

- If you are a user of Windows,You can use this puppet to implement your chatbot.
+ If you are a user of Windows, You can use this puppet to implement your chatbot.

📝 NOTE
This review was outside the diff hunks, and no overlapping diff hunk was found. Original lines [57-57]

The heading "RUNNING WHITH NPM" contains a typo. It should be "RUNNING WITH NPM" to correct the spelling mistake.

- ## RUNNING WHITH NPM
+ ## RUNNING WITH NPM

- 删除了测试使用的wxid
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 5

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between bf72246 and 18ba707.
Files ignored due to path filters (1)
  • package.json is excluded by: !**/*.json
Files selected for processing (7)
  • .vscode/launch.json (1 hunks)
  • examples/quick-start.ts (7 hunks)
  • examples/raw-sidecar.ts (7 hunks)
  • src/init-agent-script.js (10 hunks)
  • src/init-agent-script.ts (8 hunks)
  • tests/frida.js (1 hunks)
  • tests/frida.ts (1 hunks)
Files skipped from review as they are similar to previous changes (4)
  • examples/quick-start.ts
  • examples/raw-sidecar.ts
  • src/init-agent-script.js
  • src/init-agent-script.ts
Additional comments: 9
.vscode/launch.json (1)
  • 1-12: The debug configuration in .vscode/launch.json looks correctly set up for CMake debugging. Ensure that the preLaunchTask named "Debug vcpkg commands" is defined in your tasks.json and correctly configured for your project's needs.
tests/frida.ts (2)
  • 1-20: Consider removing the commented-out console.log in the logging utility for clarity and to keep the codebase clean.
  • 22-225: Ensure to document the source of these offsets and note that they may need to be updated with new versions of WeChat to maintain script functionality.
tests/frida.js (6)
  • 1-1: Please ensure that the Frida script is intended for ethical use and complies with legal regulations and WeChat's terms of service.
  • 4-18: The log object provides a structured way to log information and errors. Consider adding more descriptive comments to explain the purpose of each function within the log object for better maintainability.
  • 20-223: The wxOffsets object contains hardcoded memory offsets. Ensure these offsets are up-to-date and consider documenting the process for updating them, as changes in the WeChat application could render these offsets incorrect.
  • 225-228: Logging the base address and module load information is useful for debugging. However, consider adding a conditional check to only log this information in a debug or verbose mode to avoid cluttering the console output in production.
  • 344-414: The sendMsgNativeFunction function sends a text message. Ensure that this functionality is used in compliance with WeChat's terms of service. Additionally, consider adding error handling for the Memory.alloc and NativeFunction calls to prevent crashes due to memory allocation failures or incorrect function signatures.
  • 650-785: The AddFriendByWxid function adds a friend by their WeChat ID. Ensure that this functionality is used ethically and complies with WeChat's terms of service. Additionally, consider adding error handling for memory allocation and native function calls to improve the robustness of this function.

tests/frida.ts Outdated
Comment on lines 372 to 867
cw.putCallAddress(contact_mgr_addr)
// MOV dword ptr [instance],EAX
cw.putMovNearPtrReg(instance, 'eax')
console.log('instance contact_mgr_addr:',instance.readU32())

// MOV EDI,0xE
cw.putMovRegU32('edi', 0xE)
// MOV ESI,0x8
cw.putMovRegU32('esi', 0x8)
// MOV EAX,0x2
cw.putMovRegU32('eax', 0x2)
// SUB ESP,0x18
cw.putSubRegImm('esp', 0x18)
// MOV EAX,ESP
cw.putMovRegReg('eax', 'esp')
// /* 此处有bug,需要修复
// MOV dword ptr ds:[EAX],0
cw.putMovRegPtrU32('eax', 0)
// MOV dword ptr ds:[EAX+0x14],0xF
cw.putMovRegOffsetPtrU32('eax', 0x14, 0xF)
// MOV dword ptr ds:[EAX+0x10],0
cw.putMovRegOffsetPtrU32('eax', 0x10, 0)
// MOV byte ptr ds:[EAX],0
cw.putMovRegPtrU32('eax', 0)
// SUB ESP,0x18
cw.putSubRegImm('esp', 0x18)
// LEA EAX,null_obj
cw.putMovRegAddress('eax', null_obj)
// MOV ECX,ESP
cw.putMovRegReg('ecx', 'esp')
// PUSH EAX
cw.putPushReg('eax')
// CALL fn1_addr
console.log('fn1_addr:', fn1_addr)
cw.putCallAddress(fn1_addr)
cw.putMovNearPtrReg(successPtr, 'eax')
console.log('successPtr:', successPtr.readU32())
// PUSH ESI
cw.putPushReg('esi')
// PUSH EDI
cw.putPushReg('edi')
// MOV EAX,w_msg
cw.putMovRegAddress('eax', w_msg)
cw.putMovNearPtrReg(successPtr, 'eax')
console.log('w_msg successPtr:', successPtr.readU32())
// SUB ESP,0x14
cw.putSubRegImm('esp', 0x14)
// MOV ECX,ESP
cw.putMovRegReg('ecx', 'esp')
// PUSH -0x1
cw.putPushU32(-0x1)
// PUSH EAX
cw.putPushReg('eax')
// CALL verify_msg_addr
console.log('verify_msg_addr:', verify_msg_addr)
cw.putCallAddress(verify_msg_addr)
cw.putMovNearPtrReg(successPtr, 'eax')
console.log('successPtr:', successPtr.readU32())
// PUSH 0x2
cw.putPushU32(0x2)
// LEA EAX,user_id
cw.putMovRegAddress('eax', user_id)

// SUB ESP,0x14
cw.putSubRegImm('esp', 0x14)
// MOV ECX,ESP
cw.putMovRegReg('ecx', 'esp')
// PUSH EAX
cw.putPushReg('eax')
// CALL set_value_addr
cw.putCallAddress(set_value_addr)
// MOV ECX,dword ptr [instance]
cw.putMovRegAddress('ecx', instance)
// CALL do_verify_user_addr
console.log('do_verify_user_addr:', do_verify_user_addr)
cw.putCallAddress(do_verify_user_addr)
// MOV success,EAX
cw.putMovNearPtrReg(successPtr, 'eax')
// */
// POPFD
// POPAD
cw.putPopax()
cw.putPopfx()
cw.putRet()
cw.flush()
console.log('cw.flush();')
})

console.log('[添加好友]txtAsm', txtAsm)
const nativeativeFunction = new NativeFunction(ptr(txtAsm), 'void', [])
try {
nativeativeFunction()
success = successPtr.readU32()
console.log('[添加好友]success:', success)
return success
} catch (e) {
log.error('[添加好友]Error:', e)
return false
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider enhancing error handling and input validation in the functions defined in this script to reduce the risk of crashing WeChat, especially given the reliance on specific memory offsets and structures.

Comment on lines +232 to +242
var initidStruct = (function (str) {
retidPtr = Memory.alloc(str.length * 2 + 1);
retidPtr.writeUtf16String(str);
retidStruct = Memory.alloc(0x14); // returns a NativePointer
retidStruct
.writePointer(retidPtr).add(0x04)
.writeU32(str.length * 2).add(0x04)
.writeU32(str.length * 2).add(0x04)
.writeU32(0).add(0x04)
.writeU32(0);
return retidStruct;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The initidStruct function initializes a structure for a given string. Consider adding error handling to ensure that memory allocation succeeds and to handle potential issues with string encoding.

tests/frida.js Outdated
Comment on lines 417 to 539
writer.putPopax();
writer.putPopfx();
writer.putRet();
writer.flush();
});
// console.log('----------txtAsm', txtAsm)
var newItem = new NativeFunction(ptr(txtAsm), 'void', []);
newItem();
// const newItem = new NativeFunction(newItemAddr, 'void', ['pointer']);
// console.log('newItem:', newItem);
// newItem(buff);
// console.log('buff1:', buff);
// 创建WeChatString对象
toUser = initStruct(wxid);
wTitle = initStruct(title);
wUrl = initStruct(url);
wThumburl = initStruct(thumburl);
wSender = initStruct(senderId);
wName = initStruct(senderName);
wDigest = initStruct(digest);
console.log('toUser:', toUser, 'wTitle:', wTitle, 'wUrl:', wUrl, 'wThumburl:', wThumburl, 'wSender:', wSender, 'wName:', wName, 'wDigest:', wDigest);
// 将WeChatString对象的地址复制到buff中的相应位置
// 注意:这里的偏移量需要根据实际的结构体布局调整
var successPtr = Memory.alloc(4);
buff.add(0x4).writePointer(wTitle);
buff.add(0x2c).writePointer(wUrl);
buff.add(0x6c).writePointer(wThumburl);
buff.add(0x94).writePointer(wDigest);
buff.add(0x1A0).writePointer(wSender);
buff.add(0x1B4).writePointer(wName);
console.log('buff:', buff);
// 调用其他函数完成消息的转发
try {
// 调用 newItemAddr 函数初始化 buff
var txtAsm2_1 = Memory.alloc(Process.pageSize);
console.log('txtAsm2:', txtAsm2_1);
Memory.patchCode(txtAsm2_1, Process.pageSize, function (code) {
var writer = new X86Writer(code, {
pc: txtAsm2_1
});
// PUSHAD
writer.putPushax();
// PUSHFD
writer.putPushfx();
// CALL app_msg_mgr_addr
console.log('appMsgMgrAddr:', appMsgMgrAddr);
writer.putCallAddress(appMsgMgrAddr);
// LEA ECX,buff
writer.putMovRegAddress('ecx', buff);
// PUSH ECX
writer.putPushReg('ecx');
// SUB ESP,0x14
writer.putSubRegImm('esp', 0x14);
// MOV EDI,EAX
writer.putMovRegReg('edi', 'eax'); // MOV EDI, EAX
// MOV ECX,ESP
writer.putMovRegReg('ecx', 'esp'); // MOV ECX, ESP
// LEA EBX,to_user
writer.putMovRegAddress('ebx', toUser); // LEA EBX, to_user
// PUSH EBX
writer.putPushReg('ebx'); // PUSH EBX
// CALL init_chat_msg_addr
console.log('initChatMsgAddr:', initChatMsgAddr);
writer.putCallAddress(initChatMsgAddr);
// MOV ECX,EDI
writer.putMovRegReg('ecx', 'edi'); // MOV ECX, EDI
// CALL forward_public_msg_addr
writer.putCallAddress(forwardPublicMsgAddr);
// MOV success,EAX
writer.putMovNearPtrReg(successPtr, 'eax');
// writer.putMovRegReg('success', 'eax'); // MOV success, EAX 实际上应该改成内存写入操作,因为 Frida 的 X86Writer 没有提供直接操作变量的架构。
// ADD EBX,0x14
writer.putAddRegImm('ebx', 0x14); // ADD EBX, 0x14
// LEA ECX,buff
writer.putMovRegAddress('ecx', buff); // LEA ECX, buff
// PUSH 0x0
writer.putPushU32(0x0); // PUSH 0x0
// CALL free_item_2_addr
console.log('freeItem2Addr:', freeItem2Addr);
writer.putCallAddress(freeItem2Addr);
console.log('writer end');
// POPFD
writer.putPopfx();
// POPAD
writer.putPopax();
writer.putRet();
writer.flush();
console.log('writer flush');
});
// console.log('----------txtAsm2', txtAsm2)
var newItem1 = new NativeFunction(ptr(txtAsm2_1), 'void', []);
newItem1();
success = successPtr.readU32();
log.info('[发送link消息]success:', success);
return success;
}
catch (e) {
log.error('[发送link消息]Error during sendLinkMsgNativeFunction function execution:', e);
return false;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sendLinkMsgNativeFunction is marked as incomplete. If this function is critical to the script's functionality, consider completing its implementation or removing it if it's not needed. Additionally, ensure that the use of this function complies with WeChat's terms of service.

Would you like assistance in completing the implementation of sendLinkMsgNativeFunction?

tests/frida.js Outdated
Comment on lines 573 to 647
var chatRoomPtr = null;
var membersBuffer = null;
var delMemberFromChatRoom = function (chat_room_id, wxids) {
var success = 0;
var successPtr = Memory.alloc(4);
var txtAsm = Memory.alloc(Process.pageSize);
var get_chat_room_mgr_addr = moduleBaseAddress.add(wxOffsets.chatRoomMgr.WX_CHAT_ROOM_MGR_OFFSET);
var del_member_addr = moduleBaseAddress.add(wxOffsets.chatRoom.WX_DEL_CHAT_ROOM_MEMBER_OFFSET);
var init_chat_msg_addr = moduleBaseAddress.add(wxOffsets.setChatMsgValue.WX_INIT_CHAT_MSG_OFFSET);
chatRoomPtr = createWeChatString(chat_room_id);
membersBuffer = Memory.alloc(Process.pointerSize * (wxids.length + 1));
console.log('membersBuffer:', membersBuffer);
for (var i = 0; i < wxids.length; i++) {
var wxidPtr = createWeChatString(wxids[i]);
membersBuffer.add(Process.pointerSize * i).writePointer(wxidPtr);
}
membersBuffer.add(Process.pointerSize * wxids.length).writePointer(NULL); // 确保数组以NULL结尾
console.log('membersBuffer:', membersBuffer);
Memory.patchCode(txtAsm, Process.pageSize, function (code) {
var writer = new X86Writer(code, {
pc: txtAsm
});
writer.putPushax();
writer.putPushfx();
// CALL get_chat_room_mgr_addr
console.log('get_chat_room_mgr_addr:', get_chat_room_mgr_addr);
writer.putCallAddress(get_chat_room_mgr_addr);
// SUB ESP,0x14
writer.putSubRegImm('esp', 0x14);
// MOV ESI,EAX
writer.putMovRegReg('esi', 'eax');
// MOV ECX,ESP
writer.putMovRegReg('ecx', 'esp');
// /*
// LEA EDI,chat_room
console.log('chat_room:', chatRoomPtr);
writer.putMovRegAddress('edi', chatRoomPtr);
// PUSH EDI
writer.putPushReg('edi');
// CALL init_chat_msg_addr
console.log('init_chat_msg_addr:', init_chat_msg_addr);
writer.putCallAddress(init_chat_msg_addr);
// MOV ECX,ESI
writer.putMovRegReg('ecx', 'esi');
// MOV EAX,dword ptr[members_ptr]
console.log('membersBuffer:', membersBuffer);
writer.putMovRegAddress('eax', ptr(membersBuffer));
// PUSH EAX
writer.putPushReg('eax');
// CALL del_member_addr
console.log('del_member_addr:', del_member_addr);
writer.putCallAddress(del_member_addr);
// MOV success,EAX
writer.putMovNearPtrReg(successPtr, 'eax');
// */
console.log('putPopax:', 'putPopax');
writer.putPopfx();
writer.putPopax();
writer.putRet();
writer.flush();
console.log('writer.flush();');
});
// console.log('----------txtAsm', txtAsm)
// 调用刚才写入的汇编代码
var nativeFunction = new NativeFunction(ptr(txtAsm), 'int', []);
try {
nativeFunction();
success = successPtr.readU32();
console.log('[踢出群聊]delMemberFromChatRoom success:', success);
return success;
}
catch (e) {
console.error('[踢出群聊]Error during delMemberFromChatRoom nativeFunction function execution:', e);
return false;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The delMemberFromChatRoom function is marked as causing WeChat to crash. It's critical to address this issue to prevent unintended behavior. Consider reviewing the memory operations and native function calls for potential causes of the crash.

Please investigate and fix the cause of the crash when calling delMemberFromChatRoom.

1. 增加一些测试调试代码
2. 准备合并入3.9.3.81分支
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 10

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 18ba707 and d052b72.
Files ignored due to path filters (1)
  • package.json is excluded by: !**/*.json
Files selected for processing (3)
  • src/init-agent-script.ts (12 hunks)
  • tests/frida.js (1 hunks)
  • tests/frida.ts (1 hunks)
Files not summarized due to errors (2)
  • tests/frida.js: Error: Message exceeds token limit
  • tests/frida.ts: Error: Message exceeds token limit
Files skipped from review as they are similar to previous changes (1)
  • src/init-agent-script.ts
Additional comments: 12
tests/frida.ts (12)
  • 1-2: The file header comments provide a good brief about the script's purpose and usage. It's always beneficial to include such comments for clarity.
  • 3-20: The log object is a simple logging utility. Consider adding type annotations for a and b parameters to improve code readability and maintainability. For example, if these are always strings, specify them as such.
  • 22-240: The wxOffsets object contains a lot of hardcoded offsets. Ensure these offsets are up-to-date and consider documenting the source or method used to obtain them for future reference and maintenance.
  • 242-245: Logging the base address of the module is good for debugging purposes. However, ensure that such logs are necessary for the production environment, as they might clutter the output.
  • 248-265: The function initidStruct is used to initialize a structure in memory. Consider adding comments to explain the structure being initialized for better code readability.
  • 267-283: Similar to initidStruct, initStruct initializes a structure but lacks comments explaining the structure. Adding such comments would improve maintainability.
  • 285-301: initmsgStruct appears to be another variant of structure initialization functions. Consistency in naming (e.g., initMsgStruct) and adding explanatory comments would enhance readability.
  • 303-312: initAtMsgStruct lacks comments explaining its purpose and the structure it initializes. Adding detailed comments would be beneficial for future maintenance.
  • 314-342: The readStringPtr function is a utility for reading strings from memory addresses. It's well-implemented but could benefit from comments explaining the logic, especially the handling of capacity and size.
  • 344-361: readWStringPtr is similar to readStringPtr but for wide strings. Again, adding comments to explain the logic would improve code maintainability.
  • 363-373: Utility functions like readString, readByteArray, and readWideString are good abstractions. Ensure they are used consistently throughout the codebase.
  • 375-388: The createWeChatString function allocates memory for a WeChat string structure. It's crucial to ensure that the memory allocated here is managed properly to avoid memory leaks.

Comment on lines +247 to +258
var initidStruct = (function (str) {
retidPtr = Memory.alloc(str.length * 2 + 1);
retidPtr.writeUtf16String(str);
retidStruct = Memory.alloc(0x14); // returns a NativePointer
retidStruct
.writePointer(retidPtr).add(0x04)
.writeU32(str.length * 2).add(0x04)
.writeU32(str.length * 2).add(0x04)
.writeU32(0).add(0x04)
.writeU32(0);
return retidStruct;
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the previous comment about adding error handling to the initidStruct function, it's crucial to ensure that memory allocation is successful before proceeding with operations on the allocated memory. This applies to all instances where Memory.alloc is used throughout the script.

Consider adding checks after each memory allocation to ensure the allocation was successful. For example:

if (!retidPtr) {
    throw new Error('Memory allocation for retidPtr failed');
}

This should be applied to all memory allocation instances to prevent potential crashes or undefined behavior.

Comment on lines +595 to +620
var checkLogin = function () {
var success = -1;
var accout_service_addr = moduleBaseAddress.add(wxOffsets.login.WX_ACCOUNT_SERVICE_OFFSET);
// const service_addr = null;
// __asm {
// PUSHAD
// CALL accout_service_addr
// MOV service_addr,EAX
// POPAD
// }
// if (service_addr) {
// success = *(DWORD *)(service_addr + 0x4E0);
// }
// 创建原生函数对象,此处假设该函数返回'pointer'并且不需要输入参数
var getAccountService = new NativeFunction(accout_service_addr, 'pointer', []);
// 调用原生函数并获取服务地址
var service_addr = getAccountService();
// 判断服务地址是否有效
if (!service_addr.isNull()) {
// 成功获取账户服务地址,现在访问0x4E0偏移的值
// 注意:针对返回的地址,必须使用正确的类型,这里假设它是DWORD
success = service_addr.add(0x4E0).readU32();
}
console.log('[当前登录状态]checkLogin success:', success === 1 ? '已登录' : '未登录');
// 返回获得的状态值
return success;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The previous comment about adding error handling for the NativeFunction call and memory read operations in the checkLogin function is still valid. Robust error handling is essential to ensure the stability and reliability of the script, especially when interacting with external processes and memory.

To enhance error handling:

  • Wrap the NativeFunction call within a try-catch block to catch any exceptions that may occur during its execution.
  • Verify the validity of pointers before dereferencing them to prevent access violations.

For example:

try {
    var service_addr = getAccountService();
    if (!service_addr.isNull()) {
        success = service_addr.add(0x4E0).readU32();
    }
} catch (e) {
    console.error('Error checking login status:', e);
}

This approach should be applied to similar operations throughout the script.

Comment on lines +391 to +394
const readWeChatString = (address: any) => {
const ptr = address.readPointer();
const len = address.add(Process.pointerSize).readU32();
return ptr.readUtf16String(len);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

readWeChatString reads a WeChat string structure from memory. Adding error handling for cases where the pointer might be invalid would enhance robustness.

Comment on lines +397 to +478
// ok,发送文本消息
const sendMsgNativeFunction = (talkerId: string, content: string) => {

// const buffwxid = Memory.alloc(0x20)

// const wxidPtr: any = Memory.alloc(talkerId.length * 2 + 2)
// wxidPtr.writeUtf16String(talkerId)
// const wxidStruct = Memory.alloc(0x0c)
// wxidStruct.writePointer(ptr(wxidPtr)).add(0x04)
// .writeU32(talkerId.length * 2).add(0x04)
// .writeU32(talkerId.length * 2).add(0x04)

const wxidStruct = initidStruct(talkerId)

// const contentPtr = Memory.alloc(content.length * 2 + 2)
// contentPtr.writeUtf16String(content)
// const contentStruct = Memory.alloc(Process.pointerSize * 5)
// contentStruct
// .writePointer(contentPtr).add(0x4)
// .writeU32(content.length).add(0x4)
// .writeU32(content.length * 2)

const contentStruct = initStruct(content)
const ecxBuffer = Memory.alloc(0x2d8)
const successPtr = Memory.alloc(4)

const txtAsm: any = Memory.alloc(Process.pageSize)
Memory.patchCode(txtAsm, Process.pageSize, code => {
const cw = new X86Writer(code, {
pc: txtAsm,
})
// PUSHFD
cw.putPushfx()
cw.putPushax()
// CALL send_message_mgr_addr
// PUSH 0x0
// PUSH 0x0
// PUSH 0x0
// PUSH 0x1
// PUSH 0x0
cw.putPushU32(0x0)
cw.putPushU32(0x0)
cw.putPushU32(0x0)
cw.putPushU32(0x1)
cw.putPushU32(0x0)
// MOV EAX,msg_pptr
cw.putMovRegAddress('eax', contentStruct)
// PUSH EAX
cw.putPushReg('eax')
// LEA EDX,to_user
cw.putMovRegAddress('edx', wxidStruct) // room_id
// LEA ECX,chat_msg
cw.putMovRegAddress('ecx', ecxBuffer)
// CALL send_text_msg_addr
cw.putCallAddress(moduleBaseAddress.add(
wxOffsets.sendText.WX_SEND_TEXT_OFFSET,
))
cw.putMovNearPtrReg(successPtr, 'eax')
// MOV success,EAX
// ADD ESP,0x18
cw.putAddRegImm('esp', 0x18)
// LEA ECX,chat_msg
// CALL free_chat_msg_addr

// POPFD
// POPAD
cw.putPopax()
cw.putPopfx()
cw.putRet()
cw.flush()

})

// console.log('----------txtAsm', txtAsm)
const nativeativeFunction = new NativeFunction(ptr(txtAsm), 'void', [])
try {
nativeativeFunction()
console.log('[发送消息] successPtr:', successPtr.readS32())
} catch (e) {
log.error('[发送消息]Error:', e)
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sendMsgNativeFunction is a complex function that interacts with native code. Ensure that all native calls are wrapped in try-catch blocks to handle potential exceptions gracefully.

Comment on lines +483 to +653

// WeChatString wthumburl(thumburl);
wThumburl = initStruct(thumburl);

// WeChatString wsender(senderId);
wSender = initStruct(senderId);

// WeChatString wname(senderName);
wName = initStruct(senderName);

// WeChatString wdigest(digest);
wDigest = initStruct(digest);


console.log('toUser:', toUser, 'wTitle:', wTitle, 'wUrl:', wUrl, 'wThumburl:', wThumburl, 'wSender:', wSender, 'wName:', wName, 'wDigest:', wDigest);
// 将WeChatString对象的地址复制到buff中的相应位置
// 注意:这里的偏移量需要根据实际的结构体布局调整

// 假设wTitle, wUrl, wThumburl, wDigest, wSender, wName已经按WeChatString结构创建并分配了内存
buff.add(0x4).writeByteArray(readByteArray(wTitle));
buff.add(0x2C).writeByteArray(readByteArray(wUrl));
buff.add(0x6C).writeByteArray(readByteArray(wThumburl));
buff.add(0x94).writeByteArray(readByteArray(wDigest));
buff.add(0x1A0).writeByteArray(readByteArray(wSender));
buff.add(0x1B4).writeByteArray(readByteArray(wName));

// 调用其他函数完成消息的转发
try {

// 调用 newItemAddr 函数初始化 buff
const txtAsm2 = Memory.alloc(Process.pageSize)
console.log('txtAsm2:', txtAsm2);
Memory.patchCode(txtAsm2, Process.pageSize, code => {
const writer = new X86Writer(code, {
pc: txtAsm2,
})

// PUSHAD
// PUSHFD
writer.putPushax();
writer.putPushfx();
// CALL app_msg_mgr_addr
console.log('appMsgMgrAddr:', app_msg_mgr_addr);
writer.putCallAddress(app_msg_mgr_addr);
writer.putMovNearPtrReg(successPtr1, 'eax');
// LEA ECX,buff
writer.putMovRegAddress('ecx', buff);
// PUSH ECX
writer.putPushReg('ecx');
// SUB ESP,0x14
writer.putSubRegImm('esp', 0x14);
// MOV EDI,EAX
writer.putMovRegReg('edi', 'eax');
// MOV ECX,ESP
writer.putMovRegReg('ecx', 'esp');
// LEA EBX,to_user
writer.putMovRegAddress('ebx', toUser);
// PUSH EBX
writer.putPushReg('ebx'); // PUSH EBX
// CALL init_chat_msg_addr
console.log('initChatMsgAddr:', init_chat_msg_addr);
writer.putCallAddress(init_chat_msg_addr);
writer.putMovNearPtrReg(successPtr1, 'eax');
// MOV ECX,EDI
writer.putMovRegReg('ecx', 'edi');
// CALL forward_public_msg_addr
writer.putCallAddress(forward_public_msg_addr);
// MOV success,EAX
writer.putMovNearPtrReg(successPtr1, 'eax');
// ADD EBX,0x14
writer.putAddRegImm('ebx', 0x14);
// LEA ECX,buff
writer.putMovRegAddress('ecx', buff);
// PUSH 0x0
writer.putPushU32(0x0);
// CALL free_item_2_addr
// console.log('freeItem2Addr:', free_item_2_addr);
writer.putCallAddress(free_item_2_addr);
writer.putMovNearPtrReg(successPtr1, 'eax');

console.log('writer end');
// POPFD
// POPAD
writer.putPopfx();
writer.putPopax();
writer.putRet()
writer.flush();
console.log('writer flush');
})

// console.log('----------txtAsm2', txtAsm2)
const newItem1 = new NativeFunction(txtAsm2, 'void', [])
newItem1()
success = successPtr1.readU32();
log.info('[发送link消息]success:', success);
return success;
} catch (e) {
log.error('[发送link消息]Error during sendLinkMsgNativeFunction function execution:', e);
return false;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sendLinkMsgNativeFunction attempts to send a link message but is marked as incomplete. It's important to finalize the implementation or provide clear TODO comments indicating what remains to be done.

Would you like assistance in completing the implementation of sendLinkMsgNativeFunction?

Comment on lines +693 to +783
const DelMemberFromChatRoom = (chat_room_id: string, wxids: string[]) => {
// int ChatRoomMgr::DelMemberFromChatRoom(wchar_t* chat_room_id, wchar_t** wxids,
// int len) {
const len = wxids.length;
// int success = 0;
let success = 0;
const successPtr = Memory.alloc(4);
successPtr.writeS32(0);

// WeChatString chat_room(chat_room_id);
const chat_room = initidStruct(chat_room_id);
// vector<WeChatString> members;
// VectorInner* list = (VectorInner*)&members;
// DWORD members_ptr = (DWORD)&list->start;
// 创建一个 NativePointer 对象来模拟 `members` 的内存
const members = Memory.alloc(Process.pointerSize * 3); // std::vector 在内存中通常有三个指针:start, finish, end_of_storage
// 创建一个 NativePointer 对象来模拟 `list` 的内存
const list = members;
// 获取 `list->start` 的地址
const members_ptr = list;

// for (int i = 0; i < len; i++) {
// WeChatString pwxid(wxids[i]);
// members.push_back(pwxid);
// }

for (let i = 0; i < len; i++) {
const pwxid = initidStruct(wxids[i]);
// members.push_back(pwxid);
members.writePointer(pwxid);
}

// DWORD get_chat_room_mgr_addr = base_addr_ + WX_CHAT_ROOM_MGR_OFFSET;
const get_chat_room_mgr_addr = moduleBaseAddress.add(wxOffsets.chatRoomMgr.WX_CHAT_ROOM_MGR_OFFSET);
// DWORD del_member_addr = base_addr_ + WX_DEL_CHAT_ROOM_MEMBER_OFFSET;
const del_member_addr = moduleBaseAddress.add(wxOffsets.chatRoom.WX_DEL_CHAT_ROOM_MEMBER_OFFSET);
// DWORD init_chat_msg_addr = base_addr_ + WX_INIT_CHAT_MSG_OFFSET;
const init_chat_msg_addr = moduleBaseAddress.add(wxOffsets.setChatMsgValue.WX_INIT_CHAT_MSG_OFFSET);

const txtAsm: any = Memory.alloc(Process.pageSize)

Memory.patchCode(txtAsm, Process.pageSize, code => {
const cw = new X86Writer(code, {
pc: txtAsm,
})

// PUSHAD
// PUSHFD
cw.putPushfx()
cw.putPushax()
// CALL get_chat_room_mgr_addr
cw.putCallAddress(get_chat_room_mgr_addr)
// SUB ESP,0x14
cw.putSubRegImm('esp', 0x14)
// MOV ESI,EAX
cw.putMovRegReg('esi', 'eax')
// MOV ECX,ESP
cw.putMovRegReg('ecx', 'esp')
// LEA EDI,chat_room
cw.putMovRegAddress('edi', chat_room)
// PUSH EDI
cw.putPushReg('edi')
// CALL init_chat_msg_addr
cw.putCallAddress(init_chat_msg_addr)
// MOV ECX,ESI
cw.putMovRegReg('ecx', 'esi')
// MOV EAX,dword ptr[members_ptr]
cw.putMovRegNearPtr('eax', members_ptr)
// PUSH EAX
cw.putPushReg('eax')
// CALL del_member_addr
cw.putCallAddress(del_member_addr)
// MOV success,EAX
cw.putMovNearPtrReg(successPtr, 'eax')
// POPFD
// POPAD
cw.putPopax()
cw.putPopfx()
cw.putRet()
cw.flush()
})

const nativeFunction = new NativeFunction(ptr(txtAsm), 'void', [])
try {
nativeFunction()
success = successPtr.readS32()
console.log('[移除群成员]successPtr:', successPtr.readS32())
} catch (e) {
log.error('[移除群成员]Error:', e)
}
// }
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DelMemberFromChatRoom is another function marked as incomplete with a known error. Similar to the previous comment, consider adding TODO comments or seeking assistance to resolve the issue.

Would you like assistance in resolving the issue with DelMemberFromChatRoom?

Comment on lines +790 to +939
// CALL contact_mgr_addr
cw.putCallAddress(contact_mgr_addr)
// MOV dword ptr [instance],EAX
cw.putMovNearPtrReg(instancePtr, 'eax')
console.log('call contact_mgr_addr res:', instancePtr.readU32())
// MOV EDI,0xE
cw.putMovRegU32('edi', 0xE)
// MOV ESI,0x8
cw.putMovRegU32('esi', 0x8)
// MOV EAX,0x2
cw.putMovRegU32('eax', 0x2)
// SUB ESP,0x18
cw.putSubRegImm('esp', 0x18)
// MOV EAX,ESP
cw.putMovRegReg('eax', 'esp')
// MOV dword ptr ds:[EAX],0
cw.putMovRegOffsetPtrU32('eax', 0x0, 0)
// MOV dword ptr ds:[EAX+0x14],0xF
cw.putMovRegOffsetPtrU32('eax', 0x14, 0xF)
// MOV dword ptr ds:[EAX+0x10],0
cw.putMovRegOffsetPtrU32('eax', 0x10, 0)
// MOV byte ptr ds:[EAX],0
cw.putBytes('66 C7 00 00');
// SUB ESP,0x18
cw.putSubRegImm('esp', 0x18)
// LEA EAX,null_obj
cw.putMovRegAddress('eax', null_obj)
// MOV ECX,ESP
cw.putMovRegReg('ecx', 'esp')
// PUSH EAX
cw.putPushReg('eax')
// CALL fn1_addr
cw.putCallAddress(fn1_addr)
cw.putMovNearPtrReg(successPtr, 'eax')
console.log('call fn1_addr res:', successPtr.readU32())
// PUSH ESI
cw.putPushReg('esi')
// PUSH EDI
cw.putPushReg('edi')
// MOV EAX,w_msg
cw.putMovRegAddress('eax', w_msg)
cw.putMovNearPtrReg(successPtr, 'eax')
console.log('w_msg 入参:', readWideString(w_msg))
// SUB ESP,0x14
cw.putSubRegImm('esp', 0x14)
// MOV ECX,ESP
cw.putMovRegReg('ecx', 'esp')
// PUSH -0x1
cw.putPushU32(-0x1)
// PUSH EAX
cw.putPushReg('eax')
cw.putMovNearPtrReg(successPtr, 'eax')
console.log('call verify_msg_addr input:', successPtr.readU32())
// CALL verify_msg_addr
cw.putCallAddress(verify_msg_addr)
cw.putMovNearPtrReg(successPtr, 'eax')
console.log('call verify_msg_addr res:', successPtr.readU32())
// PUSH 0x2
cw.putPushU32(0x2)
// LEA EAX,user_id
cw.putMovRegAddress('eax', user_id)
// SUB ESP,0x14
cw.putSubRegImm('esp', 0x14)
// MOV ECX,ESP
cw.putMovRegReg('ecx', 'esp')
// PUSH EAX
cw.putPushReg('eax')
// CALL set_value_addr
cw.putCallAddress(set_value_addr)
// MOV ECX,dword ptr [instance]
cw.putMovRegAddress('ecx', instancePtr)
// CALL do_verify_user_addr
cw.putCallAddress(do_verify_user_addr)
// MOV success,EAX
cw.putMovNearPtrReg(successPtr1, 'eax')
console.log('call do_verify_user_addr res:', successPtr1.readS32())
// */
// POPFD
// POPAD
cw.putPopax()
cw.putPopfx()
cw.putRet()
cw.flush()
console.log('cw.flush();')
})

console.log('[添加好友]txtAsm', txtAsm)
const nativeativeFunction = new NativeFunction(ptr(txtAsm), 'void', [])
try {
nativeativeFunction()
console.log('instancePtr:', instancePtr.readU32())
console.log('instancePtr1:', instancePtr1.readU32())
console.log('successPtr1:', successPtr1.readS32())
success = successPtr.readU32()
console.log('[添加好友]success:', success)
return success
} catch (e) {
log.error('[添加好友]Error:', e)
return false
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addFriendByWxid is marked as incomplete with a known error. It's crucial to address these errors and ensure the function is fully operational. Adding detailed comments or seeking help might be necessary.

Would you like assistance in fixing the error in addFriendByWxid?

Comment on lines +944 to +998
// ok,设置联系人备注——done,2024-03-13,call和实现方法来源于ttttupup/wxhelper项目
const modifyContactRemarkFunction = (contactId: string, text: string) => {

// int success = -1;
let success = -1;
const successPtr = Memory.alloc(4);
successPtr.writeS32(success)

// WeChatString contact(wxid);
const contactPtr: any = initidStruct(contactId);
// WeChatString content(remark);
const contentPtr: any = initStruct(text);
// DWORD mod__addr = base_addr_ + WX_MOD_REMARK_OFFSET;
const mod__addr = moduleBaseAddress.add(
wxOffsets.contact.WX_MOD_REMARK_OFFSET,
);

const txtAsm: any = Memory.alloc(Process.pageSize)
Memory.patchCode(txtAsm, Process.pageSize, code => {
const writer = new X86Writer(code, {
pc: txtAsm,
})
// PUSHAD
// PUSHFD
writer.putPushfx();
writer.putPushax();
// LEA EAX,content
writer.putMovRegAddress('eax', contentPtr);
// PUSH EAX
writer.putPushReg('eax');
// LEA EAX,contact
writer.putMovRegAddress('eax', contactPtr);
// PUSH EAX
writer.putPushReg('eax');
// CALL mod__addr
writer.putCallAddress(mod__addr);
writer.putMovNearPtrReg(successPtr, 'eax')

// POPFD
// POPAD
writer.putPopax();
writer.putPopfx();
writer.putRet()
writer.flush();

})

// console.log('----------txtAsm', txtAsm)
const nativeativeFunction = new NativeFunction(ptr(txtAsm), 'void', [])
try {
nativeativeFunction()
console.log('[设置联系人备注] successPtr:', successPtr.readS32())
} catch (e) {
log.error('[设置联系人备注]Error:', e)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

modifyContactRemarkFunction seems to be a completed function. Ensure that all native calls are correctly handled and consider adding error handling for robustness.

Comment on lines +1004 to +1082
// 改写自ttttupup/wxhelper项目
const SendText = (wxid: string, msg: string) => {
// int success = -1;
let success = -1;
let successPtr = Memory.alloc(4);
successPtr.writeS32(-1);

// WeChatString to_user(wxid);
const to_user = initidStruct(wxid);
// WeChatString text_msg(msg);
// wchar_t** msg_pptr = &text_msg.ptr;
const text_msg = initmsgStruct(msg);
const msg_pptr = ptr(text_msg);

// DWORD send_message_mgr_addr = base_addr_ + WX_SEND_MESSAGE_MGR_OFFSET;
const send_message_mgr_addr = moduleBaseAddress.add(wxOffsets.sendMessageMgr.WX_SEND_MESSAGE_MGR_OFFSET);
// DWORD send_text_msg_addr = base_addr_ + WX_SEND_TEXT_OFFSET;
const send_text_msg_addr = moduleBaseAddress.add(wxOffsets.sendText.WX_SEND_TEXT_OFFSET);
// DWORD free_chat_msg_addr = base_addr_ + WX_FREE_CHAT_MSG_OFFSET;
const free_chat_msg_addr = moduleBaseAddress.add(wxOffsets.chatMsg.WX_FREE_CHAT_MSG_OFFSET);
// char chat_msg[0x2D8] = {0};
const chat_msg = Memory.alloc(0x2d8);

const txtAsm: any = Memory.alloc(Process.pageSize)
Memory.patchCode(txtAsm, Process.pageSize, code => {
const cw = new X86Writer(code, {
pc: txtAsm,
})
// PUSHAD
// PUSHFD
cw.putPushfx();
cw.putPushax();
// CALL send_message_mgr_addr
cw.putCallAddress(send_message_mgr_addr);
// PUSH 0x0
cw.putPushU32(0x0);
// PUSH 0x0
cw.putPushU32(0x0);
// PUSH 0x0
cw.putPushU32(0x0);
// PUSH 0x1
cw.putPushU32(0x1);
// PUSH 0x0
cw.putPushU32(0x0);
// MOV EAX,msg_pptr
cw.putMovRegAddress('eax', msg_pptr);
// PUSH EAX
cw.putPushReg('eax');
// LEA EDX,to_user
cw.putMovRegAddress('edx', to_user);
// LEA ECX,chat_msg
cw.putMovRegAddress('ecx', chat_msg);
// CALL send_text_msg_addr
cw.putCallAddress(send_text_msg_addr);
// MOV success,EAX
cw.putMovNearPtrReg(successPtr, 'eax');
// ADD ESP,0x18
cw.putAddRegImm('esp', 0x18);
// LEA ECX,chat_msg
cw
// CALL free_chat_msg_addr
// cw.putCallAddress(free_chat_msg_addr);
// POPFD
// POPAD
cw.putPopax();
cw.putPopfx();
cw.putRet()
cw.flush();
})

const nativeativeFunction = new NativeFunction(ptr(txtAsm), 'void', [])
try {
nativeativeFunction()
success = successPtr.readS32()
console.log('[发送消息] successPtr:', success)
} catch (e) {
log.error('[发送消息]Error:', e)
}
return success;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SendText is a function for sending text messages. Ensure that the native calls are correctly handled and consider adding error handling for robustness.

Comment on lines +1087 to +1234
// }
if (number < 1) {
return success;
}

// using wstring = basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t>>;
// std::wstring origin(msg);
const origin = msg;

// at_msg += origin;
at_msg += origin;

// AtInner at_list = {0};
const at_list = Memory.alloc(0x0c);

// at_list.start = (DWORD)at_users;
at_list.add(0x00).writePointer(at_users);

// at_list.finsh = (DWORD)&at_users[number];
at_list.add(0x04).writePointer(at_users.add(Process.pointerSize * number));
// at_list.end = (DWORD)&at_users[number];
at_list.add(0x08).writePointer(at_users.add(Process.pointerSize * number));
// WeChatString to_user(chat_room_id);
const to_user = initidStruct(chat_room_id);
// WeChatString text_msg((wchar_t *)at_msg.c_str());
const text_msg = initmsgStruct(at_msg);
// wchar_t **msg_pptr = &text_msg.ptr;
const msg_pptr = ptr(text_msg);

// DWORD send_message_mgr_addr = base_addr_ + WX_SEND_MESSAGE_MGR_OFFSET;
const send_message_mgr_addr = moduleBaseAddress.add(wxOffsets.sendMessageMgr.WX_SEND_MESSAGE_MGR_OFFSET);
// DWORD send_text_msg_addr = base_addr_ + WX_SEND_TEXT_OFFSET;
const send_text_msg_addr = moduleBaseAddress.add(wxOffsets.sendText.WX_SEND_TEXT_OFFSET);
// DWORD free_chat_msg_addr = base_addr_ + WX_FREE_CHAT_MSG_OFFSET;
const free_chat_msg_addr = moduleBaseAddress.add(wxOffsets.chatMsg.WX_FREE_CHAT_MSG_OFFSET);

// char chat_msg[0x2D8] = {0};
const chat_msg = Memory.alloc(0x2d8);

const txtAsm: any = Memory.alloc(Process.pageSize)

Memory.patchCode(txtAsm, Process.pageSize, code => {
const cw = new X86Writer(code, {
pc: txtAsm,
})
// PUSHAD
// PUSHFD
cw.putPushfx();
cw.putPushax();
// CALL send_message_mgr_addr
cw.putCallAddress(send_message_mgr_addr);
// PUSH 0x0
cw.putPushU32(0x0);
// PUSH 0x0
cw.putPushU32(0x0);
// PUSH 0x0
cw.putPushU32(0x0);
// PUSH 0x1
cw.putPushU32(0x1);
// LEA EAX,at_list
cw.putMovRegAddress('eax', at_list);
// PUSH EAX
cw.putPushReg('eax');
// MOV EAX,msg_pptr
cw.putMovRegAddress('eax', msg_pptr);
// PUSH EAX
cw.putPushReg('eax');
// LEA EDX,to_user
cw.putMovRegAddress('edx', to_user);
// LEA ECX,chat_msg
cw.putMovRegAddress('ecx', chat_msg);
// CALL send_text_msg_addr
cw.putCallAddress(send_text_msg_addr);
// MOV success,EAX
cw.putMovNearPtrReg(successPtr, 'eax');
// ADD ESP,0x18
cw.putAddRegImm('esp', 0x18);
// LEA ECX,chat_msg
cw.putMovRegAddress('ecx', chat_msg);
// CALL free_chat_msg_addr
cw.putCallAddress(free_chat_msg_addr);
// POPFD
// POPAD
cw.putPopax();
cw.putPopfx();
cw.putRet()
cw.flush();
});


// SPDLOG_INFO("SendText code = {}",success);
const nativeativeFunction = new NativeFunction(ptr(txtAsm), 'void', [])
try {
nativeativeFunction()
success = successPtr.readS32()
console.log('[发送AT消息] successPtr:', success)
} catch (e) {
log.error('[发送AT消息]Error:', e)
}
return success;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SendAtText is intended for sending @ messages in chat rooms. It's important to ensure that the implementation is complete and robust, especially in handling native calls and memory management.

Fixed the bug where the system crashes upon receiving a message before successful startup
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 3

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between d052b72 and 632e0fa.
Files ignored due to path filters (1)
  • package.json is excluded by: !**/*.json
Files selected for processing (2)
  • README.md (1 hunks)
  • src/puppet-xp.ts (4 hunks)
Additional comments: 5
README.md (1)
  • 105-114: The version history section mentions fixes and new features in versions v1.13.12 and v1.13.9. Ensure these changes are accurately reflected in the codebase and documentation.
Verification successful

Given the results, it appears that the specific changes mentioned in the version history are only directly referenced in the README.md file itself. To ensure a comprehensive verification, it would be beneficial to expand the search to include related terms, examine commit messages for relevant changes, and check for any additional documentation or comments within the code that might refer to these updates indirectly. This approach will help in confirming whether the changes are accurately reflected in the codebase and documentation.


The verification process has confirmed that the changes mentioned in the version history (v1.13.12 and v1.13.9) are documented in the commit history, with commits 632e0faab0a61b7a754942c377613978a9df0a64 and f1bc232350ac700c15e7dc0782800031fb564b2e corresponding to the described updates. Although the specific terms related to these changes were not found elsewhere in the codebase or additional documentation files beyond the README.md, the commit logs provide a traceable record of these changes being made. This supports the conclusion that the changes are accurately reflected in the codebase and documentation, as per the original task.

Scripts Executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Verify if the mentioned bug fix and features are documented elsewhere in the project
rg "Fixed the bug where the system crashes upon receiving a message before successful startup"
rg "Add setting for contact remark"
rg "Optimize sample code"

Length of output: 343



Script:

#!/bin/bash
# Broaden the search to include related terms and check for commit messages
# Search for terms related to the bug fix
rg "crash" --files-with-matches | xargs rg "message" --files-with-matches
rg "startup" --files-with-matches | xargs rg "crash" --files-with-matches

# Search for terms related to the new feature
rg "contact" --files-with-matches | xargs rg "setting" --files-with-matches

# Search for terms related to the optimization
rg "sample code" --files-with-matches

# Check for recent commit messages that might mention these changes
git log --grep="crash" --since="2023-09-01"
git log --grep="contact" --since="2023-09-01"
git log --grep="sample code" --since="2023-09-01"

Length of output: 1071

src/puppet-xp.ts (4)
  • 76-76: The addition of the isReady property is a good practice for managing the readiness state of the agent. This can help prevent actions from being taken before the agent is fully initialized.
  • 84-84: Modifying the default value of options in the constructor to an empty object is a safe and clean approach to ensure that options is always an object, preventing potential undefined access errors.
  • 155-156: Updating the onAgentReady method to set isReady to true and emit a ready event with selfInfo is a clear way to signal that the agent is ready for operation. This is crucial for asynchronous initialization processes.
  • 501-503: Checking isReady before emitting the message event is a good practice to ensure that the agent is fully initialized before processing messages. This prevents potential issues with handling messages too early.

Comment on lines +656 to +659
if (alias) {
await this.sidecar.modifyContactRemark(contactId, alias)
return alias
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding logic in contactAlias to modify the contact remark if alias is provided is a useful feature for users to personalize their contact list. However, it's important to handle the case where the modification fails, possibly due to external API limitations or network issues.

+ try {
+   await this.sidecar.modifyContactRemark(contactId, alias)
+ } catch (error) {
+   log.error('PuppetXp', 'Failed to modify contact remark for %s: %s', contactId, error)
+   throw new Error(`Failed to modify contact remark: ${error}`)
+ }

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
if (alias) {
await this.sidecar.modifyContactRemark(contactId, alias)
return alias
}
if (alias) {
try {
await this.sidecar.modifyContactRemark(contactId, alias)
} catch (error) {
log.error('PuppetXp', 'Failed to modify contact remark for %s: %s', contactId, error)
throw new Error(`Failed to modify contact remark: ${error}`)
}
return alias
}

Comment on lines 102 to 117

## HISTORY

### next v1.13.0 (September 21, 2023)
### v1.13.12

1. Fixed the bug where the system crashes upon receiving a message before successful startup

### v1.13.9

1. Add setting for contact remark
2. Optimize sample code

### v1.13.0 (September 21, 2023)

1. This version start to support WeChat v3.9.2.23,need to update WeChat on your pc to 3.9.2.23
2. [WeChatSetup-v3.9.2.23.exe](https://github.com/tom-snow/wechat-windows-versions/releases/download/v3.9.2.23/WeChatSetup-3.9.2.23.exe)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 NOTE
This review was outside the diff hunks, and no overlapping diff hunk was found. Original lines [23-23]

There's a grammatical issue with the spacing after a comma.

- If you are a user of Windows,You can use this puppet to implement your chatbot.
+ If you are a user of Windows, You can use this puppet to implement your chatbot.

📝 NOTE
This review was outside the diff hunks, and no overlapping diff hunk was found. Original lines [57-57]

The heading "RUNNING WHITH NPM" contains a typo and should be corrected for clarity.

- ## RUNNING WHITH NPM
+ ## RUNNING WITH NPM

@atorber atorber closed this Mar 27, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants