Răsfoiți Sursa

低调更新。。。

akemimadoka 6 ani în urmă
părinte
comite
027627ba77

+ 2 - 0
.clang-format

@@ -31,5 +31,7 @@ TabWidth: 2
 PointerAlignment: Left
 ColumnLimit: 100
 AlwaysBreakTemplateDeclarations: Yes
+MacroBlockBegin: "^JCE_STRUCT.*$"
+MacroBlockEnd: "^END_JCE_STRUCT$"
 
 ...

+ 1 - 2
CMakeLists.txt

@@ -15,8 +15,7 @@ conan_add_remote(NAME Cafe
 
 conan_cmake_run(CONANFILE conanfile.txt
                 BASIC_SETUP CMAKE_TARGETS
-                BUILD missing
-                SETTINGS compiler.cppstd=20)
+                BUILD missing)
 
 add_subdirectory(YumeBot)
 

+ 414 - 0
Docs/XposedLog.txt

@@ -0,0 +1,414 @@
+08-04 22:52:40.159 2906-2906/? I/Xposed: Loaded package: com.tencent.mobileqq
+08-04 22:52:41.005 2906-2922/com.tencent.mobileqq:MSF I/Xposed: Hooked method b(ToServiceMsg)
+08-04 22:52:41.005 2906-2922/com.tencent.mobileqq:MSF I/Xposed: ToServiceMsg: ToServiceMsg msName:reportMsg ssoSeq:47450 appId:537039093 appSeq:1 sName:com.tencent.mobileqq.msf.service.MsfService uin:0 sCmd:ConfigService.ClientReq t:30000 needResp:true
+08-04 22:52:41.014 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b()
+08-04 22:52:41.014 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Returned msgCookie: (null)
+08-04 22:52:41.089 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:41.089 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: (null)
+08-04 22:52:41.162 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:41.162 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:0 serviceCmd:ConfigService.ClientReq appId:-1 appSeq:47450
+08-04 22:52:41.166 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:41.166 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:41.166 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:48.953 2906-2921/com.tencent.mobileqq:MSF I/Xposed: Hooked method GetStWithPasswd
+08-04 22:52:48.953 2906-2921/com.tencent.mobileqq:MSF I/Xposed: userAccount : (已删除), dwAppid = 16, dwMainSigMap = 1970272, dwSubAppid = 537039093, dwSubAppidList = (null), bPwdMd5 = true, userPasswd = (已删除,似乎是强行转到字符串的 md5), userSigInfo = oicq.wlogin_sdk.request.WUserSigInfo@537659f, st = null, isSmsLogin = false, sync = 0
+08-04 22:52:48.954 2906-2921/com.tencent.mobileqq:MSF I/Xposed: stackTrace: [
+    dalvik.system.VMStack.getThreadStackTrace(Native Method),
+    java.lang.Thread.getStackTrace(Thread.java:580),
+    moe.hotococoa.xposedsandbox.XposedSandbox$handleLoadPackage$7.beforeHookedMethod(XposedSandbox.kt:167),
+    de.robv.android.xposed.XposedBridge.handleHookedMethod(XposedBridge.java:340),
+    oicq.wlogin_sdk.request.WtloginHelper.GetStWithPasswd(<Xposed>),
+    oicq.wlogin_sdk.request.WtloginHelper.GetStWithPasswdMd5(WtloginHelper.java:1243),
+    com.tencent.mobileqq.msf.core.auth.h.a(Unknown Source),
+    com.tencent.mobileqq.msf.core.MsfCore.login(Unknown Source),
+    com.tencent.mobileqq.msf.service.f.a(Unknown Source),
+    com.tencent.mobileqq.msf.service.e.sendToServiceMsg(Unknown Source),
+    com.tencent.qphone.base.remote.IBaseService$Stub.onTransact(Unknown Source),
+    android.os.Binder.execTransact(Binder.java:446)
+]
+08-04 22:52:48.955 2906-2983/com.tencent.mobileqq:MSF I/Xposed: Hooked method GetStWithPasswd
+08-04 22:52:48.955 2906-2983/com.tencent.mobileqq:MSF I/Xposed: sync call ignored.
+08-04 22:52:48.965 2906-2983/com.tencent.mobileqq:MSF I/Xposed: Hooked method make_request
+08-04 22:52:48.967 2906-2983/com.tencent.mobileqq:MSF I/Xposed: appId = 16, subAppId = 537039093, clientVersion = 1, uin = (已删除), rc = 0, clientIp = 00000000, initTime = 5d46f26c, savePwd = 0, pwdMd5 = (已删除,密码的 md5), sigSrc = 1, bitmap = 32636, getSig = 66560, subAppIdList = (null), getSig1 = 1970400, wxAppId = 537039093, appClientVersion = 1, picType = 0, capType = 0, picSize = 0, retType = 1, ksid = dd1c2351d59086a9bf3493c91ccfa48d, userSigInfo = oicq.wlogin_sdk.request.WUserSigInfo@537659f, userSigInfo._domains = [ game.qq.com ]
+08-04 22:52:48.967 2906-2983/com.tencent.mobileqq:MSF I/Xposed: stackTrace: [
+    dalvik.system.VMStack.getThreadStackTrace(Native Method),
+    java.lang.Thread.getStackTrace(Thread.java:580),
+    moe.hotococoa.xposedsandbox.XposedSandbox$handleLoadPackage$5.beforeHookedMethod(XposedSandbox.kt:118),
+    de.robv.android.xposed.XposedBridge.handleHookedMethod(XposedBridge.java:340),
+    oicq.wlogin_sdk.request.request_TGTGT.make_request(<Xposed>),
+    oicq.wlogin_sdk.request.WtloginHelper.GetStWithPasswd(WtloginHelper.java:1528),
+    de.robv.android.xposed.XposedBridge.invokeOriginalMethodNative(Native Method),
+    de.robv.android.xposed.XposedBridge.handleHookedMethod(XposedBridge.java:360),
+    oicq.wlogin_sdk.request.WtloginHelper.GetStWithPasswd(<Xposed>),
+    oicq.wlogin_sdk.request.WtloginHelper.access$400(WtloginHelper.java:51),
+    oicq.wlogin_sdk.request.WtloginHelper$HelperThread.run(WtloginHelper.java:4210)
+]
+08-04 22:52:48.985 2906-2984/com.tencent.mobileqq:MSF I/Xposed: Hooked method b(ToServiceMsg)
+08-04 22:52:48.985 2906-2984/com.tencent.mobileqq:MSF I/Xposed: ToServiceMsg: ToServiceMsg msName:wt_loginAuth ssoSeq:47456 appId:537039093 appSeq:2 sName:com.tencent.mobileqq.msf.service.MsfService uin:(已删除) sCmd:wtlogin.login t:40000 needResp:true
+08-04 22:52:48.985 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b()
+08-04 22:52:48.985 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Returned msgCookie: 907c6b5d
+08-04 22:52:49.045 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:49.045 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:wtlogin.login appId:-1 appSeq:47456
+08-04 22:52:49.045 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:49.045 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:49.045 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:49.097 2906-2987/com.tencent.mobileqq:MSF I/Xposed: Hooked method b(ToServiceMsg)
+08-04 22:52:49.097 2906-2987/com.tencent.mobileqq:MSF I/Xposed: ToServiceMsg: ToServiceMsg msName:wt_other ssoSeq:47458 appId:537039093 appSeq:-1 sName: uin:(已删除) sCmd:wtlogin.trans_emp t:45000 needResp:true
+08-04 22:52:49.097 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b()
+08-04 22:52:49.097 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Returned msgCookie: 907c6b5d
+08-04 22:52:49.099 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b(ToServiceMsg)
+08-04 22:52:49.099 2906-2975/com.tencent.mobileqq:MSF I/Xposed: ToServiceMsg: ToServiceMsg msName:checkRole ssoSeq:47460 appId:537039093 appSeq:-1 sName: uin:(已删除) sCmd:GrayUinPro.Check t:30000 needResp:true
+08-04 22:52:49.110 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b()
+08-04 22:52:49.110 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Returned msgCookie: 907c6b5d
+08-04 22:52:49.110 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b(ToServiceMsg)
+08-04 22:52:49.111 2906-2975/com.tencent.mobileqq:MSF I/Xposed: ToServiceMsg: ToServiceMsg msName:checkRole ssoSeq:47462 appId:537039093 appSeq:-1 sName: uin:(已删除) sCmd:GrayUinPro.Check t:30000 needResp:true
+08-04 22:52:49.121 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b()
+08-04 22:52:49.121 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Returned msgCookie: 907c6b5d
+08-04 22:52:49.128 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:49.128 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:GrayUinPro.Check appId:-1 appSeq:47460
+08-04 22:52:49.128 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:49.128 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:49.128 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:49.136 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:49.136 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:GrayUinPro.Check appId:-1 appSeq:47462
+08-04 22:52:49.136 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:49.136 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:49.136 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:49.157 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:49.157 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:wtlogin.trans_emp appId:-1 appSeq:47458
+08-04 22:52:49.157 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:49.157 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:49.157 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:49.623 2906-2922/com.tencent.mobileqq:MSF I/Xposed: Hooked method b(ToServiceMsg)
+08-04 22:52:49.623 2906-2922/com.tencent.mobileqq:MSF I/Xposed: ToServiceMsg: ToServiceMsg msName:reportMsg ssoSeq:47467 appId:537039093 appSeq:5 sName:com.tencent.mobileqq.msf.service.MsfService uin:0 sCmd:ConfigService.ClientReq t:30000 needResp:true
+08-04 22:52:49.624 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b()
+08-04 22:52:49.624 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Returned msgCookie: 907c6b5d
+08-04 22:52:49.627 2906-2922/com.tencent.mobileqq:MSF I/Xposed: Hooked method b(ToServiceMsg)
+08-04 22:52:49.627 2906-2922/com.tencent.mobileqq:MSF I/Xposed: ToServiceMsg: ToServiceMsg msName:unknown ssoSeq:47469 appId:537039093 appSeq:6 sName:com.tencent.mobileqq.msf.service.MsfService uin:(已删除) sCmd:OidbSvc.0x7a2_0 t:30000 needResp:true
+08-04 22:52:49.638 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b()
+08-04 22:52:49.638 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Returned msgCookie: 907c6b5d
+08-04 22:52:49.645 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:49.646 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:0 serviceCmd:ConfigService.ClientReq appId:-1 appSeq:47467
+08-04 22:52:49.646 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:49.646 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:49.646 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:49.675 2906-2922/com.tencent.mobileqq:MSF I/Xposed: Hooked method b(ToServiceMsg)
+08-04 22:52:49.675 2906-2922/com.tencent.mobileqq:MSF I/Xposed: ToServiceMsg: ToServiceMsg msName:_msf_RegPush ssoSeq:47472 appId:537039093 appSeq:8 sName: uin:(已删除) sCmd:StatSvc.register t:30000 needResp:true
+08-04 22:52:49.675 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b()
+08-04 22:52:49.675 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Returned msgCookie: 907c6b5d
+08-04 22:52:49.685 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:49.685 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:OidbSvc.0x7a2_0 appId:-1 appSeq:47469
+08-04 22:52:49.686 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:49.686 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:49.686 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:49.808 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:49.808 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:StatSvc.register appId:-1 appSeq:47472
+08-04 22:52:49.809 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:49.809 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:49.809 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:50.291 2906-2922/com.tencent.mobileqq:MSF I/Xposed: Hooked method b(ToServiceMsg)
+08-04 22:52:50.291 2906-2922/com.tencent.mobileqq:MSF I/Xposed: ToServiceMsg: ToServiceMsg msName:unknown ssoSeq:47475 appId:537039093 appSeq:9 sName:com.tencent.mobileqq.msf.service.MsfService uin:(已删除) sCmd:RegPrxySvc.infoLogin t:30000 needResp:true
+08-04 22:52:50.291 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b()
+08-04 22:52:50.291 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Returned msgCookie: 907c6b5d
+08-04 22:52:50.327 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:50.328 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:RegPrxySvc.GetMsgV2 appId:-1 appSeq:-1290219796
+08-04 22:52:50.328 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:50.328 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:50.328 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:50.376 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:50.376 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:RegPrxySvc.infoLogin appId:-1 appSeq:47475
+08-04 22:52:50.376 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:50.376 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:50.376 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:50.376 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:50.376 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:RegPrxySvc.PushParam appId:-1 appSeq:-1290219795
+08-04 22:52:50.376 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:50.376 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:50.376 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:50.377 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:50.377 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:RegPrxySvc.PullGroupMsgSeq appId:-1 appSeq:-1290219794
+08-04 22:52:50.377 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:50.377 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:50.377 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:50.380 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:50.380 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:RegPrxySvc.PbGetMsg appId:-1 appSeq:-1290219793
+08-04 22:52:50.380 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:50.380 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:50.380 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:50.381 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:50.381 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:RegPrxySvc.NoticeEnd appId:-1 appSeq:-1290219792
+08-04 22:52:50.381 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:50.381 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:50.381 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:50.411 2906-2922/com.tencent.mobileqq:MSF I/Xposed: Hooked method b(ToServiceMsg)
+08-04 22:52:50.411 2906-2922/com.tencent.mobileqq:MSF I/Xposed: ToServiceMsg: ToServiceMsg msName:unknown ssoSeq:47478 appId:537039093 appSeq:10 sName:com.tencent.mobileqq.msf.service.MsfService uin:(已删除) sCmd:RegPrxySvc.getOffMsg t:30000 needResp:true
+08-04 22:52:50.411 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b()
+08-04 22:52:50.411 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Returned msgCookie: 907c6b5d
+08-04 22:52:50.430 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:50.430 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:RegPrxySvc.getOffMsg appId:-1 appSeq:47478
+08-04 22:52:50.430 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:50.430 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:50.430 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:50.476 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:50.476 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:RegPrxySvc.PullGroupMsgSeq appId:-1 appSeq:-1290219496
+08-04 22:52:50.476 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:50.476 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:50.476 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:50.480 2906-2921/com.tencent.mobileqq:MSF I/Xposed: Hooked method b(ToServiceMsg)
+08-04 22:52:50.481 2906-2921/com.tencent.mobileqq:MSF I/Xposed: ToServiceMsg: ToServiceMsg msName:unknown ssoSeq:47479 appId:537039093 appSeq:11 sName:com.tencent.mobileqq.msf.service.MsfService uin:(已删除) sCmd:AvatarUpdate.checkUpdate t:30000 needResp:true
+08-04 22:52:50.481 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b()
+08-04 22:52:50.481 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Returned msgCookie: 907c6b5d
+08-04 22:52:50.489 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:50.489 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:RegPrxySvc.PbGetGroupMsg appId:-1 appSeq:-1290219495
+08-04 22:52:50.489 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:50.489 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:50.489 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:50.490 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:50.490 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:RegPrxySvc.NoticeEnd appId:-1 appSeq:-1290219494
+08-04 22:52:50.490 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:50.490 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:50.490 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:50.536 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:50.536 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:AvatarUpdate.checkUpdate appId:-1 appSeq:47479
+08-04 22:52:50.536 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:50.536 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:50.536 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:50.590 2906-3009/com.tencent.mobileqq:MSF I/Xposed: Hooked method b(ToServiceMsg)
+08-04 22:52:50.590 2906-3009/com.tencent.mobileqq:MSF I/Xposed: ToServiceMsg: ToServiceMsg msName:unknown ssoSeq:47480 appId:537039093 appSeq:12 sName:com.tencent.mobileqq.msf.service.MsfService uin:(已删除) sCmd:friendlist.GetTroopListReqV2 t:30000 needResp:true
+08-04 22:52:50.590 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b()
+08-04 22:52:50.590 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Returned msgCookie: 907c6b5d
+08-04 22:52:50.615 2906-2922/com.tencent.mobileqq:MSF I/Xposed: Hooked method b(ToServiceMsg)
+08-04 22:52:50.615 2906-2922/com.tencent.mobileqq:MSF I/Xposed: ToServiceMsg: ToServiceMsg msName:unknown ssoSeq:47481 appId:537039093 appSeq:13 sName:com.tencent.mobileqq.msf.service.MsfService uin:(已删除) sCmd:ProfileService.SearchGroup t:30000 needResp:true
+08-04 22:52:50.615 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b()
+08-04 22:52:50.615 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Returned msgCookie: 907c6b5d
+08-04 22:52:50.634 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:50.634 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:friendlist.GetTroopListReqV2 appId:-1 appSeq:47480
+08-04 22:52:50.634 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:50.634 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:50.634 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:50.649 2906-3009/com.tencent.mobileqq:MSF I/Xposed: Hooked method b(ToServiceMsg)
+08-04 22:52:50.650 2906-3009/com.tencent.mobileqq:MSF I/Xposed: ToServiceMsg: ToServiceMsg msName:getPluginConfig ssoSeq:47483 appId:537039093 appSeq:14 sName:com.tencent.mobileqq.msf.service.MsfService uin:(已删除) sCmd:ConfigService.ClientReq t:30000 needResp:true
+08-04 22:52:50.650 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b()
+08-04 22:52:50.650 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Returned msgCookie: 907c6b5d
+08-04 22:52:50.652 2906-2922/com.tencent.mobileqq:MSF I/Xposed: Hooked method b(ToServiceMsg)
+08-04 22:52:50.652 2906-2922/com.tencent.mobileqq:MSF I/Xposed: ToServiceMsg: ToServiceMsg msName:getPluginConfig ssoSeq:47484 appId:537039093 appSeq:15 sName:com.tencent.mobileqq.msf.service.MsfService uin:(已删除) sCmd:ConfigService.ClientReq t:30000 needResp:true
+08-04 22:52:50.659 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:50.660 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:ProfileService.SearchGroup appId:-1 appSeq:47481
+08-04 22:52:50.660 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:50.660 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:50.660 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:50.661 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b()
+08-04 22:52:50.661 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Returned msgCookie: 907c6b5d
+08-04 22:52:50.665 2906-3009/com.tencent.mobileqq:MSF I/Xposed: Hooked method b(ToServiceMsg)
+08-04 22:52:50.665 2906-3009/com.tencent.mobileqq:MSF I/Xposed: ToServiceMsg: ToServiceMsg msName:unknown ssoSeq:47486 appId:537039093 appSeq:17 sName:com.tencent.mobileqq.msf.service.MsfService uin:(已删除) sCmd:ConfigService.GetResourceReq t:30000 needResp:true
+08-04 22:52:50.673 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b()
+08-04 22:52:50.673 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Returned msgCookie: 907c6b5d
+08-04 22:52:50.677 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:50.677 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:ConfigService.ClientReq appId:-1 appSeq:47483
+08-04 22:52:50.677 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:50.677 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:50.677 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:50.688 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:50.688 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:ConfigService.ClientReq appId:-1 appSeq:47484
+08-04 22:52:50.688 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:50.689 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:50.689 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:50.718 2906-2922/com.tencent.mobileqq:MSF I/Xposed: Hooked method b(ToServiceMsg)
+08-04 22:52:50.718 2906-2922/com.tencent.mobileqq:MSF I/Xposed: ToServiceMsg: ToServiceMsg msName:unknown ssoSeq:47487 appId:537039093 appSeq:18 sName:com.tencent.mobileqq.msf.service.MsfService uin:(已删除) sCmd:ProfileService.CheckUpdateReq t:30000 needResp:true
+08-04 22:52:50.719 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b()
+08-04 22:52:50.719 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Returned msgCookie: 907c6b5d
+08-04 22:52:50.728 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:50.728 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:ConfigService.GetResourceReq appId:-1 appSeq:47486
+08-04 22:52:50.728 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:50.729 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:50.729 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:50.950 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:50.950 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:ProfileService.CheckUpdateReq appId:-1 appSeq:47487
+08-04 22:52:50.950 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:50.950 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:50.950 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:51.050 2906-2921/com.tencent.mobileqq:MSF I/Xposed: Hooked method b(ToServiceMsg)
+08-04 22:52:51.050 2906-2921/com.tencent.mobileqq:MSF I/Xposed: ToServiceMsg: ToServiceMsg msName:unknown ssoSeq:47488 appId:537039093 appSeq:19 sName:com.tencent.mobileqq.msf.service.MsfService uin:(已删除) sCmd:CarrierEntry.queryCarrier t:30000 needResp:true
+08-04 22:52:51.051 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b()
+08-04 22:52:51.051 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Returned msgCookie: 907c6b5d
+08-04 22:52:51.072 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:51.072 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:CarrierEntry.queryCarrier appId:-1 appSeq:47488
+08-04 22:52:51.073 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:51.073 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:51.073 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:51.084 2906-3009/com.tencent.mobileqq:MSF I/Xposed: Hooked method b(ToServiceMsg)
+08-04 22:52:51.084 2906-3009/com.tencent.mobileqq:MSF I/Xposed: ToServiceMsg: ToServiceMsg msName:unknown ssoSeq:47489 appId:537039093 appSeq:20 sName:com.tencent.mobileqq.msf.service.MsfService uin:(已删除) sCmd:EqqAccountSvc.get_eqq_list t:30000 needResp:true
+08-04 22:52:51.084 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b()
+08-04 22:52:51.084 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Returned msgCookie: 907c6b5d
+08-04 22:52:51.087 2906-2922/com.tencent.mobileqq:MSF I/Xposed: Hooked method b(ToServiceMsg)
+08-04 22:52:51.087 2906-2922/com.tencent.mobileqq:MSF I/Xposed: ToServiceMsg: ToServiceMsg msName:unknown ssoSeq:47490 appId:537039093 appSeq:21 sName:com.tencent.mobileqq.msf.service.MsfService uin:(已删除) sCmd:PubAccountSvc.get_follow_list t:30000 needResp:true
+08-04 22:52:51.090 2906-2921/com.tencent.mobileqq:MSF I/Xposed: Hooked method b(ToServiceMsg)
+08-04 22:52:51.090 2906-2921/com.tencent.mobileqq:MSF I/Xposed: ToServiceMsg: ToServiceMsg msName:unknown ssoSeq:47491 appId:537039093 appSeq:22 sName:com.tencent.mobileqq.msf.service.MsfService uin:(已删除) sCmd:OidbSvc.0x4fc_30 t:10000 needResp:true
+08-04 22:52:51.095 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b()
+08-04 22:52:51.095 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Returned msgCookie: 907c6b5d
+08-04 22:52:51.102 2906-3009/com.tencent.mobileqq:MSF I/Xposed: Hooked method b(ToServiceMsg)
+08-04 22:52:51.102 2906-3009/com.tencent.mobileqq:MSF I/Xposed: ToServiceMsg: ToServiceMsg msName:unknown ssoSeq:47492 appId:537039093 appSeq:23 sName:com.tencent.mobileqq.msf.service.MsfService uin:(已删除) sCmd:SQQzoneSvc.getQQLoginMsgListData t:60000 needResp:true
+08-04 22:52:51.106 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b()
+08-04 22:52:51.106 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Returned msgCookie: 907c6b5d
+08-04 22:52:51.113 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:51.113 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:EqqAccountSvc.get_eqq_list appId:-1 appSeq:47489
+08-04 22:52:51.113 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:51.113 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:51.113 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:51.117 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b()
+08-04 22:52:51.117 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Returned msgCookie: 907c6b5d
+08-04 22:52:51.132 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:51.132 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:OidbSvc.0x4fc_30 appId:-1 appSeq:47491
+08-04 22:52:51.132 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:51.132 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:51.132 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:51.139 2906-2922/com.tencent.mobileqq:MSF I/Xposed: Hooked method b(ToServiceMsg)
+08-04 22:52:51.139 2906-2922/com.tencent.mobileqq:MSF I/Xposed: ToServiceMsg: ToServiceMsg msName:unknown ssoSeq:47493 appId:537039093 appSeq:24 sName:com.tencent.mobileqq.msf.service.MsfService uin:(已删除) sCmd:BQMallSvc.TabOpReq t:30000 needResp:true
+08-04 22:52:51.139 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b()
+08-04 22:52:51.139 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Returned msgCookie: 907c6b5d
+08-04 22:52:51.141 2906-2921/com.tencent.mobileqq:MSF I/Xposed: Hooked method b(ToServiceMsg)
+08-04 22:52:51.141 2906-2921/com.tencent.mobileqq:MSF I/Xposed: ToServiceMsg: ToServiceMsg msName:unknown ssoSeq:47494 appId:537039093 appSeq:25 sName:com.tencent.mobileqq.msf.service.MsfService uin:(已删除) sCmd:ProfileService.GetSimpleInfo t:30000 needResp:true
+08-04 22:52:51.144 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:51.144 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:PubAccountSvc.get_follow_list appId:-1 appSeq:47490
+08-04 22:52:51.144 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:51.144 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:51.144 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:51.150 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b()
+08-04 22:52:51.150 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Returned msgCookie: 907c6b5d
+08-04 22:52:51.156 2906-3009/com.tencent.mobileqq:MSF I/Xposed: Hooked method b(ToServiceMsg)
+08-04 22:52:51.156 2906-3009/com.tencent.mobileqq:MSF I/Xposed: ToServiceMsg: ToServiceMsg msName:unknown ssoSeq:47495 appId:537039093 appSeq:26 sName:com.tencent.mobileqq.msf.service.MsfService uin:(已删除) sCmd:SsoSnsSession.Cmd0x3_SubCmd0x1_FuncGetBlockList t:60000 needResp:true
+08-04 22:52:51.160 2906-2922/com.tencent.mobileqq:MSF I/Xposed: Hooked method b(ToServiceMsg)
+08-04 22:52:51.160 2906-2922/com.tencent.mobileqq:MSF I/Xposed: ToServiceMsg: ToServiceMsg msName:unknown ssoSeq:47496 appId:537039093 appSeq:27 sName:com.tencent.mobileqq.msf.service.MsfService uin:(已删除) sCmd:CliLogSvc.UploadReq t:30000 needResp:true
+08-04 22:52:51.160 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b()
+08-04 22:52:51.160 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Returned msgCookie: 907c6b5d
+08-04 22:52:51.162 2906-2921/com.tencent.mobileqq:MSF I/Xposed: Hooked method b(ToServiceMsg)
+08-04 22:52:51.162 2906-2921/com.tencent.mobileqq:MSF I/Xposed: ToServiceMsg: ToServiceMsg msName:unknown ssoSeq:47497 appId:537039093 appSeq:28 sName:com.tencent.mobileqq.msf.service.MsfService uin:(已删除) sCmd:TransService.ReqGetSign t:30000 needResp:true
+08-04 22:52:51.166 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:51.167 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:SQQzoneSvc.getQQLoginMsgListData appId:-1 appSeq:47492
+08-04 22:52:51.167 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:51.167 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:51.167 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:51.171 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b()
+08-04 22:52:51.171 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Returned msgCookie: 907c6b5d
+08-04 22:52:51.171 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:51.171 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:BQMallSvc.TabOpReq appId:-1 appSeq:47493
+08-04 22:52:51.172 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:51.172 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:51.172 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:51.181 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b()
+08-04 22:52:51.181 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Returned msgCookie: 907c6b5d
+08-04 22:52:51.185 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:51.185 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:SsoSnsSession.Cmd0x3_SubCmd0x1_FuncGetBlockList appId:-1 appSeq:47495
+08-04 22:52:51.185 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:51.185 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:51.185 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:51.193 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:51.193 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:ProfileService.GetSimpleInfo appId:-1 appSeq:47494
+08-04 22:52:51.193 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:51.193 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:51.193 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:51.193 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:51.193 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:CliLogSvc.UploadReq appId:-1 appSeq:47496
+08-04 22:52:51.193 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:51.193 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:51.193 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:51.238 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:51.238 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:TransService.ReqGetSign appId:-1 appSeq:47497
+08-04 22:52:51.238 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:51.238 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:51.238 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:51.258 2906-3009/com.tencent.mobileqq:MSF I/Xposed: Hooked method b(ToServiceMsg)
+08-04 22:52:51.258 2906-3009/com.tencent.mobileqq:MSF I/Xposed: ToServiceMsg: ToServiceMsg msName:unknown ssoSeq:47501 appId:537039093 appSeq:29 sName:com.tencent.mobileqq.msf.service.MsfService uin:(已删除) sCmd:SQQzoneSvc.getUndealCount t:30000 needResp:true
+08-04 22:52:51.258 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b()
+08-04 22:52:51.258 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Returned msgCookie: 907c6b5d
+08-04 22:52:51.260 2906-2922/com.tencent.mobileqq:MSF I/Xposed: Hooked method b(ToServiceMsg)
+08-04 22:52:51.260 2906-2922/com.tencent.mobileqq:MSF I/Xposed: ToServiceMsg: ToServiceMsg msName:unknown ssoSeq:47502 appId:537039093 appSeq:30 sName:com.tencent.mobileqq.msf.service.MsfService uin:(已删除) sCmd:ConfigurationService.ReqGetConfig t:30000 needResp:true
+08-04 22:52:51.261 2906-2921/com.tencent.mobileqq:MSF I/Xposed: Hooked method b(ToServiceMsg)
+08-04 22:52:51.261 2906-2921/com.tencent.mobileqq:MSF I/Xposed: ToServiceMsg: ToServiceMsg msName:unknown ssoSeq:47503 appId:537039093 appSeq:31 sName:com.tencent.mobileqq.msf.service.MsfService uin:(已删除) sCmd:ConfigurationService.ReqGetConfig t:30000 needResp:true
+08-04 22:52:51.261 2906-3009/com.tencent.mobileqq:MSF I/Xposed: Hooked method b(ToServiceMsg)
+08-04 22:52:51.261 2906-3009/com.tencent.mobileqq:MSF I/Xposed: ToServiceMsg: ToServiceMsg msName:unknown ssoSeq:47504 appId:537039093 appSeq:32 sName:com.tencent.mobileqq.msf.service.MsfService uin:(已删除) sCmd:ConfigurationService.ReqGetConfig t:30000 needResp:true
+08-04 22:52:51.264 2906-2922/com.tencent.mobileqq:MSF I/Xposed: Hooked method b(ToServiceMsg)
+08-04 22:52:51.264 2906-2922/com.tencent.mobileqq:MSF I/Xposed: ToServiceMsg: ToServiceMsg msName:unknown ssoSeq:47505 appId:537039093 appSeq:33 sName:com.tencent.mobileqq.msf.service.MsfService uin:(已删除) sCmd:ConfigService.ClientReq t:20000 needResp:true
+08-04 22:52:51.269 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b()
+08-04 22:52:51.269 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Returned msgCookie: 907c6b5d
+08-04 22:52:51.280 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b()
+08-04 22:52:51.280 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Returned msgCookie: 907c6b5d
+08-04 22:52:51.291 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b()
+08-04 22:52:51.291 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Returned msgCookie: 907c6b5d
+08-04 22:52:51.302 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b()
+08-04 22:52:51.302 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Returned msgCookie: 907c6b5d
+08-04 22:52:51.308 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:51.308 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:SQQzoneSvc.getUndealCount appId:-1 appSeq:47501
+08-04 22:52:51.308 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:51.308 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:51.308 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:51.355 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:51.355 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:ConfigurationService.ReqGetConfig appId:-1 appSeq:47502
+08-04 22:52:51.355 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:51.355 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:51.355 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:51.355 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:51.355 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:ConfigService.ClientReq appId:-1 appSeq:47505
+08-04 22:52:51.355 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:51.355 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:51.355 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:51.401 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:51.401 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:ConfigurationService.ReqGetConfig appId:-1 appSeq:47504
+08-04 22:52:51.401 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:51.401 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:51.401 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:51.409 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:51.409 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:ConfigurationService.ReqGetConfig appId:-1 appSeq:47503
+08-04 22:52:51.409 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:51.409 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:51.409 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:52.674 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:52.675 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:ConfigPushSvc.PushDomain appId:-1 appSeq:-658642814
+08-04 22:52:52.675 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:52.675 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:52.675 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:52.687 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:52.688 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:ConfigPushSvc.PushReq appId:-1 appSeq:-658642816
+08-04 22:52:52.688 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:52.688 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:52.688 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:52.691 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method b(ToServiceMsg)
+08-04 22:52:52.691 2906-2979/com.tencent.mobileqq:MSF I/Xposed: ToServiceMsg: ToServiceMsg msName:unknown ssoSeq:-658642816 appId:537039093 appSeq:-1 sName: uin:(已删除) sCmd:ConfigPushSvc.PushResp t:30000 needResp:false
+08-04 22:52:52.691 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b()
+08-04 22:52:52.691 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Returned msgCookie: 907c6b5d
+08-04 22:52:53.770 2906-3064/com.tencent.mobileqq:MSF I/Xposed: Hooked method b(ToServiceMsg)
+08-04 22:52:53.770 2906-3064/com.tencent.mobileqq:MSF I/Xposed: ToServiceMsg: ToServiceMsg msName:wt_CheckDevLockStatus ssoSeq:47508 appId:537039093 appSeq:34 sName:com.tencent.mobileqq.msf.service.MsfService uin:(已删除) sCmd:wtlogin.trans_emp t:30000 needResp:true
+08-04 22:52:53.771 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b()
+08-04 22:52:53.771 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Returned msgCookie: 907c6b5d
+08-04 22:52:53.846 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:53.846 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:wtlogin.trans_emp appId:-1 appSeq:47508
+08-04 22:52:53.846 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:53.846 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:53.846 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:56.824 2906-2921/com.tencent.mobileqq:MSF I/Xposed: Hooked method b(ToServiceMsg)
+08-04 22:52:56.824 2906-2921/com.tencent.mobileqq:MSF I/Xposed: ToServiceMsg: ToServiceMsg msName:unknown ssoSeq:47509 appId:537039093 appSeq:36 sName:com.tencent.mobileqq.msf.service.MsfService uin:(已删除) sCmd:StatSvc.BindUin t:30000 needResp:true
+08-04 22:52:56.824 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b()
+08-04 22:52:56.824 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Returned msgCookie: 907c6b5d
+08-04 22:52:56.846 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:56.846 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:StatSvc.BindUin appId:-1 appSeq:47509
+08-04 22:52:56.847 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:56.847 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:56.847 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:56.870 2906-2922/com.tencent.mobileqq:MSF I/Xposed: Hooked method b(ToServiceMsg)
+08-04 22:52:56.870 2906-2922/com.tencent.mobileqq:MSF I/Xposed: ToServiceMsg: ToServiceMsg msName:unknown ssoSeq:47511 appId:537039093 appSeq:37 sName:com.tencent.mobileqq.msf.service.MsfService uin:(已删除) sCmd:StatSvc.BindUin t:30000 needResp:true
+08-04 22:52:56.870 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b()
+08-04 22:52:56.870 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Returned msgCookie: 907c6b5d
+08-04 22:52:56.896 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:56.896 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:StatSvc.BindUin appId:-1 appSeq:47511
+08-04 22:52:56.896 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:56.896 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:56.896 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d
+08-04 22:52:57.019 2906-2921/com.tencent.mobileqq:MSF I/Xposed: Hooked method b(ToServiceMsg)
+08-04 22:52:57.019 2906-2921/com.tencent.mobileqq:MSF I/Xposed: ToServiceMsg: ToServiceMsg msName:_msf_UnRegPush ssoSeq:47513 appId:537039093 appSeq:38 sName: uin:(已删除) sCmd:StatSvc.register t:30000 needResp:true
+08-04 22:52:57.019 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Hooked method b()
+08-04 22:52:57.020 2906-2975/com.tencent.mobileqq:MSF I/Xposed: Returned msgCookie: 907c6b5d
+08-04 22:52:57.070 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method onResponse
+08-04 22:52:57.070 2906-2979/com.tencent.mobileqq:MSF I/Xposed: FromServiceMsg: FromServiceMsg msName:unknown ssoSeq:-1 failCode:1000 errorMsg: uin:(已删除) serviceCmd:StatSvc.register appId:-1 appSeq:47513
+08-04 22:52:57.070 2906-2979/com.tencent.mobileqq:MSF I/Xposed: msgCookie: 907c6b5d
+08-04 22:52:57.070 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Hooked method a
+08-04 22:52:57.070 2906-2979/com.tencent.mobileqq:MSF I/Xposed: Setting msgCookie: 907c6b5d

+ 83 - 72
Docs/libcodecwrapperV2.h

@@ -1,14 +1,17 @@
+#include <jni.h>
 #include <string>
 #include <vector>
-#include <jni.h>
+
+// Java 端入口在 com.tencent.qphone.base.util.CodecWarpper 中定义
 
 class CCodecWarpper
 {
 public:
-    CCodecWarpper(JavaVM *vm);
-    virtual ~CCodecWarpper();
+	CCodecWarpper(JavaVM* vm);
+	virtual ~CCodecWarpper();
 
-	std::uint32_t CreatePhSigLcIdCheckPacket(std::string&, int, std::vector<std::string>&, const char*);
+	std::uint32_t CreatePhSigLcIdCheckPacket(std::string&, int, std::vector<std::string>&,
+	                                         const char*);
 	int FixAppid();
 	void ParseOtherResp(_JNIEnv*, int, CSSOData const&, int);
 	void ParsePhSigCheck(_JNIEnv*, CSSOData const&);
@@ -24,20 +27,17 @@ public:
 	}
 
 private:
-    std::uint32_t m_UnknownInt = 0x0000C350;	// 0x04
-    std::string m_UnknownStr;					// 0x08
-    std::uint32_t m_SignState = 0;				// 0x20
-    JavaVM* m_Vm;								// 0x24
-	// 指向 com.tencent.qphone.base.util.CodecWarpper
-    jclass m_CodecWarpper;						// 0x28
-	// 指向 android.content.Context 的实例,当前的 context
-    jobject m_Context;							// 0x2C
-	// 指向 com.tencent.qphone.base.remote.FromServiceMsg
-    jclass m_FromServiceMsg;					// 0x30
-    std::vector<int> m_UnknownVec;				// 0x34
-    std::int32_t m_MaxPackageSize = 0x00100000;	// 0x40
-    std::uint32_t m_UnknownInt2 = 0x21;			// 0x44
-    std::string m_Ksid;							// 0x48
+	std::uint32_t m_SsoSeq = 0x0000C350; // 0x04
+	std::string m_UnknownStr;            // 0x08
+	std::uint32_t m_SignState = 0;       // 0x20
+	JavaVM* m_Vm;                        // 0x24
+	jclass m_CodecWarpper;               // 0x28,指向 com.tencent.qphone.base.util.CodecWarpper
+	jobject m_Context;       // 0x2C,指向 android.content.Context 的实例,当前的 context
+	jclass m_FromServiceMsg; // 0x30,指向 com.tencent.qphone.base.remote.FromServiceMsg
+	std::vector<int> m_SsoSeqVec;               // 0x34
+	std::int32_t m_MaxPackageSize = 0x00100000; // 0x40
+	std::uint32_t m_UnknownInt2 = 0x21;         // 0x44
+	std::string m_Ksid;                         // 0x48
 };
 
 // sizeof(CCodecWarpper) == 0x60
@@ -45,15 +45,15 @@ private:
 class CSSOHead
 {
 public:
-    virtual ~CSSOHead();
+	virtual ~CSSOHead();
 
 private:
-    std::uint8_t m_UnknownByte = 2;     // 0x04
-    std::uint32_t m_KSSOVersion = 8;    // 0x08
-    std::string m_D2 = "";      // 0x0C
-    std::uint8_t m_UnknownByte2 = 0;    // 0x24
-    std::string m_Uin = "";     // 0x28
-                                // Uin 即用户的 qq 号
+	std::uint8_t m_UnknownByte = 2;  // 0x04
+	std::uint32_t m_KSSOVersion = 8; // 0x08
+	std::string m_D2 = "";           // 0x0C
+	std::uint8_t m_UnknownByte2 = 0; // 0x24
+	std::string m_Uin = "";          // 0x28
+	                                 // Uin 即用户的 qq 号
 };
 
 // sizeof(CSSOHead) == 0x40
@@ -61,29 +61,29 @@ private:
 class CSSOReqHead
 {
 public:
-    CSSOReqHead();
-    virtual ~CSSOReqHead();
+	CSSOReqHead();
+	virtual ~CSSOReqHead();
 
-    std::uint32_t Length();
-    std::uint32_t Length_ver9();
-    bool deSerialize()
+	std::uint32_t Length();
+	std::uint32_t Length_ver9();
+	bool deSerialize();
 
 private:
-    std::int32_t m_SsoSeq;          // 0x04
-    std::int32_t m_AppId = -1;    // 0x08
-    std::int32_t m_MsfAppId = -1;    // 0x0C
-    std::uint8_t m_B2Value = 2;     // 0x10
-    std::uint8_t m_UnknownArray[0x0B]{} // 0x11
-    std::string m_A2 = "";      // 0x1C
-    std::string m_ServiceCmd = "";     // 0x34
-    std::string m_Data = "";     // 0x4C, m_Cookie?
-    std::string m_ImeiValue = "";     // 0x64
-    std::string m_ImsiValue = "";     // 0x7C
-    std::string m_TimeStat = "";     // 0x94
-    std::string m_Ksid = "";     // 0xAC
-    std::int32_t m_UnknownInt4 = 0;     // 0xC4
-    std::string m_UnknownStr8 = "";     // 0xC8
-    std::int32_t m_UnknownInt = 0;     // 0xE0
+	std::int32_t m_SsoSeq;               // 0x04
+	std::int32_t m_AppId = -1;           // 0x08
+	std::int32_t m_MsfAppId = -1;        // 0x0C
+	std::uint8_t m_B2Value = 2;          // 0x10
+	std::uint8_t m_UnknownArray[0x0B]{}; // 0x11
+	std::string m_A2 = "";               // 0x1C
+	std::string m_ServiceCmd = "";       // 0x34
+	std::string m_Cookie = "";           // 0x4C
+	std::string m_ImeiValue = "";        // 0x64
+	std::string m_ClientVerInfo = "";    // 0x7C, imsi + "|A" + revision
+	std::string m_TimeStat = "";         // 0x94
+	std::string m_Ksid = "";             // 0xAC
+	std::int32_t m_UnknownInt4 = 0;      // 0xC4
+	std::string m_UnknownStr8 = "";      // 0xC8
+	std::int32_t m_UnknownInt = 0;       // 0xE0
 };
 
 // sizeof(CSSOReqHead) == 0xE4
@@ -91,13 +91,13 @@ private:
 class CSSOData
 {
 public:
-    virtual ~CSSOData();
+	virtual ~CSSOData();
 
 private:
-    CSSOHead m_Head;                // 0x0004
-    CSSOReqHead m_ReqHead;          // 0x0044
-    std::string m_WupBuffer = "";  // 0x0128
-    std::uint32_t m_UnknownInt = 0; // 0x0144
+	CSSOHead m_Head;                // 0x0004
+	CSSOReqHead m_ReqHead;          // 0x0044
+	std::string m_WupBuffer = "";   // 0x0128
+	std::uint32_t m_UnknownInt = 0; // 0x0144
 };
 
 // sizeof(CSSOData) == 0x0148
@@ -105,35 +105,46 @@ private:
 class CAuthData
 {
 public:
-    virtual ~CAuthData();
+	virtual ~CAuthData();
 
 private:
-    std::string m_A1;       // 0x04
-    std::string m_A2;      // 0x1C
-    std::string m_A3;      // 0x34
-    std::string m_D1;      // 0x4C
-    std::string m_D2;      // 0x64
-    std::string m_S2;      // 0x7C
-    std::string m_Key;      // 0x94
-    std::string m_UnknownData;      // 0xAC
-    std::string m_Sid;      // 0xC4
-    std::string m_UnknownData2;     // 0xDC
+	std::string m_A1;           // 0x04
+	std::string m_A2;           // 0x1C
+	std::string m_A3;           // 0x34
+	std::string m_D1;           // 0x4C
+	std::string m_D2;           // 0x64
+	std::string m_S2;           // 0x7C
+	std::string m_Key;          // 0x94
+	std::string m_UnknownData;  // 0xAC
+	std::string m_Sid;          // 0xC4
+	std::string m_UnknownData2; // 0xDC
 };
 
 // sizeof(CAuthData) == 0xF4
 
 namespace KQQConfig
 {
-    class SignatureReq
-        : public taf::JceStructBase
-    {
-    public:
-    private:
-        std::vector<std::string> m_UnknownVecStr;   // 0x00
-        std::uint32_t m_AppId;                      // 0x0C
-        std::vector<std::string> m_UnknownVecStr2;  // 0x10
-        std::uint8_t m_UnknownByte;                 // 0x1C
-    };
-}
+	class SignatureReq : public taf::JceStructBase
+	{
+	public:
+	private:
+		std::vector<std::string> m_Signatures; // 0x00
+		std::uint32_t m_AppId;                 // 0x0C
+		std::vector<std::string> m_Uins;       // 0x10
+		std::uint8_t m_UnknownByte;            // 0x1C
+	};
+} // namespace KQQConfig
 
 // sizeof(KQQConfig::SignatureReq) == 0x1D?
+
+// src/main/java/com/tencent/msf/service/protocol/e/e.java
+class SDKConfReq : public taf::JceStructBase
+{
+public:
+private:
+	std::int32_t m_UnknownInt;
+	std::int32_t iGetSdkLastTime;
+	std::vector<std::string> Uins;
+	std::int32_t iGetEspLastTime;
+	std::int32_t iGetAppidTime;
+};

+ 39 - 0
Docs/研究.md

@@ -0,0 +1,39 @@
+各种研究
+====
+
+AppId
+----
+记录于 com.tencent.common.config.AppSetting 的已混淆字段 a 中
+
+com.tencent.common.app.BaseApplicationImpl(实现 mqq.app.MobileQQ)的方法 getAppId(String) 将无视参数总是返回该值
+
+在 mqq.app.MobileQQ 的 doInit 过程中作为参数初始化了 mqq.app.MainService,在其初始化过程中又用于 com.tencent.mobileqq.msf.sdk.MsfServiceSdk 的初始化
+
+版本
+----
+位于 assets/revision.txt,也可由 com.tencent.common.config.AppSetting 的已混淆字段 g + "." + d(具有 String 类型的)组合而成
+
+Seq
+----
+Msf 的 seq 初始值随机自 [0, 100000),之后逐渐以 1 递增,若值递增至大于 100000,则将会重新随机到 [60000, 160000),通过 com.tencent.mobileqq.msf.core.MsfCore.getNextSeq() 方法获取下一个 seq
+
+通过 mqq.app.MSFServlet 转发到 Msf 的消息的 seq 初始值为 0,之后逐渐以 1 递增,无最大值限制
+
+请求的 seq 初始值为 0,在 oicq.wlogin_sdk.request.request_global.getClone(long seqence) 以非正 sequence 值调用时(用于从存储的 seq 中恢复?)逐渐以 1 递增,值存储于产生的 request_global 副本中,全局 seq 存储于 request_global._cur_sequence,若值递增至大于 200,则将会重新设为 0
+
+登录请求相关
+----
+com.tencent.mobileqq.msf.sdk.MsfServiceSdk.getLoginMsg(String uin, byte[] pwd) 方法将会打包登录请求信息,之后由 com.tencent.mobileqq.msf.core.auth.b.a(ToServiceMsg msg, int buFlag, int TrafficBitmap, byte[] sigSession)(混淆名,推测类的实际名称为 AccountCenter)调用 com.tencent.mobileqq.msf.core.auth.f.a(int appId, String uin, byte[] password, int buFlag, int TrafficBitmap, byte[] sigSession)(混淆名,推测类的实际名称为 AuthCoder) 填充 wupBuffer,然后将登录请求信息发送到 com.tencent.mobileqq.msf.service.MsfService
+
+Account
+----
+tgtgt_key = Md5(随机 16 字节 + IMEI)
+
+MsgCookie
+----
+利用 Xposed 获取了 MsgCookie 信息,由获取的信息可知,msgCookie 由任意不附带 msgCookie 的第一个请求获取,之后用于登录等其他请求,不再尝试接收新的 msgCookie,始终保持相同,不会进行持久化保存
+Xposed 获取的 MsgCookie 信息详见 XposedLog.txt
+
+安卓 apk 签名获取
+----
+可使用命令行 openssl pkcs7 -inform DER -in CERT.RSA -print_certs | openssl x509 -outform DER -out CERT.cer 获取

+ 6 - 0
Readme.md

@@ -0,0 +1,6 @@
+YumeBot
+====
+
+一个 QQ Bot,使用手机 QQ 协议
+
+本工程仅提供用于学习和研究,严禁用于商业及制作第三方 QQ 客户端用途,任何用于非法用途的行为均与作者无关

+ 1 - 0
YumeBot.Test/CMakeLists.txt

@@ -1,6 +1,7 @@
 set(SOURCE_FILES
     CryptographyTest.cpp
     JceTest.cpp
+    TlvTest.cpp
     YumeBot.Test.cpp)
 
 add_executable(YumeBot.Test ${SOURCE_FILES})

+ 9 - 7
YumeBot.Test/CryptographyTest.cpp

@@ -20,18 +20,19 @@ TEST_CASE("Cryptography", "[Utility][Cryptography]")
 		constexpr const char key[] = "00000000000000000000000000000000";
 
 		char result[CalculateOutputSize(std::size(text))]{};
-		const auto formattedKey = FormatKey(Utility::ToByteSpan(key));
+		const auto formattedKey = FormatKey(gsl::as_bytes(gsl::make_span(key)));
 
 		// 0x30303030 == { '0', '0', '0', '0' }
 		REQUIRE(std::all_of(
 		    std::cbegin(formattedKey), std::cend(formattedKey),
 		    [](std::uint32_t value) constexpr { return value == 0x30303030; }));
 
-		const auto resultSize =
-		    Encrypt(Utility::ToByteSpan(text), Utility::ToByteSpan(result), formattedKey);
+		const auto resultSize = Encrypt(gsl::as_bytes(gsl::make_span(text)),
+		                                gsl::as_writeable_bytes(gsl::make_span(result)), formattedKey);
 		char decryptResult[std::size(result)]{};
 		const auto decryptResultSize =
-		    Decrypt(Utility::ToByteSpan(result), Utility::ToByteSpan(decryptResult), formattedKey);
+		    Decrypt(gsl::as_bytes(gsl::make_span(result)),
+		            gsl::as_writeable_bytes(gsl::make_span(decryptResult)), formattedKey);
 
 		REQUIRE(resultSize == CalculateOutputSize(std::size(text)));
 		REQUIRE(decryptResultSize == std::size(text));
@@ -45,13 +46,14 @@ TEST_CASE("Cryptography", "[Utility][Cryptography]")
 		constexpr const char test[] = "test";
 
 		std::byte result[16];
-		Calculate(Utility::ToByteSpan(test).subspan(0, std::size(test) - 1), result);
+		Calculate(gsl::as_bytes(gsl::make_span(test)).subspan(0, std::size(test) - 1), result);
 
 		constexpr const std::uint8_t expectedResult[] =
 		    "\x09\x8f\x6b\xcd\x46\x21\xd3\x73\xca\xde\x4e\x83\x26\x27\xb4\xf6";
 		constexpr const auto expectedResultStr = u8"098f6bcd4621d373cade4e832627b4f6"_sv;
 		REQUIRE(std::memcmp(result, expectedResult, std::size(result)) == 0);
-		Md5ToHexString(
-		    result, [&](StringView<CodePage::Utf8> const& str) { REQUIRE(str == expectedResultStr.Trim()); });
+		Md5ToHexString(result, [&](StringView<CodePage::Utf8> const& str) {
+			REQUIRE(str == expectedResultStr.Trim());
+		});
 	}
 }

+ 20 - 0
YumeBot.Test/TlvTest.cpp

@@ -0,0 +1,20 @@
+#include <Tlv.h>
+#include <Utility.h>
+#include <catch2/catch.hpp>
+
+using namespace YumeBot;
+using namespace Cafe::Encoding::StringLiterals;
+
+TEST_CASE("Tlv", "[Tlv]")
+{
+	using namespace Tlv;
+
+	SECTION("Serialization")
+	{
+		Cafe::Io::MemoryStream stream;
+
+		TlvBuilder builder{ &stream };
+		builder.WriteTlv(
+		    TlvT<1>{ .Uin = 123456, .ServerTime = Utility::GetPosixTime(), .ClientIp = {} });
+	}
+}

+ 4 - 1
YumeBot/CMakeLists.txt

@@ -1,6 +1,7 @@
 set(SOURCE_FILES
     Cryptography.cpp
     Jce.cpp
+    Session.cpp
     Tlv.cpp
     Wup.cpp)
 
@@ -9,6 +10,8 @@ set(HEADERS
     Jce.h
     JceStructDef.h
     Misc.h
+    Request.h
+    Session.h
     Tlv.h
     Utility.h
     Wup.h)
@@ -26,7 +29,7 @@ target_include_directories(YumeBot INTERFACE
     PRIVATE ${OPENSSL_INCLUDE_DIR})
 
 target_link_libraries(YumeBot
-    PUBLIC CONAN_PKG::Cafe CONAN_PKG::asio
+    PUBLIC CONAN_PKG::Cafe
     PRIVATE ${OPENSSL_LIBRARIES})
 
 install(TARGETS YumeBot

+ 141 - 32
YumeBot/Cryptography.cpp

@@ -1,8 +1,12 @@
 #include "Cryptography.h"
 #include "Utility.h"
-#include <random>
-#include <openssl/md5.h>
+#include <Cafe/Io/Streams/MemoryStream.h>
+#include <Cafe/Misc/Scope.h>
 #include <cstring>
+#include <openssl/ecdh.h>
+#include <openssl/md5.h>
+#include <openssl/objects.h>
+#include <random>
 
 #undef min
 #undef max
@@ -16,7 +20,9 @@ namespace
 	constexpr std::size_t TeaIterationTimes = 16;
 	constexpr std::uint32_t TeaDecryptInitSum = TeaDelta << 4;
 
-	void Encrypt(gsl::span<const std::uint32_t, 2> const& input, gsl::span<std::uint32_t, 2> const& output, gsl::span<const std::uint32_t, 4> const& key)
+	void Encrypt(gsl::span<const std::uint32_t, 2> const& input,
+	             gsl::span<std::uint32_t, 2> const& output,
+	             gsl::span<const std::uint32_t, 4> const& key)
 	{
 		auto left = input[0], right = input[1];
 		const auto a = key[0], b = key[1], c = key[2], d = key[3];
@@ -33,7 +39,9 @@ namespace
 		output[1] = right;
 	}
 
-	void Decrypt(gsl::span<const std::uint32_t, 2> const& input, gsl::span<std::uint32_t, 2> const& output, gsl::span<const std::uint32_t, 4> const& key)
+	void Decrypt(gsl::span<const std::uint32_t, 2> const& input,
+	             gsl::span<std::uint32_t, 2> const& output,
+	             gsl::span<const std::uint32_t, 4> const& key)
 	{
 		auto left = input[0], right = input[1];
 		const auto a = key[0], b = key[1], c = key[2], d = key[3];
@@ -49,7 +57,7 @@ namespace
 		output[0] = left;
 		output[1] = right;
 	}
-}
+} // namespace
 
 std::array<std::uint32_t, 4> Tea::FormatKey(gsl::span<const std::byte> const& key)
 {
@@ -63,15 +71,29 @@ std::array<std::uint32_t, 4> Tea::FormatKey(gsl::span<const std::byte> const& ke
 	return result;
 }
 
-///	@see https://baike.baidu.com/item/TEA%E5%8A%A0%E5%AF%86%E7%AE%97%E6%B3%95
-std::size_t Tea::Encrypt(gsl::span<const std::byte> const& input, gsl::span<std::byte> const& output, gsl::span<const std::uint32_t, 4> const& key)
+std::size_t Tea::Encrypt(gsl::span<const std::byte> const& input,
+                         gsl::span<std::byte> const& output,
+                         gsl::span<const std::uint32_t, 4> const& key)
+{
+	Cafe::Io::ExternalMemoryOutputStream stream{ output, Cafe::Io::ErrorOnOutOfRange };
+	return Encrypt(input, &stream, key);
+}
+
+std::size_t Tea::Decrypt(gsl::span<const std::byte> const& input,
+                         gsl::span<std::byte> const& output,
+                         gsl::span<const std::uint32_t, 4> const& key)
+{
+	Cafe::Io::ExternalMemoryOutputStream stream{ output, Cafe::Io::ErrorOnOutOfRange };
+	return Decrypt(input, &stream, key);
+}
+
+std::size_t Tea::Encrypt(gsl::span<const std::byte> const& input,
+                         Cafe::Io::OutputStream* outputStream,
+                         gsl::span<const std::uint32_t, 4> const& key)
 {
 	const auto totalProcessSize = CalculateOutputSize(input.size());
 	assert(totalProcessSize % TeaProcessUnitSize == 0);
-	if (static_cast<std::size_t>(output.size()) < totalProcessSize)
-	{
-		CAFE_THROW(CryptoException, u8"No enough space to output."_sv);
-	}
+
 	const auto paddingSize = totalProcessSize - input.size();
 	const auto frontPaddingSize = paddingSize - 7;
 
@@ -84,7 +106,8 @@ std::size_t Tea::Encrypt(gsl::span<const std::byte> const& input, gsl::span<std:
 
 	auto inputPtr = input.data();
 
-	for (std::size_t processedLength = 0; processedLength < totalProcessSize; processedLength += TeaProcessUnitSize)
+	for (std::size_t processedLength = 0; processedLength < totalProcessSize;
+	     processedLength += TeaProcessUnitSize)
 	{
 		if (processedLength == totalProcessSize - TeaProcessUnitSize)
 		{
@@ -98,17 +121,18 @@ std::size_t Tea::Encrypt(gsl::span<const std::byte> const& input, gsl::span<std:
 
 			if (processedLength < frontPaddingSize)
 			{
-				const auto paddingEndPointer = std::next(writePointer, std::min((sizeof inputBuffer) / sizeof(std::byte), frontPaddingSize - processedLength));
+				const auto paddingEndPointer =
+				    std::next(writePointer, std::min((sizeof inputBuffer) / sizeof(std::byte),
+				                                     frontPaddingSize - processedLength));
 
 				if (processedLength == 0)
 				{
-					*writePointer++ = static_cast<std::byte>((dist(randomEngine) & 0xF8) | (paddingSize - 10));
+					*writePointer++ =
+					    static_cast<std::byte>((dist(randomEngine) & 0xF8) | (paddingSize - 10));
 				}
 
-				std::generate(writePointer, paddingEndPointer, [&]
-				{
-					return static_cast<std::byte>(dist(randomEngine));
-				});
+				std::generate(writePointer, paddingEndPointer,
+				              [&] { return static_cast<std::byte>(dist(randomEngine)); });
 
 				writePointer = paddingEndPointer;
 			}
@@ -129,13 +153,15 @@ std::size_t Tea::Encrypt(gsl::span<const std::byte> const& input, gsl::span<std:
 		}
 
 		::Encrypt(inputBuffer, outputBuffer, key);
-		std::memcpy(&output[processedLength], outputBuffer, TeaProcessUnitSize);
+		outputStream->WriteBytes(gsl::as_bytes(gsl::make_span(outputBuffer)));
 	}
 
 	return totalProcessSize;
 }
 
-std::size_t Tea::Decrypt(gsl::span<const std::byte> const& input, gsl::span<std::byte> const& output, gsl::span<const std::uint32_t, 4> const& key)
+std::size_t Tea::Decrypt(gsl::span<const std::byte> const& input,
+                         Cafe::Io::OutputStream* outputStream,
+                         gsl::span<const std::uint32_t, 4> const& key)
 {
 	const auto inputSize = static_cast<std::size_t>(input.size());
 	if (inputSize % TeaProcessUnitSize != 0 || inputSize < 16)
@@ -148,9 +174,9 @@ std::size_t Tea::Decrypt(gsl::span<const std::byte> const& input, gsl::span<std:
 	std::uint32_t lastInputBuffer[2];
 
 	std::size_t frontPaddingSize;
-	auto outputPtr = output.data();
 
-	for (std::size_t processedLength = 0; processedLength < inputSize; processedLength += TeaProcessUnitSize)
+	for (std::size_t processedLength = 0; processedLength < inputSize;
+	     processedLength += TeaProcessUnitSize)
 	{
 		std::memcpy(inputBuffer, &input[processedLength], TeaProcessUnitSize);
 
@@ -172,21 +198,17 @@ std::size_t Tea::Decrypt(gsl::span<const std::byte> const& input, gsl::span<std:
 		{
 			const auto outputBufferPtr = reinterpret_cast<std::uint8_t*>(outputBuffer);
 			const std::size_t paddingSize = (outputBufferPtr[0] & 7u) + 10u;
-			if (static_cast<std::size_t>(output.size()) < inputSize - paddingSize)
-			{
-				CAFE_THROW(CryptoException, u8"No enough space to output."_sv);
-			}
 			frontPaddingSize = paddingSize - 7;
 			if (frontPaddingSize < TeaProcessUnitSize)
 			{
 				const auto dataSize = TeaProcessUnitSize - frontPaddingSize;
-				std::memcpy(outputPtr, outputBufferPtr + frontPaddingSize, dataSize);
-				outputPtr += dataSize;
+				outputStream->WriteBytes(
+				    gsl::as_bytes(gsl::make_span(outputBufferPtr + frontPaddingSize, dataSize)));
 			}
 		}
 		else if (processedLength == inputSize - TeaProcessUnitSize)
 		{
-			*outputPtr = reinterpret_cast<std::byte*>(outputBuffer)[0];
+			outputStream->WriteByte(reinterpret_cast<std::byte*>(outputBuffer)[0]);
 		}
 		else
 		{
@@ -203,8 +225,7 @@ std::size_t Tea::Decrypt(gsl::span<const std::byte> const& input, gsl::span<std:
 				outputBufferPtr += TeaProcessUnitSize - outputSize;
 			}
 
-			std::memcpy(outputPtr, outputBufferPtr, outputSize);
-			outputPtr += outputSize;
+			outputStream->WriteBytes(gsl::as_bytes(gsl::make_span(outputBufferPtr, outputSize)));
 		}
 	}
 
@@ -213,5 +234,93 @@ std::size_t Tea::Decrypt(gsl::span<const std::byte> const& input, gsl::span<std:
 
 void Md5::Calculate(gsl::span<const std::byte> const& input, gsl::span<std::byte, 16> const& output)
 {
-	MD5(reinterpret_cast<const unsigned char*>(input.data()), input.size(), reinterpret_cast<unsigned char*>(output.data()));
+	MD5(reinterpret_cast<const unsigned char*>(input.data()), input.size(),
+	    reinterpret_cast<unsigned char*>(output.data()));
+}
+
+namespace
+{
+	// 对应 QQ 5.X
+	constexpr unsigned char S_PUB_KEY[] = { 0x04, 0x92, 0x8D, 0x88, 0x50, 0x67, 0x30, 0x88, 0xB3,
+		                                      0x43, 0x26, 0x4E, 0x0C, 0x6B, 0xAC, 0xB8, 0x49, 0x6D,
+		                                      0x69, 0x77, 0x99, 0xF3, 0x72, 0x11, 0xDE, 0xB2, 0x5B,
+		                                      0xB7, 0x39, 0x06, 0xCB, 0x08, 0x9F, 0xEA, 0x96, 0x39,
+		                                      0xB4, 0xE0, 0x26, 0x04, 0x98, 0xB5, 0x1A, 0x99, 0x2D,
+		                                      0x50, 0x81, 0x3D, 0xA8 };
+} // namespace
+
+void Ecdh::GenerateKeyPair(gsl::span<std::byte, 25> const& pubKey,
+                           gsl::span<std::byte, 16> const& shareKey)
+{
+	const auto key = EC_KEY_new_by_curve_name(NID_secp192k1);
+	if (!key)
+	{
+		CAFE_THROW(CryptoException, u8"EC_KEY_new_by_curve_name failed"_sv);
+	}
+
+	CAFE_SCOPE_EXIT
+	{
+		EC_KEY_free(key);
+	};
+
+	if (!EC_KEY_generate_key(key))
+	{
+		CAFE_THROW(CryptoException, u8"EC_KEY_generate_key failed"_sv);
+	}
+
+	const auto point1 = EC_KEY_get0_public_key(key);
+	if (!point1)
+	{
+		CAFE_THROW(CryptoException, u8"EC_KEY_get0_public_key failed"_sv);
+	}
+
+	const auto group1 = EC_KEY_get0_group(key);
+	if (!group1)
+	{
+		CAFE_THROW(CryptoException, u8"EC_KEY_get0_group failed"_sv);
+	}
+
+	unsigned char resultPubKey[25];
+	const auto octSize = EC_POINT_point2oct(group1, point1, POINT_CONVERSION_COMPRESSED, resultPubKey,
+	                                        sizeof resultPubKey, nullptr);
+	if (octSize != sizeof resultPubKey)
+	{
+		CAFE_THROW(CryptoException, u8"EC_POINT_point2oct failed"_sv);
+	}
+
+	const auto group2 = EC_KEY_get0_group(key);
+	if (!group2)
+	{
+		CAFE_THROW(CryptoException, u8"EC_KEY_get0_group failed"_sv);
+	}
+
+	const auto point2 = EC_POINT_new(group2);
+	if (!point2)
+	{
+		CAFE_THROW(CryptoException, u8"EC_POINT_new failed"_sv);
+	}
+
+	CAFE_SCOPE_EXIT
+	{
+		EC_POINT_free(point2);
+	};
+
+	const auto pointSize = EC_POINT_oct2point(group2, point2, S_PUB_KEY, sizeof S_PUB_KEY, nullptr);
+	if (!pointSize)
+	{
+		CAFE_THROW(CryptoException, u8"EC_POINT_oct2point failed"_sv);
+	}
+
+	unsigned char resultShareKey[25];
+	const auto result = ECDH_compute_key(resultShareKey, sizeof resultShareKey, point2, key, nullptr);
+	if (result != sizeof resultShareKey)
+	{
+		CAFE_THROW(CryptoException, u8"ECDH_compute_key failed"_sv);
+	}
+
+	unsigned char resultShareKeyMd5[16];
+	MD5(resultShareKey, result, resultShareKeyMd5);
+
+	std::memcpy(pubKey.data(), resultPubKey, 25);
+	std::memcpy(shareKey.data(), resultShareKeyMd5, 16);
 }

+ 18 - 1
YumeBot/Cryptography.h

@@ -1,7 +1,7 @@
 #pragma once
 
 #include <Cafe/ErrorHandling/ErrorHandling.h>
-#include <gsl/span>
+#include <Cafe/Io/Streams/StreamBase.h>
 
 #include "Utility.h"
 #include <charconv>
@@ -25,6 +25,17 @@ namespace YumeBot::Cryptography
 		                    gsl::span<const std::uint32_t, 4> const& key);
 		std::size_t Decrypt(gsl::span<const std::byte> const& input, gsl::span<std::byte> const& output,
 		                    gsl::span<const std::uint32_t, 4> const& key);
+
+		///	@see    https://baike.baidu.com/item/TEA%E5%8A%A0%E5%AF%86%E7%AE%97%E6%B3%95
+		/// @return 应当写入的字节数,用户应检查是否成功写入指定数量的字节到 outputStream 内
+		///         若 outputStream 在写入开始前具有不少于 Tea::CalculateOutputSize(key.size())
+		///         的可用空间,则保证写入一定成功
+		std::size_t Encrypt(gsl::span<const std::byte> const& input,
+		                    Cafe::Io::OutputStream* outputStream,
+		                    gsl::span<const std::uint32_t, 4> const& key);
+		std::size_t Decrypt(gsl::span<const std::byte> const& input,
+		                    Cafe::Io::OutputStream* outputStream,
+		                    gsl::span<const std::uint32_t, 4> const& key);
 	} // namespace Tea
 
 	namespace Md5
@@ -56,4 +67,10 @@ namespace YumeBot::Cryptography
 			                   Cafe::Encoding::StringView<Cafe::Encoding::CodePage::Utf8>{ result });
 		}
 	} // namespace Md5
+
+	namespace Ecdh
+	{
+		void GenerateKeyPair(gsl::span<std::byte, 25> const& pubKey,
+		                     gsl::span<std::byte, 16> const& shareKey);
+	} // namespace Ecdh
 } // namespace YumeBot::Cryptography

+ 41 - 21
YumeBot/JceStructDef.h

@@ -1,85 +1,85 @@
 #ifndef JCE_STRUCT
-#define JCE_STRUCT(name, alias)
+#	define JCE_STRUCT(name, alias)
 #endif
 
 #ifndef JCE_STRUCT_DEFAULT_ALIAS
-#define JCE_STRUCT_DEFAULT_ALIAS(name) JCE_STRUCT(name, #name)
+#	define JCE_STRUCT_DEFAULT_ALIAS(name) JCE_STRUCT(name, #  name)
 #endif
 
 #ifndef END_JCE_STRUCT
-#define END_JCE_STRUCT(name)
+#	define END_JCE_STRUCT(name)
 #endif
 
 #ifndef NO_OP
-#define NO_OP
+#	define NO_OP
 #endif
 
 #ifndef DEFAULT_INITIALIZER
-#define DEFAULT_INITIALIZER(...) NO_OP
+#	define DEFAULT_INITIALIZER(...) NO_OP
 #endif
 
 #ifndef IS_OPTIONAL
-#define IS_OPTIONAL(defaultValue) NO_OP
+#	define IS_OPTIONAL(defaultValue) NO_OP
 #endif
 
 #ifndef TEMPLATE_ARGUMENT
-#define TEMPLATE_ARGUMENT(...) NO_OP
+#	define TEMPLATE_ARGUMENT(...) NO_OP
 #endif
 
 #ifndef FIELD
-#define FIELD(name, tag, type, ...)
+#	define FIELD(name, tag, type, ...)
 #endif
 
 #ifndef BYTE
-#define BYTE(name, tag, ...) FIELD(name, tag, Byte, __VA_ARGS__)
+#	define BYTE(name, tag, ...) FIELD(name, tag, Byte, __VA_ARGS__)
 #endif
 
 #ifndef SHORT
-#define SHORT(name, tag, ...) FIELD(name, tag, Short, __VA_ARGS__)
+#	define SHORT(name, tag, ...) FIELD(name, tag, Short, __VA_ARGS__)
 #endif
 
 #ifndef INT
-#define INT(name, tag, ...) FIELD(name, tag, Int, __VA_ARGS__)
+#	define INT(name, tag, ...) FIELD(name, tag, Int, __VA_ARGS__)
 #endif
 
 #ifndef LONG
-#define LONG(name, tag, ...) FIELD(name, tag, Long, __VA_ARGS__)
+#	define LONG(name, tag, ...) FIELD(name, tag, Long, __VA_ARGS__)
 #endif
 
 #ifndef FLOAT
-#define FLOAT(name, tag, ...) FIELD(name, tag, Float, __VA_ARGS__)
+#	define FLOAT(name, tag, ...) FIELD(name, tag, Float, __VA_ARGS__)
 #endif
 
 #ifndef DOUBLE
-#define DOUBLE(name, tag, ...) FIELD(name, tag, Double, __VA_ARGS__)
+#	define DOUBLE(name, tag, ...) FIELD(name, tag, Double, __VA_ARGS__)
 #endif
 
 #ifndef STRING1
-#define STRING1(name, tag, ...) FIELD(name, tag, String1, __VA_ARGS__)
+#	define STRING1(name, tag, ...) FIELD(name, tag, String1, __VA_ARGS__)
 #endif
 
 #ifndef STRING4
-#define STRING4(name, tag, ...) FIELD(name, tag, String4, __VA_ARGS__)
+#	define STRING4(name, tag, ...) FIELD(name, tag, String4, __VA_ARGS__)
 #endif
 
 #ifndef MAP
-#define MAP(name, tag, ...) FIELD(name, tag, Map, __VA_ARGS__)
+#	define MAP(name, tag, ...) FIELD(name, tag, Map, __VA_ARGS__)
 #endif
 
 #ifndef LIST
-#define LIST(name, tag, ...) FIELD(name, tag, List, __VA_ARGS__)
+#	define LIST(name, tag, ...) FIELD(name, tag, List, __VA_ARGS__)
 #endif
 
 #ifndef STRUCT
-#define STRUCT(name, tag, ...) FIELD(name, tag, StructBegin, __VA_ARGS__)
+#	define STRUCT(name, tag, ...) FIELD(name, tag, StructBegin, __VA_ARGS__)
 #endif
 
 #ifndef ZERO_TAG
-#define ZERO_TAG(name, tag, ...) FIELD(name, tag, ZeroTag, __VA_ARGS__)
+#	define ZERO_TAG(name, tag, ...) FIELD(name, tag, ZeroTag, __VA_ARGS__)
 #endif
 
 #ifndef SIMPLE_LIST
-#define SIMPLE_LIST(name, tag, ...) FIELD(name, tag, SimpleList, __VA_ARGS__)
+#	define SIMPLE_LIST(name, tag, ...) FIELD(name, tag, SimpleList, __VA_ARGS__)
 #endif
 
 JCE_STRUCT_DEFAULT_ALIAS(JceTest)
@@ -106,6 +106,26 @@ JCE_STRUCT_DEFAULT_ALIAS(RequestPacket)
 	MAP(status, 10, TEMPLATE_ARGUMENT(UsingString, UsingString))
 END_JCE_STRUCT(RequestPacket)
 
+JCE_STRUCT_DEFAULT_ALIAS(RequestHeader)
+	INT(a, 0)
+	INT(b, 1)
+	INT(MsfSeq, 2)
+	INT(d, 3)
+	STRING1(Uin, 4)
+	INT(AppId, 5)
+	STRING1(AppIdStr, 6)
+	STRING1(h, 7)
+	INT(i, 8)
+END_JCE_STRUCT(RequestHeader)
+
+JCE_STRUCT_DEFAULT_ALIAS(SDKConfReq)
+	INT(UnknownInt, 0)
+	INT(iGetSdkLastTime, 1)
+	LIST(Uins, 2, TEMPLATE_ARGUMENT(UsingString))
+	INT(iGetEspLastTime, 3)
+	INT(iGetAppidTime, 4)
+END_JCE_STRUCT(SDKConfReq)
+
 #undef SIMPLE_LIST
 #undef ZERO_TAG
 #undef STRUCT

+ 53 - 2
YumeBot/Misc.h

@@ -3,14 +3,65 @@
 
 namespace YumeBot
 {
-	enum class LocaleId
+	constexpr std::uint32_t DefaultAppId = 537039093;
+	/// @remark 使用短信登录时为 3
+	constexpr std::uint32_t DefualtSigSrc = 1;
+	constexpr std::uint32_t DefaultBitmap = 0x7F7C;
+	constexpr std::uint32_t DefaultGetSig = 0x10400;
+	constexpr std::uint32_t DefaultGetSig1 = 0x1E1060;
+
+	constexpr UsingStringView DefaultDomains[]{ CAFE_UTF8_SV("game.qq.com") };
+
+	struct IpV4Addr
+	{
+		std::uint8_t Content[4]{};
+
+		constexpr bool IsUnspecified() const noexcept
+		{
+			return std::all_of(std::begin(Content), std::end(Content),
+			                   [](std::uint8_t value) { return value == 0; });
+		}
+	};
+
+	enum class LocaleIdEnum
 	{
 		EN_US = 1033,
 		ZH_CN = 2052,
 		ZH_HK = 1028,
 	};
 
-	constexpr LocaleId UsingLocaleId = LocaleId::ZH_CN;
+	constexpr LocaleIdEnum UsingLocaleId = LocaleIdEnum::ZH_CN;
+
+	enum class ConnectionTypeEnum
+	{
+		Mobile = 0,
+		Wifi = 1,
+		MobileMMS = 2,
+		MobileSUPL = 3,
+		MobileDUN = 4,
+		MobileHIPRI = 5,
+		WiMAX = 6,
+		Bluetooth = 7,
+		Dummy = 8,
+		Ethernet = 9,
+		Vpn = 17
+	};
+
+	constexpr auto DefaultApkVersion = CAFE_UTF8_SV("5.0.0");
+
+	constexpr std::uint16_t DefaultClientVersion = 8001;
+
+	// 参考 Docs/研究.md,是签名的 MD5
+	constexpr std::uint8_t Signature[]{ 0xa6, 0xb7, 0x45, 0xbf, 0x24, 0xa2, 0xc2, 0x77,
+		                                  0x52, 0x77, 0x16, 0xf6, 0xf3, 0x6e, 0xb6, 0x8d };
+
+	// GMT 2014/7/21 8:08:42
+	constexpr std::time_t BuildTime = 1405930122;
+
+	constexpr auto OsType = CAFE_UTF8_SV("android");
+	constexpr auto DefaultOsVersion = CAFE_UTF8_SV("5.0.2");
+
+	constexpr auto SdkVersion = CAFE_UTF8_SV("5.2.2.98");
 
 	static_assert(
 	    std::numeric_limits<float>::is_iec559 && std::numeric_limits<double>::is_iec559,

+ 303 - 0
YumeBot/Request.h

@@ -0,0 +1,303 @@
+#pragma once
+
+#include "Tlv.h"
+
+namespace YumeBot::Request
+{
+	struct KeyStorage
+	{
+		std::byte PubKey[25];
+		std::byte ShareKey[16];
+		std::byte RandomKey[16];
+
+		struct RandomizeTag
+		{
+		};
+
+		static constexpr RandomizeTag Randomize{};
+
+		KeyStorage(gsl::span<std::byte, 25> const& pubKey, gsl::span<std::byte, 16> const& shareKey,
+		           gsl::span<std::byte, 16> const& randomKey)
+		{
+			std::memcpy(PubKey, pubKey.data(), 25);
+			std::memcpy(ShareKey, shareKey.data(), 16);
+			std::memcpy(RandomKey, randomKey.data(), 16);
+		}
+
+		explicit KeyStorage(RandomizeTag)
+		{
+			Cryptography::Ecdh::GenerateKeyPair(gsl::make_span(PubKey), gsl::make_span(ShareKey));
+
+			std::random_device rd;
+			std::default_random_engine engine{ rd };
+			std::uniform_int_distribution<> dist{ 0, std::numeric_limits<std::uint8_t>::max() };
+			std::generate(std::begin(RandomKey), std::end(RandomKey),
+			              [&] { return static_cast<std::byte>(dist(engine)); });
+		}
+	};
+
+	struct RequestContext
+	{
+		std::uint32_t Uin;
+		std::array<std::byte, 16> PasswordMd5;
+		std::uint32_t ServerTime = Utility::GetPosixTime();
+		LocaleIdEnum CurrentLocaleId = LocaleIdEnum::ZH_CN;
+
+		UsingString OsVersion = DefaultOsVersion;
+
+		UsingString Imei;
+		UsingString WifiMac;
+		UsingString AndroidId;
+
+		KeyStorage Keys{ KeyStorage::Randomize };
+
+		UsingString SimOperatorName;
+		ConnectionTypeEnum ConnectionType;
+		UsingString Apn;
+
+		UsingString ApkVersion = DefaultApkVersion;
+		gsl::span<const std::byte> ApkSignature = gsl::as_bytes(gsl::make_span(Signature));
+
+		std::array<std::byte, 16> const& GetGuid() const
+		{
+			if (m_Guid.has_value())
+			{
+				return m_Guid.value();
+			}
+
+			const auto tmp = Imei + WifiMac;
+			std::array<std::byte, 16> result;
+			Cryptography::Md5::Calculate(gsl::as_bytes(tmp.GetView().GetTrimmedSpan()),
+			                             gsl::make_span(result));
+			return result;
+		}
+
+		std::size_t AcquireRequestSeq() const noexcept
+		{
+			return std::exchange(m_RequestSeq, (m_RequestSeq + 1) % 200);
+		}
+
+		std::size_t AcquireClientSeq() const noexcept
+		{
+			return std::exchange(m_ClientSeq, (m_ClientSeq + 1) % 200);
+		}
+
+	private:
+		std::optional<std::array<std::byte, 16>> m_Guid;
+		mutable std::size_t m_RequestSeq{};
+		mutable std::size_t m_ClientSeq{};
+	};
+
+	/// @brief  加密类型
+	enum class EncryptType
+	{
+		Ecdh,
+		Kc
+	};
+
+	template <typename T, std::uint16_t CmdValue, std::uint16_t SubCmdValue,
+	          EncryptType EncryptTypeValue>
+	struct RequestBase
+	{
+		static constexpr std::uint16_t Cmd = CmdValue;
+		static constexpr std::uint16_t SubCmd = SubCmdValue;
+		static constexpr EncryptType UsingEncryptType = EncryptTypeValue;
+
+		void Write(Tlv::TlvBuilder& tlvBuilder, RequestContext const& context, std::size_t seq) const
+		{
+			static_cast<const T*>(this)->DoWrite(tlvBuilder, context, seq);
+		}
+	};
+
+	template <typename T, std::uint16_t SubCmdValue>
+	struct ResponseBase
+	{
+		static constexpr std::uint16_t SubCmd = SubCmdValue;
+
+		void ProcessResponse(Cafe::Io::BinaryReader& reader, RequestContext& context,
+		                     std::size_t seq) const
+		{
+			return static_cast<const T*>(this)->DoProcessResponse(reader, context, seq);
+		}
+	};
+
+	class RequestBuilder
+	{
+	public:
+		static constexpr std::size_t RequestHeadSize = 27;
+
+		explicit RequestBuilder(RequestContext context) : m_Context{ std::move(context) }
+		{
+		}
+
+		/// @return Seq
+		template <typename T, std::uint16_t CmdValue, std::uint16_t SubCmdValue,
+		          EncryptType EncryptTypeValue>
+		std::size_t
+		WriteRequest(Cafe::Io::OutputStream* stream,
+		             RequestBase<T, CmdValue, SubCmdValue, EncryptTypeValue> const& request) const
+		{
+			const auto seq = m_Context.AcquireRequestSeq();
+
+			Cafe::Io::MemoryStream unencryptedBodyStream;
+			Cafe::Io::BinaryWriter writer{ &unencryptedBodyStream, std::endian::big };
+
+			writer.Write(SubCmdValue);
+
+			const auto tlvNumPos = unencryptedBodyStream.GetPosition();
+			writer.Write(std::uint16_t{});
+
+			const auto tlvNum = [&] {
+				Tlv::TlvBuilder tlvBuilder{ &unencryptedBodyStream };
+				request.Write(tlvBuilder, m_Context, seq);
+				return tlvBuilder.GetTlvCount();
+			}();
+
+			unencryptedBodyStream.SeekFromBegin(tlvNumPos);
+			writer.Write(tlvNum);
+
+			Cafe::Io::MemoryStream requestContentStream;
+			Cafe::Io::BinaryWriter requestWriter{ &requestContentStream, std::endian::big };
+
+			// 写入 Head
+			const auto clientSeq = m_Context.AcquireClientSeq();
+			requestWriter.Write(std::uint8_t{ 2 });
+			const auto totalSizePos = requestContentStream.GetPosition();
+			requestWriter.Write(std::uint16_t{});
+			requestWriter.Write(DefaultClientVersion);
+			requestWriter.Write(CmdValue);
+			requestWriter.Write(seq);
+			requestWriter.Write(m_Context.Uin);
+			requestWriter.Write(std::uint8_t{ 3 });
+			requestWriter.Write(std::uint8_t{ 7 });
+			requestWriter.Write(std::uint8_t{});     // retry
+			requestWriter.Write(std::uint32_t{ 2 }); // ext type
+			requestWriter.Write(std::uint32_t{});    // app client type
+			requestWriter.Write(std::uint32_t{});    // ext instance
+
+			// 写入加密的 Body
+			const auto bodyBeginPos = requestContentStream.GetPosition();
+			EncryptBody<EncryptTypeValue>(&requestContentStream,
+			                              unencryptedBodyStream.GetInternalStorage());
+			const auto bodyEndPos = requestContentStream.GetPosition();
+			const auto bodySize = bodyEndPos - bodyBeginPos;
+
+			requestContentStream.SeekFromBegin(totalSizePos);
+			requestWriter.Write(static_cast<std::uint16_t>(RequestHeadSize + 2 + bodySize));
+
+			requestContentStream.SeekFromBegin(bodyEndPos);
+
+			// 写入 End
+			requestWriter.Write(std::uint8_t{ 3 });
+
+			EncodeRequest(stream, requestContentStream.GetInternalStorage());
+
+			return seq;
+		}
+
+		template <EncryptType EncryptTypeValue>
+		void EncryptBody(Cafe::Io::OutputStream* stream, gsl::span<const std::byte> const& body)
+		{
+			Cafe::Io::BinaryWriter writer{ stream, std::endian::big };
+
+			const auto teaKey = [&] {
+				if constexpr (EncryptTypeValue == EncryptType::Ecdh)
+				{
+					writer.Write(std::uint16_t{ 0x0101 });
+					stream->WriteBytes(gsl::make_span(m_Context.Keys.RandomKey));
+					writer.Write(std::uint16_t{ 0x0102 });
+					writer.Write(static_cast<std::uint16_t>(sizeof m_Context.Keys.PubKey));
+					stream->WriteBytes(gsl::make_span(m_Context.Keys.PubKey));
+
+					return Cryptography::Tea::FormatKey(m_Context.Keys.ShareKey);
+				}
+				else
+				{
+					writer.Write(std::uint16_t{ 0x0102 });
+					stream->WriteBytes(gsl::make_span(m_Context.Keys.RandomKey));
+					writer.Write(std::uint16_t{ 0x0102 });
+					writer.Write(std::uint16_t{});
+
+					return Cryptography::Tea::FormatKey(m_Context.Keys.RandomKey);
+				}
+			}();
+			Cryptography::Tea::Encrypt(body, stream, teaKey);
+		}
+
+		void EncodeRequest(Cafe::Io::OutputStream* stream, gsl::span<const std::byte> const& request)
+		{
+			// TODO
+		}
+
+	private:
+		RequestContext m_Context;
+	};
+
+	struct RequestTGTGT : RequestBase<RequestTGTGT, 2064, 9, EncryptType::Ecdh>
+	{
+		void DoWrite(Tlv::TlvBuilder& tlvBuilder, RequestContext const& context, std::size_t seq) const
+		{
+			const auto& guid = context.GetGuid();
+
+			tlvBuilder.WriteTlv(Tlv::TlvT<0x106>{ AppId, SubAppId, ClientVersion, Uin, InitTime, ClientIp,
+			                                      false, PasswordMd5, 0, TGTGTKey, false, guid, 1 });
+			tlvBuilder.WriteTlv(Tlv::TlvT<0x100>{ AppId, SubAppId, WxAppId, GetSig1 });
+			tlvBuilder.WriteTlv(Tlv::TlvT<0x107>{ PicType, CapType, PicSize, RetType });
+			tlvBuilder.WriteTlv(Tlv::TlvT<0x116>{ Bitmap, GetSig, SubAppIdList });
+			tlvBuilder.WriteTlv(Tlv::TlvT<0x145>{ guid });
+			tlvBuilder.WriteTlv(Tlv::TlvT<0x154>{ seq });
+			tlvBuilder.WriteTlv(
+			    Tlv::TlvT<0x141>{ context.SimOperatorName, context.ConnectionType, context.Apn });
+			tlvBuilder.WriteTlv(Tlv::TlvT<0x8>{ 0, context.CurrentLocaleId, 0 });
+			tlvBuilder.WriteTlv(
+			    Tlv::TlvT<0x147>{ AppId, DefaultApkVersion, gsl::as_bytes(gsl::make_span(Signature)) });
+			tlvBuilder.WriteTlv(Tlv::TlvT<0x177>{ BuildTime, SdkVersion });
+
+			if (!Ksid.empty())
+			{
+				tlvBuilder.WriteTlv(Tlv::TlvT<0x108>{ std::vector<std::byte>(Ksid.begin(), Ksid.end()) });
+			}
+
+			if (!context.WifiMac.IsEmpty())
+			{
+				tlvBuilder.WriteTlv(Tlv::TlvT<0x187>{ context.WifiMac });
+			}
+
+			if (!context.AndroidId.IsEmpty())
+			{
+				tlvBuilder.WriteTlv(Tlv::TlvT<0x188>{ context.AndroidId });
+			}
+
+			if (!context.Imei.IsEmpty())
+			{
+				tlvBuilder.WriteTlv(Tlv::TlvT<0x109>{ context.Imei });
+			}
+
+			// TODO
+		}
+
+		std::uint32_t AppId;
+		std::uint32_t SubAppId;
+		std::uint32_t ClientVersion;
+		std::uint32_t Uin;
+		std::uint32_t Rc;
+		IpV4Addr ClientIp;
+		gsl::span<const std::byte> InitTime;
+		gsl::span<const std::byte, 16> PasswordMd5;
+		gsl::span<const std::byte> TGTGTKey;
+		std::uint32_t SigSrc;
+		std::uint32_t Bitmap;
+		std::uint32_t GetSig;
+		gsl::span<const std::uint32_t> SubAppIdList;
+		std::uint32_t GetSig1;
+		std::uint32_t WxAppId;
+		std::uint16_t PicType;
+		std::uint8_t CapType;
+		std::uint16_t PicSize;
+		std::uint8_t RetType;
+		gsl::span<const std::byte> Ksid;
+		gsl::span<const std::byte> SigSession;
+		UsingStringView ApkId;
+		gsl::span<const UsingStringView> Domains;
+	};
+} // namespace YumeBot::Request

+ 24 - 0
YumeBot/Session.cpp

@@ -0,0 +1,24 @@
+#include "Session.h"
+
+using namespace YumeBot;
+
+SessionFactory::UserPassword::UserPassword(UsingStringView const& password) noexcept
+{
+	Cryptography::Md5::Calculate(gsl::as_bytes(password.GetTrimmedSpan()), PasswordMd5);
+}
+
+SessionFactory::UserPassword::UserPassword(
+    gsl::span<const std::byte, 16> const& passwordMd5) noexcept
+{
+	std::memcpy(PasswordMd5.data(), passwordMd5.data(), 16);
+}
+
+SessionFactory::SessionFactory(Request::RequestContext commonInitialContext)
+    : m_CommonInitialContext{ std::move(commonInitialContext) }
+{
+}
+
+Request::RequestContext& SessionFactory::GetContext()
+{
+	return m_CommonInitialContext;
+}

+ 125 - 0
YumeBot/Session.h

@@ -0,0 +1,125 @@
+#pragma once
+
+#include "Request.h"
+
+namespace YumeBot
+{
+	/// @brief  抽象 Socket
+	/// @note   实现该接口以使用不同后端的 Socket 分发信息
+	/// @remark Socket 要求使用 TCP
+	template <typename TSocketImpl>
+	struct AbstractSocket
+	{
+		void ConnectTo(IpV4Addr const& ip, std::uint16_t port)
+		{
+			static_cast<TSocketImpl*>(this)->DoConnectTo(ip, port);
+		}
+
+		/// @remark 同一次通讯中 PullData 可能调用多次
+		void PullData(gsl::span<std::byte> const& buffer)
+		{
+			static_cast<TSocketImpl*>(this)->DoPullData(buffer);
+		}
+
+		void PushData(gsl::span<const std::byte> const& buffer)
+		{
+			static_cast<TSocketImpl*>(this)->DoPushData(buffer);
+		}
+
+		void CloseConnection()
+		{
+			static_cast<TSocketImpl*>(this)->DoCloseConnection();
+		}
+
+	protected:
+		~AbstractSocket() = default;
+	};
+
+	enum class LoginStatusEnum
+	{
+		Success,
+		RequestVerify,
+		Failed
+	};
+
+	template <LoginStatusEnum LoginStatusValue>
+	struct LoginResult
+	{
+		static constexpr LoginStatusEnum LoginStatus = LoginStatusValue;
+	};
+
+	template <>
+	struct LoginResult<LoginStatusEnum::RequestVerify>
+	{
+		static constexpr LoginStatusEnum LoginStatus = LoginStatusEnum::RequestVerify;
+
+		const gsl::span<const std::byte> VerifyCodePicture;
+		const std::size_t Width, Height;
+	};
+
+	class SessionFactory
+	{
+		struct UserPassword
+		{
+			UserPassword(UsingStringView const& password) noexcept;
+			UserPassword(gsl::span<const std::byte, 16> const& passwordMd5) noexcept;
+
+			std::array<std::byte, 16> PasswordMd5;
+		};
+
+		template <typename TSocketImpl>
+		class Session
+		{
+		public:
+			Session(AbstractSocket<TSocketImpl>& socket, Request::RequestContext&& initialRequestContext)
+			    : m_Socket{ socket }, m_RequestBuilder{ std::move(initialRequestContext) }
+			{
+			}
+
+			Session(Session const&) = delete;
+			Session& operator=(Session const&) = delete;
+
+			template <typename LoginCallback>
+			void Login(LoginCallback&& callback)
+			{
+				Cafe::Io::MemoryStream stream;
+				// TODO
+				m_RequestBuilder.WriteRequest(stream, Request::RequestTGTGT{});
+				m_Socket.PushData(stream.GetInternalStorage());
+
+				// TODO: 验证 Response
+				throw std::runtime_error("Not implemented");
+			}
+
+		private:
+			AbstractSocket<TSocketImpl>& m_Socket;
+			Request::RequestBuilder m_RequestBuilder;
+		};
+
+	public:
+		/// @see    SessionFactory::GetContext()
+		SessionFactory(Request::RequestContext commonInitialContext);
+
+		SessionFactory(SessionFactory const&) = delete;
+		SessionFactory& operator=(SessionFactory const&) = delete;
+
+		/// @brief  获取共同初始化上下文
+		/// @note   不需要存储 Uin 及密码 MD5,会在创建会话时覆盖
+		Request::RequestContext& GetContext();
+
+		/// @brief  以 Uin、密码及用户指定的 Socket 构建会话
+		/// @remark 会话不具有 Socket 的所有权,用户需自行保证在会话有效期间有效
+		template <typename TSocketImpl>
+		std::unique_ptr<Session<TSocketImpl>> CreateSession(std::uint32_t uin, UserPassword password,
+		                                                    AbstractSocket<TSocketImpl>& socket)
+		{
+			Request::RequestContext context = m_CommonInitialContext;
+			context.Uin = uin;
+			context.PasswordMd5 = password.PasswordMd5;
+			return std::make_unique<Session>(socket, std::move(context));
+		}
+
+	private:
+		Request::RequestContext m_CommonInitialContext;
+	};
+} // namespace YumeBot

+ 12 - 1
YumeBot/Tlv.cpp

@@ -3,7 +3,18 @@
 using namespace YumeBot;
 using namespace Tlv;
 
-TlvBuilder::TlvBuilder(Cafe::Io::OutputStream *stream) : m_Writer{ stream, std::endian::big }
+TlvBuilder::TlvBuilder(Cafe::Io::OutputStream* stream, std::size_t initialTlvCount)
+    : m_Writer{ stream, std::endian::big }, m_TlvCount{ initialTlvCount }
+{
+	assert(dynamic_cast<Cafe::Io::SeekableStreamBase*>(stream) && "stream should be seekable.");
+}
+
+std::size_t TlvBuilder::GetTlvCount() const noexcept
+{
+	return m_TlvCount;
+}
+
+TlvReader::TlvReader(Cafe::Io::InputStream* stream) : m_Reader{ stream, std::endian::big }
 {
 	assert(dynamic_cast<Cafe::Io::SeekableStreamBase*>(stream) && "stream should be seekable.");
 }

+ 128 - 32
YumeBot/Tlv.h

@@ -1,25 +1,63 @@
 #pragma once
 #include "Cryptography.h"
 #include "Misc.h"
+#include <Cafe/Io/StreamHelpers/BinaryReader.h>
 #include <Cafe/Io/StreamHelpers/BinaryWriter.h>
 #include <Cafe/Io/Streams/MemoryStream.h>
-#include <asio/ip/address_v4.hpp>
 #include <random>
 
 namespace YumeBot::Tlv
 {
+	/// @brief  表示指定 Cmd 的 Tlv
+	/// @remark 若 Tlv 具有读取的能力,应当自行管理生命周期问题
+	///         即若 Tlv 不需要读取,可以全部使用视图而不是容器保存自身的值
 	template <std::uint16_t Cmd>
 	struct TlvT
 	{
 		void Write(Cafe::Io::BinaryWriter& writer) const
 		{
 		}
+
+		static TlvT<Cmd> Read(Cafe::Io::BinaryReader& reader, std::size_t bodySize)
+		{
+			return {};
+		}
+	};
+
+	template <std::uint16_t Cmd, typename = void>
+	struct IsWritableTlvTrait : std::false_type
+	{
+	};
+
+	template <>
+	struct IsWritableTlvTrait<
+	    Cmd, std::void_t<decltype(TlvT<Cmd>::Write(std::declval<Cafe::Io::BinaryWriter&>()))>>
+	    : std::true_type
+	{
+	};
+
+	template <std::uint16_t Cmd>
+	constexpr bool IsWritableTlv = IsWritableTlvTrait<Cmd>::value;
+
+	template <std::uint16_t Cmd, typename = void>
+	struct IsReadableTlvTrait : std::false_type
+	{
 	};
 
+	template <std::uint16_t Cmd>
+	struct IsReadableTlvTrait<
+	    Cmd, std::void_t<decltype(TlvT<Cmd>::Read(std::declval<Cafe::Io::BinaryReader&>(),
+	                                              std::declval<std::size_t>()))>> : std::true_type
+	{
+	};
+
+	template <std::uint16_t Cmd>
+	constexpr bool IsReadableTlv = IsReadableTlvTrait<Cmd>::value;
+
 	class TlvBuilder
 	{
 	public:
-		explicit TlvBuilder(Cafe::Io::OutputStream* stream);
+		explicit TlvBuilder(Cafe::Io::OutputStream* stream, std::size_t initialTlvCount = 0);
 
 		template <std::uint16_t Cmd>
 		void WriteTlv(TlvT<Cmd> const& tlv)
@@ -37,10 +75,49 @@ namespace YumeBot::Tlv
 			assert(length <= std::numeric_limits<std::uint16_t>::max());
 			seekableStream->SeekFromBegin(lengthPos);
 			m_Writer.Write(static_cast<std::uint16_t>(length));
+
+			++m_TlvCount;
 		}
 
+		std::size_t GetTlvCount() const noexcept;
+
 	private:
 		Cafe::Io::BinaryWriter m_Writer;
+		std::size_t m_TlvCount;
+	};
+
+	class TlvReader
+	{
+	public:
+		explicit TlvReader(Cafe::Io::InputStream* stream);
+
+		template <std::uint16_t Cmd>
+		std::optional<TlvT<Cmd>> ReadTlv()
+		{
+			const auto stream = m_Reader.GetStream();
+			const auto seekableStream = dynamic_cast<Cafe::Io::SeekableStreamBase*>(stream);
+			assert(seekableStream);
+			seekableStream->SeekFromBegin(0);
+
+			while (stream->GetAvailableBytes() > 4)
+			{
+				const auto cmd = m_Reader.Read<std::uint16_t>();
+				const auto bodySize = m_Reader.Read<std::uint16_t>();
+				if (cmd == Cmd)
+				{
+					return TlvT<Cmd>::Read(m_Reader, bodySize);
+				}
+				else
+				{
+					seekableStream->Seek(Cafe::Io::SeekOrigin::Current, bodySize);
+				}
+			}
+
+			return {};
+		}
+
+	private:
+		Cafe::Io::BinaryReader m_Reader;
 	};
 
 	template <>
@@ -50,15 +127,15 @@ namespace YumeBot::Tlv
 		{
 			writer.Write(Uin);
 			writer.Write(ServerTime);
-			if (!ClientIp.is_unspecified())
+			if (!ClientIp.IsUnspecified())
 			{
-				writer.GetStream()->WriteBytes(gsl::as_bytes(gsl::make_span(ClientIp.to_bytes())));
+				writer.GetStream()->WriteBytes(gsl::as_bytes(gsl::make_span(ClientIp.Content)));
 			}
 		}
 
 		std::uint32_t Uin;
 		std::uint32_t ServerTime;
-		asio::ip::address_v4 ClientIp = {};
+		IpV4Addr ClientIp = {};
 	};
 
 	template <>
@@ -91,12 +168,12 @@ namespace YumeBot::Tlv
 		void Write(Cafe::Io::BinaryWriter& writer) const
 		{
 			writer.Write(TimeZoneVer);
-			writer.Write(LocaleId);
+			writer.Write(static_cast<std::uint32_t>(LocaleId));
 			writer.Write(TimeZoneOffset);
 		}
 
 		std::uint16_t TimeZoneVer = 0;
-		std::uint32_t LocaleId = static_cast<std::uint32_t>(UsingLocaleId);
+		LocaleIdEnum LocaleId = UsingLocaleId;
 		std::uint16_t TimeZoneOffset = 0;
 	};
 
@@ -181,9 +258,9 @@ namespace YumeBot::Tlv
 			unencryptedBodyWriter.Write(ClientVer);
 			unencryptedBodyWriter.Write(Uin);
 			unencryptedBodyStream.WriteBytes(InitTime);
-			if (!ClientIp.is_unspecified())
+			if (!ClientIp.IsUnspecified())
 			{
-				unencryptedBodyStream.WriteBytes(gsl::as_bytes(gsl::make_span(ClientIp.to_bytes())));
+				unencryptedBodyStream.WriteBytes(gsl::as_bytes(gsl::make_span(ClientIp.Content)));
 			}
 			unencryptedBodyWriter.Write(SavePwd);
 			unencryptedBodyStream.WriteBytes(Md5);
@@ -238,13 +315,13 @@ namespace YumeBot::Tlv
 		std::uint32_t ClientVer;
 		std::uint64_t Uin;
 		gsl::span<const std::byte> InitTime;
-		asio::ip::address_v4 ClientIp;
+		IpV4Addr ClientIp;
 		bool SavePwd;
-		gsl::span<const std::byte> Md5;
+		gsl::span<const std::byte, 16> Md5;
 		std::uint64_t MSalt;
 		gsl::span<const std::byte> TGTGTKey;
 		bool ReadFlg;
-		gsl::span<const std::byte> Guid;
+		gsl::span<const std::byte, 16> Guid;
 		std::uint32_t SigSrc;
 	};
 
@@ -270,10 +347,17 @@ namespace YumeBot::Tlv
 	{
 		void Write(Cafe::Io::BinaryWriter& writer) const
 		{
-			writer.GetStream()->WriteBytes(Ksid);
+			writer.GetStream()->WriteBytes(gsl::make_span(Ksid));
+		}
+
+		static TlvT<0x108> Read(Cafe::Io::BinaryReader& reader, std::size_t bodySize)
+		{
+			TlvT<0x108> tlv{ { bodySize } };
+			reader.GetStream()->ReadBytes(gsl::make_span(tlv.Ksid));
+			return tlv;
 		}
 
-		gsl::span<const std::byte> Ksid;
+		std::vector<std::byte> Ksid;
 	};
 
 	template <>
@@ -281,10 +365,11 @@ namespace YumeBot::Tlv
 	{
 		void Write(Cafe::Io::BinaryWriter& writer) const
 		{
-			writer.GetStream()->WriteBytes(Imei);
+			const auto imei = gsl::as_bytes(Imei.GetTrimmedSpan());
+			writer.GetStream()->WriteBytes(imei);
 		}
 
-		gsl::span<const std::byte> Imei;
+		UsingStringView Imei;
 	};
 
 	template <>
@@ -362,7 +447,7 @@ namespace YumeBot::Tlv
 			writer.GetStream()->WriteBytes(osType);
 			writer.Write(static_cast<std::uint16_t>(osVer.size()));
 			writer.GetStream()->WriteBytes(osVer);
-			writer.Write(NetType);
+			writer.Write(static_cast<std::uint16_t>(NetType));
 			writer.Write(static_cast<std::uint16_t>(netDetail.size()));
 			writer.GetStream()->WriteBytes(netDetail);
 			writer.Write(static_cast<std::uint16_t>(addr.size()));
@@ -373,7 +458,7 @@ namespace YumeBot::Tlv
 
 		UsingStringView OsType;
 		UsingStringView OsVer;
-		std::uint16_t NetType;
+		ConnectionTypeEnum NetType;
 		UsingStringView NetDetail;
 		UsingStringView Addr;
 		UsingStringView Apn;
@@ -467,14 +552,14 @@ namespace YumeBot::Tlv
 			writer.Write(static_cast<std::uint16_t>(operatorNameSize));
 			writer.GetStream()->WriteBytes(operatorName);
 
-			writer.Write(NetworkType);
+			writer.Write(static_cast<std::uint16_t>(NetworkType));
 
 			writer.Write(static_cast<std::uint16_t>(apnSize));
 			writer.GetStream()->WriteBytes(apn);
 		}
 
 		UsingStringView OperatorName;
-		std::uint16_t NetworkType;
+		ConnectionTypeEnum NetworkType;
 		UsingStringView Apn;
 	};
 
@@ -553,7 +638,7 @@ namespace YumeBot::Tlv
 			writer.GetStream()->WriteBytes(Guid);
 		}
 
-		gsl::span<const std::byte> Guid;
+		gsl::span<const std::byte, 16> Guid;
 	};
 
 	template <>
@@ -565,22 +650,18 @@ namespace YumeBot::Tlv
 			const auto appVer =
 			    appVerTrimmedSpan.subspan(0, std::min(appVerTrimmedSpan.size(), std::ptrdiff_t{ 32 }));
 
-			const auto appSignTrimmedSpan = gsl::as_bytes(AppSign.GetTrimmedSpan());
-			const auto appSign =
-			    appSignTrimmedSpan.subspan(0, std::min(appSignTrimmedSpan.size(), std::ptrdiff_t{ 32 }));
-
 			writer.Write(AppVerId);
 
 			writer.Write(static_cast<std::uint16_t>(appVer.size()));
 			writer.GetStream()->WriteBytes(appVer);
 
-			writer.Write(static_cast<std::uint16_t>(appSign.size()));
-			writer.GetStream()->WriteBytes(appSign);
+			writer.Write(static_cast<std::uint16_t>(AppSign.size()));
+			writer.GetStream()->WriteBytes(AppSign);
 		}
 
 		std::uint32_t AppVerId;
 		UsingStringView AppVer;
-		UsingStringView AppSign;
+		gsl::span<const std::byte, 16> AppSign;
 	};
 
 	template <>
@@ -818,10 +899,11 @@ namespace YumeBot::Tlv
 	{
 		void Write(Cafe::Io::BinaryWriter& writer) const
 		{
-			writer.GetStream()->WriteBytes(Mac);
+			const auto mac = gsl::as_bytes(Mac.GetTrimmedSpan());
+			writer.GetStream()->WriteBytes(mac);
 		}
 
-		gsl::span<const std::byte, 16> Mac;
+		UsingStringView Mac;
 	};
 
 	template <>
@@ -829,9 +911,23 @@ namespace YumeBot::Tlv
 	{
 		void Write(Cafe::Io::BinaryWriter& writer) const
 		{
-			writer.GetStream()->WriteBytes(AndroidID);
+			const auto androidID = gsl::as_bytes(AndroidID.GetTrimmedSpan());
+			writer.GetStream()->WriteBytes(androidID);
+		}
+
+		UsingStringView AndroidID;
+	};
+
+	template <>
+	struct TlvT<0x305>
+	{
+		static TlvT<0x305> Read(Cafe::Io::BinaryReader& reader, std::size_t bodySize)
+		{
+			TlvT<0x305> tlv{ { bodySize } };
+			reader.GetStream()->ReadBytes(gsl::make_span(tlv.SessionKey));
+			return tlv;
 		}
 
-		gsl::span<const std::byte, 16> AndroidID;
+		std::vector<std::byte> SessionKey;
 	};
 } // namespace YumeBot::Tlv

+ 0 - 27
YumeBot/Utility.h

@@ -11,33 +11,6 @@ namespace YumeBot::Utility
 		return num + alignment - 1 & ~(alignment - 1);
 	}
 
-	template <typename T, typename U>
-	struct MayAddConst
-	{
-		using Type = U;
-	};
-
-	template <typename T, typename U>
-	struct MayAddConst<const T, U>
-	{
-		using Type = std::add_const_t<U>;
-	};
-
-	template <typename T, std::size_t N>
-	typename MayAddConst<T, std::byte>::Type (
-	    &ToByteArray(T (&arr)[N]) noexcept)[sizeof(T) * N / sizeof(std::byte)]
-	{
-		return reinterpret_cast<
-		    typename MayAddConst<T, std::byte>::Type(&)[sizeof(T) * N / sizeof(std::byte)]>(arr);
-	}
-
-	template <typename T, std::size_t N>
-	gsl::span<typename MayAddConst<T, std::byte>::Type, sizeof(T) * N / sizeof(std::byte)>
-	    ToByteSpan(T (&arr)[N]) noexcept
-	{
-		return ToByteArray(arr);
-	}
-
 	template <typename T>
 	struct ResultType
 	{

+ 1 - 2
conanfile.txt

@@ -1,7 +1,6 @@
 [requires]
 Cafe/0.1@Chino/Cafe
-asio/1.13.0@bincrafters/stable
-Catch2/2.8.0@catchorg/stable
+Catch2/2.9.2@catchorg/stable
 
 [generators]
 cmake