Loading... 因某个顾客老是说,需要判断是否已经登陆进游戏了,所以,就有了此文。 ### 关键信息查找 因为是进行状态判断,其关键字应该和“ingame”之类的相关,通过外网一番翻找,发现如下字眼“it uses flags...check ths isplayerinworld lua function.” ### 数据定位 使用工具将游戏内存转储、PE修补后,将unpack后的文件拖入ida,静候30分钟自动分析完成后,在字符串界面搜索“isplayerinworld”,定位到如下信息: ```c++ .rdata:00000001426E6DD8 ; DATA XREF: .data:0000000142C3F7E0↓o .rdata:00000001426E6DEB align 10h .rdata:00000001426E6DF0 aIsplayerinworl db 'IsPlayerInWorld',0 ; DATA XREF: .data:0000000142C3F7F0↓o <-- 点击此处引用跳转 .rdata:00000001426E6E00 aGetdungeoninfo db 'GetDungeonInfo',0 ; DATA XREF: .data:0000000142C3F800↓o .rdata:00000001426E6E0F align 10h .rdata:00000001426E6E10 aReportbug db 'ReportBug',0 ; DATA XREF: .data:0000000142C3F810↓o ``` 来到如下地方: ```c++ .data:0000000142C3F7E0 dq offset aIslegacydiffic ; "IsLegacyDifficulty" .data:0000000142C3F7E8 dq offset sub_1415D6010 .data:0000000142C3F7F0 dq offset aIsplayerinworl ; "IsPlayerInWorld" .data:0000000142C3F7F8 dq offset sub_1415CE330 <-----该地址即为我们需要找的对应c lua函数 .data:0000000142C3F800 dq offset aGetdungeoninfo ; "GetDungeonInfo" .data:0000000142C3F808 dq offset sub_1415D54E0 .data:0000000142C3F810 dq offset aReportbug ; "ReportBug" .data:0000000142C3F818 dq offset sub_1415D60B0 .data:0000000142C3F820 dq offset aReportsuggesti ; "ReportSuggestion" .data:0000000142C3F828 dq offset sub_1415D6100 ``` 跳转到函数 1415CE330: ```c++ .text:00000001415CE330 sub_1415CE330 proc near ; DATA XREF: .data:0000000142C3F7F8↓o .text:00000001415CE330 ; .pdata:000000014334A7C8↓o .text:00000001415CE330 sub rsp, 28h //内部栈空间开辟 .text:00000001415CE334 movzx edx, cs:byte_1430A3134 //获取地址1430A3134处的值,类型为byte 也就是 byte status = *(byte*)0x1430A3134 .text:00000001415CE33B shr edx, 2 //status >>2 .text:00000001415CE33E and edx, 1 //status&1 <-----此处结果就是我们需要的值 .text:00000001415CE341 call sub_1402BBAB0 //lua 压栈函数,不管 .text:00000001415CE346 mov eax, 1 .text:00000001415CE34B add rsp, 28h .text:00000001415CE34F retn .text:00000001415CE34F sub_1415CE330 endp ``` ### 代码实现 于是,有了如下代码: ```c++ /// <summary> /// 角色是否已进入游戏 /// </summary> /// <param name="handle">进程句柄</param> /// <param name="hModule">主模块基址</param> /// <returns>bool</returns> bool PlayerOnLine(HANDLE handle, DWORD64 hModule) { if (handle <= 0 || hModule <= 0) return false; UINT64 ReturnLength = 0; uint8_t gameStatus = 0; ReadProcessMemory((HANDLE)handle, (PVOID64)(hModule + player_online), &gameStatus, 1, &ReturnLength); return (gameStatus >> 2) & 1; } ``` 实际测试发现,在登陆加载界面,上面代码中gameStatus第三位也是1,因此结合实际情况,将上述代码调整为: ```c++ /// <summary> /// 角色是否已进入游戏 /// </summary> /// <param name="handle">进程句柄</param> /// <param name="hModule">主模块基址</param> /// <returns>bool</returns> bool PlayerOnLine(HANDLE handle, DWORD64 hModule) { if (handle <= 0 || hModule <= 0) return false; UINT64 ReturnLength = 0; uint8_t gameStatus = 0; ReadProcessMemory((HANDLE)handle, (PVOID64)(hModule + player_online), &gameStatus, 1, &ReturnLength); return gameStatus == (uint8_t)0x84; } ``` 再顺便记录一下该值其他状态: ```c++ EnteringGame => Status is 0x80 or 0x82 or 0x83 or 0x86; ReloadingGame => Status is 0xE4 or 0xE0 or 0xC3 or 0xC4 or 0xC6; Reloading => ReloadingGame || EnteringGame; InGame => Status == 0x84; ``` 最后修改:2022 年 12 月 11 日 07 : 50 PM © 禁止转载