chore: RevokeMsgHook: clean up code
This commit is contained in:
@@ -55,252 +55,10 @@ jclass klassRevokeMsgHook = nullptr;
|
||||
jobject gInstanceRevokeMsgHook = nullptr;
|
||||
jmethodID handleRecallSysMsgFromNtKernel = nullptr;
|
||||
|
||||
uintptr_t gfnCreatePBMessage = 0;
|
||||
|
||||
uintptr_t gOffsetForTmpRev5048 = 0;
|
||||
|
||||
NOINLINE
|
||||
uint64_t ThunkGetInt64Property(const void* thiz, int property) {
|
||||
// vtable
|
||||
// 4160. [[this+8]+0x58]
|
||||
void* thisp8 = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(thiz) + 8);
|
||||
uintptr_t vtable = *reinterpret_cast<uintptr_t*>(thisp8);
|
||||
void* func = *reinterpret_cast<void**>(vtable + 0x58);
|
||||
return reinterpret_cast<decltype(ThunkGetInt64Property)*>(func)(thisp8, property);
|
||||
}
|
||||
|
||||
NOINLINE
|
||||
uint32_t ThunkGetInt32Property(const void* thiz, int property) {
|
||||
// vtable
|
||||
// 4160. [[this+8]+0x38]
|
||||
void* thisp8 = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(thiz) + 8);
|
||||
uintptr_t vtable = *reinterpret_cast<uintptr_t*>(thisp8);
|
||||
void* func = *reinterpret_cast<void**>(vtable + 0x38);
|
||||
return reinterpret_cast<decltype(ThunkGetInt32Property)*>(func)(thisp8, property);
|
||||
}
|
||||
|
||||
NOINLINE
|
||||
std::string ThunkGetStringProperty(void* thiz, int property) {
|
||||
// vtable
|
||||
// 4160. [[this+8]+0x70]
|
||||
void* thisp8 = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(thiz) + 8);
|
||||
uintptr_t vtable = *reinterpret_cast<uintptr_t*>(thisp8);
|
||||
void* func = *reinterpret_cast<void**>(vtable + 0x70);
|
||||
return reinterpret_cast<decltype(ThunkGetStringProperty)*>(func)(thisp8, property);
|
||||
}
|
||||
|
||||
template<typename ReturnType, uintptr_t vtableOffset, uintptr_t thizOffset, typename... ArgTypes>
|
||||
requires((std::is_same_v<ReturnType, void> || std::is_integral_v<ReturnType> || std::is_pointer_v<ReturnType>)
|
||||
&& ((std::is_integral_v<ArgTypes> || std::is_pointer_v<ArgTypes>) && ...))
|
||||
NOINLINE
|
||||
ReturnType vcall(void* thiz, ArgTypes... args) {
|
||||
// vtable
|
||||
// [[this+thizOff]+offsetVT]
|
||||
void* thisp8 = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(thiz) + thizOffset);
|
||||
uintptr_t vtable = *reinterpret_cast<uintptr_t*>(thisp8);
|
||||
void* func = *reinterpret_cast<void**>(vtable + vtableOffset);
|
||||
if constexpr (std::is_same_v<ReturnType, void>) {
|
||||
reinterpret_cast<ReturnType(*)(void*, ArgTypes...)>(func)(thisp8, args...);
|
||||
return;
|
||||
} else {
|
||||
return reinterpret_cast<ReturnType(*)(void*, ArgTypes...)>(func)(thisp8, args...);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename... ArgTypes>
|
||||
requires(((std::is_integral_v<ArgTypes> || std::is_pointer_v<ArgTypes>) && ...))
|
||||
NOINLINE
|
||||
void vcall_x8_v2(void* thiz, uintptr_t vtableOffset, uintptr_t thizOffset, void* x8, ArgTypes... args) {
|
||||
// vtable
|
||||
// [[this+thizOff]+offsetVT]
|
||||
void* thisp8 = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(thiz) + thizOffset);
|
||||
uintptr_t vtable = *reinterpret_cast<uintptr_t*>(thisp8);
|
||||
void* func = *reinterpret_cast<void**>(vtable + vtableOffset);
|
||||
static_assert(sizeof...(args) <= 3);
|
||||
std::array<void*, 3> argArray = {reinterpret_cast<void*>(args)...};
|
||||
call_func_with_x8(func, x8, thisp8, argArray[0], argArray[1], argArray[2]);
|
||||
}
|
||||
|
||||
// helper for uintptr_t as this
|
||||
template<typename ReturnType, uintptr_t vtableOffset, uintptr_t thizOffset, typename... ArgTypes>
|
||||
requires((std::is_same_v<ReturnType, void> || std::is_integral_v<ReturnType> || std::is_pointer_v<ReturnType>)
|
||||
&& ((std::is_integral_v<ArgTypes> || std::is_pointer_v<ArgTypes>) && ...))
|
||||
static inline ReturnType vcall(uintptr_t thiz, ArgTypes... args) {
|
||||
if constexpr (std::is_same_v<ReturnType, void>) {
|
||||
vcall<vtableOffset, thizOffset, ArgTypes...>(reinterpret_cast<void*>(thiz), args...);
|
||||
return;
|
||||
} else {
|
||||
return vcall<vtableOffset, thizOffset, ArgTypes...>(reinterpret_cast<void*>(thiz), args...);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename... ArgTypes> requires((std::is_integral_v<ArgTypes> || std::is_pointer_v<ArgTypes>) && ...)
|
||||
static inline void vcall_x8_v2(uintptr_t thiz, uintptr_t vtableOffset, uintptr_t thizOffset, void* x8, ArgTypes... args) {
|
||||
vcall_x8_v2<ArgTypes...>(reinterpret_cast<void*>(thiz), vtableOffset, thizOffset, x8, args...);
|
||||
}
|
||||
|
||||
//void ThunkCallAPI(void* x0, uintptr_t api_caller_id, int x2, int x3, int& x4, std::string& x5) {
|
||||
// // 4160. 0x00cc0750
|
||||
// // "CallAPI"
|
||||
// // "!!! RegisterAPIHandler Error crash: api_caller_id is empty can not use You can use GlobalAPI or set other value to api_caller_id !!!"
|
||||
// auto func = reinterpret_cast<decltype(ThunkCallAPI)*>((uintptr_t) gLibkernelBaseAddress + 0x00cc0750);
|
||||
// func(x0, api_caller_id, x2, x3, x4, x5);
|
||||
//}
|
||||
|
||||
class RevokeMsgInfoAccess {
|
||||
public:
|
||||
|
||||
struct UnknownObjectStub16 {
|
||||
void* _unk0_8;
|
||||
void* _unk8_8;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
void NotifyRecallSysMsgEvent(int chatType, const std::string& peerUid, const std::string& recallOpUid, const std::string& msgAuthorUid,
|
||||
const std::string& toUid, uint64_t random64, uint64_t timeSeconds, uint64_t msgUid, uint64_t msgSeq, uint32_t msgClientSeq) {
|
||||
JavaVM* vm = HostInfo::GetJavaVM();
|
||||
if (vm == nullptr) {
|
||||
LOGE("NotifyRecallSysMsgEvent fatal vm == null");
|
||||
return;
|
||||
}
|
||||
if (klassRevokeMsgHook == nullptr) {
|
||||
LOGE("NotifyRecallSysMsgEvent fatal klassRevokeMsgHook == null");
|
||||
return;
|
||||
}
|
||||
// check if current thread is attached to jvm
|
||||
JNIEnv* env = nullptr;
|
||||
bool isAttachedManually = false;
|
||||
jint err = vm->GetEnv((void**) &env, JNI_VERSION_1_6);
|
||||
if (err == JNI_EDETACHED) {
|
||||
if (vm->AttachCurrentThread(&env, nullptr) != JNI_OK) {
|
||||
LOGE("NotifyRecallSysMsgEvent fatal AttachCurrentThread failed");
|
||||
return;
|
||||
}
|
||||
isAttachedManually = true;
|
||||
} else if (env == nullptr) {
|
||||
LOGE("NotifyRecallSysMsgEvent fatal GetEnv failed, err = {}", err);
|
||||
return;
|
||||
}
|
||||
// call java method
|
||||
env->CallStaticVoidMethod(klassRevokeMsgHook, handleRecallSysMsgFromNtKernel,
|
||||
jint(chatType), env->NewStringUTF(peerUid.c_str()), env->NewStringUTF(recallOpUid.c_str()),
|
||||
env->NewStringUTF(msgAuthorUid.c_str()), env->NewStringUTF(toUid.c_str()),
|
||||
jlong(random64), jlong(timeSeconds), jlong(msgUid), jlong(msgSeq), jint(msgClientSeq));
|
||||
// check if exception occurred
|
||||
if (env->ExceptionCheck()) {
|
||||
env->ExceptionDescribe();
|
||||
env->ExceptionClear();
|
||||
}
|
||||
// detach thread if attached manually
|
||||
if (isAttachedManually) {
|
||||
vm->DetachCurrentThread();
|
||||
}
|
||||
}
|
||||
|
||||
void NotifyRecallMsgEventForC2c(const std::string& fromUid, const std::string& toUid,
|
||||
uint64_t random64, uint64_t timeSeconds,
|
||||
uint64_t msgUid, uint64_t msgSeq, uint32_t msgClientSeq) {
|
||||
NotifyRecallSysMsgEvent(1, fromUid, fromUid, fromUid, toUid, random64, timeSeconds, msgUid, msgSeq, msgClientSeq);
|
||||
}
|
||||
|
||||
void NotifyRecallMsgEventForGroup(const std::string& peerUid, const std::string& recallOpUid, const std::string& msgAuthorUid,
|
||||
uint64_t random64, uint64_t timeSeconds, uint64_t msgSeq) {
|
||||
NotifyRecallSysMsgEvent(2, peerUid, recallOpUid, msgAuthorUid, peerUid, random64, timeSeconds, 0, msgSeq, 0);
|
||||
}
|
||||
|
||||
|
||||
void (* sOriginHandleGroupRecallSysMsgCallback)(void*, void*, void*) = nullptr;
|
||||
|
||||
void HandleGroupRecallSysMsgCallback([[maybe_unused]] void* x0, void* x1, [[maybe_unused]] void* x2, [[maybe_unused]] int x3) {
|
||||
LOGD("HandleGroupRecallSysMsgCallback start p1={:p}, p2={:p}, p3={:p}", x0, x1, x2);
|
||||
return;
|
||||
// we can still do it... hitherto p3 == null... we need to decode the message manually...
|
||||
uintptr_t base = (uintptr_t) gLibkernelBaseAddress;
|
||||
void* pVar1 = *(void**) x1;
|
||||
if ((vcall<int, 0x118, 8, int>(pVar1, 3) & 1) == 0) {
|
||||
LOGE("msg_recall: HandleRecallSysMsg: on recall group sys msg! hasn't msg_common::Msg::kBody");
|
||||
return;
|
||||
}
|
||||
void* pVar2 = *(void**) x1;
|
||||
STACK_GUARD;
|
||||
std::array<uint8_t, 0x100> objVar1 = {}; // actual size unknown, maybe 0x90
|
||||
STACK_GUARD;
|
||||
vcall_x8_v2<int>(pVar2, gOffsetForTmpRev5048, 0, &objVar1, 3);
|
||||
auto pVar3 = *(void**) (objVar1.data());
|
||||
if (pVar3 == nullptr) {
|
||||
LOGE("msg_recall: HandleRecallSysMsg: on recall group sys msg! msg_common::Msg::kBody = null");
|
||||
return;
|
||||
}
|
||||
if ((vcall<int, 0x118, 8, int>(pVar3, 2) & 1) == 0) {
|
||||
LOGE("msg_recall: HandleRecallSysMsg: on recall group sys msg! hasn't im_msg_body::MsgBody::kBytesMsgContent");
|
||||
return;
|
||||
}
|
||||
STACK_GUARD;
|
||||
std::vector<uint8_t> msgContentBytes;
|
||||
STACK_GUARD;
|
||||
vcall_x8_v2<int>(pVar3, 0x78, 8, &msgContentBytes, 2);
|
||||
if (msgContentBytes.size() < 8) {
|
||||
LOGE("msg_recall: HandleRecallSysMsg: on recall group sys msg! im_msg_body::MsgBody::kBytesMsgContent is error");
|
||||
return;
|
||||
}
|
||||
std::vector<uint8_t> content = {msgContentBytes.begin() + 7, msgContentBytes.end()};
|
||||
STACK_GUARD;
|
||||
std::array<void*, 2> objVar3 = {}; // actual size 0x10, maybe shared_ptr, but we don't have dtor
|
||||
STACK_GUARD;
|
||||
call_func_with_x8((void*) gfnCreatePBMessage, &objVar3, 0, 0, 0, 0);
|
||||
void* notifyMsgBody = objVar3[0];
|
||||
if ((vcall<int, 0x100, 8, std::vector<uint8_t>*>(notifyMsgBody, &content) & 1) == 0) {
|
||||
LOGE("on recall group sys msg! decode kBytesMsgContent fail");
|
||||
return;
|
||||
}
|
||||
uint64_t groupCode = vcall<uint64_t, 0x58, 8, int>(notifyMsgBody, 4);
|
||||
if (groupCode == 0) {
|
||||
LOGE("on recall group sys msg! group code is 0");
|
||||
return;
|
||||
}
|
||||
uint64_t opType = vcall<uint64_t, 0x58, 8, int>(notifyMsgBody, 1);
|
||||
if (opType != 7) {
|
||||
LOGW("HandleGroupRecallSysMsgCallback: on recall group sys msg! no Prompt_MsgRecallReminder op_type:{}", opType);
|
||||
return;
|
||||
}
|
||||
if ((vcall<uint64_t, 0x118, 8, int>(notifyMsgBody, 0xb) & 1) == 0) {
|
||||
LOGE("HandleGroupRecallSysMsgCallback: on recall group sys msg! no NotifyMsgBody::opt_msg_recall");
|
||||
return;
|
||||
}
|
||||
STACK_GUARD;
|
||||
std::array<void*, 2> optMsgRecall = {}; // actual size 0x10, maybe shared_ptr, but we don't have dtor
|
||||
STACK_GUARD;
|
||||
vcall_x8_v2<int>(notifyMsgBody, gOffsetForTmpRev5048, 0, &optMsgRecall, 0xb);
|
||||
if (optMsgRecall[0] == nullptr) {
|
||||
LOGE("HandleGroupRecallSysMsgCallback: on recall group sys msg! NotifyMsgBody::opt_msg_recall == null");
|
||||
return;
|
||||
}
|
||||
if ((vcall<int, 0x118, 8, int>(optMsgRecall[0], 3) & 1) == 0) {
|
||||
LOGE("HandleGroupRecallSysMsgCallback: on recall group sys msg! on recall group sys msg! no msg_infos");
|
||||
return;
|
||||
}
|
||||
std::array<void*, 3> vectorResultStub = {nullptr, nullptr, nullptr};
|
||||
vcall_x8_v2<int>(optMsgRecall[0], 0xf0, 8, &vectorResultStub, 3);
|
||||
std::string recallOpUid = ThunkGetStringProperty(optMsgRecall[0], 1);
|
||||
const auto& msgInfoList = *reinterpret_cast<const std::vector<RevokeMsgInfoAccess::UnknownObjectStub16>*>(&vectorResultStub);
|
||||
if (msgInfoList.empty()) {
|
||||
LOGE("HandleGroupRecallSysMsgCallback: on recall group sys msg! no any msg info");
|
||||
return;
|
||||
}
|
||||
std::string peerUid = fmt::format("{}", groupCode);
|
||||
for (const auto& msgInfo: msgInfoList) {
|
||||
uint32_t msgSeq = ThunkGetInt32Property(msgInfo._unk0_8, 1);
|
||||
uint32_t random = ThunkGetInt32Property(msgInfo._unk0_8, 3);
|
||||
uint64_t time = ThunkGetInt64Property(msgInfo._unk0_8, 2);
|
||||
std::string msgAuthorUid = ThunkGetStringProperty(msgInfo._unk0_8, 6);
|
||||
|
||||
// Unfortunately, I didn't find a way to find the origMsgSenderUid.
|
||||
// The only thing we can do is to get message by msgSeq, and get senderUid from it, iff we have the message.
|
||||
|
||||
NotifyRecallMsgEventForGroup(peerUid, recallOpUid, msgAuthorUid, random, time, msgSeq);
|
||||
}
|
||||
// LOGD("HandleGroupRecallSysMsgCallback start p1={:p}, p2={:p}, p3={:p}", x0, x1, x2);
|
||||
}
|
||||
|
||||
void (* sOriginHandleC2cRecallSysMsgCallback)(void*, void*, void*) = nullptr;
|
||||
@@ -310,54 +68,7 @@ void HandleC2cRecallSysMsgCallback([[maybe_unused]] void* p1, [[maybe_unused]] v
|
||||
LOGE("HandleC2cGroupSysMsgCallback BUG !!! *p3 = null, this should not happen!!!");
|
||||
return;
|
||||
}
|
||||
LOGD("HandleC2cRecallSysMsgCallback start p1={:p}, p2={:p}, p3={:p}", p1, p2, p3);
|
||||
return;
|
||||
|
||||
std::array<void*, 3> vectorResultStub = {nullptr, nullptr, nullptr};
|
||||
|
||||
void* v1 = *(void**) p3;
|
||||
void** v2 = (void**) ((uintptr_t) v1 + 8);
|
||||
|
||||
// 4160. 0xf0
|
||||
auto func = reinterpret_cast<std::array<void*, 3>(*)(void*, int)>(*(void**) ((uintptr_t) *v2 + 0xf0));
|
||||
// XXX: memory leak, no dtor available
|
||||
vectorResultStub = func(v2, 1);
|
||||
|
||||
static_assert(sizeof(std::vector<int>) == sizeof(std::array<void*, 3>), "libcxx vector size not match");
|
||||
const auto& objects = *reinterpret_cast<const std::vector<RevokeMsgInfoAccess::UnknownObjectStub16>*>(&vectorResultStub);
|
||||
|
||||
if (!objects.empty()) {
|
||||
|
||||
// void* x0 = nullptr;
|
||||
// uintptr_t x1 = 0;
|
||||
// {
|
||||
// uint8_t* param_1 = static_cast<uint8_t*>(p1) + 8;
|
||||
// uint8_t* pbVar1;
|
||||
// uint64_t uVar2;
|
||||
// uVar2 = *(uint64_t*) (param_1 + 8);
|
||||
// pbVar1 = *(uint8_t**) (param_1 + 0x10);
|
||||
// if ((*param_1 & 1) == 0) {
|
||||
// pbVar1 = param_1 + 1;
|
||||
// uVar2 = (uint64_t) (*param_1 >> 1);
|
||||
// }
|
||||
// x0 = pbVar1;
|
||||
// x1 = uVar2;
|
||||
// }
|
||||
// int tmpInt = 0x138b;
|
||||
// std::string tmpString;
|
||||
// ThunkCallAPI(x0, x1, 0x10, 1, tmpInt, tmpString);
|
||||
|
||||
for (const auto& obj: objects) {
|
||||
auto fromUid = ThunkGetStringProperty(obj._unk0_8, 1);
|
||||
auto toUid = ThunkGetStringProperty(obj._unk0_8, 2);
|
||||
auto randomId = ThunkGetInt64Property(obj._unk0_8, 6);
|
||||
auto timeSeconds = ThunkGetInt64Property(obj._unk0_8, 5);
|
||||
auto msgUid = ThunkGetInt64Property(obj._unk0_8, 4);
|
||||
auto msgSeq = ThunkGetInt64Property(obj._unk0_8, 0x14);
|
||||
auto msgClientSeq = ThunkGetInt32Property(obj._unk0_8, 3);
|
||||
NotifyRecallMsgEventForC2c(fromUid, toUid, randomId, timeSeconds, msgUid, msgSeq, msgClientSeq);
|
||||
}
|
||||
}
|
||||
// LOGD("HandleC2cRecallSysMsgCallback start p1={:p}, p2={:p}, p3={:p}", p1, p2, p3);
|
||||
}
|
||||
|
||||
// Nobody uses PaiYiPai, right?
|
||||
@@ -389,39 +100,11 @@ bool PerformNtRecallMsgHook(uint64_t baseAddress) {
|
||||
.WithOffsetsForResult({-0x18, -0x24, -0x28})
|
||||
.WithResultValidator(CommonAobScanValidator::kArm64StpX29X30SpImm);
|
||||
|
||||
//OffsetForTmpRev5048
|
||||
//61 01 80 52 mov w1,#0xb
|
||||
//?? ?? ?? ?? ??? ??,??
|
||||
//?? 10 00 94 bl FUN_?
|
||||
//?? ?? 00 36 tbz w0,#0x0,LAB_?
|
||||
//?? ?? 40 f9 ldr x?,[x??]
|
||||
//61 01 80 52 mov w1,#0xb
|
||||
// ---------- THE GAP ----------
|
||||
//e0 03 ?? aa mov x0,x??
|
||||
//09 !! 40 f9 ldr x9,[x8, #0x!!] <-- we need to find this
|
||||
//e8 ?? ?? 91 add x8,sp,#0x??
|
||||
//20 01 3f d6 blr x9
|
||||
auto targetInstructionOffsetForTmpRev5048 = AobScanTarget()
|
||||
.WithName("InstructionOffsetForTmpRev5048")
|
||||
// 0x61 0x01 0x80 0x52 0x?? 0x?? 0x?? 0x??
|
||||
// 0x?? 0x10 0x00 0x94 0x?? 0x?? 0x00 0x36
|
||||
// 0x?? 0x?? 0x40 0xf9 0x61 0x01 0x80 0x52
|
||||
.WithSequence({0x61, 0x01, 0x80, 0x52, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x10, 0x00, 0x94, 0x00, 0x00, 0x00, 0x36,
|
||||
0x00, 0x00, 0x40, 0xf9, 0x61, 0x01, 0x80, 0x52})
|
||||
.WithMask({ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff})
|
||||
.WithStep(4)
|
||||
.WithExecMemOnly(true)
|
||||
.WithOffsetsForResult({7 * 4});
|
||||
//@formatter:on
|
||||
|
||||
std::vector<std::string> errorMsgList;
|
||||
// auto start = std::chrono::steady_clock::now();
|
||||
if (!SearchForAllAobScanTargets({&targetRecallC2cSysMsg, &targetRecallGroupSysMsg,
|
||||
&targetInstructionOffsetForTmpRev5048},
|
||||
gLibkernelBaseAddress, true, errorMsgList)) {
|
||||
if (!SearchForAllAobScanTargets({&targetRecallC2cSysMsg, &targetRecallGroupSysMsg}, gLibkernelBaseAddress, true, errorMsgList)) {
|
||||
LOGE("InitInitNtKernelRecallMsgHook SearchForAllAobScanTargets failed");
|
||||
// sth went wrong
|
||||
for (const auto& msg: errorMsgList) {
|
||||
@@ -431,120 +114,13 @@ bool PerformNtRecallMsgHook(uint64_t baseAddress) {
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
// nt::IPBMessage::createPBMessage is an exported symbol for libbasic_share.so since 9.0.70.
|
||||
// libbasic_share.so must be already loaded, for 9.0.70+, it's DT_NEEDED by libkernel.so.
|
||||
void* createPBMessage = nullptr;
|
||||
void* libbasic_share = loader_dlopen("libbasic_share.so", RTLD_NOW | RTLD_NOLOAD, gLibkernelBaseAddress);
|
||||
if (libbasic_share != nullptr) {
|
||||
const char* sym = "_ZN2nt10IPBMessage15createPBMessageEv";
|
||||
createPBMessage = dlsym(libbasic_share, sym);
|
||||
}
|
||||
|
||||
LOGD("libbasic_share.so: {:p}, createPBMessage: {:p}", libbasic_share, createPBMessage);
|
||||
|
||||
if (createPBMessage != nullptr) {
|
||||
// we are all set
|
||||
gfnCreatePBMessage = reinterpret_cast<uintptr_t>(createPBMessage);
|
||||
} else {
|
||||
// AOB scan for QQ before 9.0.70
|
||||
// nt::IPBMessage::createPBMessage() 3f 8d 01 f8 f4 03 00 aa 1f 10 00 f9
|
||||
auto targetCreatePBMessage = AobScanTarget()
|
||||
.WithName("nt::IPBMessage::createPBMessage()")
|
||||
.WithSequence({0x3f, 0x8d, 0x01, 0xf8, 0xf4, 0x03, 0x00, 0xaa, 0x1f, 0x10, 0x00, 0xf9})
|
||||
.WithStep(4)
|
||||
.WithExecMemOnly(true)
|
||||
.WithOffsetsForResult({-0x78})
|
||||
.WithResultValidator(CommonAobScanValidator::kArm64StpX29X30SpImm);
|
||||
|
||||
errorMsgList.clear();
|
||||
if (!SearchForAllAobScanTargets({&targetCreatePBMessage}, gLibkernelBaseAddress, true, errorMsgList)) {
|
||||
LOGE("InitInitNtKernelRecallMsgHook targetCreatePBMessage failed");
|
||||
// sth went wrong
|
||||
for (const auto& msg: errorMsgList) {
|
||||
// report error to UI somehow
|
||||
TraceError(nullptr, gInstanceRevokeMsgHook, msg);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
uint64_t offsetCreatePBMessage = targetCreatePBMessage.GetResultOffset();
|
||||
gfnCreatePBMessage = reinterpret_cast<uintptr_t>(gLibkernelBaseAddress) + offsetCreatePBMessage;
|
||||
}
|
||||
}
|
||||
|
||||
// auto end = std::chrono::steady_clock::now();
|
||||
// LOGD("InitInitNtKernelRecallMsgHook AobScan elapsed: {}us", std::chrono::duration_cast<std::chrono::microseconds>(end - start).count());
|
||||
|
||||
if (auto pkg = HostInfo::GetPackageName(); pkg != "com.tencent.mobileqq") {
|
||||
TraceErrorF(nullptr, gInstanceRevokeMsgHook, "InitInitNtKernelRecallMsgHook failed, unexpected package name: {}", pkg);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t offsetC2c = targetRecallC2cSysMsg.GetResultOffset();
|
||||
uint64_t offsetGroup = targetRecallGroupSysMsg.GetResultOffset();
|
||||
uint64_t offsetInstForTmpRev5048 = targetInstructionOffsetForTmpRev5048.GetResultOffset();
|
||||
|
||||
{
|
||||
using ::platform::arch::endian::btoh32;
|
||||
uint32_t instructionForTmpRev5048m0 = *reinterpret_cast<uint32_t*>(
|
||||
reinterpret_cast<uintptr_t>(gLibkernelBaseAddress) + offsetInstForTmpRev5048);
|
||||
uint32_t instructionForTmpRev5048m4 = *reinterpret_cast<uint32_t*>(
|
||||
reinterpret_cast<uintptr_t>(gLibkernelBaseAddress) + offsetInstForTmpRev5048 - 4u);
|
||||
// LOGD("instructionForTmpRev5048={:08x}", instructionForTmpRev5048);
|
||||
if ((instructionForTmpRev5048m0 & btoh32(0xff00ffffu)) == btoh32(0x090040f9u)) {
|
||||
// try 1: for case w/o function outline
|
||||
// 09 !! 40 f9 ldr x9,[x8, #0x!!]
|
||||
uint32_t imm12 = ((instructionForTmpRev5048m0 >> 10u) & 0xfffu) << 3u;
|
||||
// LOGD("imm12={:x}", imm12);
|
||||
gOffsetForTmpRev5048 = imm12;
|
||||
} else if ((instructionForTmpRev5048m4 & (0b11111100u << 24u)) == (0b10010100u << 24u)) {
|
||||
// try 2: for case w/ function outline
|
||||
// bl xxx
|
||||
uint32_t ins_bl = instructionForTmpRev5048m4;
|
||||
auto imm26 = int32_t(ins_bl & 0x3ffffffu);
|
||||
// sign extend
|
||||
imm26 <<= 6u;
|
||||
imm26 >>= 6u;
|
||||
uint64_t curr_pc = reinterpret_cast<uintptr_t>(gLibkernelBaseAddress) + offsetInstForTmpRev5048 - 4u;
|
||||
uint64_t target = curr_pc + (imm26 << 2u);
|
||||
LOGD("imm26={:x}, target={:p}(base+{:x})", imm26, (void*) target, target - baseAddress);
|
||||
if (IsMemoryReadable(reinterpret_cast<const void*>(target), 16)) {
|
||||
// try 4 instructions at most
|
||||
std::vector<uint32_t> instructions;
|
||||
instructions.reserve(4);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
instructions.push_back(*reinterpret_cast<const uint32_t*>(target + i * 4));
|
||||
}
|
||||
for (int i = 0; i < 4; i++) {
|
||||
auto ins = instructions[i];
|
||||
if ((ins & btoh32(0xff00ffffu)) == btoh32(0x090040f9u)) {
|
||||
// try 1: for case w/o function outline
|
||||
// 09 !! 40 f9 ldr x9,[x8, #0x!!]
|
||||
uint32_t imm12 = ((ins >> 10u) & 0xfffu) << 3u;
|
||||
// LOGD("imm12={:x}", imm12);
|
||||
gOffsetForTmpRev5048 = imm12;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
TraceErrorF(nullptr, gInstanceRevokeMsgHook,
|
||||
"InitInitNtKernelRecallMsgHook failed, target is not readable, target={:p}(base+{:x})",
|
||||
(void*) target, target - baseAddress);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (gOffsetForTmpRev5048 == 0) {
|
||||
TraceErrorF(nullptr,
|
||||
gInstanceRevokeMsgHook,
|
||||
"InitInitNtKernelRecallMsgHook failed, gOffsetForTmpRev5048 == 0, offsetInstForTmpRev5048 == 0, "
|
||||
"ins[0]={:08x}, ins[-4]={:08x}",
|
||||
instructionForTmpRev5048m0,
|
||||
instructionForTmpRev5048m4);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
LOGD("offsetC2c={:x}, offsetGroup={:x}, gfnCreatePBMessage={:p}, gOffsetForTmpRev5048={:x}",
|
||||
offsetC2c, offsetGroup, (void*) gfnCreatePBMessage, gOffsetForTmpRev5048);
|
||||
|
||||
LOGD("offsetC2c={:x}, offsetGroup={:x}", offsetC2c, offsetGroup);
|
||||
|
||||
if (offsetC2c != 0) {
|
||||
void* c2c = (void*) (baseAddress + offsetC2c);
|
||||
|
||||
@@ -445,9 +445,9 @@ public class RevokeMsgHook extends CommonConfigFunctionHook {
|
||||
String authorUid = msgInfo.getMsgAuthorUid();
|
||||
long random64 = msgInfo.getRandomId();
|
||||
|
||||
Log.d("handleMsgPushForGroupRecall: groupCode=" + groupCodeText + ", operatorUid=" + operatorUid
|
||||
+ ", authorUid=" + authorUid + ", random64=" + random64 + ", timeSeconds=" + timeSeconds
|
||||
+ ", msgSeq=" + msgSeq);
|
||||
// Log.d("handleMsgPushForGroupRecall: groupCode=" + groupCodeText + ", operatorUid=" + operatorUid
|
||||
// + ", authorUid=" + authorUid + ", random64=" + random64 + ", timeSeconds=" + timeSeconds
|
||||
// + ", msgSeq=" + msgSeq);
|
||||
|
||||
// invoke the handler
|
||||
onRecallSysMsgForNT(ChatTypeConstants.GROUP, groupCodeText, operatorUid, authorUid, groupCodeText, random64, timeSeconds, 0, msgSeq, 0);
|
||||
|
||||
Reference in New Issue
Block a user