Skip to content

Commit 22f1758

Browse files
author
StArray
committed
feat(runtime): 新增NativeFuncResolver支持ELF符号和特征码解析
- 实现NativeFuncResolver类,支持ELF文件的符号查找与特征码搜索 - 支持通过符号名或字节码特征码获取函数RVA与函数指针 - 实现ELF文件加载和基址获取,支持符号的通配符模式匹配 - 在Hook生成器中添加Resolver方法存在性检查,提升Hook声明的可靠性 - NativeHook特性支持通过RVA和ResolverMethod传递函数地址获取方式 - HookHelper新增GetFunctionRVA方法,结合解析器和回退路径定位函数地址 - MinHook和Dobby实现新增RVA地址获取逻辑,统一支持基址+RVA计算 - DL库封装重命名及接口调整,统一命名风格与参数类型 - GLESBindingsContext及ImGuiVulkanRenderer更新调用DL新接口 - AndroidInput新增完整Android NDK输入系统API封装,支持输入事件处理 - Android UI层ImGui输入处理优化,添加异常捕获和状态标记 - AndroidInput使用NativeFunctions委托回调,支持IME文本输入和特殊键处理 - Gradle构建脚本升级NDK版本,新增copyCoreClrToJniLibs任务确保SO文件打包 - Diagnostics增加ResolverMethodNotFound错误,提示Hook对应的解析方法缺失或签名错误 - 调整HookGenerator代码生成逻辑,支持通过ResolverMethod动态获取函数地址 - RGCT补充部分接口实现,提升运行时类型反射的支持能力 - 更新version.json版本号至1.0.5,修正版本下载地址和sha256校验码
1 parent 81cb1d1 commit 22f1758

19 files changed

Lines changed: 1302 additions & 548 deletions

File tree

‎Android/library/build.gradle‎

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ plugins {
1010
android {
1111
namespace 'starray.android.modmanager'
1212
compileSdk 35
13-
ndkVersion "25.2.9519653"
13+
ndkVersion "27.2.12479018"
1414

1515
defaultConfig {
1616
minSdk 26
@@ -135,4 +135,27 @@ tasks.register("downloadRuntime"){
135135
zipFile.delete()
136136
}
137137
}
138-
preBuild.dependsOn downloadRuntime
138+
139+
tasks.register("copyCoreClrToJniLibs") {
140+
description = '复制 CoreCLR .so 到 jniLibs 以打包进 AAR'
141+
group = 'build'
142+
143+
doLast {
144+
def jniLibsDir = file("$projectDir/src/main/jniLibs/arm64-v8a")
145+
jniLibsDir.mkdirs()
146+
147+
fileTree("$projectDir/src/main/cpp/libs/coreclr").include('**/*.so').each { f ->
148+
def target = new File(jniLibsDir, f.name)
149+
if (!target.exists() || target.lastModified() < f.lastModified()) {
150+
copy {
151+
from f
152+
into jniLibsDir
153+
}
154+
logger.lifecycle("Copied ${f.name} to jniLibs/arm64-v8a")
155+
}
156+
}
157+
}
158+
}
159+
160+
preBuild.dependsOn downloadRuntime
161+
preBuild.dependsOn copyCoreClrToJniLibs

‎StArray.ModManager.Analyzer/Diagnostics.cs‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,11 @@ internal static class Diagnostics
7272
"实例方法 Hook 的首个参数应为 nint(this 指针)",
7373
"方法 '{0}' 的首个参数是 '{1}';被 hook 的实例方法在 native 侧首参为 this 指针,通常应声明为 nint",
7474
Category, DiagnosticSeverity.Info, isEnabledByDefault: true);
75+
76+
/// <summary>Resolver 方法不存在</summary>
77+
public static readonly DiagnosticDescriptor ResolverMethodNotFound = new(
78+
"SAMM010",
79+
"Resolver 方法不存在",
80+
"方法 '{0}' 中指定的 resolver 方法 '{1}' 不存在或签名不匹配(需要 static nint MethodName())",
81+
Category, DiagnosticSeverity.Error, isEnabledByDefault: true);
7582
}

‎StArray.ModManager.Analyzer/HookGenerator.cs‎

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,16 @@ private sealed class HookInfo
3737
{
3838
public string AttrType { get; set; }
3939
public string ContainingType { get; set; }
40+
public string TypeAccessibility { get; set; }
4041
public string MethodName { get; set; }
4142
public string ReturnType { get; set; }
4243
public ImmutableArray<(string Type, string Name)> Parameters { get; set; }
4344
public ImmutableArray<string> CtorArgs { get; set; }
4445
public ImmutableArray<(string Key, string Value)> NamedArgs { get; set; }
4546
public bool HasUnmanagedCallersOnly { get; set; }
47+
public bool ResolverMethodExists { get; set; } = true;
48+
public string ResolverCallExpression { get; set; }
49+
public Microsoft.CodeAnalysis.Location Location { get; set; }
4650
}
4751

4852
private static HookInfo? GetHookInfo(GeneratorSyntaxContext ctx)
@@ -77,16 +81,34 @@ private sealed class HookInfo
7781
var uco = sym.GetAttributes().Any(a =>
7882
a.AttributeClass?.ToDisplayString() == "System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute");
7983

84+
var accessibility = sym.ContainingType.DeclaredAccessibility;
85+
var typeAcc = accessibility switch
86+
{
87+
Accessibility.Public => "public",
88+
Accessibility.Internal => "internal",
89+
_ => "internal",
90+
};
91+
92+
var resolverCallExpr = "";
93+
if (attrType == "NativeHook" && ca.Count == 1 && ca[0].StartsWith("\""))
94+
{
95+
var rawName = ca[0].Trim('"');
96+
resolverCallExpr = rawName.Replace("::", ".");
97+
}
98+
8099
return new HookInfo
81100
{
82101
AttrType = attrType,
83102
ContainingType = ct,
103+
TypeAccessibility = typeAcc,
84104
MethodName = sym.Name,
85105
ReturnType = rt,
86106
Parameters = pl.ToImmutable(),
87107
CtorArgs = ca.ToImmutable(),
88108
NamedArgs = na.ToImmutable(),
89109
HasUnmanagedCallersOnly = uco,
110+
ResolverCallExpression = resolverCallExpr,
111+
Location = method.GetLocation(),
90112
};
91113
}
92114
return null;
@@ -120,8 +142,30 @@ private static void GenerateCode(SourceProductionContext ctx, Compilation compil
120142
{
121143
if (hooks.Length == 0) return;
122144

145+
foreach (var h in hooks)
146+
{
147+
if (string.IsNullOrEmpty(h.ResolverCallExpression))
148+
continue;
149+
150+
var methodName = h.ResolverCallExpression.Contains('.')
151+
? h.ResolverCallExpression.Substring(h.ResolverCallExpression.LastIndexOf('.') + 1)
152+
: h.ResolverCallExpression;
153+
154+
var found = compilation.GetSymbolsWithName(methodName, SymbolFilter.Member)
155+
.Any(m => m is IMethodSymbol ms &&
156+
ms.Name == methodName &&
157+
ms.IsStatic &&
158+
ms.Parameters.Length == 0 &&
159+
ms.ReturnType.SpecialType == SpecialType.System_IntPtr);
160+
161+
if (!found)
162+
ctx.ReportDiagnostic(Diagnostic.Create(
163+
Diagnostics.ResolverMethodNotFound, h.Location, h.MethodName, h.ResolverCallExpression));
164+
}
165+
123166
foreach (var group in hooks.GroupBy(h => h.ContainingType))
124167
{
168+
var first = group.First();
125169
var ns = ExtractNamespace(group.Key);
126170
var cn = ExtractClassName(group.Key);
127171
var sb = new StringBuilder();
@@ -130,7 +174,7 @@ private static void GenerateCode(SourceProductionContext ctx, Compilation compil
130174
sb.AppendLine("#nullable enable");
131175
sb.AppendLine($"namespace {ns ?? "__Hooks"}");
132176
sb.AppendLine("{");
133-
sb.AppendLine($" public unsafe partial class {cn}");
177+
sb.AppendLine($" {first.TypeAccessibility} unsafe partial class {cn}");
134178
sb.AppendLine(" {");
135179

136180
foreach (var h in group)
@@ -160,9 +204,18 @@ private static void GenerateCode(SourceProductionContext ctx, Compilation compil
160204
sb.AppendLine(" {");
161205
if (h.AttrType == "NativeHook")
162206
{
163-
bool isAddr = h.CtorArgs.Length == 1 && !h.CtorArgs[0].StartsWith("\"");
164-
if (isAddr)
165-
sb.AppendLine($" var t = (nint){h.CtorArgs[0]};");
207+
bool isRva = h.CtorArgs.Length == 2 && h.CtorArgs[0].StartsWith("\"") && !h.CtorArgs[1].StartsWith("\"");
208+
bool isResolver = h.CtorArgs.Length == 1 && h.CtorArgs[0].StartsWith("\"");
209+
if (isResolver)
210+
{
211+
sb.AppendLine($" var t = {h.ResolverCallExpression}();");
212+
}
213+
else if (isRva)
214+
{
215+
var l = h.CtorArgs[0];
216+
var r = h.CtorArgs[1];
217+
sb.AppendLine($" var t = global::StArray.ModManager.Runtime.HookHelper.GetFunctionRVA({l}, (long){r});");
218+
}
166219
else
167220
{
168221
var l = h.CtorArgs.Length > 0 ? h.CtorArgs[0] : "\"\"";
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
namespace StArray.ModManager.Android.Native;
2+
using System;
3+
using System.Runtime.InteropServices;
4+
5+
/// <summary>
6+
/// Android NDK 输入系统 API 的 C# P/Invoke 封装。
7+
/// 对应 AOSP 的 input.h 和 libui.so / libandroid.so。
8+
/// </summary>
9+
public static class AndroidInput
10+
{
11+
// ======================== 常量与枚举 ========================
12+
13+
/// <summary>ALooper_prepare 选项</summary>
14+
[Flags]
15+
public enum PrepareFlags
16+
{
17+
None = 0,
18+
AllowNonCallbacks = 1 << 0,
19+
}
20+
21+
/// <summary>输入事件类型</summary>
22+
public enum EventType
23+
{
24+
Key = 1,
25+
Motion = 2,
26+
}
27+
28+
/// <summary>按键动作</summary>
29+
public enum KeyAction
30+
{
31+
Down = 0,
32+
Up = 1,
33+
Multiple = 2,
34+
}
35+
36+
/// <summary>触摸动作(主动作需用 ActionMask 提取)</summary>
37+
public enum MotionAction
38+
{
39+
Down = 0,
40+
Up = 1,
41+
Move = 2,
42+
Cancel = 3,
43+
Outside = 4,
44+
PointerDown = 5,
45+
PointerUp = 6,
46+
HoverEnter = 7,
47+
HoverMove = 8,
48+
HoverExit = 9,
49+
ButtonPress = 10,
50+
ButtonRelease = 11,
51+
}
52+
53+
/// <summary>Meta 键状态</summary>
54+
[Flags]
55+
public enum MetaState
56+
{
57+
None = 0,
58+
ShiftOn = 0x01,
59+
AltOn = 0x02,
60+
ShiftLeftOn = 0x40,
61+
ShiftRightOn = 0x80,
62+
AltLeftOn = 0x10,
63+
AltRightOn = 0x20,
64+
}
65+
66+
/// <summary>触摸事件动作掩码工具</summary>
67+
public static class MotionMask
68+
{
69+
public const int Action = 0xFF;
70+
public const int PointerIndex = 0xFF00;
71+
public const int PointerIndexShift = 8;
72+
}
73+
74+
// ======================== 不透明句柄结构体 ========================
75+
76+
/// <summary>不透明输入事件句柄</summary>
77+
[StructLayout(LayoutKind.Sequential)]
78+
public struct AInputEvent { }
79+
80+
/// <summary>不透明输入队列句柄</summary>
81+
[StructLayout(LayoutKind.Sequential)]
82+
public struct AInputQueue { }
83+
84+
/// <summary>不透明 Looper 句柄</summary>
85+
[StructLayout(LayoutKind.Sequential)]
86+
public struct ALooper { }
87+
88+
// ======================== 委托类型 ========================
89+
90+
/// <summary>
91+
/// AInputQueue_attachLooper 回调签名。
92+
/// 必须保持委托实例的引用,防止被 GC 回收。
93+
/// </summary>
94+
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
95+
public delegate int InputQueueCallback(int fd, int events, IntPtr data);
96+
97+
// ======================== P/Invoke 导入 ========================
98+
99+
private const string Lib = "libandroid.so";
100+
101+
[DllImport(Lib, CallingConvention = CallingConvention.Cdecl)]
102+
public static extern IntPtr ALooper_prepare(PrepareFlags opts);
103+
104+
[DllImport(Lib, CallingConvention = CallingConvention.Cdecl)]
105+
public static extern void AInputQueue_attachLooper(
106+
IntPtr queue,
107+
IntPtr looper,
108+
int ident,
109+
InputQueueCallback callback,
110+
IntPtr data
111+
);
112+
113+
[DllImport(Lib, CallingConvention = CallingConvention.Cdecl)]
114+
public static extern void AInputQueue_detachLooper(IntPtr queue);
115+
116+
[DllImport(Lib, CallingConvention = CallingConvention.Cdecl)]
117+
public static extern int AInputQueue_getEvent(
118+
IntPtr queue,
119+
out IntPtr outEvent
120+
);
121+
122+
[DllImport(Lib, CallingConvention = CallingConvention.Cdecl)]
123+
public static extern void AInputQueue_finishEvent(
124+
IntPtr queue,
125+
IntPtr ev,
126+
int handled
127+
);
128+
129+
[DllImport(Lib, CallingConvention = CallingConvention.Cdecl)]
130+
public static extern EventType AInputEvent_getType(IntPtr ev);
131+
132+
[DllImport(Lib, CallingConvention = CallingConvention.Cdecl)]
133+
public static extern int AKeyEvent_getKeyCode(IntPtr ev);
134+
135+
[DllImport(Lib, CallingConvention = CallingConvention.Cdecl)]
136+
public static extern KeyAction AKeyEvent_getAction(IntPtr ev);
137+
138+
[DllImport(Lib, CallingConvention = CallingConvention.Cdecl)]
139+
public static extern MetaState AKeyEvent_getMetaState(IntPtr ev);
140+
141+
[DllImport(Lib, CallingConvention = CallingConvention.Cdecl)]
142+
public static extern int AKeyEvent_getRepeatCount(IntPtr ev);
143+
144+
[DllImport(Lib, CallingConvention = CallingConvention.Cdecl)]
145+
public static extern int AMotionEvent_getAction(IntPtr ev);
146+
147+
[DllImport(Lib, CallingConvention = CallingConvention.Cdecl)]
148+
public static extern float AMotionEvent_getX(IntPtr ev, int pointerIndex);
149+
150+
[DllImport(Lib, CallingConvention = CallingConvention.Cdecl)]
151+
public static extern float AMotionEvent_getY(IntPtr ev, int pointerIndex);
152+
153+
[DllImport(Lib, CallingConvention = CallingConvention.Cdecl)]
154+
public static extern int AMotionEvent_getPointerCount(IntPtr ev);
155+
156+
[DllImport(Lib, CallingConvention = CallingConvention.Cdecl)]
157+
public static extern int AMotionEvent_getPointerId(IntPtr ev, int pointerIndex);
158+
159+
// ======================== 辅助方法(扩展风格) ========================
160+
161+
/// <summary>获取触摸事件的主动作(去除指针索引)</summary>
162+
public static MotionAction GetMainAction(this IntPtr ev)
163+
{
164+
if (AInputEvent_getType(ev) != EventType.Motion)
165+
throw new InvalidOperationException("事件不是 Motion 类型");
166+
int raw = AMotionEvent_getAction(ev);
167+
return (MotionAction)(raw & MotionMask.Action);
168+
}
169+
170+
/// <summary>获取触摸事件的指针索引(用于多点触控)</summary>
171+
public static int GetPointerIndex(this IntPtr ev)
172+
{
173+
int raw = AMotionEvent_getAction(ev);
174+
return (raw & MotionMask.PointerIndex) >> MotionMask.PointerIndexShift;
175+
}
176+
}

‎StArray.ModManager.Android/Native/DL.cs‎

Lines changed: 0 additions & 21 deletions
This file was deleted.

0 commit comments

Comments
 (0)