fa
Feedback
ThePedroo

ThePedroo

رفتن به کانال در Telegram

نمایش بیشتر
کشور مشخص نشده استفناوری و برنامه‌ها43 615
487
مشترکین
اطلاعاتی وجود ندارد24 ساعت
+487 روز
+11230 روز
آرشیو پست ها
This is a post about the detections of KernelSU (and its forks) (without reinforced denylist system by ReZygisk), and susfs (with or without ReZygisk), discovered/created by me, ThePedroo. 1. Isolated Services Android allows apps to create services, not only for dividing tasks, but also for enhanced security, utilizing isolated processes. In isolated services, many privileges of the process are removed, and as a consequence, the UID of the process is changed, going from 90000 to 99999. 2. KernelSU DenyList selector Unlike Magisk, KernelSU doesn't allow you to select isolated services to be individually excluded or not, limiting the whole app to be umounted or not. By itself, this is not an issue, however the issue, but rather a limitation that by itself, is harmless. 3. The Issue Inside KernelSU's code, it only utilizes the app's UID to check whether or not it should be umounted. The problem is that it never takes into consideration the special case of isolated services, where its UID will not be the same as the apps, hence it will under the global umount toggle. However, because in setuid handle they check if it's an isolated service and returns — not umounting — it will end up leaking either way. SusFS utilizes the same setuid code, and only umounts for them if the if that includes isolated UID check returns false, ending up the same way. The situation for SusFS, however, is even worse: because it hides the KernelSU mounts from Zygote, not even Zygisk implementations are capable of identifying them to umount them, which makes it not fixable with current DenyList codes, requiring Zygisks to "guess". 4. Detection Now aware of the flaws, we can start to detect it easily. First, we must create an Isolated Service:
        <service
            android:name="NativeService"
            android:exported="false"
            android:process=":detectionService"
            android:isolatedProcess="true" />
The name and process name can be any, as it doesn't affect the detection. After that, we must utilize two types of extremely simple and known detections: 1. Suspicious/Root-related mounts detections: We need to parse /proc/self/mountinfo, and analyze the target, root and source name, ensuring the source name, for example, isn't KSU. 2. /debug_ramdisk and / dev match: We need to stat both /debug_ramdisk and / to match dev, or else it means /debug_ramdisk is mounted, which is abnormal. ... which they will run in the isolated service. The first detection will fail in KernelSU without SusFS, and with SusFS will pass the first and fail the second, having a mismatch. The SusFS one cannot be fixed with Zygisk unlike SusFSless KernelSU rooted environments, blocking any user using it [1]. [1]: This has been already reported to Simon, and the fix should expand to other branches soon. This will allow it to pass this detection, but older versions will fail. 5. Information This detection shows how easy is to forget those services, and how tricky then can be for bypassing such detections. It is critical to always take them into consideration, or else it might end up being detected with service-based detections. This has been already reported to Simon, known as SusFS4KSU creator, and the fix should expand to other branches soon. This will allow it to pass this detection, but older versions will fail. As for KernelSU, soon I should be creating a PR to implement a fix to it, umounting mounts for all isolated services, as rooted applications shouldn't use them — not with the isolated service with root power. Please, when fixing or adding this detection to some software, please add a URL to this post or where it origins from. This has been publicly published in good intentions, so that more people can become aware of how the root detection area is and works, despite knowledge here hardly being shared. You held my hand, promised me the heaven, I left from where I was, without any question. But you made me suffer, made me shed tears. Now I am here. Admitting errs, that despairs.

correct. INFO: When removing a soinfo from solist, the linker unloads the library, but it only does that if the base and size is not 0. Because we only want the soinfo of libzygisk.so and loaded modules to be discarded, we must set the size to 0, bypassing the m(emory)unmap. After some time, analyzing linker code and SoInfo hiding code of ReZygisk, I remembered a very interesting structure: ProtectedDataGuard. ProtectedDataGuard is responsible for protecting numerous structures of the linker, allowing it only to be writable when running some linker functions, and after done, making it read-only. In ReZygisk, we properly deal with that, making me wonder why this happen. After hours, I spot something: we inverted it. It's a bit confusing, after all, we first unprotect (ctor) to only after written to, protect (dtor). Because one is called constructor and the other deconstructor in C++, I ended up reversing their names. When that was fixed, we had it fully working, and now properly hiding SoInfo from libzygisk.so and loaded modules from apps, marking this issue as fixed. I am afraid of knowing the truth, When I can't even see the end of this. Please be realistic, tell the sooth. So that in the end, I can feel bliss.

This the information about the process of fixing A16 QPR1 Beta 1 with ReZygisk. Context: There has been reports of additional detections regarding injection after updating to A16 QPR1 Beta 1. Upon looking at the logs, the SoList hiding code was failing, complaining about not being able to find a symbol. 1. Retrieving linker binary For this type of issue, it's critical to have the binary of linker64 for local analysis, so that I can use readelf to observe all available symbols that are inside it, and also used for ReZygisk SoList hiding code. 2. Analyzing the first issue 2.1. Looking for "E zygisk-" in the sent logs, from the one that reported that issue. In it I found: Failed to find solist __dl__ZL6solist* This could be caused by two scenarios: 1. The linker64 renamed, removed, didn't export the solist anymore. 2. The ELF utils has a bug which lead to it not finding the symbol. To confirm, I asked the user for their device's linker64 (/system/bin/linker64), which he immediatly sent. To analyze that, readelf was used, and by using readelf -Ws linker64 | grep solist, I was able to confirm that indeed the requested symbol didn't exist, however there were ones that caught my attention: 1. solist_get_head 2. solist_get_tail SoList is basically an array, and it has a start (head) and an end (tail). This function were wrappers around that. I was not the one to write that code, so I wondered why it wasn't used. My only guess was that it was too new to be used. To confirm my guess, I analyzed the source code of Android 9 linker, the lowest version of Android which ReZygisk is able to run fully functional. However my guess was wrong. It was available there, so I modified the code to use it instead of requesting soinfo structure directly, making it more future-proof while also extending compatibility. 2.2. However, this wasn't even remotely to the end. After sending the build with the cited modifications, the tester could still find traces of injection in detectors, so I asked for another Debug Assistant log. There I could find another error: Failed to find sonext __dl__ZL6sonext* Again, there could be two scenarios that could cause it, and again I utilized readelf in the already-sent linker64 to confirm, and again, it wasn't found, and no wrapper was also found. I wasn't sure of what sonext was utilized for in the ReZygisk code, and upon closer look, I saw it wasn't being utilized at all in the code, so I could fully remove its traces from there, fixing this issue. And, again, I sent a new build for the tester to try it out. 2.3. Before we were dealing with injection traces, however after fixing two issues, the situation got worse: The device was not able to fully boot. Debug Assistant, however, is able to collect logs before Zygisk can break Zygote, and with some additional builds adding debugging logs in areas of SoInfo hiding code, I caught that get_next(iter) function always returned the same address as iter, creating an infinite loop. This was a hard issue to fix, after all, it worked in other devices, offset for next was correct, so what could it be? Well, I also would like to know. I guess not anymore. However I questioned myself: Why do we need to do all this ourselves? Doesn't the linker have some wrapper that simplifies the same process? With that, I started searching for functions that returned soinfo and took something related to a library to search it and return its soinfo. After a while, I found find_containing_library, a function that returned soinfo for a library that had p (address) within its memory limits. With that, we both reduced greatly the amount of symbols searched, simplified the process, and made it faster, since it now compared numbers and not strings. 2.4. SoInfo search was fixed, however the tester could still not boot his device, and again, sent a Debug Assistant log. With numerous builds, I was able to spot that the issue occured when setting the new size for the library, although not when reading the size, which returned a proper size, confirming that the offset was

I suppose I should start talking a bit of ReZygisk development parts in here, as it might interest some people, I hope.

Treat Wheel 0.0.3 is here. Same rules as previous versions apply here. For more information, seek the other build messages. Support for those not using Trusted CIs or old versions of ReZygisk will not be offered. Don't be deceived. Don't be redundant. Be reasonable and find where you belong to.

As for the first message here, I'd like to say: I hate SELinux and its rules