0%

Magisk注入app并嵌入imgui(三)

Magisk 注入 app 并嵌入 imgui (二) 里成功创建了 surface, 但是 imgui 的画面并没有显示出来,

看看 SurfaceFlinger 的信息.

1
adb shell dumpsys SurfaceFlinger

1
2
3
4
5
6
7
Offscreen Layers:
Layer Surface(name=cac9055 InputMethod)/@0x5406b5b - animation-leash of insets_animation#0 (EffectLayer) callingPid:3013 callingUid:1000 ownerUid:1000
Layer Surface(name=50f3462 com.tencent.mf.uam/com.epicgames.ue4.GameActivity)/@0x5e8236 - animation-leash of starting_reveal#0 (EffectLayer) callingPid:3013 callingUid:1000 ownerUid:1000
Layer Surface(name=Task=1)/@0xca72fe0 - animation-leash of app_transition#0 (EffectLayer) callingPid:3013 callingUid:1000 ownerUid:1000
Layer Surface(name=Task=185)/@0xc4029e3 - animation-leash of app_transition#0 (EffectLayer) callingPid:3013 callingUid:1000 ownerUid:1000
Layer Shocker#0 (BufferStateLayer) callingPid:8669 callingUid:10219 ownerUid:10219
Layer bbq-wrapper#1 (BufferStateLayer) callingPid:8669 callingUid:10219 ownerUid:10219

唉,我的 Layer 怎么在 Offscreen 里?

1
Layer Shocker#0 (BufferStateLayer) callingPid:8669 callingUid:10219 ownerUid:10219

打开 imgui 可执行文件的版本.
看看有什么区别.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
+ BufferStateLayer (ImGuiLink#0  screenFlags = 0  miuiVkWidgetTransparent = 0) uid=0
Region TransparentRegion (this=0 count=0)
Region VisibleRegion (this=0 count=0)
Region SurfaceDamageRegion (this=0 count=0)
layerStack= 0, z= 0, pos=(0,0), size=( -1, -1), crop=[ 0, 0, -1, -1], cornerRadius=0.000000, isProtected=0, isTrustedOverlay=0, isOpaque=0, invalidate=0, dataspace=Default, defaultPixelFormat=Unknown/None, backgroundBlurRadius=0, color=(0.000,0.000,0.000,1.000), flags=0x00000000, tr=[0.00, 0.00][0.00, 0.00]
parent=none
zOrderRelativeOf=none
activeBuffer=[ 0x 0: 0,Unknown/None], tr=[0.00, 0.00][0.00, 0.00] queued-frames=0, mRefreshPending=0, metadata={}, cornerRadiusCrop=[0.00, 0.00, 0.00, 0.00], shadowRadius=0.000,
+ BufferStateLayer (bbq-wrapper#0 screenFlags = 0 miuiVkWidgetTransparent = 0) uid=0
Region TransparentRegion (this=0 count=0)
Region VisibleRegion (this=0 count=1)
[ 0, 0, 1440, 3200]
Region SurfaceDamageRegion (this=0 count=0)
layerStack= 0, z= 0, pos=(0,0), size=(1440,3200), crop=[ 0, 0, -1, -1], cornerRadius=0.000000, isProtected=0, isTrustedOverlay=0, isOpaque=0, invalidate=0, dataspace=Default, defaultPixelFormat=RGBA_8888, backgroundBlurRadius=0, color=(0.000,0.000,0.000,1.000), flags=0x00000100, tr=[0.00, 0.00][0.00, 0.00]
parent=ImGuiLink#0 screenFlags = 0 miuiVkWidgetTransparent = 0
zOrderRelativeOf=none
activeBuffer=[1440x3200:1472,RGBA_8888], tr=[0.00, 0.00][0.00, 0.00] queued-frames=0, mRefreshPending=0, metadata={dequeueTime:514178138135}, cornerRadiusCrop=[0.00, 0.00, 0.00, 0.00], shadowRadius=0.000,

唉,发现可执行文件的 uid=0 而,app 创建的 surface 的 uid 不为 0.

去源码看看.

1
2
3
4353      bool addToRoot = callingThreadHasUnscopedSurfaceFlingerAccess();
4354 result = addClientLayer(client, *handle, *gbp, layer, parentHandle, parentLayer, addToRoot,
4355 outTransformHint);

http://aospxref.com/android-12.0.0_r3/s?refs=createLayer&project=frameworks

1
2
3
4
5
6
7
8
9
10
11
3888  bool SurfaceFlinger::callingThreadHasUnscopedSurfaceFlingerAccess(bool usePermissionCache) {
3889 IPCThreadState* ipc = IPCThreadState::self();
3890 const int pid = ipc->getCallingPid();
3891 const int uid = ipc->getCallingUid();
3892 if ((uid != AID_GRAPHICS && uid != AID_SYSTEM) &&
3893 (usePermissionCache ? !PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid)
3894 : !checkPermission(sAccessSurfaceFlinger, pid, uid))) {
3895 return false;
3896 }
3897 return true;
3898 }

http://aospxref.com/android-12.0.0_r3/s?refs=callingThreadHasUnscopedSurfaceFlingerAccess&project=frameworks

这里的 pid,uid 就是通过下面的函数获取的.

1
2
3890      const int pid = ipc->getCallingPid();
3891 const int uid = ipc->getCallingUid();

对于可执行文件来说,pid 和 uid 都是 0.

那么有没有办法让我们创建的 surface pid 和 uid 同时为 0 呢?

当然有…
Hook surfaceflinger 进程给 surface 开后门

最后做一个总结:
相比于外部 imgui,hook eglswapbuffers 来说,creteSurface 基本上是最优解,它既不会涉及到跨进程读写内存,也不会卡游戏画面.
唯一美中不足的地方就是编译复杂,没法跨安卓版本使用.