This commit is contained in:
HolographicHat
2025-10-23 08:01:43 +08:00
parent 19f84bdb86
commit 1218d1cbc4
4 changed files with 84 additions and 18 deletions

View File

@@ -19,12 +19,15 @@ message AchievementItem {
message MethodRvaConfig {
uint32 do_cmd = 1;
uint32 to_uint16 = 2;
uint32 update_normal_prop = 3;
uint32 new_string = 4;
uint32 find_game_object = 5;
uint32 event_system_update = 6;
uint32 simulate_pointer_click = 7;
uint32 to_int32 = 8;
uint32 tcp_state_ptr = 9;
uint32 shared_info_ptr = 10;
uint32 decompress = 11;
}
message NativeLibConfig {

View File

@@ -260,12 +260,15 @@ public static class Utils {
break;
case 0xFD:
writer.Write(methodRva.DoCmd);
writer.Write(methodRva.ToUint16);
writer.Write(methodRva.UpdateNormalProp);
writer.Write(methodRva.NewString);
writer.Write(methodRva.FindGameObject);
writer.Write(methodRva.EventSystemUpdate);
writer.Write(methodRva.SimulatePointerClick);
writer.Write(methodRva.ToInt32);
writer.Write(methodRva.TcpStatePtr);
writer.Write(methodRva.SharedInfoPtr);
writer.Write(methodRva.Decompress);
break;
case 0xFE:
_proc!.ResumeMainThread();

View File

@@ -2,6 +2,7 @@ using System.Buffers.Binary;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Yae.Utilities;
using static Yae.GameMethod;
namespace Yae;
@@ -26,10 +27,10 @@ internal static unsafe class Application {
Log.ResetConsole();
//
RecordChecksum();
MinHook.Attach(GameMethod.DoCmd, &OnDoCmd, out _doCmd);
MinHook.Attach(GameMethod.ToUInt16, &OnToUInt16, out _toUInt16);
MinHook.Attach(GameMethod.UpdateNormalProp, &OnUpdateNormalProp, out _updateNormalProp);
MinHook.Attach(GameMethod.EventSystemUpdate, &OnEventSystemUpdate, out _eventSystemUpdate);
MinHook.Attach(DoCmd, &OnDoCmd, out _doCmd);
MinHook.Attach(ToUInt32, &OnToInt32, out _toInt32);
MinHook.Attach(UpdateNormalProp, &OnUpdateNormalProp, out _updateNormalProp);
MinHook.Attach(EventSystemUpdate, &OnEventSystemUpdate, out _eventSystemUpdate);
return 0;
}
@@ -41,12 +42,12 @@ internal static unsafe class Application {
#region RecvPacket
private static delegate*unmanaged<byte*, int, ushort> _toUInt16;
private static delegate*unmanaged<byte*, int, int> _toInt32;
[UnmanagedCallersOnly]
private static ushort OnToUInt16(byte* val, int startIndex) {
var ret = _toUInt16(val, startIndex);
if (ret != 0xAB89 || *(ushort*) (val += 0x20) != 0x6745) {
private static int OnToInt32(byte* val, int startIndex) {
var ret = _toInt32(val, startIndex);
if (startIndex != 6 || *(ushort*) (val += 0x20) != 0x6745) {
return ret;
}
var cmdId = BinaryPrimitives.ReverseEndianness(*(ushort*) (val + 2));
@@ -58,11 +59,61 @@ internal static unsafe class Application {
return ret;
static Span<byte> GetData(byte* val) {
var headLen = BinaryPrimitives.ReverseEndianness(*(ushort*) (val + 4));
var headPtr = val + 10;
var dataLen = BinaryPrimitives.ReverseEndianness(*(uint*) (val + 6));
return new Span<byte>(val + 10 + headLen, (int) dataLen);
var dataPtr = val + 10 + headLen;
var unzipLen = GetDecompressedSize(new Span<byte>(headPtr, headLen));
if (unzipLen == 0) {
return new Span<byte>(dataPtr, (int) dataLen);
}
var unzipBuf = NativeMemory.Alloc(unzipLen);
if (!Decompress(*TcpStatePtr, *SharedInfoPtr, dataPtr, dataLen, unzipBuf, unzipLen)) {
throw new InvalidDataException("Decompress failed.");
}
return new Span<byte>(unzipBuf, (int) unzipLen);
}
}
private static uint GetDecompressedSize(Span<byte> header) {
var offset = 0;
ulong tag;
while (offset != header.Length && (tag = ReadRawVarInt64(header, ref offset)) != 0) {
if (tag == 64) {
return (uint) ReadRawVarInt64(header, ref offset);
}
switch (tag & 7) {
case 0:
ReadRawVarInt64(header, ref offset);
break;
case 1:
offset += 8;
break;
case 2:
offset += (int) ReadRawVarInt64(header, ref offset);
break;
case 3:
case 4:
throw new NotSupportedException();
case 5:
offset += 4;
break;
}
}
return 0;
}
private static ulong ReadRawVarInt64(this Span<byte> span, ref int offset) {
ulong result = 0;
for (var i = 0; i < 8; i++) {
var b = span[offset++];
result |= (ulong) (b & 0x7F) << (i * 7);
if (b < 0x80) {
return result;
}
}
throw new InvalidDataException("CodedInputStream encountered a malformed varint.");
}
#endregion
#region Prop
@@ -118,7 +169,7 @@ internal static unsafe class Application {
Buffer = buffer,
Length = 256
};
_ = GameMethod.DoCmd(23, Unsafe.AsPointer(ref data), sizeof(RecordChecksumCmdData));
_ = DoCmd(23, Unsafe.AsPointer(ref data), sizeof(RecordChecksumCmdData));
RecordedChecksum[i] = data;
//REPL//Log.Trace($"nType={i}, value={new string((sbyte*) buffer, 0, data.Length)}");
}
@@ -153,9 +204,9 @@ internal static unsafe class Application {
public static void OnEventSystemUpdate(nint @this) {
_eventSystemUpdate(@this);
if (Environment.TickCount64 - _lastTryEnterTime > 200) {
var obj = GameMethod.FindGameObject(GameMethod.NewString("BtnStart"u8.AsPointer()));
if (obj != 0 && GameMethod.SimulatePointerClick(@this, obj)) {
MinHook.Detach((nint) GameMethod.EventSystemUpdate);
var obj = FindGameObject(NewString("BtnStart"u8.AsPointer()));
if (obj != 0 && SimulatePointerClick(@this, obj)) {
MinHook.Detach((nint) EventSystemUpdate);
}
_lastTryEnterTime = Environment.TickCount64;
}

View File

@@ -15,8 +15,6 @@ internal static unsafe class GameMethod {
public static delegate*unmanaged<int, void*, int, int> DoCmd { get; set; }
public static delegate*unmanaged<byte*, int, ushort> ToUInt16 { get; set; }
public static delegate*unmanaged<nint, int, double, double, int, void> UpdateNormalProp { get; set; }
public static delegate*unmanaged<nint, nint> NewString { get; set; }
@@ -27,6 +25,14 @@ internal static unsafe class GameMethod {
public static delegate*unmanaged<nint, nint, bool> SimulatePointerClick { get; set; }
public static delegate*unmanaged<byte*, int, int> ToUInt32 { get; set; }
public static void** TcpStatePtr { get; set; }
public static void** SharedInfoPtr { get; set; }
public static delegate*unmanaged<void*, void*, void*, uint, void*, uint, bool> Decompress { get; set; }
}
internal static class Goshujin {
@@ -83,12 +89,15 @@ internal static class Goshujin {
public static unsafe void LoadMethodTable() {
_pipeWriter.Write((byte) 0xFD);
GameMethod.DoCmd = (delegate*unmanaged<int, void*, int, int>) Native.RVAToVA(_pipeReader.ReadUInt32());
GameMethod.ToUInt16 = (delegate*unmanaged<byte*, int, ushort>) Native.RVAToVA(_pipeReader.ReadUInt32());
GameMethod.UpdateNormalProp = (delegate*unmanaged<nint, int, double, double, int, void>) Native.RVAToVA(_pipeReader.ReadUInt32());
GameMethod.NewString = (delegate*unmanaged<nint, nint>) Native.RVAToVA(_pipeReader.ReadUInt32());
GameMethod.FindGameObject = (delegate*unmanaged<nint, nint>) Native.RVAToVA(_pipeReader.ReadUInt32());
GameMethod.EventSystemUpdate = (delegate*unmanaged<nint, void>) Native.RVAToVA(_pipeReader.ReadUInt32());
GameMethod.SimulatePointerClick = (delegate*unmanaged<nint, nint, bool>) Native.RVAToVA(_pipeReader.ReadUInt32());
GameMethod.ToUInt32 = (delegate*unmanaged<byte*, int, int>) Native.RVAToVA(_pipeReader.ReadUInt32());
GameMethod.TcpStatePtr = (void**) Native.RVAToVA(_pipeReader.ReadUInt32());
GameMethod.SharedInfoPtr = (void**) Native.RVAToVA(_pipeReader.ReadUInt32());
GameMethod.Decompress = (delegate*unmanaged<void*, void*, void*, uint, void*, uint, bool>) Native.RVAToVA(_pipeReader.ReadUInt32());
}
public static void ResumeMainThread() {